diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r-- | drivers/usb/dwc3/core.c | 751 |
1 files changed, 517 insertions, 234 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 30aaef90ac..8e6dc59a5d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0-only -/** +// SPDX-License-Identifier: GPL-2.0 +/* * core.c - DesignWare USB3 DRD Controller Core file * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -16,18 +16,14 @@ #include <init.h> #include <linux/reset.h> -#include "gadget.h" #include "core.h" +#include "gadget.h" #include "io.h" +#include "debug.h" #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ -struct dwc3_match_data { - const struct clk_bulk_data *clks; - const int num_clks; -}; - /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure @@ -35,7 +31,7 @@ struct dwc3_match_data { static int dwc3_get_dr_mode(struct dwc3 *dwc) { enum usb_dr_mode mode; - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; unsigned int hw_mode; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) @@ -72,8 +68,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) * mode. If the controller supports DRD but the dr_mode is not * specified or set to OTG, then set the mode to peripheral. */ - if (mode == USB_DR_MODE_OTG && - dwc->revision >= DWC3_REVISION_330A) + if (mode == USB_DR_MODE_OTG && !dwc->edev && + (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) || + !of_property_read_bool(dwc->dev->of_node, "usb-role-switch")) && + !DWC3_VER_IS_PRIOR(DWC3, 330A)) mode = USB_DR_MODE_PERIPHERAL; } @@ -100,25 +98,28 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) +{ + struct dwc3 *dwc = dep->dwc; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, + DWC3_GDBGFIFOSPACE_NUM(dep->number) | + DWC3_GDBGFIFOSPACE_TYPE(type)); + + reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); + + return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); +} + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ -static int dwc3_core_soft_reset(struct dwc3 *dwc) +int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; int retries = 1000; - int ret; - - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - return ret; - - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) { - phy_exit(dwc->usb2_generic_phy); - return ret; - } /* * We're resetting only the device side because, if we're in host mode, @@ -130,33 +131,94 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); + reg &= ~DWC3_DCTL_RUN_STOP; + dwc3_gadget_dctl_write_safe(dwc, reg); + + /* + * For DWC_usb31 controller 1.90a and later, the DCTL.CSFRST bit + * is cleared only after all the clocks are synchronized. This can + * take a little more than 50ms. Set the polling rate at 20ms + * for 10 times instead. + */ + if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) + retries = 10; do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) goto done; - udelay(1); + if (DWC3_VER_IS_WITHIN(DWC31, 190A, ANY) || DWC3_IP_IS(DWC32)) + mdelay(20); + else + udelay(1); } while (--retries); - phy_exit(dwc->usb3_generic_phy); - phy_exit(dwc->usb2_generic_phy); - + dev_warn(dwc->dev, "DWC3 controller soft reset failed.\n"); return -ETIMEDOUT; done: /* - * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared, - * we must wait at least 50ms before accessing the PHY domain - * (synchronization delay). DWC_usb31 programming guide section 1.3.2. + * For DWC_usb31 controller 1.80a and prior, once DCTL.CSFRST bit + * is cleared, we must wait at least 50ms before accessing the PHY + * domain (synchronization delay). */ - if (dwc3_is_usb31(dwc)) + if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A)) mdelay(50); return 0; } +/* + * dwc3_frame_length_adjustment - Adjusts frame length if required + * @dwc3: Pointer to our controller context structure + */ +static void dwc3_frame_length_adjustment(struct dwc3 *dwc) +{ + u32 reg; + u32 dft; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + if (dwc->fladj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + if (dft != dwc->fladj) { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); + } +} + +/** + * dwc3_ref_clk_period - Reference clock period configuration + * Default reference clock period depends on hardware + * configuration. For systems with reference clock that differs + * from the default, this will set clock period in DWC3_GUCTL + * register. + * @dwc: Pointer to our controller context structure + */ +static void dwc3_ref_clk_period(struct dwc3 *dwc) +{ + u32 reg; + u32 dft; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + if (dwc->fladj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); +} + /** * dwc3_free_one_event_buffer - Frees one event buffer * @dwc: Pointer to our controller context structure @@ -165,7 +227,7 @@ done: static void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt) { - dma_free_coherent(evt->buf, 0, sizeof(dma_addr_t)); + dma_free_coherent(evt->buf, evt->dma, evt->length); } /** @@ -177,16 +239,20 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, * otherwise ERR_PTR(errno). */ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, - unsigned length) + unsigned int length) { struct dwc3_event_buffer *evt; - evt = xzalloc(sizeof(*evt)); + evt = kzalloc(sizeof(*evt), GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); evt->dwc = dwc; evt->length = length; + evt->cache = kzalloc(length, GFP_KERNEL); + if (!evt->cache) + return ERR_PTR(-ENOMEM); + evt->buf = dma_alloc_coherent(length, &evt->dma); if (!evt->buf) return ERR_PTR(-ENOMEM); @@ -215,7 +281,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) * Returns 0 on success otherwise negative errno. In the error case, dwc * may contain some buffers allocated but not all which were requested. */ -static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) +static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length) { struct dwc3_event_buffer *evt; @@ -235,7 +301,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) * * Returns 0 on success otherwise negative errno. */ -static int dwc3_event_buffers_setup(struct dwc3 *dwc) +int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; @@ -252,8 +318,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) return 0; } - -static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) +void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; @@ -296,11 +361,15 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) if (!dwc->nr_scratch) return 0; - scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf, - dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dwc->dev, scratch_addr)) { - dev_err(dwc->dev, "failed to map scratch buffer\n"); + /* should never fall here */ + if (!WARN_ON(dwc->scratchbuf)) + return 0; + + scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf, + dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dwc->sysdev, scratch_addr)) { + dev_err(dwc->sysdev, "failed to map scratch buffer\n"); ret = -EFAULT; goto err0; } @@ -324,33 +393,28 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) return 0; err1: - dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * + DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); err0: return ret; } -/* - * dwc3_frame_length_adjustment - Adjusts frame length if required - * @dwc3: Pointer to our controller context structure - */ -static void dwc3_frame_length_adjustment(struct dwc3 *dwc) +static void dwc3_free_scratch_buffers(struct dwc3 *dwc) { - u32 reg; - u32 dft; + if (!dwc->has_hibernation) + return; - if (dwc->revision < DWC3_REVISION_250A) + if (!dwc->nr_scratch) return; - if (dwc->fladj == 0) + /* should never fall here */ + if (!WARN_ON(dwc->scratchbuf)) return; - reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); - dft = reg & DWC3_GFLADJ_30MHZ_MASK; - reg &= ~DWC3_GFLADJ_30MHZ_MASK; - reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; - dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); + dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * + DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + kfree(dwc->scratchbuf); } static void dwc3_core_num_eps(struct dwc3 *dwc) @@ -373,6 +437,9 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); + + if (DWC3_IP_IS(DWC32)) + parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9); } static int dwc3_core_ulpi_init(struct dwc3 *dwc) @@ -401,8 +468,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) */ static int dwc3_phy_setup(struct dwc3 *dwc) { + unsigned int hw_mode; u32 reg; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); /* @@ -417,9 +487,17 @@ static int dwc3_phy_setup(struct dwc3 *dwc) * will be '0' when the core is reset. Application needs to set it * to '1' after the core initialization is completed. */ - if (dwc->revision > DWC3_REVISION_194A) + if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB3PIPECTL_SUSPHY; + /* + * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; @@ -470,9 +548,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) break; } - /* FALLTHROUGH */ + fallthrough; case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: - /* FALLTHROUGH */ default: break; } @@ -500,9 +577,17 @@ static int dwc3_phy_setup(struct dwc3 *dwc) * be '0' when the core is reset. Application needs to set it to * '1' after the core initialization is completed. */ - if (dwc->revision > DWC3_REVISION_194A) + if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB2PHYCFG_SUSPHY; + /* + * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; @@ -511,7 +596,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) else reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; - if (dwc->dis_u2_freeclk_exists_quirk) + if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); @@ -523,14 +608,17 @@ static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); phy_power_off(dwc->usb2_generic_phy); phy_power_off(dwc->usb3_generic_phy); - clk_bulk_disable(dwc->num_clks, dwc->clks); - dwc3_free_event_buffers(dwc); + usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy); + phy_exit(dwc->usb2_generic_phy); + phy_exit(dwc->usb3_generic_phy); + + reset_control_assert(dwc->reset); } static bool dwc3_core_is_valid(struct dwc3 *dwc) @@ -538,15 +626,13 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); + dwc->ip = DWC3_GSNPS_ID(reg); /* This should read as U3 followed by revision number */ - if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) { - /* Detected DWC_usb3 IP */ + if (DWC3_IP_IS(DWC3)) { dwc->revision = reg; - } else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) { - /* Detected DWC_usb31 IP */ + } else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) { dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); - dwc->revision |= DWC3_REVISION_IS_DWC31; dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE); } else { return false; @@ -579,8 +665,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) */ if ((dwc->dr_mode == USB_DR_MODE_HOST || dwc->dr_mode == USB_DR_MODE_OTG) && - (dwc->revision >= DWC3_REVISION_210A && - dwc->revision <= DWC3_REVISION_250A)) + DWC3_VER_IS_WITHIN(DWC3, 210A, 250A)) reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; else reg &= ~DWC3_GCTL_DSBLCLKGTNG; @@ -606,8 +691,8 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) dwc->is_fpga = true; } - WARN(dwc->disable_scramble_quirk && !dwc->is_fpga, - "disable_scramble cannot be used on non-FPGA builds\n"); + WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga, + "disable_scramble cannot be used on non-FPGA builds\n"); if (dwc->disable_scramble_quirk && dwc->is_fpga) reg |= DWC3_GCTL_DISSCRAMBLE; @@ -623,25 +708,26 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) * and falls back to high-speed mode which causes * the device to enter a Connect/Disconnect loop */ - if (dwc->revision < DWC3_REVISION_190A) + if (DWC3_VER_IS_PRIOR(DWC3, 190A)) reg |= DWC3_GCTL_U2RSTECN; dwc3_writel(dwc->regs, DWC3_GCTL, reg); } static int dwc3_core_get_phy(struct dwc3 *dwc); +static int dwc3_core_ulpi_init(struct dwc3 *dwc); /* set global incr burst type configuration registers */ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) { - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; /* incrx_mode : for INCR burst type. */ bool incrx_mode; /* incrx_size : for size of INCRX burst. */ u32 incrx_size; u32 *vals; u32 cfg; - int ntype = 0; + int ntype; int ret; int i; @@ -654,24 +740,19 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) * result = 1, means INCRx burst mode supported. * result > 1, means undefined length burst mode supported. */ - of_find_property(dev->device_node, "snps,incr-burst-type-adjustment", - &ntype); - - ntype /= sizeof(u32); - + ntype = of_property_count_elems_of_size(dev->of_node, + "snps,incr-burst-type-adjustment", + sizeof(u32)); if (ntype <= 0) return; vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL); - if (!vals) { - dev_err(dev, "Error to get memory\n"); + if (!vals) return; - } /* Get INCR burst type, and parse it */ - ret = of_property_read_u32_array(dev->device_node, - "snps,incr-burst-type-adjustment", - vals, ntype); + ret = of_property_read_u32_array(dev->of_node, + "snps,incr-burst-type-adjustment", vals, ntype); if (ret) { kfree(vals); dev_err(dev, "Error to get property\n"); @@ -738,14 +819,11 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) */ static int dwc3_core_init(struct dwc3 *dwc) { + unsigned int hw_mode; u32 reg; int ret; - if (!dwc3_core_is_valid(dwc)) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto err0; - } + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); /* * Write Linux Version Code to our GUID register so it's easy to figure @@ -753,21 +831,19 @@ static int dwc3_core_init(struct dwc3 *dwc) */ dwc3_writel(dwc->regs, DWC3_GUID, 0xdeadbeef); - /* Handle USB2.0-only core configuration */ - if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == - DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { - if (dwc->maximum_speed == USB_SPEED_SUPER) - dwc->maximum_speed = USB_SPEED_HIGH; - } - ret = dwc3_phy_setup(dwc); if (ret) goto err0; if (!dwc->ulpi_ready) { ret = dwc3_core_ulpi_init(dwc); - if (ret) + if (ret) { + if (ret == -ETIMEDOUT) { + dwc3_core_soft_reset(dwc); + ret = -EPROBE_DEFER; + } goto err0; + } dwc->ulpi_ready = true; } @@ -778,34 +854,66 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->phys_ready = true; } + usb_phy_init(dwc->usb2_phy); + usb_phy_init(dwc->usb3_phy); + ret = phy_init(dwc->usb2_generic_phy); + if (ret < 0) + goto err0a; + + ret = phy_init(dwc->usb3_generic_phy); + if (ret < 0) { + phy_exit(dwc->usb2_generic_phy); + goto err0a; + } + ret = dwc3_core_soft_reset(dwc); if (ret) - goto err0a; + goto err1; + + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && + !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { + if (!dwc->dis_u3_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + } + + if (!dwc->dis_u2_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + } dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); ret = dwc3_setup_scratch_buffers(dwc); if (ret) - goto err0a; + goto err1; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); + /* Adjust Reference Clock Period */ + dwc3_ref_clk_period(dwc); + dwc3_set_incr_burst_type(dwc); + usb_phy_set_suspend(dwc->usb2_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) - goto err1; + goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) - goto err2; + goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err3; + goto err4; } /* @@ -813,25 +921,57 @@ static int dwc3_core_init(struct dwc3 *dwc) * the DWC_usb3 controller. It is NOT available in the * DWC_usb31 controller. */ - if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); reg |= DWC3_GUCTL2_RST_ACTBITLATER; dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); } - if (dwc->revision >= DWC3_REVISION_250A) { + /* + * When configured in HOST mode, after issuing U3/L2 exit controller + * fails to send proper CRC checksum in CRC5 feild. Because of this + * behaviour Transaction Error is generated, resulting in reset and + * re-enumeration of usb device attached. All the termsel, xcvrsel, + * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1 + * will correct this problem. This option is to support certain + * legacy ULPI PHYs. + */ + if (dwc->resume_hs_terminations) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); + reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST; + dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); + } + + if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); /* * Enable hardware control of sending remote wakeup * in HS when the device is in the L1 state. */ - if (dwc->revision >= DWC3_REVISION_290A) + if (!DWC3_VER_IS_PRIOR(DWC3, 290A)) reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW; + /* + * Decouple USB 2.0 L1 & L2 events which will allow for + * gadget driver to only receive U3/L2 suspend & wakeup + * events and prevent the more frequent L1 LPM transitions + * from interrupting the driver. + */ + if (!DWC3_VER_IS_PRIOR(DWC3, 300A)) + reg |= DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT; + if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; + if (dwc->parkmode_disable_ss_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; + + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && + (dwc->maximum_speed == USB_SPEED_HIGH || + dwc->maximum_speed == USB_SPEED_FULL)) + reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } @@ -855,7 +995,7 @@ static int dwc3_core_init(struct dwc3 *dwc) * Must config both number of packets and max burst settings to enable * RX and/or TX threshold. */ - if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) { + if (!DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) { u8 rx_thr_num = dwc->rx_thr_num_pkt_prd; u8 rx_maxburst = dwc->rx_max_burst_prd; u8 tx_thr_num = dwc->tx_thr_num_pkt_prd; @@ -890,80 +1030,88 @@ static int dwc3_core_init(struct dwc3 *dwc) return 0; -err3: +err4: phy_power_off(dwc->usb3_generic_phy); -err2: + +err3: phy_power_off(dwc->usb2_generic_phy); + +err2: + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + err1: + usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); + err0a: + dwc3_ulpi_exit(dwc); + err0: return ret; } static int dwc3_core_get_phy(struct dwc3 *dwc) { - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; int ret; dwc->usb2_generic_phy = phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) { + if (ret == -ENOSYS || ret == -ENODEV) dwc->usb2_generic_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; - } else { - dev_err(dev, "no usb2 phy configured\n"); - return ret; - } + else + return dev_err_probe(dev, ret, "no usb2 phy configured\n"); } dwc->usb3_generic_phy = phy_get(dev, "usb3-phy"); if (IS_ERR(dwc->usb3_generic_phy)) { ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) { + if (ret == -ENOSYS || ret == -ENODEV) dwc->usb3_generic_phy = NULL; - } else if (ret == -EPROBE_DEFER) { - return ret; - } else { - dev_err(dev, "no usb3 phy configured\n"); - return ret; - } + else + return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } return 0; } -static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode) +static int dwc3_set_dr_mode(void *ctx, enum usb_dr_mode mode) { struct dwc3 *dwc = ctx; - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; int ret; switch (mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); +// if (dwc->usb2_phy) +// otg_set_vbus(dwc->usb2_phy->otg, false); + phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + ret = dwc3_gadget_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize gadget\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize gadget\n"); break; case USB_DR_MODE_HOST: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); +// if (dwc->usb2_phy) +// otg_set_vbus(dwc->usb2_phy->otg, true); + phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); + phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + ret = dwc3_host_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize host\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to initialize host\n"); break; default: + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } @@ -973,20 +1121,43 @@ static int dwc3_set_mode(void *ctx, enum usb_dr_mode mode) static int dwc3_core_init_mode(struct dwc3 *dwc) { if (dwc->dr_mode == USB_DR_MODE_OTG) - return usb_register_otg_device(dwc->dev, dwc3_set_mode, dwc); + return usb_register_otg_device(dwc->dev, dwc3_set_dr_mode, dwc); else - return dwc3_set_mode(dwc, dwc->dr_mode); + return dwc3_set_dr_mode(dwc, dwc->dr_mode); +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_gadget_exit(dwc); + break; + case USB_DR_MODE_HOST: + dwc3_host_exit(dwc); + break; + default: + /* do nothing */ + break; + } + + /* de-assert DRVVBUS for HOST and OTG mode */ + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); } static void dwc3_get_properties(struct dwc3 *dwc) { - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; + u8 rx_thr_num_pkt_prd = 0; + u8 rx_max_burst_prd = 0; + u8 tx_thr_num_pkt_prd = 0; + u8 tx_max_burst_prd = 0; + u8 tx_fifo_resize_max_num; /* default to highest possible threshold */ - lpm_nyet_threshold = 0xff; + lpm_nyet_threshold = 0xf; /* default to -3.5dB de-emphasis */ tx_de_emphasis = 1; @@ -997,39 +1168,142 @@ static void dwc3_get_properties(struct dwc3 *dwc) */ hird_threshold = 12; - dwc->maximum_speed = of_usb_get_maximum_speed(dev->device_node, NULL); - dwc->dr_mode = of_usb_get_dr_mode(dev->device_node, NULL); - dwc->hsphy_mode = of_usb_get_phy_mode(dev->device_node, NULL); + /* + * default to a TXFIFO size large enough to fit 6 max packets. This + * allows for systems with larger bus latencies to have some headroom + * for endpoints that have a large bMaxBurst value. + */ + tx_fifo_resize_max_num = 6; + + dwc->maximum_speed = of_usb_get_maximum_speed(dev->of_node, NULL); +// dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); + dwc->dr_mode = of_usb_get_dr_mode(dev->of_node, NULL); + dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node, NULL); + + dwc->sysdev_is_parent = of_property_read_bool(dev->of_node, + "linux,sysdev_is_parent"); + if (dwc->sysdev_is_parent) + dwc->sysdev = dwc->dev->parent; + else + dwc->sysdev = dwc->dev; + + dwc->has_lpm_erratum = of_property_read_bool(dev->of_node, + "snps,has-lpm-erratum"); + of_property_read_u8(dev->of_node, "snps,lpm-nyet-threshold", + &lpm_nyet_threshold); + dwc->is_utmi_l1_suspend = of_property_read_bool(dev->of_node, + "snps,is-utmi-l1-suspend"); + of_property_read_u8(dev->of_node, "snps,hird-threshold", + &hird_threshold); + dwc->dis_start_transfer_quirk = of_property_read_bool(dev->of_node, + "snps,dis-start-transfer-quirk"); + dwc->usb3_lpm_capable = of_property_read_bool(dev->of_node, + "snps,usb3_lpm_capable"); + dwc->usb2_lpm_disable = of_property_read_bool(dev->of_node, + "snps,usb2-lpm-disable"); + dwc->usb2_gadget_lpm_disable = of_property_read_bool(dev->of_node, + "snps,usb2-gadget-lpm-disable"); + of_property_read_u8(dev->of_node, "snps,rx-thr-num-pkt-prd", + &rx_thr_num_pkt_prd); + of_property_read_u8(dev->of_node, "snps,rx-max-burst-prd", + &rx_max_burst_prd); + of_property_read_u8(dev->of_node, "snps,tx-thr-num-pkt-prd", + &tx_thr_num_pkt_prd); + of_property_read_u8(dev->of_node, "snps,tx-max-burst-prd", + &tx_max_burst_prd); + dwc->do_fifo_resize = of_property_read_bool(dev->of_node, + "tx-fifo-resize"); + if (dwc->do_fifo_resize) + of_property_read_u8(dev->of_node, "tx-fifo-max-num", + &tx_fifo_resize_max_num); + + dwc->disable_scramble_quirk = of_property_read_bool(dev->of_node, + "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = of_property_read_bool(dev->of_node, + "snps,u2exit_lfps_quirk"); + dwc->u2ss_inp3_quirk = of_property_read_bool(dev->of_node, + "snps,u2ss_inp3_quirk"); + dwc->req_p1p2p3_quirk = of_property_read_bool(dev->of_node, + "snps,req_p1p2p3_quirk"); + dwc->del_p1p2p3_quirk = of_property_read_bool(dev->of_node, + "snps,del_p1p2p3_quirk"); + dwc->del_phy_power_chg_quirk = of_property_read_bool(dev->of_node, + "snps,del_phy_power_chg_quirk"); + dwc->lfps_filter_quirk = of_property_read_bool(dev->of_node, + "snps,lfps_filter_quirk"); + dwc->rx_detect_poll_quirk = of_property_read_bool(dev->of_node, + "snps,rx_detect_poll_quirk"); + dwc->dis_u3_susphy_quirk = of_property_read_bool(dev->of_node, + "snps,dis_u3_susphy_quirk"); + dwc->dis_u2_susphy_quirk = of_property_read_bool(dev->of_node, + "snps,dis_u2_susphy_quirk"); + dwc->dis_enblslpm_quirk = of_property_read_bool(dev->of_node, + "snps,dis_enblslpm_quirk"); + dwc->dis_u1_entry_quirk = of_property_read_bool(dev->of_node, + "snps,dis-u1-entry-quirk"); + dwc->dis_u2_entry_quirk = of_property_read_bool(dev->of_node, + "snps,dis-u2-entry-quirk"); + dwc->dis_rxdet_inp3_quirk = of_property_read_bool(dev->of_node, + "snps,dis_rxdet_inp3_quirk"); + dwc->dis_u2_freeclk_exists_quirk = of_property_read_bool(dev->of_node, + "snps,dis-u2-freeclk-exists-quirk"); + dwc->dis_del_phy_power_chg_quirk = of_property_read_bool(dev->of_node, + "snps,dis-del-phy-power-chg-quirk"); + dwc->dis_tx_ipgap_linecheck_quirk = of_property_read_bool(dev->of_node, + "snps,dis-tx-ipgap-linecheck-quirk"); + dwc->resume_hs_terminations = of_property_read_bool(dev->of_node, + "snps,resume-hs-terminations"); + dwc->parkmode_disable_ss_quirk = of_property_read_bool(dev->of_node, + "snps,parkmode-disable-ss-quirk"); + dwc->gfladj_refclk_lpm_sel = of_property_read_bool(dev->of_node, + "snps,gfladj-refclk-lpm-sel-quirk"); + + dwc->tx_de_emphasis_quirk = of_property_read_bool(dev->of_node, + "snps,tx_de_emphasis_quirk"); + of_property_read_u8(dev->of_node, "snps,tx_de_emphasis", + &tx_de_emphasis); + of_property_read_string(dev->of_node, "snps,hsphy_interface", + &dwc->hsphy_interface); + of_property_read_u32(dev->of_node, "snps,quirk-frame-length-adjustment", + &dwc->fladj); + of_property_read_u32(dev->of_node, "snps,ref-clock-period-ns", + &dwc->ref_clk_per); + + dwc->dis_metastability_quirk = of_property_read_bool(dev->of_node, + "snps,dis_metastability_quirk"); + + dwc->dis_split_quirk = of_property_read_bool(dev->of_node, + "snps,dis-split-quirk"); dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; - if (of_get_property(dev->device_node, "snps,dis_rxdet_inp3_quirk", - NULL)) - dwc->dis_rxdet_inp3_quirk = 1; + dwc->hird_threshold = hird_threshold; - of_property_read_u32_array(dev->device_node, - "snps,quirk-frame-length-adjustment", - &dwc->fladj, 1); + dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd; + dwc->rx_max_burst_prd = rx_max_burst_prd; - dwc->hird_threshold = hird_threshold - | (dwc->is_utmi_l1_suspend << 4); + dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; + dwc->tx_max_burst_prd = tx_max_burst_prd; dwc->imod_interval = 0; + + dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; } /* check whether the core supports IMOD */ bool dwc3_has_imod(struct dwc3 *dwc) { - return ((dwc3_is_usb3(dwc) && - dwc->revision >= DWC3_REVISION_300A) || - (dwc3_is_usb31(dwc) && - dwc->revision >= DWC3_USB31_REVISION_120A)); + return DWC3_VER_IS_WITHIN(DWC3, 300A, ANY) || + DWC3_VER_IS_WITHIN(DWC31, 120A, ANY) || + DWC3_IP_IS(DWC32); } static void dwc3_check_params(struct dwc3 *dwc) { - struct device_d *dev = dwc->dev; + struct device *dev = dwc->dev; + unsigned int hwparam_gen = + DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3); /* Check for proper value of imod_interval */ if (dwc->imod_interval && !dwc3_has_imod(dwc)) { @@ -1045,81 +1319,106 @@ static void dwc3_check_params(struct dwc3 *dwc) * affected version. */ if (!dwc->imod_interval && - (dwc->revision == DWC3_REVISION_300A)) + DWC3_VER_IS(DWC3, 300A)) dwc->imod_interval = 1; /* Check the maximum_speed parameter */ switch (dwc->maximum_speed) { - case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: + break; case USB_SPEED_SUPER: + if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) + dev_warn(dev, "UDC doesn't support Gen 1\n"); + break; case USB_SPEED_SUPER_PLUS: + if ((DWC3_IP_IS(DWC32) && + hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) || + (!DWC3_IP_IS(DWC32) && + hwparam_gen != DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) + dev_warn(dev, "UDC doesn't support SSP\n"); break; default: dev_err(dev, "invalid maximum_speed parameter %d\n", dwc->maximum_speed); - /* fall through */ + fallthrough; case USB_SPEED_UNKNOWN: - /* default to superspeed */ - dwc->maximum_speed = USB_SPEED_SUPER; - - /* - * default to superspeed plus if we are capable. - */ - if (dwc3_is_usb31(dwc) && - (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == - DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) + switch (hwparam_gen) { + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2: dwc->maximum_speed = USB_SPEED_SUPER_PLUS; - + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1: + if (DWC3_IP_IS(DWC32)) + dwc->maximum_speed = USB_SPEED_SUPER_PLUS; + else + dwc->maximum_speed = USB_SPEED_SUPER; + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_DIS: + dwc->maximum_speed = USB_SPEED_HIGH; + break; + default: + dwc->maximum_speed = USB_SPEED_SUPER; + break; + } break; } -} - -static void dwc3_coresoft_reset(struct dwc3 *dwc) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* - * Similar reset sequence in U-Boot has a 100ms delay here. In - * practice reset sequence seem to work as expected even - * without a delay. + * Currently the controller does not have visibility into the HW + * parameter to determine the maximum number of lanes the HW supports. + * If the number of lanes is not specified in the device property, then + * set the default to support dual-lane for DWC_usb32 and single-lane + * for DWC_usb31 for super-speed-plus. */ - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); + if (dwc->maximum_speed == USB_SPEED_SUPER_PLUS) { + switch (dwc->max_ssp_rate) { + case USB_SSP_GEN_2x1: + if (hwparam_gen == DWC3_GHWPARAMS3_SSPHY_IFC_GEN1) + dev_warn(dev, "UDC only supports Gen 1\n"); + break; + case USB_SSP_GEN_1x2: + case USB_SSP_GEN_2x2: + if (DWC3_IP_IS(DWC31)) + dev_warn(dev, "UDC only supports single lane\n"); + break; + case USB_SSP_GEN_UNKNOWN: + default: + switch (hwparam_gen) { + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN2: + if (DWC3_IP_IS(DWC32)) + dwc->max_ssp_rate = USB_SSP_GEN_2x2; + else + dwc->max_ssp_rate = USB_SSP_GEN_2x1; + break; + case DWC3_GHWPARAMS3_SSPHY_IFC_GEN1: + if (DWC3_IP_IS(DWC32)) + dwc->max_ssp_rate = USB_SSP_GEN_1x2; + break; + } + break; + } + } } -static int dwc3_probe(struct device_d *dev) +static int dwc3_probe(struct device *dev) { - const struct dwc3_match_data *match; struct dwc3 *dwc; int ret; dwc = xzalloc(sizeof(*dwc)); dev->priv = dwc; - match = device_get_match_data(dev); - dwc->clks = xmemdup(match->clks, match->num_clks * - sizeof(struct clk_bulk_data)); dwc->dev = dev; dwc->regs = dev_get_mem_region(dwc->dev, 0) + DWC3_GLOBALS_REGS_START; dwc3_get_properties(dwc); - if (dev->device_node) { - dwc->num_clks = match->num_clks; + if (dev->of_node) { + ret = clk_bulk_get_all(dev, &dwc->clks); + if (ret < 0) + return ret; - if (of_find_property(dev->device_node, "clocks", NULL)) { - ret = clk_bulk_get(dev, dwc->num_clks, dwc->clks); - if (ret) - return ret; - } + dwc->num_clks = ret; } ret = clk_bulk_enable(dwc->num_clks, dwc->clks); @@ -1136,7 +1435,12 @@ static int dwc3_probe(struct device_d *dev) mdelay(1); reset_control_deassert(dwc->reset); - dwc3_coresoft_reset(dwc); + if (!dwc3_core_is_valid(dwc)) { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + return -ENODEV; + } + + dwc3_core_soft_reset(dwc); dwc3_cache_hwparams(dwc); @@ -1170,53 +1474,32 @@ static int dwc3_probe(struct device_d *dev) return 0; } -static void dwc3_remove(struct device_d *dev) +static void dwc3_remove(struct device *dev) { struct dwc3 *dwc = dev->priv; + dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); clk_bulk_put(dwc->num_clks, dwc->clks); + dwc3_free_event_buffers(dwc); + dwc3_free_scratch_buffers(dwc); } -static const struct clk_bulk_data dwc3_core_clks[] = { - { .id = "ref" }, - { .id = "bus_early" }, - { .id = "suspend" }, -}; - -static const struct dwc3_match_data dwc3_default = { - .clks = dwc3_core_clks, - .num_clks = ARRAY_SIZE(dwc3_core_clks), -}; - -static const struct clk_bulk_data dwc3_core_clks_rk3568[] = { - { .id = "ref_clk" }, - { .id = "bus_clk" }, - { .id = "suspend_clk" }, -}; - -static const struct dwc3_match_data dwc3_rk3568 = { - .clks = dwc3_core_clks_rk3568, - .num_clks = ARRAY_SIZE(dwc3_core_clks_rk3568), -}; - static const struct of_device_id of_dwc3_match[] = { { .compatible = "snps,dwc3", - .data = &dwc3_default, }, { .compatible = "synopsys,dwc3", - .data = &dwc3_default, }, { .compatible = "rockchip,rk3568-dwc3", - .data = &dwc3_rk3568, }, { }, }; +MODULE_DEVICE_TABLE(of, of_dwc3_match); -static struct driver_d dwc3_driver = { +static struct driver dwc3_driver = { .probe = dwc3_probe, .remove = dwc3_remove, .name = "dwc3", |