• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3 
4 Marvell BSD License Option
5 
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File under the following licensing terms.
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10 
11 * Redistributions of source code must retain the above copyright notice,
12   this list of conditions and the following disclaimer.
13 
14 * Redistributions in binary form must reproduce the above copyright
15   notice, this list of conditions and the following disclaimer in the
16   documentation and/or other materials provided with the distribution.
17 
18 * Neither the name of Marvell nor the names of its contributors may be
19   used to endorse or promote products derived from this software without
20   specific prior written permission.
21 
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 *******************************************************************************/
34 
35 #include <Protocol/I2cMaster.h>
36 #include <Protocol/I2cEnumerate.h>
37 #include <Protocol/I2cBusConfigurationManagement.h>
38 #include <Protocol/DevicePath.h>
39 
40 #include <Library/BaseLib.h>
41 #include <Library/IoLib.h>
42 #include <Library/DebugLib.h>
43 #include <Library/PcdLib.h>
44 #include <Library/UefiLib.h>
45 #include <Library/ParsePcdLib.h>
46 #include <Library/MemoryAllocationLib.h>
47 #include <Library/UefiBootServicesTableLib.h>
48 
49 #include "MvI2cDxe.h"
50 
51 STATIC MV_I2C_BAUD_RATE baud_rate;
52 
53 STATIC MV_I2C_DEVICE_PATH MvI2cDevicePathProtocol = {
54   {
55     {
56       HARDWARE_DEVICE_PATH,
57       HW_VENDOR_DP,
58       {
59   (UINT8) (sizeof(VENDOR_DEVICE_PATH)),
60   (UINT8) (sizeof(VENDOR_DEVICE_PATH) >> 8),
61       },
62     },
63     EFI_CALLER_ID_GUID
64   },
65   {
66     END_DEVICE_PATH_TYPE,
67     END_ENTIRE_DEVICE_PATH_SUBTYPE,
68     {
69       sizeof(EFI_DEVICE_PATH_PROTOCOL),
70       0
71     }
72   }
73 };
74 
75 STATIC
76 UINT32
I2C_READ(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINTN off)77 I2C_READ(
78   IN I2C_MASTER_CONTEXT *I2cMasterContext,
79   IN UINTN off)
80 {
81   ASSERT (I2cMasterContext != NULL);
82   return MmioRead32 (I2cMasterContext->BaseAddress + off);
83 }
84 
85 STATIC
86 EFI_STATUS
I2C_WRITE(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINTN off,IN UINT32 Value)87 I2C_WRITE (
88   IN I2C_MASTER_CONTEXT *I2cMasterContext,
89   IN UINTN off,
90   IN UINT32 Value)
91 {
92   ASSERT (I2cMasterContext != NULL);
93   return MmioWrite32 (I2cMasterContext->BaseAddress + off, Value);
94 }
95 
96 EFI_STATUS
97 EFIAPI
MvI2cInitialiseController(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable,IN EFI_PHYSICAL_ADDRESS BaseAddress)98 MvI2cInitialiseController (
99   IN EFI_HANDLE  ImageHandle,
100   IN EFI_SYSTEM_TABLE  *SystemTable,
101   IN EFI_PHYSICAL_ADDRESS BaseAddress
102   )
103 {
104   EFI_STATUS Status;
105   I2C_MASTER_CONTEXT *I2cMasterContext;
106   STATIC INTN Bus = 0;
107   MV_I2C_DEVICE_PATH *DevicePath;
108 
109   DevicePath = AllocateCopyPool (sizeof(MvI2cDevicePathProtocol),
110                                  &MvI2cDevicePathProtocol);
111   if (DevicePath == NULL) {
112     DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device path allocation failed\n"));
113     return EFI_OUT_OF_RESOURCES;
114   }
115   DevicePath->Guid.Guid.Data4[0] = Bus;
116 
117   /* if attachment succeeds, this gets freed at ExitBootServices */
118   I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
119   if (I2cMasterContext == NULL) {
120     DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C master context allocation failed\n"));
121     return EFI_OUT_OF_RESOURCES;
122   }
123   I2cMasterContext->Signature = I2C_MASTER_SIGNATURE;
124   I2cMasterContext->I2cMaster.Reset = MvI2cReset;
125   I2cMasterContext->I2cMaster.StartRequest = MvI2cStartRequest;
126   I2cMasterContext->I2cEnumerate.Enumerate = MvI2cEnumerate;
127   I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = MvI2cEnableConf;
128   I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency);
129   I2cMasterContext->BaseAddress = BaseAddress;
130   I2cMasterContext->Bus = Bus;
131   /* I2cMasterContext->Lock is responsible for serializing I2C operations */
132   EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY);
133 
134   MvI2cCalBaudRate( I2cMasterContext,
135                     PcdGet32 (PcdI2cBaudRate),
136                     &baud_rate,
137                     I2cMasterContext->TclkFrequency
138                   );
139 
140   Status = gBS->InstallMultipleProtocolInterfaces(
141       &I2cMasterContext->Controller,
142       &gEfiI2cMasterProtocolGuid,
143       &I2cMasterContext->I2cMaster,
144       &gEfiI2cEnumerateProtocolGuid,
145       &I2cMasterContext->I2cEnumerate,
146       &gEfiI2cBusConfigurationManagementProtocolGuid,
147       &I2cMasterContext->I2cBusConf,
148       &gEfiDevicePathProtocolGuid,
149       (EFI_DEVICE_PATH_PROTOCOL *) DevicePath,
150       NULL);
151 
152   if (EFI_ERROR(Status)) {
153     DEBUG((DEBUG_ERROR, "MvI2cDxe: Installing protocol interfaces failed!\n"));
154     goto fail;
155   }
156   DEBUG((DEBUG_ERROR, "Succesfully installed controller %d at 0x%llx\n", Bus,
157         I2cMasterContext->BaseAddress));
158 
159   Bus++;
160 
161   return EFI_SUCCESS;
162 
163 fail:
164   FreePool(I2cMasterContext);
165   return Status;
166 }
167 
168 EFI_STATUS
169 EFIAPI
MvI2cInitialise(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)170 MvI2cInitialise (
171   IN EFI_HANDLE  ImageHandle,
172   IN EFI_SYSTEM_TABLE  *SystemTable
173   )
174 {
175   EFI_STATUS Status;
176   UINT32 BusCount;
177   EFI_PHYSICAL_ADDRESS I2cBaseAddresses[PcdGet32 (PcdI2cBusCount)];
178   INTN i;
179 
180   BusCount = PcdGet32 (PcdI2cBusCount);
181   if (BusCount == 0)
182     return EFI_SUCCESS;
183 
184   Status = ParsePcdString (
185       (CHAR16 *) PcdGetPtr (PcdI2cBaseAddresses),
186       BusCount,
187       I2cBaseAddresses,
188       NULL
189       );
190   if (EFI_ERROR(Status))
191     return Status;
192 
193   for (i = 0; i < BusCount; i++) {
194     Status = MvI2cInitialiseController(
195         ImageHandle,
196         SystemTable,
197         I2cBaseAddresses[i]
198         );
199     if (EFI_ERROR(Status))
200       return Status;
201   }
202 
203   return Status;
204 }
205 
206 STATIC
207 VOID
MvI2cControlClear(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINT32 Mask)208 MvI2cControlClear (
209   IN I2C_MASTER_CONTEXT *I2cMasterContext,
210   IN UINT32 Mask)
211 {
212   UINT32 Value;
213 
214   /* clears given bits in I2C_CONTROL register */
215   Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
216   Value &= ~Mask;
217   I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
218 }
219 
220 STATIC
221 VOID
MvI2cControlSet(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINT32 Mask)222 MvI2cControlSet (
223   IN I2C_MASTER_CONTEXT *I2cMasterContext,
224   IN UINT32 Mask)
225 {
226   UINT32 Value;
227 
228   /* sets given bits in I2C_CONTROL register */
229   Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
230   Value |= Mask;
231   I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
232 }
233 
234 STATIC
235 VOID
MvI2cClearIflg(IN I2C_MASTER_CONTEXT * I2cMasterContext)236 MvI2cClearIflg (
237  IN I2C_MASTER_CONTEXT *I2cMasterContext
238  )
239 {
240   gBS->Stall(I2C_OPERATION_TIMEOUT);
241   MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG);
242   gBS->Stall(I2C_OPERATION_TIMEOUT);
243 }
244 
245 /* Timeout is given in us */
246 STATIC
247 UINTN
MvI2cPollCtrl(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINTN Timeout,IN UINT32 Mask)248 MvI2cPollCtrl (
249   IN I2C_MASTER_CONTEXT *I2cMasterContext,
250   IN UINTN Timeout,
251   IN UINT32 Mask)
252 {
253   Timeout /= 10;
254   while (!(I2C_READ(I2cMasterContext, I2C_CONTROL) & Mask)) {
255     gBS->Stall(10);
256     if (--Timeout == 0)
257       return (Timeout);
258   }
259   return (0);
260 }
261 
262 /*
263  * 'Timeout' is given in us. Note also that Timeout handling is not exact --
264  * MvI2cLockedStart() total wait can be more than 2 x Timeout
265  * (MvI2cPollCtrl() is called twice). 'Mask' can be either I2C_STATUS_START
266  * or I2C_STATUS_RPTD_START
267  */
268 STATIC
269 EFI_STATUS
MvI2cLockedStart(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN INT32 Mask,IN UINT8 Slave,IN UINTN Timeout)270 MvI2cLockedStart (
271   IN I2C_MASTER_CONTEXT *I2cMasterContext,
272   IN INT32 Mask,
273   IN UINT8 Slave,
274   IN UINTN Timeout
275   )
276 {
277   UINTN ReadAccess, IflgSet = 0;
278   UINT32 I2cStatus;
279 
280   if (Mask == I2C_STATUS_RPTD_START) {
281     /* read IFLG to know if it should be cleared later */
282     IflgSet = I2C_READ(I2cMasterContext, I2C_CONTROL) & I2C_CONTROL_IFLG;
283   }
284 
285   MvI2cControlSet(I2cMasterContext, I2C_CONTROL_START);
286 
287   if (Mask == I2C_STATUS_RPTD_START && IflgSet) {
288     DEBUG((DEBUG_INFO, "MvI2cDxe: IFLG set, clearing\n"));
289     MvI2cClearIflg(I2cMasterContext);
290   }
291 
292   /* Without this delay we Timeout checking IFLG if the Timeout is 0 */
293   gBS->Stall(I2C_OPERATION_TIMEOUT);
294 
295   if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
296     DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending %sSTART condition\n",
297         Mask == I2C_STATUS_START ? "" : "repeated "));
298     return EFI_NO_RESPONSE;
299   }
300 
301   I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
302   if (I2cStatus != Mask) {
303     DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) after sending %sSTART condition\n",
304         I2cStatus, Mask == I2C_STATUS_START ? "" : "repeated "));
305     return EFI_DEVICE_ERROR;
306   }
307 
308   I2C_WRITE(I2cMasterContext, I2C_DATA, Slave);
309   gBS->Stall(I2C_OPERATION_TIMEOUT);
310   MvI2cClearIflg(I2cMasterContext);
311 
312   if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
313     DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending Slave address\n"));
314     return EFI_NO_RESPONSE;
315   }
316 
317   ReadAccess = (Slave & 0x1) ? 1 : 0;
318   I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
319   if (I2cStatus != (ReadAccess ?
320       I2C_STATUS_ADDR_R_ACK : I2C_STATUS_ADDR_W_ACK)) {
321     DEBUG((DEBUG_ERROR, "MvI2cDxe: no ACK (I2cStatus: %02x) after sending Slave address\n",
322         I2cStatus));
323     return EFI_NO_RESPONSE;
324   }
325 
326   return EFI_SUCCESS;
327 }
328 
329 #define  ABSSUB(a,b)  (((a) > (b)) ? (a) - (b) : (b) - (a))
330 STATIC
331 VOID
MvI2cCalBaudRate(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN CONST UINT32 target,IN OUT MV_I2C_BAUD_RATE * rate,UINT32 clk)332 MvI2cCalBaudRate (
333   IN I2C_MASTER_CONTEXT *I2cMasterContext,
334   IN CONST UINT32 target,
335   IN OUT MV_I2C_BAUD_RATE *rate,
336   UINT32 clk
337   )
338 {
339   UINT32 cur, diff, diff0, baud;
340   UINTN m, n, m0, n0;
341 
342   /* Read initial m0, n0 values from register */
343   baud = I2C_READ(I2cMasterContext, I2C_BAUD_RATE);
344   m0 = I2C_M_FROM_BAUD(baud);
345   n0 = I2C_N_FROM_BAUD(baud);
346   /* Calculate baud rate. */
347   diff0 = 0xffffffff;
348 
349   for (n = 0; n < 8; n++) {
350     for (m = 0; m < 16; m++) {
351       cur = I2C_BAUD_RATE_RAW(clk,m,n);
352       diff = ABSSUB(target, cur);
353       if (diff < diff0) {
354         m0 = m;
355         n0 = n;
356         diff0 = diff;
357       }
358     }
359   }
360   rate->raw = I2C_BAUD_RATE_RAW(clk, m0, n0);
361   rate->param = I2C_BAUD_RATE_PARAM(m0, n0);
362   rate->m = m0;
363   rate->n = n0;
364 }
365 
366 EFI_STATUS
367 EFIAPI
MvI2cReset(IN CONST EFI_I2C_MASTER_PROTOCOL * This)368 MvI2cReset (
369   IN CONST EFI_I2C_MASTER_PROTOCOL *This
370   )
371 {
372   UINT32 param;
373   I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
374 
375   param = baud_rate.param;
376 
377   EfiAcquireLock (&I2cMasterContext->Lock);
378   I2C_WRITE(I2cMasterContext, I2C_SOFT_RESET, 0x0);
379   gBS->Stall(2 * I2C_OPERATION_TIMEOUT);
380   I2C_WRITE(I2cMasterContext, I2C_BAUD_RATE, param);
381   I2C_WRITE(I2cMasterContext, I2C_CONTROL, I2C_CONTROL_I2CEN | I2C_CONTROL_ACK);
382   gBS->Stall(I2C_OPERATION_TIMEOUT);
383   EfiReleaseLock (&I2cMasterContext->Lock);
384 
385   return EFI_SUCCESS;
386 }
387 
388 /*
389  * Timeout is given in us
390  */
391 STATIC
392 EFI_STATUS
MvI2cRepeatedStart(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINT8 Slave,IN UINTN Timeout)393 MvI2cRepeatedStart (
394   IN I2C_MASTER_CONTEXT *I2cMasterContext,
395   IN UINT8 Slave,
396   IN UINTN Timeout
397   )
398 {
399   EFI_STATUS Status;
400 
401   EfiAcquireLock (&I2cMasterContext->Lock);
402   Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_RPTD_START, Slave,
403       Timeout);
404   EfiReleaseLock (&I2cMasterContext->Lock);
405 
406   if (EFI_ERROR(Status)) {
407     MvI2cStop(I2cMasterContext);
408   }
409   return Status;
410 }
411 
412 /*
413  * Timeout is given in us
414  */
415 STATIC
416 EFI_STATUS
MvI2cStart(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN UINT8 Slave,IN UINTN Timeout)417 MvI2cStart (
418   IN I2C_MASTER_CONTEXT *I2cMasterContext,
419   IN UINT8 Slave,
420   IN UINTN Timeout
421   )
422 {
423   EFI_STATUS Status;
424 
425   EfiAcquireLock (&I2cMasterContext->Lock);
426   Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_START, Slave, Timeout);
427   EfiReleaseLock (&I2cMasterContext->Lock);
428 
429   if (EFI_ERROR(Status)) {
430     MvI2cStop(I2cMasterContext);
431   }
432   return Status;
433 }
434 
435 STATIC
436 EFI_STATUS
MvI2cStop(IN I2C_MASTER_CONTEXT * I2cMasterContext)437 MvI2cStop (
438   IN I2C_MASTER_CONTEXT *I2cMasterContext
439   )
440 {
441   EfiAcquireLock (&I2cMasterContext->Lock);
442   MvI2cControlSet(I2cMasterContext, I2C_CONTROL_STOP);
443   gBS->Stall(I2C_OPERATION_TIMEOUT);
444   MvI2cClearIflg(I2cMasterContext);
445   EfiReleaseLock (&I2cMasterContext->Lock);
446 
447   return EFI_SUCCESS;
448 }
449 
450 STATIC
451 EFI_STATUS
MvI2cRead(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN OUT UINT8 * Buf,IN UINTN Length,IN OUT UINTN * read,IN UINTN last,IN UINTN delay)452 MvI2cRead (
453   IN I2C_MASTER_CONTEXT *I2cMasterContext,
454   IN OUT UINT8 *Buf,
455   IN UINTN Length,
456   IN OUT UINTN *read,
457   IN UINTN last,
458   IN UINTN delay
459   )
460 {
461   UINT32 I2cStatus;
462   UINTN LastByte;
463   EFI_STATUS Status;
464 
465   EfiAcquireLock (&I2cMasterContext->Lock);
466   *read = 0;
467   while (*read < Length) {
468     /*
469      * Check if we are reading last byte of the last Buffer,
470      * do not send ACK then, per I2C specs
471      */
472     LastByte = ((*read == Length - 1) && last) ? 1 : 0;
473     if (LastByte)
474       MvI2cControlClear(I2cMasterContext, I2C_CONTROL_ACK);
475     else
476       MvI2cControlSet(I2cMasterContext, I2C_CONTROL_ACK);
477 
478     gBS->Stall (I2C_OPERATION_TIMEOUT);
479     MvI2cClearIflg(I2cMasterContext);
480 
481     if (MvI2cPollCtrl(I2cMasterContext, delay, I2C_CONTROL_IFLG)) {
482       DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout reading data\n"));
483       Status = EFI_NO_RESPONSE;
484       goto out;
485     }
486 
487     I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
488     if (I2cStatus != (LastByte ?
489         I2C_STATUS_DATA_RD_NOACK : I2C_STATUS_DATA_RD_ACK)) {
490       DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) while reading\n", I2cStatus));
491       Status = EFI_DEVICE_ERROR;
492       goto out;
493     }
494 
495     *Buf++ = I2C_READ(I2cMasterContext, I2C_DATA);
496     (*read)++;
497   }
498   Status = EFI_SUCCESS;
499 out:
500   EfiReleaseLock (&I2cMasterContext->Lock);
501   return (Status);
502 }
503 
504 STATIC
505 EFI_STATUS
MvI2cWrite(IN I2C_MASTER_CONTEXT * I2cMasterContext,IN OUT CONST UINT8 * Buf,IN UINTN Length,IN OUT UINTN * Sent,IN UINTN Timeout)506 MvI2cWrite (
507   IN I2C_MASTER_CONTEXT *I2cMasterContext,
508   IN OUT CONST UINT8 *Buf,
509   IN UINTN Length,
510   IN OUT UINTN *Sent,
511   IN UINTN Timeout
512   )
513 {
514   UINT32 status;
515   EFI_STATUS Status;
516 
517   EfiAcquireLock (&I2cMasterContext->Lock);
518   *Sent = 0;
519   while (*Sent < Length) {
520     I2C_WRITE(I2cMasterContext, I2C_DATA, *Buf++);
521 
522     MvI2cClearIflg(I2cMasterContext);
523     if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
524       DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout writing data\n"));
525       Status = EFI_NO_RESPONSE;
526       goto out;
527     }
528 
529     status = I2C_READ(I2cMasterContext, I2C_STATUS);
530     if (status != I2C_STATUS_DATA_WR_ACK) {
531       DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong status (%02x) while writing\n", status));
532       Status = EFI_DEVICE_ERROR;
533       goto out;
534     }
535     (*Sent)++;
536   }
537   Status = EFI_SUCCESS;
538 out:
539   EfiReleaseLock (&I2cMasterContext->Lock);
540   return (Status);
541 }
542 
543 /*
544  * MvI2cStartRequest should be called only by I2cHost.
545  * I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead.
546  */
547 STATIC
548 EFI_STATUS
MvI2cStartRequest(IN CONST EFI_I2C_MASTER_PROTOCOL * This,IN UINTN SlaveAddress,IN EFI_I2C_REQUEST_PACKET * RequestPacket,IN EFI_EVENT Event OPTIONAL,OUT EFI_STATUS * I2cStatus OPTIONAL)549 MvI2cStartRequest (
550   IN CONST EFI_I2C_MASTER_PROTOCOL *This,
551   IN UINTN                         SlaveAddress,
552   IN EFI_I2C_REQUEST_PACKET        *RequestPacket,
553   IN EFI_EVENT                     Event      OPTIONAL,
554   OUT EFI_STATUS                   *I2cStatus OPTIONAL
555   )
556 {
557   UINTN Count;
558   UINTN ReadMode;
559   UINTN Transmitted;
560   I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
561   EFI_I2C_OPERATION *Operation;
562 
563   ASSERT (RequestPacket != NULL);
564   ASSERT (I2cMasterContext != NULL);
565 
566   for (Count = 0; Count < RequestPacket->OperationCount; Count++) {
567     Operation = &RequestPacket->Operation[Count];
568     ReadMode = Operation->Flags & I2C_FLAG_READ;
569 
570     if (Count == 0) {
571       MvI2cStart ( I2cMasterContext,
572                    (SlaveAddress << 1) | ReadMode,
573                    I2C_TRANSFER_TIMEOUT
574                  );
575     } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) {
576       MvI2cRepeatedStart ( I2cMasterContext,
577                            (SlaveAddress << 1) | ReadMode,
578                            I2C_TRANSFER_TIMEOUT
579                          );
580     }
581 
582     if (ReadMode) {
583       MvI2cRead ( I2cMasterContext,
584                   Operation->Buffer,
585                   Operation->LengthInBytes,
586                   &Transmitted,
587                   Count == 1,
588                   I2C_TRANSFER_TIMEOUT
589                  );
590     } else {
591       MvI2cWrite ( I2cMasterContext,
592                    Operation->Buffer,
593                    Operation->LengthInBytes,
594                    &Transmitted,
595                    I2C_TRANSFER_TIMEOUT
596                   );
597     }
598     if (Count == RequestPacket->OperationCount - 1) {
599       MvI2cStop ( I2cMasterContext );
600     }
601   }
602 
603   if (I2cStatus != NULL)
604     I2cStatus = EFI_SUCCESS;
605   if (Event != NULL)
606     gBS->SignalEvent(Event);
607   return EFI_SUCCESS;
608 }
609 
610 STATIC CONST EFI_GUID DevGuid = I2C_GUID;
611 
612 #define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
613 #define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff)
614 
615 STATIC
616 EFI_STATUS
MvI2cAllocDevice(IN UINT8 SlaveAddress,IN UINT8 Bus,IN OUT CONST EFI_I2C_DEVICE ** Device)617 MvI2cAllocDevice (
618   IN UINT8 SlaveAddress,
619   IN UINT8 Bus,
620   IN OUT CONST EFI_I2C_DEVICE **Device
621   )
622 {
623   EFI_STATUS Status;
624   EFI_I2C_DEVICE *Dev;
625   UINT32 *TmpSlaveArray;
626   EFI_GUID *TmpGuidP;
627 
628   Status = gBS->AllocatePool ( EfiBootServicesData,
629              sizeof(EFI_I2C_DEVICE),
630              (VOID **) &Dev );
631   if (EFI_ERROR(Status)) {
632     DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device memory allocation failed\n"));
633     return Status;
634   }
635   *Device = Dev;
636   Dev->DeviceIndex = SlaveAddress;
637   Dev->DeviceIndex = I2C_DEVICE_INDEX(Bus, SlaveAddress);
638   Dev->SlaveAddressCount = 1;
639   Dev->I2cBusConfiguration = 0;
640   Status = gBS->AllocatePool ( EfiBootServicesData,
641              sizeof(UINT32),
642              (VOID **) &TmpSlaveArray);
643   if (EFI_ERROR(Status)) {
644     goto fail1;
645   }
646   TmpSlaveArray[0] = SlaveAddress;
647   Dev->SlaveAddressArray = TmpSlaveArray;
648 
649   Status = gBS->AllocatePool ( EfiBootServicesData,
650              sizeof(EFI_GUID),
651              (VOID **) &TmpGuidP);
652   if (EFI_ERROR(Status)) {
653     goto fail2;
654   }
655   *TmpGuidP = DevGuid;
656   Dev->DeviceGuid = TmpGuidP;
657 
658   DEBUG((DEBUG_INFO, "MvI2c: allocated device with address %x\n", (UINTN)SlaveAddress));
659   return EFI_SUCCESS;
660 
661 fail2:
662   FreePool(TmpSlaveArray);
663 fail1:
664   FreePool(Dev);
665 
666   return Status;
667 }
668 
669 /*
670  * It is called by I2cBus to enumerate devices on I2C bus. In this case,
671  * enumeration is based on PCD configuration - all Slave addresses specified
672  * in PCD get their corresponding EFI_I2C_DEVICE structures here.
673  *
674  * After enumeration succeeds, Supported() function of drivers that installed
675  * DriverBinding protocol is called.
676  */
677 STATIC
678 EFI_STATUS
679 EFIAPI
MvI2cEnumerate(IN CONST EFI_I2C_ENUMERATE_PROTOCOL * This,IN OUT CONST EFI_I2C_DEVICE ** Device)680 MvI2cEnumerate (
681   IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
682   IN OUT CONST EFI_I2C_DEVICE         **Device
683   )
684 {
685   UINT8 *DevicesPcd;
686   UINT8 *DeviceBusPcd;
687   UINTN Index, NextIndex, DevCount;
688   UINT8 NextDeviceAddress;
689   I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_ENUMERATE(This);
690 
691   DevCount = PcdGetSize (PcdI2cSlaveAddresses);
692   DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses);
693   DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses);
694   if (*Device == NULL) {
695     for (Index = 0; Index < DevCount ; Index++) {
696       if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
697         continue;
698       if (Index < DevCount)
699         MvI2cAllocDevice (DevicesPcd[Index], I2cMasterContext->Bus, Device);
700       return EFI_SUCCESS;
701     }
702   } else {
703     /* Device is not NULL, so something was already allocated */
704     for (Index = 0; Index < DevCount; Index++) {
705       if (DeviceBusPcd[Index] != I2cMasterContext->Bus)
706         continue;
707       if (DevicesPcd[Index] == I2C_DEVICE_ADDRESS((*Device)->DeviceIndex)) {
708         for (NextIndex = Index + 1; NextIndex < DevCount; NextIndex++) {
709           if (DeviceBusPcd[NextIndex] != I2cMasterContext->Bus)
710             continue;
711           NextDeviceAddress = DevicesPcd[NextIndex];
712           if (NextIndex < DevCount)
713             MvI2cAllocDevice(NextDeviceAddress, I2cMasterContext->Bus, Device);
714           return EFI_SUCCESS;
715         }
716       }
717     }
718     *Device = NULL;
719     return EFI_SUCCESS;
720   }
721   return EFI_SUCCESS;
722 }
723 
724 STATIC
725 EFI_STATUS
726 EFIAPI
MvI2cEnableConf(IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL * This,IN UINTN I2cBusConfiguration,IN EFI_EVENT Event OPTIONAL,IN EFI_STATUS * I2cStatus OPTIONAL)727 MvI2cEnableConf (
728   IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
729   IN UINTN                                               I2cBusConfiguration,
730   IN EFI_EVENT                                           Event      OPTIONAL,
731   IN EFI_STATUS                                          *I2cStatus OPTIONAL
732   )
733 {
734   /* do nothing */
735   if (I2cStatus != NULL)
736     I2cStatus = EFI_SUCCESS;
737   if (Event != NULL)
738     gBS->SignalEvent(Event);
739   return EFI_SUCCESS;
740 }
741