]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkSouthCluster/Library/I2cLib/I2cLib.c
QuarkSocPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Library / I2cLib / I2cLib.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2I2C Library for Quark I2C Controller.\r
3Follows I2C Controller setup instructions as detailed in\r
4Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.\r
5\r
6\r
7Copyright (c) 2013-2015 Intel Corporation.\r
8\r
c9f231d0 9SPDX-License-Identifier: BSD-2-Clause-Patent\r
9b6bbcdb
MK
10\r
11**/\r
12\r
13#include "CommonHeader.h"\r
14\r
15/**\r
16 The Called to Common Service Entry.\r
17\r
18 @return None.\r
19\r
20**/\r
21\r
22VOID\r
23I2cCommonServiceEntry (\r
24 OUT UINT16 *SaveCmdPtr,\r
25 OUT UINT32 *SaveBar0Ptr\r
26 )\r
27{\r
28 *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);\r
29 if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {\r
30\r
31 IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =\r
32 FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;\r
33\r
34 //\r
35 // also Save Cmd Register, Setup by InitializeInternal later during xfers.\r
36 //\r
37 *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);\r
38 }\r
39}\r
40\r
41/**\r
42 The Called on Common Service Exit.\r
43\r
44 @return None.\r
45\r
46**/\r
47VOID\r
48I2cCommonServiceExit (\r
49 IN CONST UINT16 SaveCmd,\r
50 IN CONST UINT32 SaveBar0\r
51\r
52 )\r
53{\r
54 if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {\r
55 IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;\r
56 IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;\r
57 }\r
58}\r
59\r
60\r
61/**\r
62 The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.\r
63\r
64 Always reads PCI configuration space to get MMIO base address of I2C Controller.\r
65\r
66 @return The IO port base address of I2C controller.\r
67\r
68**/\r
69UINTN\r
70GetI2CIoPortBaseAddress (\r
71 VOID\r
72 )\r
73{\r
74 UINTN I2CIoPortBaseAddress;\r
75\r
76 //\r
77 // Get I2C Memory Mapped registers base address.\r
78 //\r
79 I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);\r
80\r
81 //\r
82 // Make sure that the IO port base address has been properly set.\r
83 //\r
84 ASSERT (I2CIoPortBaseAddress != 0);\r
85 ASSERT (I2CIoPortBaseAddress != 0xFF);\r
86\r
87 return I2CIoPortBaseAddress;\r
88}\r
89\r
90\r
91/**\r
92 The EnableI2CMmioSpace() function enables access to I2C MMIO space.\r
93\r
94**/\r
95VOID\r
96EnableI2CMmioSpace (\r
97 VOID\r
98 )\r
99{\r
100 UINT8 PciCmd;\r
101\r
102 //\r
103 // Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4\r
104 //\r
105 PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);\r
106\r
107 //\r
108 // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)\r
109 //\r
110 PciCmd |= 0x7;\r
111 IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;\r
112\r
113}\r
114\r
115/**\r
116 The DisableI2CController() functions disables I2C Controller.\r
117\r
118**/\r
119VOID\r
120DisableI2CController (\r
121 VOID\r
122 )\r
123{\r
124 UINTN I2CIoPortBaseAddress;\r
125 UINT32 Addr;\r
126 UINT32 Data;\r
127 UINT8 PollCount;\r
128\r
129 PollCount = 0;\r
130\r
131 //\r
132 // Get I2C Memory Mapped registers base address.\r
133 //\r
134 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
135\r
136 //\r
137 // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero\r
138 //\r
139 Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
140 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
141 Data &= ~B_I2C_REG_ENABLE;\r
142 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
143\r
144 //\r
145 // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled\r
146 //\r
147 Data = 0xFF;\r
148 Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;\r
149 Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;\r
150 while (Data != 0) {\r
151 //\r
152 // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).\r
153 //\r
154 PollCount++;\r
155 if (PollCount >= MAX_T_POLL_COUNT) {\r
156 break;\r
157 }\r
158 MicroSecondDelay(TI2C_POLL);\r
159 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
160 Data &= I2C_REG_ENABLE_STATUS;\r
161 }\r
162\r
163 //\r
164 // Asset if controller does not enter Disabled state.\r
165 //\r
166 ASSERT (PollCount < MAX_T_POLL_COUNT);\r
167\r
168 //\r
169 // Read IC_CLR_INTR register to automatically clear the combined interrupt,\r
170 // all individual interrupts and the IC_TX_ABRT_SOURCE register.\r
171 //\r
172 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;\r
173 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
174\r
175}\r
176\r
177/**\r
178 The EnableI2CController() function enables the I2C Controller.\r
179\r
180**/\r
181VOID\r
182EnableI2CController (\r
183 VOID\r
184 )\r
185{\r
186 UINTN I2CIoPortBaseAddress;\r
187 UINT32 Addr;\r
188 UINT32 Data;\r
189\r
190 //\r
191 // Get I2C Memory Mapped registers base address.\r
192 //\r
193 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
194\r
195 //\r
196 // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1\r
197 //\r
198 Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
199 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
200 Data |= B_I2C_REG_ENABLE;\r
201 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
202\r
203 //\r
204 // Clear overflow and abort error status bits before transactions.\r
205 //\r
206 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;\r
207 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
208 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;\r
209 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
210 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;\r
211 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
212\r
213}\r
214\r
215/**\r
216 The WaitForStopDet() function waits until I2C STOP Condition occurs,\r
217 indicating transfer completion.\r
218\r
219 @retval EFI_SUCCESS Stop detected.\r
220 @retval EFI_TIMEOUT Timeout while waiting for stop condition.\r
221 @retval EFI_ABORTED Tx abort signaled in HW status register.\r
222 @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.\r
223\r
224**/\r
225EFI_STATUS\r
226WaitForStopDet (\r
227 VOID\r
228 )\r
229{\r
230 UINTN I2CIoPortBaseAddress;\r
231 UINT32 Addr;\r
232 UINT32 Data;\r
233 UINT32 PollCount;\r
234 EFI_STATUS Status;\r
235\r
236 Status = EFI_SUCCESS;\r
237\r
238 PollCount = 0;\r
239\r
240 //\r
241 // Get I2C Memory Mapped registers base address.\r
242 //\r
243 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
244\r
245 //\r
246 // Wait for STOP Detect.\r
247 //\r
248 Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
249\r
250 do {\r
251 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
252 if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {\r
253 Status = EFI_ABORTED;\r
254 break;\r
255 }\r
256 if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {\r
257 Status = EFI_DEVICE_ERROR;\r
258 break;\r
259 }\r
260 if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {\r
261 Status = EFI_DEVICE_ERROR;\r
262 break;\r
263 }\r
264 if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {\r
265 Status = EFI_SUCCESS;\r
266 break;\r
267 }\r
268 MicroSecondDelay(TI2C_POLL);\r
269 PollCount++;\r
270 if (PollCount >= MAX_STOP_DET_POLL_COUNT) {\r
271 Status = EFI_TIMEOUT;\r
272 break;\r
273 }\r
274\r
275 } while (TRUE);\r
276\r
277 return Status;\r
278}\r
279\r
280/**\r
281\r
282 The InitializeInternal() function initialises internal I2C Controller\r
283 register values that are commonly required for I2C Write and Read transfers.\r
284\r
285 @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
286\r
287 @retval EFI_SUCCESS I2C Operation completed successfully.\r
288\r
289**/\r
290EFI_STATUS\r
291InitializeInternal (\r
292 IN EFI_I2C_ADDR_MODE AddrMode\r
293 )\r
294{\r
295 UINTN I2CIoPortBaseAddress;\r
296 UINTN Addr;\r
297 UINT32 Data;\r
298 EFI_STATUS Status;\r
299\r
300 Status = EFI_SUCCESS;\r
301\r
302 //\r
303 // Enable access to I2C Controller MMIO space.\r
304 //\r
305 EnableI2CMmioSpace ();\r
306\r
307 //\r
308 // Disable I2C Controller initially\r
309 //\r
310 DisableI2CController ();\r
311\r
312 //\r
313 // Get I2C Memory Mapped registers base address.\r
314 //\r
315 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
316\r
317 //\r
318 // Clear START_DET\r
319 //\r
320 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;\r
321 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
322 Data &= ~B_I2C_REG_CLR_START_DET;\r
323 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
324\r
325 //\r
326 // Clear STOP_DET\r
327 //\r
328 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;\r
329 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
330 Data &= ~B_I2C_REG_CLR_STOP_DET;\r
331 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
332\r
333 //\r
334 // Set addressing mode to user defined (7 or 10 bit) and\r
335 // speed mode to that defined by PCD (standard mode default).\r
336 //\r
337 Addr = I2CIoPortBaseAddress + I2C_REG_CON;\r
338 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
339 // Set Addressing Mode\r
340 if (AddrMode == EfiI2CSevenBitAddrMode) {\r
341 Data &= ~B_I2C_REG_CON_10BITADD_MASTER;\r
342 } else {\r
343 Data |= B_I2C_REG_CON_10BITADD_MASTER;\r
344 }\r
345 // Set Speed Mode\r
346 Data &= ~B_I2C_REG_CON_SPEED;\r
347 if (FeaturePcdGet (PcdI2CFastModeEnabled)) {\r
348 Data |= BIT2;\r
349 } else {\r
350 Data |= BIT1;\r
351 }\r
352 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
353\r
354 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
355\r
356 return Status;\r
357\r
358}\r
359\r
360/**\r
361\r
362 The WriteByte() function provides a standard way to execute a\r
363 standard single byte write to an IC2 device (without accessing\r
364 sub-addresses), as defined in the I2C Specification.\r
365\r
366 @param I2CAddress I2C Slave device address\r
367 @param Value The 8-bit value to write.\r
368\r
369 @retval EFI_SUCCESS Transfer success.\r
370 @retval EFI_UNSUPPORTED Unsupported input param.\r
371 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
372 @retval EFI_ABORTED Controller aborted xfer.\r
373 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
374\r
375**/\r
376EFI_STATUS\r
377EFIAPI\r
378WriteByte (\r
379 IN UINTN I2CAddress,\r
380 IN UINT8 Value\r
381 )\r
382{\r
383 UINTN I2CIoPortBaseAddress;\r
384 UINTN Addr;\r
385 UINT32 Data;\r
386 EFI_STATUS Status;\r
387\r
388 //\r
389 // Get I2C Memory Mapped registers base address\r
390 //\r
391 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
392\r
393 //\r
394 // Write to the IC_TAR register the address of the slave device to be addressed\r
395 //\r
396 Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
397 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
398 Data &= ~B_I2C_REG_TAR;\r
399 Data |= I2CAddress;\r
400 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
401\r
402 //\r
403 // Enable the I2C Controller\r
404 //\r
405 EnableI2CController ();\r
406\r
407 //\r
408 // Write the data and transfer direction to the IC_DATA_CMD register.\r
409 // Also specify that transfer should be terminated by STOP condition.\r
410 //\r
411 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
412 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
413 Data &= 0xFFFFFF00;\r
414 Data |= (UINT8)Value;\r
415 Data &= ~B_I2C_REG_DATA_CMD_RW;\r
416 Data |= B_I2C_REG_DATA_CMD_STOP;\r
417 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
418\r
419 //\r
420 // Wait for transfer completion.\r
421 //\r
422 Status = WaitForStopDet ();\r
423\r
424 //\r
425 // Ensure I2C Controller disabled.\r
426 //\r
427 DisableI2CController();\r
428\r
429 return Status;\r
430}\r
431\r
432/**\r
433\r
434 The ReadByte() function provides a standard way to execute a\r
435 standard single byte read to an IC2 device (without accessing\r
436 sub-addresses), as defined in the I2C Specification.\r
437\r
438 @param I2CAddress I2C Slave device address\r
439 @param ReturnDataPtr Pointer to location to receive read byte.\r
440\r
441 @retval EFI_SUCCESS Transfer success.\r
442 @retval EFI_UNSUPPORTED Unsupported input param.\r
443 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
444 @retval EFI_ABORTED Controller aborted xfer.\r
445 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
446\r
447**/\r
448EFI_STATUS\r
449EFIAPI\r
450ReadByte (\r
451 IN UINTN I2CAddress,\r
452 OUT UINT8 *ReturnDataPtr\r
453 )\r
454{\r
455 UINTN I2CIoPortBaseAddress;\r
456 UINTN Addr;\r
457 UINT32 Data;\r
458 EFI_STATUS Status;\r
459\r
460 //\r
461 // Get I2C Memory Mapped registers base address.\r
462 //\r
463 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
464\r
465 //\r
466 // Write to the IC_TAR register the address of the slave device to be addressed\r
467 //\r
468 Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
469 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
470 Data &= ~B_I2C_REG_TAR;\r
471 Data |= I2CAddress;\r
472 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
473\r
474 //\r
475 // Enable the I2C Controller\r
476 //\r
477 EnableI2CController ();\r
478\r
479 //\r
480 // Write transfer direction to the IC_DATA_CMD register and\r
481 // specify that transfer should be terminated by STOP condition.\r
482 //\r
483 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
484 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
485 Data &= 0xFFFFFF00;\r
486 Data |= B_I2C_REG_DATA_CMD_RW;\r
487 Data |= B_I2C_REG_DATA_CMD_STOP;\r
488 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
489\r
490 //\r
491 // Wait for transfer completion\r
492 //\r
493 Status = WaitForStopDet ();\r
494 if (!EFI_ERROR(Status)) {\r
495\r
496 //\r
497 // Clear RX underflow before reading IC_DATA_CMD.\r
498 //\r
499 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;\r
500 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
501\r
502 //\r
503 // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).\r
504 //\r
505 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
506 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
507 Data &= 0x000000FF;\r
508 *ReturnDataPtr = (UINT8) Data;\r
509\r
510 Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
511 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
512 Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;\r
513 if (Data != 0) {\r
514 Status = EFI_DEVICE_ERROR;\r
515 }\r
516 }\r
517\r
518 //\r
519 // Ensure I2C Controller disabled.\r
520 //\r
521 DisableI2CController ();\r
522\r
523 return Status;\r
524}\r
525\r
526/**\r
527\r
528 The WriteMultipleByte() function provides a standard way to execute\r
529 multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
530 when writing block of data), as defined in the I2C Specification.\r
531\r
532 @param I2CAddress The I2C slave address of the device\r
533 with which to communicate.\r
534\r
535 @param WriteBuffer Contains the value of byte to be written to the\r
536 I2C slave device.\r
537\r
538 @param Length No. of bytes to be written.\r
539\r
540 @retval EFI_SUCCESS Transfer success.\r
541 @retval EFI_UNSUPPORTED Unsupported input param.\r
542 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
543 @retval EFI_ABORTED Tx abort signaled in HW status register.\r
544 @retval EFI_DEVICE_ERROR Tx overflow detected.\r
545\r
546**/\r
547EFI_STATUS\r
548EFIAPI\r
549WriteMultipleByte (\r
550 IN UINTN I2CAddress,\r
551 IN UINT8 *WriteBuffer,\r
552 IN UINTN Length\r
553 )\r
554{\r
555 UINTN I2CIoPortBaseAddress;\r
556 UINTN Index;\r
557 UINTN Addr;\r
558 UINT32 Data;\r
559 EFI_STATUS Status;\r
560\r
561 if (Length > I2C_FIFO_SIZE) {\r
562 return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.\r
563 }\r
564\r
565 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
566\r
567 //\r
568 // Write to the IC_TAR register the address of the slave device to be addressed\r
569 //\r
570 Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
571 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
572 Data &= ~B_I2C_REG_TAR;\r
573 Data |= I2CAddress;\r
574 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
575\r
576 //\r
577 // Enable the I2C Controller\r
578 //\r
579 EnableI2CController ();\r
580\r
581 //\r
582 // Write the data and transfer direction to the IC_DATA_CMD register.\r
583 // Also specify that transfer should be terminated by STOP condition.\r
584 //\r
585 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
586 for (Index = 0; Index < Length; Index++) {\r
587 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
588 Data &= 0xFFFFFF00;\r
589 Data |= (UINT8)WriteBuffer[Index];\r
590 Data &= ~B_I2C_REG_DATA_CMD_RW;\r
591 if (Index == (Length-1)) {\r
592 Data |= B_I2C_REG_DATA_CMD_STOP;\r
593 }\r
594 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
595 }\r
596\r
597 //\r
598 // Wait for transfer completion\r
599 //\r
600 Status = WaitForStopDet ();\r
601\r
602 //\r
603 // Ensure I2C Controller disabled.\r
604 //\r
605 DisableI2CController ();\r
606 return Status;\r
607}\r
608\r
609/**\r
610\r
611 The ReadMultipleByte() function provides a standard way to execute\r
612 multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
613 when reading block of data), as defined in the I2C Specification (I2C combined\r
614 write/read protocol).\r
615\r
616 @param I2CAddress The I2C slave address of the device\r
617 with which to communicate.\r
618\r
619 @param Buffer Contains the value of byte data written or read from the\r
620 I2C slave device.\r
621\r
622 @param WriteLength No. of bytes to be written. In this case data\r
623 written typically contains sub-address or sub-addresses\r
624 in Hi-Lo format, that need to be read (I2C combined\r
625 write/read protocol).\r
626\r
627 @param ReadLength No. of bytes to be read from I2C slave device.\r
628\r
629 @retval EFI_SUCCESS Transfer success.\r
630 @retval EFI_UNSUPPORTED Unsupported input param.\r
631 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
632 @retval EFI_ABORTED Tx abort signaled in HW status register.\r
633 @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.\r
634\r
635**/\r
636EFI_STATUS\r
637EFIAPI\r
638ReadMultipleByte (\r
639 IN UINTN I2CAddress,\r
640 IN OUT UINT8 *Buffer,\r
641 IN UINTN WriteLength,\r
642 IN UINTN ReadLength\r
643 )\r
644{\r
645 UINTN I2CIoPortBaseAddress;\r
646 UINTN Index;\r
647 UINTN Addr;\r
648 UINT32 Data;\r
649 UINT8 PollCount;\r
650 EFI_STATUS Status;\r
651\r
652 if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {\r
653 return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.\r
654 }\r
655\r
656 I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
657\r
658 //\r
659 // Write to the IC_TAR register the address of the slave device to be addressed\r
660 //\r
661 Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
662 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
663 Data &= ~B_I2C_REG_TAR;\r
664 Data |= I2CAddress;\r
665 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
666\r
667 //\r
668 // Enable the I2C Controller\r
669 //\r
670 EnableI2CController ();\r
671\r
672 //\r
673 // Write the data (sub-addresses) to the IC_DATA_CMD register.\r
674 //\r
675 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
676 for (Index = 0; Index < WriteLength; Index++) {\r
677 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
678 Data &= 0xFFFFFF00;\r
679 Data |= (UINT8)Buffer[Index];\r
680 Data &= ~B_I2C_REG_DATA_CMD_RW;\r
681 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
682 }\r
683\r
684 //\r
685 // Issue Read Transfers for each byte (Restart issued when write/read bit changed).\r
686 //\r
687 for (Index = 0; Index < ReadLength; Index++) {\r
688 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
689 Data |= B_I2C_REG_DATA_CMD_RW;\r
690 // Issue a STOP for last read transfer.\r
691 if (Index == (ReadLength-1)) {\r
692 Data |= B_I2C_REG_DATA_CMD_STOP;\r
693 }\r
694 *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
695 }\r
696\r
697 //\r
698 // Wait for STOP condition.\r
699 //\r
700 Status = WaitForStopDet ();\r
701 if (!EFI_ERROR(Status)) {\r
702\r
703 //\r
704 // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).\r
705 //\r
706 Data = 0;\r
707 PollCount = 0;\r
708 Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;\r
709 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
710 while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {\r
711 MicroSecondDelay(TI2C_POLL);\r
712 PollCount++;\r
713 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
714 }\r
715\r
716 Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
717 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
718\r
719 //\r
720 // If no timeout or device error then read rx data.\r
721 //\r
722 if (PollCount == MAX_T_POLL_COUNT) {\r
723 Status = EFI_TIMEOUT;\r
724 } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {\r
725 Status = EFI_DEVICE_ERROR;\r
726 } else {\r
727\r
728 //\r
729 // Clear RX underflow before reading IC_DATA_CMD.\r
730 //\r
731 Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;\r
732 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
733\r
734 //\r
735 // Read data.\r
736 //\r
737 Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
738 for (Index = 0; Index < ReadLength; Index++) {\r
739 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
740 Data &= 0x000000FF;\r
741 *(Buffer+Index) = (UINT8)Data;\r
742 }\r
743 Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
744 Data = *((volatile UINT32 *) (UINTN)(Addr));\r
745 Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;\r
746 if (Data != 0) {\r
747 Status = EFI_DEVICE_ERROR;\r
748 } else {\r
749 Status = EFI_SUCCESS;\r
750 }\r
751 }\r
752 }\r
753\r
754 //\r
755 // Ensure I2C Controller disabled.\r
756 //\r
757 DisableI2CController ();\r
758\r
759 return Status;\r
760}\r
761\r
762/**\r
763\r
764 The I2cWriteByte() function is a wrapper function for the WriteByte function.\r
765 Provides a standard way to execute a standard single byte write to an IC2 device\r
766 (without accessing sub-addresses), as defined in the I2C Specification.\r
767\r
768 @param SlaveAddress The I2C slave address of the device\r
769 with which to communicate.\r
770\r
771 @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
772\r
773 @param Buffer Contains the value of byte data to execute to the\r
774 I2C slave device.\r
775\r
776\r
777 @retval EFI_SUCCESS Transfer success.\r
778 @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
779 @retval EFI_UNSUPPORTED Unsupported input param.\r
780 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
781 @retval EFI_ABORTED Controller aborted xfer.\r
782 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
783\r
784**/\r
785EFI_STATUS\r
786EFIAPI\r
787I2cWriteByte (\r
788 IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
789 IN EFI_I2C_ADDR_MODE AddrMode,\r
790 IN OUT VOID *Buffer\r
791 )\r
792{\r
793 EFI_STATUS Status;\r
794 UINTN I2CAddress;\r
795 UINT16 SaveCmd;\r
796 UINT32 SaveBar0;\r
797\r
798 if (Buffer == NULL) {\r
799 return EFI_INVALID_PARAMETER;\r
800 }\r
801 SaveCmd = 0;\r
802 SaveBar0 = 0;\r
803\r
804 I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
805\r
806 Status = EFI_SUCCESS;\r
807\r
808 I2CAddress = SlaveAddress.I2CDeviceAddress;\r
809 Status = InitializeInternal (AddrMode);\r
810 if (!EFI_ERROR(Status)) {\r
811 Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);\r
812 }\r
813\r
814 I2cCommonServiceExit (SaveCmd, SaveBar0);\r
815 return Status;\r
816}\r
817\r
818/**\r
819\r
820 The I2cReadByte() function is a wrapper function for the ReadByte function.\r
821 Provides a standard way to execute a standard single byte read to an I2C device\r
822 (without accessing sub-addresses), as defined in the I2C Specification.\r
823\r
824 @param SlaveAddress The I2C slave address of the device\r
825 with which to communicate.\r
826\r
827 @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
828\r
829 @param Buffer Contains the value of byte data read from the\r
830 I2C slave device.\r
831\r
832\r
833 @retval EFI_SUCCESS Transfer success.\r
834 @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
835 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
836 @retval EFI_ABORTED Controller aborted xfer.\r
837 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
838\r
839\r
840**/\r
841EFI_STATUS\r
842EFIAPI\r
843I2cReadByte (\r
844 IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
845 IN EFI_I2C_ADDR_MODE AddrMode,\r
846 IN OUT VOID *Buffer\r
847 )\r
848{\r
849 EFI_STATUS Status;\r
850 UINTN I2CAddress;\r
851 UINT16 SaveCmd;\r
852 UINT32 SaveBar0;\r
853\r
854 if (Buffer == NULL) {\r
855 return EFI_INVALID_PARAMETER;\r
856 }\r
857 SaveCmd = 0;\r
858 SaveBar0 =0;\r
859\r
860 I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
861\r
862 Status = EFI_SUCCESS;\r
863\r
864 I2CAddress = SlaveAddress.I2CDeviceAddress;\r
865\r
866 Status = InitializeInternal (AddrMode);\r
867 if (!EFI_ERROR(Status)) {\r
868 Status = ReadByte (I2CAddress, (UINT8 *) Buffer);\r
869 }\r
870 I2cCommonServiceExit (SaveCmd, SaveBar0);\r
871 return Status;\r
872}\r
873\r
874/**\r
875\r
876 The I2cWriteMultipleByte() function is a wrapper function for the\r
877 WriteMultipleByte() function. Provides a standard way to execute multiple\r
878 byte writes to an I2C device (e.g. when accessing sub-addresses or writing\r
879 block of data), as defined in the I2C Specification.\r
880\r
881 @param SlaveAddress The I2C slave address of the device\r
882 with which to communicate.\r
883\r
884 @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
885\r
886 @param Length No. of bytes to be written.\r
887\r
888 @param Buffer Contains the value of byte to be written to the\r
889 I2C slave device.\r
890\r
891 @retval EFI_SUCCESS Transfer success.\r
892 @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.\r
893 @retval EFI_UNSUPPORTED Unsupported input param.\r
894 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
895 @retval EFI_ABORTED Controller aborted xfer.\r
896 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
897\r
898**/\r
899EFI_STATUS\r
900EFIAPI\r
901I2cWriteMultipleByte (\r
902 IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
903 IN EFI_I2C_ADDR_MODE AddrMode,\r
904 IN UINTN *Length,\r
905 IN OUT VOID *Buffer\r
906 )\r
907{\r
908 EFI_STATUS Status;\r
909 UINTN I2CAddress;\r
910 UINT16 SaveCmd;\r
911 UINT32 SaveBar0;\r
912\r
913 if (Buffer == NULL || Length == NULL) {\r
914 return EFI_INVALID_PARAMETER;\r
915 }\r
916 SaveCmd = 0;\r
917 SaveBar0 =0;\r
918\r
919 I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
920 Status = EFI_SUCCESS;\r
921\r
922 I2CAddress = SlaveAddress.I2CDeviceAddress;\r
923\r
924 Status = InitializeInternal (AddrMode);\r
925 if (!EFI_ERROR(Status)) {\r
926 Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));\r
927 }\r
928\r
929 I2cCommonServiceExit (SaveCmd, SaveBar0);\r
930 return Status;\r
931}\r
932\r
933/**\r
934\r
935 The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.\r
936 Provides a standard way to execute multiple byte writes to an I2C device\r
937 (e.g. when accessing sub-addresses or when reading block of data), as defined\r
938 in the I2C Specification (I2C combined write/read protocol).\r
939\r
940 @param SlaveAddress The I2C slave address of the device\r
941 with which to communicate.\r
942\r
943 @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
944\r
945 @param WriteLength No. of bytes to be written. In this case data\r
946 written typically contains sub-address or sub-addresses\r
947 in Hi-Lo format, that need to be read (I2C combined\r
948 write/read protocol).\r
949\r
950 @param ReadLength No. of bytes to be read from I2C slave device.\r
951\r
952 @param Buffer Contains the value of byte data read from the\r
953 I2C slave device.\r
954\r
955 @retval EFI_SUCCESS Transfer success.\r
956 @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer\r
957 pointers are invalid.\r
958 @retval EFI_UNSUPPORTED Unsupported input param.\r
959 @retval EFI_TIMEOUT Timeout while waiting xfer.\r
960 @retval EFI_ABORTED Controller aborted xfer.\r
961 @retval EFI_DEVICE_ERROR Device error detected by controller.\r
962\r
963**/\r
964EFI_STATUS\r
965EFIAPI\r
966I2cReadMultipleByte (\r
967 IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
968 IN EFI_I2C_ADDR_MODE AddrMode,\r
969 IN UINTN *WriteLength,\r
970 IN UINTN *ReadLength,\r
971 IN OUT VOID *Buffer\r
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 UINTN I2CAddress;\r
976 UINT16 SaveCmd;\r
977 UINT32 SaveBar0;\r
978\r
979 if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {\r
980 return EFI_INVALID_PARAMETER;\r
981 }\r
982 SaveCmd = 0;\r
983 SaveBar0 =0;\r
984\r
985 I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
986\r
987 Status = EFI_SUCCESS;\r
988\r
989 I2CAddress = SlaveAddress.I2CDeviceAddress;\r
990 Status = InitializeInternal (AddrMode);\r
991 if (!EFI_ERROR(Status)) {\r
992 Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));\r
993 }\r
994 I2cCommonServiceExit (SaveCmd, SaveBar0);\r
995 return Status;\r
996}\r
997\r
998\r