Loading drivers/usb/dwc3/core.c +32 −2 Original line number Diff line number Diff line Loading @@ -670,6 +670,16 @@ int dwc3_core_init(struct dwc3 *dwc) } } /* * Workaround for STAR 9000961433 which affects only version * 3.00a of the DWC_usb3 core. This prevents the controller * interrupt from being masked while handling events. IMOD * allows us to work around this issue. Enable it for the * affected version. */ if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A)) dwc->imod_interval = 1; ret = dwc3_core_reset(dwc); if (ret) goto err0; Loading Loading @@ -1000,6 +1010,15 @@ err0: #define DWC3_ALIGN_MASK (16 - 1) /* check whether the core supports IMOD */ bool dwc3_has_imod(struct dwc3 *dwc) { return ((dwc3_is_usb3(dwc) && dwc->revision >= DWC3_REVISION_300A) || (dwc3_is_usb31(dwc) && dwc->revision >= DWC3_USB31_REVISION_120A)); } static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; Loading Loading @@ -1040,8 +1059,8 @@ static int dwc3_probe(struct platform_device *pdev) /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); 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); Loading Loading @@ -1219,6 +1238,14 @@ static int dwc3_probe(struct platform_device *pdev) dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); if (!dwc->dwc_wq) { pr_err("%s: Unable to create workqueue dwc_wq\n", __func__); return -ENOMEM; } INIT_WORK(&dwc->bh_work, dwc3_bh_work); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); Loading Loading @@ -1284,6 +1311,7 @@ err0: * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; destroy_workqueue(dwc->dwc_wq); return ret; } Loading Loading @@ -1313,6 +1341,8 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); destroy_workqueue(dwc->dwc_wq); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); Loading drivers/usb/dwc3/core.h +31 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ #define DWC3_DEVICE_EVENT_OVERFLOW 11 #define DWC3_GEVNTCOUNT_MASK 0xfffc #define DWC3_GEVNTCOUNT_EHB (1 << 31) #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff Loading Loading @@ -149,6 +150,8 @@ #define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10)) #define DWC3_DEPCMD(n) (0xc80c + (n * 0x10)) #define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4)) /* OTG Registers */ #define DWC3_OCFG 0xcc00 #define DWC3_OCTL 0xcc04 Loading Loading @@ -433,6 +436,11 @@ #define DWC3_DEPCMD_TYPE_BULK 2 #define DWC3_DEPCMD_TYPE_INTR 3 #define DWC3_DEV_IMOD_COUNT_SHIFT 16 #define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16) #define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 #define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0) /* Structures */ struct dwc3_trb; Loading Loading @@ -837,6 +845,8 @@ struct dwc3_scratchpad_array { * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -920,6 +930,7 @@ struct dwc3 { #define DWC3_REVISION_260A 0x5533260a #define DWC3_REVISION_270A 0x5533270a #define DWC3_REVISION_280A 0x5533280a #define DWC3_REVISION_300A 0x5533300a #define DWC3_REVISION_310A 0x5533310a /* Loading @@ -928,6 +939,7 @@ struct dwc3 { */ #define DWC3_REVISION_IS_DWC31 0x80000000 #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31) #define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; Loading Loading @@ -1008,6 +1020,11 @@ struct dwc3 { bool b_suspend; unsigned vbus_draw; u16 imod_interval; struct workqueue_struct *dwc_wq; struct work_struct bh_work; /* IRQ timing statistics */ int irq; unsigned long irq_cnt; Loading Loading @@ -1175,6 +1192,20 @@ struct dwc3_gadget_ep_cmd_params { void dwc3_set_mode(struct dwc3 *dwc, u32 mode); int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); /* check whether we are on the DWC_usb3 core */ static inline bool dwc3_is_usb3(struct dwc3 *dwc) { return !(dwc->revision & DWC3_REVISION_IS_DWC31); } /* check whether we are on the DWC_usb31 core */ static inline bool dwc3_is_usb31(struct dwc3 *dwc) { return !!(dwc->revision & DWC3_REVISION_IS_DWC31); } bool dwc3_has_imod(struct dwc3 *dwc); #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); Loading drivers/usb/dwc3/dwc3-msm.c +3 −0 Original line number Diff line number Diff line Loading @@ -2053,6 +2053,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) if (dwc->irq) disable_irq(dwc->irq); if (work_busy(&dwc->bh_work)) dbg_event(0xFF, "pend evt", 0); /* disable power event irq, hs and ss phy irq is used as wake up src */ disable_irq(mdwc->pwr_event_irq); Loading drivers/usb/dwc3/gadget.c +27 −3 Original line number Diff line number Diff line Loading @@ -2011,6 +2011,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) int ret = 0; u32 reg; /* * Use IMOD if enabled via dwc->imod_interval. Otherwise, if * the core supports IMOD, disable it. */ if (dwc->imod_interval) { dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); } else if (dwc3_has_imod(dwc)) { dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); } reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); Loading Loading @@ -3362,8 +3373,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) */ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; left -= 4; dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); } dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4); Loading @@ -3377,9 +3386,22 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) reg &= ~DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); if (dwc->imod_interval) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), DWC3_GEVNTCOUNT_EHB); return ret; } void dwc3_bh_work(struct work_struct *w) { struct dwc3 *dwc = container_of(w, struct dwc3, bh_work); pm_runtime_get_sync(dwc->dev); dwc3_thread_interrupt(dwc->irq, dwc); pm_runtime_put(dwc->dev); } static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; Loading Loading @@ -3434,6 +3456,8 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) reg |= DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), count); return IRQ_WAKE_THREAD; } Loading Loading @@ -3469,7 +3493,7 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc) dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; if (ret == IRQ_WAKE_THREAD) dwc3_thread_interrupt(dwc->irq, dwc); queue_work(dwc->dwc_wq, &dwc->bh_work); return IRQ_HANDLED; } Loading drivers/usb/dwc3/gadget.h +1 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); irqreturn_t dwc3_interrupt(int irq, void *_dwc); void dwc3_bh_work(struct work_struct *w); static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, struct dwc3_trb *trb) Loading Loading
drivers/usb/dwc3/core.c +32 −2 Original line number Diff line number Diff line Loading @@ -670,6 +670,16 @@ int dwc3_core_init(struct dwc3 *dwc) } } /* * Workaround for STAR 9000961433 which affects only version * 3.00a of the DWC_usb3 core. This prevents the controller * interrupt from being masked while handling events. IMOD * allows us to work around this issue. Enable it for the * affected version. */ if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A)) dwc->imod_interval = 1; ret = dwc3_core_reset(dwc); if (ret) goto err0; Loading Loading @@ -1000,6 +1010,15 @@ err0: #define DWC3_ALIGN_MASK (16 - 1) /* check whether the core supports IMOD */ bool dwc3_has_imod(struct dwc3 *dwc) { return ((dwc3_is_usb3(dwc) && dwc->revision >= DWC3_REVISION_300A) || (dwc3_is_usb31(dwc) && dwc->revision >= DWC3_USB31_REVISION_120A)); } static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; Loading Loading @@ -1040,8 +1059,8 @@ static int dwc3_probe(struct platform_device *pdev) /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); 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); Loading Loading @@ -1219,6 +1238,14 @@ static int dwc3_probe(struct platform_device *pdev) dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); if (!dwc->dwc_wq) { pr_err("%s: Unable to create workqueue dwc_wq\n", __func__); return -ENOMEM; } INIT_WORK(&dwc->bh_work, dwc3_bh_work); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); Loading Loading @@ -1284,6 +1311,7 @@ err0: * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; destroy_workqueue(dwc->dwc_wq); return ret; } Loading Loading @@ -1313,6 +1341,8 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); destroy_workqueue(dwc->dwc_wq); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); Loading
drivers/usb/dwc3/core.h +31 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ #define DWC3_DEVICE_EVENT_OVERFLOW 11 #define DWC3_GEVNTCOUNT_MASK 0xfffc #define DWC3_GEVNTCOUNT_EHB (1 << 31) #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff Loading Loading @@ -149,6 +150,8 @@ #define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10)) #define DWC3_DEPCMD(n) (0xc80c + (n * 0x10)) #define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4)) /* OTG Registers */ #define DWC3_OCFG 0xcc00 #define DWC3_OCTL 0xcc04 Loading Loading @@ -433,6 +436,11 @@ #define DWC3_DEPCMD_TYPE_BULK 2 #define DWC3_DEPCMD_TYPE_INTR 3 #define DWC3_DEV_IMOD_COUNT_SHIFT 16 #define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16) #define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 #define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0) /* Structures */ struct dwc3_trb; Loading Loading @@ -837,6 +845,8 @@ struct dwc3_scratchpad_array { * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -920,6 +930,7 @@ struct dwc3 { #define DWC3_REVISION_260A 0x5533260a #define DWC3_REVISION_270A 0x5533270a #define DWC3_REVISION_280A 0x5533280a #define DWC3_REVISION_300A 0x5533300a #define DWC3_REVISION_310A 0x5533310a /* Loading @@ -928,6 +939,7 @@ struct dwc3 { */ #define DWC3_REVISION_IS_DWC31 0x80000000 #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31) #define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; Loading Loading @@ -1008,6 +1020,11 @@ struct dwc3 { bool b_suspend; unsigned vbus_draw; u16 imod_interval; struct workqueue_struct *dwc_wq; struct work_struct bh_work; /* IRQ timing statistics */ int irq; unsigned long irq_cnt; Loading Loading @@ -1175,6 +1192,20 @@ struct dwc3_gadget_ep_cmd_params { void dwc3_set_mode(struct dwc3 *dwc, u32 mode); int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); /* check whether we are on the DWC_usb3 core */ static inline bool dwc3_is_usb3(struct dwc3 *dwc) { return !(dwc->revision & DWC3_REVISION_IS_DWC31); } /* check whether we are on the DWC_usb31 core */ static inline bool dwc3_is_usb31(struct dwc3 *dwc) { return !!(dwc->revision & DWC3_REVISION_IS_DWC31); } bool dwc3_has_imod(struct dwc3 *dwc); #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); Loading
drivers/usb/dwc3/dwc3-msm.c +3 −0 Original line number Diff line number Diff line Loading @@ -2053,6 +2053,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) if (dwc->irq) disable_irq(dwc->irq); if (work_busy(&dwc->bh_work)) dbg_event(0xFF, "pend evt", 0); /* disable power event irq, hs and ss phy irq is used as wake up src */ disable_irq(mdwc->pwr_event_irq); Loading
drivers/usb/dwc3/gadget.c +27 −3 Original line number Diff line number Diff line Loading @@ -2011,6 +2011,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) int ret = 0; u32 reg; /* * Use IMOD if enabled via dwc->imod_interval. Otherwise, if * the core supports IMOD, disable it. */ if (dwc->imod_interval) { dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); } else if (dwc3_has_imod(dwc)) { dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); } reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); Loading Loading @@ -3362,8 +3373,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) */ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; left -= 4; dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); } dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4); Loading @@ -3377,9 +3386,22 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) reg &= ~DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); if (dwc->imod_interval) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), DWC3_GEVNTCOUNT_EHB); return ret; } void dwc3_bh_work(struct work_struct *w) { struct dwc3 *dwc = container_of(w, struct dwc3, bh_work); pm_runtime_get_sync(dwc->dev); dwc3_thread_interrupt(dwc->irq, dwc); pm_runtime_put(dwc->dev); } static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; Loading Loading @@ -3434,6 +3456,8 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) reg |= DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), count); return IRQ_WAKE_THREAD; } Loading Loading @@ -3469,7 +3493,7 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc) dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; if (ret == IRQ_WAKE_THREAD) dwc3_thread_interrupt(dwc->irq, dwc); queue_work(dwc->dwc_wq, &dwc->bh_work); return IRQ_HANDLED; } Loading
drivers/usb/dwc3/gadget.h +1 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); irqreturn_t dwc3_interrupt(int irq, void *_dwc); void dwc3_bh_work(struct work_struct *w); static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, struct dwc3_trb *trb) Loading