xref: /aosp_15_r20/external/coreboot/src/southbridge/intel/bd82x6x/early_usb_mrc.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/pci_ops.h>
4 #include <device/pci_def.h>
5 #include "pch.h"
6 #include "chip.h"
7 #include <northbridge/intel/sandybridge/pei_data.h>
8 
9 #define PCH_EHCI1_TEMP_BAR0 0xe8000000
10 #define PCH_EHCI2_TEMP_BAR0 0xe8000400
11 
12 /*
13  * Setup USB controller MMIO BAR to prevent the
14  * reference code from resetting the controller.
15  *
16  * The BAR will be re-assigned during device
17  * enumeration so these are only temporary.
18  */
enable_usb_bar(void)19 void enable_usb_bar(void)
20 {
21 	pci_devfn_t usb0 = PCH_EHCI1_DEV;
22 	pci_devfn_t usb1 = PCH_EHCI2_DEV;
23 
24 	/* USB Controller 1 */
25 	pci_write_config32(usb0, PCI_BASE_ADDRESS_0,
26 			   PCH_EHCI1_TEMP_BAR0);
27 	pci_or_config16(usb0, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
28 
29 	/* USB Controller 2 */
30 	pci_write_config32(usb1, PCI_BASE_ADDRESS_0,
31 			   PCH_EHCI2_TEMP_BAR0);
32 	pci_or_config16(usb1, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
33 }
34 
35 /*
36  * Translate coreboot native USB port configuration in devicetree
37  * into a format reference code expects:
38  *
39  * [MRC index] = .native_field // what for
40  *         [0] = .enabled // enable
41  *         [1] = .oc_pin // overcurrent pin
42  *         [2] = .current // length
43  *
44  * For .current, use these native values for MRC settings 1-3, corresponding
45  * to values of 0x40/0x80/0x130, which should produce the correct values
46  * across all supported PCHs.
47  *
48  * PCH type    | 1 | 2 | 3
49  * ------------+---+---+---
50  * Mobile      | 0 | 1 | 2
51  * Desktop x6x | 6 | 1 | 7
52  * Desktop x7x | 8 | 9 | 2
53  *
54  * See also:
55  * northbridge/intel/sandybridge/pei_data.h
56  * pch.h
57  * early_usb.c
58  */
southbridge_fill_pei_data(struct pei_data * pei_data)59 void southbridge_fill_pei_data(struct pei_data *pei_data)
60 {
61 	const struct device *dev = pcidev_on_root(0x1d, 0);
62 	const struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
63 	/* Native current -> MRC length map to get the same USBIRx register value */
64 	const uint16_t currents[] = { 0x40, 0x80, 0x130,
65 				      0, 0, 0, /* 3-5 not seen in MRC */
66 				      0x40, 0x130, 0x40, 0x80};
67 	for (unsigned int port = 0; port < ARRAY_SIZE(config->usb_port_config); port++) {
68 		uint16_t current = 0;
69 		int ocp = config->usb_port_config[port].oc_pin;
70 		if (ocp == -1)
71 			ocp = (port < 8) ? 0 : 4;
72 
73 		if (config->usb_port_config[port].current < ARRAY_SIZE(currents))
74 			current = currents[config->usb_port_config[port].current];
75 
76 		/*
77 		 * Note for developers: If this message shows, your board uses a
78 		 * current setting MRC.bin cannot produce. Choose a value as close
79 		 * as possible and test all USB ports, or consider using native raminit.
80 		 */
81 		if (current == 0) {
82 			printk(BIOS_NOTICE,
83 			       "%s: USB%02d: %d is an invalid setting for MRC.bin!\n",
84 			       __func__, port, config->usb_port_config[port].current);
85 		}
86 
87 		pei_data->usb_port_config[port][0] = config->usb_port_config[port].enabled;
88 		pei_data->usb_port_config[port][1] = ocp;
89 		pei_data->usb_port_config[port][2] = current;
90 	}
91 
92 	pei_data->usb3.hs_port_switch_mask = config->xhci_switchable_ports;
93 }
94