Home | History | Annotate | Download | only in SmbusDxe
      1 /** @file
      2 
      3   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      4 
      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 <Uefi.h>
     16 #include <Omap3530/Omap3530.h>
     17 
     18 #include <Library/DebugLib.h>
     19 #include <Library/IoLib.h>
     20 #include <Library/UefiBootServicesTableLib.h>
     21 
     22 #include <Protocol/SmbusHc.h>
     23 
     24 #define MAX_RETRY  1000
     25 
     26 //
     27 // Internal Functions
     28 //
     29 STATIC
     30 EFI_STATUS
     31 WaitForBusBusy (
     32   VOID
     33   )
     34 {
     35   UINTN Retry = 0;
     36 
     37   while (++Retry < MAX_RETRY && (MmioRead16(I2C_STAT) & BB) == 0x1);
     38 
     39   if (Retry == MAX_RETRY) {
     40     return EFI_TIMEOUT;
     41   }
     42 
     43   return EFI_SUCCESS;
     44 }
     45 
     46 STATIC
     47 EFI_STATUS
     48 PollForStatus(
     49   UINT16 StatusBit
     50   )
     51 {
     52   UINTN Retry = 0;
     53 
     54   while(Retry < MAX_RETRY) {
     55     if (MmioRead16(I2C_STAT) & StatusBit) {
     56       //Clear particular status bit from Status register.
     57       MmioOr16(I2C_STAT, StatusBit);
     58       break;
     59     }
     60     Retry++;
     61   }
     62 
     63   if (Retry == MAX_RETRY) {
     64     return EFI_TIMEOUT;
     65   }
     66 
     67   return EFI_SUCCESS;
     68 }
     69 
     70 STATIC
     71 EFI_STATUS
     72 ConfigureI2c (
     73   VOID
     74   )
     75 {
     76   //Program prescaler to obtain 12-MHz clock
     77   MmioWrite16(I2C_PSC, 0x0000);
     78 
     79   //Program SCLL and SCLH
     80   //NOTE: Following values are the register dump after U-Boot code executed.
     81   //We need to figure out how its calculated based on the I2C functional clock and I2C_PSC.
     82   MmioWrite16(I2C_SCLL, 0x0035);
     83   MmioWrite16(I2C_SCLH, 0x0035);
     84 
     85   //Take the I2C controller out of reset.
     86   MmioOr16(I2C_CON, I2C_EN);
     87 
     88   //Initialize the I2C controller.
     89 
     90   //Set I2C controller in Master mode.
     91   MmioOr16(I2C_CON, MST);
     92 
     93   //Enable interrupts for receive/transmit mode.
     94   MmioOr16(I2C_IE, (XRDY_IE | RRDY_IE | ARDY_IE | NACK_IE));
     95 
     96   return EFI_SUCCESS;
     97 }
     98 
     99 STATIC
    100 EFI_STATUS
    101 I2CReadOneByte (
    102   UINT8 *Data
    103   )
    104 {
    105   EFI_STATUS Status;
    106 
    107   //I2C bus status checking
    108   Status = WaitForBusBusy();
    109   if (EFI_ERROR(Status)) {
    110     return Status;
    111   }
    112 
    113   //Poll till Receive ready bit is set.
    114   Status = PollForStatus(RRDY);
    115   if (EFI_ERROR(Status)) {
    116     return Status;
    117   }
    118 
    119   *Data = MmioRead8(I2C_DATA);
    120 
    121   return EFI_SUCCESS;
    122 }
    123 
    124 STATIC
    125 EFI_STATUS
    126 I2CWriteOneByte (
    127   UINT8 Data
    128   )
    129 {
    130   EFI_STATUS Status;
    131 
    132   //I2C bus status checking
    133   Status = WaitForBusBusy();
    134   if (EFI_ERROR(Status)) {
    135     return Status;
    136   }
    137 
    138   //Data transfer
    139   //Poll till Transmit ready bit is set
    140   Status = PollForStatus(XRDY);
    141   if (EFI_ERROR(Status)) {
    142     return Status;
    143   }
    144 
    145   MmioWrite8(I2C_DATA, Data);
    146 
    147   //Wait and check if the NACK is not set.
    148   gBS->Stall(1000);
    149   if (MmioRead16(I2C_STAT) & NACK) {
    150     return EFI_DEVICE_ERROR;
    151   }
    152 
    153   return EFI_SUCCESS;
    154 }
    155 
    156 STATIC
    157 EFI_STATUS
    158 SmbusBlockRead (
    159   OUT UINT8       *Buffer,
    160   IN  UINTN       Length
    161   )
    162 {
    163   UINTN      Index = 0;
    164   EFI_STATUS Status = EFI_SUCCESS;
    165 
    166   //Transfer configuration for receiving data.
    167   MmioWrite16(I2C_CNT, Length);
    168   //Need stop bit before sending data.
    169   MmioWrite16(I2C_CON, (I2C_EN | MST | STP | STT));
    170 
    171   while (Index < Length) {
    172     //Read a byte
    173     Status = I2CReadOneByte(&Buffer[Index++]);
    174     if (EFI_ERROR(Status)) {
    175       return Status;
    176     }
    177   }
    178 
    179   //Transfer completion
    180   Status = PollForStatus(ARDY);
    181   if (EFI_ERROR(Status)) {
    182     return Status;
    183   }
    184 
    185   return Status;
    186 }
    187 
    188 STATIC
    189 EFI_STATUS
    190 SmbusBlockWrite (
    191   IN UINT8       *Buffer,
    192   IN UINTN       Length
    193   )
    194 {
    195   UINTN      Index = 0;
    196   EFI_STATUS Status = EFI_SUCCESS;
    197 
    198   //Transfer configuration for transmitting data
    199   MmioWrite16(I2C_CNT, Length);
    200   MmioWrite16(I2C_CON, (I2C_EN | TRX | MST | STT | STP));
    201 
    202   while (Index < Length) {
    203     //Send a byte
    204     Status = I2CWriteOneByte(Buffer[Index++]);
    205     if (EFI_ERROR(Status)) {
    206       return Status;
    207     }
    208   }
    209 
    210   //Transfer completion
    211   Status = PollForStatus(ARDY);
    212   if (EFI_ERROR(Status)) {
    213     return Status;
    214   }
    215 
    216   return Status;
    217 }
    218 
    219 //
    220 // Public Functions.
    221 //
    222 EFI_STATUS
    223 EFIAPI
    224 SmbusExecute (
    225   IN CONST EFI_SMBUS_HC_PROTOCOL    *This,
    226   IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
    227   IN CONST EFI_SMBUS_DEVICE_COMMAND Command,
    228   IN CONST EFI_SMBUS_OPERATION      Operation,
    229   IN CONST BOOLEAN                  PecCheck,
    230   IN OUT   UINTN                    *Length,
    231   IN OUT   VOID                     *Buffer
    232   )
    233 {
    234   UINT8      *ByteBuffer  = Buffer;
    235   EFI_STATUS Status       = EFI_SUCCESS;
    236   UINT8      SlaveAddr    = (UINT8)(SlaveAddress.SmbusDeviceAddress);
    237 
    238   if (PecCheck) {
    239     return EFI_UNSUPPORTED;
    240   }
    241 
    242   if ((Operation != EfiSmbusWriteBlock) && (Operation != EfiSmbusReadBlock)) {
    243     return EFI_UNSUPPORTED;
    244   }
    245 
    246   //Set the Slave address.
    247   MmioWrite16(I2C_SA, SlaveAddr);
    248 
    249   if (Operation == EfiSmbusReadBlock) {
    250     Status = SmbusBlockRead(ByteBuffer, *Length);
    251   } else if (Operation == EfiSmbusWriteBlock) {
    252     Status = SmbusBlockWrite(ByteBuffer, *Length);
    253   }
    254 
    255   return Status;
    256 }
    257 
    258 EFI_STATUS
    259 EFIAPI
    260 SmbusArpDevice (
    261   IN CONST EFI_SMBUS_HC_PROTOCOL    *This,
    262   IN       BOOLEAN                  ArpAll,
    263   IN       EFI_SMBUS_UDID           *SmbusUdid OPTIONAL,
    264   IN OUT   EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL
    265   )
    266 {
    267   return EFI_UNSUPPORTED;
    268 }
    269 
    270 
    271 EFI_STATUS
    272 EFIAPI
    273 SmbusGetArpMap (
    274   IN CONST EFI_SMBUS_HC_PROTOCOL    *This,
    275   IN OUT   UINTN                    *Length,
    276   IN OUT   EFI_SMBUS_DEVICE_MAP     **SmbusDeviceMap
    277   )
    278 {
    279   return EFI_UNSUPPORTED;
    280 }
    281 
    282 
    283 EFI_STATUS
    284 EFIAPI
    285 SmbusNotify (
    286   IN CONST  EFI_SMBUS_HC_PROTOCOL     *This,
    287   IN CONST  EFI_SMBUS_DEVICE_ADDRESS  SlaveAddress,
    288   IN CONST  UINTN                     Data,
    289   IN CONST  EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
    290   )
    291 {
    292   return EFI_UNSUPPORTED;
    293 }
    294 
    295 EFI_SMBUS_HC_PROTOCOL SmbusProtocol =
    296 {
    297   SmbusExecute,
    298   SmbusArpDevice,
    299   SmbusGetArpMap,
    300   SmbusNotify
    301 };
    302 
    303 EFI_STATUS
    304 InitializeSmbus (
    305     IN EFI_HANDLE       ImageHandle,
    306     IN EFI_SYSTEM_TABLE *SystemTable
    307     )
    308 {
    309   EFI_HANDLE      Handle = NULL;
    310   EFI_STATUS      Status;
    311 
    312   //Configure I2C controller.
    313   Status = ConfigureI2c();
    314   if (EFI_ERROR(Status)) {
    315     DEBUG ((EFI_D_ERROR, "InitializeI2c fails.\n"));
    316     return Status;
    317   }
    318 
    319   // Install the SMBUS interface
    320   Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiSmbusHcProtocolGuid, &SmbusProtocol, NULL);
    321   ASSERT_EFI_ERROR(Status);
    322 
    323   return Status;
    324 }
    325 
    326