Platform.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. /** @file
  2. Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. Module Name:
  5. Platform.c
  6. Abstract:
  7. This is a generic template for a child of the IchSmm driver.
  8. --*/
  9. #include "SmmPlatform.h"
  10. //
  11. // Local variables
  12. //
  13. typedef struct {
  14. UINT8 Device;
  15. UINT8 Function;
  16. } EFI_PCI_BUS_MASTER;
  17. EFI_PCI_BUS_MASTER mPciBm[] = {
  18. { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 },
  19. { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 },
  20. { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 },
  21. { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 },
  22. { PCI_DEVICE_NUMBER_PCH_USB, PCI_FUNCTION_NUMBER_PCH_EHCI }
  23. };
  24. UINT16 mAcpiBaseAddr;
  25. SYSTEM_CONFIGURATION mSystemConfiguration;
  26. EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
  27. EFI_GLOBAL_NVS_AREA_PROTOCOL *mGlobalNvsAreaPtr;
  28. UINT16 mPM1_SaveState16;
  29. UINT32 mGPE_SaveState32;
  30. BOOLEAN mSetSmmVariableProtocolSmiAllowed = TRUE;
  31. //
  32. // Variables. Need to initialize this from Setup
  33. //
  34. BOOLEAN mWakeOnLanS5Variable;
  35. BOOLEAN mWakeOnRtcVariable;
  36. UINT8 mWakeupDay;
  37. UINT8 mWakeupHour;
  38. UINT8 mWakeupMinute;
  39. UINT8 mWakeupSecond;
  40. //
  41. // Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On
  42. //
  43. UINT8 mAcLossVariable;
  44. static
  45. UINT8 mTco1Sources[] = {
  46. IchnNmi
  47. };
  48. VOID
  49. S4S5ProgClock();
  50. VOID
  51. EnableS5WakeOnRtc();
  52. UINT8
  53. HexToBcd(
  54. UINT8 HexValue
  55. );
  56. VOID
  57. CpuSmmSxWorkAround(
  58. );
  59. /**
  60. Initializes the SMM Handler Driver
  61. @param ImageHandle
  62. @param SystemTable
  63. @retval None
  64. **/
  65. EFI_STATUS
  66. EFIAPI
  67. InitializePlatformSmm (
  68. IN EFI_HANDLE ImageHandle,
  69. IN EFI_SYSTEM_TABLE *SystemTable
  70. )
  71. {
  72. EFI_STATUS Status;
  73. UINT8 Index;
  74. EFI_HANDLE Handle;
  75. EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButtonContext;
  76. EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL *PowerButtonDispatch;
  77. EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext;
  78. EFI_SMM_ICHN_DISPATCH_PROTOCOL *IchnDispatch;
  79. EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatch;
  80. EFI_SMM_SX_DISPATCH_CONTEXT EntryDispatchContext;
  81. EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch;
  82. EFI_SMM_SW_DISPATCH_CONTEXT SwContext;
  83. UINTN VarSize;
  84. EFI_BOOT_MODE BootMode;
  85. Handle = NULL;
  86. //
  87. // Locate the Global NVS Protocol.
  88. //
  89. Status = gBS->LocateProtocol (
  90. &gEfiGlobalNvsAreaProtocolGuid,
  91. NULL,
  92. (void **)&mGlobalNvsAreaPtr
  93. );
  94. ASSERT_EFI_ERROR (Status);
  95. //
  96. // Get the ACPI Base Address
  97. //
  98. mAcpiBaseAddr = PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE ) & B_PCH_LPC_ACPI_BASE_BAR;
  99. VarSize = sizeof(SYSTEM_CONFIGURATION);
  100. Status = SystemTable->RuntimeServices->GetVariable(
  101. L"Setup",
  102. &gEfiSetupVariableGuid,
  103. NULL,
  104. &VarSize,
  105. &mSystemConfiguration
  106. );
  107. if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
  108. //The setup variable is corrupted
  109. VarSize = sizeof(SYSTEM_CONFIGURATION);
  110. Status = SystemTable->RuntimeServices->GetVariable(
  111. L"SetupRecovery",
  112. &gEfiSetupVariableGuid,
  113. NULL,
  114. &VarSize,
  115. &mSystemConfiguration
  116. );
  117. ASSERT_EFI_ERROR (Status);
  118. }
  119. if (!EFI_ERROR(Status)) {
  120. mAcLossVariable = mSystemConfiguration.StateAfterG3;
  121. //
  122. // If LAN is disabled, WOL function should be disabled too.
  123. //
  124. if (mSystemConfiguration.Lan == 0x01){
  125. mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5;
  126. } else {
  127. mWakeOnLanS5Variable = FALSE;
  128. }
  129. mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5;
  130. }
  131. BootMode = GetBootModeHob ();
  132. //
  133. // Get the Power Button protocol
  134. //
  135. Status = gBS->LocateProtocol(
  136. &gEfiSmmPowerButtonDispatchProtocolGuid,
  137. NULL,
  138. (void **)&PowerButtonDispatch
  139. );
  140. ASSERT_EFI_ERROR(Status);
  141. if (BootMode != BOOT_ON_FLASH_UPDATE) {
  142. //
  143. // Register for the power button event
  144. //
  145. PowerButtonContext.Phase = PowerButtonEntry;
  146. Status = PowerButtonDispatch->Register(
  147. PowerButtonDispatch,
  148. PowerButtonCallback,
  149. &PowerButtonContext,
  150. &Handle
  151. );
  152. ASSERT_EFI_ERROR(Status);
  153. }
  154. //
  155. // Get the Sx dispatch protocol
  156. //
  157. Status = gBS->LocateProtocol (
  158. &gEfiSmmSxDispatchProtocolGuid,
  159. NULL,
  160. (void **)&SxDispatch
  161. );
  162. ASSERT_EFI_ERROR(Status);
  163. //
  164. // Register entry phase call back function
  165. //
  166. EntryDispatchContext.Type = SxS3;
  167. EntryDispatchContext.Phase = SxEntry;
  168. Status = SxDispatch->Register (
  169. SxDispatch,
  170. (EFI_SMM_SX_DISPATCH)SxSleepEntryCallBack,
  171. &EntryDispatchContext,
  172. &Handle
  173. );
  174. EntryDispatchContext.Type = SxS4;
  175. Status = SxDispatch->Register (
  176. SxDispatch,
  177. S4S5CallBack,
  178. &EntryDispatchContext,
  179. &Handle
  180. );
  181. ASSERT_EFI_ERROR(Status);
  182. EntryDispatchContext.Type = SxS5;
  183. Status = SxDispatch->Register (
  184. SxDispatch,
  185. S4S5CallBack,
  186. &EntryDispatchContext,
  187. &Handle
  188. );
  189. ASSERT_EFI_ERROR(Status);
  190. Status = SxDispatch->Register (
  191. SxDispatch,
  192. S5SleepAcLossCallBack,
  193. &EntryDispatchContext,
  194. &Handle
  195. );
  196. ASSERT_EFI_ERROR(Status);
  197. //
  198. // Get the Sw dispatch protocol
  199. //
  200. Status = gBS->LocateProtocol (
  201. &gEfiSmmSwDispatchProtocolGuid,
  202. NULL,
  203. (void **)&SwDispatch
  204. );
  205. ASSERT_EFI_ERROR(Status);
  206. //
  207. // Register ACPI enable handler
  208. //
  209. SwContext.SwSmiInputValue = ACPI_ENABLE;
  210. Status = SwDispatch->Register (
  211. SwDispatch,
  212. EnableAcpiCallback,
  213. &SwContext,
  214. &Handle
  215. );
  216. ASSERT_EFI_ERROR(Status);
  217. //
  218. // Register ACPI disable handler
  219. //
  220. SwContext.SwSmiInputValue = ACPI_DISABLE;
  221. Status = SwDispatch->Register (
  222. SwDispatch,
  223. DisableAcpiCallback,
  224. &SwContext,
  225. &Handle
  226. );
  227. ASSERT_EFI_ERROR(Status);
  228. //
  229. // Register for SmmReadyToBootCallback
  230. //
  231. SwContext.SwSmiInputValue = SMI_SET_SMMVARIABLE_PROTOCOL;
  232. Status = SwDispatch->Register(
  233. SwDispatch,
  234. SmmReadyToBootCallback,
  235. &SwContext,
  236. &Handle
  237. );
  238. ASSERT_EFI_ERROR(Status);
  239. //
  240. // Get the ICHn protocol
  241. //
  242. Status = gBS->LocateProtocol(
  243. &gEfiSmmIchnDispatchProtocolGuid,
  244. NULL,
  245. (void **)&IchnDispatch
  246. );
  247. ASSERT_EFI_ERROR(Status);
  248. //
  249. // Register for the events that may happen that we do not care.
  250. // This is true for SMI related to TCO since TCO is enabled by BIOS WP
  251. //
  252. for (Index = 0; Index < sizeof(mTco1Sources)/sizeof(UINT8); Index++) {
  253. IchnContext.Type = mTco1Sources[Index];
  254. Status = IchnDispatch->Register(
  255. IchnDispatch,
  256. (EFI_SMM_ICHN_DISPATCH)DummyTco1Callback,
  257. &IchnContext,
  258. &Handle
  259. );
  260. ASSERT_EFI_ERROR( Status );
  261. }
  262. //
  263. // Lock TCO_EN bit.
  264. //
  265. IoWrite16( mAcpiBaseAddr + R_PCH_TCO_CNT, IoRead16( mAcpiBaseAddr + R_PCH_TCO_CNT ) | B_PCH_TCO_CNT_LOCK );
  266. //
  267. // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
  268. //
  269. //
  270. // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.
  271. // This is because no matter how, if WOL enabled or AC Loss variable not disabled, the board needs to wake from G3 to program the LAN WOL settings.
  272. // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.
  273. //
  274. if (mAcLossVariable != 0x00) {
  275. SetAfterG3On (TRUE);
  276. } else {
  277. SetAfterG3On (FALSE);
  278. }
  279. return EFI_SUCCESS;
  280. }
  281. VOID
  282. EFIAPI
  283. SmmReadyToBootCallback (
  284. IN EFI_HANDLE DispatchHandle,
  285. IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
  286. )
  287. {
  288. EFI_STATUS Status;
  289. if (mSetSmmVariableProtocolSmiAllowed)
  290. {
  291. //
  292. // It is okay to use gBS->LocateProtocol here because
  293. // we are still in trusted execution.
  294. //
  295. Status = gBS->LocateProtocol(
  296. &gEfiSmmVariableProtocolGuid,
  297. NULL,
  298. (void **)&mSmmVariable
  299. );
  300. ASSERT_EFI_ERROR(Status);
  301. //
  302. // mSetSmmVariableProtocolSmiAllowed will prevent this function from
  303. // being executed more than 1 time.
  304. //
  305. mSetSmmVariableProtocolSmiAllowed = FALSE;
  306. }
  307. }
  308. /**
  309. @param DispatchHandle The handle of this callback, obtained when registering
  310. @param DispatchContext The predefined context which contained sleep type and phase
  311. @retval EFI_SUCCESS Operation successfully performed
  312. **/
  313. EFI_STATUS
  314. EFIAPI
  315. SxSleepEntryCallBack (
  316. IN EFI_HANDLE DispatchHandle,
  317. IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
  318. )
  319. {
  320. EFI_STATUS Status;
  321. Status = SaveRuntimeScriptTable ();
  322. if (EFI_ERROR(Status)) {
  323. return Status;
  324. }
  325. //
  326. // Workaround for S3 wake hang if C State is enabled
  327. //
  328. CpuSmmSxWorkAround();
  329. return EFI_SUCCESS;
  330. }
  331. VOID
  332. CpuSmmSxWorkAround(
  333. )
  334. {
  335. UINT64 MsrValue;
  336. MsrValue = AsmReadMsr64 (0xE2);
  337. if (MsrValue & BIT15) {
  338. return;
  339. }
  340. if (MsrValue & BIT10) {
  341. MsrValue &= ~BIT10;
  342. AsmWriteMsr64 (0xE2, MsrValue);
  343. }
  344. }
  345. VOID
  346. ClearP2PBusMaster(
  347. )
  348. {
  349. UINT8 Command;
  350. UINT8 Index;
  351. for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {
  352. Command = MmioRead8 (
  353. MmPciAddress (0,
  354. DEFAULT_PCI_BUS_NUMBER_PCH,
  355. mPciBm[Index].Device,
  356. mPciBm[Index].Function,
  357. PCI_COMMAND_OFFSET
  358. )
  359. );
  360. Command &= ~EFI_PCI_COMMAND_BUS_MASTER;
  361. MmioWrite8 (
  362. MmPciAddress (0,
  363. DEFAULT_PCI_BUS_NUMBER_PCH,
  364. mPciBm[Index].Device,
  365. mPciBm[Index].Function,
  366. PCI_COMMAND_OFFSET
  367. ),
  368. Command
  369. );
  370. }
  371. }
  372. /**
  373. Set the AC Loss to turn on or off.
  374. **/
  375. VOID
  376. SetAfterG3On (
  377. BOOLEAN Enable
  378. )
  379. {
  380. UINT8 PmCon1;
  381. //
  382. // ICH handling portion
  383. //
  384. PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );
  385. PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  386. if (Enable) {
  387. PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  388. }
  389. MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);
  390. }
  391. /**
  392. When a power button event happens, it shuts off the machine
  393. **/
  394. VOID
  395. EFIAPI
  396. PowerButtonCallback (
  397. IN EFI_HANDLE DispatchHandle,
  398. IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT *DispatchContext
  399. )
  400. {
  401. //
  402. // Check what the state to return to after AC Loss. If Last State, then
  403. // set it to Off.
  404. //
  405. UINT16 data16;
  406. if (mWakeOnRtcVariable) {
  407. EnableS5WakeOnRtc();
  408. }
  409. if (mAcLossVariable == 1) {
  410. SetAfterG3On (TRUE);
  411. }
  412. ClearP2PBusMaster();
  413. //
  414. // Program clock chip
  415. //
  416. S4S5ProgClock();
  417. data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN));
  418. data16 &= B_PCH_ACPI_GPE0a_EN_PCI_EXP;
  419. //
  420. // Clear Sleep SMI Status
  421. //
  422. IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_STS,
  423. (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_STS) | B_PCH_SMI_STS_ON_SLP_EN));
  424. //
  425. // Clear Sleep Type Enable
  426. //
  427. IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_EN,
  428. (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_EN) & (~B_PCH_SMI_EN_ON_SLP_EN)));
  429. //
  430. // Clear Power Button Status
  431. //
  432. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_PWRBTN);
  433. //
  434. // Shut it off now!
  435. //
  436. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, V_PCH_ACPI_PM1_CNT_S5);
  437. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, B_PCH_ACPI_PM1_CNT_SLP_EN | V_PCH_ACPI_PM1_CNT_S5);
  438. //
  439. // Should not return
  440. //
  441. CpuDeadLoop();
  442. }
  443. /**
  444. @param DispatchHandle - The handle of this callback, obtained when registering
  445. @param DispatchContext - The predefined context which contained sleep type and phase
  446. **/
  447. VOID
  448. EFIAPI
  449. S5SleepAcLossCallBack (
  450. IN EFI_HANDLE DispatchHandle,
  451. IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
  452. )
  453. {
  454. //
  455. // Check what the state to return to after AC Loss. If Last State, then
  456. // set it to Off.
  457. //
  458. if (mAcLossVariable == 1) {
  459. SetAfterG3On (TRUE);
  460. }
  461. }
  462. /**
  463. @param DispatchHandle The handle of this callback, obtained when registering
  464. @param DispatchContext The predefined context which contained sleep type and phase
  465. @retval Clears the Save State bit in the clock.
  466. **/
  467. VOID
  468. EFIAPI
  469. S4S5CallBack (
  470. IN EFI_HANDLE DispatchHandle,
  471. IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
  472. )
  473. {
  474. UINT32 Data32;
  475. //
  476. // Enable/Disable USB Charging
  477. //
  478. if (mSystemConfiguration.UsbCharging == 0x01) {
  479. Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL);
  480. Data32 |= BIT8;
  481. IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32);
  482. }
  483. }
  484. VOID
  485. S4S5ProgClock()
  486. {
  487. }
  488. /**
  489. SMI handler to enable ACPI mode
  490. Dispatched on reads from APM port with value 0xA0
  491. Disables the SW SMI Timer.
  492. ACPI events are disabled and ACPI event status is cleared.
  493. SCI mode is then enabled.
  494. Disable SW SMI Timer
  495. Clear all ACPI event status and disable all ACPI events
  496. Disable PM sources except power button
  497. Clear status bits
  498. Disable GPE0 sources
  499. Clear status bits
  500. Disable GPE1 sources
  501. Clear status bits
  502. Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
  503. Enable SCI
  504. @param DispatchHandle - EFI Handle
  505. @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
  506. @retval Nothing
  507. **/
  508. VOID
  509. EFIAPI
  510. EnableAcpiCallback (
  511. IN EFI_HANDLE DispatchHandle,
  512. IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
  513. )
  514. {
  515. UINT32 SmiEn;
  516. UINT16 Pm1Cnt;
  517. UINT16 wordValue;
  518. UINT32 RegData32;
  519. //
  520. // Disable SW SMI Timer
  521. //
  522. SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN);
  523. SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR;
  524. IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn);
  525. wordValue = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS);
  526. if(wordValue & B_PCH_ACPI_PM1_STS_WAK) {
  527. IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN), 0x0000);
  528. IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), 0xffffffff);
  529. }
  530. else {
  531. mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN);
  532. //
  533. // Disable PM sources except power button
  534. //
  535. // power button is enabled only for PCAT. Disabled it on Tablet platform
  536. //
  537. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN);
  538. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
  539. mGPE_SaveState32 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN);
  540. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, 0x0000);
  541. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
  542. }
  543. //
  544. // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
  545. // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid
  546. //
  547. IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
  548. IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
  549. RegData32 = IoRead32(ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN);
  550. RegData32 &= ~(BIT7);
  551. IoWrite32((ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN), RegData32);
  552. //
  553. // Enable SCI
  554. //
  555. Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
  556. Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SCI_EN;
  557. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
  558. }
  559. /**
  560. SMI handler to disable ACPI mode
  561. Dispatched on reads from APM port with value 0xA1
  562. ACPI events are disabled and ACPI event status is cleared.
  563. SCI mode is then disabled.
  564. Clear all ACPI event status and disable all ACPI events
  565. Disable PM sources except power button
  566. Clear status bits
  567. Disable GPE0 sources
  568. Clear status bits
  569. Disable GPE1 sources
  570. Clear status bits
  571. Disable SCI
  572. @param DispatchHandle - EFI Handle
  573. @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
  574. @retval Nothing
  575. **/
  576. VOID
  577. EFIAPI
  578. DisableAcpiCallback (
  579. IN EFI_HANDLE DispatchHandle,
  580. IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
  581. )
  582. {
  583. UINT16 Pm1Cnt;
  584. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
  585. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16);
  586. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
  587. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32);
  588. //
  589. // Disable SCI
  590. //
  591. Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
  592. Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SCI_EN;
  593. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
  594. }
  595. /**
  596. When an unknown event happen.
  597. @retval None
  598. **/
  599. VOID
  600. DummyTco1Callback (
  601. IN EFI_HANDLE DispatchHandle,
  602. IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext
  603. )
  604. {
  605. }
  606. /**
  607. @retval 1. Check Alarm interrupt is not set.
  608. 2. Clear Alarm interrupt.
  609. 2. Set RTC wake up date and time.
  610. 2. Enable RTC wake up alarm.
  611. 3. Enable ICH PM1 EN Bit 10(RTC_EN)
  612. **/
  613. VOID
  614. EnableS5WakeOnRtc()
  615. {
  616. UINT8 CmosData;
  617. UINTN i;
  618. EFI_STATUS Status;
  619. UINTN VarSize;
  620. //
  621. // make sure EFI_SMM_VARIABLE_PROTOCOL is available
  622. //
  623. if (!mSmmVariable) {
  624. return;
  625. }
  626. VarSize = sizeof(SYSTEM_CONFIGURATION);
  627. //
  628. // read the variable into the buffer
  629. //
  630. Status = mSmmVariable->SmmGetVariable(
  631. L"Setup",
  632. &gEfiSetupVariableGuid,
  633. NULL,
  634. &VarSize,
  635. &mSystemConfiguration
  636. );
  637. if (EFI_ERROR(Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
  638. //The setup variable is corrupted
  639. VarSize = sizeof(SYSTEM_CONFIGURATION);
  640. Status = mSmmVariable->SmmGetVariable(
  641. L"SetupRecovery",
  642. &gEfiSetupVariableGuid,
  643. NULL,
  644. &VarSize,
  645. &mSystemConfiguration
  646. );
  647. ASSERT_EFI_ERROR (Status);
  648. }
  649. if (!mSystemConfiguration.WakeOnRtcS5) {
  650. return;
  651. }
  652. mWakeupDay = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupDate);
  653. mWakeupHour = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeHour);
  654. mWakeupMinute = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeMinute);
  655. mWakeupSecond = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeSecond);
  656. //
  657. // Check RTC alarm interrupt is enabled. If enabled, someone already
  658. // grabbed RTC alarm. Just return.
  659. //
  660. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  661. if(IoRead8(PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE){
  662. return;
  663. }
  664. //
  665. // Set Date
  666. //
  667. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
  668. CmosData = IoRead8(PCAT_RTC_DATA_REGISTER);
  669. CmosData &= ~(B_RTC_DATE_ALARM_MASK);
  670. CmosData |= mWakeupDay ;
  671. for(i = 0 ; i < 0xffff ; i++){
  672. IoWrite8(PCAT_RTC_DATA_REGISTER, CmosData);
  673. SmmStall(1);
  674. if(((CmosData = IoRead8(PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK)
  675. == mWakeupDay){
  676. break;
  677. }
  678. }
  679. //
  680. // Set Second
  681. //
  682. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM);
  683. for(i = 0 ; i < 0xffff ; i++){
  684. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupSecond);
  685. SmmStall(1);
  686. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupSecond){
  687. break;
  688. }
  689. }
  690. //
  691. // Set Minute
  692. //
  693. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM);
  694. for(i = 0 ; i < 0xffff ; i++){
  695. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupMinute);
  696. SmmStall(1);
  697. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupMinute){
  698. break;
  699. }
  700. }
  701. //
  702. // Set Hour
  703. //
  704. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM);
  705. for(i = 0 ; i < 0xffff ; i++){
  706. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupHour);
  707. SmmStall(1);
  708. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupHour){
  709. break;
  710. }
  711. }
  712. //
  713. // Wait for UIP to arm RTC alarm
  714. //
  715. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
  716. while (IoRead8(PCAT_RTC_DATA_REGISTER) & 0x80);
  717. //
  718. // Read RTC register 0C to clear pending RTC interrupts
  719. //
  720. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
  721. IoRead8(PCAT_RTC_DATA_REGISTER);
  722. //
  723. // Enable RTC Alarm Interrupt
  724. //
  725. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  726. IoWrite8(PCAT_RTC_DATA_REGISTER, IoRead8(PCAT_RTC_DATA_REGISTER) | B_RTC_ALARM_INT_ENABLE);
  727. //
  728. // Clear ICH RTC Status
  729. //
  730. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
  731. //
  732. // Enable ICH RTC event
  733. //
  734. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN,
  735. (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC));
  736. }
  737. UINT8
  738. HexToBcd(
  739. IN UINT8 HexValue
  740. )
  741. {
  742. UINTN HighByte;
  743. UINTN LowByte;
  744. HighByte = (UINTN)HexValue / 10;
  745. LowByte = (UINTN)HexValue % 10;
  746. return ((UINT8)(LowByte + (HighByte << 4)));
  747. }