1 /** @file
2   I2C PEI Lib Instance.
3 
4   Copyright (c) 1999- 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "I2CDelayPei.h"
16 #include "I2CIoLibPei.h"
17 #include "I2CAccess.h"
18 #include "I2CLibPei.h"
19 #include <PlatformBaseAddresses.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/PeiServicesTablePointerLib.h>
23 #include <Library/HobLib.h>
24 #include <PchRegs/PchRegsPcu.h>
25 #include <PchRegs/PchRegsLpss.h>
26 
27 #define LPSS_PCI_DEVICE_NUMBER  8
28 
29 #define R_PCH_LPIO_I2C_MEM_RESETS                 0x804 // Software Reset
30 #define B_PCH_LPIO_I2C_MEM_RESETS_FUNC            BIT1  // Function Clock Domain Reset
31 #define B_PCH_LPIO_I2C_MEM_RESETS_APB             BIT0  // APB Domain Reset
32 #define R_PCH_LPSS_I2C_MEM_PCP                    0x800 // Private Clock Parameters
33 
34 #define PEI_TEPM_LPSS_DMA_BAR                     0xFE900000
35 #define PEI_TEPM_LPSS_I2C0_BAR                    0xFE910000
36 #define PCI_CONFIG_SPACE_SIZE                     0x10000
37 
38 EFI_GUID  mI2CPeiInitGuid = {
39   0x96DED71A, 0xB9E7, 0x4EAD, 0x96, 0x2C, 0x01, 0x69, 0x3C, 0xED, 0x2A, 0x64
40 };
41 
42 
43 UINT16 I2CGPIO[]= {
44   //
45   // 19.1.6  I2C0
46   // I2C0_SDA-OD-O -    write 0x2003CC81 to IOBASE + 0x0210
47   // I2C0_SCL-OD-O -    write 0x2003CC81 to IOBASE + 0x0200
48   //
49   0x0210,
50   0x0200,
51 
52   //
53   // 19.1.7  I2C1
54   // I2C1_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01F0
55   // I2C1_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01E0
56   //
57   0x01F0,
58   0x01E0,
59 
60   //
61   // 19.1.8  I2C2
62   // I2C2_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01D0
63   // I2C2_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01B0
64   //
65   0x01D0,
66   0x01B0,
67 
68   //
69   // 19.1.9  I2C3
70   // I2C3_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0190
71   // I2C3_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x01C0
72   //
73   0x0190,
74   0x01C0,
75 
76   //
77   // 19.1.10 I2C4
78   // I2C4_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x01A0
79   // I2C4_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x0170
80   //
81   0x01A0,
82   0x0170,
83 
84   //
85   // 19.1.11 I2C5
86   // I2C5_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0150
87   // I2C5_SCL-OD-O/I - write 0x2003CC81 to IOBASE + 0x0140
88   //
89   0x0150,
90   0x0140,
91 
92   //
93   // 19.1.12 I2C6
94   // I2C6_SDA-OD-O/I - write 0x2003CC81 to IOBASE + 0x0180
95   // I2C6_SCL-OD-O/I -  write 0x2003CC81 to IOBASE + 0x0160
96   //
97   0x0180,
98   0x0160
99 };
100 
101 /**
102   Constructor of this library.
103 
104   @param   VOID
105 
106   @return  EFI_SUCCESS
107 **/
108 EFI_STATUS
109 EFIAPI
IntelI2CPeiLibConstructor(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)110 IntelI2CPeiLibConstructor (
111   IN EFI_PEI_FILE_HANDLE     FileHandle,
112   IN CONST EFI_PEI_SERVICES  **PeiServices
113   )
114 {
115   UINTN Index;
116 
117   for (Index = 0; Index < sizeof(I2CGPIO)/sizeof(UINT16); Index ++) {
118     I2CLibPeiMmioWrite32(IO_BASE_ADDRESS+I2CGPIO[Index], 0x2003CC81);
119   }
120 
121   return EFI_SUCCESS;
122 }
123 
124 /**
125   Programe all I2C controllers on LPSS.
126 
127   I2C0 is function 1 of LPSS. I2C1 is function 2 of LPSS, etc..
128 
129   @param   VOID
130 
131   @return  EFI_SUCCESS
132 **/
133 EFI_STATUS
ProgramPciLpssI2C(VOID)134 ProgramPciLpssI2C (
135   VOID
136   )
137 {
138   UINT32       PmcBase;
139   UINT32       DevID;
140   UINTN        PciMmBase=0;
141   UINTN        Index;
142   UINTN        Bar0;
143   UINTN        Bar1;
144   DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() Start\n"));
145 
146   //
147   // Set the VLV Function Disable Register to ZERO
148   //
149   PmcBase         = I2CLibPeiMmioRead32(PciD31F0RegBase + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR;
150 
151   if(I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)&
152       (B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2
153        | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5
154        | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7)) {
155     I2CLibPeiMmioWrite32(
156       PmcBase+R_PCH_PMC_FUNC_DIS,
157       I2CLibPeiMmioRead32(PmcBase + R_PCH_PMC_FUNC_DIS)& \
158       ~(B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2 \
159         | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4 \
160         | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5 | B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6|B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7)
161       );
162     DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() enable all I2C controllers\n"));
163   }
164 
165   for(Index = 0; Index < LPSS_PCI_DEVICE_NUMBER; Index ++) {
166 
167     PciMmBase = MmPciAddress (
168                   0,
169                   DEFAULT_PCI_BUS_NUMBER_PCH,
170                   PCI_DEVICE_NUMBER_PCH_LPSS_I2C,
171                   Index,
172                   0
173                   );
174     DevID =  I2CLibPeiMmioRead32(PciMmBase);
175 
176     Bar0 = PEI_TEPM_LPSS_DMA_BAR + (Index * PCI_CONFIG_SPACE_SIZE);
177     Bar1 = Bar0 + 0x8000;
178 
179     DEBUG((EFI_D_ERROR, "Program Pci Lpss I2C Device  Function=%x DevID=%08x\n", Index, DevID));
180 
181     //
182     // Check if device present
183     //
184     if (DevID  != 0xFFFFFFFF)  {
185       if(!(I2CLibPeiMmioRead32 (PciMmBase + R_PCH_LPSS_I2C_STSCMD) & B_PCH_LPSS_I2C_STSCMD_MSE)) {
186         //
187         // Program BAR 0
188         //
189         I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR), (UINT32)(Bar0 & B_PCH_LPSS_I2C_BAR_BA));
190 
191         DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR)));
192 
193         //
194         // Program BAR 1
195         //
196         I2CLibPeiMmioWrite32 ((UINTN)(PciMmBase + R_PCH_LPSS_I2C_BAR1), (UINT32)(Bar1 & B_PCH_LPSS_I2C_BAR1_BA));
197         DEBUG ((EFI_D_ERROR, "I2CBaseAddress1 = 0x%x \n",I2CLibPeiMmioRead32(PciMmBase+R_PCH_LPSS_I2C_BAR1)));
198 
199         //
200         // Bus Master Enable & Memory Space Enable
201         //
202         I2CLibPeiMmioWrite32((UINTN) (PciMmBase + R_PCH_LPSS_I2C_STSCMD), (UINT32)(B_PCH_LPSS_I2C_STSCMD_BME | B_PCH_LPSS_I2C_STSCMD_MSE));
203       }
204 
205       //
206       // Release Resets
207       //
208       I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPIO_I2C_MEM_RESETS, (B_PCH_LPIO_I2C_MEM_RESETS_FUNC | B_PCH_LPIO_I2C_MEM_RESETS_APB));
209 
210       //
211       // Activate Clocks
212       //
213       I2CLibPeiMmioWrite32 (Bar0 + R_PCH_LPSS_I2C_MEM_PCP, 0x80020003);//No use for A0
214 
215       DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Programmed()\n"));
216     }
217 
218   }
219 
220   DEBUG ((EFI_D_INFO, "Pei ProgramPciLpssI2C() End\n"));
221 
222   return EFI_SUCCESS;
223 }
224 
225 /**
226   Disable I2C Bus.
227 
228   @param I2cControllerIndex   Index of I2C controller.
229 
230   @return EFI_SUCCESS
231 **/
232 EFI_STATUS
I2cDisable(IN UINT8 I2cControllerIndex)233 I2cDisable (
234   IN UINT8 I2cControllerIndex
235   )
236 {
237   UINTN  I2CBaseAddress;
238   UINT32 NumTries = 10000;  // 0.1 seconds
239 
240   I2CBaseAddress = (UINT32) PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE;
241 
242   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 0);
243   while (0 != ( I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_ENABLE_STATUS ) & 1)) {
244     MicroSecondDelay (10);
245     NumTries --;
246     if(0 == NumTries) return EFI_NOT_READY;
247   }
248 
249   return EFI_SUCCESS;
250 }
251 
252 /**
253   Enable I2C Bus.
254 
255   @param I2cControllerIndex   Index of I2C controller.
256 
257   @return EFI_SUCCESS
258 **/
259 EFI_STATUS
I2cEnable(IN UINT8 I2cControllerIndex)260 I2cEnable (
261   IN UINT8 I2cControllerIndex
262   )
263 {
264   UINTN   I2CBaseAddress;
265   UINT32 NumTries = 10000;  // 0.1 seconds
266 
267   I2CBaseAddress = (UINT32) PEI_TEPM_LPSS_I2C0_BAR+ I2cControllerIndex * PCI_CONFIG_SPACE_SIZE;
268   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_ENABLE, 1);
269   while (0 == ( I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_ENABLE_STATUS ) & 1)) {
270     MicroSecondDelay (10);
271     NumTries --;
272     if(0 == NumTries) return EFI_NOT_READY;
273   }
274 
275   return EFI_SUCCESS;
276 }
277 
278 
279 /**
280   Set the I2C controller bus clock frequency.
281 
282   @param[in] This           Address of the library's I2C context structure
283   @param[in] PlatformData   Address of the platform configuration data
284   @param[in] BusClockHertz  New I2C bus clock frequency in Hertz
285 
286   @retval RETURN_SUCCESS      The bus frequency was set successfully.
287   @retval RETURN_UNSUPPORTED  The controller does not support this frequency.
288 
289 **/
290 EFI_STATUS
I2cBusFrequencySet(IN UINTN I2CBaseAddress,IN UINTN BusClockHertz,IN UINT16 * I2cMode)291 I2cBusFrequencySet (
292   IN UINTN   I2CBaseAddress,
293   IN UINTN   BusClockHertz,
294   IN UINT16  *I2cMode
295   )
296 {
297   DEBUG((EFI_D_INFO,"InputFreq BusClockHertz: %d\r\n",BusClockHertz));
298 
299   *I2cMode = B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE;
300 
301   //
302   //  Set the 100 KHz clock divider
303   //
304   //  From Table 10 of the I2C specification
305   //
306   //    High: 4.00 uS
307   //    Low:  4.70 uS
308   //
309   I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_HCNT, (UINT16)0x214 );
310   I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_SS_SCL_LCNT, (UINT16)0x272 );
311 
312   //
313   //    Set the 400 KHz clock divider
314   //
315   //    From Table 10 of the I2C specification
316   //
317   //      High: 0.60 uS
318   //      Low:  1.30 uS
319   //
320   I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_HCNT, (UINT16)0x50 );
321   I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_FS_SCL_LCNT, (UINT16)0xAD );
322 
323   switch ( BusClockHertz ) {
324     case 100 * 1000:
325       I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x40);//100K
326       *I2cMode |= V_SPEED_STANDARD;
327       break;
328     case 400 * 1000:
329       I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x32);//400K
330       *I2cMode |= V_SPEED_FAST;
331       break;
332     default:
333       I2CLibPeiMmioWrite32 ( I2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x09);//3.4M
334       *I2cMode |= V_SPEED_HIGH;
335   }
336 
337   return EFI_SUCCESS;
338 }
339 
340 /**
341   Initializes the host controller to execute I2C commands.
342 
343   @param I2cControllerIndex Index of I2C controller in LPSS device. 0 represents I2C0, which is PCI function 1 of LPSS device.
344 
345   @return EFI_SUCCESS       Opcode initialization on the I2C host controller completed.
346   @return EFI_DEVICE_ERROR  Device error, operation failed.
347 **/
348 EFI_STATUS
I2CInit(UINT8 I2cControllerIndex,UINT16 SlaveAddress)349 I2CInit (
350   UINT8 I2cControllerIndex,
351   UINT16 SlaveAddress
352   )
353 {
354   EFI_STATUS   Status;
355   UINT32       NumTries = 0;
356   UINTN        I2CBaseAddress;
357   UINT16       I2cMode;
358   UINTN        PciMmBase=0;
359 
360 
361   PciMmBase = MmPciAddress (
362                 0,
363                 DEFAULT_PCI_BUS_NUMBER_PCH,
364                 PCI_DEVICE_NUMBER_PCH_LPSS_I2C,
365                 (I2cControllerIndex + 1),
366                 0
367                 );
368 
369   I2CBaseAddress = I2CLibPeiMmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR);
370 
371   //
372   //  Verify the parameters
373   //
374   if (1023 < SlaveAddress ) {
375     Status =  EFI_INVALID_PARAMETER;
376     DEBUG((EFI_D_INFO,"I2cStartRequest Exit with Status %r\r\n", Status));
377     return Status;
378   }
379 
380   if(I2CBaseAddress ==  (PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE)) {
381     return EFI_SUCCESS;
382   }
383   ProgramPciLpssI2C();
384 
385   I2CBaseAddress = (UINT32) (PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE);
386   DEBUG ((EFI_D_ERROR, "I2CBaseAddress = 0x%x \n",I2CBaseAddress));
387   NumTries = 10000; // 1 seconds
388   while ((1 == ( I2CLibPeiMmioRead32 ( I2CBaseAddress + R_IC_STATUS) & STAT_MST_ACTIVITY ))) {
389     MicroSecondDelay(10);
390     NumTries --;
391     if(0 == NumTries)
392       return EFI_DEVICE_ERROR;
393   }
394 
395   Status = I2cDisable (I2cControllerIndex);
396   DEBUG((EFI_D_INFO, "I2cDisable Status = %r\r\n", Status));
397 
398   I2cBusFrequencySet(I2CBaseAddress, 400 * 1000, &I2cMode);//Set I2cMode
399 
400   I2CLibPeiMmioWrite16(I2CBaseAddress + R_IC_INTR_MASK, 0x0);
401   if (0x7F < SlaveAddress) {
402     SlaveAddress = (SlaveAddress & 0x3ff ) | IC_TAR_10BITADDR_MASTER;
403   }
404   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TAR, (UINT16) SlaveAddress );
405   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_RX_TL, 0);
406   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_TX_TL, 0 );
407   I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_CON, I2cMode);
408 
409   Status = I2cEnable(I2cControllerIndex);
410   DEBUG((EFI_D_INFO, "I2cEnable Status = %r\r\n", Status));
411   I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_CLR_TX_ABRT );
412 
413   return EFI_SUCCESS;
414 }
415 
416 /**
417   Reads a Byte from I2C Device.
418 
419   @param  I2cControllerIndex  I2C Bus no to which the I2C device has been connected
420   @param  SlaveAddress        Device Address from which the byte value has to be read
421   @param  Offset              Offset from which the data has to be read
422   @param  *Byte               Address to which the value read has to be stored
423 
424   @return  EFI_SUCCESS        If the byte value has been successfully read
425   @return  EFI_DEVICE_ERROR   Operation Failed, Device Error
426 **/
ByteReadI2CBasic(IN UINT8 I2cControllerIndex,IN UINT8 SlaveAddress,IN UINTN ReadBytes,OUT UINT8 * ReadBuffer,IN UINT8 Start,IN UINT8 End)427 EFI_STATUS ByteReadI2CBasic(
428   IN  UINT8 I2cControllerIndex,
429   IN  UINT8 SlaveAddress,
430   IN  UINTN ReadBytes,
431   OUT UINT8 *ReadBuffer,
432   IN  UINT8 Start,
433   IN  UINT8 End
434   )
435 {
436 
437   EFI_STATUS Status;
438   UINT32 I2cStatus;
439   UINT16 ReceiveData;
440   UINT8 *ReceiveDataEnd;
441   UINT8 *ReceiveRequest;
442   UINT16 RawIntrStat;
443   UINTN   I2CBaseAddress;
444 
445   I2CBaseAddress = (UINT32)(PEI_TEPM_LPSS_I2C0_BAR + I2cControllerIndex * PCI_CONFIG_SPACE_SIZE);
446 
447   Status = EFI_SUCCESS;
448 
449   I2CInit(I2cControllerIndex, SlaveAddress);
450 
451   ReceiveDataEnd = &ReadBuffer [ReadBytes];
452   if(ReadBytes) {
453     ReceiveRequest = ReadBuffer;
454     DEBUG((EFI_D_INFO,"Read: ---------------%d bytes to RX\r\n",ReceiveDataEnd - ReceiveRequest));
455 
456     while ((ReceiveDataEnd > ReceiveRequest) || (ReceiveDataEnd > ReadBuffer)) {
457       //
458       // Check for NACK
459       //
460       RawIntrStat = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RawIntrStat );
461       if ( 0 != (RawIntrStat & I2C_INTR_TX_ABRT )) {
462         I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_CLR_TX_ABRT );
463         Status = RETURN_DEVICE_ERROR;
464         DEBUG((EFI_D_INFO,"TX ABRT ,%d bytes hasn't been transferred\r\n",ReceiveDataEnd - ReceiveRequest));
465         break;
466       }
467 
468       //
469       // Determine if another byte was received
470       //
471       I2cStatus = I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_STATUS );
472       if ( 0 != ( I2cStatus & STAT_RFNE )) {
473         ReceiveData = I2CLibPeiMmioRead16 ( I2CBaseAddress + R_IC_DATA_CMD );
474         *ReadBuffer++ = (UINT8)ReceiveData;
475         DEBUG((EFI_D_INFO,"MmioRead32 ,1 byte 0x:%x is received\r\n",ReceiveData));
476       }
477 
478       if(ReceiveDataEnd==ReceiveRequest) {
479         //
480         // Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE.
481         //
482         continue;
483       }
484 
485       //
486       // Wait until a read request will fit
487       //
488       if ( 0 == ( I2cStatus & STAT_TFNF )) {
489         MicroSecondDelay ( 10 );
490         continue;
491       }
492 
493       //
494       // Issue the next read request
495       //
496       if(End && Start ) {
497         I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART|B_CMD_STOP);
498       } else if (!End && Start ) {
499         I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART);
500       } else if (End && !Start ) {
501         I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_STOP);
502       } else if (!End && !Start ) {
503         I2CLibPeiMmioWrite16 ( I2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD);
504       }
505       ReceiveRequest += 1;
506     }
507 
508   }
509   return Status;
510 
511 }
512 
513 /**
514   Writes a Byte to I2C Device.
515 
516   @param  I2cControllerIndex   I2C Bus no to which the I2C device has been connected
517   @param  SlaveAddress         Device Address from which the byte value has to be written
518   @param  Offset               Offset from which the data has to be read
519   @param  *Byte                Address to which the value written is stored
520 
521   @return  EFI_SUCCESS         IF the byte value has been successfully written
522   @return  EFI_DEVICE_ERROR    Operation Failed, Device Error
523 **/
524 EFI_STATUS
ByteWriteI2CBasic(IN UINT8 I2cControllerIndex,IN UINT8 SlaveAddress,IN UINTN WriteBytes,IN UINT8 * WriteBuffer,IN UINT8 Start,IN UINT8 End)525 ByteWriteI2CBasic(
526   IN  UINT8 I2cControllerIndex,
527   IN  UINT8 SlaveAddress,
528   IN  UINTN WriteBytes,
529   IN  UINT8 *WriteBuffer,
530   IN  UINT8 Start,
531   IN  UINT8 End
532   )
533 {
534 
535   EFI_STATUS Status;
536   UINT32 I2cStatus;
537   UINT8 *TransmitEnd;
538   UINT16 RawIntrStat;
539   UINTN   I2CBaseAddress;
540 
541   I2CBaseAddress = (UINT32)PEI_TEPM_LPSS_I2C0_BAR+ I2cControllerIndex * PCI_CONFIG_SPACE_SIZE;
542 
543   Status = EFI_SUCCESS;
544 
545   I2CInit(I2cControllerIndex, SlaveAddress);
546 
547   TransmitEnd = &WriteBuffer [WriteBytes];
548   if( WriteBytes ) {
549 
550     DEBUG((EFI_D_INFO,"Write: --------------%d bytes to TX\r\n", TransmitEnd - WriteBuffer));
551 
552     while ( TransmitEnd > WriteBuffer) {
553       I2cStatus = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_STATUS);
554       RawIntrStat = I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_RawIntrStat);
555       if ( 0 != (RawIntrStat & I2C_INTR_TX_ABRT)) {
556         I2CLibPeiMmioRead16 (I2CBaseAddress + R_IC_CLR_TX_ABRT);
557         Status = RETURN_DEVICE_ERROR;
558         DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer));
559         break;
560       }
561       if (0 == ( I2cStatus & STAT_TFNF)) {
562         continue;
563       }
564       if(End && Start) {
565         I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_RESTART | B_CMD_STOP);
566       } else if (!End && Start ) {
567         I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_RESTART);
568       } else if (End && !Start ) {
569         I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++) | B_CMD_STOP);
570       } else if (!End && !Start ) {
571         I2CLibPeiMmioWrite16 (I2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++));
572       }
573 
574       // Add a small delay to work around some odd behavior being seen.  Without this delay bytes get dropped.
575       MicroSecondDelay ( FIFO_WRITE_DELAY );
576     }
577 
578   }
579 
580   if(EFI_ERROR(Status)) {
581     DEBUG((EFI_D_INFO,"I2cStartRequest Exit with Status %r\r\n",Status));
582   }
583 
584   return Status;
585 }
586 
587 /**
588   Reads a Byte from I2C Device.
589 
590   @param  I2cControllerIndex   I2C Bus no to which the I2C device has been connected
591   @param  SlaveAddress         Device Address from which the byte value has to be read
592   @param  Offset               Offset from which the data has to be read
593   @param  ReadBytes            Number of bytes to be read
594   @param  *ReadBuffer          Address to which the value read has to be stored
595 
596   @return  EFI_SUCCESS       IF the byte value has been successfully read
597   @return  EFI_DEVICE_ERROR  Operation Failed, Device Error
598 **/
599 EFI_STATUS
ByteReadI2C(IN UINT8 I2cControllerIndex,IN UINT8 SlaveAddress,IN UINT8 Offset,IN UINTN ReadBytes,OUT UINT8 * ReadBuffer)600 ByteReadI2C(
601   IN  UINT8 I2cControllerIndex,
602   IN  UINT8 SlaveAddress,
603   IN  UINT8 Offset,
604   IN  UINTN ReadBytes,
605   OUT UINT8 *ReadBuffer
606   )
607 {
608   EFI_STATUS        Status;
609 
610   DEBUG ((EFI_D_ERROR, "ByteReadI2C:---offset:0x%x\n",Offset));
611   Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress, 1, &Offset,TRUE,FALSE);
612   Status = ByteReadI2CBasic(I2cControllerIndex, SlaveAddress, ReadBytes, ReadBuffer, TRUE, TRUE);
613 
614   return Status;
615 }
616 
617 /**
618   Writes a Byte to I2C Device.
619 
620   @param  I2cControllerIndex  I2C Bus no to which the I2C device has been connected
621   @param  SlaveAddress        Device Address from which the byte value has to be written
622   @param  Offset              Offset from which the data has to be written
623   @param  WriteBytes          Number of bytes to be written
624   @param  *Byte               Address to which the value written is stored
625 
626   @return  EFI_SUCCESS       IF the byte value has been successfully read
627   @return  EFI_DEVICE_ERROR  Operation Failed, Device Error
628 **/
ByteWriteI2C(IN UINT8 I2cControllerIndex,IN UINT8 SlaveAddress,IN UINT8 Offset,IN UINTN WriteBytes,IN UINT8 * WriteBuffer)629 EFI_STATUS ByteWriteI2C(
630   IN  UINT8 I2cControllerIndex,
631   IN  UINT8 SlaveAddress,
632   IN  UINT8 Offset,
633   IN  UINTN WriteBytes,
634   IN  UINT8 *WriteBuffer
635   )
636 {
637   EFI_STATUS        Status;
638 
639   DEBUG ((EFI_D_ERROR, "ByteWriteI2C:---offset/bytes/buf:0x%x,0x%x,0x%x,0x%x\n",Offset,WriteBytes,WriteBuffer,*WriteBuffer));
640   Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress, 1, &Offset, TRUE, FALSE);
641   Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress, WriteBytes, WriteBuffer, FALSE, TRUE);
642 
643   return Status;
644 }
645