blob: 721fde8a930bea63af7f45e9644b2deacc23cfe5 [file] [log] [blame]
Patrick Georgid21f68b2008-09-02 16:06:22 +00001/*
2 * This file is part of the libpayload project.
3 *
Stefan Reinauerb56f2d02010-03-25 22:17:36 +00004 * Copyright (C) 2008-2010 coresystems GmbH
Patrick Georgid21f68b2008-09-02 16:06:22 +00005 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Stefan Reinauer8992e532013-05-02 16:16:41 -070030//#define USB_DEBUG
Jordan Crousedb8c0ab2008-11-24 17:54:46 +000031#include <libpayload-config.h>
Jordan Crouse29061a52008-09-11 17:29:00 +000032#include <usb/usb.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000033#include "uhci.h"
Patrick Georgi6615ef32010-08-13 09:18:58 +000034#include "ohci.h"
Patrick Georgi7f43dc12010-09-25 17:01:13 +000035#include "ehci.h"
Patrick Georgi6615ef32010-08-13 09:18:58 +000036#include "xhci.h"
huang lin365250e2014-08-06 16:43:43 +080037#include "dwc2.h"
Jordan Crouse29061a52008-09-11 17:29:00 +000038#include <usb/usbdisk.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000039
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070040#if IS_ENABLED(CONFIG_LP_USB_PCI)
Patrick Georgid21f68b2008-09-02 16:06:22 +000041/**
42 * Initializes USB controller attached to PCI
43 *
44 * @param bus PCI bus number
45 * @param dev PCI device id at bus
46 * @param func function id of the controller
47 */
Nico Huberba22e4c2012-11-23 11:34:20 +010048static int usb_controller_initialize(int bus, int dev, int func)
Patrick Georgid21f68b2008-09-02 16:06:22 +000049{
50 u32 class;
51 u32 devclass;
52 u32 prog_if;
Gabe Black9e8af582012-11-08 19:31:23 -080053 pcidev_t pci_device;
Patrick Georgid21f68b2008-09-02 16:06:22 +000054 u32 pciid;
55
Gabe Black9e8af582012-11-08 19:31:23 -080056 pci_device = PCI_DEV (bus, dev, func);
57 class = pci_read_config32(pci_device, 8);
58 pciid = pci_read_config32(pci_device, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +000059
60 devclass = class >> 16;
61 prog_if = (class >> 8) & 0xff;
62
63 /* enable busmaster */
Patrick Georgid21f68b2008-09-02 16:06:22 +000064 if (devclass == 0xc03) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000065 u32 pci_command;
66
Gabe Black9e8af582012-11-08 19:31:23 -080067 pci_command = pci_read_config32(pci_device, PCI_COMMAND);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000068 pci_command |= PCI_COMMAND_MASTER;
Gabe Black9e8af582012-11-08 19:31:23 -080069 pci_write_config32(pci_device, PCI_COMMAND, pci_command);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000070
Dave Frodin6bf11cf2012-12-11 13:08:07 -070071 usb_debug("%02x:%02x.%x %04x:%04x.%d ", bus, dev, func,
Patrick Georgid21f68b2008-09-02 16:06:22 +000072 pciid >> 16, pciid & 0xFFFF, func);
Gabe Black1b33c312012-10-08 01:58:37 -070073 switch (prog_if) {
74 case 0x00:
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070075#if IS_ENABLED(CONFIG_LP_USB_UHCI)
Dave Frodin6bf11cf2012-12-11 13:08:07 -070076 usb_debug("UHCI controller\n");
Stefan Reinauer8992e532013-05-02 16:16:41 -070077 uhci_pci_init (pci_device);
Patrick Georgid21f68b2008-09-02 16:06:22 +000078#else
Dave Frodin6bf11cf2012-12-11 13:08:07 -070079 usb_debug("UHCI controller (not supported)\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +000080#endif
Gabe Black1b33c312012-10-08 01:58:37 -070081 break;
Steven A. Falco25f23f12011-07-13 21:59:31 -040082
Gabe Black1b33c312012-10-08 01:58:37 -070083 case 0x10:
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070084#if IS_ENABLED(CONFIG_LP_USB_OHCI)
Dave Frodin6bf11cf2012-12-11 13:08:07 -070085 usb_debug("OHCI controller\n");
Stefan Reinauer8992e532013-05-02 16:16:41 -070086 ohci_pci_init(pci_device);
Patrick Georgid21f68b2008-09-02 16:06:22 +000087#else
Dave Frodin6bf11cf2012-12-11 13:08:07 -070088 usb_debug("OHCI controller (not supported)\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +000089#endif
Gabe Black1b33c312012-10-08 01:58:37 -070090 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +000091
Gabe Black1b33c312012-10-08 01:58:37 -070092 case 0x20:
Stefan Reinauer1b4d3942015-06-29 15:47:34 -070093#if IS_ENABLED(CONFIG_LP_USB_EHCI)
Dave Frodin6bf11cf2012-12-11 13:08:07 -070094 usb_debug("EHCI controller\n");
Stefan Reinauer8992e532013-05-02 16:16:41 -070095 ehci_pci_init(pci_device);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000096#else
Dave Frodin6bf11cf2012-12-11 13:08:07 -070097 usb_debug("EHCI controller (not supported)\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000098#endif
Gabe Black1b33c312012-10-08 01:58:37 -070099 break;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000100
Gabe Black1b33c312012-10-08 01:58:37 -0700101 case 0x30:
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700102#if IS_ENABLED(CONFIG_LP_USB_XHCI)
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700103 usb_debug("xHCI controller\n");
Stefan Reinauer8992e532013-05-02 16:16:41 -0700104 xhci_pci_init(pci_device);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000105#else
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700106 usb_debug("xHCI controller (not supported)\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000107#endif
Gabe Black1b33c312012-10-08 01:58:37 -0700108 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000109
Gabe Black1b33c312012-10-08 01:58:37 -0700110 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700111 usb_debug("unknown controller %x not supported\n",
Gabe Black1b33c312012-10-08 01:58:37 -0700112 prog_if);
113 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000114 }
115 }
116
117 return 0;
118}
119
Gabe Black1b33c312012-10-08 01:58:37 -0700120static void usb_scan_pci_bus(int bus)
121{
122 int dev, func;
123 for (dev = 0; dev < 32; dev++) {
124 u8 header_type;
Gabe Black9e8af582012-11-08 19:31:23 -0800125 pcidev_t pci_device = PCI_DEV(bus, dev, 0);
126
Gabe Black1b33c312012-10-08 01:58:37 -0700127 /* Check if there's a device here at all. */
Gabe Black9e8af582012-11-08 19:31:23 -0800128 if (pci_read_config32(pci_device, REG_VENDOR_ID) == 0xffffffff)
Gabe Black1b33c312012-10-08 01:58:37 -0700129 continue;
Gabe Black9e8af582012-11-08 19:31:23 -0800130
Gabe Black1b33c312012-10-08 01:58:37 -0700131 /*
132 * EHCI is defined by standards to be at a higher function
133 * than the USB1 controllers. We don't want to init USB1 +
134 * devices just to "steal" those for USB2, so make sure USB2
Gabe Black9e8af582012-11-08 19:31:23 -0800135 * comes first by scanning multifunction devices from 7 to 0.
Gabe Black1b33c312012-10-08 01:58:37 -0700136 */
Gabe Black9e8af582012-11-08 19:31:23 -0800137
Gabe Black1b33c312012-10-08 01:58:37 -0700138 /* Check for a multifunction device. */
Gabe Black9e8af582012-11-08 19:31:23 -0800139 header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
Gabe Black1b33c312012-10-08 01:58:37 -0700140 if (header_type & HEADER_TYPE_MULTIFUNCTION)
Gabe Black9e8af582012-11-08 19:31:23 -0800141 func = 7;
142 else
143 func = 0;
144
145 for (; func >= 0; func--) {
146 pci_device = PCI_DEV(bus, dev, func);
147 header_type = pci_read_config8(pci_device, REG_HEADER_TYPE);
148 /* If this is a bridge, scan the other side. */
149 if ((header_type & ~HEADER_TYPE_MULTIFUNCTION) ==
Lee Leahye32b6e72014-12-17 13:05:26 -0800150 HEADER_TYPE_BRIDGE) {
151 /* Verify that the bridge is enabled */
152 if ((pci_read_config16(pci_device, REG_COMMAND)
153 & 3) != 0)
154 usb_scan_pci_bus(pci_read_config8(
155 pci_device, REG_SECONDARY_BUS));
156 }
Gabe Black9e8af582012-11-08 19:31:23 -0800157 else
Gabe Black1b33c312012-10-08 01:58:37 -0700158 usb_controller_initialize(bus, dev, func);
Gabe Black9e8af582012-11-08 19:31:23 -0800159 }
Gabe Black1b33c312012-10-08 01:58:37 -0700160 }
161}
Stefan Reinauer8992e532013-05-02 16:16:41 -0700162#endif
163
Patrick Georgid21f68b2008-09-02 16:06:22 +0000164/**
165 * Initialize all USB controllers attached to PCI.
166 */
Gabe Black1b33c312012-10-08 01:58:37 -0700167int usb_initialize(void)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000168{
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700169#if IS_ENABLED(CONFIG_LP_USB_PCI)
Gabe Black1b33c312012-10-08 01:58:37 -0700170 usb_scan_pci_bus(0);
Stefan Reinauer8992e532013-05-02 16:16:41 -0700171#endif
Patrick Georgid21f68b2008-09-02 16:06:22 +0000172 return 0;
173}
Julius Wernerd7c25b32013-09-04 17:20:32 -0700174
175hci_t *usb_add_mmio_hc(hc_type type, void *bar)
176{
177 switch (type) {
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700178#if IS_ENABLED(CONFIG_LP_USB_OHCI)
Julius Wernerd7c25b32013-09-04 17:20:32 -0700179 case OHCI:
Marc Jones86127c72014-12-29 22:07:04 -0700180 return ohci_init((unsigned long)bar);
Julius Wernerd7c25b32013-09-04 17:20:32 -0700181#endif
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700182#if IS_ENABLED(CONFIG_LP_USB_EHCI)
Julius Wernerd7c25b32013-09-04 17:20:32 -0700183 case EHCI:
Marc Jones86127c72014-12-29 22:07:04 -0700184 return ehci_init((unsigned long)bar);
Julius Wernerd7c25b32013-09-04 17:20:32 -0700185#endif
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700186#if IS_ENABLED(CONFIG_LP_USB_DWC2)
huang lin365250e2014-08-06 16:43:43 +0800187 case DWC2:
188 return dwc2_init(bar);
189#endif
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700190#if IS_ENABLED(CONFIG_LP_USB_XHCI)
Julius Wernerd7c25b32013-09-04 17:20:32 -0700191 case XHCI:
Marc Jones86127c72014-12-29 22:07:04 -0700192 return xhci_init((unsigned long)bar);
Julius Wernerd7c25b32013-09-04 17:20:32 -0700193#endif
194 default:
195 usb_debug("HC type %d (at %p) is not supported!\n", type, bar);
196 return NULL;
197 }
198}