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