Home | History | Annotate | Download | only in I2CLibPei
      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
    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
    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
    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
    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
    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
    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 **/
    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
    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
    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 **/
    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