Loading drivers/usb/dwc3/core.c +169 −71 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,13 @@ #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); /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure Loading Loading @@ -114,6 +117,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } EXPORT_SYMBOL(dwc3_set_prtcap); static void __dwc3_set_mode(struct work_struct *work) { Loading Loading @@ -230,8 +234,28 @@ 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); 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_SUPER) { 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 Loading @@ -376,6 +400,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, 0); } /** Loading @@ -397,6 +424,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, 0); return 0; } Loading @@ -420,6 +449,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, 0); return 0; } Loading @@ -436,6 +467,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, 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -904,11 +938,24 @@ static void dwc3_set_incr_burst_type(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; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; 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 @@ -957,7 +1004,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(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 @@ -966,12 +1015,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 @@ -1059,10 +1102,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } 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 @@ -1070,6 +1112,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 @@ -1083,6 +1126,7 @@ static int dwc3_core_init(struct dwc3 *dwc) err0: return ret; } EXPORT_SYMBOL(dwc3_core_init); static int dwc3_core_get_phy(struct dwc3 *dwc) { Loading Loading @@ -1151,7 +1195,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } static int dwc3_core_init_mode(struct dwc3 *dwc) static int __maybe_unused dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; Loading Loading @@ -1204,7 +1248,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) 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 @@ -1222,6 +1266,29 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) } } static void (*notify_event)(struct dwc3 *, enum dwc3_notify_event, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, enum dwc3_notify_event, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value) { int ret = 0; if (notify_event) notify_event(dwc, event, value); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); static void dwc3_get_properties(struct dwc3 *dwc) { struct device *dev = dwc->dev; Loading @@ -1246,6 +1313,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 @@ -1322,6 +1390,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 @@ -1410,6 +1480,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 @@ -1421,19 +1499,34 @@ 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"); 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; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; irq = platform_get_irq(to_platform_device(dwc->dev), 0); 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; } if (notify_event) /* will be enabled in dwc3_msm_resume() */ disable_irq(irq); dwc->irq = irq; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. Loading @@ -1445,6 +1538,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 @@ -1459,7 +1560,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks); if (ret == -EPROBE_DEFER) return ret; goto err0; /* * Clocks are optional, but new DT platforms should support all * clocks as required by the DT-binding. Loading @@ -1470,60 +1571,58 @@ static int dwc3_probe(struct platform_device *pdev) ret = reset_control_deassert(dwc->reset); if (ret) return ret; goto err0; ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks); if (ret) goto assert_reset; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; goto disable_clks; } platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); 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; goto err2; if (!notify_event) { ret = dwc3_core_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize core: %d\n", ret); goto err4; dev_err(dev, "failed to initialize core: %d\n", ret); goto err3; } dwc3_check_params(dwc); ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err3; } ret = dwc3_core_init_mode(dwc); if (ret) goto err5; if (ret) { dwc3_event_buffers_cleanup(dwc); goto err3; } } dwc3_debugfs_init(dwc); Loading @@ -1536,32 +1635,22 @@ 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); dwc3_ulpi_exit(dwc); err4: dwc3_free_scratch_buffers(dwc); err3: dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); err2: pm_runtime_allow(&pdev->dev); dwc3_free_event_buffers(dwc); err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); disable_clks: clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); assert_reset: reset_control_assert(dwc->reset); destroy_workqueue(dwc->dwc_wq); err0: return ret; } Loading @@ -1569,15 +1658,8 @@ static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); pm_runtime_get_sync(&pdev->dev); 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 @@ -1764,6 +1846,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, 0)) return 0; if (dwc3_runtime_checks(dwc)) return -EBUSY; Loading @@ -1781,6 +1867,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, 0)) return 0; device_init_wakeup(dev, false); ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); Loading Loading @@ -1830,6 +1920,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, 0)) return 0; ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; Loading @@ -1844,6 +1938,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, 0)) return 0; pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); Loading drivers/usb/dwc3/core.h +93 −2 Original line number Diff line number Diff line Loading @@ -162,8 +162,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 SoC Bus Configuration INCRx Register 0 */ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */ Loading Loading @@ -265,6 +277,9 @@ #define DWC3_GSTS_CURMOD_DEVICE 0 #define DWC3_GSTS_CURMOD_HOST 1 /* 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 @@ -294,6 +309,7 @@ #define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28) #define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27) #define DWC3_GUSB3PIPECTL_REQP1P2P3 BIT(24) #define DWC3_GUSB3PIPECTL_DISRXDETU3 BIT(22) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) Loading @@ -303,6 +319,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 @@ -483,6 +500,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 @@ -683,10 +701,13 @@ struct dwc3_ep_events { * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint * @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 Loading @@ -714,8 +735,10 @@ struct dwc3_ep { 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 @@ -751,6 +774,7 @@ struct dwc3_ep { unsigned direction:1; unsigned stream_capable:1; unsigned gsi:1; /* For isochronous START TRANSFER workaround only */ u8 combo_num; Loading @@ -759,6 +783,7 @@ struct dwc3_ep { struct dwc3_ep_events dbg_ep_events; struct dwc3_ep_events dbg_ep_events_diff; ktime_t dbg_ep_events_kt; int fifo_depth; }; enum dwc3_phy { Loading Loading @@ -980,9 +1005,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 * @version_type: VERSIONTYPE register contents, a sub release of a revision * @dr_mode: requested mode of operation Loading Loading @@ -1071,6 +1098,14 @@ 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 * @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 @@ -1126,6 +1161,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 @@ -1143,6 +1179,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 @@ -1265,24 +1302,42 @@ 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; struct workqueue_struct *dwc_wq; struct work_struct bh_work; unsigned long ep_cmd_timeout_cnt; 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 INCRX_BURST_MODE 0 Loading Loading @@ -1483,11 +1538,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 @@ -1502,6 +1562,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 @@ -1557,4 +1623,29 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif enum dwc3_notify_event { DWC3_CONTROLLER_ERROR_EVENT, DWC3_CONTROLLER_RESET_EVENT, DWC3_CONTROLLER_POST_RESET_EVENT, DWC3_CORE_PM_SUSPEND_EVENT, DWC3_CORE_PM_RESUME_EVENT, DWC3_CONTROLLER_CONNDONE_EVENT, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, /* USB GSI event buffer related notification */ DWC3_GSI_EVT_BUF_ALLOC, DWC3_GSI_EVT_BUF_SETUP, DWC3_GSI_EVT_BUF_CLEANUP, DWC3_GSI_EVT_BUF_CLEAR, DWC3_GSI_EVT_BUF_FREE, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, }; extern void dwc3_set_notifier(void (*notify)(struct dwc3 *dwc3, enum dwc3_notify_event event, unsigned int value)); extern int dwc3_notify_event(struct dwc3 *dwc3, enum dwc3_notify_event event, unsigned int value); #endif /* __DRIVERS_USB_DWC3_CORE_H */ drivers/usb/dwc3/debug_ipc.c +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ void dwc3_dbg_print(struct dwc3 *dwc, u8 ep_num, const char *name, ipc_log_string(dwc->dwc_ipc_log_ctxt, "%02X %-25.25s %4i ?\t%s", ep_num, name, status, extra); } EXPORT_SYMBOL(dwc3_dbg_print); /** * dwc3_dbg_done: prints a DONE event Loading drivers/usb/dwc3/debugfs.c +70 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,11 @@ static int dwc3_lsp_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_GSTS); current_mode = DWC3_GSTS_CURMOD(reg); Loading Loading @@ -394,6 +399,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 @@ -428,6 +438,11 @@ static ssize_t dwc3_mode_write(struct file *file, u32 mode = 0; 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 @@ -459,6 +474,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 @@ -505,6 +525,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 @@ -544,6 +569,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) u32 reg; u8 speed; 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_GSTS); if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { Loading Loading @@ -580,6 +610,11 @@ static ssize_t dwc3_link_state_write(struct file *file, u32 reg; u8 speed; 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 @@ -640,6 +675,11 @@ static int dwc3_tx_fifo_size_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_TXFIFO); Loading @@ -659,6 +699,11 @@ static int dwc3_rx_fifo_size_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_RXFIFO); Loading Loading @@ -693,6 +738,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 @@ -708,6 +758,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 @@ -723,6 +778,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 @@ -738,6 +798,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 @@ -1052,6 +1117,11 @@ 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, "ep_cmd_timeout_cnt : %lu\n", dwc->ep_cmd_timeout_cnt); spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading Loading
drivers/usb/dwc3/core.c +169 −71 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,13 @@ #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); /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure Loading Loading @@ -114,6 +117,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } EXPORT_SYMBOL(dwc3_set_prtcap); static void __dwc3_set_mode(struct work_struct *work) { Loading Loading @@ -230,8 +234,28 @@ 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); 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_SUPER) { 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 Loading @@ -376,6 +400,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, 0); } /** Loading @@ -397,6 +424,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, 0); return 0; } Loading @@ -420,6 +449,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, 0); return 0; } Loading @@ -436,6 +467,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, 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -904,11 +938,24 @@ static void dwc3_set_incr_burst_type(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; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; 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 @@ -957,7 +1004,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(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 @@ -966,12 +1015,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 @@ -1059,10 +1102,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } 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 @@ -1070,6 +1112,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 @@ -1083,6 +1126,7 @@ static int dwc3_core_init(struct dwc3 *dwc) err0: return ret; } EXPORT_SYMBOL(dwc3_core_init); static int dwc3_core_get_phy(struct dwc3 *dwc) { Loading Loading @@ -1151,7 +1195,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } static int dwc3_core_init_mode(struct dwc3 *dwc) static int __maybe_unused dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; Loading Loading @@ -1204,7 +1248,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) 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 @@ -1222,6 +1266,29 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) } } static void (*notify_event)(struct dwc3 *, enum dwc3_notify_event, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, enum dwc3_notify_event, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value) { int ret = 0; if (notify_event) notify_event(dwc, event, value); else ret = -ENODEV; return ret; } EXPORT_SYMBOL(dwc3_notify_event); static void dwc3_get_properties(struct dwc3 *dwc) { struct device *dev = dwc->dev; Loading @@ -1246,6 +1313,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 @@ -1322,6 +1390,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 @@ -1410,6 +1480,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 @@ -1421,19 +1499,34 @@ 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"); 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; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; irq = platform_get_irq(to_platform_device(dwc->dev), 0); 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; } if (notify_event) /* will be enabled in dwc3_msm_resume() */ disable_irq(irq); dwc->irq = irq; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. Loading @@ -1445,6 +1538,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 @@ -1459,7 +1560,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks); if (ret == -EPROBE_DEFER) return ret; goto err0; /* * Clocks are optional, but new DT platforms should support all * clocks as required by the DT-binding. Loading @@ -1470,60 +1571,58 @@ static int dwc3_probe(struct platform_device *pdev) ret = reset_control_deassert(dwc->reset); if (ret) return ret; goto err0; ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks); if (ret) goto assert_reset; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; goto disable_clks; } platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); 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; goto err2; if (!notify_event) { ret = dwc3_core_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize core: %d\n", ret); goto err4; dev_err(dev, "failed to initialize core: %d\n", ret); goto err3; } dwc3_check_params(dwc); ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err3; } ret = dwc3_core_init_mode(dwc); if (ret) goto err5; if (ret) { dwc3_event_buffers_cleanup(dwc); goto err3; } } dwc3_debugfs_init(dwc); Loading @@ -1536,32 +1635,22 @@ 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); dwc3_ulpi_exit(dwc); err4: dwc3_free_scratch_buffers(dwc); err3: dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); err2: pm_runtime_allow(&pdev->dev); dwc3_free_event_buffers(dwc); err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); disable_clks: clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); assert_reset: reset_control_assert(dwc->reset); destroy_workqueue(dwc->dwc_wq); err0: return ret; } Loading @@ -1569,15 +1658,8 @@ static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); pm_runtime_get_sync(&pdev->dev); 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 @@ -1764,6 +1846,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, 0)) return 0; if (dwc3_runtime_checks(dwc)) return -EBUSY; Loading @@ -1781,6 +1867,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, 0)) return 0; device_init_wakeup(dev, false); ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); Loading Loading @@ -1830,6 +1920,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, 0)) return 0; ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; Loading @@ -1844,6 +1938,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, 0)) return 0; pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); Loading
drivers/usb/dwc3/core.h +93 −2 Original line number Diff line number Diff line Loading @@ -162,8 +162,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 SoC Bus Configuration INCRx Register 0 */ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */ Loading Loading @@ -265,6 +277,9 @@ #define DWC3_GSTS_CURMOD_DEVICE 0 #define DWC3_GSTS_CURMOD_HOST 1 /* 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 @@ -294,6 +309,7 @@ #define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28) #define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27) #define DWC3_GUSB3PIPECTL_REQP1P2P3 BIT(24) #define DWC3_GUSB3PIPECTL_DISRXDETU3 BIT(22) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) Loading @@ -303,6 +319,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 @@ -483,6 +500,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 @@ -683,10 +701,13 @@ struct dwc3_ep_events { * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint * @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 Loading @@ -714,8 +735,10 @@ struct dwc3_ep { 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 @@ -751,6 +774,7 @@ struct dwc3_ep { unsigned direction:1; unsigned stream_capable:1; unsigned gsi:1; /* For isochronous START TRANSFER workaround only */ u8 combo_num; Loading @@ -759,6 +783,7 @@ struct dwc3_ep { struct dwc3_ep_events dbg_ep_events; struct dwc3_ep_events dbg_ep_events_diff; ktime_t dbg_ep_events_kt; int fifo_depth; }; enum dwc3_phy { Loading Loading @@ -980,9 +1005,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 * @version_type: VERSIONTYPE register contents, a sub release of a revision * @dr_mode: requested mode of operation Loading Loading @@ -1071,6 +1098,14 @@ 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 * @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 @@ -1126,6 +1161,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 @@ -1143,6 +1179,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 @@ -1265,24 +1302,42 @@ 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; struct workqueue_struct *dwc_wq; struct work_struct bh_work; unsigned long ep_cmd_timeout_cnt; 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 INCRX_BURST_MODE 0 Loading Loading @@ -1483,11 +1538,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 @@ -1502,6 +1562,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 @@ -1557,4 +1623,29 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif enum dwc3_notify_event { DWC3_CONTROLLER_ERROR_EVENT, DWC3_CONTROLLER_RESET_EVENT, DWC3_CONTROLLER_POST_RESET_EVENT, DWC3_CORE_PM_SUSPEND_EVENT, DWC3_CORE_PM_RESUME_EVENT, DWC3_CONTROLLER_CONNDONE_EVENT, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, /* USB GSI event buffer related notification */ DWC3_GSI_EVT_BUF_ALLOC, DWC3_GSI_EVT_BUF_SETUP, DWC3_GSI_EVT_BUF_CLEANUP, DWC3_GSI_EVT_BUF_CLEAR, DWC3_GSI_EVT_BUF_FREE, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, }; extern void dwc3_set_notifier(void (*notify)(struct dwc3 *dwc3, enum dwc3_notify_event event, unsigned int value)); extern int dwc3_notify_event(struct dwc3 *dwc3, enum dwc3_notify_event event, unsigned int value); #endif /* __DRIVERS_USB_DWC3_CORE_H */
drivers/usb/dwc3/debug_ipc.c +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ void dwc3_dbg_print(struct dwc3 *dwc, u8 ep_num, const char *name, ipc_log_string(dwc->dwc_ipc_log_ctxt, "%02X %-25.25s %4i ?\t%s", ep_num, name, status, extra); } EXPORT_SYMBOL(dwc3_dbg_print); /** * dwc3_dbg_done: prints a DONE event Loading
drivers/usb/dwc3/debugfs.c +70 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,11 @@ static int dwc3_lsp_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_GSTS); current_mode = DWC3_GSTS_CURMOD(reg); Loading Loading @@ -394,6 +399,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 @@ -428,6 +438,11 @@ static ssize_t dwc3_mode_write(struct file *file, u32 mode = 0; 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 @@ -459,6 +474,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 @@ -505,6 +525,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 @@ -544,6 +569,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) u32 reg; u8 speed; 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_GSTS); if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { Loading Loading @@ -580,6 +610,11 @@ static ssize_t dwc3_link_state_write(struct file *file, u32 reg; u8 speed; 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 @@ -640,6 +675,11 @@ static int dwc3_tx_fifo_size_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_TXFIFO); Loading @@ -659,6 +699,11 @@ static int dwc3_rx_fifo_size_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_RXFIFO); Loading Loading @@ -693,6 +738,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 @@ -708,6 +758,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 @@ -723,6 +778,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 @@ -738,6 +798,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 @@ -1052,6 +1117,11 @@ 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, "ep_cmd_timeout_cnt : %lu\n", dwc->ep_cmd_timeout_cnt); spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading