xref: /aosp_15_r20/external/coreboot/payloads/libpayload/drivers/usb/usbinit.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008-2010 coresystems GmbH
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 //#define USB_DEBUG
30 #include <libpayload-config.h>
31 #include <usb/usb.h>
32 #include "uhci.h"
33 #include "ohci.h"
34 #include "ehci.h"
35 #include "xhci.h"
36 #include "dwc2.h"
37 #include <usb/usbdisk.h>
38 
39 #if CONFIG(LP_USB_PCI)
40 /**
41  * Initializes USB controller attached to PCI
42  *
43  * @param bus PCI bus number
44  * @param dev PCI device id at bus
45  * @param func function id of the controller
46  */
usb_controller_initialize(int bus,int dev,int func)47 static int usb_controller_initialize(int bus, int dev, int func)
48 {
49 	u32 class;
50 	u32 devclass;
51 	u32 prog_if;
52 	pcidev_t pci_device;
53 	u32 pciid;
54 
55 	pci_device = PCI_DEV(bus, dev, func);
56 	class = pci_read_config32(pci_device, 8);
57 	pciid = pci_read_config32(pci_device, 0);
58 
59 	devclass = class >> 16;
60 	prog_if = (class >> 8) & 0xff;
61 
62 	/* enable busmaster */
63 	if (devclass == 0xc03) {
64 		u16 pci_command;
65 
66 		pci_command = pci_read_config16(pci_device, PCI_COMMAND);
67 		pci_command |= PCI_COMMAND_MASTER;
68 		pci_write_config16(pci_device, PCI_COMMAND, pci_command);
69 
70 		usb_debug("%02x:%02x.%x %04x:%04x.%d ", bus, dev, func,
71 			pciid >> 16, pciid & 0xFFFF, func);
72 		switch (prog_if) {
73 		case 0x00:
74 #if CONFIG(LP_USB_UHCI)
75 			usb_debug("UHCI controller\n");
76 			uhci_pci_init(pci_device);
77 #else
78 			usb_debug("UHCI controller (not supported)\n");
79 #endif
80 			break;
81 
82 		case 0x10:
83 #if CONFIG(LP_USB_OHCI)
84 			usb_debug("OHCI controller\n");
85 			ohci_pci_init(pci_device);
86 #else
87 			usb_debug("OHCI controller (not supported)\n");
88 #endif
89 			break;
90 
91 		case 0x20:
92 #if CONFIG(LP_USB_EHCI)
93 			usb_debug("EHCI controller\n");
94 			ehci_pci_init(pci_device);
95 #else
96 			usb_debug("EHCI controller (not supported)\n");
97 #endif
98 			break;
99 
100 		case 0x30:
101 #if CONFIG(LP_USB_XHCI)
102 			usb_debug("xHCI controller\n");
103 			xhci_pci_init(pci_device);
104 #else
105 			usb_debug("xHCI controller (not supported)\n");
106 #endif
107 			break;
108 
109 		default:
110 			usb_debug("unknown controller %x not supported\n",
111 			       prog_if);
112 			break;
113 		}
114 	}
115 
116 	return 0;
117 }
118 
usb_scan_pci_bus(int bus)119 static void usb_scan_pci_bus(int bus)
120 {
121 	int dev, func;
122 	for (dev = 0; dev < 32; dev++) {
123 		u8 header_type;
124 		pcidev_t pci_device = PCI_DEV(bus, dev, 0);
125 
126 		/* Check if there's a device here at all. */
127 		if (pci_read_config32(pci_device, REG_VENDOR_ID) == 0xffffffff)
128 			continue;
129 
130 		/*
131 		 * EHCI is defined by standards to be at a higher function
132 		 * than the USB1 controllers. We don't want to init USB1 +
133 		 * devices just to "steal" those for USB2, so make sure USB2
134 		 * comes first by scanning multifunction devices from 7 to 0.
135 		 */
136 
137 		/* Check for a multifunction device. */
138 		header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
139 		if (header_type & HEADER_TYPE_MULTIFUNCTION)
140 			func = 7;
141 		else
142 			func = 0;
143 
144 		for (; func >= 0; func--) {
145 			pci_device = PCI_DEV(bus, dev, func);
146 			header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
147 			/* If this is a bridge, scan the other side. */
148 			if ((header_type & ~HEADER_TYPE_MULTIFUNCTION) ==
149 					HEADER_TYPE_BRIDGE) {
150 				/* Verify that the bridge is enabled */
151 				if ((pci_read_config16(pci_device, REG_COMMAND)
152 						& 3) != 0)
153 					usb_scan_pci_bus(pci_read_config8(
154 						pci_device, REG_SECONDARY_BUS));
155 			}
156 			else
157 				usb_controller_initialize(bus, dev, func);
158 		}
159 	}
160 }
161 #endif
162 
163 /**
164  * Initialize all USB controllers attached to PCI.
165  */
usb_initialize(void)166 int usb_initialize(void)
167 {
168 #if CONFIG(LP_USB_PCI)
169 	usb_scan_pci_bus(0);
170 #endif
171 	return 0;
172 }
173 
usb_add_mmio_hc(hc_type type,void * bar)174 hci_t *usb_add_mmio_hc(hc_type type, void *bar)
175 {
176 	switch (type) {
177 #if CONFIG(LP_USB_OHCI)
178 	case OHCI:
179 		return ohci_init((unsigned long)bar);
180 #endif
181 #if CONFIG(LP_USB_EHCI)
182 	case EHCI:
183 		return ehci_init((unsigned long)bar);
184 #endif
185 #if CONFIG(LP_USB_DWC2)
186 	case DWC2:
187 		return dwc2_init(bar);
188 #endif
189 #if CONFIG(LP_USB_XHCI)
190 	case XHCI:
191 		return xhci_init((unsigned long)bar);
192 #endif
193 	default:
194 		usb_debug("HC type %d (at %p) is not supported!\n", type, bar);
195 		return NULL;
196 	}
197 }
198