Platform.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  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_REGISTER_CONTEXT PowerButtonContext;
  76. EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL *PowerButtonDispatch;
  77. EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext;
  78. EFI_SMM_ICHN_DISPATCH_PROTOCOL *IchnDispatch;
  79. EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
  80. EFI_SMM_SX_REGISTER_CONTEXT EntryDispatchContext;
  81. EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
  82. EFI_SMM_SW_REGISTER_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 = gSmst->SmmLocateProtocol(
  136. &gEfiSmmPowerButtonDispatch2ProtocolGuid,
  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 = EfiPowerButtonEntry;
  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 = gSmst->SmmLocateProtocol(
  158. &gEfiSmmSxDispatch2ProtocolGuid,
  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. 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 = gSmst->SmmLocateProtocol (
  201. &gEfiSmmSwDispatch2ProtocolGuid,
  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. EFI_STATUS
  282. EFIAPI
  283. SmmReadyToBootCallback (
  284. IN EFI_HANDLE DispatchHandle,
  285. IN CONST VOID *Context OPTIONAL,
  286. IN OUT VOID *CommBuffer OPTIONAL,
  287. IN OUT UINTN *CommBufferSize OPTIONAL
  288. )
  289. {
  290. EFI_STATUS Status;
  291. if (mSetSmmVariableProtocolSmiAllowed)
  292. {
  293. //
  294. // It is okay to use gBS->LocateProtocol here because
  295. // we are still in trusted execution.
  296. //
  297. Status = gBS->LocateProtocol(
  298. &gEfiSmmVariableProtocolGuid,
  299. NULL,
  300. (void **)&mSmmVariable
  301. );
  302. ASSERT_EFI_ERROR(Status);
  303. //
  304. // mSetSmmVariableProtocolSmiAllowed will prevent this function from
  305. // being executed more than 1 time.
  306. //
  307. mSetSmmVariableProtocolSmiAllowed = FALSE;
  308. }
  309. return EFI_SUCCESS;
  310. }
  311. /**
  312. @param DispatchHandle The handle of this callback, obtained when registering
  313. @param DispatchContext The predefined context which contained sleep type and phase
  314. @retval EFI_SUCCESS Operation successfully performed
  315. **/
  316. EFI_STATUS
  317. EFIAPI
  318. SxSleepEntryCallBack (
  319. IN EFI_HANDLE DispatchHandle,
  320. IN CONST VOID *Context OPTIONAL,
  321. IN OUT VOID *CommBuffer OPTIONAL,
  322. IN OUT UINTN *CommBufferSize OPTIONAL
  323. )
  324. {
  325. EFI_STATUS Status;
  326. Status = SaveRuntimeScriptTable ();
  327. if (EFI_ERROR(Status)) {
  328. return Status;
  329. }
  330. //
  331. // Workaround for S3 wake hang if C State is enabled
  332. //
  333. CpuSmmSxWorkAround();
  334. return EFI_SUCCESS;
  335. }
  336. VOID
  337. CpuSmmSxWorkAround(
  338. )
  339. {
  340. UINT64 MsrValue;
  341. MsrValue = AsmReadMsr64 (0xE2);
  342. if (MsrValue & BIT15) {
  343. return;
  344. }
  345. if (MsrValue & BIT10) {
  346. MsrValue &= ~BIT10;
  347. AsmWriteMsr64 (0xE2, MsrValue);
  348. }
  349. }
  350. VOID
  351. ClearP2PBusMaster(
  352. )
  353. {
  354. UINT8 Command;
  355. UINT8 Index;
  356. for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {
  357. Command = MmioRead8 (
  358. MmPciAddress (0,
  359. DEFAULT_PCI_BUS_NUMBER_PCH,
  360. mPciBm[Index].Device,
  361. mPciBm[Index].Function,
  362. PCI_COMMAND_OFFSET
  363. )
  364. );
  365. Command &= ~EFI_PCI_COMMAND_BUS_MASTER;
  366. MmioWrite8 (
  367. MmPciAddress (0,
  368. DEFAULT_PCI_BUS_NUMBER_PCH,
  369. mPciBm[Index].Device,
  370. mPciBm[Index].Function,
  371. PCI_COMMAND_OFFSET
  372. ),
  373. Command
  374. );
  375. }
  376. }
  377. /**
  378. Set the AC Loss to turn on or off.
  379. **/
  380. VOID
  381. SetAfterG3On (
  382. BOOLEAN Enable
  383. )
  384. {
  385. UINT8 PmCon1;
  386. //
  387. // ICH handling portion
  388. //
  389. PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );
  390. PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  391. if (Enable) {
  392. PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
  393. }
  394. MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);
  395. }
  396. /**
  397. When a power button event happens, it shuts off the machine
  398. **/
  399. EFI_STATUS
  400. EFIAPI
  401. PowerButtonCallback (
  402. IN EFI_HANDLE DispatchHandle,
  403. IN CONST VOID *Context OPTIONAL,
  404. IN OUT VOID *CommBuffer OPTIONAL,
  405. IN OUT UINTN *CommBufferSize OPTIONAL
  406. )
  407. {
  408. //
  409. // Check what the state to return to after AC Loss. If Last State, then
  410. // set it to Off.
  411. //
  412. UINT16 data16;
  413. if (mWakeOnRtcVariable) {
  414. EnableS5WakeOnRtc();
  415. }
  416. if (mAcLossVariable == 1) {
  417. SetAfterG3On (TRUE);
  418. }
  419. ClearP2PBusMaster();
  420. //
  421. // Program clock chip
  422. //
  423. S4S5ProgClock();
  424. data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN));
  425. data16 &= B_PCH_ACPI_GPE0a_EN_PCI_EXP;
  426. //
  427. // Clear Sleep SMI Status
  428. //
  429. IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_STS,
  430. (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_STS) | B_PCH_SMI_STS_ON_SLP_EN));
  431. //
  432. // Clear Sleep Type Enable
  433. //
  434. IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_EN,
  435. (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_EN) & (~B_PCH_SMI_EN_ON_SLP_EN)));
  436. //
  437. // Clear Power Button Status
  438. //
  439. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_PWRBTN);
  440. //
  441. // Shut it off now!
  442. //
  443. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, V_PCH_ACPI_PM1_CNT_S5);
  444. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, B_PCH_ACPI_PM1_CNT_SLP_EN | V_PCH_ACPI_PM1_CNT_S5);
  445. //
  446. // Should not return
  447. //
  448. CpuDeadLoop();
  449. return EFI_SUCCESS;
  450. }
  451. /**
  452. @param DispatchHandle - The handle of this callback, obtained when registering
  453. @param DispatchContext - The predefined context which contained sleep type and phase
  454. **/
  455. EFI_STATUS
  456. EFIAPI
  457. S5SleepAcLossCallBack (
  458. IN EFI_HANDLE DispatchHandle,
  459. IN CONST VOID *Context OPTIONAL,
  460. IN OUT VOID *CommBuffer OPTIONAL,
  461. IN OUT UINTN *CommBufferSize OPTIONAL
  462. )
  463. {
  464. //
  465. // Check what the state to return to after AC Loss. If Last State, then
  466. // set it to Off.
  467. //
  468. if (mAcLossVariable == 1) {
  469. SetAfterG3On (TRUE);
  470. }
  471. return EFI_SUCCESS;
  472. }
  473. /**
  474. @param DispatchHandle The handle of this callback, obtained when registering
  475. @param DispatchContext The predefined context which contained sleep type and phase
  476. @retval Clears the Save State bit in the clock.
  477. **/
  478. EFI_STATUS
  479. EFIAPI
  480. S4S5CallBack (
  481. IN EFI_HANDLE DispatchHandle,
  482. IN CONST VOID *Context OPTIONAL,
  483. IN OUT VOID *CommBuffer OPTIONAL,
  484. IN OUT UINTN *CommBufferSize OPTIONAL
  485. )
  486. {
  487. UINT32 Data32;
  488. //
  489. // Enable/Disable USB Charging
  490. //
  491. if (mSystemConfiguration.UsbCharging == 0x01) {
  492. Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL);
  493. Data32 |= BIT8;
  494. IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32);
  495. }
  496. return EFI_SUCCESS;
  497. }
  498. VOID
  499. S4S5ProgClock()
  500. {
  501. }
  502. /**
  503. SMI handler to enable ACPI mode
  504. Dispatched on reads from APM port with value 0xA0
  505. Disables the SW SMI Timer.
  506. ACPI events are disabled and ACPI event status is cleared.
  507. SCI mode is then enabled.
  508. Disable SW SMI Timer
  509. Clear all ACPI event status and disable all ACPI events
  510. Disable PM sources except power button
  511. Clear status bits
  512. Disable GPE0 sources
  513. Clear status bits
  514. Disable GPE1 sources
  515. Clear status bits
  516. Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
  517. Enable SCI
  518. @param DispatchHandle - EFI Handle
  519. @param DispatchContext - Pointer to the EFI_SMM_SW_REGISTER_CONTEXT
  520. @retval Nothing
  521. **/
  522. EFI_STATUS
  523. EFIAPI
  524. EnableAcpiCallback (
  525. IN EFI_HANDLE DispatchHandle,
  526. IN CONST VOID *Context OPTIONAL,
  527. IN OUT VOID *CommBuffer OPTIONAL,
  528. IN OUT UINTN *CommBufferSize OPTIONAL
  529. )
  530. {
  531. UINT32 SmiEn;
  532. UINT16 Pm1Cnt;
  533. UINT16 wordValue;
  534. UINT32 RegData32;
  535. //
  536. // Disable SW SMI Timer
  537. //
  538. SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN);
  539. SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR;
  540. IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn);
  541. wordValue = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS);
  542. if(wordValue & B_PCH_ACPI_PM1_STS_WAK) {
  543. IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN), 0x0000);
  544. IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), 0xffffffff);
  545. }
  546. else {
  547. mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN);
  548. //
  549. // Disable PM sources except power button
  550. //
  551. // power button is enabled only for PCAT. Disabled it on Tablet platform
  552. //
  553. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN);
  554. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
  555. mGPE_SaveState32 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN);
  556. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, 0x0000);
  557. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
  558. }
  559. //
  560. // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
  561. // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid
  562. //
  563. IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
  564. IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
  565. RegData32 = IoRead32(ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN);
  566. RegData32 &= ~(BIT7);
  567. IoWrite32((ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN), RegData32);
  568. //
  569. // Enable SCI
  570. //
  571. Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
  572. Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SCI_EN;
  573. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
  574. return EFI_SUCCESS;
  575. }
  576. /**
  577. SMI handler to disable ACPI mode
  578. Dispatched on reads from APM port with value 0xA1
  579. ACPI events are disabled and ACPI event status is cleared.
  580. SCI mode is then disabled.
  581. Clear all ACPI event status and disable all ACPI events
  582. Disable PM sources except power button
  583. Clear status bits
  584. Disable GPE0 sources
  585. Clear status bits
  586. Disable GPE1 sources
  587. Clear status bits
  588. Disable SCI
  589. @param DispatchHandle - EFI Handle
  590. @param DispatchContext - Pointer to the EFI_SMM_SW_REGISTER_CONTEXT
  591. @retval Nothing
  592. **/
  593. EFI_STATUS
  594. EFIAPI
  595. DisableAcpiCallback (
  596. IN EFI_HANDLE DispatchHandle,
  597. IN CONST VOID *Context OPTIONAL,
  598. IN OUT VOID *CommBuffer OPTIONAL,
  599. IN OUT UINTN *CommBufferSize OPTIONAL
  600. )
  601. {
  602. UINT16 Pm1Cnt;
  603. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
  604. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16);
  605. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
  606. IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32);
  607. //
  608. // Disable SCI
  609. //
  610. Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
  611. Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SCI_EN;
  612. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
  613. return EFI_SUCCESS;
  614. }
  615. /**
  616. When an unknown event happen.
  617. @retval None
  618. **/
  619. VOID
  620. DummyTco1Callback (
  621. IN EFI_HANDLE DispatchHandle,
  622. IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext
  623. )
  624. {
  625. }
  626. /**
  627. @retval 1. Check Alarm interrupt is not set.
  628. 2. Clear Alarm interrupt.
  629. 2. Set RTC wake up date and time.
  630. 2. Enable RTC wake up alarm.
  631. 3. Enable ICH PM1 EN Bit 10(RTC_EN)
  632. **/
  633. VOID
  634. EnableS5WakeOnRtc()
  635. {
  636. UINT8 CmosData;
  637. UINTN i;
  638. EFI_STATUS Status;
  639. UINTN VarSize;
  640. //
  641. // make sure EFI_SMM_VARIABLE_PROTOCOL is available
  642. //
  643. if (!mSmmVariable) {
  644. return;
  645. }
  646. VarSize = sizeof(SYSTEM_CONFIGURATION);
  647. //
  648. // read the variable into the buffer
  649. //
  650. Status = mSmmVariable->SmmGetVariable(
  651. L"Setup",
  652. &gEfiSetupVariableGuid,
  653. NULL,
  654. &VarSize,
  655. &mSystemConfiguration
  656. );
  657. if (EFI_ERROR(Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
  658. //The setup variable is corrupted
  659. VarSize = sizeof(SYSTEM_CONFIGURATION);
  660. Status = mSmmVariable->SmmGetVariable(
  661. L"SetupRecovery",
  662. &gEfiSetupVariableGuid,
  663. NULL,
  664. &VarSize,
  665. &mSystemConfiguration
  666. );
  667. ASSERT_EFI_ERROR (Status);
  668. }
  669. if (!mSystemConfiguration.WakeOnRtcS5) {
  670. return;
  671. }
  672. mWakeupDay = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupDate);
  673. mWakeupHour = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeHour);
  674. mWakeupMinute = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeMinute);
  675. mWakeupSecond = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeSecond);
  676. //
  677. // Check RTC alarm interrupt is enabled. If enabled, someone already
  678. // grabbed RTC alarm. Just return.
  679. //
  680. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  681. if(IoRead8(PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE){
  682. return;
  683. }
  684. //
  685. // Set Date
  686. //
  687. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
  688. CmosData = IoRead8(PCAT_RTC_DATA_REGISTER);
  689. CmosData &= ~(B_RTC_DATE_ALARM_MASK);
  690. CmosData |= mWakeupDay ;
  691. for(i = 0 ; i < 0xffff ; i++){
  692. IoWrite8(PCAT_RTC_DATA_REGISTER, CmosData);
  693. SmmStall(1);
  694. if(((CmosData = IoRead8(PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK)
  695. == mWakeupDay){
  696. break;
  697. }
  698. }
  699. //
  700. // Set Second
  701. //
  702. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM);
  703. for(i = 0 ; i < 0xffff ; i++){
  704. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupSecond);
  705. SmmStall(1);
  706. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupSecond){
  707. break;
  708. }
  709. }
  710. //
  711. // Set Minute
  712. //
  713. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM);
  714. for(i = 0 ; i < 0xffff ; i++){
  715. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupMinute);
  716. SmmStall(1);
  717. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupMinute){
  718. break;
  719. }
  720. }
  721. //
  722. // Set Hour
  723. //
  724. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM);
  725. for(i = 0 ; i < 0xffff ; i++){
  726. IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupHour);
  727. SmmStall(1);
  728. if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupHour){
  729. break;
  730. }
  731. }
  732. //
  733. // Wait for UIP to arm RTC alarm
  734. //
  735. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
  736. while (IoRead8(PCAT_RTC_DATA_REGISTER) & 0x80);
  737. //
  738. // Read RTC register 0C to clear pending RTC interrupts
  739. //
  740. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
  741. IoRead8(PCAT_RTC_DATA_REGISTER);
  742. //
  743. // Enable RTC Alarm Interrupt
  744. //
  745. IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  746. IoWrite8(PCAT_RTC_DATA_REGISTER, IoRead8(PCAT_RTC_DATA_REGISTER) | B_RTC_ALARM_INT_ENABLE);
  747. //
  748. // Clear ICH RTC Status
  749. //
  750. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
  751. //
  752. // Enable ICH RTC event
  753. //
  754. IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN,
  755. (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC));
  756. }
  757. UINT8
  758. HexToBcd(
  759. IN UINT8 HexValue
  760. )
  761. {
  762. UINTN HighByte;
  763. UINTN LowByte;
  764. HighByte = (UINTN)HexValue / 10;
  765. LowByte = (UINTN)HexValue % 10;
  766. return ((UINT8)(LowByte + (HighByte << 4)));
  767. }