blob: cb6f6ee8e6d777f8cc28cf806b47faaa2b5c847f [file] [log] [blame]
Angel Pons70c61852022-05-06 23:17:39 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <console/console.h>
4#include <delay.h>
5#include <device/mmio.h>
6#include <device/pci_def.h>
7#include <device/pci_ops.h>
8#include <northbridge/intel/haswell/haswell.h>
9#include <northbridge/intel/haswell/raminit.h>
10#include <southbridge/intel/lynxpoint/iobp.h>
11#include <southbridge/intel/lynxpoint/pch.h>
12#include <timer.h>
13#include <types.h>
14
15static unsigned int is_usbr_enabled(void)
16{
17 return !!(pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) & BIT(5));
18}
19
20static char *const xhci_bar = (char *)PCH_XHCI_TEMP_BAR0;
21
22static void ehci_hcs_init(const pci_devfn_t dev, const uintptr_t ehci_bar)
23{
24 pci_write_config32(dev, PCI_BASE_ADDRESS_0, ehci_bar);
25
26 /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
27 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
28
29 char *const mem_bar = (char *)ehci_bar;
30
31 /**
32 * Shared EHCI/XHCI ports w/a.
33 * This step is required when some of the ports are routed to EHCI
34 * and other ports are routed XHCI at the same time.
35 *
36 * FIXME: Under which conditions should this be done?
37 */
38 pci_and_config16(dev, 0x78, ~0x03);
39
40 /* Skip reset if usbdebug is enabled */
41 if (!CONFIG(USBDEBUG_IN_PRE_RAM))
42 setbits32(mem_bar + EHCI_USB_CMD, EHCI_USB_CMD_HCRESET);
43
44 /* 2: Configure number of controllers and ports */
45 pci_or_config16(dev, EHCI_ACCESS_CNTL, ACCESS_CNTL_ENABLE);
46 clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 12, 0);
47 clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 0, 2 + is_usbr_enabled());
48 pci_and_config16(dev, EHCI_ACCESS_CNTL, ~ACCESS_CNTL_ENABLE);
49
50 pci_or_config16(dev, 0x78, BIT(2));
51 pci_or_config16(dev, 0x7c, BIT(14) | BIT(7));
52 pci_update_config32(dev, 0x8c, ~(0xf << 8), (4 << 8));
53 pci_update_config32(dev, 0x8c, ~BIT(26), BIT(17));
54}
55
56static inline unsigned int physical_port_count(void)
57{
58 return MAX_USB2_PORTS;
59}
60
61static unsigned int hs_port_count(void)
62{
63 /** TODO: Apparently, WPT-LP has 10 USB2 ports **/
64 if (CONFIG(INTEL_LYNXPOINT_LP))
65 return 8;
66
67 switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 1) & 3) {
68 case 3:
69 return 8;
70 case 2:
71 return 10;
72 case 1:
73 return 12;
74 case 0:
75 default:
76 return 14;
77 }
78}
79
80static unsigned int ss_port_count(void)
81{
82 if (CONFIG(INTEL_LYNXPOINT_LP))
83 return 4;
84
85 switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 3) & 3) {
86 case 3:
87 return 0;
88 case 2:
89 return 2;
90 case 1:
91 return 4;
92 case 0:
93 default:
94 return 6;
95 }
96}
97
98static void common_ehci_hcs_init(void)
99{
100 const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
101
102 ehci_hcs_init(PCH_EHCI1_DEV, PCH_EHCI1_TEMP_BAR0);
103 if (!is_lp)
104 ehci_hcs_init(PCH_EHCI2_DEV, PCH_EHCI2_TEMP_BAR0);
105
106 pch_iobp_update(0xe5007f04, 0, 0x00004481);
107
108 for (unsigned int port = 0; port < physical_port_count(); port++)
109 pch_iobp_update(0xe500400f + port * 0x100, ~(1 << 0), 0 << 0);
110
111 pch_iobp_update(0xe5007f14, ~(3 << 19), (3 << 19));
112
113 if (is_lp)
114 pch_iobp_update(0xe5007f02, ~(3 << 22), (0 << 22));
115}
116
117static void xhci_open_memory_space(void)
118{
119 /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
120 pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, (uintptr_t)xhci_bar);
121 pci_or_config16(PCH_XHCI_DEV, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
122}
123
124static void xhci_close_memory_space(void)
125{
126 pci_and_config16(PCH_XHCI_DEV, PCI_COMMAND, ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY));
127 pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, 0);
128}
129
130static void common_xhci_hc_init(void)
131{
132 const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
133
134 if (!is_lp) {
135 const unsigned int max_ports = 15 + ss_port_count();
136 clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_1, 0xf << 28, max_ports << 28);
137 }
138
139 clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_3, 0xffff << 16 | 0xff, 0x200 << 16 | 0x0a);
140 clrsetbits32(xhci_bar + XHCI_HCC_PARAMS, BIT(5), BIT(10) | BIT(9));
141
142 if (!is_lp)
143 clrsetbits32(xhci_bar + 0x8008, BIT(19), 0);
144
145 if (is_lp)
146 clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16));
147 else
148 clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16) | BIT(20));
149
150 clrsetbits32(xhci_bar + 0x8060, 0, BIT(25) | BIT(18));
151 clrsetbits32(xhci_bar + 0x8090, 0, BIT(14) | BIT(8));
152 clrsetbits32(xhci_bar + 0x8094, 0, BIT(23) | BIT(21) | BIT(14));
153 clrsetbits32(xhci_bar + 0x80e0, BIT(16), BIT(6));
154 clrsetbits32(xhci_bar + 0x80ec, (7 << 12) | (7 << 9), (0 << 12) | (6 << 9));
155 clrsetbits32(xhci_bar + 0x80f0, BIT(20), 0);
156
157 if (is_lp)
158 clrsetbits32(xhci_bar + 0x80fc, 0, BIT(25));
159
160 if (is_lp)
161 clrsetbits32(xhci_bar + 0x8110, BIT(8) | BIT(2), BIT(20) | BIT(11));
162 else
163 clrsetbits32(xhci_bar + 0x8110, BIT(2), BIT(20) | BIT(11));
164
165 if (is_lp)
166 write32(xhci_bar + 0x8140, 0xff00f03c);
167 else
168 write32(xhci_bar + 0x8140, 0xff03c132);
169
170 if (is_lp)
171 clrsetbits32(xhci_bar + 0x8154, BIT(21), BIT(13));
172 else
173 clrsetbits32(xhci_bar + 0x8154, BIT(21) | BIT(13), 0);
174
175 clrsetbits32(xhci_bar + 0x8154, BIT(3), 0);
176
177 if (is_lp) {
178 clrsetbits32(xhci_bar + 0x8164, 0, BIT(1) | BIT(0));
179 write32(xhci_bar + 0x8174, 0x01400c0a);
180 write32(xhci_bar + 0x817c, 0x033200a3);
181 write32(xhci_bar + 0x8180, 0x00cb0028);
182 write32(xhci_bar + 0x8184, 0x0064001e);
183 }
184
185 /*
186 * Note: Register at offset 0x44 is 32-bit, but bit 31 is write-once.
187 * We use these weird partial accesses here to avoid locking bit 31.
188 */
189 pci_or_config16(PCH_XHCI_DEV, 0x44, BIT(15) | BIT(14) | BIT(10) | BIT(0));
190 pci_or_config8(PCH_XHCI_DEV, 0x44 + 2, 0x0f);
191
192 /* LPT-LP >= B0 */
193 if (is_lp)
194 clrsetbits32(xhci_bar + 0x8188, 0, BIT(26) | BIT(24));
195
196 /* LPT-H >= C0 */
197 if (!is_lp)
198 clrsetbits32(xhci_bar + 0x8188, 0, BIT(24));
199}
200
201static inline bool is_mem_sr(void)
202{
203 return pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2) & GEN_PMCON_2_MEM_SR;
204}
205
206static bool should_restore_xhci_smart_auto(void)
207{
208 if (!is_mem_sr())
209 return false;
210
211 return pci_read_config32(PCH_LPC_DEV, PMIR) & PMIR_XHCI_SMART_AUTO;
212}
213
214enum usb_port_route {
215 ROUTE_TO_EHCI,
216 ROUTE_TO_XHCI,
217};
218
219/* Returns whether port reset was successful */
220static bool reset_usb2_ports(const unsigned int ehci_ports)
221{
222 for (unsigned int port = 0; port < ehci_ports; port++) {
223 /* Initiate port reset for all USB2 ports */
224 clrsetbits32(
225 xhci_bar + XHCI_USB2_PORTSC(port),
226 XHCI_USB2_PORTSC_PED,
227 XHCI_USB2_PORTSC_PR);
228 }
229 /* Poll for port reset bit to be cleared or time out at 100ms */
230 struct stopwatch timer;
231 stopwatch_init_msecs_expire(&timer, 100);
232 uint32_t reg32;
233 do {
234 reg32 = 0;
235 for (unsigned int port = 0; port < ehci_ports; port++)
236 reg32 |= read32(xhci_bar + XHCI_USB2_PORTSC(port));
237
238 reg32 &= XHCI_USB2_PORTSC_PR;
239 if (!reg32) {
240 const long elapsed_time = stopwatch_duration_usecs(&timer);
241 printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
242 return true;
243 }
244 /* Reference code has a 10 ms delay here, but a smaller delay works too */
245 udelay(100);
246 } while (!stopwatch_expired(&timer));
247 printk(BIOS_ERR, "%s: timed out\n", __func__);
248 return !reg32;
249}
250
251/* Returns whether warm reset was successful */
252static bool warm_reset_usb3_ports(const unsigned int xhci_ports)
253{
254 for (unsigned int port = 0; port < xhci_ports; port++) {
255 /* Initiate warm reset for all USB3 ports */
256 clrsetbits32(
257 xhci_bar + XHCI_USB3_PORTSC(port),
258 XHCI_USB3_PORTSC_PED,
259 XHCI_USB3_PORTSC_WPR);
260 }
261 /* Poll for port reset bit to be cleared or time out at 100ms */
262 struct stopwatch timer;
263 stopwatch_init_msecs_expire(&timer, 100);
264 uint32_t reg32;
265 do {
266 reg32 = 0;
267 for (unsigned int port = 0; port < xhci_ports; port++)
268 reg32 |= read32(xhci_bar + XHCI_USB3_PORTSC(port));
269
270 reg32 &= XHCI_USB3_PORTSC_PR;
271 if (!reg32) {
272 const long elapsed_time = stopwatch_duration_usecs(&timer);
273 printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
274 return true;
275 }
276 /* Reference code has a 10 ms delay here, but a smaller delay works too */
277 udelay(100);
278 } while (!stopwatch_expired(&timer));
279 printk(BIOS_ERR, "%s: timed out\n", __func__);
280 return !reg32;
281}
282
283static void perform_xhci_ehci_switching_flow(const enum usb_port_route usb_route)
284{
285 const pci_devfn_t dev = PCH_XHCI_DEV;
286
287 const unsigned int ehci_ports = hs_port_count() + is_usbr_enabled();
288 const unsigned int xhci_ports = ss_port_count();
289
290 const uint32_t ehci_mask = BIT(ehci_ports) - 1;
291 const uint32_t xhci_mask = BIT(xhci_ports) - 1;
292
293 /** TODO: Handle USBr port? How, though? **/
294 pci_update_config32(dev, XHCI_USB2PRM, ~XHCI_USB2PR_HCSEL, ehci_mask);
295 pci_update_config32(dev, XHCI_USB3PRM, ~XHCI_USB3PR_SSEN, xhci_mask);
296
297 /*
298 * Workaround for USB2PR / USB3PR value not surviving warm reset.
299 * Restore USB Port Routing registers if OS HC Switch driver has been executed.
300 */
301 if (should_restore_xhci_smart_auto()) {
302 /** FIXME: Derive values from mainboard code instead? **/
303 pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_mask);
304 pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_mask);
305 }
306
307 /* Later stages shouldn't need the value of this bit */
308 pci_and_config32(PCH_LPC_DEV, PMIR, ~PMIR_XHCI_SMART_AUTO);
309
310 /**
311 * FIXME: Things here depend on the chosen routing mode.
312 * For now, implement both functions.
313 */
314
315 /* Route to EHCI if xHCI disabled or auto mode */
316 if (usb_route == ROUTE_TO_EHCI) {
317 if (!reset_usb2_ports(ehci_ports))
318 printk(BIOS_ERR, "USB2 port reset timed out\n");
319
320 pci_and_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL);
321
322 for (unsigned int port = 0; port < ehci_ports; port++) {
323 clrsetbits32(
324 xhci_bar + XHCI_USB2_PORTSC(port),
325 XHCI_USB2_PORTSC_PED,
326 XHCI_USB2_PORTSC_CHST);
327 }
328
329 if (!warm_reset_usb3_ports(xhci_ports))
330 printk(BIOS_ERR, "USB3 warm reset timed out\n");
331
332 /* FIXME: BWG says this should be inside the warm reset function */
333 pci_and_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN);
334
335 for (unsigned int port = 0; port < ehci_ports; port++) {
336 clrsetbits32(
337 xhci_bar + XHCI_USB3_PORTSC(port),
338 XHCI_USB3_PORTSC_PED,
339 XHCI_USB3_PORTSC_CHST);
340 }
341
342 setbits32(xhci_bar + XHCI_USBCMD, BIT(0));
343 clrbits32(xhci_bar + XHCI_USBCMD, BIT(0));
344 }
345
346 /* Route to xHCI if xHCI enabled */
347 if (usb_route == ROUTE_TO_XHCI) {
348 if (is_mem_sr()) {
349 if (!warm_reset_usb3_ports(xhci_ports))
350 printk(BIOS_ERR, "USB3 warm reset timed out\n");
351 }
352
353 const uint32_t xhci_port_mask = pci_read_config32(dev, XHCI_USB3PRM) & 0x3f;
354 pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_port_mask);
355
356 const uint32_t ehci_port_mask = pci_read_config32(dev, XHCI_USB2PRM) & 0x7fff;
357 pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_port_mask);
358 }
359}
360
361/* Do not shift in this macro, as it can cause undefined behaviour for bad port/oc values */
362#define PORT_TO_OC_SHIFT(port, oc) ((oc) * 8 + (port))
363
364/* Avoid shifting into undefined behaviour */
365static inline bool shift_ok(const int shift)
366{
367 return shift >= 0 && shift < 32;
368}
369
370static void usb_overcurrent_mapping(void)
371{
372 const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
373
374 uint32_t ehci_1_ocmap = 0;
375 uint32_t ehci_2_ocmap = 0;
376 uint32_t xhci_1_ocmap = 0;
377 uint32_t xhci_2_ocmap = 0;
378
379 /*
380 * EHCI
381 */
382 for (unsigned int idx = 0; idx < physical_port_count(); idx++) {
383 const struct usb2_port_config *const port = &mainboard_usb2_ports[idx];
384 printk(BIOS_DEBUG, "USB2 port %u => ", idx);
385 if (!port->enable) {
386 printk(BIOS_DEBUG, "disabled\n");
387 continue;
388 }
389 const unsigned short oc_pin = port->oc_pin;
390 if (oc_pin == USB_OC_PIN_SKIP) {
391 printk(BIOS_DEBUG, "not mapped to OC pin\n");
392 continue;
393 }
394 /* Ports 0 .. 7 => OC 0 .. 3 */
395 if (idx < 8 && oc_pin <= 3) {
396 const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
397 if (shift_ok(shift)) {
398 printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
399 ehci_1_ocmap |= 1 << shift;
400 continue;
401 }
402 }
403 /* Ports 8 .. 13 => OC 4 .. 7 (LPT-H only) */
404 if (!is_lp && idx >= 8 && oc_pin >= 4) {
405 const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
406 if (shift_ok(shift)) {
407 printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
408 ehci_2_ocmap |= 1 << shift;
409 continue;
410 }
411 }
412 printk(BIOS_ERR, "Invalid OC pin %u for USB2 port %u\n", oc_pin, idx);
413 }
414 printk(BIOS_DEBUG, "\n");
415 pci_write_config32(PCH_EHCI1_DEV, EHCI_OCMAP, ehci_1_ocmap);
416 if (!is_lp)
417 pci_write_config32(PCH_EHCI2_DEV, EHCI_OCMAP, ehci_2_ocmap);
418
419 /*
420 * xHCI
421 */
422 for (unsigned int idx = 0; idx < ss_port_count(); idx++) {
423 const struct usb3_port_config *const port = &mainboard_usb3_ports[idx];
424 printk(BIOS_DEBUG, "USB3 port %u => ", idx);
425 if (!port->enable) {
426 printk(BIOS_DEBUG, "disabled\n");
427 continue;
428 }
429 const unsigned short oc_pin = port->oc_pin;
430 if (oc_pin == USB_OC_PIN_SKIP) {
431 printk(BIOS_DEBUG, "not mapped to OC pin\n");
432 continue;
433 }
434 /* Ports 0 .. 5 => OC 0 .. 3 */
435 if (oc_pin <= 3) {
436 const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
437 if (shift_ok(shift)) {
438 printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
439 xhci_1_ocmap |= 1 << shift;
440 continue;
441 }
442 }
443 /* Ports 0 .. 5 => OC 4 .. 7 (LPT-H only) */
444 if (!is_lp && oc_pin >= 4) {
445 const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
446 if (shift_ok(shift)) {
447 printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
448 xhci_2_ocmap |= 1 << shift;
449 continue;
450 }
451 }
452 printk(BIOS_ERR, "Invalid OC pin %u for USB3 port %u\n", oc_pin, idx);
453 }
454 printk(BIOS_DEBUG, "\n");
455 pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM1, ehci_1_ocmap);
456 pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM1, xhci_1_ocmap);
457 if (!is_lp) {
458 pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM2, ehci_2_ocmap);
459 pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM2, xhci_2_ocmap);
460 }
461}
462
463static uint8_t get_ehci_tune_param_1(const struct usb2_port_config *const port)
464{
465 const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
466
467 const enum pch_platform_type plat_type = get_pch_platform_type();
468 const enum usb2_port_location location = port->location;
469 const uint16_t length = port->length;
470 if (!is_lp) {
471 if (plat_type == PCH_TYPE_DESKTOP) {
472 if (location == USB_PORT_BACK_PANEL)
473 return 4; /* Back Panel */
474 else
475 return 3; /* Front Panel */
476
477 } else if (plat_type == PCH_TYPE_MOBILE) {
478 if (location == USB_PORT_INTERNAL)
479 return 5; /* Internal Topology */
480 else if (location == USB_PORT_DOCK)
481 return 4; /* Dock */
482 else if (length < 0x70)
483 return 5; /* Back Panel, less than 7" */
484 else
485 return 6; /* Back Panel, 7" or more */
486 }
487 } else {
488 if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
489 if (length < 0x70)
490 return 5; /* Back Panel, less than 7" */
491 else
492 return 6; /* Back Panel, 7" or more */
493 } else if (location == USB_PORT_DOCK) {
494 return 4; /* Dock */
495 } else {
496 return 5; /* Internal Topology */
497 }
498 }
499 printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
500 return 0;
501}
502
503static uint8_t get_ehci_tune_param_2(const struct usb2_port_config *const port)
504{
505 const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
506
507 const enum pch_platform_type plat_type = get_pch_platform_type();
508 const enum usb2_port_location location = port->location;
509 const uint16_t length = port->length;
510 if (!is_lp) {
511 if (plat_type == PCH_TYPE_DESKTOP) {
512 if (location == USB_PORT_BACK_PANEL) {
513 if (length < 0x80)
514 return 2; /* Back Panel, less than 8" */
515 else if (length < 0x130)
516 return 3; /* Back Panel, 8"-13" */
517 else
518 return 4; /* Back Panel, 13" or more */
519 } else {
520 return 2; /* Front Panel */
521 }
522
523 } else if (plat_type == PCH_TYPE_MOBILE) {
524 if (location == USB_PORT_INTERNAL) {
525 return 2; /* Internal Topology */
526 } else if (location == USB_PORT_DOCK) {
527 if (length < 0x50)
528 return 1; /* Dock, less than 5" */
529 else
530 return 2; /* Dock, 5" or more */
531 } else {
532 if (length < 0x100)
533 return 2; /* Back Panel, less than 10" */
534 else
535 return 3; /* Back Panel, 10" or more */
536 }
537 }
538 } else {
539 if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
540 if (length < 0x100)
541 return 2; /* Back Panel, less than 10" */
542 else
543 return 3; /* Back Panel, 10" or more */
544 } else if (location == USB_PORT_DOCK) {
545 if (length < 0x50)
546 return 1; /* Dock, less than 5" */
547 else
548 return 2; /* Dock, 5" or more */
549 } else {
550 return 2; /* Internal Topology */
551 }
552 }
553 printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
554 return 0;
555}
556
557static void program_ehci_port_length(void)
558{
559 for (unsigned int port = 0; port < physical_port_count(); port++) {
560 if (!mainboard_usb2_ports[port].enable)
561 continue;
562 const uint32_t addr = 0xe5004000 + (port + 1) * 0x100;
563 const uint8_t param_1 = get_ehci_tune_param_1(&mainboard_usb2_ports[port]);
564 const uint8_t param_2 = get_ehci_tune_param_2(&mainboard_usb2_ports[port]);
565 pch_iobp_update(addr, ~0x7f00, param_2 << 11 | param_1 << 8);
566 }
567}
568
569void early_usb_init(void)
570{
571 /** TODO: Make this configurable? How do the modes affect usbdebug? **/
572 const enum usb_port_route usb_route = ROUTE_TO_XHCI;
573 ///(pd->boot_mode == 2 && pd->usb_xhci_on_resume) ? ROUTE_TO_XHCI : ROUTE_TO_EHCI;
574
575 common_ehci_hcs_init();
576 xhci_open_memory_space();
577 common_xhci_hc_init();
578 perform_xhci_ehci_switching_flow(usb_route);
579 usb_overcurrent_mapping();
580 program_ehci_port_length();
581 /** FIXME: USB per port control is missing, is it needed? **/
582 xhci_close_memory_space();
583 /** TODO: Close EHCI memory space? **/
584}