/** 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); }
/** Clear SMI related chipset status and re-enable SMI by setting the EOS bit. @retval EFI_SUCCESS The requested operation has been carried out successfully @retval EFI_DEVICE_ERROR The EOS bit could not be set. **/ EFI_STATUS SmmClear ( VOID ) { UINT16 PM1BLK_Base; UINT16 GPE0BLK_Base; // // Get PM1BLK_Base & GPE0BLK_Base // PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress); GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress); // // Clear the Power Button Override Status Bit, it gates EOS from being set. // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing. // // // 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); return EFI_SUCCESS; }
/** 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); }
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; }