Loading drivers/usb/dwc3/core.c +295 −122 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <linux/of.h> #include <linux/acpi.h> #include <linux/pinctrl/consumer.h> #include <linux/irq.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -49,6 +50,20 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); if (suspend) reg |= DWC3_GUSB3PIPECTL_SUSPHY; else reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; Loading @@ -57,6 +72,37 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* * Set this bit so that device attempts three more times at SS, even * if it failed previously to operate in SS mode. */ reg |= DWC3_GCTL_U2RSTECN; reg &= ~(DWC3_GCTL_SOFITPSYNC); reg &= ~(DWC3_GCTL_PWRDNSCALEMASK); reg |= DWC3_GCTL_PWRDNSCALE(2); reg |= DWC3_GCTL_U2EXIT_LFPS; dwc3_writel(dwc->regs, DWC3_GCTL, reg); if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) { /* * Allow ITP generated off of ref clk based counter instead * of UTMI/ULPI clk based counter, when superspeed only is * active so that UTMI/ULPI PHY can be suspened. * * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used * instead. */ if (dwc->revision < DWC3_REVISION_250A) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_SOFITPSYNC; dwc3_writel(dwc->regs, DWC3_GCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); reg |= DWC3_GFLADJ_REFCLK_LPM_SEL; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } } } u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) Loading @@ -74,17 +120,36 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) } /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * Peforms initialization of HS and SS PHYs. * If used as a part of POR or init sequence it is recommended * that we should perform hard reset of the PHYs prior to invoking * this function. * @dwc: pointer to our context structure */ static int dwc3_core_soft_reset(struct dwc3 *dwc) static int dwc3_init_usb_phys(struct dwc3 *dwc) { u32 reg; int retries = 1000; int ret; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); /* Bring up PHYs */ ret = usb_phy_init(dwc->usb2_phy); if (ret) { pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n", __func__, ret); return ret; } ret = usb_phy_init(dwc->usb3_phy); if (ret == -EBUSY) { /* * Setting Max speed as high when USB3 PHY initialiation * is failing and USB superspeed can't be supported. */ dwc->maximum_speed = USB_SPEED_HIGH; } else if (ret) { pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n", __func__, ret); return ret; } ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; Loading @@ -95,27 +160,34 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } /* * We're resetting only the device side because, if we're in host mode, * XHCI driver will reset the host block. If dwc3 was configured for * host-only mode, then we can return early. */ if (dwc->dr_mode == USB_DR_MODE_HOST) return 0; } reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; dwc3_writel(dwc->regs, DWC3_DCTL, reg); /** * dwc3_core_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static int dwc3_core_reset(struct dwc3 *dwc) { int ret; do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) return 0; /* Reset PHYs */ usb_phy_reset(dwc->usb2_phy); usb_phy_reset(dwc->usb3_phy); udelay(1); } while (--retries); /* Initialize PHYs */ ret = dwc3_init_usb_phys(dwc); if (ret) { pr_err("%s: dwc3_init_phys returned %d\n", __func__, ret); return ret; } return -ETIMEDOUT; dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); return 0; } /** Loading Loading @@ -249,7 +321,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; Loading Loading @@ -526,7 +598,7 @@ static void dwc3_core_exit(struct dwc3 *dwc) * * Returns 0 on success otherwise negative errno. */ static int dwc3_core_init(struct dwc3 *dwc) int dwc3_core_init(struct dwc3 *dwc) { u32 hwparams4 = dwc->hwparams.hwparams4; u32 reg; Loading Loading @@ -561,11 +633,12 @@ static int dwc3_core_init(struct dwc3 *dwc) } /* issue device SoftReset too */ ret = dwc3_soft_reset(dwc); ret = dwc3_core_reset(dwc); if (ret) goto err0; ret = dwc3_core_soft_reset(dwc); /* issue device SoftReset too */ ret = dwc3_soft_reset(dwc); if (ret) goto err0; Loading Loading @@ -639,13 +712,26 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; dwc3_core_num_eps(dwc); /* * Disable clock gating to work around a known HW bug that causes the * internal RAM clock to get stuck when entering low power modes. */ if (dwc->disable_clk_gating) { dev_dbg(dwc->dev, "Disabling controller clock gating.\n"); reg |= DWC3_GCTL_DSBLCLKGTNG; } dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_core_num_eps(dwc); ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err1; ret = dwc3_setup_scratch_buffers(dwc); if (ret) goto err1; goto err2; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); Loading @@ -656,28 +742,21 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret < 0) goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err4; /* * clear Elastic buffer mode in GUSBPIPE_CTRL(0) register, otherwise * it results in high link errors and could cause SS mode transfer * failure. */ if (!dwc->nominal_elastic_buffer) { reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } return 0; err4: phy_power_off(dwc->usb2_generic_phy); err3: phy_power_off(dwc->usb3_generic_phy); err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_core_exit(dwc); dwc3_free_scratch_buffers(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); Loading Loading @@ -759,42 +838,16 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize gadget\n"); return ret; } break; case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize host\n"); return ret; } break; case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize host\n"); return ret; } ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize gadget\n"); return ret; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); Loading Loading @@ -823,6 +876,96 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) } } /* XHCI reset, resets other CORE registers as well, re-init those */ void dwc3_post_host_reset_core_init(struct dwc3 *dwc) { dwc3_core_init(dwc); dwc3_gadget_restart(dwc); } static void (*notify_event)(struct dwc3 *, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, unsigned int event) { int ret = 0; if (dwc->notify_event) dwc->notify_event(dwc, event); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); int dwc3_core_pre_init(struct dwc3 *dwc) { int ret; dwc3_cache_hwparams(dwc); ret = dwc3_phy_setup(dwc); if (ret) goto err0; if (!dwc->ev_buf) { ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err1; } } ret = dwc3_core_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize core\n"); goto err2; } ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err3; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err4; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err5; } ret = dwc3_core_init_mode(dwc); if (ret) { dev_err(dwc->dev, "failed to set mode with dwc3 core\n"); goto err6; } return ret; err6: dwc3_event_buffers_cleanup(dwc); err5: phy_power_off(dwc->usb3_generic_phy); err4: phy_power_off(dwc->usb2_generic_phy); err3: dwc3_core_exit(dwc); err2: dwc3_free_event_buffers(dwc); err1: dwc3_ulpi_exit(dwc); err0: return ret; } #define DWC3_ALIGN_MASK (16 - 1) static int dwc3_probe(struct platform_device *pdev) Loading @@ -833,6 +976,7 @@ static int dwc3_probe(struct platform_device *pdev) u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; int irq; int ret; Loading @@ -847,12 +991,37 @@ static int dwc3_probe(struct platform_device *pdev) dwc->mem = mem; dwc->dev = dev; dwc->notify_event = notify_event; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; irq = platform_get_irq(to_platform_device(dwc->dev), 0); /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); return -ENODEV; } dwc->irq = irq; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->reg_phys = res->start; dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; Loading Loading @@ -934,14 +1103,19 @@ static int dwc3_probe(struct platform_device *pdev) device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, 500); pm_runtime_use_autosuspend(dev); } dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); init_waitqueue_head(&dwc->wait_linkstate); platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); ret = dwc3_core_get_phy(dwc); if (ret) Loading @@ -955,43 +1129,21 @@ static int dwc3_probe(struct platform_device *pdev) dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); } pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) goto err1; pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err2; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_UNKNOWN)) if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_UNKNOWN)) dwc->dr_mode = USB_DR_MODE_PERIPHERAL; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) { dwc->dr_mode = USB_DR_MODE_OTG; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err3; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err4; dwc->is_drd = true; } /* Check the maximum_speed parameter */ Loading Loading @@ -1021,32 +1173,48 @@ static int dwc3_probe(struct platform_device *pdev) break; } ret = dwc3_core_init_mode(dwc); if (ret) goto err5; dwc3_debugfs_init(dwc); pm_runtime_put(dev); return 0; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); err5: dwc3_event_buffers_cleanup(dwc); /* Hardcode number of eps */ dwc->num_in_eps = 16; dwc->num_out_eps = 16; err4: dwc3_free_scratch_buffers(dwc); if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err0; } } err3: dwc3_free_event_buffers(dwc); dwc3_ulpi_exit(dwc); if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_HOST) { ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err_gadget; } } err2: pm_runtime_allow(&pdev->dev); ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err_host; } err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_allow(dev); return 0; err_host: if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_HOST) dwc3_host_exit(dwc); err_gadget: if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) dwc3_gadget_exit(dwc); err0: /* * restore res->start back to its original value so that, in case the Loading Loading @@ -1157,8 +1325,9 @@ static int dwc3_runtime_suspend(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; if (dwc3_runtime_checks(dwc)) return -EBUSY; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) return 0; ret = dwc3_suspend_common(dwc); if (ret) Loading @@ -1174,6 +1343,10 @@ static int dwc3_runtime_resume(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) return 0; device_init_wakeup(dev, false); ret = dwc3_resume_common(dwc); Loading drivers/usb/dwc3/core.h +113 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ #include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/debugfs.h> #include <linux/workqueue.h> #include <linux/wait.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -45,7 +48,7 @@ #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_SIZE 4 /* bytes */ #define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */ #define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM) #define DWC3_EVENT_BUFFERS_SIZE (2 * PAGE_SIZE) #define DWC3_EVENT_TYPE_MASK 0xfe #define DWC3_EVENT_TYPE_DEV 0 Loading @@ -59,6 +62,8 @@ #define DWC3_DEVICE_EVENT_WAKEUP 4 #define DWC3_DEVICE_EVENT_HIBER_REQ 5 #define DWC3_DEVICE_EVENT_EOPF 6 /* For version 2.30a and above */ #define DWC3_DEVICE_EVENT_SUSPEND 6 #define DWC3_DEVICE_EVENT_SOF 7 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 #define DWC3_DEVICE_EVENT_CMD_CMPL 10 Loading Loading @@ -155,6 +160,10 @@ /* Bit fields */ /* Global SoC Bus Configuration Register 1 */ #define DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK (0x0f << 8) #define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) ((n) << 8) /* Global Debug Queue/FIFO Space Available Register */ #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) Loading @@ -175,7 +184,10 @@ /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000) #define DWC3_GCTL_U2RSTECN (1 << 16) #define DWC3_GCTL_SOFITPSYNC (1 << 10) #define DWC3_GCTL_U2EXIT_LFPS (1 << 2) #define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) #define DWC3_GCTL_CLK_PIPE (1) Loading @@ -197,8 +209,15 @@ #define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1) #define DWC3_GCTL_DSBLCLKGTNG (1 << 0) /* Global User Control Register */ #define DWC3_GUCTL_REFCLKPER (0x3FF << 22) /* Global Debug LTSSM Register */ #define DWC3_GDBGLTSSM_LINKSTATE_MASK (0xF << 22) /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) Loading @@ -225,6 +244,8 @@ #define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) #define DWC3_GUSB3PIPECTL_DELAYP1TRANS (1 << 18) #define DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE (1 << 0) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) Loading Loading @@ -279,6 +300,11 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f #define DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1 (1 << 31) #define DWC3_GFLADJ_REFCLK_240MHZ_DECR (0x7F << 24) #define DWC3_GFLADJ_REFCLK_LPM_SEL (1 << 23) #define DWC3_GFLADJ_REFCLK_FLADJ (0x3FFF << 8) /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) Loading Loading @@ -348,6 +374,8 @@ #define DWC3_DEVTEN_ERRTICERREN (1 << 9) #define DWC3_DEVTEN_SOFEN (1 << 7) #define DWC3_DEVTEN_EOPFEN (1 << 6) /* For version 2.30a and above*/ #define DWC3_DEVTEN_SUSPEND (1 << 6) #define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5) #define DWC3_DEVTEN_WKUPEVTEN (1 << 4) #define DWC3_DEVTEN_ULSTCNGEN (1 << 3) Loading Loading @@ -389,6 +417,7 @@ #define DWC3_DGCMD_SET_LMP 0x01 #define DWC3_DGCMD_SET_PERIODIC_PAR 0x02 #define DWC3_DGCMD_XMIT_FUNCTION 0x03 #define DWC3_DGCMD_XMIT_DEV 0x07 /* These apply for core versions 1.94a and later */ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 Loading Loading @@ -485,8 +514,10 @@ struct dwc3_event_buffer { * @started_list: list of started requests on this endpoint * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_dma_pool: dma pool used to get aligned trb memory pool * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool * @num_trbs: num of trbs in the trb dma pool * @trb_enqueue: enqueue 'pointer' into TRB array * @trb_dequeue: dequeue 'pointer' into TRB array * @desc: usb_endpoint_descriptor pointer Loading @@ -511,8 +542,10 @@ struct dwc3_ep { spinlock_t lock; void __iomem *regs; struct dma_pool *trb_dma_pool; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; u32 num_trbs; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; Loading Loading @@ -716,6 +749,18 @@ struct dwc3_scratchpad_array { __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; }; #define DWC3_CONTROLLER_ERROR_EVENT 0 #define DWC3_CONTROLLER_RESET_EVENT 1 #define DWC3_CONTROLLER_POST_RESET_EVENT 2 #define DWC3_CORE_PM_SUSPEND_EVENT 3 #define DWC3_CORE_PM_RESUME_EVENT 4 #define DWC3_CONTROLLER_CONNDONE_EVENT 5 #define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6 #define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7 #define DWC3_CONTROLLER_RESTART_USB_SESSION 8 #define MAX_INTR_STATS 10 /** * struct dwc3 - representation of our controller * @ctrl_req: usb control request which is used for ep0 Loading @@ -738,6 +783,7 @@ struct dwc3_scratchpad_array { * @regs_size: address space size * @fladj: frame length adjustment * @irq_gadget: peripheral controller's IRQ number * @reg_phys: physical base address of dwc3 core register address space * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) Loading Loading @@ -805,6 +851,19 @@ struct dwc3_scratchpad_array { * 1 - -3.5dB de-emphasis * 2 - No de-emphasis * 3 - Reserved * @is_drd: device supports dual-role or not * @err_evt_seen: previous event in queue was erratic error * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode. * @in_lpm: indicates if controller is in low power mode (no clocks) * @tx_fifo_size: Available RAM size for TX fifo allocation * @irq: irq number * @bh: tasklet which handles the interrupt * @irq_cnt: total irq count * @bh_completion_time: time taken for taklet completion * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -843,6 +902,7 @@ struct dwc3 { void __iomem *regs; size_t regs_size; phys_addr_t reg_phys; enum usb_dr_mode dr_mode; Loading Loading @@ -917,6 +977,9 @@ struct dwc3 { const char *hsphy_interface; unsigned connected:1; void (*notify_event)(struct dwc3 *, unsigned int); struct work_struct wakeup_work; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; Loading Loading @@ -945,6 +1008,37 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; unsigned is_drd:1; /* Indicate if the gadget was powered by the otg driver */ unsigned vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned softconnect:1; unsigned nominal_elastic_buffer:1; unsigned err_evt_seen:1; unsigned usb3_u1u2_disable:1; /* Indicate if need to disable controller internal clkgating */ unsigned disable_clk_gating:1; unsigned enable_bus_suspend:1; atomic_t in_lpm; int tx_fifo_size; bool b_suspend; unsigned int vbus_draw; /* IRQ timing statistics */ int irq; struct tasklet_struct bh; unsigned long irq_cnt; unsigned int bh_completion_time[MAX_INTR_STATS]; unsigned int bh_handled_evt_cnt[MAX_INTR_STATS]; unsigned int bh_dbg_index; ktime_t irq_start_time[MAX_INTR_STATS]; ktime_t t_pwr_evt_irq; unsigned int irq_completion_time[MAX_INTR_STATS]; unsigned int irq_event_count[MAX_INTR_STATS]; unsigned int irq_dbg_index; wait_queue_head_t wait_linkstate; }; /* -------------------------------------------------------------------------- */ Loading Loading @@ -1119,17 +1213,22 @@ static inline void dwc3_host_exit(struct dwc3 *dwc) #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_gadget_init(struct dwc3 *dwc); void dwc3_gadget_exit(struct dwc3 *dwc); void dwc3_gadget_restart(struct dwc3 *dwc); int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); int dwc3_gadget_get_link_state(struct dwc3 *dwc); int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); void dwc3_gadget_enable_irq(struct dwc3 *dwc); void dwc3_gadget_disable_irq(struct dwc3 *dwc); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } static inline void dwc3_gadget_restart(struct dwc3 *dwc) { } static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) { return 0; } static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc) Loading @@ -1144,6 +1243,10 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } static inline void dwc3_gadget_enable_irq(struct dwc3 *dwc) { } static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc) { } #endif /* power management interface */ Loading Loading @@ -1177,4 +1280,13 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif int dwc3_core_init(struct dwc3 *dwc); int dwc3_core_pre_init(struct dwc3 *dwc); void dwc3_post_host_reset_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); #endif /* __DRIVERS_USB_DWC3_CORE_H */ drivers/usb/dwc3/debug.h +3 −3 Original line number Diff line number Diff line Loading @@ -313,11 +313,11 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status) void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS extern void dwc3_debugfs_init(struct dwc3 *); extern int dwc3_debugfs_init(struct dwc3 *); extern void dwc3_debugfs_exit(struct dwc3 *); #else static inline void dwc3_debugfs_init(struct dwc3 *d) { } static inline int dwc3_debugfs_init(struct dwc3 *d) { return 0; } static inline void dwc3_debugfs_exit(struct dwc3 *d) { } #endif Loading drivers/usb/dwc3/debugfs.c +13 −4 Original line number Diff line number Diff line Loading @@ -843,23 +843,25 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc, } } void dwc3_debugfs_init(struct dwc3 *dwc) int dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; struct dentry *file; int ret; root = debugfs_create_dir(dev_name(dwc->dev), NULL); if (IS_ERR_OR_NULL(root)) { if (!root) dev_err(dwc->dev, "Can't create debugfs root\n"); return; ret = -ENOMEM; goto err0; } dwc->root = root; dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL); if (!dwc->regset) { debugfs_remove_recursive(root); return; ret = -ENOMEM; goto err1; } dwc->regset->regs = dwc3_regs; Loading Loading @@ -891,6 +893,13 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc3_debugfs_create_endpoint_dirs(dwc, root); } return 0; err1: debugfs_remove_recursive(root); err0: return ret; } void dwc3_debugfs_exit(struct dwc3 *dwc) Loading Loading
drivers/usb/dwc3/core.c +295 −122 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <linux/of.h> #include <linux/acpi.h> #include <linux/pinctrl/consumer.h> #include <linux/irq.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -49,6 +50,20 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); if (suspend) reg |= DWC3_GUSB3PIPECTL_SUSPHY; else reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; Loading @@ -57,6 +72,37 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); /* * Set this bit so that device attempts three more times at SS, even * if it failed previously to operate in SS mode. */ reg |= DWC3_GCTL_U2RSTECN; reg &= ~(DWC3_GCTL_SOFITPSYNC); reg &= ~(DWC3_GCTL_PWRDNSCALEMASK); reg |= DWC3_GCTL_PWRDNSCALE(2); reg |= DWC3_GCTL_U2EXIT_LFPS; dwc3_writel(dwc->regs, DWC3_GCTL, reg); if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) { /* * Allow ITP generated off of ref clk based counter instead * of UTMI/ULPI clk based counter, when superspeed only is * active so that UTMI/ULPI PHY can be suspened. * * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used * instead. */ if (dwc->revision < DWC3_REVISION_250A) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_SOFITPSYNC; dwc3_writel(dwc->regs, DWC3_GCTL, reg); } else { reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); reg |= DWC3_GFLADJ_REFCLK_LPM_SEL; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } } } u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) Loading @@ -74,17 +120,36 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) } /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * Peforms initialization of HS and SS PHYs. * If used as a part of POR or init sequence it is recommended * that we should perform hard reset of the PHYs prior to invoking * this function. * @dwc: pointer to our context structure */ static int dwc3_core_soft_reset(struct dwc3 *dwc) static int dwc3_init_usb_phys(struct dwc3 *dwc) { u32 reg; int retries = 1000; int ret; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); /* Bring up PHYs */ ret = usb_phy_init(dwc->usb2_phy); if (ret) { pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n", __func__, ret); return ret; } ret = usb_phy_init(dwc->usb3_phy); if (ret == -EBUSY) { /* * Setting Max speed as high when USB3 PHY initialiation * is failing and USB superspeed can't be supported. */ dwc->maximum_speed = USB_SPEED_HIGH; } else if (ret) { pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n", __func__, ret); return ret; } ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; Loading @@ -95,27 +160,34 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } /* * We're resetting only the device side because, if we're in host mode, * XHCI driver will reset the host block. If dwc3 was configured for * host-only mode, then we can return early. */ if (dwc->dr_mode == USB_DR_MODE_HOST) return 0; } reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; dwc3_writel(dwc->regs, DWC3_DCTL, reg); /** * dwc3_core_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ static int dwc3_core_reset(struct dwc3 *dwc) { int ret; do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) return 0; /* Reset PHYs */ usb_phy_reset(dwc->usb2_phy); usb_phy_reset(dwc->usb3_phy); udelay(1); } while (--retries); /* Initialize PHYs */ ret = dwc3_init_usb_phys(dwc); if (ret) { pr_err("%s: dwc3_init_phys returned %d\n", __func__, ret); return ret; } return -ETIMEDOUT; dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); return 0; } /** Loading Loading @@ -249,7 +321,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; Loading Loading @@ -526,7 +598,7 @@ static void dwc3_core_exit(struct dwc3 *dwc) * * Returns 0 on success otherwise negative errno. */ static int dwc3_core_init(struct dwc3 *dwc) int dwc3_core_init(struct dwc3 *dwc) { u32 hwparams4 = dwc->hwparams.hwparams4; u32 reg; Loading Loading @@ -561,11 +633,12 @@ static int dwc3_core_init(struct dwc3 *dwc) } /* issue device SoftReset too */ ret = dwc3_soft_reset(dwc); ret = dwc3_core_reset(dwc); if (ret) goto err0; ret = dwc3_core_soft_reset(dwc); /* issue device SoftReset too */ ret = dwc3_soft_reset(dwc); if (ret) goto err0; Loading Loading @@ -639,13 +712,26 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; dwc3_core_num_eps(dwc); /* * Disable clock gating to work around a known HW bug that causes the * internal RAM clock to get stuck when entering low power modes. */ if (dwc->disable_clk_gating) { dev_dbg(dwc->dev, "Disabling controller clock gating.\n"); reg |= DWC3_GCTL_DSBLCLKGTNG; } dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_core_num_eps(dwc); ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err1; ret = dwc3_setup_scratch_buffers(dwc); if (ret) goto err1; goto err2; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); Loading @@ -656,28 +742,21 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret < 0) goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err4; /* * clear Elastic buffer mode in GUSBPIPE_CTRL(0) register, otherwise * it results in high link errors and could cause SS mode transfer * failure. */ if (!dwc->nominal_elastic_buffer) { reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); reg &= ~DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } return 0; err4: phy_power_off(dwc->usb2_generic_phy); err3: phy_power_off(dwc->usb3_generic_phy); err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_core_exit(dwc); dwc3_free_scratch_buffers(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); Loading Loading @@ -759,42 +838,16 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize gadget\n"); return ret; } break; case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize host\n"); return ret; } break; case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize host\n"); return ret; } ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize gadget\n"); return ret; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); Loading Loading @@ -823,6 +876,96 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) } } /* XHCI reset, resets other CORE registers as well, re-init those */ void dwc3_post_host_reset_core_init(struct dwc3 *dwc) { dwc3_core_init(dwc); dwc3_gadget_restart(dwc); } static void (*notify_event)(struct dwc3 *, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, unsigned int event) { int ret = 0; if (dwc->notify_event) dwc->notify_event(dwc, event); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); int dwc3_core_pre_init(struct dwc3 *dwc) { int ret; dwc3_cache_hwparams(dwc); ret = dwc3_phy_setup(dwc); if (ret) goto err0; if (!dwc->ev_buf) { ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err1; } } ret = dwc3_core_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize core\n"); goto err2; } ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err3; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err4; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err5; } ret = dwc3_core_init_mode(dwc); if (ret) { dev_err(dwc->dev, "failed to set mode with dwc3 core\n"); goto err6; } return ret; err6: dwc3_event_buffers_cleanup(dwc); err5: phy_power_off(dwc->usb3_generic_phy); err4: phy_power_off(dwc->usb2_generic_phy); err3: dwc3_core_exit(dwc); err2: dwc3_free_event_buffers(dwc); err1: dwc3_ulpi_exit(dwc); err0: return ret; } #define DWC3_ALIGN_MASK (16 - 1) static int dwc3_probe(struct platform_device *pdev) Loading @@ -833,6 +976,7 @@ static int dwc3_probe(struct platform_device *pdev) u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; int irq; int ret; Loading @@ -847,12 +991,37 @@ static int dwc3_probe(struct platform_device *pdev) dwc->mem = mem; dwc->dev = dev; dwc->notify_event = notify_event; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; irq = platform_get_irq(to_platform_device(dwc->dev), 0); /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); return -ENODEV; } dwc->irq = irq; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->reg_phys = res->start; dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; Loading Loading @@ -934,14 +1103,19 @@ static int dwc3_probe(struct platform_device *pdev) device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, 500); pm_runtime_use_autosuspend(dev); } dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); init_waitqueue_head(&dwc->wait_linkstate); platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); ret = dwc3_core_get_phy(dwc); if (ret) Loading @@ -955,43 +1129,21 @@ static int dwc3_probe(struct platform_device *pdev) dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); } pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) goto err1; pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err2; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_UNKNOWN)) if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_UNKNOWN)) dwc->dr_mode = USB_DR_MODE_PERIPHERAL; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) { dwc->dr_mode = USB_DR_MODE_OTG; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err3; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err4; dwc->is_drd = true; } /* Check the maximum_speed parameter */ Loading Loading @@ -1021,32 +1173,48 @@ static int dwc3_probe(struct platform_device *pdev) break; } ret = dwc3_core_init_mode(dwc); if (ret) goto err5; dwc3_debugfs_init(dwc); pm_runtime_put(dev); return 0; /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); err5: dwc3_event_buffers_cleanup(dwc); /* Hardcode number of eps */ dwc->num_in_eps = 16; dwc->num_out_eps = 16; err4: dwc3_free_scratch_buffers(dwc); if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err0; } } err3: dwc3_free_event_buffers(dwc); dwc3_ulpi_exit(dwc); if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_HOST) { ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err_gadget; } } err2: pm_runtime_allow(&pdev->dev); ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err_host; } err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_allow(dev); return 0; err_host: if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_HOST) dwc3_host_exit(dwc); err_gadget: if (dwc->dr_mode == USB_DR_MODE_OTG || dwc->dr_mode == USB_DR_MODE_PERIPHERAL) dwc3_gadget_exit(dwc); err0: /* * restore res->start back to its original value so that, in case the Loading Loading @@ -1157,8 +1325,9 @@ static int dwc3_runtime_suspend(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; if (dwc3_runtime_checks(dwc)) return -EBUSY; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) return 0; ret = dwc3_suspend_common(dwc); if (ret) Loading @@ -1174,6 +1343,10 @@ static int dwc3_runtime_resume(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) return 0; device_init_wakeup(dev, false); ret = dwc3_resume_common(dwc); Loading
drivers/usb/dwc3/core.h +113 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ #include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/debugfs.h> #include <linux/workqueue.h> #include <linux/wait.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -45,7 +48,7 @@ #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_SIZE 4 /* bytes */ #define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */ #define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM) #define DWC3_EVENT_BUFFERS_SIZE (2 * PAGE_SIZE) #define DWC3_EVENT_TYPE_MASK 0xfe #define DWC3_EVENT_TYPE_DEV 0 Loading @@ -59,6 +62,8 @@ #define DWC3_DEVICE_EVENT_WAKEUP 4 #define DWC3_DEVICE_EVENT_HIBER_REQ 5 #define DWC3_DEVICE_EVENT_EOPF 6 /* For version 2.30a and above */ #define DWC3_DEVICE_EVENT_SUSPEND 6 #define DWC3_DEVICE_EVENT_SOF 7 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 #define DWC3_DEVICE_EVENT_CMD_CMPL 10 Loading Loading @@ -155,6 +160,10 @@ /* Bit fields */ /* Global SoC Bus Configuration Register 1 */ #define DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK (0x0f << 8) #define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) ((n) << 8) /* Global Debug Queue/FIFO Space Available Register */ #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) Loading @@ -175,7 +184,10 @@ /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000) #define DWC3_GCTL_U2RSTECN (1 << 16) #define DWC3_GCTL_SOFITPSYNC (1 << 10) #define DWC3_GCTL_U2EXIT_LFPS (1 << 2) #define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) #define DWC3_GCTL_CLK_PIPE (1) Loading @@ -197,8 +209,15 @@ #define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1) #define DWC3_GCTL_DSBLCLKGTNG (1 << 0) /* Global User Control Register */ #define DWC3_GUCTL_REFCLKPER (0x3FF << 22) /* Global Debug LTSSM Register */ #define DWC3_GDBGLTSSM_LINKSTATE_MASK (0xF << 22) /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) Loading @@ -225,6 +244,8 @@ #define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) #define DWC3_GUSB3PIPECTL_DELAYP1TRANS (1 << 18) #define DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE (1 << 0) /* Global TX Fifo Size Register */ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) Loading Loading @@ -279,6 +300,11 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f #define DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1 (1 << 31) #define DWC3_GFLADJ_REFCLK_240MHZ_DECR (0x7F << 24) #define DWC3_GFLADJ_REFCLK_LPM_SEL (1 << 23) #define DWC3_GFLADJ_REFCLK_FLADJ (0x3FFF << 8) /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) Loading Loading @@ -348,6 +374,8 @@ #define DWC3_DEVTEN_ERRTICERREN (1 << 9) #define DWC3_DEVTEN_SOFEN (1 << 7) #define DWC3_DEVTEN_EOPFEN (1 << 6) /* For version 2.30a and above*/ #define DWC3_DEVTEN_SUSPEND (1 << 6) #define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5) #define DWC3_DEVTEN_WKUPEVTEN (1 << 4) #define DWC3_DEVTEN_ULSTCNGEN (1 << 3) Loading Loading @@ -389,6 +417,7 @@ #define DWC3_DGCMD_SET_LMP 0x01 #define DWC3_DGCMD_SET_PERIODIC_PAR 0x02 #define DWC3_DGCMD_XMIT_FUNCTION 0x03 #define DWC3_DGCMD_XMIT_DEV 0x07 /* These apply for core versions 1.94a and later */ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 Loading Loading @@ -485,8 +514,10 @@ struct dwc3_event_buffer { * @started_list: list of started requests on this endpoint * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_dma_pool: dma pool used to get aligned trb memory pool * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool * @num_trbs: num of trbs in the trb dma pool * @trb_enqueue: enqueue 'pointer' into TRB array * @trb_dequeue: dequeue 'pointer' into TRB array * @desc: usb_endpoint_descriptor pointer Loading @@ -511,8 +542,10 @@ struct dwc3_ep { spinlock_t lock; void __iomem *regs; struct dma_pool *trb_dma_pool; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; u32 num_trbs; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; Loading Loading @@ -716,6 +749,18 @@ struct dwc3_scratchpad_array { __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; }; #define DWC3_CONTROLLER_ERROR_EVENT 0 #define DWC3_CONTROLLER_RESET_EVENT 1 #define DWC3_CONTROLLER_POST_RESET_EVENT 2 #define DWC3_CORE_PM_SUSPEND_EVENT 3 #define DWC3_CORE_PM_RESUME_EVENT 4 #define DWC3_CONTROLLER_CONNDONE_EVENT 5 #define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6 #define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7 #define DWC3_CONTROLLER_RESTART_USB_SESSION 8 #define MAX_INTR_STATS 10 /** * struct dwc3 - representation of our controller * @ctrl_req: usb control request which is used for ep0 Loading @@ -738,6 +783,7 @@ struct dwc3_scratchpad_array { * @regs_size: address space size * @fladj: frame length adjustment * @irq_gadget: peripheral controller's IRQ number * @reg_phys: physical base address of dwc3 core register address space * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) Loading Loading @@ -805,6 +851,19 @@ struct dwc3_scratchpad_array { * 1 - -3.5dB de-emphasis * 2 - No de-emphasis * 3 - Reserved * @is_drd: device supports dual-role or not * @err_evt_seen: previous event in queue was erratic error * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode. * @in_lpm: indicates if controller is in low power mode (no clocks) * @tx_fifo_size: Available RAM size for TX fifo allocation * @irq: irq number * @bh: tasklet which handles the interrupt * @irq_cnt: total irq count * @bh_completion_time: time taken for taklet completion * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -843,6 +902,7 @@ struct dwc3 { void __iomem *regs; size_t regs_size; phys_addr_t reg_phys; enum usb_dr_mode dr_mode; Loading Loading @@ -917,6 +977,9 @@ struct dwc3 { const char *hsphy_interface; unsigned connected:1; void (*notify_event)(struct dwc3 *, unsigned int); struct work_struct wakeup_work; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; Loading Loading @@ -945,6 +1008,37 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; unsigned is_drd:1; /* Indicate if the gadget was powered by the otg driver */ unsigned vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned softconnect:1; unsigned nominal_elastic_buffer:1; unsigned err_evt_seen:1; unsigned usb3_u1u2_disable:1; /* Indicate if need to disable controller internal clkgating */ unsigned disable_clk_gating:1; unsigned enable_bus_suspend:1; atomic_t in_lpm; int tx_fifo_size; bool b_suspend; unsigned int vbus_draw; /* IRQ timing statistics */ int irq; struct tasklet_struct bh; unsigned long irq_cnt; unsigned int bh_completion_time[MAX_INTR_STATS]; unsigned int bh_handled_evt_cnt[MAX_INTR_STATS]; unsigned int bh_dbg_index; ktime_t irq_start_time[MAX_INTR_STATS]; ktime_t t_pwr_evt_irq; unsigned int irq_completion_time[MAX_INTR_STATS]; unsigned int irq_event_count[MAX_INTR_STATS]; unsigned int irq_dbg_index; wait_queue_head_t wait_linkstate; }; /* -------------------------------------------------------------------------- */ Loading Loading @@ -1119,17 +1213,22 @@ static inline void dwc3_host_exit(struct dwc3 *dwc) #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_gadget_init(struct dwc3 *dwc); void dwc3_gadget_exit(struct dwc3 *dwc); void dwc3_gadget_restart(struct dwc3 *dwc); int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); int dwc3_gadget_get_link_state(struct dwc3 *dwc); int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); void dwc3_gadget_enable_irq(struct dwc3 *dwc); void dwc3_gadget_disable_irq(struct dwc3 *dwc); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } static inline void dwc3_gadget_restart(struct dwc3 *dwc) { } static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) { return 0; } static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc) Loading @@ -1144,6 +1243,10 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } static inline void dwc3_gadget_enable_irq(struct dwc3 *dwc) { } static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc) { } #endif /* power management interface */ Loading Loading @@ -1177,4 +1280,13 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif int dwc3_core_init(struct dwc3 *dwc); int dwc3_core_pre_init(struct dwc3 *dwc); void dwc3_post_host_reset_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); #endif /* __DRIVERS_USB_DWC3_CORE_H */
drivers/usb/dwc3/debug.h +3 −3 Original line number Diff line number Diff line Loading @@ -313,11 +313,11 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status) void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS extern void dwc3_debugfs_init(struct dwc3 *); extern int dwc3_debugfs_init(struct dwc3 *); extern void dwc3_debugfs_exit(struct dwc3 *); #else static inline void dwc3_debugfs_init(struct dwc3 *d) { } static inline int dwc3_debugfs_init(struct dwc3 *d) { return 0; } static inline void dwc3_debugfs_exit(struct dwc3 *d) { } #endif Loading
drivers/usb/dwc3/debugfs.c +13 −4 Original line number Diff line number Diff line Loading @@ -843,23 +843,25 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc, } } void dwc3_debugfs_init(struct dwc3 *dwc) int dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; struct dentry *file; int ret; root = debugfs_create_dir(dev_name(dwc->dev), NULL); if (IS_ERR_OR_NULL(root)) { if (!root) dev_err(dwc->dev, "Can't create debugfs root\n"); return; ret = -ENOMEM; goto err0; } dwc->root = root; dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL); if (!dwc->regset) { debugfs_remove_recursive(root); return; ret = -ENOMEM; goto err1; } dwc->regset->regs = dwc3_regs; Loading Loading @@ -891,6 +893,13 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc3_debugfs_create_endpoint_dirs(dwc, root); } return 0; err1: debugfs_remove_recursive(root); err0: return ret; } void dwc3_debugfs_exit(struct dwc3 *dwc) Loading