Loading Documentation/devicetree/bindings/usb/dwc3.txt +2 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ Optional properties: - snps,xhci-imod-value: Interrupt moderation interval for host mode (in increments of 250nsec). - usb-core-id: Differentiates between different controllers present on a device. - snps,bus-suspend-enable: If present then controller supports low power mode during bus suspend. - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated. Loading drivers/usb/dwc3/Makefile +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0 # define_trace.h needs to know how to find our header CFLAGS_trace.o := -I$(src) CFLAGS_dwc3-msm.o := -Idrivers/usb/host -Idrivers/base/power obj-$(CONFIG_USB_DWC3) += dwc3.o Loading drivers/usb/dwc3/core.c +185 −125 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/of.h> #include <linux/usb/otg.h> #include <linux/irq.h> #include "core.h" #include "gadget.h" Loading @@ -38,11 +39,28 @@ #include "debug.h" #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 500 /* ms */ static int count; static struct dwc3 *dwc3_instance[DWC_CTRL_COUNT]; static void dwc3_check_params(struct dwc3 *dwc); static void __dwc3_set_mode(struct dwc3 *dwc); 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); } /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure Loading Loading @@ -106,12 +124,14 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } static void __dwc3_set_mode(struct work_struct *work) static void __maybe_unused __dwc3_set_mode(struct dwc3 *dwc) { struct dwc3 *dwc = work_to_dwc(work); unsigned long flags; int ret; dev_dbg(dwc->dev, "%s(): desired_dr_role:%d curent_dr_role:%d\n", __func__, dwc->desired_dr_role, dwc->current_dr_role); if (dwc->dr_mode != USB_DR_MODE_OTG) return; Loading @@ -121,8 +141,10 @@ static void __dwc3_set_mode(struct work_struct *work) if (!dwc->desired_dr_role) return; if (dwc->desired_dr_role == dwc->current_dr_role) if (dwc->desired_dr_role == dwc->current_dr_role) { dwc3_set_prtcap(dwc, dwc->desired_dr_role); return; } if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) return; Loading Loading @@ -222,8 +244,36 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) int retries = 1000; int ret; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); /* Reset PHYs */ usb_phy_reset(dwc->usb2_phy); if (dwc->maximum_speed == USB_SPEED_SUPER) usb_phy_reset(dwc->usb3_phy); 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; } if (dwc->maximum_speed == USB_SPEED_HIGH) goto generic_phy_init; 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; } generic_phy_init: ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; Loading Loading @@ -355,6 +405,9 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) evt = dwc->ev_buf; if (evt) dwc3_free_one_event_buffer(dwc, evt); /* free GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE); } /** Loading @@ -376,6 +429,8 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) } dwc->ev_buf = evt; /* alloc GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC); return 0; } Loading @@ -399,6 +454,8 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* setup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP); return 0; } Loading @@ -415,6 +472,9 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(0)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* cleanup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -787,7 +847,7 @@ static int dwc3_core_ulpi_init(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 reg; int ret; Loading @@ -798,6 +858,13 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err0; } dwc3_cache_hwparams(dwc); ret = dwc3_get_dr_mode(dwc); if (ret) { ret = -EINVAL; goto err0; } /* * Write Linux Version Code to our GUID register so it's easy to figure * out which kernel version a bug was found. Loading Loading @@ -844,7 +911,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_frame_length_adjustment(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); if (dwc->maximum_speed >= USB_SPEED_SUPER) usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err2; Loading @@ -853,12 +922,6 @@ static int dwc3_core_init(struct dwc3 *dwc) 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; } /* * ENDXFER polling is available on version 3.10a and later of * the DWC_usb3 controller. It is NOT available in the Loading Loading @@ -923,10 +986,9 @@ static int dwc3_core_init(struct dwc3 *dwc) } } return 0; dwc3_check_params(dwc); err4: phy_power_off(dwc->usb3_generic_phy); return 0; err3: phy_power_off(dwc->usb2_generic_phy); Loading @@ -934,6 +996,7 @@ static int dwc3_core_init(struct dwc3 *dwc) err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_free_scratch_buffers(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); Loading Loading @@ -1015,61 +1078,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } 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_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; } 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; } phy_calibrate(dwc->usb2_generic_phy); break; case USB_DR_MODE_OTG: INIT_WORK(&dwc->drd_work, __dwc3_set_mode); ret = dwc3_drd_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize dual-role\n"); return ret; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } return 0; } static void dwc3_core_exit_mode(struct dwc3 *dwc) static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) { switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: Loading @@ -1087,6 +1096,26 @@ static void dwc3_core_exit_mode(struct dwc3 *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 (notify_event) notify_event(dwc, event); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); static void dwc3_get_properties(struct dwc3 *dwc) { struct device *dev = dwc->dev; Loading @@ -1111,6 +1140,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) hird_threshold = 12; dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_hw_supp_speed = dwc->maximum_speed; dwc->dr_mode = usb_get_dr_mode(dev); dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); Loading Loading @@ -1186,6 +1216,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); dwc->enable_bus_suspend = device_property_read_bool(dev, "snps,bus-suspend-enable"); dwc->dis_metastability_quirk = device_property_read_bool(dev, "snps,dis_metastability_quirk"); Loading Loading @@ -1272,6 +1304,14 @@ static int dwc3_probe(struct platform_device *pdev) int ret; void __iomem *regs; int irq; if (count >= DWC_CTRL_COUNT) { dev_err(dev, "Err dwc instance %d >= %d available\n", count, DWC_CTRL_COUNT); ret = -EINVAL; return ret; } dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) Loading @@ -1283,7 +1323,6 @@ static int dwc3_probe(struct platform_device *pdev) return -ENOMEM; dwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); Loading @@ -1296,6 +1335,21 @@ static int dwc3_probe(struct platform_device *pdev) dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; res->start += DWC3_GLOBALS_REGS_START; 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_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); return -ENODEV; } dwc->irq = irq; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. Loading @@ -1307,6 +1361,14 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); if (!dwc->dwc_wq) { dev_err(dev, "%s: Unable to create workqueue dwc_wq\n", __func__); goto err0; } INIT_WORK(&dwc->bh_work, dwc3_bh_work); dwc->regs = regs; dwc->regs_size = resource_size(&dwc_res); Loading @@ -1314,7 +1376,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); if (IS_ERR(dwc->reset)) return PTR_ERR(dwc->reset); goto skip_clk_reset; if (dev->of_node) { dwc->num_clks = ARRAY_SIZE(dwc3_core_clks); Loading Loading @@ -1342,47 +1404,32 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto unprepare_clks; skip_clk_reset: platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); init_waitqueue_head(&dwc->wait_linkstate); spin_lock_init(&dwc->lock); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); 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; goto err1; } ret = dwc3_get_dr_mode(dwc); if (ret) goto err3; 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; } dwc3_check_params(dwc); ret = dwc3_core_init_mode(dwc); if (ret) goto err5; goto err2; dwc3_debugfs_init(dwc); Loading @@ -1395,26 +1442,13 @@ static int dwc3_probe(struct platform_device *pdev) dwc->index = count; count++; pm_runtime_put(dev); pm_runtime_allow(dev); return 0; err5: dwc3_event_buffers_cleanup(dwc); err4: dwc3_free_scratch_buffers(dwc); err3: dwc3_free_event_buffers(dwc); err2: pm_runtime_allow(&pdev->dev); dwc3_free_event_buffers(dwc); err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); if (dwc->num_clks) { clk_bulk_disable(dwc->num_clks, dwc->clks); unprepare_clks: clk_bulk_unprepare(dwc->num_clks, dwc->clks); Loading @@ -1422,6 +1456,15 @@ static int dwc3_probe(struct platform_device *pdev) reset_control_assert(dwc->reset); put_clks: clk_bulk_put(dwc->num_clks, dwc->clks); } destroy_workqueue(dwc->dwc_wq); err0: /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; return ret; } Loading @@ -1429,16 +1472,17 @@ static int dwc3_probe(struct platform_device *pdev) static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pm_runtime_get_sync(&pdev->dev); /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; dwc3_debugfs_exit(dwc); dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); Loading Loading @@ -1630,6 +1674,10 @@ static int dwc3_runtime_suspend(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_SUSPEND_EVENT)) return 0; if (dwc3_runtime_checks(dwc)) return -EBUSY; Loading @@ -1647,6 +1695,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, PMSG_AUTO_RESUME); Loading Loading @@ -1696,6 +1748,10 @@ static int dwc3_suspend(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_SUSPEND_EVENT)) return 0; ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; Loading @@ -1710,6 +1766,10 @@ static int dwc3_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; pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); Loading drivers/usb/dwc3/core.h +90 −2 Original line number Diff line number Diff line Loading @@ -161,8 +161,20 @@ #define DWC3_OEVTEN 0xcc0C #define DWC3_OSTS 0xcc10 /* DWC 3.1 Link Registers */ #define DWC31_LINK_LU3LFPSRXTIM(n) (0xd010 + ((n) * 0x80)) #define GEN2_U3_EXIT_RSP_RX_CLK(n) ((n) << 16) #define GEN2_U3_EXIT_RSP_RX_CLK_MASK GEN2_U3_EXIT_RSP_RX_CLK(0xff) #define GEN1_U3_EXIT_RSP_RX_CLK(n) (n) #define GEN1_U3_EXIT_RSP_RX_CLK_MASK GEN1_U3_EXIT_RSP_RX_CLK(0xff) #define DWC31_LINK_GDBGLTSSM 0xd050 /* 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 Loading @@ -240,6 +252,9 @@ #define DWC3_GSTS_CSR_TIMEOUT BIT(5) #define DWC3_GSTS_BUS_ERR_ADDR_VLD BIT(4) /* Global Debug LTSSM Register */ #define DWC3_GDBGLTSSM_LINKSTATE_MASK (0xF << 22) /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) Loading Loading @@ -278,6 +293,7 @@ #define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) #define DWC3_GUSB3PIPECTL_DELAYP1TRANS BIT(18) /* Global TX Fifo Size Register */ #define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ Loading Loading @@ -458,6 +474,7 @@ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05 #define DWC3_DGCMD_XMIT_DEV 0x07 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c Loading Loading @@ -659,10 +676,13 @@ struct dwc3_ep_events { * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete * @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 * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation * @flags: endpoint flags (wedged, stalled, ...) Loading @@ -688,8 +708,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; struct dwc3 *dwc; u32 saved_state; Loading Loading @@ -906,6 +928,22 @@ 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 /* USB GSI event buffer related notification */ #define DWC3_GSI_EVT_BUF_ALLOC 9 #define DWC3_GSI_EVT_BUF_SETUP 10 #define DWC3_GSI_EVT_BUF_CLEANUP 11 #define DWC3_GSI_EVT_BUF_FREE 12 #define MAX_INTR_STATS 10 /** Loading Loading @@ -940,9 +978,11 @@ struct dwc3_scratchpad_array { * @current_otg_role: current role of operation while using the OTG block * @desired_otg_role: desired role of operation while using the OTG block * @otg_restart_host: flag that OTG controller needs to restart host * @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) * @maximum_speed: maximum speed to operate as requested by sw * @max_hw_supp_speed: maximum speed supported by hw design * @revision: revision register contents * @dr_mode: requested mode of operation * @current_dr_role: current role of operation when in dual-role mode Loading Loading @@ -1024,6 +1064,15 @@ struct dwc3_scratchpad_array { * 2 - No de-emphasis * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. * @err_evt_seen: previous event in queue was erratic error * @in_lpm: indicates if controller is in low power mode (no clocks) * @irq: irq number * @irq_cnt: total irq count * @bh_completion_time: time taken for IRQ bottom-half completion * @bh_handled_evt_cnt: no. of events handled per IRQ bottom-half * @irq_dbg_index: index for capturing IRQ stats * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @xhci_imod_value: imod value to use with xhci Loading Loading @@ -1080,6 +1129,7 @@ struct dwc3 { void __iomem *regs; size_t regs_size; phys_addr_t reg_phys; enum usb_dr_mode dr_mode; u32 current_dr_role; Loading @@ -1097,6 +1147,7 @@ struct dwc3 { u32 nr_scratch; u32 u1u2; u32 maximum_speed; u32 max_hw_supp_speed; /* * All 3.1 IP version constants are greater than the 3.0 IP Loading Loading @@ -1166,6 +1217,8 @@ struct dwc3 { const char *hsphy_interface; struct work_struct wakeup_work; unsigned connected:1; unsigned delayed_status:1; unsigned ep0_bounced:1; Loading Loading @@ -1199,25 +1252,45 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; unsigned err_evt_seen:1; unsigned enable_bus_suspend:1; atomic_t in_lpm; bool b_suspend; unsigned int vbus_draw; unsigned dis_metastability_quirk:1; u16 imod_interval; u32 xhci_imod_value; int core_id; struct workqueue_struct *dwc_wq; struct work_struct bh_work; unsigned long ep_cmd_timeout_cnt; unsigned long l1_remote_wakeup_cnt; wait_queue_head_t wait_linkstate; unsigned int index; void *dwc_ipc_log_ctxt; struct dwc3_gadget_events dbg_gadget_events; /* IRQ timing statistics */ int irq; unsigned long irq_cnt; unsigned int bh_completion_time[MAX_INTR_STATS]; unsigned int bh_handled_evt_cnt[MAX_INTR_STATS]; 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; /* Indicate if the gadget was powered by the otg driver */ unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned int softconnect:1; }; #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work)) Loading Loading @@ -1415,11 +1488,16 @@ 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_disable_irq(struct dwc3 *dwc); int dwc3_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(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 @@ -1434,6 +1512,12 @@ 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_disable_irq(struct dwc3 *dwc) { } static int dwc3_core_init(struct dwc3 *dwc) { return 0; } static int dwc3_event_buffers_setup(struct dwc3 *dwc) { return 0; } #endif #if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) Loading Loading @@ -1489,4 +1573,8 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); #endif /* __DRIVERS_USB_DWC3_CORE_H */ drivers/usb/dwc3/debugfs.c +67 −1 Original line number Diff line number Diff line Loading @@ -288,6 +288,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GCTL); spin_unlock_irqrestore(&dwc->lock, flags); Loading Loading @@ -320,7 +325,12 @@ static ssize_t dwc3_mode_write(struct file *file, struct seq_file *s = file->private_data; struct dwc3 *dwc = s->private; u32 mode = 0; char buf[32]; char buf[32] = {}; if (atomic_read(&dwc->in_lpm)) { dev_err(dwc->dev, "USB device is powered off\n"); return count; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -353,6 +363,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= DWC3_DCTL_TSTCTRL_MASK; Loading Loading @@ -399,6 +414,11 @@ static ssize_t dwc3_testmode_write(struct file *file, u32 testmode = 0; char buf[32]; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -437,6 +457,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) enum dwc3_link_state state; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DSTS); state = DWC3_DSTS_USBLNKST(reg); Loading @@ -461,6 +486,11 @@ static ssize_t dwc3_link_state_write(struct file *file, enum dwc3_link_state state = 0; char buf[32]; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -506,6 +536,11 @@ static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ); seq_printf(s, "%u\n", val); Loading @@ -521,6 +556,11 @@ static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ); seq_printf(s, "%u\n", val); Loading Loading @@ -551,6 +591,11 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); seq_printf(s, "%u\n", val); Loading @@ -566,6 +611,11 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); seq_printf(s, "%u\n", val); Loading @@ -581,6 +631,11 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); seq_printf(s, "%u\n", val); Loading @@ -596,6 +651,11 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); seq_printf(s, "%u\n", val); Loading Loading @@ -887,6 +947,12 @@ static int dwc3_gadget_int_events_show(struct seq_file *s, void *unused) seq_printf(s, "%d\t", dwc->bh_completion_time[i]); seq_putc(s, '\n'); seq_printf(s, "t_pwr evt irq : %lld\n", ktime_to_us(dwc->t_pwr_evt_irq)); seq_printf(s, "l1_remote_wakeup_cnt : %lu\n", dwc->l1_remote_wakeup_cnt); spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading Loading
Documentation/devicetree/bindings/usb/dwc3.txt +2 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ Optional properties: - snps,xhci-imod-value: Interrupt moderation interval for host mode (in increments of 250nsec). - usb-core-id: Differentiates between different controllers present on a device. - snps,bus-suspend-enable: If present then controller supports low power mode during bus suspend. - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated. Loading
drivers/usb/dwc3/Makefile +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0 # define_trace.h needs to know how to find our header CFLAGS_trace.o := -I$(src) CFLAGS_dwc3-msm.o := -Idrivers/usb/host -Idrivers/base/power obj-$(CONFIG_USB_DWC3) += dwc3.o Loading
drivers/usb/dwc3/core.c +185 −125 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/of.h> #include <linux/usb/otg.h> #include <linux/irq.h> #include "core.h" #include "gadget.h" Loading @@ -38,11 +39,28 @@ #include "debug.h" #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 500 /* ms */ static int count; static struct dwc3 *dwc3_instance[DWC_CTRL_COUNT]; static void dwc3_check_params(struct dwc3 *dwc); static void __dwc3_set_mode(struct dwc3 *dwc); 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); } /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure Loading Loading @@ -106,12 +124,14 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } static void __dwc3_set_mode(struct work_struct *work) static void __maybe_unused __dwc3_set_mode(struct dwc3 *dwc) { struct dwc3 *dwc = work_to_dwc(work); unsigned long flags; int ret; dev_dbg(dwc->dev, "%s(): desired_dr_role:%d curent_dr_role:%d\n", __func__, dwc->desired_dr_role, dwc->current_dr_role); if (dwc->dr_mode != USB_DR_MODE_OTG) return; Loading @@ -121,8 +141,10 @@ static void __dwc3_set_mode(struct work_struct *work) if (!dwc->desired_dr_role) return; if (dwc->desired_dr_role == dwc->current_dr_role) if (dwc->desired_dr_role == dwc->current_dr_role) { dwc3_set_prtcap(dwc, dwc->desired_dr_role); return; } if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) return; Loading Loading @@ -222,8 +244,36 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) int retries = 1000; int ret; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); /* Reset PHYs */ usb_phy_reset(dwc->usb2_phy); if (dwc->maximum_speed == USB_SPEED_SUPER) usb_phy_reset(dwc->usb3_phy); 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; } if (dwc->maximum_speed == USB_SPEED_HIGH) goto generic_phy_init; 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; } generic_phy_init: ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; Loading Loading @@ -355,6 +405,9 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) evt = dwc->ev_buf; if (evt) dwc3_free_one_event_buffer(dwc, evt); /* free GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE); } /** Loading @@ -376,6 +429,8 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) } dwc->ev_buf = evt; /* alloc GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC); return 0; } Loading @@ -399,6 +454,8 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* setup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP); return 0; } Loading @@ -415,6 +472,9 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(0)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* cleanup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -787,7 +847,7 @@ static int dwc3_core_ulpi_init(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 reg; int ret; Loading @@ -798,6 +858,13 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err0; } dwc3_cache_hwparams(dwc); ret = dwc3_get_dr_mode(dwc); if (ret) { ret = -EINVAL; goto err0; } /* * Write Linux Version Code to our GUID register so it's easy to figure * out which kernel version a bug was found. Loading Loading @@ -844,7 +911,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_frame_length_adjustment(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); if (dwc->maximum_speed >= USB_SPEED_SUPER) usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err2; Loading @@ -853,12 +922,6 @@ static int dwc3_core_init(struct dwc3 *dwc) 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; } /* * ENDXFER polling is available on version 3.10a and later of * the DWC_usb3 controller. It is NOT available in the Loading Loading @@ -923,10 +986,9 @@ static int dwc3_core_init(struct dwc3 *dwc) } } return 0; dwc3_check_params(dwc); err4: phy_power_off(dwc->usb3_generic_phy); return 0; err3: phy_power_off(dwc->usb2_generic_phy); Loading @@ -934,6 +996,7 @@ static int dwc3_core_init(struct dwc3 *dwc) err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_free_scratch_buffers(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); Loading Loading @@ -1015,61 +1078,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } 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_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; } 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; } phy_calibrate(dwc->usb2_generic_phy); break; case USB_DR_MODE_OTG: INIT_WORK(&dwc->drd_work, __dwc3_set_mode); ret = dwc3_drd_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize dual-role\n"); return ret; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } return 0; } static void dwc3_core_exit_mode(struct dwc3 *dwc) static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) { switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: Loading @@ -1087,6 +1096,26 @@ static void dwc3_core_exit_mode(struct dwc3 *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 (notify_event) notify_event(dwc, event); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); static void dwc3_get_properties(struct dwc3 *dwc) { struct device *dev = dwc->dev; Loading @@ -1111,6 +1140,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) hird_threshold = 12; dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_hw_supp_speed = dwc->maximum_speed; dwc->dr_mode = usb_get_dr_mode(dev); dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); Loading Loading @@ -1186,6 +1216,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); dwc->enable_bus_suspend = device_property_read_bool(dev, "snps,bus-suspend-enable"); dwc->dis_metastability_quirk = device_property_read_bool(dev, "snps,dis_metastability_quirk"); Loading Loading @@ -1272,6 +1304,14 @@ static int dwc3_probe(struct platform_device *pdev) int ret; void __iomem *regs; int irq; if (count >= DWC_CTRL_COUNT) { dev_err(dev, "Err dwc instance %d >= %d available\n", count, DWC_CTRL_COUNT); ret = -EINVAL; return ret; } dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) Loading @@ -1283,7 +1323,6 @@ static int dwc3_probe(struct platform_device *pdev) return -ENOMEM; dwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); Loading @@ -1296,6 +1335,21 @@ static int dwc3_probe(struct platform_device *pdev) dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; res->start += DWC3_GLOBALS_REGS_START; 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_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); return -ENODEV; } dwc->irq = irq; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. Loading @@ -1307,6 +1361,14 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); if (!dwc->dwc_wq) { dev_err(dev, "%s: Unable to create workqueue dwc_wq\n", __func__); goto err0; } INIT_WORK(&dwc->bh_work, dwc3_bh_work); dwc->regs = regs; dwc->regs_size = resource_size(&dwc_res); Loading @@ -1314,7 +1376,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); if (IS_ERR(dwc->reset)) return PTR_ERR(dwc->reset); goto skip_clk_reset; if (dev->of_node) { dwc->num_clks = ARRAY_SIZE(dwc3_core_clks); Loading Loading @@ -1342,47 +1404,32 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto unprepare_clks; skip_clk_reset: platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); init_waitqueue_head(&dwc->wait_linkstate); spin_lock_init(&dwc->lock); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); 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; goto err1; } ret = dwc3_get_dr_mode(dwc); if (ret) goto err3; 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; } dwc3_check_params(dwc); ret = dwc3_core_init_mode(dwc); if (ret) goto err5; goto err2; dwc3_debugfs_init(dwc); Loading @@ -1395,26 +1442,13 @@ static int dwc3_probe(struct platform_device *pdev) dwc->index = count; count++; pm_runtime_put(dev); pm_runtime_allow(dev); return 0; err5: dwc3_event_buffers_cleanup(dwc); err4: dwc3_free_scratch_buffers(dwc); err3: dwc3_free_event_buffers(dwc); err2: pm_runtime_allow(&pdev->dev); dwc3_free_event_buffers(dwc); err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); if (dwc->num_clks) { clk_bulk_disable(dwc->num_clks, dwc->clks); unprepare_clks: clk_bulk_unprepare(dwc->num_clks, dwc->clks); Loading @@ -1422,6 +1456,15 @@ static int dwc3_probe(struct platform_device *pdev) reset_control_assert(dwc->reset); put_clks: clk_bulk_put(dwc->num_clks, dwc->clks); } destroy_workqueue(dwc->dwc_wq); err0: /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; return ret; } Loading @@ -1429,16 +1472,17 @@ static int dwc3_probe(struct platform_device *pdev) static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pm_runtime_get_sync(&pdev->dev); /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; dwc3_debugfs_exit(dwc); dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); Loading Loading @@ -1630,6 +1674,10 @@ static int dwc3_runtime_suspend(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_SUSPEND_EVENT)) return 0; if (dwc3_runtime_checks(dwc)) return -EBUSY; Loading @@ -1647,6 +1695,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, PMSG_AUTO_RESUME); Loading Loading @@ -1696,6 +1748,10 @@ static int dwc3_suspend(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_SUSPEND_EVENT)) return 0; ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; Loading @@ -1710,6 +1766,10 @@ static int dwc3_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; pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); Loading
drivers/usb/dwc3/core.h +90 −2 Original line number Diff line number Diff line Loading @@ -161,8 +161,20 @@ #define DWC3_OEVTEN 0xcc0C #define DWC3_OSTS 0xcc10 /* DWC 3.1 Link Registers */ #define DWC31_LINK_LU3LFPSRXTIM(n) (0xd010 + ((n) * 0x80)) #define GEN2_U3_EXIT_RSP_RX_CLK(n) ((n) << 16) #define GEN2_U3_EXIT_RSP_RX_CLK_MASK GEN2_U3_EXIT_RSP_RX_CLK(0xff) #define GEN1_U3_EXIT_RSP_RX_CLK(n) (n) #define GEN1_U3_EXIT_RSP_RX_CLK_MASK GEN1_U3_EXIT_RSP_RX_CLK(0xff) #define DWC31_LINK_GDBGLTSSM 0xd050 /* 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 Loading @@ -240,6 +252,9 @@ #define DWC3_GSTS_CSR_TIMEOUT BIT(5) #define DWC3_GSTS_BUS_ERR_ADDR_VLD BIT(4) /* Global Debug LTSSM Register */ #define DWC3_GDBGLTSSM_LINKSTATE_MASK (0xF << 22) /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) Loading Loading @@ -278,6 +293,7 @@ #define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) #define DWC3_GUSB3PIPECTL_DELAYP1TRANS BIT(18) /* Global TX Fifo Size Register */ #define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ Loading Loading @@ -458,6 +474,7 @@ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05 #define DWC3_DGCMD_XMIT_DEV 0x07 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c Loading Loading @@ -659,10 +676,13 @@ struct dwc3_ep_events { * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete * @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 * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation * @flags: endpoint flags (wedged, stalled, ...) Loading @@ -688,8 +708,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; struct dwc3 *dwc; u32 saved_state; Loading Loading @@ -906,6 +928,22 @@ 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 /* USB GSI event buffer related notification */ #define DWC3_GSI_EVT_BUF_ALLOC 9 #define DWC3_GSI_EVT_BUF_SETUP 10 #define DWC3_GSI_EVT_BUF_CLEANUP 11 #define DWC3_GSI_EVT_BUF_FREE 12 #define MAX_INTR_STATS 10 /** Loading Loading @@ -940,9 +978,11 @@ struct dwc3_scratchpad_array { * @current_otg_role: current role of operation while using the OTG block * @desired_otg_role: desired role of operation while using the OTG block * @otg_restart_host: flag that OTG controller needs to restart host * @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) * @maximum_speed: maximum speed to operate as requested by sw * @max_hw_supp_speed: maximum speed supported by hw design * @revision: revision register contents * @dr_mode: requested mode of operation * @current_dr_role: current role of operation when in dual-role mode Loading Loading @@ -1024,6 +1064,15 @@ struct dwc3_scratchpad_array { * 2 - No de-emphasis * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. * @err_evt_seen: previous event in queue was erratic error * @in_lpm: indicates if controller is in low power mode (no clocks) * @irq: irq number * @irq_cnt: total irq count * @bh_completion_time: time taken for IRQ bottom-half completion * @bh_handled_evt_cnt: no. of events handled per IRQ bottom-half * @irq_dbg_index: index for capturing IRQ stats * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @xhci_imod_value: imod value to use with xhci Loading Loading @@ -1080,6 +1129,7 @@ struct dwc3 { void __iomem *regs; size_t regs_size; phys_addr_t reg_phys; enum usb_dr_mode dr_mode; u32 current_dr_role; Loading @@ -1097,6 +1147,7 @@ struct dwc3 { u32 nr_scratch; u32 u1u2; u32 maximum_speed; u32 max_hw_supp_speed; /* * All 3.1 IP version constants are greater than the 3.0 IP Loading Loading @@ -1166,6 +1217,8 @@ struct dwc3 { const char *hsphy_interface; struct work_struct wakeup_work; unsigned connected:1; unsigned delayed_status:1; unsigned ep0_bounced:1; Loading Loading @@ -1199,25 +1252,45 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; unsigned err_evt_seen:1; unsigned enable_bus_suspend:1; atomic_t in_lpm; bool b_suspend; unsigned int vbus_draw; unsigned dis_metastability_quirk:1; u16 imod_interval; u32 xhci_imod_value; int core_id; struct workqueue_struct *dwc_wq; struct work_struct bh_work; unsigned long ep_cmd_timeout_cnt; unsigned long l1_remote_wakeup_cnt; wait_queue_head_t wait_linkstate; unsigned int index; void *dwc_ipc_log_ctxt; struct dwc3_gadget_events dbg_gadget_events; /* IRQ timing statistics */ int irq; unsigned long irq_cnt; unsigned int bh_completion_time[MAX_INTR_STATS]; unsigned int bh_handled_evt_cnt[MAX_INTR_STATS]; 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; /* Indicate if the gadget was powered by the otg driver */ unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ unsigned int softconnect:1; }; #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work)) Loading Loading @@ -1415,11 +1488,16 @@ 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_disable_irq(struct dwc3 *dwc); int dwc3_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(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 @@ -1434,6 +1512,12 @@ 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_disable_irq(struct dwc3 *dwc) { } static int dwc3_core_init(struct dwc3 *dwc) { return 0; } static int dwc3_event_buffers_setup(struct dwc3 *dwc) { return 0; } #endif #if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) Loading Loading @@ -1489,4 +1573,8 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); #endif /* __DRIVERS_USB_DWC3_CORE_H */
drivers/usb/dwc3/debugfs.c +67 −1 Original line number Diff line number Diff line Loading @@ -288,6 +288,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GCTL); spin_unlock_irqrestore(&dwc->lock, flags); Loading Loading @@ -320,7 +325,12 @@ static ssize_t dwc3_mode_write(struct file *file, struct seq_file *s = file->private_data; struct dwc3 *dwc = s->private; u32 mode = 0; char buf[32]; char buf[32] = {}; if (atomic_read(&dwc->in_lpm)) { dev_err(dwc->dev, "USB device is powered off\n"); return count; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -353,6 +363,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= DWC3_DCTL_TSTCTRL_MASK; Loading Loading @@ -399,6 +414,11 @@ static ssize_t dwc3_testmode_write(struct file *file, u32 testmode = 0; char buf[32]; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -437,6 +457,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) enum dwc3_link_state state; u32 reg; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DSTS); state = DWC3_DSTS_USBLNKST(reg); Loading @@ -461,6 +486,11 @@ static ssize_t dwc3_link_state_write(struct file *file, enum dwc3_link_state state = 0; char buf[32]; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; Loading Loading @@ -506,6 +536,11 @@ static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ); seq_printf(s, "%u\n", val); Loading @@ -521,6 +556,11 @@ static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ); seq_printf(s, "%u\n", val); Loading Loading @@ -551,6 +591,11 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); seq_printf(s, "%u\n", val); Loading @@ -566,6 +611,11 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); seq_printf(s, "%u\n", val); Loading @@ -581,6 +631,11 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); seq_printf(s, "%u\n", val); Loading @@ -596,6 +651,11 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; if (atomic_read(&dwc->in_lpm)) { seq_puts(s, "USB device is powered off\n"); return 0; } spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); seq_printf(s, "%u\n", val); Loading Loading @@ -887,6 +947,12 @@ static int dwc3_gadget_int_events_show(struct seq_file *s, void *unused) seq_printf(s, "%d\t", dwc->bh_completion_time[i]); seq_putc(s, '\n'); seq_printf(s, "t_pwr evt irq : %lld\n", ktime_to_us(dwc->t_pwr_evt_irq)); seq_printf(s, "l1_remote_wakeup_cnt : %lu\n", dwc->l1_remote_wakeup_cnt); spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading