提交 56932e84 编写于 作者: T Tom Rini

Merge branch 'master' of git://git.denx.de/u-boot-usb

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 = <&reg11>;
vdda1v8-supply = <&reg18>
#phy-cells = <0>;
};
usbphyc_port1: usb-phy@1 {
reg = <1>;
phy-supply = <&vdd_usb>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>
#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
// 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,
&regulator_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);
......
// 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,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,
};
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册