/** Calling this function causes the system to enter a power state equivalent to the ACPI G2/S5 or G3 states. System shutdown should not return, if it returns, it means the system does not support shut down reset. **/ VOID EFIAPI ResetShutdown ( VOID ) { // // Reference to QuarkNcSocId BWG // Disable RTC Alarm : (RTC Enable at PM1BLK + 02h[10])) // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0); // // Firstly, GPE0_EN should be disabled to // avoid any GPI waking up the system from S5 // IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0); // // Reference to QuarkNcSocId BWG // Disable Resume Well GPIO : (GPIO bits in GPIOBASE + 34h[8:0]) // IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0); // // No power button status bit to clear for our platform, go to next step. // // // Finally, transform system into S5 sleep state // IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5); }
/** Triggers a run time or boot time SMI. This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data. @param Data The value to set the APMC status. **/ VOID InternalTriggerSmi ( IN UINT8 Data ) { UINT16 PM1BLK_Base; UINT16 GPE0BLK_Base; UINT32 NewValue; // // Get PM1BLK_Base & GPE0BLK_Base // PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress); GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF); // // Enable APM SMI // IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM); // // 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); // // Set APM_STS // IoWrite8 (PcdGet16 (PcdSmmDataPort), Data); // // Generate the APM SMI // IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData)); // // Clear the APM SMI Status Bit // IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM); // // Set the EOS Bit // IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS); }
/** Gets the software SMI data. This function tests if a software SMM interrupt happens. If a software SMI happens, it retrieves the SMM data and returns it as a non-negative value; otherwise a negative value is returned. @return Data The data retrieved from SMM data port in case of a software SMI; otherwise a negative value. **/ INTN InternalGetSwSmiData ( VOID ) { UINT8 SmiStatus; UINT8 Data; SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS); if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) && (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) { Data = IoRead8 (PcdGet16 (PcdSmmDataPort)); return (INTN)(UINTN)Data; } return -1; }
/** Gets Io port base address of Smbus Host Controller. This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always read Pci configuration space to get that value in each Smbus bus transaction. @return The Io port base address of Smbus host controller. **/ UINTN GetSmbusIoPortBaseAddress ( VOID ) { UINTN IoPortBaseAddress; if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) { IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress); } else { IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK; } // // Make sure that the IO port base address has been properly set. // ASSERT (IoPortBaseAddress != 0); return IoPortBaseAddress; }
/** Clear APM SMI Status Bit; Set the EOS bit. **/ VOID EFIAPI ClearSmi ( VOID ) { UINT16 GPE0BLK_Base; // // Get GpeBase // GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF); // // Clear the APM SMI Status Bit // IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM); // // Set the EOS Bit // IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS); }
// // Routines local to this source module. // STATIC VOID LegacyGpioSetLevel ( IN CONST UINT32 LevelRegOffset, IN CONST UINT32 GpioNum, IN CONST BOOLEAN HighLevel ) { UINT32 RegValue; UINT32 GpioBaseAddress; UINT32 GpioNumMask; GpioBaseAddress = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK; ASSERT (GpioBaseAddress > 0); RegValue = IoRead32 (GpioBaseAddress + LevelRegOffset); GpioNumMask = (1 << GpioNum); if (HighLevel) { RegValue |= (GpioNumMask); } else { RegValue &= ~(GpioNumMask); } IoWrite32 (GpioBaseAddress + R_QNC_GPIO_RGLVL_RESUME_WELL, RegValue); }
VOID QNCSmmPeriodicTimerProgramTimers ( VOID ) { UINT32 GpePmcwValue; SUPPORTED_TIMER Timer; DATABASE_RECORD *RecordInDb; LIST_ENTRY *LinkInDb; TIMER_INTERVAL *TimerInterval; // // Find the minimum required interval for each timer // for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) { mTimers[Timer].MinReqInterval = ~(UINT64)0x0; mTimers[Timer].NumChildren = 0; } LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); if (RecordInDb->ProtocolType == PeriodicTimerType) { // // This child is registerd with the PeriodicTimer protocol // TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext); if(TimerInterval != NULL) { Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer; ASSERT (Timer >= 0 && Timer < NUM_TIMERS); if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; } mTimers[Timer].NumChildren++; } } LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); } // // Program the hardware // GpePmcwValue = 0; if (mTimers[PERIODIC_TIMER].NumChildren > 0) { switch (mTimers[PERIODIC_TIMER].MinReqInterval) { case TIME_64s: GpePmcwValue = INDEX_TIME_64s; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s; break; case TIME_32s: GpePmcwValue = INDEX_TIME_32s; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s; break; case TIME_16s: GpePmcwValue = INDEX_TIME_16s; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s; break; case TIME_8s: GpePmcwValue = INDEX_TIME_8s; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s; break; case TIME_64ms: GpePmcwValue = INDEX_TIME_64ms; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms; break; case TIME_32ms: GpePmcwValue = INDEX_TIME_32ms; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms; break; case TIME_16ms: GpePmcwValue = INDEX_TIME_16ms; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms; break; case TIME_1_5ms: GpePmcwValue = INDEX_TIME_1_5ms; mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms; break; default: ASSERT (FALSE); break; }; GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE; IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue); // // Restart the timer here, just need to clear the SMI // QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); } else { QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); } }
/** Do memory initialisation for QNC DDR3 SDRAM Controller @return EFI_SUCCESS Memory initialisation completed successfully. All other error conditions encountered result in an ASSERT. **/ EFI_STATUS MemoryInit ( VOID ) { MRC_PARAMS MrcData; EFI_BOOT_MODE BootMode; EFI_STATUS Status; EFI_STATUS_CODE_VALUE ErrorCodeValue; UINT16 PmswAdr; PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES]; UINT8 NumRanges; EFI_PHYSICAL_ADDRESS BadMemoryAddress; EFI_PHYSICAL_ADDRESS FspReservedArea; UINT64 ReservedBytes; UINT32 RmuMainMemoryAddress; ErrorCodeValue = 0; // // It is critical that both of these data structures are initialized to 0. // This PEIM knows the number of DIMMs in the system and works with that // information. The MCH PEIM that consumes these data structures does not // know the number of DIMMs so it expects the entire structure to be // properly initialized. By initializing these to zero, all flags indicating // that the SPD is present or the row should be configured are set to false. // ZeroMem (&MrcData, sizeof(MrcData)); // // Determine boot mode // BootMode = GetBootMode(); // // Initialize Error type for reporting status code // switch (BootMode) { case BOOT_ON_FLASH_UPDATE: ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_UPDATE_FAIL; break; case BOOT_ON_S3_RESUME: ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_S3_RESUME_FAIL; break; default: ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY; break; } // // Specify MRC boot mode // switch (BootMode) { case BOOT_ON_S3_RESUME: case BOOT_ON_FLASH_UPDATE: MrcData.boot_mode = bmS3; break; case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES: MrcData.boot_mode = bmFast; break; default: MrcData.boot_mode = bmCold; break; } // // Configure MRC input parameters. // MrcConfigureFromMcFuses (&MrcData); MrcConfigureFromInfoHob (&MrcData); if (BootMode == BOOT_IN_RECOVERY_MODE) { // // Always do bmCold on recovery. // DEBUG ((DEBUG_INFO, "MemoryInit:Force bmCold on Recovery\n")); MrcData.boot_mode = bmCold; } else { // // Get the saved memory data if possible // if ((GetMrcDataPtr() != 0) && (GetMrcDataLength() != 0)) { ASSERT(GetMrcDataLength() == sizeof(MrcData.timings)); CopyMem (&MrcData.timings, (void *)GetMrcDataPtr(), GetMrcDataLength()); } else { switch (BootMode) { case BOOT_ON_S3_RESUME: case BOOT_ON_FLASH_UPDATE: DEBUG ((DEBUG_ERROR, "ERROR: MRC data missing - reboot\n")); REPORT_STATUS_CODE ( EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED, ErrorCodeValue ); return FSP_STATUS_RESET_REQUIRED_COLD; break; default: MrcData.boot_mode = bmCold; break; } } } PmswAdr = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMSW; if( IoRead32 (PmswAdr) & B_QNC_GPE0BLK_PMSW_DRAM_INIT) { // MRC did not complete last execution, force cold boot path MrcData.boot_mode = bmCold; } // Mark MRC pending IoOr32 (PmswAdr, (UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT); // // Call Memory Reference Code's Routines // Mrc (&MrcData); // Mark MRC completed IoAnd32 (PmswAdr, ~(UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT); // // Get the Memory Map // NumRanges = MAX_RANGES; ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges); Status = GetMemoryMap ( MrcData.mem_size, (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap, &NumRanges, &RmuMainMemoryAddress ); ASSERT_EFI_ERROR (Status); ASSERT(NumRanges <= MAX_RANGES); // // Locate the FSP reserved memory (last entry). // FspReservedArea = MemoryMap[NumRanges - 1].PhysicalAddress; ReservedBytes = MemoryMap[NumRanges - 1].RangeLength; // // Test the memory from 1M->TOM // if (BootMode != BOOT_ON_S3_RESUME) { if (BootMode != BOOT_ON_FLASH_UPDATE) { Status = BaseMemoryTest ( 0x100000, (MrcData.mem_size - 0x100000), Quick, &BadMemoryAddress ); ASSERT_EFI_ERROR (Status); } // // Assign physical memory to PEI // FspInstallPeiMemory (FspReservedArea, ReservedBytes); } // // Enable memory for use // PostInstallMemory (&MrcData, FALSE, RmuMainMemoryAddress); // // Save the memory configuration data into a HOB // HOB data size (stored in variable) is required to be multiple of 8 bytes // if (BootMode != BOOT_ON_S3_RESUME) { InitializeHeap((UINTN)FspReservedArea, (UINTN)ReservedBytes); BuildHobs (MemoryMap, NumRanges, FspReservedArea, ReservedBytes, &MrcData); } DEBUG ((EFI_D_INFO, "MemoryInit Complete.\n")); return EFI_SUCCESS; }