Home | History | Annotate | Download | only in PlatformHelperLib
      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