summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/common/common.c29
-rw-r--r--drivers/usb/dwc3/Kconfig6
-rw-r--r--drivers/usb/dwc3/Makefile1
-rw-r--r--drivers/usb/dwc3/core.c62
-rw-r--r--drivers/usb/dwc3/core.h6
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c157
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c3
-rw-r--r--drivers/usb/dwc3/gadget.c2
-rw-r--r--drivers/usb/dwc3/linux-compat.h5
-rw-r--r--drivers/usb/dwc3/ti_usb_phy.c1
-rw-r--r--drivers/usb/gadget/f_thor.c13
-rw-r--r--drivers/usb/gadget/f_thor.h2
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/xhci-zynqmp.c85
14 files changed, 328 insertions, 45 deletions
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index 17a0ab23ff..a55def5aba 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 ae7fc1c630..943b7630eb 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 cd18b8d9ec..60b5515a67 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 7a91015048..1ab5cee609 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 cbe9850a0b..58fe91dc51 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 0000000000..ca63eac3d9
--- /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 64822ee739..8b19140182 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 d45fae044c..e340cb268f 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 27ae21247b..35850f91a3 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 925f56c97c..d168e868e3 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 f874509cf3..c8eda05832 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 47abc8aebd..8ba3fa21b7 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 3455e8113b..b4dd005651 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 1723d2f686..7fe54281c3 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,
+};