Merge branch 'master' of git://git.denx.de/u-boot-usb
This commit is contained in:
commit
56932e84ea
73
Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt
Normal file
73
Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt
Normal file
@ -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>;
|
||||
};
|
||||
};
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
402
drivers/phy/phy-stm32-usbphyc.c
Normal file
402
drivers/phy/phy-stm32-usbphyc.c
Normal file
@ -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),
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
157
drivers/usb/dwc3/dwc3-generic.c
Normal file
157
drivers/usb/dwc3/dwc3-generic.c
Normal file
@ -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,
|
||||
};
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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,40 +81,6 @@ 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)
|
||||
{
|
||||
struct zynqmp_xhci *ctx = &zynqmp_xhci;
|
||||
int ret = 0;
|
||||
uint32_t hclen;
|
||||
|
||||
if (index < 0 || index >= ARRAY_SIZE(ctr_addr))
|
||||
return -EINVAL;
|
||||
|
||||
ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
|
||||
ctx->dwc3_reg = (struct dwc3 *)((void *)ctx->hcd + DWC3_REG_OFFSET);
|
||||
|
||||
ret = board_usb_init(index, USB_INIT_HOST);
|
||||
if (ret != 0) {
|
||||
puts("Failed to initialize board for USB\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = zynqmp_xhci_core_init(ctx);
|
||||
if (ret < 0) {
|
||||
puts("Failed to initialize xhci\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*hccr = (struct xhci_hccr *)ctx->hcd;
|
||||
hclen = HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase));
|
||||
*hcor = (struct xhci_hcor *)((uintptr_t) *hccr + hclen);
|
||||
|
||||
debug("zynqmp-xhci: init hccr %p and hcor %p hc_length %d\n",
|
||||
*hccr, *hcor, hclen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xhci_hcd_stop(int index)
|
||||
{
|
||||
/*
|
||||
@ -121,3 +90,57 @@ void xhci_hcd_stop(int index)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
puts("XHCI: failed to initialize controller\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hcor = (struct xhci_hcor *)((ulong)ctx->hcd +
|
||||
HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)));
|
||||
|
||||
return xhci_register(dev, ctx->hcd, hcor);
|
||||
}
|
||||
|
||||
static int xhci_usb_remove(struct udevice *dev)
|
||||
{
|
||||
return xhci_deregister(dev);
|
||||
}
|
||||
|
||||
static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
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 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,
|
||||
};
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user