diff options
author | Tom Rini | 2018-05-20 09:44:13 -0400 |
---|---|---|
committer | Tom Rini | 2018-05-20 09:44:13 -0400 |
commit | 56932e84ea5e25167c53a55f81b8e551e4531158 (patch) | |
tree | 7d29f642b3983227bc8ee5184434c2a94d0b96cf | |
parent | 904e546970184d9f5b7e1bde7065b745e67a1bef (diff) | |
parent | 0ad3f771b69c0db837f40f6ffd5d41915fc07095 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-usb
41 files changed, 837 insertions, 112 deletions
diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt new file mode 100644 index 00000000000..725ae71ae65 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt @@ -0,0 +1,73 @@ +STMicroelectronics STM32 USB HS PHY controller + +The STM32 USBPHYC block contains a dual port High Speed UTMI+ PHY and a UTMI +switch. It controls PHY configuration and status, and the UTMI+ switch that +selects either OTG or HOST controller for the second PHY port. It also sets +PLL configuration. + +USBPHYC + |_ PLL + | + |_ PHY port#1 _________________ HOST controller + | _ | + | / 1|________________| + |_ PHY port#2 ----| |________________ + | \_0| | + |_ UTMI switch_______| OTG controller + + +Phy provider node +================= + +Required properties: +- compatible: must be "st,stm32mp1-usbphyc" +- reg: address and length of the usb phy control register set +- clocks: phandle + clock specifier for the PLL phy clock +- #address-cells: number of address cells for phys sub-nodes, must be <1> +- #size-cells: number of size cells for phys sub-nodes, must be <0> + +Optional properties: +- assigned-clocks: phandle + clock specifier for the PLL phy clock +- assigned-clock-parents: the PLL phy clock parent +- resets: phandle + reset specifier + +Required nodes: one sub-node per port the controller provides. + +Phy sub-nodes +============== + +Required properties: +- reg: phy port index +- phy-supply: phandle to the regulator providing 3V3 power to the PHY, + see phy-bindings.txt in the same directory. +- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY +- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY +- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY + port#1 and must be <1> for PHY port#2, to select USB controller + + +Example: + usbphyc: usb-phy@5a006000 { + compatible = "st,stm32mp1-usbphyc"; + reg = <0x5a006000 0x1000>; + clocks = <&rcc_clk USBPHY_K>; + resets = <&rcc_rst USBPHY_R>; + #address-cells = <1>; + #size-cells = <0>; + + usbphyc_port0: usb-phy@0 { + reg = <0>; + phy-supply = <&vdd_usb>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18> + #phy-cells = <0>; + }; + + usbphyc_port1: usb-phy@1 { + reg = <1>; + phy-supply = <&vdd_usb>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18> + #phy-cells = <1>; + }; + }; diff --git a/arch/arm/include/asm/arch-zynqmp/hardware.h b/arch/arm/include/asm/arch-zynqmp/hardware.h index dfd6097b4be..acc68251be9 100644 --- a/arch/arm/include/asm/arch-zynqmp/hardware.h +++ b/arch/arm/include/asm/arch-zynqmp/hardware.h @@ -17,9 +17,6 @@ #define ARASAN_NAND_BASEADDR 0xFF100000 -#define ZYNQMP_USB0_XHCI_BASEADDR 0xFE200000 -#define ZYNQMP_USB1_XHCI_BASEADDR 0xFE300000 - #define ZYNQMP_TCM_BASE_ADDR 0xFFE00000 #define ZYNQMP_TCM_SIZE 0x40000 diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 57c0d93aa1b..e41fec32df3 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -548,49 +548,3 @@ int checkboard(void) puts("Board: Xilinx ZynqMP\n"); return 0; } - -#ifdef CONFIG_USB_DWC3 -static struct dwc3_device dwc3_device_data0 = { - .maximum_speed = USB_SPEED_HIGH, - .base = ZYNQMP_USB0_XHCI_BASEADDR, - .dr_mode = USB_DR_MODE_PERIPHERAL, - .index = 0, -}; - -static struct dwc3_device dwc3_device_data1 = { - .maximum_speed = USB_SPEED_HIGH, - .base = ZYNQMP_USB1_XHCI_BASEADDR, - .dr_mode = USB_DR_MODE_PERIPHERAL, - .index = 1, -}; - -int usb_gadget_handle_interrupts(int index) -{ - dwc3_uboot_handle_interrupt(index); - return 0; -} - -int board_usb_init(int index, enum usb_init_type init) -{ - debug("%s: index %x\n", __func__, index); - -#if defined(CONFIG_USB_GADGET_DOWNLOAD) - g_dnl_set_serialnumber(CONFIG_SYS_CONFIG_NAME); -#endif - - switch (index) { - case 0: - return dwc3_uboot_init(&dwc3_device_data0); - case 1: - return dwc3_uboot_init(&dwc3_device_data1); - }; - - return -1; -} - -int board_usb_cleanup(int index, enum usb_init_type init) -{ - dwc3_uboot_exit(index); - return 0; -} -#endif diff --git a/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig b/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig index 3aa39306520..f5a33342fa6 100644 --- a/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm015_dc1_defconfig @@ -83,6 +83,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig b/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig index 1bd52ab7912..7f7ee558ee7 100644 --- a/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm016_dc2_defconfig @@ -79,6 +79,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig b/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig index e1e7d22a3a6..2add3bafe27 100644 --- a/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig +++ b/configs/xilinx_zynqmp_zc1751_xm017_dc3_defconfig @@ -75,6 +75,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu100_revC_defconfig b/configs/xilinx_zynqmp_zcu100_revC_defconfig index 3dd6ae9a0b3..2a6a5a69cdf 100644 --- a/configs/xilinx_zynqmp_zcu100_revC_defconfig +++ b/configs/xilinx_zynqmp_zcu100_revC_defconfig @@ -73,6 +73,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig index 0ddec998669..4cb3959f362 100644 --- a/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig +++ b/configs/xilinx_zynqmp_zcu102_rev1_0_defconfig @@ -93,6 +93,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu102_revA_defconfig b/configs/xilinx_zynqmp_zcu102_revA_defconfig index 94dc62a6164..e989d1635c3 100644 --- a/configs/xilinx_zynqmp_zcu102_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revA_defconfig @@ -91,6 +91,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu102_revB_defconfig b/configs/xilinx_zynqmp_zcu102_revB_defconfig index 8889f1909ac..bd67df904a2 100644 --- a/configs/xilinx_zynqmp_zcu102_revB_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revB_defconfig @@ -91,6 +91,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu104_revA_defconfig b/configs/xilinx_zynqmp_zcu104_revA_defconfig index 3d3d941d375..a76b9cf5462 100644 --- a/configs/xilinx_zynqmp_zcu104_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu104_revA_defconfig @@ -84,6 +84,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu104_revC_defconfig b/configs/xilinx_zynqmp_zcu104_revC_defconfig index 7c22d7f020e..dcd4897f2fb 100644 --- a/configs/xilinx_zynqmp_zcu104_revC_defconfig +++ b/configs/xilinx_zynqmp_zcu104_revC_defconfig @@ -84,6 +84,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu106_revA_defconfig b/configs/xilinx_zynqmp_zcu106_revA_defconfig index 017940e9836..a5fa33e366a 100644 --- a/configs/xilinx_zynqmp_zcu106_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu106_revA_defconfig @@ -90,6 +90,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/configs/xilinx_zynqmp_zcu111_revA_defconfig b/configs/xilinx_zynqmp_zcu111_revA_defconfig index 028a7b53284..4d9b9156352 100644 --- a/configs/xilinx_zynqmp_zcu111_revA_defconfig +++ b/configs/xilinx_zynqmp_zcu111_revA_defconfig @@ -84,6 +84,7 @@ CONFIG_USB_XHCI_DWC3=y CONFIG_USB_XHCI_ZYNQMP=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_DWC3_GENERIC=y CONFIG_USB_ULPI_VIEWPORT=y CONFIG_USB_ULPI=y CONFIG_USB_STORAGE=y diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 119edec2048..8fc2295d03a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -110,6 +110,19 @@ config STI_USB_PHY used by USB2 and USB3 Host controllers available on STiH407 SoC families. +config PHY_STM32_USBPHYC + tristate "STMicroelectronics STM32 SoC USB HS PHY driver" + depends on PHY && ARCH_STM32MP + help + Enable this to support the High-Speed USB transceiver that is part of + STMicroelectronics STM32 SoCs. + + This driver controls the entire USB PHY block: the USB PHY controller + (USBPHYC) and the two 8-bit wide UTMI+ interface. First interface is + used by an HS USB Host controller, and the second one is shared + between an HS USB OTG controller and an HS USB Host controller, + selected by an USB switch. + config MESON_GXL_USB_PHY bool "Amlogic Meson GXL USB PHYs" depends on PHY && ARCH_MESON && MESON_GXL diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 5c8711d6a4f..ba0803cd040 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -12,4 +12,5 @@ obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o +obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c new file mode 100644 index 00000000000..4ff6a9a34bc --- /dev/null +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <clk.h> +#include <div64.h> +#include <dm.h> +#include <fdtdec.h> +#include <generic-phy.h> +#include <reset.h> +#include <syscon.h> +#include <usb.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <power/regulator.h> + +/* USBPHYC registers */ +#define STM32_USBPHYC_PLL 0x0 +#define STM32_USBPHYC_MISC 0x8 + +/* STM32_USBPHYC_PLL bit fields */ +#define PLLNDIV GENMASK(6, 0) +#define PLLNDIV_SHIFT 0 +#define PLLFRACIN GENMASK(25, 10) +#define PLLFRACIN_SHIFT 10 +#define PLLEN BIT(26) +#define PLLSTRB BIT(27) +#define PLLSTRBYP BIT(28) +#define PLLFRACCTL BIT(29) +#define PLLDITHEN0 BIT(30) +#define PLLDITHEN1 BIT(31) + +/* STM32_USBPHYC_MISC bit fields */ +#define SWITHOST BIT(0) + +#define MAX_PHYS 2 + +#define PLL_LOCK_TIME_US 100 +#define PLL_PWR_DOWN_TIME_US 5 +#define PLL_FVCO 2880 /* in MHz */ +#define PLL_INFF_MIN_RATE 19200000 /* in Hz */ +#define PLL_INFF_MAX_RATE 38400000 /* in Hz */ + +struct pll_params { + u8 ndiv; + u16 frac; +}; + +struct stm32_usbphyc { + fdt_addr_t base; + struct clk clk; + struct stm32_usbphyc_phy { + struct udevice *vdd; + struct udevice *vdda1v1; + struct udevice *vdda1v8; + int index; + bool init; + bool powered; + } phys[MAX_PHYS]; +}; + +void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) +{ + unsigned long long fvco, ndiv, frac; + + /* + * | FVCO = INFF*2*(NDIV + FRACT/2^16 ) when DITHER_DISABLE[1] = 1 + * | FVCO = 2880MHz + * | NDIV = integer part of input bits to set the LDF + * | FRACT = fractional part of input bits to set the LDF + * => PLLNDIV = integer part of (FVCO / (INFF*2)) + * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16 + * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16 + */ + fvco = (unsigned long long)PLL_FVCO * 1000000; /* In Hz */ + + ndiv = fvco; + do_div(ndiv, (clk_rate * 2)); + pll_params->ndiv = (u8)ndiv; + + frac = fvco * (1 << 16); + do_div(frac, (clk_rate * 2)); + frac = frac - (ndiv * (1 << 16)); + pll_params->frac = (u16)frac; +} + +static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) +{ + struct pll_params pll_params; + u32 clk_rate = clk_get_rate(&usbphyc->clk); + u32 usbphyc_pll; + + if ((clk_rate < PLL_INFF_MIN_RATE) || (clk_rate > PLL_INFF_MAX_RATE)) { + pr_debug("%s: input clk freq (%dHz) out of range\n", + __func__, clk_rate); + return -EINVAL; + } + + stm32_usbphyc_get_pll_params(clk_rate, &pll_params); + + usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP; + usbphyc_pll |= ((pll_params.ndiv << PLLNDIV_SHIFT) & PLLNDIV); + + if (pll_params.frac) { + usbphyc_pll |= PLLFRACCTL; + usbphyc_pll |= ((pll_params.frac << PLLFRACIN_SHIFT) + & PLLFRACIN); + } + + writel(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL); + + pr_debug("%s: input clk freq=%dHz, ndiv=%d, frac=%d\n", __func__, + clk_rate, pll_params.ndiv, pll_params.frac); + + return 0; +} + +static bool stm32_usbphyc_is_init(struct stm32_usbphyc *usbphyc) +{ + int i; + + for (i = 0; i < MAX_PHYS; i++) { + if (usbphyc->phys[i].init) + return true; + } + + return false; +} + +static bool stm32_usbphyc_is_powered(struct stm32_usbphyc *usbphyc) +{ + int i; + + for (i = 0; i < MAX_PHYS; i++) { + if (usbphyc->phys[i].powered) + return true; + } + + return false; +} + +static int stm32_usbphyc_phy_init(struct phy *phy) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); + struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + bool pllen = readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN ? + true : false; + int ret; + + pr_debug("%s phy ID = %lu\n", __func__, phy->id); + /* Check if one phy port has already configured the pll */ + if (pllen && stm32_usbphyc_is_init(usbphyc)) + goto initialized; + + if (pllen) { + clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); + udelay(PLL_PWR_DOWN_TIME_US); + } + + ret = stm32_usbphyc_pll_init(usbphyc); + if (ret) + return ret; + + setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); + + /* + * We must wait PLL_LOCK_TIME_US before checking that PLLEN + * bit is still set + */ + udelay(PLL_LOCK_TIME_US); + + if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)) + return -EIO; + +initialized: + usbphyc_phy->init = true; + + return 0; +} + +static int stm32_usbphyc_phy_exit(struct phy *phy) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); + struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + + pr_debug("%s phy ID = %lu\n", __func__, phy->id); + usbphyc_phy->init = false; + + /* Check if other phy port requires pllen */ + if (stm32_usbphyc_is_init(usbphyc)) + return 0; + + clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); + + /* + * We must wait PLL_PWR_DOWN_TIME_US before checking that PLLEN + * bit is still clear + */ + udelay(PLL_PWR_DOWN_TIME_US); + + if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN) + return -EIO; + + return 0; +} + +static int stm32_usbphyc_phy_power_on(struct phy *phy) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); + struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + int ret; + + pr_debug("%s phy ID = %lu\n", __func__, phy->id); + if (usbphyc_phy->vdda1v1) { + ret = regulator_set_enable(usbphyc_phy->vdda1v1, true); + if (ret) + return ret; + } + + if (usbphyc_phy->vdda1v8) { + ret = regulator_set_enable(usbphyc_phy->vdda1v8, true); + if (ret) + return ret; + } + if (usbphyc_phy->vdd) { + ret = regulator_set_enable(usbphyc_phy->vdd, true); + if (ret) + return ret; + } + + usbphyc_phy->powered = true; + + return 0; +} + +static int stm32_usbphyc_phy_power_off(struct phy *phy) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); + struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + int ret; + + pr_debug("%s phy ID = %lu\n", __func__, phy->id); + usbphyc_phy->powered = false; + + if (stm32_usbphyc_is_powered(usbphyc)) + return 0; + + if (usbphyc_phy->vdda1v1) { + ret = regulator_set_enable(usbphyc_phy->vdda1v1, false); + if (ret) + return ret; + } + + if (usbphyc_phy->vdda1v8) { + ret = regulator_set_enable(usbphyc_phy->vdda1v8, false); + if (ret) + return ret; + } + + if (usbphyc_phy->vdd) { + ret = regulator_set_enable(usbphyc_phy->vdd, false); + if (ret) + return ret; + } + + return 0; +} + +static int stm32_usbphyc_get_regulator(struct udevice *dev, ofnode node, + char *supply_name, + struct udevice **regulator) +{ + struct ofnode_phandle_args regulator_phandle; + int ret; + + ret = ofnode_parse_phandle_with_args(node, supply_name, + NULL, 0, 0, + ®ulator_phandle); + if (ret) { + dev_err(dev, "Can't find %s property (%d)\n", supply_name, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, + regulator_phandle.node, + regulator); + + if (ret) { + dev_err(dev, "Can't get %s regulator (%d)\n", supply_name, ret); + return ret; + } + + return 0; +} + +static int stm32_usbphyc_of_xlate(struct phy *phy, + struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + pr_debug("%s: invalid args_count: %d\n", __func__, + args->args_count); + return -EINVAL; + } + + if (args->args[0] >= MAX_PHYS) + return -ENODEV; + + if (args->args_count) + phy->id = args->args[0]; + else + phy->id = 0; + + return 0; +} + +static const struct phy_ops stm32_usbphyc_phy_ops = { + .init = stm32_usbphyc_phy_init, + .exit = stm32_usbphyc_phy_exit, + .power_on = stm32_usbphyc_phy_power_on, + .power_off = stm32_usbphyc_phy_power_off, + .of_xlate = stm32_usbphyc_of_xlate, +}; + +static int stm32_usbphyc_probe(struct udevice *dev) +{ + struct stm32_usbphyc *usbphyc = dev_get_priv(dev); + struct reset_ctl reset; + ofnode node; + int i, ret; + + usbphyc->base = dev_read_addr(dev); + if (usbphyc->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Enable clock */ + ret = clk_get_by_index(dev, 0, &usbphyc->clk); + if (ret) + return ret; + + ret = clk_enable(&usbphyc->clk); + if (ret) + return ret; + + /* Reset */ + ret = reset_get_by_index(dev, 0, &reset); + if (!ret) { + reset_assert(&reset); + udelay(2); + reset_deassert(&reset); + } + + /* + * parse all PHY subnodes in order to populate regulator associated + * to each PHY port + */ + node = dev_read_first_subnode(dev); + for (i = 0; i < MAX_PHYS; i++) { + struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i; + + usbphyc_phy->index = i; + usbphyc_phy->init = false; + usbphyc_phy->powered = false; + ret = stm32_usbphyc_get_regulator(dev, node, "phy-supply", + &usbphyc_phy->vdd); + if (ret) + return ret; + + ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v1-supply", + &usbphyc_phy->vdda1v1); + if (ret) + return ret; + + ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v8-supply", + &usbphyc_phy->vdda1v8); + if (ret) + return ret; + + node = dev_read_next_subnode(node); + } + + /* Check if second port has to be used for host controller */ + if (dev_read_bool(dev, "st,port2-switch-to-host")) + setbits_le32(usbphyc->base + STM32_USBPHYC_MISC, SWITHOST); + + return 0; +} + +static const struct udevice_id stm32_usbphyc_of_match[] = { + { .compatible = "st,stm32mp1-usbphyc", }, + { }, +}; + +U_BOOT_DRIVER(stm32_usb_phyc) = { + .name = "stm32-usbphyc", + .id = UCLASS_PHY, + .of_match = stm32_usbphyc_of_match, + .ops = &stm32_usbphyc_phy_ops, + .probe = stm32_usbphyc_probe, + .priv_auto_alloc_size = sizeof(struct stm32_usbphyc), +}; diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 17a0ab23ff5..a55def5aba6 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -9,6 +9,7 @@ #include <common.h> #include <linux/libfdt.h> #include <linux/usb/otg.h> +#include <linux/usb/ch9.h> DECLARE_GLOBAL_DATA_PTR; @@ -37,3 +38,31 @@ enum usb_dr_mode usb_get_dr_mode(int node) return USB_DR_MODE_UNKNOWN; } + +static const char *const speed_names[] = { + [USB_SPEED_UNKNOWN] = "UNKNOWN", + [USB_SPEED_LOW] = "low-speed", + [USB_SPEED_FULL] = "full-speed", + [USB_SPEED_HIGH] = "high-speed", + [USB_SPEED_WIRELESS] = "wireless", + [USB_SPEED_SUPER] = "super-speed", +}; + +enum usb_device_speed usb_get_maximum_speed(int node) +{ + const void *fdt = gd->fdt_blob; + const char *max_speed; + int i; + + max_speed = fdt_getprop(fdt, node, "maximum-speed", NULL); + if (!max_speed) { + pr_err("usb maximum-speed not found\n"); + return USB_SPEED_UNKNOWN; + } + + for (i = 0; i < ARRAY_SIZE(speed_names); i++) + if (!strcmp(max_speed, speed_names[i])) + return i; + + return USB_SPEED_UNKNOWN; +} diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index ae7fc1c6304..943b7630eba 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -37,6 +37,12 @@ config USB_DWC3_OMAP Say 'Y' here if you have one such device +config USB_DWC3_GENERIC + bool "Xilinx ZynqMP and similar Platforms" + depends on DM_USB && USB_DWC3 + help + Some platforms can reuse this DWC3 generic implementation. + config USB_DWC3_UNIPHIER bool "DesignWare USB3 Host Support on UniPhier Platforms" depends on ARCH_UNIPHIER && USB_XHCI_DWC3 diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index cd18b8d9ec0..60b5515a67d 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -7,6 +7,7 @@ dwc3-y := core.o obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o +obj-$(CONFIG_USB_DWC3_GENERIC) += dwc3-generic.o obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7a91015048f..1ab5cee6096 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -18,6 +18,7 @@ #include <dwc3-uboot.h> #include <asm/dma-mapping.h> #include <linux/ioport.h> +#include <dm.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -110,7 +111,8 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, { struct dwc3_event_buffer *evt; - evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); + evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt), + GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); @@ -623,7 +625,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) void *mem; - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + mem = devm_kzalloc((struct udevice *)dev, + sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -785,3 +788,58 @@ MODULE_ALIAS("platform:dwc3"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); + +#ifdef CONFIG_DM_USB + +int dwc3_init(struct dwc3 *dwc) +{ + int ret; + + dwc3_cache_hwparams(dwc); + + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); + if (ret) { + dev_err(dwc->dev, "failed to allocate event buffers\n"); + return -ENOMEM; + } + + ret = dwc3_core_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize core\n"); + goto core_fail; + } + + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto event_fail; + } + + ret = dwc3_core_init_mode(dwc); + if (ret) + goto mode_fail; + + return 0; + +mode_fail: + dwc3_event_buffers_cleanup(dwc); + +event_fail: + dwc3_core_exit(dwc); + +core_fail: + dwc3_free_event_buffers(dwc); + + return ret; +} + +void dwc3_remove(struct dwc3 *dwc) +{ + dwc3_core_exit_mode(dwc); + dwc3_event_buffers_cleanup(dwc); + dwc3_free_event_buffers(dwc); + dwc3_core_exit(dwc); + kfree(dwc->mem); +} + +#endif diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cbe9850a0bd..58fe91dc513 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -712,7 +712,11 @@ struct dwc3 { /* device lock */ spinlock_t lock; +#if defined(__UBOOT__) && defined(CONFIG_DM_USB) + struct udevice *dev; +#else struct device *dev; +#endif struct platform_device *xhci; struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; @@ -987,6 +991,8 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); +int dwc3_init(struct dwc3 *dwc); +void dwc3_remove(struct dwc3 *dwc); #ifdef CONFIG_USB_DWC3_HOST int dwc3_host_init(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c new file mode 100644 index 00000000000..ca63eac3d98 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic DWC3 Glue layer + * + * Copyright (C) 2016 - 2018 Xilinx, Inc. + * + * Based on dwc3-omap.c. + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <linux/usb/otg.h> +#include <linux/compat.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <malloc.h> +#include <usb.h> +#include "core.h" +#include "gadget.h" +#include "linux-compat.h" + +DECLARE_GLOBAL_DATA_PTR; + +int usb_gadget_handle_interrupts(int index) +{ + struct dwc3 *priv; + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); + if (!dev || ret) { + pr_err("No USB device found\n"); + return -ENODEV; + } + + priv = dev_get_priv(dev); + + dwc3_gadget_uboot_handle_interrupt(priv); + + return 0; +} + +static int dwc3_generic_peripheral_probe(struct udevice *dev) +{ + struct dwc3 *priv = dev_get_priv(dev); + + return dwc3_init(priv); +} + +static int dwc3_generic_peripheral_remove(struct udevice *dev) +{ + struct dwc3 *priv = dev_get_priv(dev); + + dwc3_remove(priv); + + return 0; +} + +static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc3 *priv = dev_get_priv(dev); + int node = dev_of_offset(dev); + + priv->regs = (void *)devfdt_get_addr(dev); + priv->regs += DWC3_GLOBALS_REGS_START; + + priv->maximum_speed = usb_get_maximum_speed(node); + if (priv->maximum_speed == USB_SPEED_UNKNOWN) { + pr_err("Invalid usb maximum speed\n"); + return -ENODEV; + } + + priv->dr_mode = usb_get_dr_mode(node); + if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { + pr_err("Invalid usb mode setup\n"); + return -ENODEV; + } + + return 0; +} + +static int dwc3_generic_peripheral_bind(struct udevice *dev) +{ + return device_probe(dev); +} + +U_BOOT_DRIVER(dwc3_generic_peripheral) = { + .name = "dwc3-generic-peripheral", + .id = UCLASS_USB_DEV_GENERIC, + .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, + .probe = dwc3_generic_peripheral_probe, + .remove = dwc3_generic_peripheral_remove, + .bind = dwc3_generic_peripheral_bind, + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct dwc3), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; + +static int dwc3_generic_bind(struct udevice *parent) +{ + const void *fdt = gd->fdt_blob; + int node; + int ret; + + for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; + node = fdt_next_subnode(fdt, node)) { + const char *name = fdt_get_name(fdt, node, NULL); + enum usb_dr_mode dr_mode; + struct udevice *dev; + const char *driver; + + debug("%s: subnode name: %s\n", __func__, name); + if (strncmp(name, "dwc3@", 4)) + continue; + + dr_mode = usb_get_dr_mode(node); + + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: + debug("%s: dr_mode: OTG or Peripheral\n", __func__); + driver = "dwc3-generic-peripheral"; + break; + case USB_DR_MODE_HOST: + debug("%s: dr_mode: HOST\n", __func__); + driver = "dwc3-generic-host"; + break; + default: + debug("%s: unsupported dr_mode\n", __func__); + return -ENODEV; + }; + + ret = device_bind_driver_to_node(parent, driver, name, + offset_to_ofnode(node), &dev); + if (ret) { + debug("%s: not able to bind usb device mode\n", + __func__); + return ret; + } + } + + return 0; +} + +static const struct udevice_id dwc3_generic_ids[] = { + { .compatible = "xlnx,zynqmp-dwc3" }, + { } +}; + +U_BOOT_DRIVER(dwc3_generic_wrapper) = { + .name = "dwc3-generic-wrapper", + .id = UCLASS_MISC, + .of_match = dwc3_generic_ids, + .bind = dwc3_generic_bind, +}; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 64822ee7399..8b191401829 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -16,6 +16,7 @@ #include <common.h> #include <malloc.h> #include <asm/io.h> +#include <dm.h> #include <dwc3-omap-uboot.h> #include <linux/usb/dwc3-omap.h> #include <linux/ioport.h> @@ -376,7 +377,7 @@ int dwc3_omap_uboot_init(struct dwc3_omap_device *omap_dev) struct device *dev = NULL; struct dwc3_omap *omap; - omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); + omap = devm_kzalloc((struct udevice *)dev, sizeof(*omap), GFP_KERNEL); if (!omap) return -ENOMEM; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d45fae044c4..e340cb268fc 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2609,7 +2609,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) if (ret) goto err4; - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); + ret = usb_add_gadget_udc((struct device *)dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); goto err4; diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h index 27ae21247b1..35850f91a36 100644 --- a/drivers/usb/dwc3/linux-compat.h +++ b/drivers/usb/dwc3/linux-compat.h @@ -20,9 +20,4 @@ static inline size_t strlcat(char *dest, const char *src, size_t n) return strlen(dest) + strlen(src); } -static inline void *devm_kzalloc(struct device *dev, unsigned int size, - unsigned int flags) -{ - return kzalloc(size, flags); -} #endif diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c index 925f56c97c8..d168e868e35 100644 --- a/drivers/usb/dwc3/ti_usb_phy.c +++ b/drivers/usb/dwc3/ti_usb_phy.c @@ -23,6 +23,7 @@ #include <linux/ioport.h> #include <asm/io.h> #include <asm/arch/sys_proto.h> +#include <dm.h> #include "linux-compat.h" diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index f874509cf38..c8eda058329 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -47,7 +47,7 @@ DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_rx_data_buf, /* ********************************************************** */ /* THOR protocol - transmission handling */ /* ********************************************************** */ -DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE); +DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE + 1); static unsigned long long int thor_file_size; static int alt_setting_num; @@ -262,8 +262,10 @@ static long long int process_rqt_download(const struct rqt_box *rqt) switch (rqt->rqt_data) { case RQT_DL_INIT: - thor_file_size = rqt->int_data[0]; - debug("INIT: total %d bytes\n", rqt->int_data[0]); + thor_file_size = (unsigned long long int)rqt->int_data[0] + + (((unsigned long long int)rqt->int_data[1]) + << 32); + debug("INIT: total %llu bytes\n", thor_file_size); break; case RQT_DL_FILE_INFO: file_type = rqt->int_data[0]; @@ -274,8 +276,11 @@ static long long int process_rqt_download(const struct rqt_box *rqt) break; } - thor_file_size = rqt->int_data[1]; + thor_file_size = (unsigned long long int)rqt->int_data[1] + + (((unsigned long long int)rqt->int_data[2]) + << 32); memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE); + f_name[F_NAME_BUF_SIZE] = '\0'; debug("INFO: name(%s, %d), size(%llu), type(%d)\n", f_name, 0, thor_file_size, file_type); diff --git a/drivers/usb/gadget/f_thor.h b/drivers/usb/gadget/f_thor.h index 47abc8aebd5..8ba3fa21b73 100644 --- a/drivers/usb/gadget/f_thor.h +++ b/drivers/usb/gadget/f_thor.h @@ -34,7 +34,7 @@ struct usb_cdc_attribute_vendor_descriptor { __u8 DAUValue; } __packed; -#define VER_PROTOCOL_MAJOR 4 +#define VER_PROTOCOL_MAJOR 5 #define VER_PROTOCOL_MINOR 0 enum rqt { diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3455e8113bb..b4dd005651c 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -75,6 +75,7 @@ config USB_XHCI_STI config USB_XHCI_ZYNQMP bool "Support for Xilinx ZynqMP on-chip xHCI USB controller" depends on ARCH_ZYNQMP + depends on DM_USB help Enables support for the on-chip xHCI controller on Xilinx ZynqMP SoCs. diff --git a/drivers/usb/host/xhci-zynqmp.c b/drivers/usb/host/xhci-zynqmp.c index 1723d2f6862..7fe54281c3c 100644 --- a/drivers/usb/host/xhci-zynqmp.c +++ b/drivers/usb/host/xhci-zynqmp.c @@ -10,6 +10,7 @@ */ #include <common.h> +#include <dm.h> #include <usb.h> #include <linux/errno.h> #include <asm/arch-zynqmp/hardware.h> @@ -54,13 +55,15 @@ #define USBOTGSS_IRQ_SET_1_DMADISABLECLR_EN BIT(17) struct zynqmp_xhci { + struct usb_platdata usb_plat; + struct xhci_ctrl ctrl; struct xhci_hccr *hcd; struct dwc3 *dwc3_reg; }; -static struct zynqmp_xhci zynqmp_xhci; - -unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST; +struct zynqmp_xhci_platdata { + fdt_addr_t hcd_base; +}; static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci) { @@ -78,46 +81,66 @@ static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci) return ret; } -int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) +void xhci_hcd_stop(int index) { - struct zynqmp_xhci *ctx = &zynqmp_xhci; - int ret = 0; - uint32_t hclen; + /* + * Currently zynqmp socs do not support PHY shutdown from + * sw. But this support may be added in future socs. + */ - if (index < 0 || index >= ARRAY_SIZE(ctr_addr)) - return -EINVAL; + return; +} - ctx->hcd = (struct xhci_hccr *)ctr_addr[index]; - ctx->dwc3_reg = (struct dwc3 *)((void *)ctx->hcd + DWC3_REG_OFFSET); +static int xhci_usb_probe(struct udevice *dev) +{ + struct zynqmp_xhci_platdata *plat = dev_get_platdata(dev); + struct zynqmp_xhci *ctx = dev_get_priv(dev); + struct xhci_hcor *hcor; + int ret; - ret = board_usb_init(index, USB_INIT_HOST); - if (ret != 0) { - puts("Failed to initialize board for USB\n"); - return ret; - } + ctx->hcd = (struct xhci_hccr *)plat->hcd_base; + ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); ret = zynqmp_xhci_core_init(ctx); - if (ret < 0) { - puts("Failed to initialize xhci\n"); - return ret; + if (ret) { + puts("XHCI: failed to initialize controller\n"); + return -EINVAL; } - *hccr = (struct xhci_hccr *)ctx->hcd; - hclen = HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)); - *hcor = (struct xhci_hcor *)((uintptr_t) *hccr + hclen); + hcor = (struct xhci_hcor *)((ulong)ctx->hcd + + HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); - debug("zynqmp-xhci: init hccr %p and hcor %p hc_length %d\n", - *hccr, *hcor, hclen); + return xhci_register(dev, ctx->hcd, hcor); +} - return ret; +static int xhci_usb_remove(struct udevice *dev) +{ + return xhci_deregister(dev); } -void xhci_hcd_stop(int index) +static int xhci_usb_ofdata_to_platdata(struct udevice *dev) { - /* - * Currently zynqmp socs do not support PHY shutdown from - * sw. But this support may be added in future socs. - */ + struct zynqmp_xhci_platdata *plat = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + + /* Get the base address for XHCI controller from the device node */ + plat->hcd_base = fdtdec_get_addr(blob, dev_of_offset(dev), "reg"); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + debug("Can't get the XHCI register base address\n"); + return -ENXIO; + } - return; + return 0; } + +U_BOOT_DRIVER(dwc3_generic_host) = { + .name = "dwc3-generic-host", + .id = UCLASS_USB, + .ofdata_to_platdata = xhci_usb_ofdata_to_platdata, + .probe = xhci_usb_probe, + .remove = xhci_usb_remove, + .ops = &xhci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct zynqmp_xhci_platdata), + .priv_auto_alloc_size = sizeof(struct zynqmp_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/include/configs/xilinx_zynqmp_zc1751_xm015_dc1.h b/include/configs/xilinx_zynqmp_zc1751_xm015_dc1.h index 852c2238de4..f0ab3f15922 100644 --- a/include/configs/xilinx_zynqmp_zc1751_xm015_dc1.h +++ b/include/configs/xilinx_zynqmp_zc1751_xm015_dc1.h @@ -11,7 +11,6 @@ #define CONFIG_ZYNQ_SDHCI0 #define CONFIG_ZYNQ_SDHCI1 -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} #include <configs/xilinx_zynqmp.h> diff --git a/include/configs/xilinx_zynqmp_zc1751_xm016_dc2.h b/include/configs/xilinx_zynqmp_zc1751_xm016_dc2.h index 2533ab86090..bfebbb3cd19 100644 --- a/include/configs/xilinx_zynqmp_zc1751_xm016_dc2.h +++ b/include/configs/xilinx_zynqmp_zc1751_xm016_dc2.h @@ -9,8 +9,6 @@ #ifndef __CONFIG_ZYNQMP_ZC1751_XM016_DC2_H #define __CONFIG_ZYNQMP_ZC1751_XM016_DC2_H -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB1_XHCI_BASEADDR} - #include <configs/xilinx_zynqmp.h> #endif /* __CONFIG_ZYNQMP_ZC1751_XM016_DC2_H */ diff --git a/include/configs/xilinx_zynqmp_zc1751_xm017_dc3.h b/include/configs/xilinx_zynqmp_zc1751_xm017_dc3.h index f7d4ab2800c..bd4a0c3178b 100644 --- a/include/configs/xilinx_zynqmp_zc1751_xm017_dc3.h +++ b/include/configs/xilinx_zynqmp_zc1751_xm017_dc3.h @@ -11,9 +11,6 @@ #define CONFIG_ZYNQ_SDHCI1 -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR, \ - ZYNQMP_USB1_XHCI_BASEADDR} - #include <configs/xilinx_zynqmp.h> #endif /* __CONFIG_ZYNQMP_ZC1751_XM017_DC3_H */ diff --git a/include/configs/xilinx_zynqmp_zcu100.h b/include/configs/xilinx_zynqmp_zcu100.h index 029347da479..b65d0c1cddd 100644 --- a/include/configs/xilinx_zynqmp_zcu100.h +++ b/include/configs/xilinx_zynqmp_zcu100.h @@ -24,9 +24,6 @@ {0, {{I2C_MUX_PCA9548, 0x75, 7} } }, \ } -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR, \ - ZYNQMP_USB1_XHCI_BASEADDR} - #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_ASIX diff --git a/include/configs/xilinx_zynqmp_zcu102.h b/include/configs/xilinx_zynqmp_zcu102.h index c61e1b5e27c..ca11b97c7c4 100644 --- a/include/configs/xilinx_zynqmp_zcu102.h +++ b/include/configs/xilinx_zynqmp_zcu102.h @@ -35,8 +35,6 @@ #define CONFIG_PCA953X -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} - #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 #define CONFIG_ZYNQ_EEPROM_BUS 5 #define CONFIG_ZYNQ_GEM_EEPROM_ADDR 0x54 diff --git a/include/configs/xilinx_zynqmp_zcu104.h b/include/configs/xilinx_zynqmp_zcu104.h index 8d417f45e01..7e3b9ad7058 100644 --- a/include/configs/xilinx_zynqmp_zcu104.h +++ b/include/configs/xilinx_zynqmp_zcu104.h @@ -26,8 +26,6 @@ #define CONFIG_PCA953X -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} - #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 #include <configs/xilinx_zynqmp.h> diff --git a/include/configs/xilinx_zynqmp_zcu106.h b/include/configs/xilinx_zynqmp_zcu106.h index 01ac12a53c1..cc2d145ddd9 100644 --- a/include/configs/xilinx_zynqmp_zcu106.h +++ b/include/configs/xilinx_zynqmp_zcu106.h @@ -35,8 +35,6 @@ #define CONFIG_PCA953X -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} - #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 #define CONFIG_ZYNQ_EEPROM_BUS 5 #define CONFIG_ZYNQ_GEM_EEPROM_ADDR 0x54 diff --git a/include/configs/xilinx_zynqmp_zcu111.h b/include/configs/xilinx_zynqmp_zcu111.h index 3233b379798..8f8cb4f0870 100644 --- a/include/configs/xilinx_zynqmp_zcu111.h +++ b/include/configs/xilinx_zynqmp_zcu111.h @@ -38,8 +38,6 @@ #define CONFIG_PCA953X -#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} - #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 #define CONFIG_ZYNQ_EEPROM_BUS 5 #define CONFIG_ZYNQ_GEM_EEPROM_ADDR 0x54 diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 0b273d8e2e8..d2604c5cafb 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -25,4 +25,13 @@ enum usb_dr_mode { */ enum usb_dr_mode usb_get_dr_mode(int node); +/** + * usb_get_maximum_speed() - Get maximum speed for given device + * @node: Node offset to the given device + * + * The function gets phy interface string from property 'maximum-speed', + * and returns the correspondig enum usb_device_speed + */ +enum usb_device_speed usb_get_maximum_speed(int node); + #endif /* __LINUX_USB_OTG_H */ diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 07dad617cf1..83277981792 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -4781,7 +4781,6 @@ CONFIG_ZLIB CONFIG_ZLT CONFIG_ZM7300 CONFIG_ZYNQMP_EEPROM -CONFIG_ZYNQMP_XHCI_LIST CONFIG_ZYNQ_EEPROM CONFIG_ZYNQ_EEPROM_BUS CONFIG_ZYNQ_GEM_EEPROM_ADDR |