From 6c167fc9b0c23ead791edb94cf4debb6b8e534b5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Oct 2011 22:55:04 +0300 Subject: usb: dwc3: allow forcing a maximum speed this is mainly for testing. In order to be able to test if we're enumerating correctly on all speeds, let that be controlled by a module parameter. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 717ebc9ff941..ca3b01f5fffa 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -59,6 +59,10 @@ #include "debug.h" +static char *maximum_speed = "super"; +module_param(maximum_speed, charp, 0); +MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure @@ -370,6 +374,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev) dwc->dev = &pdev->dev; dwc->irq = irq; + if (!strncmp("super", maximum_speed, 5)) + dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; + else if (!strncmp("high", maximum_speed, 4)) + dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; + else if (!strncmp("full", maximum_speed, 4)) + dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; + else if (!strncmp("low", maximum_speed, 3)) + dwc->maximum_speed = DWC3_DCFG_LOWSPEED; + else + dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); pm_runtime_forbid(&pdev->dev); -- cgit v1.2.3 From 9f622b2a407d8b34a5a7f5b4abd8b29b25cf4f32 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Oct 2011 10:31:04 +0300 Subject: usb: dwc3: calculate number of event buffers dynamically This will allow us to only allocate memory when we actually need. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 21 +++++++++++---------- drivers/usb/dwc3/core.h | 8 ++++++-- drivers/usb/dwc3/gadget.c | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ca3b01f5fffa..1f67606fd4fb 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -154,7 +154,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int i; - for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { + for (i = 0; i < dwc->num_event_buffers; i++) { evt = dwc->ev_buffs[i]; if (evt) { dwc3_free_one_event_buffer(dwc, evt); @@ -166,17 +166,19 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) /** * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length * @dwc: Pointer to out controller context structure - * @num: number of event buffers to allocate * @length: size of event buffer * * Returns 0 on success otherwise negative errno. In error the case, dwc * may contain some buffers allocated but not all which were requested. */ -static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, - unsigned length) +static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) { + int num; int i; + num = DWC3_NUM_INT(dwc->hwparams.hwparams1); + dwc->num_event_buffers = num; + for (i = 0; i < num; i++) { struct dwc3_event_buffer *evt; @@ -202,7 +204,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int n; - for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { + for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buffs[n]; dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", evt->buf, (unsigned long long) evt->dma, @@ -225,7 +227,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int n; - for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { + for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buffs[n]; dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); @@ -289,8 +291,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) cpu_relax(); } while (true); - ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, - DWC3_EVENT_BUFFERS_SIZE); + 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"); ret = -ENOMEM; @@ -303,8 +306,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) goto err1; } - dwc3_cache_hwparams(dwc); - return 0; err1: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b7d56c3a1fbb..4b6c673ed608 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -52,7 +52,7 @@ /* Global constants */ #define DWC3_ENDPOINTS_NUM 32 -#define DWC3_EVENT_BUFFERS_NUM 2 +#define DWC3_EVENT_BUFFERS_MAX 2 #define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE #define DWC3_EVENT_TYPE_MASK 0xfe @@ -536,6 +536,8 @@ struct dwc3_hwparams { u32 hwparams8; }; +#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) + /** * struct dwc3 - representation of our controller * @ctrl_req: usb control request which is used for ep0 @@ -555,6 +557,7 @@ struct dwc3_hwparams { * @regs: base address for our registers * @regs_size: address space size * @irq: IRQ number + * @num_event_buffers: calculated number of event buffers * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents * @is_selfpowered: true when we are selfpowered @@ -585,7 +588,7 @@ struct dwc3 { spinlock_t lock; struct device *dev; - struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM]; + struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_MAX]; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct usb_gadget gadget; @@ -596,6 +599,7 @@ struct dwc3 { int irq; + u32 num_event_buffers; u32 maximum_speed; u32 revision; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 807737aec00e..b84418e88774 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1925,7 +1925,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) spin_lock(&dwc->lock); - for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { + for (i = 0; i < dwc->num_event_buffers; i++) { irqreturn_t status; status = dwc3_process_event_buf(dwc, i); -- cgit v1.2.3 From 0949e99b05736946cf0ac78e37194be0807e497e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Oct 2011 10:44:56 +0300 Subject: usb: dwc3: fetch mode of operation from HW There's no need to add driver_data for something we can fetch from HW. This also makes our id_table unnecessary - at least for now -, so we also remove it on the same patch. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 57 +++++++++++++++++++++++++------------------- drivers/usb/dwc3/core.h | 11 +++++++++ drivers/usb/dwc3/dwc3-omap.c | 2 +- drivers/usb/dwc3/dwc3-pci.c | 4 ++-- 4 files changed, 46 insertions(+), 28 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1f67606fd4fb..df151992e49d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -325,15 +325,17 @@ static void dwc3_core_exit(struct dwc3 *dwc) static int __devinit dwc3_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); struct resource *res; struct dwc3 *dwc; - void __iomem *regs; - unsigned int features = id->driver_data; + int ret = -ENOMEM; int irq; + + void __iomem *regs; void *mem; + u8 mode; + mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(&pdev->dev, "not enough memory\n"); @@ -396,13 +398,22 @@ static int __devinit dwc3_probe(struct platform_device *pdev) goto err3; } - if (features & DWC3_HAS_PERIPHERAL) { + mode = DWC3_MODE(dwc->hwparams.hwparams0); + + switch (mode) { + case DWC3_MODE_DRD: + case DWC3_MODE_DEVICE: ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialized gadget\n"); + dev_err(&pdev->dev, "failed to initialize gadget\n"); goto err4; } + break; + default: + dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); + goto err4; } + dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { @@ -415,8 +426,15 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return 0; err5: - if (features & DWC3_HAS_PERIPHERAL) + switch (mode) { + case DWC3_MODE_DRD: + case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); + break; + default: + /* do nothing */ + break; + } err4: dwc3_core_exit(dwc); @@ -436,10 +454,8 @@ err0: static int __devexit dwc3_remove(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); struct dwc3 *dwc = platform_get_drvdata(pdev); struct resource *res; - unsigned int features = id->driver_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -448,8 +464,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); - if (features & DWC3_HAS_PERIPHERAL) + switch (dwc->mode) { + case DWC3_MODE_DRD: + case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); + break; + default: + /* do nothing */ + break; + } dwc3_core_exit(dwc); release_mem_region(res->start, resource_size(res)); @@ -459,28 +482,12 @@ static int __devexit dwc3_remove(struct platform_device *pdev) return 0; } -static const struct platform_device_id dwc3_id_table[] __devinitconst = { - { - .name = "dwc3-omap", - .driver_data = (DWC3_HAS_PERIPHERAL - | DWC3_HAS_XHCI - | DWC3_HAS_OTG), - }, - { - .name = "dwc3-pci", - .driver_data = DWC3_HAS_PERIPHERAL, - }, - { }, /* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(platform, dwc3_id_table); - static struct platform_driver dwc3_driver = { .probe = dwc3_probe, .remove = __devexit_p(dwc3_remove), .driver = { .name = "dwc3", }, - .id_table = dwc3_id_table, }; MODULE_AUTHOR("Felipe Balbi "); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4b6c673ed608..a3ef8f34bf77 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -536,6 +536,15 @@ struct dwc3_hwparams { u32 hwparams8; }; +/* HWPARAMS0 */ +#define DWC3_MODE(n) ((n) & 0x7) + +#define DWC3_MODE_DEVICE 0 +#define DWC3_MODE_HOST 1 +#define DWC3_MODE_DRD 2 +#define DWC3_MODE_HUB 3 + +/* HWPARAMS1 */ #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) /** @@ -560,6 +569,7 @@ struct dwc3_hwparams { * @num_event_buffers: calculated number of event buffers * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents + * @mode: mode of operation * @is_selfpowered: true when we are selfpowered * @three_stage_setup: set if we perform a three phase setup * @ep0_status_pending: ep0 status response without a req is pending @@ -602,6 +612,7 @@ struct dwc3 { u32 num_event_buffers; u32 maximum_speed; u32 revision; + u32 mode; #define DWC3_REVISION_173A 0x5533173a #define DWC3_REVISION_175A 0x5533175a diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 062552b5fc8a..7bcf6775a1a1 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -236,7 +236,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) goto err1; } - dwc3 = platform_device_alloc("dwc3-omap", -1); + dwc3 = platform_device_alloc("dwc3", -1); if (!dwc3) { dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); goto err2; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f77c00042685..193f1bd90d59 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -118,7 +118,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, if (devid < 0) goto err2; - dwc3 = platform_device_alloc("dwc3-pci", devid); + dwc3 = platform_device_alloc("dwc3", devid); if (!dwc3) { dev_err(&pci->dev, "couldn't allocate dwc3 device\n"); goto err3; @@ -196,7 +196,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); static struct pci_driver dwc3_pci_driver = { - .name = "pci-dwc3", + .name = "dwc3-pci", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = __devexit_p(dwc3_pci_remove), -- cgit v1.2.3 From d07e8819a03dc2d1f03f725194ae56544e6c680b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Oct 2011 14:08:26 +0300 Subject: usb: dwc3: add xHCI Host support The Designware USB3 IP can be configured with an internal xHCI. If we're running on such a version, let's start the xHCI stack. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/Kconfig | 1 + drivers/usb/dwc3/Makefile | 2 + drivers/usb/dwc3/core.c | 39 ++++++++++++++-- drivers/usb/dwc3/core.h | 9 ++++ drivers/usb/dwc3/host.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 drivers/usb/dwc3/host.c (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 3c1d67d324fd..2c05ec9cf352 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -2,6 +2,7 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) select USB_OTG_UTILS + select USB_XHCI_PLATFORM help Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 593d1dbc465b..0926e71142b9 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -4,11 +4,13 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG obj-$(CONFIG_USB_DWC3) += dwc3.o dwc3-y := core.o +dwc3-y += host.o ifneq ($(CONFIG_USB_GADGET_DWC3),) dwc3-y += gadget.o ep0.o endif + ifneq ($(CONFIG_DEBUG_FS),) dwc3-y += debugfs.o endif diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index df151992e49d..410835e28cf6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -350,6 +350,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev) goto err1; } + dwc->res = res; + res = request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev)); if (!res) { @@ -401,8 +403,27 @@ static int __devinit dwc3_probe(struct platform_device *pdev) mode = DWC3_MODE(dwc->hwparams.hwparams0); switch (mode) { - case DWC3_MODE_DRD: case DWC3_MODE_DEVICE: + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize gadget\n"); + goto err4; + } + break; + case DWC3_MODE_HOST: + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize host\n"); + goto err4; + } + break; + case DWC3_MODE_DRD: + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize host\n"); + goto err4; + } + ret = dwc3_gadget_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize gadget\n"); @@ -427,10 +448,16 @@ static int __devinit dwc3_probe(struct platform_device *pdev) err5: switch (mode) { - case DWC3_MODE_DRD: case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; + case DWC3_MODE_HOST: + dwc3_host_exit(dwc); + break; + case DWC3_MODE_DRD: + dwc3_host_exit(dwc); + dwc3_gadget_exit(dwc); + break; default: /* do nothing */ break; @@ -465,10 +492,16 @@ static int __devexit dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); switch (dwc->mode) { - case DWC3_MODE_DRD: case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; + case DWC3_MODE_HOST: + dwc3_host_exit(dwc); + break; + case DWC3_MODE_DRD: + dwc3_host_exit(dwc); + dwc3_gadget_exit(dwc); + break; default: /* do nothing */ break; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a3ef8f34bf77..a77554373224 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -560,6 +561,7 @@ struct dwc3_hwparams { * @ep0_bounce_addr: dma address of ep0_bounce * @lock: for synchronizing * @dev: pointer to our struct device + * @xhci: pointer to our xHCI child * @event_buffer_list: a list of event buffers * @gadget: device side representation of the peripheral controller * @gadget_driver: pointer to the gadget driver @@ -598,6 +600,9 @@ struct dwc3 { spinlock_t lock; struct device *dev; + struct platform_device *xhci; + struct resource *res; + struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_MAX]; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; @@ -782,4 +787,8 @@ union dwc3_event { #define DWC3_HAS_XHCI BIT(1) #define DWC3_HAS_OTG BIT(3) +/* prototypes */ +int dwc3_host_init(struct dwc3 *dwc); +void dwc3_host_exit(struct dwc3 *dwc); + #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c new file mode 100644 index 000000000000..9b300a26fceb --- /dev/null +++ b/drivers/usb/dwc3/host.c @@ -0,0 +1,116 @@ +/** + * host.c - DesignWare USB3 DRD Controller Host Glue + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Felipe Balbi , + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "io.h" + +#include "debug.h" + +static struct resource generic_resources[] = { + { + .flags = IORESOURCE_IRQ, + }, + { + .flags = IORESOURCE_MEM, + }, +}; + +int dwc3_host_init(struct dwc3 *dwc) +{ + struct platform_device *xhci; + int ret; + + xhci = platform_device_alloc("xhci", -1); + if (!xhci) { + dev_err(dwc->dev, "couldn't allocate xHCI device\n"); + ret = -ENOMEM; + goto err0; + } + + dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); + + xhci->dev.parent = dwc->dev; + xhci->dev.dma_mask = dwc->dev->dma_mask; + xhci->dev.dma_parms = dwc->dev->dma_parms; + + dwc->xhci = xhci; + + /* setup resources */ + generic_resources[0].start = dwc->irq; + + generic_resources[1].start = dwc->res->start; + generic_resources[1].end = dwc->res->start + 0x7fff; + + ret = platform_device_add_resources(xhci, generic_resources, + ARRAY_SIZE(generic_resources)); + if (ret) { + dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); + goto err1; + } + + ret = platform_device_add(xhci); + if (ret) { + dev_err(dwc->dev, "failed to register xHCI device\n"); + goto err1; + } + + return 0; + +err1: + platform_device_put(xhci); + +err0: + return ret; +} + +void dwc3_host_exit(struct dwc3 *dwc) +{ + platform_device_unregister(dwc->xhci); +} -- cgit v1.2.3 From 7ae4fc4dc835033067096639bd26416b3df744c7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Oct 2011 19:39:50 +0200 Subject: usb: dwc3: add a platform device alias We can have three modules here: dwc3.ko, dwc3-omap.ko and dwc3-pci.ko. The later have already ids-aliases for probing and is fine. The omap module has alias for DT but lacks alias for the "native" platform_device. Maybe we should get rid of it and stick to the DT name? Both glue modules create a new device for which the dwc3.ko module is responsible and that one lacks the platform alias. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 1 + drivers/usb/dwc3/dwc3-omap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 410835e28cf6..d55d84db2be7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -523,6 +523,7 @@ static struct platform_driver dwc3_driver = { }, }; +MODULE_ALIAS("platform:dwc3"); MODULE_AUTHOR("Felipe Balbi "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 7bcf6775a1a1..0bdc5e9095b7 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -384,6 +384,7 @@ static struct platform_driver dwc3_omap_driver = { }, }; +MODULE_ALIAS("platform:omap-dwc3"); MODULE_AUTHOR("Felipe Balbi "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); -- cgit v1.2.3 From 8300dd236e957429acfb36be0ce8fe276dbe823c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 18 Oct 2011 13:54:01 +0300 Subject: usb: dwc3: move dwc3 device ID bitmap to core.c if we want to support situations where we have both SoC and PCIe versions of the IP on the same platform, we need to have sequential numbers between them, otherwise we will still have name collisions. Because of that, we need to move dwc3_get/put_device_id() to core.c and export that symbol to be used by glue layers. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/dwc3-pci.c | 45 +++++---------------------------------------- 3 files changed, 50 insertions(+), 40 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d55d84db2be7..83e382b4ae28 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -63,6 +63,48 @@ static char *maximum_speed = "super"; module_param(maximum_speed, charp, 0); MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); +/* -------------------------------------------------------------------------- */ + +#define DWC3_DEVS_POSSIBLE 32 + +static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); + +int dwc3_get_device_id(void) +{ + int id; + +again: + id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); + if (id < DWC3_DEVS_POSSIBLE) { + int old; + + old = test_and_set_bit(id, dwc3_devs); + if (old) + goto again; + } else { + pr_err("dwc3: no space for new device\n"); + id = -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(dwc3_get_device_id); + +void dwc3_put_device_id(int id) +{ + int ret; + + if (id < 0) + return; + + ret = test_bit(id, dwc3_devs); + WARN(!ret, "dwc3: ID %d not in use\n", id); + clear_bit(id, dwc3_devs); +} +EXPORT_SYMBOL_GPL(dwc3_put_device_id); + +/* -------------------------------------------------------------------------- */ + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index bebb5e1530a0..95d5a87b4091 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -793,4 +793,7 @@ void dwc3_host_exit(struct dwc3 *dwc); int dwc3_gadget_init(struct dwc3 *dwc); void dwc3_gadget_exit(struct dwc3 *dwc); +extern int dwc3_get_device_id(void); +extern void dwc3_put_device_id(int id); + #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 193f1bd90d59..cd1429f168c2 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -42,52 +42,17 @@ #include #include +#include "core.h" + /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd -#define DWC3_PCI_DEVS_POSSIBLE 32 - struct dwc3_pci { struct device *dev; struct platform_device *dwc3; }; -static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); - -static int dwc3_pci_get_device_id(struct dwc3_pci *glue) -{ - int id; - -again: - id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); - if (id < DWC3_PCI_DEVS_POSSIBLE) { - int old; - - old = test_and_set_bit(id, dwc3_pci_devs); - if (old) - goto again; - } else { - dev_err(glue->dev, "no space for new device\n"); - id = -ENOMEM; - } - - return 0; -} - -static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id) -{ - int ret; - - if (id < 0) - return; - - ret = test_bit(id, dwc3_pci_devs); - WARN(!ret, "Device: %s\nID %d not in use\n", - dev_driver_string(glue->dev), id); - clear_bit(id, dwc3_pci_devs); -} - static int __devinit dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) { @@ -114,7 +79,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, pci_set_power_state(pci, PCI_D0); pci_set_master(pci); - devid = dwc3_pci_get_device_id(glue); + devid = dwc3_get_device_id(); if (devid < 0) goto err2; @@ -163,7 +128,7 @@ err4: platform_device_put(dwc3); err3: - dwc3_pci_put_device_id(glue, devid); + dwc3_put_device_id(devid); err2: pci_disable_device(pci); @@ -179,7 +144,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci) { struct dwc3_pci *glue = pci_get_drvdata(pci); - dwc3_pci_put_device_id(glue, glue->dwc3->id); + dwc3_put_device_id(glue->dwc3->id); platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); pci_disable_device(pci); -- cgit v1.2.3 From 457d3f214f97783c392dd4d64e2427c121b1a4d6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 24 Oct 2011 12:03:13 +0300 Subject: usb: dwc3: core: drop DWC3_EVENT_BUFFERS_MAX hardware will tell us how many event buffers we need to support, so let's allocate the array dynamically too. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 83e382b4ae28..a2db41162575 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -221,6 +221,12 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) num = DWC3_NUM_INT(dwc->hwparams.hwparams1); dwc->num_event_buffers = num; + dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); + if (!dwc->ev_buffs) { + dev_err(dwc->dev, "can't allocate event buffers array\n"); + return -ENOMEM; + } + for (i = 0; i < num; i++) { struct dwc3_event_buffer *evt; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 95d5a87b4091..d6f1b793cd04 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -53,7 +53,6 @@ /* Global constants */ #define DWC3_ENDPOINTS_NUM 32 -#define DWC3_EVENT_BUFFERS_MAX 2 #define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE #define DWC3_EVENT_TYPE_MASK 0xfe @@ -603,7 +602,7 @@ struct dwc3 { struct platform_device *xhci; struct resource *res; - struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_MAX]; + struct dwc3_event_buffer **ev_buffs; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct usb_gadget gadget; -- cgit v1.2.3 From 3140e8cbfec18ecb9c9ef856933fdb98c09af1e8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 31 Oct 2011 22:25:40 +0100 Subject: usb: dwc3: use a helper function for operation mode setting There are two where need to set operational mode: - during initialization while we decide to run in host,device or DRD mode - at runtime via the debugfs interface. This patch provides a new function which sets the operational mode and moves its initialiation to the mode switch instead in the gadget code itself. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 13 ++++++++++++- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/debugfs.c | 21 +++++++++------------ drivers/usb/dwc3/gadget.c | 2 -- 4 files changed, 23 insertions(+), 15 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a2db41162575..217547514faa 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -103,7 +103,15 @@ void dwc3_put_device_id(int id) } EXPORT_SYMBOL_GPL(dwc3_put_device_id); -/* -------------------------------------------------------------------------- */ +void dwc3_set_mode(struct dwc3 *dwc, u32 mode) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); + reg |= DWC3_GCTL_PRTCAPDIR(mode); + dwc3_writel(dwc->regs, DWC3_GCTL, reg); +} /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset @@ -452,6 +460,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) switch (mode) { case DWC3_MODE_DEVICE: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize gadget\n"); @@ -459,6 +468,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) } break; case DWC3_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); @@ -466,6 +476,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) } break; case DWC3_MODE_DRD: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d6f1b793cd04..cecff5624af3 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -786,6 +786,8 @@ union dwc3_event { #define DWC3_HAS_OTG BIT(3) /* prototypes */ +void dwc3_set_mode(struct dwc3 *dwc, u32 mode); + int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index b5370e781500..ca4be0afc33d 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -443,29 +443,26 @@ static ssize_t dwc3_mode_write(struct file *file, struct seq_file *s = file->private_data; struct dwc3 *dwc = s->private; unsigned long flags; - u32 reg; + u32 mode = 0; char buf[32]; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; - spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - - reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); - if (!strncmp(buf, "host", 4)) - reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_HOST); + mode |= DWC3_GCTL_PRTCAP_HOST; if (!strncmp(buf, "device", 6)) - reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_DEVICE); + mode |= DWC3_GCTL_PRTCAP_DEVICE; if (!strncmp(buf, "otg", 3)) - reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_OTG); - - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - spin_unlock_irqrestore(&dwc->lock, flags); + mode |= DWC3_GCTL_PRTCAP_OTG; + if (mode) { + spin_lock_irqsave(&dwc->lock, flags); + dwc3_set_mode(dwc, mode); + spin_unlock_irqrestore(&dwc->lock, flags); + } return count; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b84418e88774..fab4ee0082e2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1158,9 +1158,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN(3); - reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG); reg &= ~DWC3_GCTL_DISSCRAMBLE; - reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { case DWC3_GHWPARAMS1_EN_PWROPT_CLK: -- cgit v1.2.3 From 4878a02898bab1a988206341e529997cb46e5f29 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 31 Oct 2011 22:25:41 +0100 Subject: usb: dwc3: move generic dwc3 code from gadget into core A few inits like the scale value or the removal of the DISSCRAMBLE is done in the gadget code however it touches a general register. Move this piece to the core.c file since it is likely to be requied by both, parts of the core (device and host). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 23 +++++++++++++++++++++++ drivers/usb/dwc3/gadget.c | 24 ------------------------ 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 217547514faa..6910a2d14d93 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -349,6 +349,29 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) dwc3_cache_hwparams(dwc); + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + reg &= ~DWC3_GCTL_SCALEDOWN(3); + reg &= ~DWC3_GCTL_DISSCRAMBLE; + + switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { + case DWC3_GHWPARAMS1_EN_PWROPT_CLK: + reg &= ~DWC3_GCTL_DSBLCLKGTNG; + break; + default: + dev_dbg(dwc->dev, "No power optimization available\n"); + } + + /* + * WORKAROUND: DWC3 revisions <1.90a have a bug + * when The device fails to connect at SuperSpeed + * and falls back to high-speed mode which causes + * the device to enter in a Connect/Disconnect loop + */ + if (dwc->revision < DWC3_REVISION_190A) + reg |= DWC3_GCTL_U2RSTECN; + + dwc3_writel(dwc->regs, DWC3_GCTL, reg); + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fab4ee0082e2..8aff490a1ae1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1155,30 +1155,6 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->gadget_driver = driver; dwc->gadget.dev.driver = &driver->driver; - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - - reg &= ~DWC3_GCTL_SCALEDOWN(3); - reg &= ~DWC3_GCTL_DISSCRAMBLE; - - switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { - case DWC3_GHWPARAMS1_EN_PWROPT_CLK: - reg &= ~DWC3_GCTL_DSBLCLKGTNG; - break; - default: - dev_dbg(dwc->dev, "No power optimization available\n"); - } - - /* - * WORKAROUND: DWC3 revisions <1.90a have a bug - * when The device fails to connect at SuperSpeed - * and falls back to high-speed mode which causes - * the device to enter in a Connect/Disconnect loop - */ - if (dwc->revision < DWC3_REVISION_190A) - reg |= DWC3_GCTL_U2RSTECN; - - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); reg |= dwc->maximum_speed; -- cgit v1.2.3 From 164d773168d7f09ecd46d9ce9b07f194ea97bf33 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 24 Nov 2011 11:22:05 +0100 Subject: usb: dwc3: use correct hwparam register for power mgm check We mask the correct bits within the wrong register. The power optimization mode is stored hwparam1 register and not in hwparam0. Reported-by: Partha Basak Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6910a2d14d93..455bb1e748d7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -353,7 +353,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) reg &= ~DWC3_GCTL_SCALEDOWN(3); reg &= ~DWC3_GCTL_DISSCRAMBLE; - switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { + switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { case DWC3_GHWPARAMS1_EN_PWROPT_CLK: reg &= ~DWC3_GCTL_DSBLCLKGTNG; break; -- cgit v1.2.3 From 248b122b131202de95aaa3670e48465619bdff14 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Dec 2011 21:59:30 +0200 Subject: usb: dwc3: core: fix cached revision on our structure All our revision macros are defined with the entire 32-bits which we read from GSNPSID register, so we must cache all 32-bits properly rather than masking the top 16-bits. This will fix all revision checks we have on current driver. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/core.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 717ebc9ff941..600d82348511 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -264,7 +264,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) ret = -ENODEV; goto err0; } - dwc->revision = reg & DWC3_GSNPSREV_MASK; + dwc->revision = reg; dwc3_core_soft_reset(dwc); -- cgit v1.2.3