IioPortBifurcation.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. /** @file
  2. Install Iio Port Bifurcation Init Data.
  3. @copyright
  4. Copyright 2017 - 2021 Intel Corporation. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <PiPei.h>
  8. #include <Upi/KtiHost.h>
  9. #include <Guid/SetupVariable.h>
  10. #include <Guid/PlatformInfo.h>
  11. #include <Ppi/Smbus2.h>
  12. #include <GpioInitData.h>
  13. #include <Library/PeiServicesTablePointerLib.h>
  14. #include <Library/GpioLib.h>
  15. #include <Library/UbaIioConfigLib.h>
  16. #include <Library/UbaPlatLib.h>
  17. #include <Library/HobLib.h>
  18. #include <Library/UbaIioPortBifurcationInitLib.h>
  19. #include <Library/PchMultiPchBase.h>
  20. #include <CpuAndRevisionDefines.h>
  21. #include <Ppi/DynamicSiLibraryPpi.h>
  22. #include "PeiCommonBoardInitLib.h"
  23. #include "IioBifurcationSlotTable.h"
  24. #define IIO_D_UBALOG(...) { DEBUG((DEBUG_ERROR, "[IIO](UBA) " __VA_ARGS__)); } // Important log always printed
  25. #define IIO_D_UBADBG(...) { DEBUG((DEBUG_INFO, "[IIO](UBA) " __VA_ARGS__)); } // Debug log, printed with BIOS debug jumper
  26. #define IIO_D_UBAWARN(...) { DEBUG((DEBUG_ERROR, "[IIO](UBA) WARNING: " __VA_ARGS__)); } // Warning log, not necessary error
  27. #define IIO_D_UBAERR(...) { DEBUG((DEBUG_ERROR, "[IIO](UBA) ERROR: " __VA_ARGS__)); } // Errorneous situation, probably bug or hw problem
  28. EFI_PLATFORM_INFO*
  29. GetPlatformInfoFromHob (
  30. VOID
  31. )
  32. {
  33. EFI_HOB_GUID_TYPE *GuidHob;
  34. GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  35. if (GuidHob == NULL) {
  36. ASSERT (FALSE);
  37. return NULL;
  38. }
  39. return GET_GUID_HOB_DATA (GuidHob);
  40. }
  41. /**
  42. Check if QAT-UPLINK override is needed
  43. @param[in] Socket Socket index
  44. @param[in] Iou IOU index
  45. @param[out] Bifurcation Buffer for bifurcation needed to support QAT
  46. @return TRUE if custom bifurcation is necessary
  47. */
  48. BOOLEAN
  49. IsQatUplinkOverrideNeeded (
  50. IN UINT8 Socket,
  51. IN UINT8 Iou,
  52. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi,
  53. OUT UINT8 *Bifurcation
  54. )
  55. {
  56. EFI_PLATFORM_INFO *PlatformInfo;
  57. UINT32 Gpio;
  58. EFI_STATUS Status;
  59. PlatformInfo = GetPlatformInfoFromHob ();
  60. if (PlatformInfo == NULL) {
  61. return FALSE;
  62. }
  63. switch (PlatformInfo->BoardId) {
  64. case TypeWilsonCityRP:
  65. case TypeWilsonCityModular:
  66. case TypeWilsonCitySMT:
  67. case TypeWilsonCityPPV:
  68. case TypeWilsonPointRP:
  69. case TypeWilsonPointModular:
  70. case TypeCooperCityRP:
  71. if (Socket %2 == 0 && Iou == 3) {
  72. //
  73. // It is possible that special bifurcation for QAT-UPLINK if needed
  74. // It can be recognized by GPIO D8: 0 means that there is no UPLINK
  75. //
  76. Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_D8, &Gpio);
  77. if (EFI_ERROR (Status)) {
  78. return FALSE;
  79. }
  80. if (Gpio != 0) {
  81. *Bifurcation = IIO_BIFURCATE_xxx8xxx8;
  82. return TRUE;
  83. } else {
  84. return FALSE;
  85. }
  86. }
  87. break;
  88. }
  89. //
  90. // By default there is no QAT-UPLINK support
  91. //
  92. return FALSE;
  93. }
  94. /**
  95. Check if QAT-CABLE override is needed
  96. @param[in] Socket Socket index
  97. @param[in] Iou IOU index
  98. @param[out] Bifurcation Buffer for bifurcation needed to support QAT
  99. @return TRUE if custom bifurcation is necessary
  100. */
  101. BOOLEAN
  102. IsQatCableOverrideNeeded (
  103. IN UINT8 Socket,
  104. IN UINT8 Iou,
  105. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi,
  106. OUT UINT8 *Bifurcation
  107. )
  108. {
  109. EFI_PLATFORM_INFO *PlatformInfo;
  110. UINT32 Gpio;
  111. EFI_STATUS Status;
  112. PlatformInfo = GetPlatformInfoFromHob ();
  113. if (PlatformInfo == NULL) {
  114. return FALSE;
  115. }
  116. switch (PlatformInfo->BoardId) {
  117. case TypeWilsonCityRP:
  118. case TypeWilsonCityModular:
  119. case TypeWilsonCitySMT:
  120. case TypeWilsonCityPPV:
  121. case TypeWilsonPointRP:
  122. case TypeWilsonPointModular:
  123. if (Iou == 4) {
  124. //
  125. // It is possible that special bifurcation for Oculink QAT cable is needed
  126. // Then cable is used to connect oculinks ports with QAT
  127. // To determine it if cable is needed GPIO-B3 needs to be examined
  128. // GPIO-B3 == 0 means that cable is present
  129. //
  130. Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B3, &Gpio);
  131. if (EFI_ERROR (Status)) {
  132. return FALSE;
  133. }
  134. if (Gpio != 0) {
  135. //
  136. // There is no cable
  137. //
  138. return FALSE;
  139. }
  140. //
  141. // Cable is present to check which MEZZ IOU is used GPIO B4 needs to be examined
  142. // GPIO-B4 == 1: MEZZ IOU from Socket0 is used;
  143. // GPIO-B4 == 0: MEZZ IOU from Socket1 is used;
  144. //
  145. Status = DynamicSiLibraryPpi->GpioGetInputValueByPchId (PCH_LEGACY_ID, GPIO_SKL_H_GPP_B4, &Gpio);
  146. if (EFI_ERROR (Status)) {
  147. return FALSE;
  148. }
  149. if ((Socket == 0 && Gpio == 1) || (Socket == 1 && Gpio == 0)) {
  150. *Bifurcation = IIO_BIFURCATE_xxx8x4x4;
  151. return TRUE;
  152. }
  153. }
  154. } //switch: Board-Id
  155. //
  156. // By default there is no QAT-cable support
  157. //
  158. return FALSE;
  159. }
  160. /**
  161. Check if QAT override is needed.
  162. There are two possible QAT variants:
  163. - QAT uplink
  164. - QAT cable
  165. If LBG with QAT is detected (by GPIO read) custom bifurcation should be set.
  166. @param[in] IioGlobalData Pointer to IioGlobalData
  167. */
  168. VOID
  169. CheckQatBifurcationOverrides (
  170. IN IIO_GLOBALS *IioGlobalData,
  171. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi
  172. )
  173. {
  174. UINT8 Socket;
  175. UINT8 Iou;
  176. UINT8 Bifurcation;
  177. UINT8 StackIndex;
  178. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  179. for (Iou = 0; Iou < MAX_IOU_PER_SOCKET; Iou++) {
  180. StackIndex = Iou+1;
  181. if (!DynamicSiLibraryPpi->IioIsSocketPresent (Socket)) {
  182. //
  183. // Skip sockets which are not present on the platform
  184. //
  185. continue;
  186. }
  187. if (!DynamicSiLibraryPpi->IioIsStackPresent (Socket, StackIndex)) {
  188. //
  189. // Skips stacks which are not present on the platform
  190. //
  191. continue;
  192. }
  193. //
  194. // Override if QAT is enabled
  195. //
  196. if (IsQatUplinkOverrideNeeded (Socket, Iou, DynamicSiLibraryPpi, &Bifurcation)) {
  197. if (IioGlobalData->SetupData.ConfigIOU[Socket][Iou] == IIO_BIFURCATE_AUTO) {
  198. IioGlobalData->SetupData.ConfigIOU[Socket][Iou] = Bifurcation;
  199. IIO_D_UBALOG ("[%d.%d] QAT-uplink detected; bif=%d\n", Socket, StackIndex, Bifurcation);
  200. }
  201. } else if (IsQatCableOverrideNeeded (Socket, Iou, DynamicSiLibraryPpi, &Bifurcation)) {
  202. if (IioGlobalData->SetupData.ConfigIOU[Socket][Iou] == IIO_BIFURCATE_AUTO) {
  203. IioGlobalData->SetupData.ConfigIOU[Socket][Iou] = Bifurcation;
  204. IIO_D_UBALOG ("[%d.%d] QAT-cable detected; bif=%d\n", Socket, StackIndex, Bifurcation);
  205. }
  206. }
  207. } // for each Iou
  208. } // for each Socket
  209. }
  210. /**
  211. Check if MRL sensor is present for given port.
  212. It depends on board architecture.
  213. Sometimes slot doesn't support it in contrast to Ext.Card.
  214. @param[in] TotalPortIndex Index of the port (across all ports on platform)
  215. @param[in] ExtCardPresent TRUE if Ext. card presence was detected
  216. @return TRUE if MRL sensor presence is expected
  217. */
  218. BOOLEAN
  219. IsMrlSensorPresent (
  220. IN UINT16 TotalPortIndex,
  221. IN BOOLEAN ExtCardPresent
  222. )
  223. {
  224. EFI_HOB_GUID_TYPE *GuidHob;
  225. EFI_PLATFORM_INFO *PlatformInfo;
  226. //
  227. // This data should be read from platform specific config (slot table IIO_BIFURCATION_DATA_ENTRY_EX)
  228. // but for now there is no such information
  229. // Let this be a temp. workaround until the update of UBA slot configs
  230. //
  231. if (ExtCardPresent) {
  232. //
  233. // MRL sensor is always present for Ext. Cards
  234. //
  235. return TRUE;
  236. }
  237. GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  238. if (GuidHob == NULL) {
  239. ASSERT (FALSE);
  240. return FALSE;
  241. }
  242. PlatformInfo = GET_GUID_HOB_DATA (GuidHob);
  243. switch (PlatformInfo->BoardId) {
  244. case TypeWilsonCityRP:
  245. //
  246. // This is version for ICX
  247. //
  248. switch (TotalPortIndex) {
  249. case SOCKET_1_INDEX + PORT_1A_INDEX:
  250. case SOCKET_1_INDEX + PORT_1B_INDEX:
  251. case SOCKET_1_INDEX + PORT_1C_INDEX:
  252. case SOCKET_1_INDEX + PORT_1D_INDEX:
  253. //
  254. // only one slot on WilsonCity supports MRL
  255. //
  256. return TRUE;
  257. default:
  258. return FALSE;
  259. }
  260. break;
  261. case TypeCooperCityRP:
  262. //
  263. // Let's assume that MRL is supported by all slots on CooperCity - where HP is enabled!
  264. //
  265. return TRUE;
  266. default:
  267. //
  268. // For the rest of platforms the situation is unknown for now
  269. //
  270. return FALSE;
  271. }
  272. }
  273. /**
  274. Verify if VMD is enabled and override Slot configuration
  275. based on the VMD settings
  276. @param[in] IioGlobalData Pointer to Iio Globals.
  277. @param[in] Slot Slot configuration settings
  278. @param[in] SlotEntries Number of slot entries
  279. @param[in] ExtCardPresent Table with results of Ext. Card detection
  280. **/
  281. #define SLOT_NUM_OFFSET_FOR_EXT_CARD_SLOT 0x50
  282. VOID
  283. ConfigureSlots (
  284. IN OUT IIO_GLOBALS *IioGlobalData,
  285. IN IIO_SLOT_CONFIG_DATA_ENTRY_EX *Slot,
  286. IN UINT8 SlotEntries,
  287. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi,
  288. IN BOOLEAN ExtCardPresent[MAX_SOCKET][MAX_IOU_PER_SOCKET]
  289. )
  290. {
  291. UINT8 Index;
  292. UINT16 TotalPortIndex;
  293. UINT8 IioIndex = 0;
  294. UINT8 Stack;
  295. UINT8 PortIndex = 0;
  296. UINT8 Iou;
  297. BOOLEAN IsHpSupportedBySlot;
  298. BOOLEAN IsVmdEnabledForSlot = TRUE;
  299. BOOLEAN IsExtCardInSlot = TRUE;
  300. BOOLEAN AreLanesAssignedToPort = TRUE;
  301. for (Index = 0; Index < SlotEntries; Index ++) {
  302. TotalPortIndex = Slot[Index].PortIndex;
  303. if (DynamicSiLibraryPpi->GetMaxPortNumPerSocket() == 0 || DynamicSiLibraryPpi->GetMaxPortNumPerSocket() == 0) {
  304. return;
  305. }
  306. IioIndex = (UINT8) (TotalPortIndex / DynamicSiLibraryPpi->GetMaxPortNumPerSocket ());
  307. PortIndex = (UINT8) (TotalPortIndex - (IioIndex * DynamicSiLibraryPpi->GetMaxPortNumPerSocket ()));
  308. Stack = IioGlobalData->IioVar.IioVData.StackPerPort[IioIndex][PortIndex];
  309. Iou = Stack - 1;
  310. IsHpSupportedBySlot = FALSE;
  311. IsVmdEnabledForSlot = DynamicSiLibraryPpi->IsVMDEnabledForPort (IioIndex, PortIndex);
  312. IsExtCardInSlot = (Slot[Index].ExtensionCardSupport && ExtCardPresent[IioIndex][Iou]);
  313. AreLanesAssignedToPort = DynamicSiLibraryPpi->IioAreLanesAssignedToPort (IioGlobalData, IioIndex, PortIndex);
  314. if (Slot[Index].Hidden || !AreLanesAssignedToPort) {
  315. //
  316. // Hide rootports which are hidden in slots table or don't have any lanes assigned
  317. //
  318. IioGlobalData->SetupData.HidePEXPMenu[TotalPortIndex] = HIDE;
  319. IioGlobalData->SetupData.PEXPHIDE[TotalPortIndex] = HIDE;
  320. } else {
  321. //
  322. // Unhide active rootports (hided by default)
  323. //
  324. IioGlobalData->SetupData.HidePEXPMenu[TotalPortIndex] = NOT_HIDE;
  325. IioGlobalData->SetupData.PEXPHIDE[TotalPortIndex] = NOT_HIDE;
  326. }
  327. if (Slot[Index].SlotPowerLimitScale != PWR_SCL_MAX) {
  328. IioGlobalData->SetupData.SLOTSPLS[TotalPortIndex] = Slot[Index].SlotPowerLimitScale;
  329. IioGlobalData->SetupData.SLOTSPLV[TotalPortIndex] = Slot[Index].SlotPowerLimitValue;
  330. }
  331. if (Slot[Index].SlotNumber != NO_SLT_IMP) {
  332. IioGlobalData->SetupData.SLOTIMP[TotalPortIndex] = SLT_IMP;
  333. IioGlobalData->SetupData.SLOTPSP[TotalPortIndex] = Slot[Index].SlotNumber;
  334. } else if (AreLanesAssignedToPort) {
  335. //
  336. // If slot is not marked as implemented yet, but is exposed in current bifurcation
  337. // assume that there will be a slot
  338. //
  339. IioGlobalData->SetupData.SLOTIMP[TotalPortIndex] = 1;
  340. IioGlobalData->SetupData.SLOTPSP[TotalPortIndex] = SLOT_NUM_OFFSET_FOR_EXT_CARD_SLOT + TotalPortIndex;
  341. }
  342. if (IsVmdEnabledForSlot) {
  343. //
  344. // Disable Electromechanical Interlock presence for VMD
  345. //
  346. IioGlobalData->SetupData.SLOTEIP[TotalPortIndex] = DISABLE;
  347. } else {
  348. IioGlobalData->SetupData.SLOTEIP[TotalPortIndex] = Slot[Index].InterLockPresent;
  349. }
  350. //
  351. // HotPlug related settings:
  352. // - first check the presence of Ext. Card in the slot and apply specific setting
  353. // - next apply common settings for HotPlug
  354. //
  355. if (IsExtCardInSlot && Slot[Index].ExtnCardHotPlugCapable) {
  356. IsHpSupportedBySlot = TRUE;
  357. //
  358. // Apply specific overrides for HP with Ext. Card
  359. //
  360. if (Slot[Index].ExtnCardHPVppPort != VPP_PORT_MAX) {
  361. IioGlobalData->SetupData.VppEnabled[TotalPortIndex] = TRUE;
  362. IioGlobalData->SetupData.VppPort[TotalPortIndex] = Slot[Index].ExtnCardHPVppPort;
  363. IioGlobalData->SetupData.VppAddress[TotalPortIndex] = Slot[Index].ExtnCardHPVppAddress;
  364. }
  365. } else if (Slot[Index].HotPlugCapable) {
  366. //
  367. // HP settings when there is no Ext. Card
  368. //
  369. IsHpSupportedBySlot = TRUE;
  370. if (Slot[Index].VppPort != VPP_PORT_MAX) {
  371. IioGlobalData->SetupData.VppEnabled[TotalPortIndex] = TRUE;
  372. IioGlobalData->SetupData.VppPort[TotalPortIndex] = Slot[Index].VppPort;
  373. IioGlobalData->SetupData.VppAddress[TotalPortIndex] = Slot[Index].VppAddress;
  374. }
  375. }
  376. if (IsHpSupportedBySlot) {
  377. //
  378. // There are common setting for HP
  379. //
  380. IioGlobalData->SetupData.SLOTHPCAP[TotalPortIndex] = ENABLE;
  381. IioGlobalData->SetupData.SLOTAIP[TotalPortIndex] = ENABLE; // Attention Indicator Present
  382. IioGlobalData->SetupData.SLOTPIP[TotalPortIndex] = ENABLE; // Power Indicator Present
  383. if (IsVmdEnabledForSlot) {
  384. IioGlobalData->SetupData.SLOTHPSUP[TotalPortIndex] = ENABLE; // HotPlug Surprise is always enabled for VMD
  385. }
  386. if (!IsVmdEnabledForSlot && IsMrlSensorPresent (TotalPortIndex, IsExtCardInSlot)) {
  387. //
  388. // Let's assume that if MRL sensor is present Attention button and Power Controller is also present
  389. //
  390. IioGlobalData->SetupData.SLOTMRLSP[TotalPortIndex] = ENABLE;
  391. IioGlobalData->SetupData.SLOTABP[TotalPortIndex] = ENABLE;
  392. IioGlobalData->SetupData.SLOTPCP[TotalPortIndex] = ENABLE;
  393. } else {
  394. IioGlobalData->SetupData.SLOTMRLSP[TotalPortIndex] = DISABLE;
  395. IioGlobalData->SetupData.SLOTABP[TotalPortIndex] = DISABLE;
  396. IioGlobalData->SetupData.SLOTPCP[TotalPortIndex] = DISABLE;
  397. }
  398. }
  399. } // for each slot entry
  400. }
  401. /**
  402. Check if lanes are reversed for given IOU - this is important when non-symetrical
  403. bifurcation is requested.
  404. @param[in] BifurcationTable record from bifurcation table
  405. @return TRUE if lanes are in reversed order
  406. */
  407. BOOLEAN
  408. IsLaneReversed (
  409. IN IIO_BIFURCATION_DATA_ENTRY_EX *BifurcationTable
  410. )
  411. {
  412. EFI_HOB_GUID_TYPE *GuidHob;
  413. EFI_PLATFORM_INFO *PlatformInfo;
  414. //
  415. // This data should be read from platform specific config - but for now we don't have this information there
  416. // Let this be a temp. workaround until the update of biffurcation config.
  417. //
  418. GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  419. if (GuidHob == NULL) {
  420. ASSERT (FALSE);
  421. return FALSE;
  422. }
  423. PlatformInfo = GET_GUID_HOB_DATA (GuidHob);
  424. switch (PlatformInfo->BoardId) {
  425. case TypeCooperCityRP:
  426. //
  427. // For CooperCityRP lane reversed are:
  428. // - on even sockets: on IOU4
  429. // - on odd sockets: on IOU1
  430. //
  431. return ((BifurcationTable->Socket&1) == 1 && BifurcationTable->IouNumber == Iio_Iou1);
  432. default:
  433. //
  434. // Let's assume that WilsonCity config is a default one.
  435. //
  436. //
  437. // This is version for ICX (default)
  438. //
  439. return (BifurcationTable->Socket == 1 &&
  440. (BifurcationTable->IouNumber == Iio_Iou0 || BifurcationTable->IouNumber == Iio_Iou4));
  441. }
  442. }
  443. /**
  444. Read the bifurcation info stored at I/O Expander (PCA9554) which BIOS
  445. can get through Smbus.
  446. To communicate with IO Expander first MUX PCA9545 needs to be configured.
  447. The bifurcation encoding is [3:0]:
  448. BW5_BIFURCATE_x4x4x4x4 1 0 0 0
  449. BW5_BIFURCATE_x4x4xxx8 1 0 0 1 Lanes to port ACD on board
  450. BW5_BIFURCATE_xxx8x4x4 1 0 1 0 Lanes to port ABC on board
  451. BW5_BIFURCATE_xxx8xxx8 1 0 1 1 Lanes to port AC on board
  452. No BW5 1 1 x x
  453. @param IioGlobalData - Pointer to IioGlobals
  454. @param BroadwayTablePtr - Pointer to BroadwayTable
  455. @retval IIO_BIFURCATE_xxxxxxxx BW communication failure
  456. @retval IIO_BIFURCATE_x4x4x4x4 Requested bifurcation x4x4x4x4
  457. @retval IIO_BIFURCATE_x4x4xxx8 Requested bifurcation x4x4xxx8
  458. @retval IIO_BIFURCATE_xxx8x4x4 Requested bifurcation xxx8x4x4
  459. @retval IIO_BIFURCATE_xxx8xxx8 Requested bifurcation xxx8xxx8
  460. **/
  461. UINT8
  462. GetBw5Bifurcation (
  463. IN IIO_BIFURCATION_DATA_ENTRY_EX *BifurcationTable,
  464. IN IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi
  465. )
  466. {
  467. EFI_STATUS Status;
  468. EFI_SMBUS_DEVICE_ADDRESS SmbDevAddr;
  469. EFI_PEI_SMBUS2_PPI *SmbPpi = NULL;
  470. UINT16 SmbData = 0;
  471. UINT8 SmbByteData = 0;
  472. UINT8 RetryCount;
  473. UINTN SmbLen = 2;
  474. UINTN SmbByteLen = 1;
  475. if (BifurcationTable->ExtnCardSMBusAddress == SMB_ADDR_MAX ) {
  476. return IIO_BIFURCATE_xxxxxxxx;
  477. }
  478. Status = PeiServicesLocatePpi (&gEfiPeiSmbus2PpiGuid, 0, NULL, (VOID **) &SmbPpi);
  479. // Initialize Bw5Id to not present
  480. if (Status != EFI_SUCCESS || SmbPpi == NULL) {
  481. DEBUG ((DEBUG_ERROR, "[Iio] Get SMBus protocol error %x\n", Status));
  482. return IIO_BIFURCATE_xxxxxxxx;
  483. }
  484. for (RetryCount = 0; RetryCount < NUM_OF_RETRIES; RetryCount++) {
  485. //
  486. // Configure through the smbus MUX PCA9545 to start communicate to GPIO expander
  487. //
  488. SmbDevAddr.SmbusDeviceAddress = BifurcationTable->MuxSMBusAddress >> 1;
  489. SmbByteData = BifurcationTable->MuxSMBusChannel;
  490. Status = SmbPpi->Execute (SmbPpi, SmbDevAddr, 0, EfiSmbusSendByte, FALSE, &SmbByteLen, &SmbByteData);
  491. if (EFI_ERROR (Status)) {
  492. continue;
  493. }
  494. //
  495. // Read the current I/O pins configuration for Port0
  496. //
  497. SmbDevAddr.SmbusDeviceAddress = BifurcationTable->ExtnCardSMBusAddress >> 1;
  498. Status = SmbPpi->Execute (SmbPpi, SmbDevAddr, BW4_CONFIG_OFFSET, EfiSmbusReadWord, FALSE, &SmbLen, &SmbData);
  499. if (!EFI_ERROR (Status)) {
  500. //
  501. // Configure the direction of I/O pins for Port0/Port1 as Input.
  502. //
  503. SmbData = SmbData | BW5_CONFIG_REG_MASK;
  504. Status = SmbPpi->Execute (SmbPpi, SmbDevAddr, BW4_CONFIG_OFFSET, EfiSmbusWriteWord, FALSE, &SmbLen, &SmbData);
  505. if (!EFI_ERROR (Status)) {
  506. //
  507. // Read Input Port0/Port1 register to identify BW5 Id
  508. //
  509. Status = SmbPpi->Execute (SmbPpi, SmbDevAddr, BW4_DATA_OFFSET, EfiSmbusReadWord, FALSE, &SmbLen, &SmbData);
  510. if (!EFI_ERROR (Status)){
  511. //
  512. // Mask the Input Port0/1 register data [15:0] to get BW5 ID [3:0].
  513. //
  514. // The bifurcation encoding is [3:0]:
  515. // BW5_BIFURCATE_x4x4x4x4 1 0 0 0
  516. // BW5_BIFURCATE_x4x4xxx8 1 0 0 1 Lanes to port ACD on board
  517. // BW5_BIFURCATE_xxx8x4x4 1 0 1 0 Lanes to port ABC on board
  518. // BW5_BIFURCATE_xxx8xxx8 1 0 1 1 Lanes to port AC on board
  519. // No BW5 1 1 x x
  520. //
  521. switch (SmbData & 0xF) {
  522. case 0x8:
  523. return IIO_BIFURCATE_x4x4x4x4;
  524. break;
  525. case 0x9:
  526. if (IsLaneReversed (BifurcationTable)) {
  527. return IIO_BIFURCATE_xxx8x4x4;
  528. } else {
  529. return IIO_BIFURCATE_x4x4xxx8;
  530. }
  531. break;
  532. case 0xA:
  533. if (IsLaneReversed (BifurcationTable)) {
  534. return IIO_BIFURCATE_x4x4xxx8;
  535. } else {
  536. return IIO_BIFURCATE_xxx8x4x4;
  537. }
  538. break;
  539. case 0xB:
  540. return IIO_BIFURCATE_xxx8xxx8;
  541. break;
  542. default:
  543. return IIO_BIFURCATE_xxxxxxxx;
  544. break;
  545. }
  546. } // Read Port0
  547. } // Configure Port0
  548. } // Read Port0 Config
  549. //
  550. // Configure through the smbus MUX PCA9545 to end communicate to GPIO expander
  551. //
  552. SmbDevAddr.SmbusDeviceAddress = BifurcationTable->MuxSMBusAddress >> 1;
  553. SmbByteData &= ~BifurcationTable->MuxSMBusChannel;
  554. Status = SmbPpi->Execute (SmbPpi, SmbDevAddr, 0, EfiSmbusSendByte, FALSE, &SmbByteLen, &SmbByteData);
  555. if (EFI_ERROR (Status)) {
  556. continue;
  557. }
  558. } //RetryCount
  559. return IIO_BIFURCATE_xxxxxxxx;
  560. }
  561. /**
  562. Set bifurcation base of default settings and Ext. Card presence
  563. (detected by BW)
  564. @param[in] IioGlobalData Pointer to Iio Globals.
  565. @param[in] BifurcationTable Bifurcation configuration settings
  566. @param[in] BifurcationEntries Number of bif. table entries
  567. @param[in] ExtCardPresent Table with results of Ext. Card detection
  568. **/
  569. VOID
  570. DetectExtCards (
  571. IN IIO_GLOBALS *IioGlobalData,
  572. IN IIO_BIFURCATION_DATA_ENTRY_EX *BifurcationTable,
  573. IN UINT8 BifurcationEntries,
  574. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi,
  575. OUT BOOLEAN ExtCardPresent[MAX_SOCKET][MAX_IOU_PER_SOCKET]
  576. )
  577. {
  578. UINT8 Index;
  579. UINT8 BwBifurcation;
  580. UINT8 Socket;
  581. UINT8 Iou;
  582. //
  583. // Try to communicate with Ext.Card which can request custom bifurcation on the stack
  584. //
  585. for (Index = 0; Index < BifurcationEntries; Index++){
  586. Socket = BifurcationTable[Index].Socket;
  587. Iou = BifurcationTable[Index].IouNumber;
  588. ExtCardPresent[Socket][Iou] = FALSE; // by default
  589. if (BifurcationTable[Index].ExtnCardSMBusAddress != SMB_ADDR_MAX) {
  590. //
  591. // ExtCard can be supported at this stack - try to detect it
  592. //
  593. BwBifurcation = GetBw5Bifurcation (&BifurcationTable[Index], DynamicSiLibraryPpi);
  594. if (BwBifurcation != IIO_BIFURCATE_xxxxxxxx) {
  595. //
  596. // Ext. Card is detected on this IOU
  597. //
  598. IIO_D_UBALOG ("[%d.%d] Ext. Card detected; bif=%d\n", Socket, Iou+1, BwBifurcation);
  599. ExtCardPresent[Socket][Iou] = TRUE;
  600. }
  601. }
  602. //
  603. // Set custom bifurcation requested by Ext. Card
  604. //
  605. if (IioGlobalData->SetupData.ConfigIOU[Socket][Iou] == IIO_BIFURCATE_AUTO) {
  606. //
  607. // There are no overrides for this IOU
  608. //
  609. if (ExtCardPresent[Socket][Iou]) {
  610. //
  611. // Set bifurcation requested by Ext. Card
  612. //
  613. IioGlobalData->SetupData.ConfigIOU[Socket][Iou] = BwBifurcation;
  614. } else {
  615. //
  616. // Set the default bifurcation for this IOU
  617. //
  618. IioGlobalData->SetupData.ConfigIOU[Socket][Iou] = BifurcationTable[Index].Bifurcation;
  619. }
  620. }
  621. IIO_D_UBADBG ("[%d.%d] final bifurcation = %X\n", Socket, Iou+1, IioGlobalData->SetupData.ConfigIOU[Socket][Iou]);
  622. } // for bifurcation table entry
  623. }
  624. /**
  625. Dump prepared configuration to log.
  626. @param[in] SetupData Pointer to SetupData structure
  627. **/
  628. VOID
  629. DumpConfiguration (
  630. IN IIO_CONFIG *SetupData,
  631. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi
  632. )
  633. {
  634. UINT8 IioIndex;
  635. UINT8 StackIndex = 0;
  636. UINT8 Iou;
  637. UINT8 PortIndex = 0;
  638. UINT8 PortInStackIndex = 0;
  639. UINT16 TotalPortIndex =0;
  640. for (IioIndex = 0; IioIndex < MAX_SOCKET ; IioIndex++) {
  641. if (!DynamicSiLibraryPpi->IioIsSocketPresent (IioIndex)) {
  642. //
  643. // Skips sockets which are not present on the platform
  644. //
  645. continue;
  646. }
  647. for (StackIndex = 0; StackIndex < DynamicSiLibraryPpi->GetMaxStackNumPerSocket (); StackIndex++) {
  648. if (DynamicSiLibraryPpi->IsDmiStack (StackIndex)) {
  649. //
  650. // Skip DMI stacks in dump
  651. //
  652. continue;
  653. }
  654. if (!DynamicSiLibraryPpi->IioIsStackPresent (IioIndex, StackIndex)) {
  655. //
  656. // Skips stacks which are not present on the platform
  657. //
  658. continue;
  659. }
  660. if (StackIndex >= MAX_IIO_STACK) {
  661. break;
  662. }
  663. Iou = StackIndex - 1;
  664. IIO_D_UBALOG("[%d.%d] Bifurcation = %X\n", IioIndex, StackIndex, SetupData->ConfigIOU[IioIndex][Iou]);
  665. IIO_D_UBALOG (" [ IDX ], PortHide, SlotImpl, SlotNumber, HotPlug, Vpp, Interlock\n");
  666. for (PortInStackIndex = 0; PortInStackIndex < DynamicSiLibraryPpi->GetMaxPortNumPerStack (StackIndex); PortInStackIndex++) {
  667. PortIndex = DynamicSiLibraryPpi->GetPortIndexbyStack (StackIndex, PortInStackIndex);
  668. TotalPortIndex = (IioIndex * DynamicSiLibraryPpi->GetMaxPortNumPerSocket ()) + PortIndex;
  669. IIO_D_UBALOG (" [%d p%02d] %2d | %2d | %3d | %3d | 0x%02x | %2d \n",
  670. IioIndex, PortIndex,
  671. SetupData->PEXPHIDE[TotalPortIndex],
  672. SetupData->SLOTIMP[TotalPortIndex],
  673. SetupData->SLOTPSP[TotalPortIndex],
  674. SetupData->SLOTHPCAP[TotalPortIndex],
  675. SetupData->VppAddress[TotalPortIndex] | SetupData->VppPort[TotalPortIndex],
  676. SetupData->SLOTEIP[TotalPortIndex]);
  677. } // foreach PortInStack
  678. } //foreach StackIndex
  679. } // foreach IioIndex
  680. }
  681. /**
  682. This function prepare the data for silicon initialization based on
  683. bifurcations and slots table
  684. This function is for tables in version PLATFORM_IIO_CONFIG_UPDATE_VERSION = 2
  685. @param[in] IioGlobalData IIO Global data structure
  686. @param[in] IioConfigTable
  687. */
  688. VOID
  689. IioPortBifurcationInitVer2 (
  690. IN IIO_GLOBALS *IioGlobalData,
  691. IN PLATFORM_IIO_CONFIG_UPDATE_TABLE_EX IioConfigTable,
  692. IN DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi
  693. )
  694. {
  695. IIO_BIFURCATION_DATA_ENTRY_EX *BifurcationTableEx;
  696. UINT8 BifurcationEntries;
  697. IIO_SLOT_CONFIG_DATA_ENTRY_EX *SlotTableEx;
  698. UINT8 SlotEntries;
  699. BOOLEAN ExtCardDetected[MAX_SOCKET][MAX_IOU_PER_SOCKET];
  700. //
  701. // Init bifurcation and slots tables
  702. //
  703. BifurcationTableEx = IioConfigTable.IioBifurcationTablePtr;
  704. BifurcationEntries = (UINT8) (IioConfigTable.IioBifurcationTableSize / sizeof (IIO_BIFURCATION_DATA_ENTRY_EX));
  705. SlotTableEx = IioConfigTable.IioSlotTablePtr;
  706. SlotEntries = (UINT8) (IioConfigTable.IioSlotTableSize / sizeof (IIO_SLOT_CONFIG_DATA_ENTRY_EX));
  707. //
  708. // Set the bifurcations for each IOU:
  709. // - if any override is set in setup menu - stay bifurcation not changed
  710. // - next check if QAT is detected (this is LBG specific) - QAT requires special bifurcation
  711. // - next try to detect ext. cards with BW bifurcation
  712. // - at the end set default bifurcation if no other options wer applied before
  713. if (DynamicSiLibraryPpi->IsCpuAndRevision (CPU_ICXSP, REV_ALL) ||
  714. DynamicSiLibraryPpi->IsCpuAndRevision (CPU_CPX, REV_ALL) ||
  715. DynamicSiLibraryPpi->IsCpuAndRevision (CPU_SKX, REV_ALL) ||
  716. DynamicSiLibraryPpi->IsCpuAndRevision (CPU_CLX, REV_ALL)
  717. ) {
  718. //
  719. // This is important only for programs with LBG PCH
  720. //
  721. CheckQatBifurcationOverrides (IioGlobalData, DynamicSiLibraryPpi);
  722. }
  723. DetectExtCards (IioGlobalData, BifurcationTableEx, BifurcationEntries, DynamicSiLibraryPpi, ExtCardDetected);
  724. //
  725. // Set each rootport settings based on slots table
  726. //
  727. ConfigureSlots (IioGlobalData, SlotTableEx, SlotEntries, DynamicSiLibraryPpi, ExtCardDetected);
  728. //
  729. // Configuration is ready - dump the config to log
  730. //
  731. DumpConfiguration (&IioGlobalData->SetupData, DynamicSiLibraryPpi);
  732. }
  733. /**
  734. Program the IIO_GLOBALS data structure with OEM IIO init values for SLOTs and Bifurcation.
  735. @param mSB - pointer to this protocol
  736. @param IioUds - Pointer to the IIO UDS data structure.
  737. @retval EFI_SUCCESS
  738. **/
  739. VOID
  740. IioPortBifurcationInitCallback (
  741. IN IIO_GLOBALS *IioGlobalData
  742. )
  743. {
  744. EFI_STATUS Status;
  745. UBA_CONFIG_DATABASE_PPI *UbaConfigPpi = NULL;
  746. DYNAMIC_SI_LIBARY_PPI *DynamicSiLibraryPpi = NULL;
  747. PLATFORM_IIO_CONFIG_UPDATE_TABLE_EX IioConfigTable;
  748. UINTN TableSize;
  749. //
  750. // Locate PLATFORM_IIO_CONFIG_UPDATE_TABLE_EX
  751. //
  752. Status = PeiServicesLocatePpi (&gUbaConfigDatabasePpiGuid, 0, NULL, (VOID **) &UbaConfigPpi);
  753. if (EFI_ERROR (Status)) {
  754. ASSERT (FALSE);
  755. return;
  756. }
  757. Status = PeiServicesLocatePpi (&gDynamicSiLibraryPpiGuid, 0, NULL, (VOID **) &DynamicSiLibraryPpi);
  758. if (EFI_ERROR (Status)) {
  759. ASSERT_EFI_ERROR (Status);
  760. return;
  761. }
  762. TableSize = sizeof (IioConfigTable);
  763. Status = UbaConfigPpi->GetData (UbaConfigPpi, &gPlatformIioConfigDataGuid, &IioConfigTable, &TableSize);
  764. if (EFI_ERROR (Status)) {
  765. ASSERT (FALSE);
  766. return;
  767. }
  768. ASSERT (IioConfigTable.Signature == PLATFORM_IIO_CONFIG_UPDATE_SIGNATURE);
  769. //
  770. // Call the right version of bifurcation init procedure
  771. //
  772. switch (IioConfigTable.Version) {
  773. case PLATFORM_IIO_CONFIG_UPDATE_VERSION_2:
  774. IioPortBifurcationInitVer2 (IioGlobalData, IioConfigTable, DynamicSiLibraryPpi);
  775. break;
  776. case PLATFORM_IIO_CONFIG_UPDATE_VERSION:
  777. IioPortBifurcationInitVer1 (IioGlobalData);
  778. break;
  779. default:
  780. ASSERT (FALSE);
  781. break;
  782. }
  783. }
  784. IIO_PORT_BIFURCATION_INIT_TABLE IioPortBifurcationInitTable =
  785. {
  786. IIO_PORT_BIFURCATION_INIT_SIGNATURE,
  787. IIO_PORT_BIFURCATION_INIT_VERSION,
  788. IioPortBifurcationInitCallback
  789. };
  790. EFI_STATUS
  791. InstallIioPortBifurcationInitData (
  792. IN UBA_CONFIG_DATABASE_PPI *UbaConfigPpi
  793. )
  794. {
  795. return UbaConfigPpi->AddData (
  796. UbaConfigPpi,
  797. &gIioPortBifurcationInitDataGuid,
  798. &IioPortBifurcationInitTable,
  799. sizeof (IioPortBifurcationInitTable)
  800. );
  801. }