diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/Kconfig | 56 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-rmobile.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sunxi.c | 80 | ||||
-rw-r--r-- | drivers/usb/host/ehci-uniphier.c | 39 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 4 |
6 files changed, 156 insertions, 32 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig new file mode 100644 index 0000000000..30d1457638 --- /dev/null +++ b/drivers/usb/host/Kconfig @@ -0,0 +1,56 @@ +# +# USB Host Controller Drivers +# +comment "USB Host Controller Drivers" + +config USB_XHCI_HCD + bool "xHCI HCD (USB 3.0) support" + ---help--- + The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 + "SuperSpeed" host controller hardware. + +config USB_XHCI + bool + default USB_XHCI_HCD + ---help--- + TODO: rename after most boards switch to Kconfig + +if USB_XHCI_HCD + +endif + +config USB_EHCI_HCD + bool "EHCI HCD (USB 2.0) support" + ---help--- + The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 + "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. + If your USB host controller supports USB 2.0, you will likely want to + configure this Host Controller Driver. + + EHCI controllers are packaged with "companion" host controllers (OHCI + or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports + will connect to EHCI if the device is high speed, otherwise they + connect to a companion controller. If you configure EHCI, you should + probably configure the OHCI (for NEC and some other vendors) USB Host + Controller Driver or UHCI (for Via motherboards) Host Controller + Driver too. + + You may want to read <file:Documentation/usb/ehci.txt>. + +config USB_EHCI + bool + default USB_EHCI_HCD + ---help--- + TODO: rename after most boards switch to Kconfig + +if USB_EHCI_HCD + +config USB_EHCI_UNIPHIER + bool "Support for Panasonic UniPhier on-chip EHCI USB controller" + depends on ARCH_UNIPHIER + default y + ---help--- + Enables support for the on-chip EHCI controller on Panasonic + UniPhier SoCs. + +endif diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 1c3592914d..c11b551620 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o +obj-$(CONFIG_USB_EHCI_UNIPHIER) += ehci-uniphier.o obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o diff --git a/drivers/usb/host/ehci-rmobile.c b/drivers/usb/host/ehci-rmobile.c index b4330876f8..7fe79efc17 100644 --- a/drivers/usb/host/ehci-rmobile.c +++ b/drivers/usb/host/ehci-rmobile.c @@ -13,18 +13,18 @@ #include "ehci.h" #if defined(CONFIG_R8A7740) -static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = { +static u32 usb_base_address[] = { 0xC6700000 }; #elif defined(CONFIG_R8A7790) -static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = { +static u32 usb_base_address[] = { 0xEE080000, /* USB0 (EHCI) */ 0xEE0A0000, /* USB1 */ 0xEE0C0000, /* USB2 */ }; #elif defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \ defined(CONFIG_R8A7794) -static u32 usb_base_address[CONFIG_USB_MAX_CONTROLLER_COUNT] = { +static u32 usb_base_address[] = { 0xEE080000, /* USB0 (EHCI) */ 0xEE0C0000, /* USB1 */ }; @@ -53,7 +53,7 @@ int ehci_hcd_stop(int index) if (!i) printf("error : ehci(%d) reset failed.\n", index); - if (index == (CONFIG_USB_MAX_CONTROLLER_COUNT - 1)) + if (index == (ARRAY_SIZE(usb_base_address) - 1)) setbits_le32(SMSTPCR7, SMSTPCR703); return 0; diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 4befd57454..cc9a8fa71e 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -10,16 +10,14 @@ */ #include <asm/arch/clock.h> +#include <asm/arch/cpu.h> #include <asm/gpio.h> #include <asm/io.h> #include <common.h> #include "ehci.h" -#define SUNXI_USB1_IO_BASE 0x01c14000 -#define SUNXI_USB2_IO_BASE 0x01c1c000 - #define SUNXI_USB_PMU_IRQ_ENABLE 0x800 -#define SUNXI_USB_CSR 0x01c13404 +#define SUNXI_USB_CSR 0x404 #define SUNXI_USB_PASSBY_EN 1 #define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10) @@ -32,25 +30,28 @@ static struct sunxi_ehci_hcd { int usb_rst_mask; int ahb_clk_mask; int gpio_vbus; - void *csr; int irq; int id; } sunxi_echi_hcd[] = { { - .usb_rst_mask = CCM_USB_CTRL_PHY1_RST, + .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK, .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, - .gpio_vbus = CONFIG_SUNXI_USB_VBUS0_GPIO, - .csr = (void *)SUNXI_USB_CSR, +#ifndef CONFIG_MACH_SUN6I .irq = 39, +#else + .irq = 72, +#endif .id = 1, }, #if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1) { - .usb_rst_mask = CCM_USB_CTRL_PHY2_RST, + .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK, .ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1, - .gpio_vbus = CONFIG_SUNXI_USB_VBUS1_GPIO, - .csr = (void *)SUNXI_USB_CSR, +#ifndef CONFIG_MACH_SUN6I .irq = 40, +#else + .irq = 74, +#endif .id = 2, } #endif @@ -60,19 +61,32 @@ static int enabled_hcd_count; static void *get_io_base(int hcd_id) { - if (hcd_id == 1) - return (void *)SUNXI_USB1_IO_BASE; - else if (hcd_id == 2) - return (void *)SUNXI_USB2_IO_BASE; - else + switch (hcd_id) { + case 0: + return (void *)SUNXI_USB0_BASE; + case 1: + return (void *)SUNXI_USB1_BASE; + case 2: + return (void *)SUNXI_USB2_BASE; + default: return NULL; + } +} + +static int get_vbus_gpio(int hcd_id) +{ + switch (hcd_id) { + case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN); + case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN); + } + return -1; } static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr, int data, int len) { int j = 0, usbc_bit = 0; - void *dest = sunxi_ehci->csr; + void *dest = get_io_base(0) + SUNXI_USB_CSR; usbc_bit = 1 << (sunxi_ehci->id * 2); for (j = 0; j < len; j++) { @@ -105,7 +119,7 @@ static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci) usb_phy_write(sunxi_ehci, 0x20, 0x14, 5); /* threshold adjustment disconnect */ -#ifdef CONFIG_MACH_SUN4I +#if defined CONFIG_MACH_SUN4I || defined CONFIG_MACH_SUN6I usb_phy_write(sunxi_ehci, 0x2a, 3, 2); #else usb_phy_write(sunxi_ehci, 0x2a, 2, 2); @@ -138,22 +152,30 @@ static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci) setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask); setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask); +#ifdef CONFIG_MACH_SUN6I + setbits_le32(&ccm->ahb_reset0_cfg, sunxi_ehci->ahb_clk_mask); +#endif sunxi_usb_phy_init(sunxi_ehci); sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN); - gpio_direction_output(sunxi_ehci->gpio_vbus, 1); + if (sunxi_ehci->gpio_vbus != -1) + gpio_direction_output(sunxi_ehci->gpio_vbus, 1); } static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci) { struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - gpio_direction_output(sunxi_ehci->gpio_vbus, 0); + if (sunxi_ehci->gpio_vbus != -1) + gpio_direction_output(sunxi_ehci->gpio_vbus, 0); sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN); +#ifdef CONFIG_MACH_SUN6I + clrbits_le32(&ccm->ahb_reset0_cfg, sunxi_ehci->ahb_clk_mask); +#endif clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask); clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask); } @@ -165,13 +187,17 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index]; int err; + sunxi_ehci->gpio_vbus = get_vbus_gpio(sunxi_ehci->id); + /* enable common PHY only once */ if (index == 0) setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); - err = gpio_request(sunxi_ehci->gpio_vbus, "ehci_vbus"); - if (err) - return err; + if (sunxi_ehci->gpio_vbus != -1) { + err = gpio_request(sunxi_ehci->gpio_vbus, "ehci_vbus"); + if (err) + return err; + } sunxi_ehci_enable(sunxi_ehci); @@ -197,9 +223,11 @@ int ehci_hcd_stop(int index) sunxi_ehci_disable(sunxi_ehci); - err = gpio_free(sunxi_ehci->gpio_vbus); - if (err) - return err; + if (sunxi_ehci->gpio_vbus != -1) { + err = gpio_free(sunxi_ehci->gpio_vbus); + if (err) + return err; + } /* disable common PHY only once, for the last enabled hcd */ if (enabled_hcd_count == 1) diff --git a/drivers/usb/host/ehci-uniphier.c b/drivers/usb/host/ehci-uniphier.c new file mode 100644 index 0000000000..77f6c9d9d1 --- /dev/null +++ b/drivers/usb/host/ehci-uniphier.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * Author: Masahiro Yamada <yamada.m@jp.panasonic.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <usb.h> +#include <asm/arch/ehci-uniphier.h> +#include "ehci.h" + +/* + * Create the appropriate control structures to manage + * a new EHCI host controller. + */ +int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, + struct ehci_hcor **hcor) +{ + struct ehci_hccr *cr; + struct ehci_hcor *or; + + uniphier_ehci_reset(index, 0); + + cr = (struct ehci_hccr *)(uniphier_ehci_platdata[index].base); + or = (void *)cr + HC_LENGTH(ehci_readl(&cr->cr_capbase)); + + *hccr = cr; + *hcor = or; + + return 0; +} + +int ehci_hcd_stop(int index) +{ + uniphier_ehci_reset(index, 1); + + return 0; +} diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 433e703da8..79aecd414e 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -47,9 +47,9 @@ struct ehci_hcor { uint32_t or_usbcmd; #define CMD_PARK (1 << 11) /* enable "park" */ #define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */ -#define CMD_ASE (1 << 5) /* async schedule enable */ #define CMD_LRESET (1 << 7) /* partial reset */ -#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */ +#define CMD_IAAD (1 << 6) /* "doorbell" interrupt */ +#define CMD_ASE (1 << 5) /* async schedule enable */ #define CMD_PSE (1 << 4) /* periodic schedule enable */ #define CMD_RESET (1 << 1) /* reset HC not bus */ #define CMD_RUN (1 << 0) /* start/stop HC */ |