91 lines
3.2 KiB
Diff
91 lines
3.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: William Wu <[email protected]>
|
|
Date: Thu, 15 Dec 2022 14:19:28 +0800
|
|
Subject: usb: dwc2: gadget: Disable nak interrupt when get first isoc in token
|
|
|
|
The dwc2 driver use the nak interrupt for the starting point
|
|
of isoc-in transfer. The first nak interrupt for isoc-in means
|
|
that in token has arrived and the dwc2 driver can obtain the
|
|
(micro) frame of the token to set the even/odd (micro) frame
|
|
field of DIEPCTL.
|
|
|
|
However, on some platforms (e.g Rockchip rk3308) which don't
|
|
support the "OTG_MULTI_PROC_INTRPT", it means that all device
|
|
endpoints share the same nak mask and interrupt. If the nak
|
|
interrupt is always enabled, it may trigger nak interrupt storm
|
|
by other endpoints except the isoc-in endpoint. So we disable
|
|
the nak interrupt when get first isoc in token if the feature
|
|
"OTG_MULTI_PROC_INTRPT" isn't enabled.
|
|
|
|
Signed-off-by: William Wu <[email protected]>
|
|
Change-Id: I99c71a5e0d7903346fd8f71619b6736c3181c0ec
|
|
---
|
|
drivers/usb/dwc2/gadget.c | 37 +++++++++-
|
|
1 file changed, 35 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/usb/dwc2/gadget.c
|
|
+++ b/drivers/usb/dwc2/gadget.c
|
|
@@ -1399,6 +1399,8 @@ static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg,
|
|
return 0;
|
|
}
|
|
|
|
+static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep);
|
|
+
|
|
static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|
gfp_t gfp_flags)
|
|
{
|
|
@@ -1519,6 +1521,20 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|
|
|
if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
|
|
dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
|
|
+ } else if (hs_ep->isochronous && hs_ep->dir_in && !hs_ep->req &&
|
|
+ !(dwc2_readl(hs, GHWCFG2) & GHWCFG2_MULTI_PROC_INT)) {
|
|
+ /* Update current frame number value. */
|
|
+ hs->frame_number = dwc2_hsotg_read_frameno(hs);
|
|
+ while (dwc2_gadget_target_frame_elapsed(hs_ep)) {
|
|
+ dwc2_gadget_incr_frame_num(hs_ep);
|
|
+ /* Update current frame number value once more as it
|
|
+ * changes here.
|
|
+ */
|
|
+ hs->frame_number = dwc2_hsotg_read_frameno(hs);
|
|
+ }
|
|
+
|
|
+ if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
|
|
+ dwc2_gadget_start_next_request(hs_ep);
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -2991,8 +3007,25 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
|
|
|
|
hs_ep->target_frame = hsotg->frame_number;
|
|
if (hs_ep->interval > 1) {
|
|
- u32 ctrl = dwc2_readl(hsotg,
|
|
- DIEPCTL(hs_ep->index));
|
|
+ u32 mask;
|
|
+ u32 ctrl;
|
|
+
|
|
+ /*
|
|
+ * Disable nak interrupt when we have got the first
|
|
+ * isoc in token. This can avoid nak interrupt storm
|
|
+ * on the Rockchip platforms which don't support the
|
|
+ * "OTG_MULTI_PROC_INTRPT", and all device endpoints
|
|
+ * share the same nak mask and interrupt.
|
|
+ */
|
|
+ if (!(dwc2_readl(hsotg, GHWCFG2) &
|
|
+ GHWCFG2_MULTI_PROC_INT)) {
|
|
+ mask = dwc2_readl(hsotg, DIEPMSK);
|
|
+ mask &= ~DIEPMSK_NAKMSK;
|
|
+ dwc2_writel(hsotg, mask, DIEPMSK);
|
|
+ }
|
|
+
|
|
+ ctrl = dwc2_readl(hsotg,
|
|
+ DIEPCTL(hs_ep->index));
|
|
if (hs_ep->target_frame & 0x1)
|
|
ctrl |= DXEPCTL_SETODDFR;
|
|
else
|
|
--
|
|
Armbian
|
|
|