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