Home | History | Annotate | Download | only in QNC
      1 /** @file
      2 
      3 This driver is responsible for the registration of child drivers
      4 and the abstraction of the QNC SMI sources.
      5 
      6 Copyright (c) 2013-2015 Intel Corporation.
      7 
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 //
     19 // Include common header file for this module.
     20 //
     21 #include "CommonHeader.h"
     22 
     23 #include "QNCSmmHelpers.h"
     24 
     25 //
     26 // Help handle porting bit shifts to IA-64.
     27 //
     28 #define BIT_ZERO 0x00000001
     29 
     30 
     31 VOID
     32 QNCSmmPublishDispatchProtocols(
     33   VOID
     34   )
     35 {
     36   UINTN      Index;
     37   EFI_STATUS Status;
     38 
     39   //
     40   // Install protocol interfaces.
     41   //
     42   for (Index = 0; Index < NUM_PROTOCOLS; Index++) {
     43     Status = gSmst->SmmInstallProtocolInterface (
     44                  &mPrivateData.InstallMultProtHandle,
     45                       mPrivateData.Protocols[Index].Guid,
     46                       EFI_NATIVE_INTERFACE,
     47                       &mPrivateData.Protocols[Index].Protocols.Generic
     48                  );
     49 
     50   ASSERT_EFI_ERROR (Status);
     51 }
     52 }
     53 
     54 EFI_STATUS
     55 QNCSmmInitHardware(
     56   VOID
     57   )
     58 /*++
     59 
     60 Routine Description:
     61 
     62   Initialize bits that aren't necessarily related to an SMI source.
     63 
     64 Dependencies:
     65 
     66   gSmst - SMM System Table; contains an entry for SMM CPU IO
     67 
     68 Returns:
     69 
     70   EFI_SUCCESS.  Asserts, otherwise.
     71 
     72 --*/
     73 {
     74   EFI_STATUS Status;
     75 
     76   //
     77   // Clear all SMIs
     78   //
     79   QNCSmmClearSmi();
     80 
     81   Status = QNCSmmEnableGlobalSmiBit ();
     82   ASSERT_EFI_ERROR (Status);
     83 
     84   //
     85   // Be *really* sure to clear all SMIs
     86   //
     87   QNCSmmClearSmi ();
     88 
     89   return EFI_SUCCESS;
     90 }
     91 
     92 EFI_STATUS
     93 QNCSmmEnableGlobalSmiBit (
     94   VOID
     95   )
     96 /*++
     97 
     98 Routine Description:
     99 
    100   Enables the QNC to generate SMIs. Note that no SMIs will be generated
    101   if no SMI sources are enabled. Conversely, no enabled SMI source will
    102   generate SMIs if SMIs are not globally enabled. This is the main
    103   switchbox for SMI generation.
    104 
    105 Arguments:
    106 
    107   None
    108 
    109 Returns:
    110 
    111   EFI_SUCCESS.
    112   Asserts, otherwise.
    113 
    114 --*/
    115 {
    116   UINT32        NewValue;
    117 
    118   //
    119   // Enable SMI globally
    120   //
    121   NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
    122   NewValue |= SMI_EN;
    123   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
    124 
    125   return EFI_SUCCESS;
    126 }
    127 
    128 EFI_STATUS
    129 QNCSmmClearSmi(
    130   VOID
    131   )
    132 /*++
    133 
    134 Routine Description:
    135 
    136   Clears the SMI after all SMI source have been processed.
    137   Note that this function will not work correctly (as it is
    138   written) unless all SMI sources have been processed.
    139   A revision of this function could manually clear all SMI
    140   status bits to guarantee success.
    141 
    142 Returns:
    143 
    144   EFI_SUCCESS.
    145   Asserts, otherwise.
    146 
    147 --*/
    148 {
    149   BOOLEAN EosSet;
    150   BOOLEAN SciEn;
    151 
    152   UINT32 Pm1Cnt = 0;
    153   UINT16 Pm1Sts = 0;
    154   UINT32 Gpe0Sts = 0;
    155   UINT32 SmiSts  = 0;
    156 
    157   //
    158   // Determine whether an ACPI OS is present (via the SCI_EN bit)
    159   //
    160   Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
    161   SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
    162 
    163   if (SciEn == FALSE) {
    164 
    165     //
    166     // Clear any SMIs that double as SCIs (when SCI_EN==0)
    167     //
    168     Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);
    169 
    170     Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;
    171 
    172     IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);
    173     IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);
    174   }
    175 
    176   //
    177   // Clear all SMIs that are unaffected by SCI_EN
    178   //
    179   SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
    180   SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
    181   IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);
    182 
    183   //
    184   // Try to clear the EOS bit. ASSERT on an error
    185   //
    186   EosSet = QNCSmmSetAndCheckEos();
    187   ASSERT (EosSet);
    188 
    189   return EFI_SUCCESS;
    190 }
    191 
    192 BOOLEAN
    193 QNCSmmSetAndCheckEos(
    194   VOID
    195   )
    196 {
    197   //
    198   // Reset the QNC to generate subsequent SMIs
    199   //
    200   IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
    201     return TRUE;
    202 }
    203 
    204 BOOLEAN
    205 QNCSmmGetSciEn(
    206   )
    207 {
    208   BOOLEAN SciEn;
    209   UINT32 Pm1Cnt;
    210 
    211   //
    212   // Determine whether an ACPI OS is present (via the SCI_EN bit)
    213   //
    214   Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
    215 
    216   SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
    217 
    218   return SciEn;
    219 }
    220 
    221 //
    222 // These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.
    223 //
    224 
    225 BOOLEAN
    226 ReadBitDesc (
    227   CONST QNC_SMM_BIT_DESC  *BitDesc
    228   )
    229 {
    230   UINT64           Register;
    231   UINT32           PciBus;
    232   UINT32           PciDev;
    233   UINT32           PciFun;
    234   UINT32           PciReg;
    235   BOOLEAN          BitWasOne;
    236 
    237   ASSERT (BitDesc != NULL );
    238   ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );
    239 
    240   Register  = 0;
    241   BitWasOne = FALSE;
    242 
    243   switch (BitDesc->Reg.Type) {
    244 
    245   case ACPI_ADDR_TYPE:
    246     //
    247     // Double check that we correctly read in the acpi base address
    248     //
    249     ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );
    250 
    251     switch (BitDesc->SizeInBytes) {
    252 
    253     case 0:
    254       //
    255       // Chances are that this field didn't get initialized.
    256       // Check your assignments to bit descriptions.
    257       //
    258       ASSERT (FALSE );
    259       break;
    260 
    261       case 1:
    262       Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
    263         break;
    264 
    265       case 2:
    266       Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
    267         break;
    268 
    269       case 4:
    270       Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
    271         break;
    272 
    273       default:
    274         //
    275         // Unsupported or invalid register size
    276         //
    277         ASSERT (FALSE );
    278         break;
    279       };
    280 
    281     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
    282         BitWasOne = TRUE;
    283       } else {
    284         BitWasOne = FALSE;
    285       }
    286     break;
    287 
    288   case GPE_ADDR_TYPE:
    289       //
    290     // Double check that we correctly read in the gpe base address
    291       //
    292     ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );
    293 
    294     switch (BitDesc->SizeInBytes) {
    295 
    296     case 0:
    297       //
    298       // Chances are that this field didn't get initialized.
    299       // Check your assignments to bit descriptions.
    300       //
    301       ASSERT (FALSE );
    302       break;
    303 
    304     case 1:
    305       Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
    306       break;
    307 
    308     case 2:
    309       Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
    310       break;
    311 
    312     case 4:
    313       Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
    314       break;
    315 
    316     default:
    317       //
    318       // Unsupported or invalid register size
    319       //
    320       ASSERT (FALSE );
    321       break;
    322     };
    323 
    324     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
    325         BitWasOne = TRUE;
    326       } else {
    327         BitWasOne = FALSE;
    328       }
    329     break;
    330 
    331   case MEMORY_MAPPED_IO_ADDRESS_TYPE:
    332     //
    333     // Read the register, and it with the bit to read
    334     //
    335 
    336     //
    337     // This code does not support reads greater then 64 bits
    338     //
    339     ASSERT (BitDesc->SizeInBytes <= 8);
    340     CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
    341     Register &= LShiftU64 (BIT0, BitDesc->Bit);
    342     if (Register) {
    343       BitWasOne = TRUE;
    344     } else {
    345       BitWasOne = FALSE;
    346     }
    347     break;
    348 
    349   case PCI_ADDR_TYPE:
    350     PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
    351     PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
    352     PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
    353     PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
    354     switch (BitDesc->SizeInBytes) {
    355 
    356     case 0:
    357       //
    358       // Chances are that this field didn't get initialized.
    359       // Check your assignments to bit descriptions.
    360       ASSERT (FALSE );
    361       break;
    362 
    363     case 1:
    364       Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
    365       break;
    366 
    367     case 2:
    368       Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
    369       break;
    370 
    371     case 4:
    372       Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
    373       break;
    374 
    375     default:
    376       //
    377       // Unsupported or invalid register size
    378       //
    379       ASSERT (FALSE );
    380       break;
    381     };
    382 
    383     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
    384         BitWasOne = TRUE;
    385     } else {
    386       BitWasOne = FALSE;
    387     }
    388     break;
    389 
    390   default:
    391     //
    392     // This address type is not yet implemented
    393     //
    394     ASSERT (FALSE );
    395     break;
    396   };
    397 
    398   return BitWasOne;
    399 }
    400 
    401 VOID
    402 WriteBitDesc (
    403   CONST QNC_SMM_BIT_DESC   *BitDesc,
    404   CONST BOOLEAN           ValueToWrite
    405   )
    406 {
    407   UINT64           Register;
    408   UINT64           AndVal;
    409   UINT64           OrVal;
    410   UINT32           PciBus;
    411   UINT32           PciDev;
    412   UINT32           PciFun;
    413   UINT32           PciReg;
    414 
    415   ASSERT (BitDesc != NULL);
    416   ASSERT (!IS_BIT_DESC_NULL(*BitDesc));
    417 
    418   AndVal = ~(BIT_ZERO << (BitDesc->Bit));
    419   OrVal  = ((UINT32)ValueToWrite) << (BitDesc->Bit);
    420 
    421   switch (BitDesc->Reg.Type) {
    422 
    423   case ACPI_ADDR_TYPE:
    424     //
    425     // Double check that we correctly read in the acpi base address
    426     //
    427     ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));
    428 
    429     switch (BitDesc->SizeInBytes) {
    430 
    431     case 0:
    432       //
    433       // Chances are that this field didn't get initialized.
    434       // Check your assignments to bit descriptions.
    435       //
    436       ASSERT (FALSE );
    437       break;
    438 
    439     case 1:
    440       IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);
    441       break;
    442 
    443     case 2:
    444       IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);
    445       break;
    446 
    447     case 4:
    448       IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);
    449       break;
    450 
    451     default:
    452       //
    453       // Unsupported or invalid register size
    454       //
    455       ASSERT (FALSE );
    456       break;
    457     };
    458     break;
    459 
    460   case GPE_ADDR_TYPE:
    461     //
    462     // Double check that we correctly read in the gpe base address
    463     //
    464     ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));
    465 
    466     switch (BitDesc->SizeInBytes) {
    467 
    468     case 0:
    469       //
    470       // Chances are that this field didn't get initialized.
    471       // Check your assignments to bit descriptions.
    472       //
    473       ASSERT (FALSE );
    474       break;
    475 
    476     case 1:
    477       IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);
    478       break;
    479 
    480     case 2:
    481       IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);
    482       break;
    483 
    484     case 4:
    485       IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);
    486       break;
    487 
    488     default:
    489       //
    490       // Unsupported or invalid register size
    491       //
    492       ASSERT (FALSE );
    493       break;
    494     };
    495       break;
    496 
    497   case MEMORY_MAPPED_IO_ADDRESS_TYPE:
    498     //
    499     // Read the register, or it with the bit to set, then write it back.
    500     //
    501 
    502     //
    503     // This code does not support writes greater then 64 bits
    504     //
    505     ASSERT (BitDesc->SizeInBytes <= 8);
    506     CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
    507     Register &= AndVal;
    508     Register |= OrVal;
    509     CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);
    510     break;
    511 
    512   case PCI_ADDR_TYPE:
    513     PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
    514     PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
    515     PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
    516     PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
    517     switch (BitDesc->SizeInBytes) {
    518 
    519     case 0:
    520       //
    521       // Chances are that this field didn't get initialized -- check your assignments
    522       // to bit descriptions.
    523       //
    524       ASSERT (FALSE );
    525       break;
    526 
    527     case 1:
    528       PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);
    529       break;
    530 
    531     case 2:
    532       PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);
    533       break;
    534 
    535     case 4:
    536       PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);
    537       break;
    538 
    539     default:
    540       //
    541       // Unsupported or invalid register size
    542       //
    543       ASSERT (FALSE );
    544       break;
    545     };
    546     break;
    547 
    548     default:
    549     //
    550     // This address type is not yet implemented
    551     //
    552     ASSERT (FALSE );
    553     break;
    554   };
    555 }
    556