PchLanSxSmm.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /** @file
  2. PCH LAN Sx handler implementation.
  3. Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/TimerLib.h>
  7. #include "PchInitSmm.h"
  8. #include <Private/Library/PmcPrivateLib.h>
  9. #include <Library/GbeMdiLib.h>
  10. #include <Register/PchRegs.h>
  11. #include <Register/PchRegsLan.h>
  12. /**
  13. Checks if Lan is Enabled or Disabled
  14. @retval BOOLEAN TRUE if device is enabled, FALSE otherwise.
  15. **/
  16. BOOLEAN
  17. IsGbeEnabled (
  18. VOID
  19. )
  20. {
  21. UINT64 GbePciBase;
  22. GbePciBase = PCI_SEGMENT_LIB_ADDRESS (
  23. DEFAULT_PCI_SEGMENT_NUMBER_PCH,
  24. DEFAULT_PCI_BUS_NUMBER_PCH,
  25. PCI_DEVICE_NUMBER_PCH_LAN,
  26. PCI_FUNCTION_NUMBER_PCH_LAN,
  27. 0
  28. );
  29. if (PciSegmentRead32 (GbePciBase) != 0xFFFFFFFF) {
  30. return TRUE;
  31. }
  32. return FALSE;
  33. }
  34. /**
  35. Configure WOL during Sx entry.
  36. @param [in] GbeBar GbE MMIO space
  37. **/
  38. VOID
  39. GbeWolWorkaround (
  40. IN UINT32 GbeBar
  41. )
  42. {
  43. UINT32 RAL0;
  44. UINT32 RAH0;
  45. UINT16 WUC;
  46. EFI_STATUS Status;
  47. UINT16 Data16;
  48. //
  49. // 1. Set page to 769 Port Control Registers
  50. // 2. Wait 4 mSec
  51. //
  52. Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
  53. if (EFI_ERROR (Status)) return;
  54. //
  55. // 3. Set registry to 17 Port General Configuration
  56. // 4. Copy all settings from Port General Configuration
  57. //
  58. Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
  59. if (EFI_ERROR (Status)) return;
  60. //
  61. // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD
  62. //
  63. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP));
  64. if (EFI_ERROR (Status)) return;
  65. //
  66. // 6. Read Receive Address Low and Receive Address High from MMIO
  67. //
  68. RAL0 = MmioRead32 (GbeBar + R_LAN_MEM_CSR_RAL);
  69. RAH0 = MmioRead32 (GbeBar + R_LAN_MEM_CSR_RAH);
  70. //
  71. // 7. Set page to 800 Wake Up Registers
  72. // 8. Wait 4 mSec
  73. //
  74. Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_800_WAKE_UP_REGISTERS);
  75. if (EFI_ERROR (Status)) return;
  76. //
  77. // 9. Set registry to 16 Receive Address Low 1/2
  78. //
  79. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_16_RAL0);
  80. if (EFI_ERROR (Status)) return;
  81. //
  82. // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1/2
  83. //
  84. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 & 0xFFFF));
  85. if (EFI_ERROR (Status)) return;
  86. //
  87. // 11. Set registry to 17 Receive Address Low 2/2
  88. //
  89. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_17_RAL1);
  90. if (EFI_ERROR (Status)) return;
  91. //
  92. // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low 2/2
  93. //
  94. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 >> 16));
  95. if (EFI_ERROR (Status)) return;
  96. //
  97. // 13. Set registry to 18 Receive Address High 1/2
  98. //
  99. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_18_RAH0);
  100. if (EFI_ERROR (Status)) return;
  101. //
  102. // 14. Program last 16 bits [32:47] out of 48
  103. //
  104. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAH0 & B_LAN_MEM_CSR_RAH_RAH));
  105. if (EFI_ERROR (Status)) return;
  106. //
  107. // 15. Set registry to 19 Receive Address High 2/2
  108. //
  109. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_19_RAH1);
  110. if (EFI_ERROR (Status)) return;
  111. //
  112. // 16. Set Address Valid
  113. //
  114. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID);
  115. if (EFI_ERROR (Status)) return;
  116. //
  117. // 17. Set Wake Up Control Register 1
  118. //
  119. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_800_REGISETER_1_WUC);
  120. if (EFI_ERROR (Status)) return;
  121. //
  122. // 18. Copy WakeUp Control from MAC MMIO
  123. //
  124. WUC = (UINT16) MmioRead32 (GbeBar + R_LAN_MEM_CSR_WUC);
  125. //
  126. // 19. Store WakeUp Contorl into LCD
  127. // Modify APME bit to enable APM wake up
  128. //
  129. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (WUC & 0xFFFF));
  130. if (EFI_ERROR (Status)) return;
  131. //
  132. // 20. Set page to 803 Host Wol Packet
  133. // 21. Wait 4 mSec
  134. //
  135. Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_803_HOST_WOL_PACKET);
  136. if (EFI_ERROR (Status)) return;
  137. //
  138. // 22. Set registry to 66 Host WoL Packet Clear
  139. //
  140. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_803_REGISETER_66_HWPC);
  141. if (EFI_ERROR (Status)) return;
  142. //
  143. // 23. Clear WOL Packet
  144. //
  145. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, R_PHY_MDI_PHY_REG_DATA_READ_WRITE, 0);
  146. if (EFI_ERROR (Status)) return;
  147. //
  148. // 24. Set page to 769 Port Control Registers
  149. // 25. Wait 4 mSec
  150. //
  151. Status = GbeMdiSetPage (GbeBar, PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
  152. if (EFI_ERROR (Status)) return;
  153. //
  154. // 26. Set registry to 17 Port General Configuration
  155. //
  156. Status = GbeMdiSetRegister (GbeBar, R_PHY_MDI_PAGE_769_REGISETER_17_PGC);
  157. if (EFI_ERROR (Status)) return;
  158. //
  159. // 27. Copy all settings from Port General Configuration
  160. //
  161. Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
  162. if (EFI_ERROR (Status)) return;
  163. //
  164. // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD
  165. //
  166. Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP) & (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE));
  167. if (EFI_ERROR (Status)) return;
  168. }
  169. /**
  170. Additional Internal GbE Controller special cases WOL Support.
  171. System BIOS is required perform additional steps upon S0 to S3,4,5 transition
  172. when ME is off and GbE device in D0. This is needed to enable LAN wake
  173. in particular when platform is shut-down from EFI.
  174. **/
  175. VOID
  176. GbeSxWorkaround (
  177. VOID
  178. )
  179. {
  180. UINT64 LanRegBase;
  181. UINT32 GbeBar;
  182. EFI_STATUS Status;
  183. LanRegBase = PCI_SEGMENT_LIB_ADDRESS (
  184. DEFAULT_PCI_SEGMENT_NUMBER_PCH,
  185. DEFAULT_PCI_BUS_NUMBER_PCH,
  186. PCI_DEVICE_NUMBER_PCH_LAN,
  187. PCI_FUNCTION_NUMBER_PCH_LAN,
  188. 0
  189. );
  190. if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
  191. return;
  192. }
  193. //
  194. // Check if GbE device is in D0
  195. //
  196. if ((PciSegmentRead16 (LanRegBase + R_LAN_CFG_PMCS) & B_LAN_CFG_PMCS_PS) != V_LAN_CFG_PMCS_PS0) {
  197. return;
  198. }
  199. ASSERT (mResvMmioSize >= (1 << N_LAN_CFG_MBARA_ALIGN));
  200. GbeBar = (UINT32) mResvMmioBaseAddr;
  201. if (GbeBar == 0) {
  202. ASSERT (FALSE);
  203. return;
  204. }
  205. //
  206. // Enable MMIO decode using reserved range.
  207. //
  208. PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
  209. PciSegmentWrite32 (LanRegBase + R_LAN_CFG_MBARA, GbeBar);
  210. PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
  211. //
  212. // If MBARA offset 5800h [0] = 1b then proceed with the w/a
  213. //
  214. if (MmioRead32 (GbeBar + R_LAN_MEM_CSR_WUC) & B_LAN_MEM_CSR_WUC_APME) {
  215. Status = GbeMdiAcquireMdio (GbeBar);
  216. ASSERT_EFI_ERROR (Status);
  217. if (!EFI_ERROR (Status)) {
  218. GbeWolWorkaround (GbeBar);
  219. GbeMdiReleaseMdio (GbeBar);
  220. }
  221. }
  222. //
  223. // Disable MMIO decode.
  224. //
  225. PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) ~EFI_PCI_COMMAND_MEMORY_SPACE);
  226. PciSegmentWrite32 (LanRegBase + R_LAN_CFG_MBARA, 0);
  227. }
  228. /**
  229. Enable platform wake from LAN when in DeepSx if platform supports it.
  230. Called upon Sx entry.
  231. **/
  232. VOID
  233. GbeConfigureDeepSxWake (
  234. VOID
  235. )
  236. {
  237. if (PmcIsLanDeepSxWakeEnabled ()) {
  238. IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96), (UINT32) B_ACPI_IO_GPE0_EN_127_96_LAN_WAKE);
  239. }
  240. }
  241. /**
  242. GbE Sx entry handler
  243. **/
  244. VOID
  245. PchLanSxCallback (
  246. VOID
  247. )
  248. {
  249. if (IsGbeEnabled ()) {
  250. GbeSxWorkaround ();
  251. GbeConfigureDeepSxWake ();
  252. }
  253. }