0005-sb-intel-lynxpoint-Add-native-USB-init.patch 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. From 9bfb8614dbf1d9800ef8251cb3d839bcdbe5577f Mon Sep 17 00:00:00 2001
  2. From: Angel Pons <th3fanbus@gmail.com>
  3. Date: Fri, 6 May 2022 23:17:39 +0200
  4. Subject: [PATCH 05/26] sb/intel/lynxpoint: Add native USB init
  5. Implement native USB initialisation for Lynx Point. This is only needed
  6. when MRC.bin is not used.
  7. TO DO: Figure out how to deal with the FIXME's and TODO's lying around.
  8. Change-Id: Ie0fbeeca7b1ca1557173772d733fd2fa27703373
  9. Signed-off-by: Angel Pons <th3fanbus@gmail.com>
  10. ---
  11. .../haswell/native_raminit/raminit_native.c | 3 +
  12. src/southbridge/intel/lynxpoint/Makefile.inc | 2 +-
  13. src/southbridge/intel/lynxpoint/early_usb.c | 11 -
  14. .../intel/lynxpoint/early_usb_native.c | 584 ++++++++++++++++++
  15. src/southbridge/intel/lynxpoint/pch.h | 49 ++
  16. 5 files changed, 637 insertions(+), 12 deletions(-)
  17. create mode 100644 src/southbridge/intel/lynxpoint/early_usb_native.c
  18. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  19. index 6a002548c1..ef61d4ee09 100644
  20. --- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  21. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  22. @@ -5,6 +5,7 @@
  23. #include <northbridge/intel/haswell/haswell.h>
  24. #include <northbridge/intel/haswell/raminit.h>
  25. #include <southbridge/intel/lynxpoint/me.h>
  26. +#include <southbridge/intel/lynxpoint/pch.h>
  27. #include <types.h>
  28. static bool early_init_native(int s3resume)
  29. @@ -15,6 +16,8 @@ static bool early_init_native(int s3resume)
  30. /** TODO: CPU replacement check must be skipped in warm boots and S3 resumes **/
  31. const bool cpu_replaced = !s3resume && intel_early_me_cpu_replacement_check();
  32. + early_usb_init();
  33. +
  34. if (!CONFIG(INTEL_LYNXPOINT_LP))
  35. dmi_early_init();
  36. diff --git a/src/southbridge/intel/lynxpoint/Makefile.inc b/src/southbridge/intel/lynxpoint/Makefile.inc
  37. index b8503ac8bc..0e1f2fe4eb 100644
  38. --- a/src/southbridge/intel/lynxpoint/Makefile.inc
  39. +++ b/src/southbridge/intel/lynxpoint/Makefile.inc
  40. @@ -37,7 +37,7 @@ bootblock-y += early_pch.c
  41. romstage-y += early_usb.c early_me.c me_status.c early_pch.c
  42. romstage-y += pmutil.c
  43. -romstage-$(CONFIG_USE_NATIVE_RAMINIT) += early_pch_native.c
  44. +romstage-$(CONFIG_USE_NATIVE_RAMINIT) += early_pch_native.c early_usb_native.c iobp.c
  45. ifeq ($(CONFIG_INTEL_LYNXPOINT_LP),y)
  46. romstage-y += lp_gpio.c
  47. diff --git a/src/southbridge/intel/lynxpoint/early_usb.c b/src/southbridge/intel/lynxpoint/early_usb.c
  48. index a753681ce0..52e8ac17f8 100644
  49. --- a/src/southbridge/intel/lynxpoint/early_usb.c
  50. +++ b/src/southbridge/intel/lynxpoint/early_usb.c
  51. @@ -4,17 +4,6 @@
  52. #include <device/pci_def.h>
  53. #include "pch.h"
  54. -/* HCD_INDEX == 2 selects 0:1a.0 (PCH_EHCI2), any other index
  55. - * selects 0:1d.0 (PCH_EHCI1) for usbdebug use.
  56. - */
  57. -#if CONFIG_USBDEBUG_HCD_INDEX != 2
  58. -#define PCH_EHCI1_TEMP_BAR0 CONFIG_EHCI_BAR
  59. -#define PCH_EHCI2_TEMP_BAR0 (PCH_EHCI1_TEMP_BAR0 + 0x400)
  60. -#else
  61. -#define PCH_EHCI2_TEMP_BAR0 CONFIG_EHCI_BAR
  62. -#define PCH_EHCI1_TEMP_BAR0 (PCH_EHCI2_TEMP_BAR0 + 0x400)
  63. -#endif
  64. -
  65. /*
  66. * Setup USB controller MMIO BAR to prevent the
  67. * reference code from resetting the controller.
  68. diff --git a/src/southbridge/intel/lynxpoint/early_usb_native.c b/src/southbridge/intel/lynxpoint/early_usb_native.c
  69. new file mode 100644
  70. index 0000000000..cb6f6ee8e6
  71. --- /dev/null
  72. +++ b/src/southbridge/intel/lynxpoint/early_usb_native.c
  73. @@ -0,0 +1,584 @@
  74. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  75. +
  76. +#include <console/console.h>
  77. +#include <delay.h>
  78. +#include <device/mmio.h>
  79. +#include <device/pci_def.h>
  80. +#include <device/pci_ops.h>
  81. +#include <northbridge/intel/haswell/haswell.h>
  82. +#include <northbridge/intel/haswell/raminit.h>
  83. +#include <southbridge/intel/lynxpoint/iobp.h>
  84. +#include <southbridge/intel/lynxpoint/pch.h>
  85. +#include <timer.h>
  86. +#include <types.h>
  87. +
  88. +static unsigned int is_usbr_enabled(void)
  89. +{
  90. + return !!(pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) & BIT(5));
  91. +}
  92. +
  93. +static char *const xhci_bar = (char *)PCH_XHCI_TEMP_BAR0;
  94. +
  95. +static void ehci_hcs_init(const pci_devfn_t dev, const uintptr_t ehci_bar)
  96. +{
  97. + pci_write_config32(dev, PCI_BASE_ADDRESS_0, ehci_bar);
  98. +
  99. + /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
  100. + pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
  101. +
  102. + char *const mem_bar = (char *)ehci_bar;
  103. +
  104. + /**
  105. + * Shared EHCI/XHCI ports w/a.
  106. + * This step is required when some of the ports are routed to EHCI
  107. + * and other ports are routed XHCI at the same time.
  108. + *
  109. + * FIXME: Under which conditions should this be done?
  110. + */
  111. + pci_and_config16(dev, 0x78, ~0x03);
  112. +
  113. + /* Skip reset if usbdebug is enabled */
  114. + if (!CONFIG(USBDEBUG_IN_PRE_RAM))
  115. + setbits32(mem_bar + EHCI_USB_CMD, EHCI_USB_CMD_HCRESET);
  116. +
  117. + /* 2: Configure number of controllers and ports */
  118. + pci_or_config16(dev, EHCI_ACCESS_CNTL, ACCESS_CNTL_ENABLE);
  119. + clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 12, 0);
  120. + clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 0, 2 + is_usbr_enabled());
  121. + pci_and_config16(dev, EHCI_ACCESS_CNTL, ~ACCESS_CNTL_ENABLE);
  122. +
  123. + pci_or_config16(dev, 0x78, BIT(2));
  124. + pci_or_config16(dev, 0x7c, BIT(14) | BIT(7));
  125. + pci_update_config32(dev, 0x8c, ~(0xf << 8), (4 << 8));
  126. + pci_update_config32(dev, 0x8c, ~BIT(26), BIT(17));
  127. +}
  128. +
  129. +static inline unsigned int physical_port_count(void)
  130. +{
  131. + return MAX_USB2_PORTS;
  132. +}
  133. +
  134. +static unsigned int hs_port_count(void)
  135. +{
  136. + /** TODO: Apparently, WPT-LP has 10 USB2 ports **/
  137. + if (CONFIG(INTEL_LYNXPOINT_LP))
  138. + return 8;
  139. +
  140. + switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 1) & 3) {
  141. + case 3:
  142. + return 8;
  143. + case 2:
  144. + return 10;
  145. + case 1:
  146. + return 12;
  147. + case 0:
  148. + default:
  149. + return 14;
  150. + }
  151. +}
  152. +
  153. +static unsigned int ss_port_count(void)
  154. +{
  155. + if (CONFIG(INTEL_LYNXPOINT_LP))
  156. + return 4;
  157. +
  158. + switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 3) & 3) {
  159. + case 3:
  160. + return 0;
  161. + case 2:
  162. + return 2;
  163. + case 1:
  164. + return 4;
  165. + case 0:
  166. + default:
  167. + return 6;
  168. + }
  169. +}
  170. +
  171. +static void common_ehci_hcs_init(void)
  172. +{
  173. + const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
  174. +
  175. + ehci_hcs_init(PCH_EHCI1_DEV, PCH_EHCI1_TEMP_BAR0);
  176. + if (!is_lp)
  177. + ehci_hcs_init(PCH_EHCI2_DEV, PCH_EHCI2_TEMP_BAR0);
  178. +
  179. + pch_iobp_update(0xe5007f04, 0, 0x00004481);
  180. +
  181. + for (unsigned int port = 0; port < physical_port_count(); port++)
  182. + pch_iobp_update(0xe500400f + port * 0x100, ~(1 << 0), 0 << 0);
  183. +
  184. + pch_iobp_update(0xe5007f14, ~(3 << 19), (3 << 19));
  185. +
  186. + if (is_lp)
  187. + pch_iobp_update(0xe5007f02, ~(3 << 22), (0 << 22));
  188. +}
  189. +
  190. +static void xhci_open_memory_space(void)
  191. +{
  192. + /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
  193. + pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, (uintptr_t)xhci_bar);
  194. + pci_or_config16(PCH_XHCI_DEV, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
  195. +}
  196. +
  197. +static void xhci_close_memory_space(void)
  198. +{
  199. + pci_and_config16(PCH_XHCI_DEV, PCI_COMMAND, ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY));
  200. + pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, 0);
  201. +}
  202. +
  203. +static void common_xhci_hc_init(void)
  204. +{
  205. + const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
  206. +
  207. + if (!is_lp) {
  208. + const unsigned int max_ports = 15 + ss_port_count();
  209. + clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_1, 0xf << 28, max_ports << 28);
  210. + }
  211. +
  212. + clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_3, 0xffff << 16 | 0xff, 0x200 << 16 | 0x0a);
  213. + clrsetbits32(xhci_bar + XHCI_HCC_PARAMS, BIT(5), BIT(10) | BIT(9));
  214. +
  215. + if (!is_lp)
  216. + clrsetbits32(xhci_bar + 0x8008, BIT(19), 0);
  217. +
  218. + if (is_lp)
  219. + clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16));
  220. + else
  221. + clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16) | BIT(20));
  222. +
  223. + clrsetbits32(xhci_bar + 0x8060, 0, BIT(25) | BIT(18));
  224. + clrsetbits32(xhci_bar + 0x8090, 0, BIT(14) | BIT(8));
  225. + clrsetbits32(xhci_bar + 0x8094, 0, BIT(23) | BIT(21) | BIT(14));
  226. + clrsetbits32(xhci_bar + 0x80e0, BIT(16), BIT(6));
  227. + clrsetbits32(xhci_bar + 0x80ec, (7 << 12) | (7 << 9), (0 << 12) | (6 << 9));
  228. + clrsetbits32(xhci_bar + 0x80f0, BIT(20), 0);
  229. +
  230. + if (is_lp)
  231. + clrsetbits32(xhci_bar + 0x80fc, 0, BIT(25));
  232. +
  233. + if (is_lp)
  234. + clrsetbits32(xhci_bar + 0x8110, BIT(8) | BIT(2), BIT(20) | BIT(11));
  235. + else
  236. + clrsetbits32(xhci_bar + 0x8110, BIT(2), BIT(20) | BIT(11));
  237. +
  238. + if (is_lp)
  239. + write32(xhci_bar + 0x8140, 0xff00f03c);
  240. + else
  241. + write32(xhci_bar + 0x8140, 0xff03c132);
  242. +
  243. + if (is_lp)
  244. + clrsetbits32(xhci_bar + 0x8154, BIT(21), BIT(13));
  245. + else
  246. + clrsetbits32(xhci_bar + 0x8154, BIT(21) | BIT(13), 0);
  247. +
  248. + clrsetbits32(xhci_bar + 0x8154, BIT(3), 0);
  249. +
  250. + if (is_lp) {
  251. + clrsetbits32(xhci_bar + 0x8164, 0, BIT(1) | BIT(0));
  252. + write32(xhci_bar + 0x8174, 0x01400c0a);
  253. + write32(xhci_bar + 0x817c, 0x033200a3);
  254. + write32(xhci_bar + 0x8180, 0x00cb0028);
  255. + write32(xhci_bar + 0x8184, 0x0064001e);
  256. + }
  257. +
  258. + /*
  259. + * Note: Register at offset 0x44 is 32-bit, but bit 31 is write-once.
  260. + * We use these weird partial accesses here to avoid locking bit 31.
  261. + */
  262. + pci_or_config16(PCH_XHCI_DEV, 0x44, BIT(15) | BIT(14) | BIT(10) | BIT(0));
  263. + pci_or_config8(PCH_XHCI_DEV, 0x44 + 2, 0x0f);
  264. +
  265. + /* LPT-LP >= B0 */
  266. + if (is_lp)
  267. + clrsetbits32(xhci_bar + 0x8188, 0, BIT(26) | BIT(24));
  268. +
  269. + /* LPT-H >= C0 */
  270. + if (!is_lp)
  271. + clrsetbits32(xhci_bar + 0x8188, 0, BIT(24));
  272. +}
  273. +
  274. +static inline bool is_mem_sr(void)
  275. +{
  276. + return pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2) & GEN_PMCON_2_MEM_SR;
  277. +}
  278. +
  279. +static bool should_restore_xhci_smart_auto(void)
  280. +{
  281. + if (!is_mem_sr())
  282. + return false;
  283. +
  284. + return pci_read_config32(PCH_LPC_DEV, PMIR) & PMIR_XHCI_SMART_AUTO;
  285. +}
  286. +
  287. +enum usb_port_route {
  288. + ROUTE_TO_EHCI,
  289. + ROUTE_TO_XHCI,
  290. +};
  291. +
  292. +/* Returns whether port reset was successful */
  293. +static bool reset_usb2_ports(const unsigned int ehci_ports)
  294. +{
  295. + for (unsigned int port = 0; port < ehci_ports; port++) {
  296. + /* Initiate port reset for all USB2 ports */
  297. + clrsetbits32(
  298. + xhci_bar + XHCI_USB2_PORTSC(port),
  299. + XHCI_USB2_PORTSC_PED,
  300. + XHCI_USB2_PORTSC_PR);
  301. + }
  302. + /* Poll for port reset bit to be cleared or time out at 100ms */
  303. + struct stopwatch timer;
  304. + stopwatch_init_msecs_expire(&timer, 100);
  305. + uint32_t reg32;
  306. + do {
  307. + reg32 = 0;
  308. + for (unsigned int port = 0; port < ehci_ports; port++)
  309. + reg32 |= read32(xhci_bar + XHCI_USB2_PORTSC(port));
  310. +
  311. + reg32 &= XHCI_USB2_PORTSC_PR;
  312. + if (!reg32) {
  313. + const long elapsed_time = stopwatch_duration_usecs(&timer);
  314. + printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
  315. + return true;
  316. + }
  317. + /* Reference code has a 10 ms delay here, but a smaller delay works too */
  318. + udelay(100);
  319. + } while (!stopwatch_expired(&timer));
  320. + printk(BIOS_ERR, "%s: timed out\n", __func__);
  321. + return !reg32;
  322. +}
  323. +
  324. +/* Returns whether warm reset was successful */
  325. +static bool warm_reset_usb3_ports(const unsigned int xhci_ports)
  326. +{
  327. + for (unsigned int port = 0; port < xhci_ports; port++) {
  328. + /* Initiate warm reset for all USB3 ports */
  329. + clrsetbits32(
  330. + xhci_bar + XHCI_USB3_PORTSC(port),
  331. + XHCI_USB3_PORTSC_PED,
  332. + XHCI_USB3_PORTSC_WPR);
  333. + }
  334. + /* Poll for port reset bit to be cleared or time out at 100ms */
  335. + struct stopwatch timer;
  336. + stopwatch_init_msecs_expire(&timer, 100);
  337. + uint32_t reg32;
  338. + do {
  339. + reg32 = 0;
  340. + for (unsigned int port = 0; port < xhci_ports; port++)
  341. + reg32 |= read32(xhci_bar + XHCI_USB3_PORTSC(port));
  342. +
  343. + reg32 &= XHCI_USB3_PORTSC_PR;
  344. + if (!reg32) {
  345. + const long elapsed_time = stopwatch_duration_usecs(&timer);
  346. + printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
  347. + return true;
  348. + }
  349. + /* Reference code has a 10 ms delay here, but a smaller delay works too */
  350. + udelay(100);
  351. + } while (!stopwatch_expired(&timer));
  352. + printk(BIOS_ERR, "%s: timed out\n", __func__);
  353. + return !reg32;
  354. +}
  355. +
  356. +static void perform_xhci_ehci_switching_flow(const enum usb_port_route usb_route)
  357. +{
  358. + const pci_devfn_t dev = PCH_XHCI_DEV;
  359. +
  360. + const unsigned int ehci_ports = hs_port_count() + is_usbr_enabled();
  361. + const unsigned int xhci_ports = ss_port_count();
  362. +
  363. + const uint32_t ehci_mask = BIT(ehci_ports) - 1;
  364. + const uint32_t xhci_mask = BIT(xhci_ports) - 1;
  365. +
  366. + /** TODO: Handle USBr port? How, though? **/
  367. + pci_update_config32(dev, XHCI_USB2PRM, ~XHCI_USB2PR_HCSEL, ehci_mask);
  368. + pci_update_config32(dev, XHCI_USB3PRM, ~XHCI_USB3PR_SSEN, xhci_mask);
  369. +
  370. + /*
  371. + * Workaround for USB2PR / USB3PR value not surviving warm reset.
  372. + * Restore USB Port Routing registers if OS HC Switch driver has been executed.
  373. + */
  374. + if (should_restore_xhci_smart_auto()) {
  375. + /** FIXME: Derive values from mainboard code instead? **/
  376. + pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_mask);
  377. + pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_mask);
  378. + }
  379. +
  380. + /* Later stages shouldn't need the value of this bit */
  381. + pci_and_config32(PCH_LPC_DEV, PMIR, ~PMIR_XHCI_SMART_AUTO);
  382. +
  383. + /**
  384. + * FIXME: Things here depend on the chosen routing mode.
  385. + * For now, implement both functions.
  386. + */
  387. +
  388. + /* Route to EHCI if xHCI disabled or auto mode */
  389. + if (usb_route == ROUTE_TO_EHCI) {
  390. + if (!reset_usb2_ports(ehci_ports))
  391. + printk(BIOS_ERR, "USB2 port reset timed out\n");
  392. +
  393. + pci_and_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL);
  394. +
  395. + for (unsigned int port = 0; port < ehci_ports; port++) {
  396. + clrsetbits32(
  397. + xhci_bar + XHCI_USB2_PORTSC(port),
  398. + XHCI_USB2_PORTSC_PED,
  399. + XHCI_USB2_PORTSC_CHST);
  400. + }
  401. +
  402. + if (!warm_reset_usb3_ports(xhci_ports))
  403. + printk(BIOS_ERR, "USB3 warm reset timed out\n");
  404. +
  405. + /* FIXME: BWG says this should be inside the warm reset function */
  406. + pci_and_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN);
  407. +
  408. + for (unsigned int port = 0; port < ehci_ports; port++) {
  409. + clrsetbits32(
  410. + xhci_bar + XHCI_USB3_PORTSC(port),
  411. + XHCI_USB3_PORTSC_PED,
  412. + XHCI_USB3_PORTSC_CHST);
  413. + }
  414. +
  415. + setbits32(xhci_bar + XHCI_USBCMD, BIT(0));
  416. + clrbits32(xhci_bar + XHCI_USBCMD, BIT(0));
  417. + }
  418. +
  419. + /* Route to xHCI if xHCI enabled */
  420. + if (usb_route == ROUTE_TO_XHCI) {
  421. + if (is_mem_sr()) {
  422. + if (!warm_reset_usb3_ports(xhci_ports))
  423. + printk(BIOS_ERR, "USB3 warm reset timed out\n");
  424. + }
  425. +
  426. + const uint32_t xhci_port_mask = pci_read_config32(dev, XHCI_USB3PRM) & 0x3f;
  427. + pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_port_mask);
  428. +
  429. + const uint32_t ehci_port_mask = pci_read_config32(dev, XHCI_USB2PRM) & 0x7fff;
  430. + pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_port_mask);
  431. + }
  432. +}
  433. +
  434. +/* Do not shift in this macro, as it can cause undefined behaviour for bad port/oc values */
  435. +#define PORT_TO_OC_SHIFT(port, oc) ((oc) * 8 + (port))
  436. +
  437. +/* Avoid shifting into undefined behaviour */
  438. +static inline bool shift_ok(const int shift)
  439. +{
  440. + return shift >= 0 && shift < 32;
  441. +}
  442. +
  443. +static void usb_overcurrent_mapping(void)
  444. +{
  445. + const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
  446. +
  447. + uint32_t ehci_1_ocmap = 0;
  448. + uint32_t ehci_2_ocmap = 0;
  449. + uint32_t xhci_1_ocmap = 0;
  450. + uint32_t xhci_2_ocmap = 0;
  451. +
  452. + /*
  453. + * EHCI
  454. + */
  455. + for (unsigned int idx = 0; idx < physical_port_count(); idx++) {
  456. + const struct usb2_port_config *const port = &mainboard_usb2_ports[idx];
  457. + printk(BIOS_DEBUG, "USB2 port %u => ", idx);
  458. + if (!port->enable) {
  459. + printk(BIOS_DEBUG, "disabled\n");
  460. + continue;
  461. + }
  462. + const unsigned short oc_pin = port->oc_pin;
  463. + if (oc_pin == USB_OC_PIN_SKIP) {
  464. + printk(BIOS_DEBUG, "not mapped to OC pin\n");
  465. + continue;
  466. + }
  467. + /* Ports 0 .. 7 => OC 0 .. 3 */
  468. + if (idx < 8 && oc_pin <= 3) {
  469. + const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
  470. + if (shift_ok(shift)) {
  471. + printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
  472. + ehci_1_ocmap |= 1 << shift;
  473. + continue;
  474. + }
  475. + }
  476. + /* Ports 8 .. 13 => OC 4 .. 7 (LPT-H only) */
  477. + if (!is_lp && idx >= 8 && oc_pin >= 4) {
  478. + const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
  479. + if (shift_ok(shift)) {
  480. + printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
  481. + ehci_2_ocmap |= 1 << shift;
  482. + continue;
  483. + }
  484. + }
  485. + printk(BIOS_ERR, "Invalid OC pin %u for USB2 port %u\n", oc_pin, idx);
  486. + }
  487. + printk(BIOS_DEBUG, "\n");
  488. + pci_write_config32(PCH_EHCI1_DEV, EHCI_OCMAP, ehci_1_ocmap);
  489. + if (!is_lp)
  490. + pci_write_config32(PCH_EHCI2_DEV, EHCI_OCMAP, ehci_2_ocmap);
  491. +
  492. + /*
  493. + * xHCI
  494. + */
  495. + for (unsigned int idx = 0; idx < ss_port_count(); idx++) {
  496. + const struct usb3_port_config *const port = &mainboard_usb3_ports[idx];
  497. + printk(BIOS_DEBUG, "USB3 port %u => ", idx);
  498. + if (!port->enable) {
  499. + printk(BIOS_DEBUG, "disabled\n");
  500. + continue;
  501. + }
  502. + const unsigned short oc_pin = port->oc_pin;
  503. + if (oc_pin == USB_OC_PIN_SKIP) {
  504. + printk(BIOS_DEBUG, "not mapped to OC pin\n");
  505. + continue;
  506. + }
  507. + /* Ports 0 .. 5 => OC 0 .. 3 */
  508. + if (oc_pin <= 3) {
  509. + const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
  510. + if (shift_ok(shift)) {
  511. + printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
  512. + xhci_1_ocmap |= 1 << shift;
  513. + continue;
  514. + }
  515. + }
  516. + /* Ports 0 .. 5 => OC 4 .. 7 (LPT-H only) */
  517. + if (!is_lp && oc_pin >= 4) {
  518. + const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
  519. + if (shift_ok(shift)) {
  520. + printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
  521. + xhci_2_ocmap |= 1 << shift;
  522. + continue;
  523. + }
  524. + }
  525. + printk(BIOS_ERR, "Invalid OC pin %u for USB3 port %u\n", oc_pin, idx);
  526. + }
  527. + printk(BIOS_DEBUG, "\n");
  528. + pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM1, ehci_1_ocmap);
  529. + pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM1, xhci_1_ocmap);
  530. + if (!is_lp) {
  531. + pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM2, ehci_2_ocmap);
  532. + pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM2, xhci_2_ocmap);
  533. + }
  534. +}
  535. +
  536. +static uint8_t get_ehci_tune_param_1(const struct usb2_port_config *const port)
  537. +{
  538. + const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
  539. +
  540. + const enum pch_platform_type plat_type = get_pch_platform_type();
  541. + const enum usb2_port_location location = port->location;
  542. + const uint16_t length = port->length;
  543. + if (!is_lp) {
  544. + if (plat_type == PCH_TYPE_DESKTOP) {
  545. + if (location == USB_PORT_BACK_PANEL)
  546. + return 4; /* Back Panel */
  547. + else
  548. + return 3; /* Front Panel */
  549. +
  550. + } else if (plat_type == PCH_TYPE_MOBILE) {
  551. + if (location == USB_PORT_INTERNAL)
  552. + return 5; /* Internal Topology */
  553. + else if (location == USB_PORT_DOCK)
  554. + return 4; /* Dock */
  555. + else if (length < 0x70)
  556. + return 5; /* Back Panel, less than 7" */
  557. + else
  558. + return 6; /* Back Panel, 7" or more */
  559. + }
  560. + } else {
  561. + if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
  562. + if (length < 0x70)
  563. + return 5; /* Back Panel, less than 7" */
  564. + else
  565. + return 6; /* Back Panel, 7" or more */
  566. + } else if (location == USB_PORT_DOCK) {
  567. + return 4; /* Dock */
  568. + } else {
  569. + return 5; /* Internal Topology */
  570. + }
  571. + }
  572. + printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
  573. + return 0;
  574. +}
  575. +
  576. +static uint8_t get_ehci_tune_param_2(const struct usb2_port_config *const port)
  577. +{
  578. + const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
  579. +
  580. + const enum pch_platform_type plat_type = get_pch_platform_type();
  581. + const enum usb2_port_location location = port->location;
  582. + const uint16_t length = port->length;
  583. + if (!is_lp) {
  584. + if (plat_type == PCH_TYPE_DESKTOP) {
  585. + if (location == USB_PORT_BACK_PANEL) {
  586. + if (length < 0x80)
  587. + return 2; /* Back Panel, less than 8" */
  588. + else if (length < 0x130)
  589. + return 3; /* Back Panel, 8"-13" */
  590. + else
  591. + return 4; /* Back Panel, 13" or more */
  592. + } else {
  593. + return 2; /* Front Panel */
  594. + }
  595. +
  596. + } else if (plat_type == PCH_TYPE_MOBILE) {
  597. + if (location == USB_PORT_INTERNAL) {
  598. + return 2; /* Internal Topology */
  599. + } else if (location == USB_PORT_DOCK) {
  600. + if (length < 0x50)
  601. + return 1; /* Dock, less than 5" */
  602. + else
  603. + return 2; /* Dock, 5" or more */
  604. + } else {
  605. + if (length < 0x100)
  606. + return 2; /* Back Panel, less than 10" */
  607. + else
  608. + return 3; /* Back Panel, 10" or more */
  609. + }
  610. + }
  611. + } else {
  612. + if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
  613. + if (length < 0x100)
  614. + return 2; /* Back Panel, less than 10" */
  615. + else
  616. + return 3; /* Back Panel, 10" or more */
  617. + } else if (location == USB_PORT_DOCK) {
  618. + if (length < 0x50)
  619. + return 1; /* Dock, less than 5" */
  620. + else
  621. + return 2; /* Dock, 5" or more */
  622. + } else {
  623. + return 2; /* Internal Topology */
  624. + }
  625. + }
  626. + printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
  627. + return 0;
  628. +}
  629. +
  630. +static void program_ehci_port_length(void)
  631. +{
  632. + for (unsigned int port = 0; port < physical_port_count(); port++) {
  633. + if (!mainboard_usb2_ports[port].enable)
  634. + continue;
  635. + const uint32_t addr = 0xe5004000 + (port + 1) * 0x100;
  636. + const uint8_t param_1 = get_ehci_tune_param_1(&mainboard_usb2_ports[port]);
  637. + const uint8_t param_2 = get_ehci_tune_param_2(&mainboard_usb2_ports[port]);
  638. + pch_iobp_update(addr, ~0x7f00, param_2 << 11 | param_1 << 8);
  639. + }
  640. +}
  641. +
  642. +void early_usb_init(void)
  643. +{
  644. + /** TODO: Make this configurable? How do the modes affect usbdebug? **/
  645. + const enum usb_port_route usb_route = ROUTE_TO_XHCI;
  646. + ///(pd->boot_mode == 2 && pd->usb_xhci_on_resume) ? ROUTE_TO_XHCI : ROUTE_TO_EHCI;
  647. +
  648. + common_ehci_hcs_init();
  649. + xhci_open_memory_space();
  650. + common_xhci_hc_init();
  651. + perform_xhci_ehci_switching_flow(usb_route);
  652. + usb_overcurrent_mapping();
  653. + program_ehci_port_length();
  654. + /** FIXME: USB per port control is missing, is it needed? **/
  655. + xhci_close_memory_space();
  656. + /** TODO: Close EHCI memory space? **/
  657. +}
  658. diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h
  659. index b5e0c2a830..ad983d86cf 100644
  660. --- a/src/southbridge/intel/lynxpoint/pch.h
  661. +++ b/src/southbridge/intel/lynxpoint/pch.h
  662. @@ -115,6 +115,7 @@ enum pch_platform_type {
  663. void pch_dmi_setup_physical_layer(void);
  664. void pch_dmi_tc_vc_mapping(u32 vc0, u32 vc1, u32 vcp, u32 vcm);
  665. +void early_usb_init(void);
  666. void usb_ehci_sleep_prepare(pci_devfn_t dev, u8 slp_typ);
  667. void usb_ehci_disable(pci_devfn_t dev);
  668. @@ -202,6 +203,8 @@ void mainboard_config_rcba(void);
  669. #define GEN_PMCON_1 0xa0
  670. #define SMI_LOCK (1 << 4)
  671. #define GEN_PMCON_2 0xa2
  672. +#define GEN_PMCON_2_DISB (1 << 7)
  673. +#define GEN_PMCON_2_MEM_SR (1 << 5)
  674. #define SYSTEM_RESET_STS (1 << 4)
  675. #define THERMTRIP_STS (1 << 3)
  676. #define SYSPWR_FLR (1 << 1)
  677. @@ -215,6 +218,7 @@ void mainboard_config_rcba(void);
  678. #define PMIR 0xac
  679. #define PMIR_CF9LOCK (1 << 31)
  680. #define PMIR_CF9GR (1 << 20)
  681. +#define PMIR_XHCI_SMART_AUTO (1 << 16) /* c.f. LPT BWG or WPT-LP BIOS spec */
  682. /* GEN_PMCON_3 bits */
  683. #define RTC_BATTERY_DEAD (1 << 2)
  684. @@ -282,6 +286,20 @@ void mainboard_config_rcba(void);
  685. #define SATA_DTLE_DATA_SHIFT 24
  686. #define SATA_DTLE_EDGE_SHIFT 16
  687. +/*
  688. + * HCD_INDEX == 2 selects 0:1a.0 (PCH_EHCI2), any other index
  689. + * selects 0:1d.0 (PCH_EHCI1) for usbdebug use.
  690. + */
  691. +#if CONFIG_USBDEBUG_HCD_INDEX != 2
  692. +#define PCH_EHCI1_TEMP_BAR0 CONFIG_EHCI_BAR
  693. +#define PCH_EHCI2_TEMP_BAR0 (PCH_EHCI1_TEMP_BAR0 + 0x400)
  694. +#else
  695. +#define PCH_EHCI2_TEMP_BAR0 CONFIG_EHCI_BAR
  696. +#define PCH_EHCI1_TEMP_BAR0 (PCH_EHCI2_TEMP_BAR0 + 0x400)
  697. +#endif
  698. +
  699. +#define PCH_XHCI_TEMP_BAR0 0xe8100000
  700. +
  701. /* EHCI PCI Registers */
  702. #define EHCI_PWR_CTL_STS 0x54
  703. #define PWR_CTL_SET_MASK 0x3
  704. @@ -289,10 +307,15 @@ void mainboard_config_rcba(void);
  705. #define PWR_CTL_SET_D3 0x3
  706. #define PWR_CTL_ENABLE_PME (1 << 8)
  707. #define PWR_CTL_STATUS_PME (1 << 15)
  708. +#define EHCI_OCMAP 0x74
  709. +#define EHCI_ACCESS_CNTL 0x80
  710. +#define ACCESS_CNTL_ENABLE (1 << 0)
  711. /* EHCI Memory Registers */
  712. +#define EHCI_HCS_PARAMS 0x04
  713. #define EHCI_USB_CMD 0x20
  714. #define EHCI_USB_CMD_RUN (1 << 0)
  715. +#define EHCI_USB_CMD_HCRESET (1 << 1)
  716. #define EHCI_USB_CMD_PSE (1 << 4)
  717. #define EHCI_USB_CMD_ASE (1 << 5)
  718. #define EHCI_PORTSC(port) (0x64 + (port) * 4)
  719. @@ -301,6 +324,10 @@ void mainboard_config_rcba(void);
  720. /* XHCI PCI Registers */
  721. #define XHCI_PWR_CTL_STS 0x74
  722. +#define XHCI_U2OCM1 0xc0
  723. +#define XHCI_U2OCM2 0xc4
  724. +#define XHCI_U3OCM1 0xc8
  725. +#define XHCI_U3OCM2 0xcc
  726. #define XHCI_USB2PR 0xd0
  727. #define XHCI_USB2PRM 0xd4
  728. #define XHCI_USB2PR_HCSEL 0x7fff
  729. @@ -313,6 +340,27 @@ void mainboard_config_rcba(void);
  730. #define XHCI_USB3PDO 0xe8
  731. /* XHCI Memory Registers */
  732. +#define XHCI_HCS_PARAMS_1 0x04
  733. +#define XHCI_HCS_PARAMS_2 0x08
  734. +#define XHCI_HCS_PARAMS_3 0x0c
  735. +#define XHCI_HCC_PARAMS 0x10
  736. +#define XHCI_USBCMD 0x80
  737. +#define XHCI_USB2_PORTSC(port) (0x480 + ((port) * 0x10))
  738. +#define XHCI_USB2_PORTSC_WPR (1 << 31) /* Warm Port Reset */
  739. +#define XHCI_USB2_PORTSC_CEC (1 << 23) /* Port Config Error Change */
  740. +#define XHCI_USB2_PORTSC_PLC (1 << 22) /* Port Link State Change */
  741. +#define XHCI_USB2_PORTSC_PRC (1 << 21) /* Port Reset Change */
  742. +#define XHCI_USB2_PORTSC_OCC (1 << 20) /* Over-current Change */
  743. +#define XHCI_USB2_PORTSC_WRC (1 << 19) /* Warm Port Reset Change */
  744. +#define XHCI_USB2_PORTSC_PEC (1 << 18) /* Port Enabled Disabled Change */
  745. +#define XHCI_USB2_PORTSC_CSC (1 << 17) /* Connect Status Change */
  746. +#define XHCI_USB2_PORTSC_CHST (0x7f << 17)
  747. +#define XHCI_USB2_PORTSC_LWS (1 << 16) /* Port Link State Write Strobe */
  748. +#define XHCI_USB2_PORTSC_PP (1 << 9)
  749. +#define XHCI_USB2_PORTSC_PR (1 << 4) /* Port Reset */
  750. +#define XHCI_USB2_PORTSC_PED (1 << 1) /* Port Enable/Disabled */
  751. +#define XHCI_USB2_PORTSC_CCS (1 << 0) /* Current Connect Status */
  752. +
  753. #define XHCI_USB3_PORTSC(port) ((pch_is_lp() ? 0x510 : 0x570) + ((port) * 0x10))
  754. #define XHCI_USB3_PORTSC_CHST (0x7f << 17)
  755. #define XHCI_USB3_PORTSC_WCE (1 << 25) /* Wake on Connect */
  756. @@ -320,6 +368,7 @@ void mainboard_config_rcba(void);
  757. #define XHCI_USB3_PORTSC_WOE (1 << 27) /* Wake on Overcurrent */
  758. #define XHCI_USB3_PORTSC_WRC (1 << 19) /* Warm Reset Complete */
  759. #define XHCI_USB3_PORTSC_LWS (1 << 16) /* Link Write Strobe */
  760. +#define XHCI_USB3_PORTSC_PR (1 << 4) /* Port Reset */
  761. #define XHCI_USB3_PORTSC_PED (1 << 1) /* Port Enabled/Disabled */
  762. #define XHCI_USB3_PORTSC_WPR (1 << 31) /* Warm Port Reset */
  763. #define XHCI_USB3_PORTSC_PLS (0xf << 5) /* Port Link State */
  764. --
  765. 2.39.2