Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 837e9f00 authored by Vardan Mikayelyan's avatar Vardan Mikayelyan Committed by Felipe Balbi
Browse files

usb: dwc2: gadget: Final fixes for BDMA ISOC



Done fixes and tested hsotg gadget's BDMA mode. Tested Control,
Bulk, Isoc, Inter transfers. Added code for isoc transfers,
removed unusable code, done minor fixes. Affected functions
and IRQ handlers:
- dwc2_hsotg_start_req(),
- dwc2_hsotg_ep_enable(),
- dwc2_hsotg_ep_queue(),
- dwc2_hsotg_handle_outdone(),
- GINTSTS_GOUTNAKEFF handler,

Removed 'has_correct_parity' flag from 'dwc2_hsotg_ep' struct.
Before this patch series, to set the data pid the DWC2 gadget
driver was toggling the even/odd until it match, then were
leaving it set. But now I have added mechanism to set pid and
excluded all code where this flag was set.

Tested-by: default avatarJohn Keeping <john@metanate.com>
Signed-off-by: default avatarVardan Mikayelyan <mvardan@synopsys.com>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent bd9971f0
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -215,7 +215,6 @@ struct dwc2_hsotg_ep {
	unsigned int            periodic:1;
	unsigned int            periodic:1;
	unsigned int            isochronous:1;
	unsigned int            isochronous:1;
	unsigned int            send_zlp:1;
	unsigned int            send_zlp:1;
	unsigned int            has_correct_parity:1;
	unsigned int            target_frame;
	unsigned int            target_frame;
#define TARGET_FRAME_INITIAL   0xFFFFFFFF
#define TARGET_FRAME_INITIAL   0xFFFFFFFF
	bool			frame_overrun;
	bool			frame_overrun;
+70 −27
Original line number Original line Diff line number Diff line
@@ -667,6 +667,16 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
			__func__, &ureq->dma, dma_reg);
			__func__, &ureq->dma, dma_reg);
	}
	}


	if (hs_ep->isochronous && hs_ep->interval == 1) {
		hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
		dwc2_gadget_incr_frame_num(hs_ep);

		if (hs_ep->target_frame & 0x1)
			ctrl |= DXEPCTL_SETODDFR;
		else
			ctrl |= DXEPCTL_SETEVENFR;
	}

	ctrl |= DXEPCTL_EPENA;	/* ensure ep enabled */
	ctrl |= DXEPCTL_EPENA;	/* ensure ep enabled */


	dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
	dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
@@ -863,9 +873,18 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
	first = list_empty(&hs_ep->queue);
	first = list_empty(&hs_ep->queue);
	list_add_tail(&hs_req->queue, &hs_ep->queue);
	list_add_tail(&hs_req->queue, &hs_ep->queue);


	if (first)
	if (first) {
		if (!hs_ep->isochronous) {
			dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
			dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
			return 0;
		}

		while (dwc2_gadget_target_frame_elapsed(hs_ep))
			dwc2_gadget_incr_frame_num(hs_ep);


		if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
			dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
	}
	return 0;
	return 0;
}
}


@@ -1673,9 +1692,10 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
	 * adjust the ISOC parity here.
	 * adjust the ISOC parity here.
	 */
	 */
	if (!using_dma(hsotg)) {
	if (!using_dma(hsotg)) {
		hs_ep->has_correct_parity = 1;
		if (hs_ep->isochronous && hs_ep->interval == 1)
		if (hs_ep->isochronous && hs_ep->interval == 1)
			dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum));
			dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum));
		else if (hs_ep->isochronous && hs_ep->interval > 1)
			dwc2_gadget_incr_frame_num(hs_ep);
	}
	}


	dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
	dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
@@ -2216,11 +2236,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
	if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
	if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
		ints &= ~DXEPINT_XFERCOMPL;
		ints &= ~DXEPINT_XFERCOMPL;


	if (ints & DXEPINT_XFERCOMPL) {
	if (ints & DXEPINT_STSPHSERCVD)
		hs_ep->has_correct_parity = 1;
		dev_dbg(hsotg->dev, "%s: StsPhseRcvd asserted\n", __func__);
		if (hs_ep->isochronous && hs_ep->interval == 1)
			dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);


	if (ints & DXEPINT_XFERCOMPL) {
		dev_dbg(hsotg->dev,
		dev_dbg(hsotg->dev,
			"%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
			"%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
			__func__, dwc2_readl(hsotg->regs + epctl_reg),
			__func__, dwc2_readl(hsotg->regs + epctl_reg),
@@ -2231,7 +2250,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
		 * at completing IN requests here
		 * at completing IN requests here
		 */
		 */
		if (dir_in) {
		if (dir_in) {
			if (hs_ep->isochronous && hs_ep->interval > 1)
				dwc2_gadget_incr_frame_num(hs_ep);

			dwc2_hsotg_complete_in(hsotg, hs_ep);
			dwc2_hsotg_complete_in(hsotg, hs_ep);
			if (ints & DXEPINT_NAKINTRPT)
				ints &= ~DXEPINT_NAKINTRPT;


			if (idx == 0 && !hs_ep->req)
			if (idx == 0 && !hs_ep->req)
				dwc2_hsotg_enqueue_setup(hsotg);
				dwc2_hsotg_enqueue_setup(hsotg);
@@ -2240,6 +2264,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
			 * We're using DMA, we need to fire an OutDone here
			 * We're using DMA, we need to fire an OutDone here
			 * as we ignore the RXFIFO.
			 * as we ignore the RXFIFO.
			 */
			 */
			if (hs_ep->isochronous && hs_ep->interval > 1)
				dwc2_gadget_incr_frame_num(hs_ep);


			dwc2_hsotg_handle_outdone(hsotg, idx);
			dwc2_hsotg_handle_outdone(hsotg, idx);
		}
		}
@@ -2556,18 +2582,16 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
	dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
	dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
		DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
		DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
		DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
		DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK,
		DIEPMSK_INTKNEPMISMSK,
		hsotg->regs + DIEPMSK);
		hsotg->regs + DIEPMSK);


	/*
	/*
	 * don't need XferCompl, we get that from RXFIFO in slave mode. In
	 * don't need XferCompl, we get that from RXFIFO in slave mode. In
	 * DMA mode we may need this.
	 * DMA mode we may need this.
	 */
	 */
	dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
	dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK) : 0) |
				    DIEPMSK_TIMEOUTMSK) : 0) |
		DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
		DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
		DOEPMSK_SETUPMSK,
		DOEPMSK_SETUPMSK | DOEPMSK_STSPHSERCVDMSK,
		hsotg->regs + DOEPMSK);
		hsotg->regs + DOEPMSK);


	dwc2_writel(0, hsotg->regs + DAINTMSK);
	dwc2_writel(0, hsotg->regs + DAINTMSK);
@@ -2858,11 +2882,29 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
	 */
	 */


	if (gintsts & GINTSTS_GOUTNAKEFF) {
	if (gintsts & GINTSTS_GOUTNAKEFF) {
		dev_info(hsotg->dev, "GOUTNakEff triggered\n");
		u8 idx;
		u32 epctrl;
		u32 gintmsk;
		struct dwc2_hsotg_ep *hs_ep;


		__orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
		/* Mask this interrupt */
		gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
		gintmsk &= ~GINTSTS_GOUTNAKEFF;
		dwc2_writel(gintmsk, hsotg->regs + GINTMSK);


		dwc2_hsotg_dump(hsotg);
		dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
		for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
			hs_ep = hsotg->eps_out[idx];
			epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));

			if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
				epctrl |= DXEPCTL_SNAK;
				epctrl |= DXEPCTL_EPDIS;
				dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx));
			}
		}

		/* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */
	}
	}


	if (gintsts & GINTSTS_GINNAKEFF) {
	if (gintsts & GINTSTS_GINNAKEFF) {
@@ -2909,6 +2951,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
	u32 epctrl_reg;
	u32 epctrl_reg;
	u32 epctrl;
	u32 epctrl;
	u32 mps;
	u32 mps;
	u32 mask;
	unsigned int dir_in;
	unsigned int dir_in;
	unsigned int i, val, size;
	unsigned int i, val, size;
	int ret = 0;
	int ret = 0;
@@ -2951,15 +2994,6 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
	 */
	 */
	epctrl |= DXEPCTL_USBACTEP;
	epctrl |= DXEPCTL_USBACTEP;


	/*
	 * set the NAK status on the endpoint, otherwise we might try and
	 * do something with data that we've yet got a request to process
	 * since the RXFIFO will take data for an endpoint even if the
	 * size register hasn't been set.
	 */

	epctrl |= DXEPCTL_SNAK;

	/* update the endpoint state */
	/* update the endpoint state */
	dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);
	dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);


@@ -2975,8 +3009,17 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
		epctrl |= DXEPCTL_SETEVENFR;
		epctrl |= DXEPCTL_SETEVENFR;
		hs_ep->isochronous = 1;
		hs_ep->isochronous = 1;
		hs_ep->interval = 1 << (desc->bInterval - 1);
		hs_ep->interval = 1 << (desc->bInterval - 1);
		if (dir_in)
		hs_ep->target_frame = TARGET_FRAME_INITIAL;
		if (dir_in) {
			hs_ep->periodic = 1;
			hs_ep->periodic = 1;
			mask = dwc2_readl(hsotg->regs + DIEPMSK);
			mask |= DIEPMSK_NAKMSK;
			dwc2_writel(mask, hsotg->regs + DIEPMSK);
		} else {
			mask = dwc2_readl(hsotg->regs + DOEPMSK);
			mask |= DOEPMSK_OUTTKNEPDISMSK;
			dwc2_writel(mask, hsotg->regs + DOEPMSK);
		}
		break;
		break;


	case USB_ENDPOINT_XFER_BULK:
	case USB_ENDPOINT_XFER_BULK:
@@ -3043,7 +3086,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
	}
	}


	/* for non control endpoints, set PID to D0 */
	/* for non control endpoints, set PID to D0 */
	if (index)
	if (index && !hs_ep->isochronous)
		epctrl |= DXEPCTL_SETD0PID;
		epctrl |= DXEPCTL_SETD0PID;


	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
+1 −0
Original line number Original line Diff line number Diff line
@@ -560,6 +560,7 @@
#define DXEPINT_INEPNAKEFF		(1 << 6)
#define DXEPINT_INEPNAKEFF		(1 << 6)
#define DXEPINT_BACK2BACKSETUP		(1 << 6)
#define DXEPINT_BACK2BACKSETUP		(1 << 6)
#define DXEPINT_INTKNEPMIS		(1 << 5)
#define DXEPINT_INTKNEPMIS		(1 << 5)
#define DXEPINT_STSPHSERCVD		(1 << 5)
#define DXEPINT_INTKNTXFEMP		(1 << 4)
#define DXEPINT_INTKNTXFEMP		(1 << 4)
#define DXEPINT_OUTTKNEPDIS		(1 << 4)
#define DXEPINT_OUTTKNEPDIS		(1 << 4)
#define DXEPINT_TIMEOUT			(1 << 3)
#define DXEPINT_TIMEOUT			(1 << 3)