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