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