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 Read 8bit character from debug stream. 95 96 Block until character is read. 97 98 @return 8bit character read from debug stream. 99 100 **/ 101 CHAR8 102 EFIAPI 103 PlatformDebugPortGetChar8 ( 104 VOID 105 ) 106 { 107 CHAR8 Got; 108 109 do { 110 if (SerialPortPoll ()) { 111 if (SerialPortRead ((UINT8 *) &Got, 1) == 1) { 112 break; 113 } 114 } 115 } while (TRUE); 116 117 return Got; 118 } 119 120 /** 121 Clear SPI Protect registers. 122 123 @retval EFI_SUCCESS SPI protect registers cleared. 124 @retval EFI_ACCESS_DENIED Unable to clear SPI protect registers. 125 **/ 126 127 EFI_STATUS 128 EFIAPI 129 PlatformClearSpiProtect ( 130 VOID 131 ) 132 { 133 UINT32 PchRootComplexBar; 134 135 PchRootComplexBar = QNC_RCRB_BASE; 136 // 137 // Check if the SPI interface has been locked-down. 138 // 139 if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) { 140 return EFI_ACCESS_DENIED; 141 } 142 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0, 0); 143 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 144 return EFI_ACCESS_DENIED; 145 } 146 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR1, 0); 147 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 148 return EFI_ACCESS_DENIED; 149 } 150 MmioWrite32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR2, 0); 151 if (MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIPBR0) != 0) { 152 return EFI_ACCESS_DENIED; 153 } 154 return EFI_SUCCESS; 155 } 156 157 /** 158 Determine if an SPI address range is protected. 159 160 @param SpiBaseAddress Base of SPI range. 161 @param Length Length of SPI range. 162 163 @retval TRUE Range is protected. 164 @retval FALSE Range is not protected. 165 **/ 166 BOOLEAN 167 EFIAPI 168 PlatformIsSpiRangeProtected ( 169 IN CONST UINT32 SpiBaseAddress, 170 IN CONST UINT32 Length 171 ) 172 { 173 UINT32 RegVal; 174 UINT32 Offset; 175 UINT32 Limit; 176 UINT32 ProtectedBase; 177 UINT32 ProtectedLimit; 178 UINT32 PchRootComplexBar; 179 180 PchRootComplexBar = QNC_RCRB_BASE; 181 182 if (Length > 0) { 183 Offset = R_QNC_RCRB_SPIPBR0; 184 Limit = SpiBaseAddress + (Length - 1); 185 do { 186 RegVal = MmioRead32 (PchRootComplexBar + Offset); 187 if ((RegVal & B_QNC_RCRB_SPIPBRn_WPE) != 0) { 188 ProtectedBase = (RegVal & 0xfff) << 12; 189 ProtectedLimit = (RegVal & 0x00fff000) + 0xfff; 190 if (SpiBaseAddress >= ProtectedBase && Limit <= ProtectedLimit) { 191 return TRUE; 192 } 193 } 194 if (Offset == R_QNC_RCRB_SPIPBR0) { 195 Offset = R_QNC_RCRB_SPIPBR1; 196 } else if (Offset == R_QNC_RCRB_SPIPBR1) { 197 Offset = R_QNC_RCRB_SPIPBR2; 198 } else { 199 break; 200 } 201 } while (TRUE); 202 } 203 return FALSE; 204 } 205 206 /** 207 Set Legacy GPIO Level 208 209 @param LevelRegOffset GPIO level register Offset from GPIO Base Address. 210 @param GpioNum GPIO bit to change. 211 @param HighLevel If TRUE set GPIO High else Set GPIO low. 212 213 **/ 214 VOID 215 EFIAPI 216 PlatformLegacyGpioSetLevel ( 217 IN CONST UINT32 LevelRegOffset, 218 IN CONST UINT32 GpioNum, 219 IN CONST BOOLEAN HighLevel 220 ) 221 { 222 UINT32 RegValue; 223 UINT32 GpioBaseAddress; 224 UINT32 GpioNumMask; 225 226 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; 227 ASSERT (GpioBaseAddress > 0); 228 229 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); 230 GpioNumMask = (1 << GpioNum); 231 if (HighLevel) { 232 RegValue |= (GpioNumMask); 233 } else { 234 RegValue &= ~(GpioNumMask); 235 } 236 IoWrite32 (GpioBaseAddress + LevelRegOffset, RegValue); 237 } 238 239 /** 240 Get Legacy GPIO Level 241 242 @param LevelRegOffset GPIO level register Offset from GPIO Base Address. 243 @param GpioNum GPIO bit to check. 244 245 @retval TRUE If bit is SET. 246 @retval FALSE If bit is CLEAR. 247 248 **/ 249 BOOLEAN 250 EFIAPI 251 PlatformLegacyGpioGetLevel ( 252 IN CONST UINT32 LevelRegOffset, 253 IN CONST UINT32 GpioNum 254 ) 255 { 256 UINT32 RegValue; 257 UINT32 GpioBaseAddress; 258 UINT32 GpioNumMask; 259 260 GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; 261 RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); 262 GpioNumMask = (1 << GpioNum); 263 return ((RegValue & GpioNumMask) != 0); 264 } 265 266 267 BOOLEAN 268 Pcal9555GetPortRegBit ( 269 IN CONST UINT32 Pcal9555SlaveAddr, 270 IN CONST UINT32 GpioNum, 271 IN CONST UINT8 RegBase 272 ) 273 { 274 EFI_STATUS Status; 275 UINTN ReadLength; 276 UINTN WriteLength; 277 UINT8 Data[2]; 278 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr; 279 EFI_I2C_ADDR_MODE I2cAddrMode; 280 UINT8 *RegValuePtr; 281 UINT8 GpioNumMask; 282 UINT8 SubAddr; 283 284 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr; 285 I2cAddrMode = EfiI2CSevenBitAddrMode; 286 287 if (GpioNum < 8) { 288 SubAddr = RegBase; 289 GpioNumMask = (UINT8)(1 << GpioNum); 290 } else { 291 SubAddr = RegBase + 1; 292 GpioNumMask = (UINT8)(1 << (GpioNum - 8)); 293 } 294 295 // 296 // Output port value always at 2nd byte in Data variable. 297 // 298 RegValuePtr = &Data[1]; 299 300 // 301 // On read entry sub address at 2nd byte, on read exit output 302 // port value in 2nd byte. 303 // 304 Data[1] = SubAddr; 305 WriteLength = 1; 306 ReadLength = 1; 307 Status = I2cReadMultipleByte ( 308 I2cDeviceAddr, 309 I2cAddrMode, 310 &WriteLength, 311 &ReadLength, 312 &Data[1] 313 ); 314 ASSERT_EFI_ERROR (Status); 315 316 // 317 // Adjust output port bit given callers request. 318 // 319 return ((*RegValuePtr & GpioNumMask) != 0); 320 } 321 322 VOID 323 Pcal9555SetPortRegBit ( 324 IN CONST UINT32 Pcal9555SlaveAddr, 325 IN CONST UINT32 GpioNum, 326 IN CONST UINT8 RegBase, 327 IN CONST BOOLEAN LogicOne 328 ) 329 { 330 EFI_STATUS Status; 331 UINTN ReadLength; 332 UINTN WriteLength; 333 UINT8 Data[2]; 334 EFI_I2C_DEVICE_ADDRESS I2cDeviceAddr; 335 EFI_I2C_ADDR_MODE I2cAddrMode; 336 UINT8 *RegValuePtr; 337 UINT8 GpioNumMask; 338 UINT8 SubAddr; 339 340 I2cDeviceAddr.I2CDeviceAddress = (UINTN)Pcal9555SlaveAddr; 341 I2cAddrMode = EfiI2CSevenBitAddrMode; 342 343 if (GpioNum < 8) { 344 SubAddr = RegBase; 345 GpioNumMask = (UINT8)(1 << GpioNum); 346 } else { 347 SubAddr = RegBase + 1; 348 GpioNumMask = (UINT8)(1 << (GpioNum - 8)); 349 } 350 351 // 352 // Output port value always at 2nd byte in Data variable. 353 // 354 RegValuePtr = &Data[1]; 355 356 // 357 // On read entry sub address at 2nd byte, on read exit output 358 // port value in 2nd byte. 359 // 360 Data[1] = SubAddr; 361 WriteLength = 1; 362 ReadLength = 1; 363 Status = I2cReadMultipleByte ( 364 I2cDeviceAddr, 365 I2cAddrMode, 366 &WriteLength, 367 &ReadLength, 368 &Data[1] 369 ); 370 ASSERT_EFI_ERROR (Status); 371 372 // 373 // Adjust output port bit given callers request. 374 // 375 if (LogicOne) { 376 *RegValuePtr = *RegValuePtr | GpioNumMask; 377 } else { 378 *RegValuePtr = *RegValuePtr & ~(GpioNumMask); 379 } 380 381 // 382 // Update register. Sub address at 1st byte, value at 2nd byte. 383 // 384 WriteLength = 2; 385 Data[0] = SubAddr; 386 Status = I2cWriteMultipleByte ( 387 I2cDeviceAddr, 388 I2cAddrMode, 389 &WriteLength, 390 Data 391 ); 392 ASSERT_EFI_ERROR (Status); 393 } 394 395 /** 396 Set the direction of Pcal9555 IO Expander GPIO pin. 397 398 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 399 @param GpioNum Gpio direction to configure - values 0-7 for Port0 400 and 8-15 for Port1. 401 @param CfgAsInput If TRUE set pin direction as input else set as output. 402 403 **/ 404 VOID 405 EFIAPI 406 PlatformPcal9555GpioSetDir ( 407 IN CONST UINT32 Pcal9555SlaveAddr, 408 IN CONST UINT32 GpioNum, 409 IN CONST BOOLEAN CfgAsInput 410 ) 411 { 412 Pcal9555SetPortRegBit ( 413 Pcal9555SlaveAddr, 414 GpioNum, 415 PCAL9555_REG_CFG_PORT0, 416 CfgAsInput 417 ); 418 } 419 420 /** 421 Set the level of Pcal9555 IO Expander GPIO high or low. 422 423 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 424 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 425 for Port1. 426 @param HighLevel If TRUE set pin high else set pin low. 427 428 **/ 429 VOID 430 EFIAPI 431 PlatformPcal9555GpioSetLevel ( 432 IN CONST UINT32 Pcal9555SlaveAddr, 433 IN CONST UINT32 GpioNum, 434 IN CONST BOOLEAN HighLevel 435 ) 436 { 437 Pcal9555SetPortRegBit ( 438 Pcal9555SlaveAddr, 439 GpioNum, 440 PCAL9555_REG_OUT_PORT0, 441 HighLevel 442 ); 443 } 444 445 /** 446 447 Enable pull-up/pull-down resistors of Pcal9555 GPIOs. 448 449 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 450 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 451 for Port1. 452 453 **/ 454 VOID 455 EFIAPI 456 PlatformPcal9555GpioEnablePull ( 457 IN CONST UINT32 Pcal9555SlaveAddr, 458 IN CONST UINT32 GpioNum 459 ) 460 { 461 Pcal9555SetPortRegBit ( 462 Pcal9555SlaveAddr, 463 GpioNum, 464 PCAL9555_REG_PULL_EN_PORT0, 465 TRUE 466 ); 467 } 468 469 /** 470 471 Disable pull-up/pull-down resistors of Pcal9555 GPIOs. 472 473 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 474 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 475 for Port1. 476 477 **/ 478 VOID 479 EFIAPI 480 PlatformPcal9555GpioDisablePull ( 481 IN CONST UINT32 Pcal9555SlaveAddr, 482 IN CONST UINT32 GpioNum 483 ) 484 { 485 Pcal9555SetPortRegBit ( 486 Pcal9555SlaveAddr, 487 GpioNum, 488 PCAL9555_REG_PULL_EN_PORT0, 489 FALSE 490 ); 491 } 492 493 /** 494 495 Get state of Pcal9555 GPIOs. 496 497 @param Pcal9555SlaveAddr I2c Slave address of Pcal9555 Io Expander. 498 @param GpioNum Gpio to change values 0-7 for Port0 and 8-15 499 for Port1. 500 501 @retval TRUE GPIO pin is high 502 @retval FALSE GPIO pin is low 503 **/ 504 BOOLEAN 505 EFIAPI 506 PlatformPcal9555GpioGetState ( 507 IN CONST UINT32 Pcal9555SlaveAddr, 508 IN CONST UINT32 GpioNum 509 ) 510 { 511 return Pcal9555GetPortRegBit (Pcal9555SlaveAddr, GpioNum, PCAL9555_REG_IN_PORT0); 512 } 513 514 515