1 /** @file 2 Helper routines with common PEI / DXE implementation. 3 4 Copyright (c) 2013-2016 Intel Corporation. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "CommonHeader.h" 17 #include <Library/I2cLib.h> 18 19 CHAR16 *mPlatTypeNameTable[] = { EFI_PLATFORM_TYPE_NAME_TABLE_DEFINITION }; 20 UINTN mPlatTypeNameTableLen = ((sizeof(mPlatTypeNameTable)) / sizeof (CHAR16 *)); 21 22 // 23 // Routines defined in other source modules of this component. 24 // 25 26 // 27 // Routines local to this source module. 28 // 29 30 // 31 // Routines shared with other souce modules in this component. 32 // 33 34 EFI_STATUS 35 WriteFirstFreeSpiProtect ( 36 IN CONST UINT32 PchRootComplexBar, 37 IN CONST UINT32 DirectValue, 38 IN CONST UINT32 BaseAddress, 39 IN CONST UINT32 Length, 40 OUT UINT32 *OffsetPtr 41 ) 42 { 43 UINT32 RegVal; 44 UINT32 Offset; 45 UINT32 StepLen; 46 47 ASSERT (PchRootComplexBar > 0); 48 49 Offset = 0; 50 if (OffsetPtr != NULL) { 51 *OffsetPtr = Offset; 52 } 53 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) == 0) { 54 Offset = R_QNC_RCRB_SPIPBR0; 55 } else { 56 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1) == 0) { 57 Offset = R_QNC_RCRB_SPIPBR1; 58 } else { 59 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2) == 0) { 60 Offset = R_QNC_RCRB_SPIPBR2; 61 } 62 } 63 } 64 if (Offset != 0) { 65 if (DirectValue == 0) { 66 StepLen = ALIGN_VALUE (Length,SIZE_4KB); // Bring up to 4K boundary. 67 RegVal = BaseAddress + StepLen - 1; 68 RegVal &= 0x00FFF000; // Set EDS Protected Range Limit (PRL). 69 RegVal |= ((BaseAddress >> 12) & 0xfff); // or in EDS Protected Range Base (PRB). 70 } else { 71 RegVal = DirectValue; 72 } 73 // 74 // Enable protection. 75 // 76 RegVal |= B_QNC_RCRB_SPIPBRn_WPE; 77 MmioWrite32 (PchRootComplexBar + Offset, RegVal); 78 if (RegVal == MmioRead32 (PchRootComplexBar + Offset)) { 79 if (OffsetPtr != NULL) { 80 *OffsetPtr = Offset; 81 } 82 return EFI_SUCCESS; 83 } 84 return EFI_DEVICE_ERROR; 85 } 86 return EFI_NOT_FOUND; 87 } 88 89 // 90 // Routines exported by this component. 91 // 92 93 /** 94 Clear SPI Protect registers. 95 96 @retval EFI_SUCCESS SPI protect registers cleared. 97 @retval EFI_ACCESS_DENIED Unable to clear SPI protect registers. 98 **/ 99 100 EFI_STATUS 101 EFIAPI 102 PlatformClearSpiProtect ( 103 VOID 104 ) 105 { 106 UINT32 PchRootComplexBar; 107 108 PchRootComplexBar = QNC_RCRB_BASE; 109 // 110 // Check if the SPI interface has been locked-down. 111 // 112 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) { 113 return EFI_ACCESS_DENIED; 114 } 115 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0, 0); 116 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 117 return EFI_ACCESS_DENIED; 118 } 119 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1, 0); 120 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 121 return EFI_ACCESS_DENIED; 122 } 123 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2, 0); 124 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 125 return EFI_ACCESS_DENIED; 126 } 127 return EFI_SUCCESS; 128 } 129 130 /** 131 Determine if an SPI address range is protected. 132 133 @param SpiBaseAddress Base of SPI range. 134 @param Length Length of SPI range. 135 136 @retval TRUE Range is protected. 137 @retval FALSE Range is not protected. 138 **/ 139 BOOLEAN 140 EFIAPI 141 PlatformIsSpiRangeProtected ( 142 IN CONST UINT32 SpiBaseAddress, 143 IN CONST UINT32 Length 144 ) 145 { 146 UINT32 RegVal; 147 UINT32 Offset; 148 UINT32 Limit; 149 UINT32 ProtectedBase; 150 UINT32 ProtectedLimit; 151 UINT32 PchRootComplexBar; 152 153 PchRootComplexBar = QNC_RCRB_BASE; 154 155 if (Length > 0) { 156 Offset = R_QNC_RCRB_SPIPBR0; 157 Limit = SpiBaseAddress + (Length - 1); 158 do { 159 RegVal = MmioRead32 (PchRootComplexBar + Offset); 160 if ((RegVal & B_QNC_RCRB_SPIPBRn_WPE) != 0) { 161 ProtectedBase = (RegVal & 0xfff) << 12; 162 ProtectedLimit = (RegVal & 0x00fff000) + 0xfff; 163 if (SpiBaseAddress >= ProtectedBase && Limit <= ProtectedLimit) { 164 return TRUE; 165 } 166 } 167 if (Offset == R_QNC_RCRB_SPIPBR0) { 168 Offset = R_QNC_RCRB_SPIPBR1; 169 } else if (Offset == R_QNC_RCRB_SPIPBR1) { 170 Offset = R_QNC_RCRB_SPIPBR2; 171 } else { 172 break; 173 } 174 } while (TRUE); 175 } 176 return FALSE; 177 } 178 179 /** 180 Set Legacy GPIO Level 181 182 @param LevelRegOffset GPIO level register Offset from GPIO Base Address. 183 @param GpioNum GPIO bit to change. 184 @param HighLevel If TRUE set GPIO High else Set GPIO low. 185 186 **/ 187 VOID 188 EFIAPI 189 PlatformLegacyGpioSetLevel ( 190 IN CONST UINT32 LevelRegOffset, 191 IN CONST UINT32 GpioNum, 192 IN CONST BOOLEAN HighLevel 193 ) 194 { 195 UINT32 RegValue; 196 UINT32 GpioBaseAddress; 197 UINT32 GpioNumMask; 198 199 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; 200 ASSERT (GpioBaseAddress > 0); 201 202 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); 203 GpioNumMask = (1 << GpioNum); 204 if (HighLevel) { 205 RegValue |= (GpioNumMask); 206 } else { 207 RegValue &= ~(GpioNumMask); 208 } 209 IoWrite32 (GpioBaseAddress + LevelRegOffset, RegValue); 210 } 211 212 /** 213 Get Legacy GPIO Level 214 215 @param LevelRegOffset GPIO level register Offset from GPIO Base Address. 216 @param GpioNum GPIO bit to check. 217 218 @retval TRUE If bit is SET. 219 @retval FALSE If bit is CLEAR. 220 221 **/ 222 BOOLEAN 223 EFIAPI 224 PlatformLegacyGpioGetLevel ( 225 IN CONST UINT32 LevelRegOffset, 226 IN CONST UINT32 GpioNum 227 ) 228 { 229 UINT32 RegValue; 230 UINT32 GpioBaseAddress; 231 UINT32 GpioNumMask; 232 233 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; 234 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); 235 GpioNumMask = (1 << GpioNum); 236 return ((RegValue & GpioNumMask) != 0); 237 } 238 239 240 BOOLEAN 241 Pcal9555GetPortRegBit ( 242 IN CONST UINT32 Pcal9555SlaveAddr, 243 IN CONST UINT32 GpioNum, 244 IN CONST UINT8 RegBase 245 ) 246 { 247 EFI_STATUS Status; 248 UINTN ReadLength; 249 UINTN WriteLength; 250 UINT8 Data[2]; 251 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr; 252 EFI_I2C_ADDR_MODE I2cAddrMode; 253 UINT8 *RegValuePtr; 254 UINT8 GpioNumMask; 255 UINT8 SubAddr; 256 257 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr; 258 I2cAddrMode = EfiI2CSevenBitAddrMode; 259 260 if (GpioNum < 8) { 261 SubAddr = RegBase; 262 GpioNumMask = (UINT8)(1 << GpioNum); 263 } else { 264 SubAddr = RegBase + 1; 265 GpioNumMask = (UINT8)(1 << (GpioNum - 8)); 266 } 267 268 // 269 // Output port value always at 2nd byte in Data variable. 270 // 271 RegValuePtr = &Data[1]; 272 273 // 274 // On read entry sub address at 2nd byte, on read exit output 275 // port value in 2nd byte. 276 // 277 Data[1] = SubAddr; 278 WriteLength = 1; 279 ReadLength = 1; 280 Status = I2cReadMultipleByte ( 281 I2cDeviceAddr, 282 I2cAddrMode, 283 &WriteLength, 284 &ReadLength, 285 &Data[1] 286 ); 287 ASSERT_EFI_ERROR (Status); 288 289 // 290 // Adjust output port bit given callers request. 291 // 292 return ((*RegValuePtr & GpioNumMask) != 0); 293 } 294 295 VOID 296 Pcal9555SetPortRegBit ( 297 IN CONST UINT32 Pcal9555SlaveAddr, 298 IN CONST UINT32 GpioNum, 299 IN CONST UINT8 RegBase, 300 IN CONST BOOLEAN LogicOne 301 ) 302 { 303 EFI_STATUS Status; 304 UINTN ReadLength; 305 UINTN WriteLength; 306 UINT8 Data[2]; 307 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr; 308 EFI_I2C_ADDR_MODE I2cAddrMode; 309 UINT8 *RegValuePtr; 310 UINT8 GpioNumMask; 311 UINT8 SubAddr; 312 313 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr; 314 I2cAddrMode = EfiI2CSevenBitAddrMode; 315 316 if (GpioNum < 8) { 317 SubAddr = RegBase; 318 GpioNumMask = (UINT8)(1 << GpioNum); 319 } else { 320 SubAddr = RegBase + 1; 321 GpioNumMask = (UINT8)(1 << (GpioNum - 8)); 322 } 323 324 // 325 // Output port value always at 2nd byte in Data variable. 326 // 327 RegValuePtr = &Data[1]; 328 329 // 330 // On read entry sub address at 2nd byte, on read exit output 331 // port value in 2nd byte. 332 // 333 Data[1] = SubAddr; 334 WriteLength = 1; 335 ReadLength = 1; 336 Status = I2cReadMultipleByte ( 337 I2cDeviceAddr, 338 I2cAddrMode, 339 &WriteLength, 340 &ReadLength, 341 &Data[1] 342 ); 343 ASSERT_EFI_ERROR (Status); 344 345 // 346 // Adjust output port bit given callers request. 347 // 348 if (LogicOne) { 349 *RegValuePtr = *RegValuePtr | GpioNumMask; 350 } else { 351 *RegValuePtr = *RegValuePtr & ~(GpioNumMask); 352 } 353 354 // 355 // Update register. Sub address at 1st byte, value at 2nd byte. 356 // 357 WriteLength = 2; 358 Data[0] = SubAddr; 359 Status = I2cWriteMultipleByte ( 360 I2cDeviceAddr, 361 I2cAddrMode, 362 &WriteLength, 363 Data 364 ); 365 ASSERT_EFI_ERROR (Status); 366 } 367 368 /** 369 Set the direction of Pcal9555 IO Expander GPIO pin. 370 371 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 372 @param GpioNum Gpio direction to configure - values 0-7 for Port0 373 and 8-15 for Port1. 374 @param CfgAsInput If TRUE set pin direction as input else set as output. 375 376 **/ 377 VOID 378 EFIAPI 379 PlatformPcal9555GpioSetDir ( 380 IN CONST UINT32 Pcal9555SlaveAddr, 381 IN CONST UINT32 GpioNum, 382 IN CONST BOOLEAN CfgAsInput 383 ) 384 { 385 Pcal9555SetPortRegBit ( 386 Pcal9555SlaveAddr, 387 GpioNum, 388 PCAL9555_REG_CFG_PORT0, 389 CfgAsInput 390 ); 391 } 392 393 /** 394 Set the level of Pcal9555 IO Expander GPIO high or low. 395 396 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 397 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 398 for Port1. 399 @param HighLevel If TRUE set pin high else set pin low. 400 401 **/ 402 VOID 403 EFIAPI 404 PlatformPcal9555GpioSetLevel ( 405 IN CONST UINT32 Pcal9555SlaveAddr, 406 IN CONST UINT32 GpioNum, 407 IN CONST BOOLEAN HighLevel 408 ) 409 { 410 Pcal9555SetPortRegBit ( 411 Pcal9555SlaveAddr, 412 GpioNum, 413 PCAL9555_REG_OUT_PORT0, 414 HighLevel 415 ); 416 } 417 418 /** 419 420 Enable pull-up/pull-down resistors of Pcal9555 GPIOs. 421 422 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 423 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 424 for Port1. 425 426 **/ 427 VOID 428 EFIAPI 429 PlatformPcal9555GpioEnablePull ( 430 IN CONST UINT32 Pcal9555SlaveAddr, 431 IN CONST UINT32 GpioNum 432 ) 433 { 434 Pcal9555SetPortRegBit ( 435 Pcal9555SlaveAddr, 436 GpioNum, 437 PCAL9555_REG_PULL_EN_PORT0, 438 TRUE 439 ); 440 } 441 442 /** 443 444 Disable pull-up/pull-down resistors of Pcal9555 GPIOs. 445 446 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 447 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 448 for Port1. 449 450 **/ 451 VOID 452 EFIAPI 453 PlatformPcal9555GpioDisablePull ( 454 IN CONST UINT32 Pcal9555SlaveAddr, 455 IN CONST UINT32 GpioNum 456 ) 457 { 458 Pcal9555SetPortRegBit ( 459 Pcal9555SlaveAddr, 460 GpioNum, 461 PCAL9555_REG_PULL_EN_PORT0, 462 FALSE 463 ); 464 } 465 466 /** 467 468 Get state of Pcal9555 GPIOs. 469 470 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 471 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 472 for Port1. 473 474 @retval TRUE GPIO pin is high 475 @retval FALSE GPIO pin is low 476 **/ 477 BOOLEAN 478 EFIAPI 479 PlatformPcal9555GpioGetState ( 480 IN CONST UINT32 Pcal9555SlaveAddr, 481 IN CONST UINT32 GpioNum 482 ) 483 { 484 return Pcal9555GetPortRegBit (Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_IN_PORT0); 485 } 486 487 488