diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/common/common.c | 29 | ||||
-rw-r--r-- | drivers/usb/dwc3/Kconfig | 6 | ||||
-rw-r--r-- | drivers/usb/dwc3/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.c | 62 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 6 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-generic.c | 157 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 3 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 2 | ||||
-rw-r--r-- | drivers/usb/dwc3/linux-compat.h | 5 | ||||
-rw-r--r-- | drivers/usb/dwc3/ti_usb_phy.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/f_thor.c | 13 | ||||
-rw-r--r-- | drivers/usb/gadget/f_thor.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-zynqmp.c | 85 |
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, +}; |