/** @file Lib function for Pei QNC. Copyright (c) 2013-2015 Intel Corporation. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "CommonHeader.h" /** This function provides the necessary SOC initialization before MRC running. It sets RCBA, GPIO, PMBASE and some parts of SOC through SOC message method. If the function cannot complete it'll ASSERT(). **/ VOID EFIAPI PeiQNCPreMemInit ( VOID ) { UINT32 RegValue; // QNCPortWrite(Port#, Offset, Value) // // Set the fixed PRI Status encodings config. // QNCPortWrite ( QUARK_NC_MEMORY_ARBITER_SB_PORT_ID, QUARK_NC_MEMORY_ARBITER_REG_ASTATUS, QNC_FIXED_CONFIG_ASTATUS ); // Sideband register write to Remote Management Unit QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QNC_MSG_TMPM_REG_PMBA, (BIT31 | PcdGet16 (PcdPmbaIoBaseAddress))); // Configurable I/O address in iLB (legacy block) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) = BIT31 | PcdGet16 (PcdSmbaIoBaseAddress); LpcPciCfg32 (R_QNC_LPC_GBA_BASE) = BIT31 | PcdGet16 (PcdGbaIoBaseAddress); LpcPciCfg32 (R_QNC_LPC_PM1BLK) = BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress); LpcPciCfg32 (R_QNC_LPC_GPE0BLK) = BIT31 | PcdGet16 (PcdGpe0blkIoBaseAddress); LpcPciCfg32 (R_QNC_LPC_WDTBA) = BIT31 | PcdGet16 (PcdWdtbaIoBaseAddress); // // Program RCBA Base Address // LpcPciCfg32AndThenOr (R_QNC_LPC_RCBA, (~B_QNC_LPC_RCBA_MASK), (((UINT32)(PcdGet64 (PcdRcbaMmioBaseAddress))) | B_QNC_LPC_RCBA_EN)); // // Program Memory Manager fixed config values. // RegValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL); RegValue &= ~(DRAM_NON_HOST_RQ_LIMIT_MASK); RegValue |= (V_DRAM_NON_HOST_RQ_LIMIT << DRAM_NON_HOST_RQ_LIMIT_BP); QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL, RegValue); // // Program iCLK fixed config values. // QncIClkAndThenOr ( QUARK_ICLK_MUXTOP, (UINT32) ~(B_MUXTOP_FLEX2_MASK | B_MUXTOP_FLEX1_MASK), (V_MUXTOP_FLEX2 << B_MUXTOP_FLEX2_BP) | (V_MUXTOP_FLEX1 << B_MUXTOP_FLEX1_BP) ); QncIClkAndThenOr ( QUARK_ICLK_REF2_DBUFF0, (UINT32) ~(BIT0), // bit[0] cleared 0 ); QncIClkOr ( QUARK_ICLK_SSC1, BIT0 // bit[0] set ); QncIClkOr ( QUARK_ICLK_SSC2, BIT0 // bit[0] set ); QncIClkOr ( QUARK_ICLK_SSC3, BIT0 // bit[0] set ); // // Set RMU DMA disable bit post boot. // RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1); RegValue |= OPTIONS_1_DMA_DISABLE; QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1, RegValue); } /** Do north cluster init which needs to be done AFTER MRC init. @param VOID @retval VOID **/ VOID EFIAPI PeiQNCPostMemInit ( VOID ) { // // Program SVID/SID the same as VID/DID for all devices except root ports. // QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, R_EFI_PCI_SVID) = QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, PCI_VENDOR_ID_OFFSET); QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, PCI_VENDOR_ID_OFFSET); QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET); QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET); return; } /** Used to check QNC if it's S3 state. Clear the register state after query. @retval TRUE if it's S3 state. @retval FALSE if it's not S3 state. **/ BOOLEAN EFIAPI QNCCheckS3AndClearState ( VOID ) { BOOLEAN S3WakeEventFound; UINT16 Pm1Sts; UINT16 Pm1En; UINT16 Pm1Cnt; UINT32 Gpe0Sts; UINT32 Gpe0En; UINT32 NewValue; CHAR8 *EventDescStr; S3WakeEventFound = FALSE; EventDescStr = NULL; // // Read the ACPI registers, // Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S); Pm1En = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E); Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S); Gpe0En = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E); // // Clear Power Management 1 Enable Register and // General Purpost Event 0 Enables Register // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0); IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0); if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S3) { // // Detect the actual WAKE event // if ((Pm1Sts & B_QNC_PM1BLK_PM1S_RTC) && (Pm1En & B_QNC_PM1BLK_PM1E_RTC)) { EventDescStr = "RTC Alarm"; S3WakeEventFound = TRUE; } if ((Pm1Sts & B_QNC_PM1BLK_PM1S_PCIEWSTS) && !(Pm1En & B_QNC_PM1BLK_PM1E_PWAKED)) { EventDescStr = "PCIe WAKE"; S3WakeEventFound = TRUE; } if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_PCIE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_PCIE)) { EventDescStr = "PCIe"; S3WakeEventFound = TRUE; } if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_GPIO) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_GPIO)) { EventDescStr = "GPIO"; S3WakeEventFound = TRUE; } if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_EGPE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_EGPE)) { EventDescStr = "Ext. GPE"; S3WakeEventFound = TRUE; } if (S3WakeEventFound == FALSE) { EventDescStr = "Unknown"; } DEBUG ((EFI_D_INFO, "S3 Wake Event - %a\n", EventDescStr)); // // If no Power Button Override event occurs and one enabled wake event occurs, // just do S3 resume and clear the state. // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP))); // // Set EOS to de Assert SMI // IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS); // // Enable SMI globally // NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); NewValue |= SMI_EN; QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue); return TRUE; } return FALSE; } /** Used to check QNC if system wakes up from power on reset. Clear the register state after query. @retval TRUE if system wakes up from power on reset @retval FALSE if system does not wake up from power on reset **/ BOOLEAN EFIAPI QNCCheckPowerOnResetAndClearState ( VOID ) { UINT16 Pm1Sts; UINT16 Pm1Cnt; // // Read the ACPI registers, // PM1_STS information cannot be lost after power down, unless CMOS is cleared. // Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S); Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); // // If B_SLP_TYP is S5 // if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S5) { IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP))); return TRUE; } return FALSE; } /** This function is used to clear SMI and wake status. **/ VOID EFIAPI QNCClearSmiAndWake ( VOID ) { UINT32 Gpe0Sts; UINT32 SmiSts; // // Read the ACPI registers // Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S); SmiSts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); // // Clear any SMI or wake state from the boot // Gpe0Sts |= B_QNC_GPE0BLK_GPE0S_ALL; SmiSts |= B_QNC_GPE0BLK_SMIS_ALL; // // Write them back // IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S, Gpe0Sts); IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, SmiSts); } /** Send DRAM Ready opcode. @param[in] OpcodeParam Parameter to DRAM ready opcode. @retval VOID **/ VOID EFIAPI QNCSendOpcodeDramReady ( IN UINT32 OpcodeParam ) { // // Before sending DRAM ready place invalid value in Scrub Config. // QNCPortWrite ( QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG, SCRUB_CFG_INVALID ); // // Send opcode and use param to notify HW of new RMU firmware location. // McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = OpcodeParam; McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_SHADOW_DW (QUARK_NC_RMU_SB_PORT_ID, 0); // // HW completed tasks on DRAM ready when scrub config read back as zero. // while (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG) != 0) { MicroSecondDelay (10); } } /** Relocate RMU Main binary to memory after MRC to improve performance. @param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary. @param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary. @param[in] Size - Specify size of the RMU Main binary. @retval VOID **/ VOID EFIAPI RmuMainRelocation ( IN CONST UINT32 DestBaseAddress, IN CONST UINT32 SrcBaseAddress, IN CONST UINTN Size ) { // // Shadow RMU Main binary into main memory. // CopyMem ((VOID *)(UINTN)DestBaseAddress,(VOID *)(UINTN) SrcBaseAddress, Size); } /** Get the total memory size **/ UINT32 EFIAPI QNCGetTotalMemorysize ( VOID ) { return QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG) & HMBOUND_MASK; } /** Get the memory range of TSEG. The TSEG's memory is below TOLM. @param[out] BaseAddress The base address of TSEG's memory range @param[out] MemorySize The size of TSEG's memory range **/ VOID EFIAPI QNCGetTSEGMemoryRange ( OUT UINT64 *BaseAddress, OUT UINT64 *MemorySize ) { UINT64 Register = 0; UINT64 SMMAddress = 0; Register = QncHsmmcRead (); // // Get the SMRAM Base address // SMMAddress = Register & SMM_START_MASK; *BaseAddress = LShift16 (SMMAddress); // // Get the SMRAM size // SMMAddress = ((Register & SMM_END_MASK) | (~SMM_END_MASK)) + 1; *MemorySize = SMMAddress - (*BaseAddress); DEBUG (( EFI_D_INFO, "TSEG's memory range: BaseAddress = 0x%x, Size = 0x%x\n", (UINT32)*BaseAddress, (UINT32)*MemorySize )); } /** Updates the PAM registers in the MCH for the requested range and mode. @param Start The start address of the memory region @param Length The length, in bytes, of the memory region @param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section. If NULL, then read attribute will not be touched by this call. @param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section. If NULL, then write attribute will not be touched by this call. @param Granularity A pointer to granularity, in bytes, that the PAM registers support @retval RETURN_SUCCESS The PAM registers in the MCH were updated @retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region. **/ EFI_STATUS EFIAPI QNCLegacyRegionManipulation ( IN UINT32 Start, IN UINT32 Length, IN BOOLEAN *ReadEnable, IN BOOLEAN *WriteEnable, OUT UINT32 *Granularity ) { // // Do nothing cos no such support on QNC // return RETURN_SUCCESS; } /** Determine if QNC is supported. @retval FALSE QNC is not supported. @retval TRUE QNC is supported. **/ BOOLEAN EFIAPI IsQncSupported ( VOID ) { UINT16 SocVendorId; UINT16 SocDeviceId; SocVendorId = MmioRead16 ( PciDeviceMmBase (MC_BUS, MC_DEV, MC_FUN) + PCI_VENDOR_ID_OFFSET ); SocDeviceId = QncGetSocDeviceId(); // // Verify that this is a supported chipset // if ((SocVendorId != QUARK_MC_VENDOR_ID) || ((SocDeviceId != QUARK_MC_DEVICE_ID) && (SocDeviceId != QUARK2_MC_DEVICE_ID))) { DEBUG ((DEBUG_ERROR, "QNC code doesn't support the Soc VendorId:0x%04x Soc DeviceId:0x%04x!\n", SocVendorId, SocDeviceId)); return FALSE; } return TRUE; } /** Get the DeviceId of the SoC @retval PCI DeviceId of the SoC **/ UINT16 EFIAPI QncGetSocDeviceId ( VOID ) { UINT16 SocDeviceId; SocDeviceId = MmioRead16 ( PciDeviceMmBase ( MC_BUS, MC_DEV, MC_FUN ) + PCI_DEVICE_ID_OFFSET ); return SocDeviceId; } /** Enable SMI detection of legacy flash access violations. **/ VOID EFIAPI QncEnableLegacyFlashAccessViolationSmi ( VOID ) { UINT32 BcValue; BcValue = LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL); // // Clear BIOSWE & set BLE. // BcValue &= (~B_QNC_LPC_BIOS_CNTL_BIOSWE); BcValue |= (B_QNC_LPC_BIOS_CNTL_BLE); LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL) = BcValue; DEBUG ((EFI_D_INFO, "BIOS Control Lock Enabled!\n")); } /** Setup RMU Thermal sensor registers for Vref mode. **/ VOID EFIAPI QNCThermalSensorSetVRefMode ( VOID ) { UINT32 Tscgf1Config; UINT32 Tscgf2Config; UINT32 Tscgf2Config2; Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG); Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG); Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2); Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK); Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP); Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN); Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_VREF_MODE << B_TSCGF1_CONFIG_IBGEN_BP); Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK); Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP); Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK); Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP); Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK); Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2); } /** Setup RMU Thermal sensor registers for Ratiometric mode. **/ VOID EFIAPI QNCThermalSensorSetRatiometricMode ( VOID ) { UINT32 Tscgf1Config; UINT32 Tscgf2Config; UINT32 Tscgf2Config2; UINT32 Tscgf3Config; Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG); Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG); Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2); Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG); Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK); Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP); Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK); Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCHOPSEL_BP); Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSINTERNALVREFEN); Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE << B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP); Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN); Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGEN_BP); Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGCHOPEN); Tscgf1Config |= (V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGCHOPEN_BP); Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK); Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP); Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK); Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP); Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK); Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP); Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK); Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP); Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSTIMING_MASK); Tscgf2Config |= (V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE << B_TSCGF2_CONFIG_IDSTIMING_BP); Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK); Tscgf3Config |= (V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2); QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config); } /** Setup RMU Thermal sensor trip point values. @param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold. @param[in] HotTripOnDegreesCelsius - Hot set trip point threshold. @param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold. @retval EFI_SUCCESS Trip points setup. @retval EFI_INVALID_PARAMETER Invalid trip point value. **/ EFI_STATUS EFIAPI QNCThermalSensorSetTripValues ( IN CONST UINTN CatastrophicTripOnDegreesCelsius, IN CONST UINTN HotTripOnDegreesCelsius, IN CONST UINTN HotTripOffDegreesCelsius ) { UINT32 RegisterValue; // // Register fields are 8-bit temperature values of granularity 1 degree C // where 0x00 corresponds to -50 degrees C // and 0xFF corresponds to 205 degrees C. // // User passes unsigned values in degrees Celsius so trips < 0 not supported. // // Add 50 to user values to get values for register fields. // if ((CatastrophicTripOnDegreesCelsius > 205) || (HotTripOnDegreesCelsius > 205) || (HotTripOffDegreesCelsius > 205)) { return EFI_INVALID_PARAMETER; } // // Set new values. // RegisterValue = ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP) | // Cat Trip Clear value must be less than Cat Trip Set Value. ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP) | ((HotTripOnDegreesCelsius + 50) << TS_HOT_TRIP_SET_THOLD_BP) | ((HotTripOffDegreesCelsius + 50) << TS_HOT_TRIP_CLEAR_THOLD_BP) ; QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, RegisterValue); return EFI_SUCCESS; } /** Enable RMU Thermal sensor with a Catastrophic Trip point. @retval EFI_SUCCESS Trip points setup. @retval EFI_INVALID_PARAMETER Invalid trip point value. **/ EFI_STATUS EFIAPI QNCThermalSensorEnableWithCatastrophicTrip ( IN CONST UINTN CatastrophicTripOnDegreesCelsius ) { UINT32 Tscgf3Config; UINT32 TsModeReg; UINT32 TsTripReg; // // Trip Register fields are 8-bit temperature values of granularity 1 degree C // where 0x00 corresponds to -50 degrees C // and 0xFF corresponds to 205 degrees C. // // User passes unsigned values in degrees Celsius so trips < 0 not supported. // // Add 50 to user values to get values for register fields. // if (CatastrophicTripOnDegreesCelsius > 205) { return EFI_INVALID_PARAMETER; } Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG); TsModeReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE); TsTripReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP); // // Setup Catastrophic Trip point. // TsTripReg &= ~(TS_CAT_TRIP_SET_THOLD_MASK); TsTripReg |= ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP); TsTripReg &= ~(TS_CAT_TRIP_CLEAR_THOLD_MASK); TsTripReg |= ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP); // Cat Trip Clear value must be less than Cat Trip Set Value. QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, TsTripReg); // // To enable the TS do the following: // 1) Take the TS out of reset by setting itsrst to 0x0. // 2) Enable the TS using RMU Thermal sensor mode register. // Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSRST); TsModeReg |= TS_ENABLE; QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config); QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE, TsModeReg); return EFI_SUCCESS; } /** Lock all RMU Thermal sensor control & trip point registers. **/ VOID EFIAPI QNCThermalSensorLockAllRegisters ( VOID ) { UINT32 RegValue; UINT32 LockMask; LockMask = TS_LOCK_THRM_CTRL_REGS_ENABLE | TS_LOCK_AUX_TRIP_PT_REGS_ENABLE; RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG); RegValue |= LockMask; QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG, RegValue); ASSERT ((LockMask == (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG) & LockMask))); } /** Set chipset policy for double bit ECC error. @param[in] PolicyValue Policy to config on double bit ECC error. **/ VOID EFIAPI QNCPolicyDblEccBitErr ( IN CONST UINT32 PolicyValue ) { UINT32 Register; Register = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL); Register &= ~(B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK); Register |= PolicyValue; QNCPortWrite ( QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL, Register ); } /** Determine if running on secure Quark hardware Sku. @retval FALSE Base Quark Sku or unprovisioned Secure Sku running. @retval TRUE Provisioned SecureSku hardware running. **/ BOOLEAN EFIAPI QncIsSecureProvisionedSku ( VOID ) { // Read QUARK Secure SKU Fuse return ((QNCAltPortRead (QUARK_SCSS_FUSE_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE) & BIT6) == BIT6); }