]> git.proxmox.com Git - mirror_edk2.git/blame - Vlv2TbltDevicePkg/Library/I2CLibDxe/I2CLib.c
EmbeddedPkg/MmcDxe: invoke SetIos() protocol method to set speed and width
[mirror_edk2.git] / Vlv2TbltDevicePkg / Library / I2CLibDxe / I2CLib.c
CommitLineData
4e522096
DW
1/** @file\r
2 Functions for accessing I2C registers.\r
3 \r
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
5 \r
6 This program and the accompanying materials are licensed and made available under\r
7 the terms and conditions of the BSD License that accompanies this distribution. \r
8 The full text of the license may be found at \r
9 http://opensource.org/licenses/bsd-license.php. \r
10 \r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13 \r
14--*/\r
15\r
16#include <Library/DebugLib.h>\r
17#include <Library/TimerLib.h>\r
18#include <PchRegs/PchRegsPcu.h> \r
19#include <PchRegs.h>\r
20#include <PlatformBaseAddresses.h>\r
21#include <PchRegs/PchRegsLpss.h> \r
22#include <Library/I2CLib.h>\r
23#include <Protocol/GlobalNvsArea.h>\r
24#include <Library/UefiBootServicesTableLib.h>\r
25#include <I2CRegs.h>\r
26\r
27#define GLOBAL_NVS_OFFSET(Field) (UINTN)((CHAR8*)&((EFI_GLOBAL_NVS_AREA*)0)->Field - (CHAR8*)0)\r
28\r
29#define PCIEX_BASE_ADDRESS 0xE0000000\r
30#define PCI_EXPRESS_BASE_ADDRESS ((VOID *) (UINTN) PCIEX_BASE_ADDRESS)\r
31#define MmPciAddress( Segment, Bus, Device, Function, Register ) \\r
32 ((UINTN)PCI_EXPRESS_BASE_ADDRESS + \\r
33 (UINTN)(Bus << 20) + \\r
34 (UINTN)(Device << 15) + \\r
35 (UINTN)(Function << 12) + \\r
36 (UINTN)(Register) \\r
37 )\r
38#define PCI_D31F0_REG_BASE PCIEX_BASE_ADDRESS + (UINT32) (31 << 15)\r
39\r
40typedef struct _LPSS_PCI_DEVICE_INFO {\r
41 UINTN Segment;\r
42 UINTN BusNum;\r
43 UINTN DeviceNum;\r
44 UINTN FunctionNum;\r
45 UINTN Bar0;\r
46 UINTN Bar1;\r
47} LPSS_PCI_DEVICE_INFO;\r
48\r
49LPSS_PCI_DEVICE_INFO mLpssPciDeviceList[] = {\r
50 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_DMAC1, PCI_FUNCTION_NUMBER_PCH_LPSS_DMAC, 0xFE900000, 0xFE908000},\r
51 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C0, 0xFE910000, 0xFE918000},\r
52 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C1, 0xFE920000, 0xFE928000},\r
53 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C2, 0xFE930000, 0xFE938000},\r
54 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C3, 0xFE940000, 0xFE948000},\r
55 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C4, 0xFE950000, 0xFE958000},\r
56 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C5, 0xFE960000, 0xFE968000},\r
57 {0, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPSS_I2C, PCI_FUNCTION_NUMBER_PCH_LPSS_I2C6, 0xFE970000, 0xFE978000}\r
58};\r
59\r
60#define LPSS_PCI_DEVICE_NUMBER sizeof(mLpssPciDeviceList)/sizeof(LPSS_PCI_DEVICE_INFO)\r
61\r
62STATIC UINTN mI2CBaseAddress = 0;\r
63STATIC UINT16 mI2CSlaveAddress = 0;\r
64\r
65UINT16 mI2cMode=B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE ;\r
66\r
67UINTN mI2cNvsBaseAddress[] = {\r
68 GLOBAL_NVS_OFFSET(LDMA2Addr),\r
69 GLOBAL_NVS_OFFSET(I2C1Addr),\r
70 GLOBAL_NVS_OFFSET(I2C2Addr),\r
71 GLOBAL_NVS_OFFSET(I2C3Addr),\r
72 GLOBAL_NVS_OFFSET(I2C4Addr),\r
73 GLOBAL_NVS_OFFSET(I2C5Addr),\r
74 GLOBAL_NVS_OFFSET(I2C6Addr),\r
75 GLOBAL_NVS_OFFSET(I2C7Addr)\r
76 };\r
77\r
78/**\r
79 This function get I2Cx controller base address (BAR0).\r
80\r
81 @param I2cControllerIndex Bus Number of I2C controller.\r
82\r
83 @return I2C BAR. \r
84**/\r
85UINTN\r
86GetI2cBarAddr(\r
87 IN UINT8 I2cControllerIndex\r
88 )\r
89{\r
90 EFI_STATUS Status;\r
91 EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea;\r
92 UINTN AcpiBaseAddr;\r
93 UINTN PciMmBase=0;\r
94\r
95 ASSERT(gBS!=NULL);\r
96\r
97 Status = gBS->LocateProtocol (\r
98 &gEfiGlobalNvsAreaProtocolGuid,\r
99 NULL,\r
100 &GlobalNvsArea\r
101 );\r
102 \r
103 //\r
104 // PCI mode from PEI ( Global NVS is not ready).\r
105 //\r
106 if (EFI_ERROR(Status)) {\r
107 DEBUG ((EFI_D_INFO, "GetI2cBarAddr() gEfiGlobalNvsAreaProtocolGuid:%r\n", Status));\r
108 //\r
109 // Global NVS is not ready.\r
110 //\r
111 return 0;\r
112 }\r
113\r
114 AcpiBaseAddr = *(UINTN*)((CHAR8*)GlobalNvsArea->Area + mI2cNvsBaseAddress[I2cControllerIndex + 1]);\r
115 \r
116 //\r
117 //PCI mode from DXE (global NVS protocal) to LPSS OnReadytoBoot(swith to ACPI).\r
118 //\r
119 if(AcpiBaseAddr==0) {\r
120 PciMmBase = MmPciAddress (\r
121 mLpssPciDeviceList[I2cControllerIndex + 1].Segment,\r
122 mLpssPciDeviceList[I2cControllerIndex + 1].BusNum,\r
123 mLpssPciDeviceList[I2cControllerIndex + 1].DeviceNum,\r
124 mLpssPciDeviceList[I2cControllerIndex + 1].FunctionNum,\r
125 0\r
126 );\r
127 DEBUG((EFI_D_ERROR, "\nGetI2cBarAddr() I2C Device %x %x %x PciMmBase:%x\n", \\r
128 mLpssPciDeviceList[I2cControllerIndex + 1].BusNum, \\r
129 mLpssPciDeviceList[I2cControllerIndex + 1].DeviceNum, \\r
130 mLpssPciDeviceList[I2cControllerIndex + 1].FunctionNum, PciMmBase));\r
131\r
132 if (MmioRead32 (PciMmBase) != 0xFFFFFFFF) {\r
133 if((MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_STSCMD)& B_PCH_LPSS_I2C_STSCMD_MSE)) {\r
134 //\r
135 // Get the address allocted.\r
136 //\r
137 mLpssPciDeviceList[I2cControllerIndex + 1].Bar0=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR); \r
138 mLpssPciDeviceList[I2cControllerIndex + 1].Bar1=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR1);\r
139 }\r
140 }\r
141 AcpiBaseAddr =mLpssPciDeviceList[I2cControllerIndex+1].Bar0;\r
142 }\r
143 \r
144 //\r
145 // ACPI mode from BDS: LPSS OnReadytoBoot\r
146 //\r
147 else {\r
148 DEBUG ((EFI_D_INFO, "GetI2cBarAddr() NVS Varialable is updated by this LIB or LPSS \n"));\r
149 }\r
150 \r
151 DEBUG ((EFI_D_INFO, "GetI2cBarAddr() I2cControllerIndex+1 0x%x AcpiBaseAddr:0x%x \n", (I2cControllerIndex + 1), AcpiBaseAddr));\r
152 return AcpiBaseAddr;\r
153}\r
154\r
155\r
156/**\r
157 This function enables I2C controllers.\r
158\r
159 @param I2cControllerIndex Bus Number of I2C controllers.\r
160\r
161 @return Result of the I2C initialization.\r
162**/\r
163EFI_STATUS\r
164ProgramPciLpssI2C (\r
165 IN UINT8 I2cControllerIndex\r
166 )\r
167{\r
168 UINT32 PmcBase;\r
169 UINTN PciMmBase=0;\r
170 EFI_STATUS Status;\r
171 EFI_GLOBAL_NVS_AREA_PROTOCOL *GlobalNvsArea;\r
172\r
173 UINT32 PmcFunctionDsiable[]= {\r
174 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC1,\r
175 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC2,\r
176 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC3,\r
177 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC4,\r
178 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC5,\r
179 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC6,\r
180 B_PCH_PMC_FUNC_DIS_LPSS2_FUNC7\r
181 };\r
182\r
183 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Start\n"));\r
184\r
185 //\r
186 // Set the VLV Function Disable Register to ZERO\r
187 //\r
188 PmcBase = MmioRead32 (PCI_D31F0_REG_BASE + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR;\r
189 if(MmioRead32(PmcBase+R_PCH_PMC_FUNC_DIS)&PmcFunctionDsiable[I2cControllerIndex]) {\r
190 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() End:I2C[%x] is disabled\n",I2cControllerIndex));\r
191 return EFI_NOT_READY;\r
192 }\r
193 \r
194 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C()------------I2cControllerIndex=%x,PMC=%x\n",I2cControllerIndex,MmioRead32(PmcBase+R_PCH_PMC_FUNC_DIS)));\r
195\r
196 {\r
197 PciMmBase = MmPciAddress (\r
198 mLpssPciDeviceList[I2cControllerIndex+1].Segment,\r
199 mLpssPciDeviceList[I2cControllerIndex+1].BusNum,\r
200 mLpssPciDeviceList[I2cControllerIndex+1].DeviceNum,\r
201 mLpssPciDeviceList[I2cControllerIndex+1].FunctionNum,\r
202 0\r
203 );\r
204 \r
205 DEBUG((EFI_D_ERROR, "Program Pci Lpss I2C Device %x %x %x PciMmBase:%x\n", \\r
206 mLpssPciDeviceList[I2cControllerIndex+1].BusNum, \\r
207 mLpssPciDeviceList[I2cControllerIndex+1].DeviceNum, \\r
208 mLpssPciDeviceList[I2cControllerIndex+1].FunctionNum, PciMmBase));\r
209\r
210 if (MmioRead32 (PciMmBase) != 0xFFFFFFFF) {\r
211 if((MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_STSCMD)& B_PCH_LPSS_I2C_STSCMD_MSE)) {\r
212 //\r
213 // Get the address allocted.\r
214 //\r
215 mLpssPciDeviceList[I2cControllerIndex+1].Bar0=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR); \r
216 mLpssPciDeviceList[I2cControllerIndex+1].Bar1=MmioRead32 (PciMmBase+R_PCH_LPSS_I2C_BAR1);\r
217 DEBUG((EFI_D_ERROR, "ProgramPciLpssI2C() bar0:0x%x bar1:0x%x\n",mLpssPciDeviceList[I2cControllerIndex+1].Bar0, mLpssPciDeviceList[I2cControllerIndex+1].Bar1));\r
218 } else {\r
219 \r
220 //\r
221 // Program BAR 0\r
222 //\r
223 ASSERT (((mLpssPciDeviceList[I2cControllerIndex+1].Bar0 & B_PCH_LPSS_I2C_BAR_BA) == mLpssPciDeviceList[I2cControllerIndex+1].Bar0) && (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 != 0));\r
224 MmioWrite32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR), (UINT32) (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 & B_PCH_LPSS_I2C_BAR_BA));\r
225 \r
226 //\r
227 // Program BAR 1\r
228 //\r
229 ASSERT (((mLpssPciDeviceList[I2cControllerIndex+1].Bar1 & B_PCH_LPSS_I2C_BAR1_BA) == mLpssPciDeviceList[I2cControllerIndex+1].Bar1) && (mLpssPciDeviceList[I2cControllerIndex+1].Bar1 != 0));\r
230 MmioWrite32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_BAR1), (UINT32) (mLpssPciDeviceList[I2cControllerIndex+1].Bar1 & B_PCH_LPSS_I2C_BAR1_BA));\r
231 \r
232 //\r
233 // Bus Master Enable & Memory Space Enable\r
234 //\r
235 MmioOr32 ((UINTN) (PciMmBase + R_PCH_LPSS_I2C_STSCMD), (UINT32) (B_PCH_LPSS_I2C_STSCMD_BME | B_PCH_LPSS_I2C_STSCMD_MSE));\r
236 ASSERT (MmioRead32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0) != 0xFFFFFFFF);\r
237 }\r
238 \r
239 //\r
240 // Release Resets\r
241 //\r
242 MmioWrite32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 + R_PCH_LPIO_I2C_MEM_RESETS,(B_PCH_LPIO_I2C_MEM_RESETS_FUNC | B_PCH_LPIO_I2C_MEM_RESETS_APB));\r
243 \r
244 //\r
245 // Activate Clocks\r
246 //\r
247 MmioWrite32 (mLpssPciDeviceList[I2cControllerIndex+1].Bar0 + R_PCH_LPSS_I2C_MEM_PCP,0x80020003);//No use for A0\r
248\r
249 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() Programmed()\n"));\r
250 }\r
251 \r
252 //\r
253 // BDS: already switched to ACPI mode\r
254 //\r
255 else {\r
256 ASSERT(gBS!=NULL);\r
257 Status = gBS->LocateProtocol (\r
258 &gEfiGlobalNvsAreaProtocolGuid,\r
259 NULL,\r
260 &GlobalNvsArea\r
261 );\r
262 if (EFI_ERROR(Status)) {\r
263 DEBUG ((EFI_D_INFO, "GetI2cBarAddr() gEfiGlobalNvsAreaProtocolGuid:%r\n", Status));\r
264 //\r
265 // gEfiGlobalNvsAreaProtocolGuid is not ready.\r
266 //\r
267 return 0;\r
268 }\r
269 mLpssPciDeviceList[I2cControllerIndex + 1].Bar0 = *(UINTN*)((CHAR8*)GlobalNvsArea->Area + mI2cNvsBaseAddress[I2cControllerIndex + 1]);\r
270 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C(): is switched to ACPI 0x:%x \n",mLpssPciDeviceList[I2cControllerIndex + 1].Bar0));\r
271 }\r
272 }\r
273 \r
274 DEBUG ((EFI_D_INFO, "ProgramPciLpssI2C() End\n"));\r
275\r
276 return EFI_SUCCESS;\r
277}\r
278\r
279/**\r
280 Disable I2C Bus.\r
281\r
282 @param VOID.\r
283\r
284 @return Result of the I2C disabling.\r
285**/\r
286RETURN_STATUS\r
287I2cDisable (\r
288 VOID\r
289 )\r
290{ \r
291 //\r
292 // 0.1 seconds\r
293 //\r
294 UINT32 NumTries = 10000;\r
295 \r
296 MmioWrite32 ( mI2CBaseAddress + R_IC_ENABLE, 0 );\r
297 while ( 0 != ( MmioRead32 ( mI2CBaseAddress + R_IC_ENABLE_STATUS) & 1)) {\r
298 MicroSecondDelay (10);\r
299 NumTries --;\r
300 if(0 == NumTries) {\r
301 return RETURN_NOT_READY;\r
302 }\r
303 }\r
304 \r
305 return RETURN_SUCCESS;\r
306}\r
307\r
308/**\r
309 Enable I2C Bus.\r
310\r
311 @param VOID.\r
312\r
313 @return Result of the I2C disabling.\r
314**/\r
315RETURN_STATUS\r
316I2cEnable (\r
317 VOID\r
318 )\r
319{\r
320 //\r
321 // 0.1 seconds\r
322 //\r
323 UINT32 NumTries = 10000;\r
324 \r
325 MmioWrite32 (mI2CBaseAddress + R_IC_ENABLE, 1);\r
326 \r
327 while (0 == (MmioRead32 (mI2CBaseAddress + R_IC_ENABLE_STATUS) & 1)) {\r
328 MicroSecondDelay (10);\r
329 NumTries --;\r
330 if(0 == NumTries){\r
331 return RETURN_NOT_READY;\r
332 }\r
333 }\r
334 \r
335 return RETURN_SUCCESS;\r
336}\r
337\r
338/**\r
339 Enable I2C Bus.\r
340\r
341 @param VOID.\r
342\r
343 @return Result of the I2C enabling.\r
344**/\r
345RETURN_STATUS\r
346I2cBusFrequencySet (\r
347 IN UINTN BusClockHertz\r
348 )\r
349{\r
350 DEBUG((EFI_D_INFO,"InputFreq BusClockHertz: %d\r\n",BusClockHertz));\r
351 \r
352 //\r
353 // Set the 100 KHz clock divider according to SV result and I2C spec\r
354 //\r
355 MmioWrite32 ( mI2CBaseAddress + R_IC_SS_SCL_HCNT, (UINT16)0x214 );\r
356 MmioWrite32 ( mI2CBaseAddress + R_IC_SS_SCL_LCNT, (UINT16)0x272 );\r
357 \r
358 //\r
359 // Set the 400 KHz clock divider according to SV result and I2C spec\r
360 //\r
361 MmioWrite32 ( mI2CBaseAddress + R_IC_FS_SCL_HCNT, (UINT16)0x50 );\r
362 MmioWrite32 ( mI2CBaseAddress + R_IC_FS_SCL_LCNT, (UINT16)0xAD );\r
363\r
364 switch ( BusClockHertz ) {\r
365 case 100 * 1000:\r
366 MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x40);//100K\r
367 mI2cMode = V_SPEED_STANDARD;\r
368 break;\r
369 case 400 * 1000:\r
370 MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x32);//400K\r
371 mI2cMode = V_SPEED_FAST;\r
372 break;\r
373 default:\r
374 MmioWrite32 ( mI2CBaseAddress + R_IC_SDA_HOLD, (UINT16)0x09);//3.4M\r
375 mI2cMode = V_SPEED_HIGH;\r
376 }\r
377\r
378 //\r
379 // Select the frequency counter,\r
380 // Enable restart condition,\r
381 // Enable master FSM, disable slave FSM.\r
382 //\r
383 mI2cMode |= B_IC_RESTART_EN | B_IC_SLAVE_DISABLE | B_MASTER_MODE;\r
384\r
385 return EFI_SUCCESS;\r
386}\r
387\r
388/**\r
389 Initializes the host controller to execute I2C commands.\r
390\r
391 @param I2cControllerIndex Index of I2C controller in LPSS device. 0 represents I2C0, which is PCI function 1 of LPSS device. \r
392 \r
393 @return EFI_SUCCESS Opcode initialization on the I2C host controller completed.\r
394 @return EFI_DEVICE_ERROR Device error, operation failed.\r
395**/\r
396EFI_STATUS\r
397I2CInit (\r
398 IN UINT8 I2cControllerIndex,\r
399 IN UINT16 SlaveAddress\r
400 )\r
401{\r
402 EFI_STATUS Status=RETURN_SUCCESS;\r
403 UINT32 NumTries = 0;\r
404 UINTN GnvsI2cBarAddr=0;\r
405 \r
406 //\r
407 // Verify the parameters\r
408 //\r
409 if ((1023 < SlaveAddress) || (6 < I2cControllerIndex)) {\r
410 Status = RETURN_INVALID_PARAMETER;\r
411 DEBUG((EFI_D_INFO,"I2CInit Exit with RETURN_INVALID_PARAMETER\r\n"));\r
412 return Status;\r
413 }\r
414 MmioWrite32 ( mI2CBaseAddress + R_IC_TAR, (UINT16)SlaveAddress );\r
415 mI2CSlaveAddress = SlaveAddress;\r
416\r
417 //\r
418 // 1.PEI: program and init ( before pci enumeration).\r
419 // 2.DXE:update address and re-init ( after pci enumeration).\r
420 // 3.BDS:update ACPI address and re-init ( after acpi mode is enabled).\r
421 //\r
422 if(mI2CBaseAddress == mLpssPciDeviceList[I2cControllerIndex + 1].Bar0) {\r
423 \r
424 //\r
425 // I2CInit is already called.\r
426 //\r
427 GnvsI2cBarAddr=GetI2cBarAddr(I2cControllerIndex);\r
428 \r
429 if((GnvsI2cBarAddr == 0)||(GnvsI2cBarAddr == mI2CBaseAddress)) {\r
430 DEBUG((EFI_D_INFO,"I2CInit Exit with mI2CBaseAddress:%x == [%x].Bar0\r\n",mI2CBaseAddress,I2cControllerIndex+1));\r
431 return RETURN_SUCCESS;\r
432 }\r
433 }\r
434 \r
435 Status=ProgramPciLpssI2C(I2cControllerIndex);\r
436 if(Status!=EFI_SUCCESS) {\r
437 return Status;\r
438 }\r
439\r
440\r
441 mI2CBaseAddress = (UINT32) mLpssPciDeviceList[I2cControllerIndex + 1].Bar0;\r
442 DEBUG ((EFI_D_ERROR, "mI2CBaseAddress = 0x%x \n",mI2CBaseAddress));\r
443 \r
444 //\r
445 // 1 seconds.\r
446 //\r
447 NumTries = 10000; \r
448 while ((1 == ( MmioRead32 ( mI2CBaseAddress + R_IC_STATUS) & STAT_MST_ACTIVITY ))) {\r
449 MicroSecondDelay(10);\r
450 NumTries --;\r
451 if(0 == NumTries) {\r
452 DEBUG((EFI_D_INFO, "Try timeout\r\n"));\r
453 return RETURN_DEVICE_ERROR;\r
454 }\r
455 }\r
456 \r
457 Status = I2cDisable();\r
458 DEBUG((EFI_D_INFO, "I2cDisable Status = %r\r\n", Status));\r
459 I2cBusFrequencySet(400 * 1000);\r
460\r
461 MmioWrite32(mI2CBaseAddress + R_IC_INTR_MASK, 0x0);\r
462 if (0x7f < SlaveAddress )\r
463 SlaveAddress = ( SlaveAddress & 0x3ff ) | IC_TAR_10BITADDR_MASTER;\r
464 MmioWrite32 ( mI2CBaseAddress + R_IC_TAR, (UINT16)SlaveAddress );\r
465 MmioWrite32 ( mI2CBaseAddress + R_IC_RX_TL, 0);\r
466 MmioWrite32 ( mI2CBaseAddress + R_IC_TX_TL, 0 );\r
467 MmioWrite32 ( mI2CBaseAddress + R_IC_CON, mI2cMode);\r
468 Status = I2cEnable();\r
469\r
470 DEBUG((EFI_D_INFO, "I2cEnable Status = %r\r\n", Status));\r
471 MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT );\r
472 \r
473 return EFI_SUCCESS;\r
474}\r
475\r
476/**\r
477 Reads a Byte from I2C Device.\r
478 \r
479 @param I2cControllerIndex I2C Bus no to which the I2C device has been connected\r
480 @param SlaveAddress Device Address from which the byte value has to be read\r
481 @param Offset Offset from which the data has to be read\r
482 @param *Byte Address to which the value read has to be stored\r
483 @param Start Whether a RESTART is issued before the byte is sent or received\r
484 @param End Whether STOP is generated after a data byte is sent or received \r
485 \r
486 @return EFI_SUCCESS IF the byte value has been successfully read\r
487 @return EFI_DEVICE_ERROR Operation Failed, Device Error\r
488**/\r
489EFI_STATUS \r
490ByteReadI2CBasic(\r
491 IN UINT8 I2cControllerIndex,\r
492 IN UINT8 SlaveAddress,\r
493 IN UINTN ReadBytes,\r
494 OUT UINT8 *ReadBuffer,\r
495 IN UINT8 Start,\r
496 IN UINT8 End\r
497 )\r
498{\r
499\r
500 EFI_STATUS Status;\r
501 UINT32 I2cStatus;\r
502 UINT16 ReceiveData;\r
503 UINT8 *ReceiveDataEnd;\r
504 UINT8 *ReceiveRequest;\r
505 UINT16 RawIntrStat;\r
506 UINT32 Count=0;\r
507\r
508 Status = EFI_SUCCESS;\r
509\r
510 ReceiveDataEnd = &ReadBuffer [ReadBytes];\r
511 if( ReadBytes ) {\r
512\r
513 ReceiveRequest = ReadBuffer;\r
514 DEBUG((EFI_D_INFO,"Read: ---------------%d bytes to RX\r\n",ReceiveDataEnd - ReceiveRequest));\r
515\r
516 while ((ReceiveDataEnd > ReceiveRequest) || (ReceiveDataEnd > ReadBuffer)) {\r
517 \r
518 //\r
519 // Check for NACK\r
520 //\r
521 RawIntrStat = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_RawIntrStat);\r
522 if ( 0 != ( RawIntrStat & I2C_INTR_TX_ABRT )) {\r
523 MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT );\r
524 Status = RETURN_DEVICE_ERROR;\r
525 DEBUG((EFI_D_INFO,"TX ABRT ,%d bytes hasn't been transferred\r\n",ReceiveDataEnd - ReceiveRequest));\r
526 break;\r
527 }\r
528 \r
529 //\r
530 // Determine if another byte was received\r
531 //\r
532 I2cStatus = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_STATUS);\r
533 if (0 != ( I2cStatus & STAT_RFNE )) {\r
534 ReceiveData = (UINT16)MmioRead32 ( mI2CBaseAddress + R_IC_DATA_CMD );\r
535 *ReadBuffer++ = (UINT8)ReceiveData;\r
536 DEBUG((EFI_D_INFO,"MmioRead32 ,1 byte 0x:%x is received\r\n",ReceiveData));\r
537 }\r
538\r
539 if(ReceiveDataEnd == ReceiveRequest) {\r
540 MicroSecondDelay ( FIFO_WRITE_DELAY );\r
541 DEBUG((EFI_D_INFO,"ReceiveDataEnd==ReceiveRequest------------%x\r\n",I2cStatus & STAT_RFNE));\r
542 Count++;\r
543 if(Count<1024) {\r
544 //\r
545 // To avoid sys hung without ul-pmc device on RVP,\r
546 // waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE.\r
547 //\r
548 continue;\r
549 } else {\r
550 break;\r
551 }\r
552 }\r
553 \r
554 //\r
555 // Wait until a read request will fit.\r
556 //\r
557 if (0 == (I2cStatus & STAT_TFNF)) {\r
558 DEBUG((EFI_D_INFO,"Wait until a read request will fit\r\n"));\r
559 MicroSecondDelay (10);\r
560 continue;\r
561 }\r
562 \r
563 //\r
564 // Issue the next read request.\r
565 //\r
566 if(End && Start) {\r
567 MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART|B_CMD_STOP);\r
568 } else if (!End && Start) {\r
569 MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_RESTART);\r
570 } else if (End && !Start) {\r
571 MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD|B_CMD_STOP);\r
572 } else if (!End && !Start) {\r
573 MmioWrite32 ( mI2CBaseAddress + R_IC_DATA_CMD, B_READ_CMD);\r
574 }\r
575 MicroSecondDelay (FIFO_WRITE_DELAY);\r
576\r
577 ReceiveRequest += 1;\r
578 }\r
579 }\r
580 \r
581 return Status;\r
582}\r
583\r
584/**\r
585 Writes a Byte to I2C Device.\r
586 \r
587 @param I2cControllerIndex I2C Bus no to which the I2C device has been connected\r
588 @param SlaveAddress Device Address from which the byte value has to be written\r
589 @param Offset Offset from which the data has to be read\r
590 @param *Byte Address to which the value written is stored\r
591 @param Start Whether a RESTART is issued before the byte is sent or received\r
592 @param End Whether STOP is generated after a data byte is sent or received \r
593 \r
594 @return EFI_SUCCESS IF the byte value has been successfully written\r
595 @return EFI_DEVICE_ERROR Operation Failed, Device Error\r
596**/\r
597EFI_STATUS ByteWriteI2CBasic(\r
598 IN UINT8 I2cControllerIndex,\r
599 IN UINT8 SlaveAddress,\r
600 IN UINTN WriteBytes,\r
601 IN UINT8 *WriteBuffer,\r
602 IN UINT8 Start,\r
603 IN UINT8 End\r
604 )\r
605{\r
606\r
607 EFI_STATUS Status;\r
608 UINT32 I2cStatus;\r
609 UINT8 *TransmitEnd;\r
610 UINT16 RawIntrStat;\r
611 UINT32 Count=0;\r
612\r
613 Status = EFI_SUCCESS;\r
614\r
615 Status=I2CInit(I2cControllerIndex, SlaveAddress);\r
616 if(Status!=EFI_SUCCESS)\r
617 return Status;\r
618\r
619 TransmitEnd = &WriteBuffer[WriteBytes];\r
620 if( WriteBytes ) {\r
621 DEBUG((EFI_D_INFO,"Write: --------------%d bytes to TX\r\n",TransmitEnd - WriteBuffer));\r
622 while (TransmitEnd > WriteBuffer) {\r
623 I2cStatus = MmioRead32 (mI2CBaseAddress + R_IC_STATUS);\r
624 RawIntrStat = (UINT16)MmioRead32 (mI2CBaseAddress + R_IC_RawIntrStat);\r
625 if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) {\r
626 MmioRead32 ( mI2CBaseAddress + R_IC_CLR_TX_ABRT);\r
627 Status = RETURN_DEVICE_ERROR;\r
628 DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer));\r
629 break;\r
630 }\r
631 if (0 == (I2cStatus & STAT_TFNF)) {\r
632 //\r
633 // If TX not full , will send cmd or continue to wait\r
634 //\r
635 MicroSecondDelay (FIFO_WRITE_DELAY);\r
636 continue;\r
637 }\r
638\r
639 if(End && Start) {\r
640 MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART|B_CMD_STOP);\r
641 } else if (!End && Start) {\r
642 MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_RESTART);\r
643 } else if (End && !Start) {\r
644 MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++)|B_CMD_STOP);\r
645 } else if (!End && !Start ) {\r
646 MmioWrite32 (mI2CBaseAddress + R_IC_DATA_CMD, (*WriteBuffer++));\r
647 }\r
648 \r
649 //\r
650 // Add a small delay to work around some odd behavior being seen. Without this delay bytes get dropped.\r
651 //\r
652 MicroSecondDelay ( FIFO_WRITE_DELAY );//wait after send cmd\r
653 \r
654 //\r
655 // Time out\r
656 //\r
657 while(1) {\r
658 RawIntrStat = MmioRead16 ( mI2CBaseAddress + R_IC_RawIntrStat );\r
659 if (0 != ( RawIntrStat & I2C_INTR_TX_ABRT)) {\r
660 MmioRead16 (mI2CBaseAddress + R_IC_CLR_TX_ABRT);\r
661 Status = RETURN_DEVICE_ERROR;\r
662 DEBUG((EFI_D_ERROR,"TX ABRT TransmitEnd:0x%x WriteBuffer:0x%x\r\n", TransmitEnd, WriteBuffer));\r
663 }\r
664 if(0 == MmioRead16(mI2CBaseAddress + R_IC_TXFLR)) break;\r
665\r
666 MicroSecondDelay (FIFO_WRITE_DELAY);\r
667 Count++;\r
668 if(Count<1024) {\r
669 //\r
670 // to avoid sys hung without ul-pmc device on RVP.\r
671 // Waiting the last request to get data and make (ReceiveDataEnd > ReadBuffer) =TRUE.\r
672 //\r
673 continue;\r
674 } else {\r
675 break;\r
676 }\r
677 }//while( 1 )\r
678 }\r
679\r
680 }\r
681\r
682 return Status;\r
683}\r
684\r
685/**\r
686 Reads a Byte from I2C Device.\r
687 \r
688 @param I2cControllerIndex I2C Bus no to which the I2C device has been connected\r
689 @param SlaveAddress Device Address from which the byte value has to be read\r
690 @param Offset Offset from which the data has to be read\r
691 @param ReadBytes Number of bytes to be read\r
692 @param *ReadBuffer Address to which the value read has to be stored\r
693 \r
694 @return EFI_SUCCESS IF the byte value has been successfully read\r
695 @return EFI_DEVICE_ERROR Operation Failed, Device Error\r
696**/\r
697EFI_STATUS ByteReadI2C(\r
698 IN UINT8 I2cControllerIndex,\r
699 IN UINT8 SlaveAddress,\r
700 IN UINT8 Offset,\r
701 IN UINTN ReadBytes,\r
702 OUT UINT8 *ReadBuffer\r
703 )\r
704{\r
705 EFI_STATUS Status;\r
706\r
707 DEBUG ((EFI_D_INFO, "ByteReadI2C:---offset:0x%x\n",Offset));\r
708 Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,1,&Offset,TRUE,FALSE);\r
709 Status = ByteReadI2CBasic(I2cControllerIndex, SlaveAddress,ReadBytes,ReadBuffer,TRUE,TRUE);\r
710\r
711 return Status;\r
712}\r
713\r
714/**\r
715 Writes a Byte to I2C Device.\r
716 \r
717 @param I2cControllerIndex I2C Bus no to which the I2C device has been connected\r
718 @param SlaveAddress Device Address from which the byte value has to be written\r
719 @param Offset Offset from which the data has to be written\r
720 @param WriteBytes Number of bytes to be written\r
721 @param *Byte Address to which the value written is stored\r
722 \r
723 @return EFI_SUCCESS IF the byte value has been successfully read\r
724 @return EFI_DEVICE_ERROR Operation Failed, Device Error\r
725**/\r
726EFI_STATUS ByteWriteI2C(\r
727 IN UINT8 I2cControllerIndex,\r
728 IN UINT8 SlaveAddress,\r
729 IN UINT8 Offset,\r
730 IN UINTN WriteBytes,\r
731 IN UINT8 *WriteBuffer\r
732 )\r
733{\r
734 EFI_STATUS Status;\r
735\r
736 DEBUG ((EFI_D_INFO, "ByteWriteI2C:---offset/bytes/buf:0x%x,0x%x,0x%x,0x%x\n",Offset,WriteBytes,WriteBuffer,*WriteBuffer));\r
737 Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,1,&Offset,TRUE,FALSE);\r
738 Status = ByteWriteI2CBasic(I2cControllerIndex, SlaveAddress,WriteBytes,WriteBuffer,FALSE,TRUE);\r
739\r
740 return Status;\r
741}\r