xref: /openbmc/linux/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
13eb1f1efSPawel Laszczak // SPDX-License-Identifier: GPL-2.0
23eb1f1efSPawel Laszczak /*
33eb1f1efSPawel Laszczak  * Cadence USBHS-DEV Driver - gadget side.
43eb1f1efSPawel Laszczak  *
53eb1f1efSPawel Laszczak  * Copyright (C) 2023 Cadence Design Systems.
63eb1f1efSPawel Laszczak  *
73eb1f1efSPawel Laszczak  * Authors: Pawel Laszczak <pawell@cadence.com>
83eb1f1efSPawel Laszczak  */
93eb1f1efSPawel Laszczak 
103eb1f1efSPawel Laszczak /*
113eb1f1efSPawel Laszczak  * Work around 1:
123eb1f1efSPawel Laszczak  * At some situations, the controller may get stale data address in TRB
133eb1f1efSPawel Laszczak  * at below sequences:
143eb1f1efSPawel Laszczak  * 1. Controller read TRB includes data address
153eb1f1efSPawel Laszczak  * 2. Software updates TRBs includes data address and Cycle bit
163eb1f1efSPawel Laszczak  * 3. Controller read TRB which includes Cycle bit
173eb1f1efSPawel Laszczak  * 4. DMA run with stale data address
183eb1f1efSPawel Laszczak  *
193eb1f1efSPawel Laszczak  * To fix this problem, driver needs to make the first TRB in TD as invalid.
203eb1f1efSPawel Laszczak  * After preparing all TRBs driver needs to check the position of DMA and
213eb1f1efSPawel Laszczak  * if the DMA point to the first just added TRB and doorbell is 1,
223eb1f1efSPawel Laszczak  * then driver must defer making this TRB as valid. This TRB will be make
233eb1f1efSPawel Laszczak  * as valid during adding next TRB only if DMA is stopped or at TRBERR
243eb1f1efSPawel Laszczak  * interrupt.
253eb1f1efSPawel Laszczak  *
263eb1f1efSPawel Laszczak  */
273eb1f1efSPawel Laszczak 
283eb1f1efSPawel Laszczak #include <linux/dma-mapping.h>
293eb1f1efSPawel Laszczak #include <linux/pm_runtime.h>
303eb1f1efSPawel Laszczak #include <linux/interrupt.h>
313eb1f1efSPawel Laszczak #include <linux/property.h>
323eb1f1efSPawel Laszczak #include <linux/dmapool.h>
333eb1f1efSPawel Laszczak #include <linux/iopoll.h>
343eb1f1efSPawel Laszczak 
353eb1f1efSPawel Laszczak #include "cdns2-gadget.h"
3607a3aef2SPawel Laszczak #include "cdns2-trace.h"
373eb1f1efSPawel Laszczak 
383eb1f1efSPawel Laszczak /**
393eb1f1efSPawel Laszczak  * set_reg_bit_32 - set bit in given 32 bits register.
403eb1f1efSPawel Laszczak  * @ptr: register address.
413eb1f1efSPawel Laszczak  * @mask: bits to set.
423eb1f1efSPawel Laszczak  */
set_reg_bit_32(void __iomem * ptr,u32 mask)433eb1f1efSPawel Laszczak static void set_reg_bit_32(void __iomem *ptr, u32 mask)
443eb1f1efSPawel Laszczak {
453eb1f1efSPawel Laszczak 	mask = readl(ptr) | mask;
463eb1f1efSPawel Laszczak 	writel(mask, ptr);
473eb1f1efSPawel Laszczak }
483eb1f1efSPawel Laszczak 
493eb1f1efSPawel Laszczak /*
503eb1f1efSPawel Laszczak  * clear_reg_bit_32 - clear bit in given 32 bits register.
513eb1f1efSPawel Laszczak  * @ptr: register address.
523eb1f1efSPawel Laszczak  * @mask: bits to clear.
533eb1f1efSPawel Laszczak  */
clear_reg_bit_32(void __iomem * ptr,u32 mask)543eb1f1efSPawel Laszczak static void clear_reg_bit_32(void __iomem *ptr, u32 mask)
553eb1f1efSPawel Laszczak {
563eb1f1efSPawel Laszczak 	mask = readl(ptr) & ~mask;
573eb1f1efSPawel Laszczak 	writel(mask, ptr);
583eb1f1efSPawel Laszczak }
593eb1f1efSPawel Laszczak 
603eb1f1efSPawel Laszczak /* Clear bit in given 8 bits register. */
clear_reg_bit_8(void __iomem * ptr,u8 mask)613eb1f1efSPawel Laszczak static void clear_reg_bit_8(void __iomem *ptr, u8 mask)
623eb1f1efSPawel Laszczak {
633eb1f1efSPawel Laszczak 	mask = readb(ptr) & ~mask;
643eb1f1efSPawel Laszczak 	writeb(mask, ptr);
653eb1f1efSPawel Laszczak }
663eb1f1efSPawel Laszczak 
673eb1f1efSPawel Laszczak /* Set bit in given 16 bits register. */
set_reg_bit_8(void __iomem * ptr,u8 mask)683eb1f1efSPawel Laszczak void set_reg_bit_8(void __iomem *ptr, u8 mask)
693eb1f1efSPawel Laszczak {
703eb1f1efSPawel Laszczak 	mask = readb(ptr) | mask;
713eb1f1efSPawel Laszczak 	writeb(mask, ptr);
723eb1f1efSPawel Laszczak }
733eb1f1efSPawel Laszczak 
cdns2_get_dma_pos(struct cdns2_device * pdev,struct cdns2_endpoint * pep)743eb1f1efSPawel Laszczak static int cdns2_get_dma_pos(struct cdns2_device *pdev,
753eb1f1efSPawel Laszczak 			     struct cdns2_endpoint *pep)
763eb1f1efSPawel Laszczak {
773eb1f1efSPawel Laszczak 	int dma_index;
783eb1f1efSPawel Laszczak 
793eb1f1efSPawel Laszczak 	dma_index = readl(&pdev->adma_regs->ep_traddr) - pep->ring.dma;
803eb1f1efSPawel Laszczak 
813eb1f1efSPawel Laszczak 	return dma_index / TRB_SIZE;
823eb1f1efSPawel Laszczak }
833eb1f1efSPawel Laszczak 
843eb1f1efSPawel Laszczak /* Get next private request from list. */
cdns2_next_preq(struct list_head * list)853eb1f1efSPawel Laszczak struct cdns2_request *cdns2_next_preq(struct list_head *list)
863eb1f1efSPawel Laszczak {
873eb1f1efSPawel Laszczak 	return list_first_entry_or_null(list, struct cdns2_request, list);
883eb1f1efSPawel Laszczak }
893eb1f1efSPawel Laszczak 
cdns2_select_ep(struct cdns2_device * pdev,u32 ep)903eb1f1efSPawel Laszczak void cdns2_select_ep(struct cdns2_device *pdev, u32 ep)
913eb1f1efSPawel Laszczak {
923eb1f1efSPawel Laszczak 	if (pdev->selected_ep == ep)
933eb1f1efSPawel Laszczak 		return;
943eb1f1efSPawel Laszczak 
953eb1f1efSPawel Laszczak 	pdev->selected_ep = ep;
963eb1f1efSPawel Laszczak 	writel(ep, &pdev->adma_regs->ep_sel);
973eb1f1efSPawel Laszczak }
983eb1f1efSPawel Laszczak 
cdns2_trb_virt_to_dma(struct cdns2_endpoint * pep,struct cdns2_trb * trb)993eb1f1efSPawel Laszczak dma_addr_t cdns2_trb_virt_to_dma(struct cdns2_endpoint *pep,
1003eb1f1efSPawel Laszczak 				 struct cdns2_trb *trb)
1013eb1f1efSPawel Laszczak {
1023eb1f1efSPawel Laszczak 	u32 offset = (char *)trb - (char *)pep->ring.trbs;
1033eb1f1efSPawel Laszczak 
1043eb1f1efSPawel Laszczak 	return pep->ring.dma + offset;
1053eb1f1efSPawel Laszczak }
1063eb1f1efSPawel Laszczak 
cdns2_free_tr_segment(struct cdns2_endpoint * pep)1073eb1f1efSPawel Laszczak static void cdns2_free_tr_segment(struct cdns2_endpoint *pep)
1083eb1f1efSPawel Laszczak {
1093eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
1103eb1f1efSPawel Laszczak 	struct cdns2_ring *ring = &pep->ring;
1113eb1f1efSPawel Laszczak 
1123eb1f1efSPawel Laszczak 	if (pep->ring.trbs) {
1133eb1f1efSPawel Laszczak 		dma_pool_free(pdev->eps_dma_pool, ring->trbs, ring->dma);
1143eb1f1efSPawel Laszczak 		memset(ring, 0, sizeof(*ring));
1153eb1f1efSPawel Laszczak 	}
1163eb1f1efSPawel Laszczak }
1173eb1f1efSPawel Laszczak 
1183eb1f1efSPawel Laszczak /* Allocates Transfer Ring segment. */
cdns2_alloc_tr_segment(struct cdns2_endpoint * pep)1193eb1f1efSPawel Laszczak static int cdns2_alloc_tr_segment(struct cdns2_endpoint *pep)
1203eb1f1efSPawel Laszczak {
1213eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
1223eb1f1efSPawel Laszczak 	struct cdns2_trb *link_trb;
1233eb1f1efSPawel Laszczak 	struct cdns2_ring *ring;
1243eb1f1efSPawel Laszczak 
1253eb1f1efSPawel Laszczak 	ring = &pep->ring;
1263eb1f1efSPawel Laszczak 
1273eb1f1efSPawel Laszczak 	if (!ring->trbs) {
1283eb1f1efSPawel Laszczak 		ring->trbs = dma_pool_alloc(pdev->eps_dma_pool,
1293eb1f1efSPawel Laszczak 					    GFP_DMA32 | GFP_ATOMIC,
1303eb1f1efSPawel Laszczak 					    &ring->dma);
1313eb1f1efSPawel Laszczak 		if (!ring->trbs)
1323eb1f1efSPawel Laszczak 			return -ENOMEM;
1333eb1f1efSPawel Laszczak 	}
1343eb1f1efSPawel Laszczak 
1353eb1f1efSPawel Laszczak 	memset(ring->trbs, 0, TR_SEG_SIZE);
1363eb1f1efSPawel Laszczak 
1373eb1f1efSPawel Laszczak 	if (!pep->num)
1383eb1f1efSPawel Laszczak 		return 0;
1393eb1f1efSPawel Laszczak 
1403eb1f1efSPawel Laszczak 	/* Initialize the last TRB as Link TRB */
1413eb1f1efSPawel Laszczak 	link_trb = (ring->trbs + (TRBS_PER_SEGMENT - 1));
1423eb1f1efSPawel Laszczak 	link_trb->buffer = cpu_to_le32(TRB_BUFFER(ring->dma));
1433eb1f1efSPawel Laszczak 	link_trb->control = cpu_to_le32(TRB_CYCLE | TRB_TYPE(TRB_LINK) |
1443eb1f1efSPawel Laszczak 					TRB_TOGGLE);
1453eb1f1efSPawel Laszczak 
1463eb1f1efSPawel Laszczak 	return 0;
1473eb1f1efSPawel Laszczak }
1483eb1f1efSPawel Laszczak 
1493eb1f1efSPawel Laszczak /*
1503eb1f1efSPawel Laszczak  * Stalls and flushes selected endpoint.
1513eb1f1efSPawel Laszczak  * Endpoint must be selected before invoking this function.
1523eb1f1efSPawel Laszczak  */
cdns2_ep_stall_flush(struct cdns2_endpoint * pep)1533eb1f1efSPawel Laszczak static void cdns2_ep_stall_flush(struct cdns2_endpoint *pep)
1543eb1f1efSPawel Laszczak {
1553eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
1563eb1f1efSPawel Laszczak 	int val;
1573eb1f1efSPawel Laszczak 
15807a3aef2SPawel Laszczak 	trace_cdns2_ep_halt(pep, 1, 1);
15907a3aef2SPawel Laszczak 
1603eb1f1efSPawel Laszczak 	writel(DMA_EP_CMD_DFLUSH, &pdev->adma_regs->ep_cmd);
1613eb1f1efSPawel Laszczak 
1623eb1f1efSPawel Laszczak 	/* Wait for DFLUSH cleared. */
1633eb1f1efSPawel Laszczak 	readl_poll_timeout_atomic(&pdev->adma_regs->ep_cmd, val,
1643eb1f1efSPawel Laszczak 				  !(val & DMA_EP_CMD_DFLUSH), 1, 1000);
1653eb1f1efSPawel Laszczak 	pep->ep_state |= EP_STALLED;
1663eb1f1efSPawel Laszczak 	pep->ep_state &= ~EP_STALL_PENDING;
1673eb1f1efSPawel Laszczak }
1683eb1f1efSPawel Laszczak 
1693eb1f1efSPawel Laszczak /*
1703eb1f1efSPawel Laszczak  * Increment a trb index.
1713eb1f1efSPawel Laszczak  *
1723eb1f1efSPawel Laszczak  * The index should never point to the last link TRB in TR. After incrementing,
1733eb1f1efSPawel Laszczak  * if it point to the link TRB, wrap around to the beginning and revert
1743eb1f1efSPawel Laszczak  * cycle state bit. The link TRB is always at the last TRB entry.
1753eb1f1efSPawel Laszczak  */
cdns2_ep_inc_trb(int * index,u8 * cs,int trb_in_seg)1763eb1f1efSPawel Laszczak static void cdns2_ep_inc_trb(int *index, u8 *cs, int trb_in_seg)
1773eb1f1efSPawel Laszczak {
1783eb1f1efSPawel Laszczak 	(*index)++;
1793eb1f1efSPawel Laszczak 	if (*index == (trb_in_seg - 1)) {
1803eb1f1efSPawel Laszczak 		*index = 0;
1813eb1f1efSPawel Laszczak 		*cs ^=  1;
1823eb1f1efSPawel Laszczak 	}
1833eb1f1efSPawel Laszczak }
1843eb1f1efSPawel Laszczak 
cdns2_ep_inc_enq(struct cdns2_ring * ring)1853eb1f1efSPawel Laszczak static void cdns2_ep_inc_enq(struct cdns2_ring *ring)
1863eb1f1efSPawel Laszczak {
1873eb1f1efSPawel Laszczak 	ring->free_trbs--;
1883eb1f1efSPawel Laszczak 	cdns2_ep_inc_trb(&ring->enqueue, &ring->pcs, TRBS_PER_SEGMENT);
1893eb1f1efSPawel Laszczak }
1903eb1f1efSPawel Laszczak 
cdns2_ep_inc_deq(struct cdns2_ring * ring)1913eb1f1efSPawel Laszczak static void cdns2_ep_inc_deq(struct cdns2_ring *ring)
1923eb1f1efSPawel Laszczak {
1933eb1f1efSPawel Laszczak 	ring->free_trbs++;
1943eb1f1efSPawel Laszczak 	cdns2_ep_inc_trb(&ring->dequeue, &ring->ccs, TRBS_PER_SEGMENT);
1953eb1f1efSPawel Laszczak }
1963eb1f1efSPawel Laszczak 
1973eb1f1efSPawel Laszczak /*
1983eb1f1efSPawel Laszczak  * Enable/disable LPM.
1993eb1f1efSPawel Laszczak  *
2003eb1f1efSPawel Laszczak  * If bit USBCS_LPMNYET is not set and device receive Extended Token packet,
2013eb1f1efSPawel Laszczak  * then controller answer with ACK handshake.
2023eb1f1efSPawel Laszczak  * If bit USBCS_LPMNYET is set and device receive Extended Token packet,
2033eb1f1efSPawel Laszczak  * then controller answer with NYET handshake.
2043eb1f1efSPawel Laszczak  */
cdns2_enable_l1(struct cdns2_device * pdev,int enable)2053eb1f1efSPawel Laszczak static void cdns2_enable_l1(struct cdns2_device *pdev, int enable)
2063eb1f1efSPawel Laszczak {
2073eb1f1efSPawel Laszczak 	if (enable) {
2083eb1f1efSPawel Laszczak 		clear_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_LPMNYET);
2093eb1f1efSPawel Laszczak 		writeb(LPMCLOCK_SLEEP_ENTRY, &pdev->usb_regs->lpmclock);
2103eb1f1efSPawel Laszczak 	} else {
2113eb1f1efSPawel Laszczak 		set_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_LPMNYET);
2123eb1f1efSPawel Laszczak 	}
2133eb1f1efSPawel Laszczak }
2143eb1f1efSPawel Laszczak 
cdns2_get_speed(struct cdns2_device * pdev)2153eb1f1efSPawel Laszczak static enum usb_device_speed cdns2_get_speed(struct cdns2_device *pdev)
2163eb1f1efSPawel Laszczak {
2173eb1f1efSPawel Laszczak 	u8 speed = readb(&pdev->usb_regs->speedctrl);
2183eb1f1efSPawel Laszczak 
2193eb1f1efSPawel Laszczak 	if (speed & SPEEDCTRL_HS)
2203eb1f1efSPawel Laszczak 		return USB_SPEED_HIGH;
2213eb1f1efSPawel Laszczak 	else if (speed & SPEEDCTRL_FS)
2223eb1f1efSPawel Laszczak 		return USB_SPEED_FULL;
2233eb1f1efSPawel Laszczak 
2243eb1f1efSPawel Laszczak 	return USB_SPEED_UNKNOWN;
2253eb1f1efSPawel Laszczak }
2263eb1f1efSPawel Laszczak 
cdns2_next_trb(struct cdns2_endpoint * pep,struct cdns2_trb * trb)2273eb1f1efSPawel Laszczak static struct cdns2_trb *cdns2_next_trb(struct cdns2_endpoint *pep,
2283eb1f1efSPawel Laszczak 					struct cdns2_trb *trb)
2293eb1f1efSPawel Laszczak {
2303eb1f1efSPawel Laszczak 	if (trb == (pep->ring.trbs + (TRBS_PER_SEGMENT - 1)))
2313eb1f1efSPawel Laszczak 		return pep->ring.trbs;
2323eb1f1efSPawel Laszczak 	else
2333eb1f1efSPawel Laszczak 		return ++trb;
2343eb1f1efSPawel Laszczak }
2353eb1f1efSPawel Laszczak 
cdns2_gadget_giveback(struct cdns2_endpoint * pep,struct cdns2_request * preq,int status)2363eb1f1efSPawel Laszczak void cdns2_gadget_giveback(struct cdns2_endpoint *pep,
2373eb1f1efSPawel Laszczak 			   struct cdns2_request *preq,
2383eb1f1efSPawel Laszczak 			   int status)
2393eb1f1efSPawel Laszczak {
2403eb1f1efSPawel Laszczak 	struct usb_request *request = &preq->request;
2413eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
2423eb1f1efSPawel Laszczak 
2433eb1f1efSPawel Laszczak 	list_del_init(&preq->list);
2443eb1f1efSPawel Laszczak 
2453eb1f1efSPawel Laszczak 	if (request->status == -EINPROGRESS)
2463eb1f1efSPawel Laszczak 		request->status = status;
2473eb1f1efSPawel Laszczak 
2483eb1f1efSPawel Laszczak 	usb_gadget_unmap_request_by_dev(pdev->dev, request, pep->dir);
2493eb1f1efSPawel Laszczak 
2503eb1f1efSPawel Laszczak 	/* All TRBs have finished, clear the counter. */
2513eb1f1efSPawel Laszczak 	preq->finished_trb = 0;
2523eb1f1efSPawel Laszczak 
25307a3aef2SPawel Laszczak 	trace_cdns2_request_giveback(preq);
25407a3aef2SPawel Laszczak 
2553eb1f1efSPawel Laszczak 	if (request->complete) {
2563eb1f1efSPawel Laszczak 		spin_unlock(&pdev->lock);
2573eb1f1efSPawel Laszczak 		usb_gadget_giveback_request(&pep->endpoint, request);
2583eb1f1efSPawel Laszczak 		spin_lock(&pdev->lock);
2593eb1f1efSPawel Laszczak 	}
2603eb1f1efSPawel Laszczak 
2613eb1f1efSPawel Laszczak 	if (request->buf == pdev->zlp_buf)
2623eb1f1efSPawel Laszczak 		cdns2_gadget_ep_free_request(&pep->endpoint, request);
2633eb1f1efSPawel Laszczak }
2643eb1f1efSPawel Laszczak 
cdns2_wa1_restore_cycle_bit(struct cdns2_endpoint * pep)2653eb1f1efSPawel Laszczak static void cdns2_wa1_restore_cycle_bit(struct cdns2_endpoint *pep)
2663eb1f1efSPawel Laszczak {
2673eb1f1efSPawel Laszczak 	/* Work around for stale data address in TRB. */
2683eb1f1efSPawel Laszczak 	if (pep->wa1_set) {
26907a3aef2SPawel Laszczak 		trace_cdns2_wa1(pep, "restore cycle bit");
27007a3aef2SPawel Laszczak 
2713eb1f1efSPawel Laszczak 		pep->wa1_set = 0;
2723eb1f1efSPawel Laszczak 		pep->wa1_trb_index = 0xFFFF;
2733eb1f1efSPawel Laszczak 		if (pep->wa1_cycle_bit)
2743eb1f1efSPawel Laszczak 			pep->wa1_trb->control |= cpu_to_le32(0x1);
2753eb1f1efSPawel Laszczak 		else
2763eb1f1efSPawel Laszczak 			pep->wa1_trb->control &= cpu_to_le32(~0x1);
2773eb1f1efSPawel Laszczak 	}
2783eb1f1efSPawel Laszczak }
2793eb1f1efSPawel Laszczak 
cdns2_wa1_update_guard(struct cdns2_endpoint * pep,struct cdns2_trb * trb)2803eb1f1efSPawel Laszczak static int cdns2_wa1_update_guard(struct cdns2_endpoint *pep,
2813eb1f1efSPawel Laszczak 				  struct cdns2_trb *trb)
2823eb1f1efSPawel Laszczak {
2833eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
2843eb1f1efSPawel Laszczak 
2853eb1f1efSPawel Laszczak 	if (!pep->wa1_set) {
2863eb1f1efSPawel Laszczak 		u32 doorbell;
2873eb1f1efSPawel Laszczak 
2883eb1f1efSPawel Laszczak 		doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
2893eb1f1efSPawel Laszczak 
2903eb1f1efSPawel Laszczak 		if (doorbell) {
2913eb1f1efSPawel Laszczak 			pep->wa1_cycle_bit = pep->ring.pcs ? TRB_CYCLE : 0;
2923eb1f1efSPawel Laszczak 			pep->wa1_set = 1;
2933eb1f1efSPawel Laszczak 			pep->wa1_trb = trb;
2943eb1f1efSPawel Laszczak 			pep->wa1_trb_index = pep->ring.enqueue;
29507a3aef2SPawel Laszczak 			trace_cdns2_wa1(pep, "set guard");
2963eb1f1efSPawel Laszczak 			return 0;
2973eb1f1efSPawel Laszczak 		}
2983eb1f1efSPawel Laszczak 	}
2993eb1f1efSPawel Laszczak 	return 1;
3003eb1f1efSPawel Laszczak }
3013eb1f1efSPawel Laszczak 
cdns2_wa1_tray_restore_cycle_bit(struct cdns2_device * pdev,struct cdns2_endpoint * pep)3023eb1f1efSPawel Laszczak static void cdns2_wa1_tray_restore_cycle_bit(struct cdns2_device *pdev,
3033eb1f1efSPawel Laszczak 					     struct cdns2_endpoint *pep)
3043eb1f1efSPawel Laszczak {
3053eb1f1efSPawel Laszczak 	int dma_index;
3063eb1f1efSPawel Laszczak 	u32 doorbell;
3073eb1f1efSPawel Laszczak 
3083eb1f1efSPawel Laszczak 	doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
3093eb1f1efSPawel Laszczak 	dma_index = cdns2_get_dma_pos(pdev, pep);
3103eb1f1efSPawel Laszczak 
3113eb1f1efSPawel Laszczak 	if (!doorbell || dma_index != pep->wa1_trb_index)
3123eb1f1efSPawel Laszczak 		cdns2_wa1_restore_cycle_bit(pep);
3133eb1f1efSPawel Laszczak }
3143eb1f1efSPawel Laszczak 
cdns2_prepare_ring(struct cdns2_device * pdev,struct cdns2_endpoint * pep,int num_trbs)3153eb1f1efSPawel Laszczak static int cdns2_prepare_ring(struct cdns2_device *pdev,
3163eb1f1efSPawel Laszczak 			      struct cdns2_endpoint *pep,
3173eb1f1efSPawel Laszczak 			      int num_trbs)
3183eb1f1efSPawel Laszczak {
3193eb1f1efSPawel Laszczak 	struct cdns2_trb *link_trb = NULL;
3203eb1f1efSPawel Laszczak 	int doorbell, dma_index;
3213eb1f1efSPawel Laszczak 	struct cdns2_ring *ring;
3223eb1f1efSPawel Laszczak 	u32 ch_bit = 0;
3233eb1f1efSPawel Laszczak 
3243eb1f1efSPawel Laszczak 	ring = &pep->ring;
3253eb1f1efSPawel Laszczak 
3263eb1f1efSPawel Laszczak 	if (num_trbs > ring->free_trbs) {
3273eb1f1efSPawel Laszczak 		pep->ep_state |= EP_RING_FULL;
32807a3aef2SPawel Laszczak 		trace_cdns2_no_room_on_ring("Ring full\n");
3293eb1f1efSPawel Laszczak 		return -ENOBUFS;
3303eb1f1efSPawel Laszczak 	}
3313eb1f1efSPawel Laszczak 
3323eb1f1efSPawel Laszczak 	if ((ring->enqueue + num_trbs)  >= (TRBS_PER_SEGMENT - 1)) {
3333eb1f1efSPawel Laszczak 		doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
3343eb1f1efSPawel Laszczak 		dma_index = cdns2_get_dma_pos(pdev, pep);
3353eb1f1efSPawel Laszczak 
3363eb1f1efSPawel Laszczak 		/* Driver can't update LINK TRB if it is current processed. */
3373eb1f1efSPawel Laszczak 		if (doorbell && dma_index == TRBS_PER_SEGMENT - 1) {
3383eb1f1efSPawel Laszczak 			pep->ep_state |= EP_DEFERRED_DRDY;
3393eb1f1efSPawel Laszczak 			return -ENOBUFS;
3403eb1f1efSPawel Laszczak 		}
3413eb1f1efSPawel Laszczak 
3423eb1f1efSPawel Laszczak 		/* Update C bt in Link TRB before starting DMA. */
3433eb1f1efSPawel Laszczak 		link_trb = ring->trbs + (TRBS_PER_SEGMENT - 1);
3443eb1f1efSPawel Laszczak 
3453eb1f1efSPawel Laszczak 		/*
3463eb1f1efSPawel Laszczak 		 * For TRs size equal 2 enabling TRB_CHAIN for epXin causes
3473eb1f1efSPawel Laszczak 		 * that DMA stuck at the LINK TRB.
3483eb1f1efSPawel Laszczak 		 * On the other hand, removing TRB_CHAIN for longer TRs for
3493eb1f1efSPawel Laszczak 		 * epXout cause that DMA stuck after handling LINK TRB.
3503eb1f1efSPawel Laszczak 		 * To eliminate this strange behavioral driver set TRB_CHAIN
3513eb1f1efSPawel Laszczak 		 * bit only for TR size > 2.
3523eb1f1efSPawel Laszczak 		 */
3533eb1f1efSPawel Laszczak 		if (pep->type == USB_ENDPOINT_XFER_ISOC || TRBS_PER_SEGMENT > 2)
3543eb1f1efSPawel Laszczak 			ch_bit = TRB_CHAIN;
3553eb1f1efSPawel Laszczak 
3563eb1f1efSPawel Laszczak 		link_trb->control = cpu_to_le32(((ring->pcs) ? TRB_CYCLE : 0) |
3573eb1f1efSPawel Laszczak 				    TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit);
3583eb1f1efSPawel Laszczak 	}
3593eb1f1efSPawel Laszczak 
3603eb1f1efSPawel Laszczak 	return 0;
3613eb1f1efSPawel Laszczak }
3623eb1f1efSPawel Laszczak 
cdns2_dbg_request_trbs(struct cdns2_endpoint * pep,struct cdns2_request * preq)3633eb1f1efSPawel Laszczak static void cdns2_dbg_request_trbs(struct cdns2_endpoint *pep,
3643eb1f1efSPawel Laszczak 				   struct cdns2_request *preq)
3653eb1f1efSPawel Laszczak {
3663eb1f1efSPawel Laszczak 	struct cdns2_trb *link_trb = pep->ring.trbs + (TRBS_PER_SEGMENT - 1);
3673eb1f1efSPawel Laszczak 	struct cdns2_trb *trb = preq->trb;
3683eb1f1efSPawel Laszczak 	int num_trbs = preq->num_of_trb;
3693eb1f1efSPawel Laszczak 	int i = 0;
3703eb1f1efSPawel Laszczak 
3713eb1f1efSPawel Laszczak 	while (i < num_trbs) {
37207a3aef2SPawel Laszczak 		trace_cdns2_queue_trb(pep, trb + i);
3733eb1f1efSPawel Laszczak 		if (trb + i == link_trb) {
3743eb1f1efSPawel Laszczak 			trb = pep->ring.trbs;
3753eb1f1efSPawel Laszczak 			num_trbs = num_trbs - i;
3763eb1f1efSPawel Laszczak 			i = 0;
3773eb1f1efSPawel Laszczak 		} else {
3783eb1f1efSPawel Laszczak 			i++;
3793eb1f1efSPawel Laszczak 		}
3803eb1f1efSPawel Laszczak 	}
3813eb1f1efSPawel Laszczak }
3823eb1f1efSPawel Laszczak 
cdns2_count_trbs(struct cdns2_endpoint * pep,u64 addr,u64 len)3833eb1f1efSPawel Laszczak static unsigned int cdns2_count_trbs(struct cdns2_endpoint *pep,
3843eb1f1efSPawel Laszczak 				     u64 addr, u64 len)
3853eb1f1efSPawel Laszczak {
3863eb1f1efSPawel Laszczak 	unsigned int num_trbs = 1;
3873eb1f1efSPawel Laszczak 
3883eb1f1efSPawel Laszczak 	if (pep->type == USB_ENDPOINT_XFER_ISOC) {
3893eb1f1efSPawel Laszczak 		/*
3903eb1f1efSPawel Laszczak 		 * To speed up DMA performance address should not exceed 4KB.
3913eb1f1efSPawel Laszczak 		 * for high bandwidth transfer and driver will split
3923eb1f1efSPawel Laszczak 		 * such buffer into two TRBs.
3933eb1f1efSPawel Laszczak 		 */
3943eb1f1efSPawel Laszczak 		num_trbs = DIV_ROUND_UP(len +
3953eb1f1efSPawel Laszczak 					(addr & (TRB_MAX_ISO_BUFF_SIZE - 1)),
3963eb1f1efSPawel Laszczak 					TRB_MAX_ISO_BUFF_SIZE);
3973eb1f1efSPawel Laszczak 
3983eb1f1efSPawel Laszczak 		if (pep->interval > 1)
3993eb1f1efSPawel Laszczak 			num_trbs = pep->dir ? num_trbs * pep->interval : 1;
4003eb1f1efSPawel Laszczak 	} else if (pep->dir) {
4013eb1f1efSPawel Laszczak 		/*
4023eb1f1efSPawel Laszczak 		 * One extra link trb for IN direction.
4033eb1f1efSPawel Laszczak 		 * Sometimes DMA doesn't want advance to next TD and transfer
4043eb1f1efSPawel Laszczak 		 * hangs. This extra Link TRB force DMA to advance to next TD.
4053eb1f1efSPawel Laszczak 		 */
4063eb1f1efSPawel Laszczak 		num_trbs++;
4073eb1f1efSPawel Laszczak 	}
4083eb1f1efSPawel Laszczak 
4093eb1f1efSPawel Laszczak 	return num_trbs;
4103eb1f1efSPawel Laszczak }
4113eb1f1efSPawel Laszczak 
cdns2_count_sg_trbs(struct cdns2_endpoint * pep,struct usb_request * req)4123eb1f1efSPawel Laszczak static unsigned int cdns2_count_sg_trbs(struct cdns2_endpoint *pep,
4133eb1f1efSPawel Laszczak 					struct usb_request *req)
4143eb1f1efSPawel Laszczak {
4153eb1f1efSPawel Laszczak 	unsigned int i, len, full_len, num_trbs = 0;
4163eb1f1efSPawel Laszczak 	struct scatterlist *sg;
4173eb1f1efSPawel Laszczak 	int trb_len = 0;
4183eb1f1efSPawel Laszczak 
4193eb1f1efSPawel Laszczak 	full_len = req->length;
4203eb1f1efSPawel Laszczak 
4213eb1f1efSPawel Laszczak 	for_each_sg(req->sg, sg, req->num_sgs, i) {
4223eb1f1efSPawel Laszczak 		len = sg_dma_len(sg);
4233eb1f1efSPawel Laszczak 		num_trbs += cdns2_count_trbs(pep, sg_dma_address(sg), len);
4243eb1f1efSPawel Laszczak 		len = min(len, full_len);
4253eb1f1efSPawel Laszczak 
4263eb1f1efSPawel Laszczak 		/*
4273eb1f1efSPawel Laszczak 		 * For HS ISO transfer TRBs should not exceed max packet size.
4283eb1f1efSPawel Laszczak 		 * When DMA is working, and data exceed max packet size then
4293eb1f1efSPawel Laszczak 		 * some data will be read in single mode instead burst mode.
4303eb1f1efSPawel Laszczak 		 * This behavior will drastically reduce the copying speed.
4313eb1f1efSPawel Laszczak 		 * To avoid this we need one or two extra TRBs.
4323eb1f1efSPawel Laszczak 		 * This issue occurs for UVC class with sg_supported = 1
4333eb1f1efSPawel Laszczak 		 * because buffers addresses are not aligned to 1024.
4343eb1f1efSPawel Laszczak 		 */
4353eb1f1efSPawel Laszczak 		if (pep->type == USB_ENDPOINT_XFER_ISOC) {
4363eb1f1efSPawel Laszczak 			u8 temp;
4373eb1f1efSPawel Laszczak 
4383eb1f1efSPawel Laszczak 			trb_len += len;
4393eb1f1efSPawel Laszczak 			temp = trb_len >> 10;
4403eb1f1efSPawel Laszczak 
4413eb1f1efSPawel Laszczak 			if (temp) {
4423eb1f1efSPawel Laszczak 				if (trb_len % 1024)
4433eb1f1efSPawel Laszczak 					num_trbs = num_trbs + temp;
4443eb1f1efSPawel Laszczak 				else
4453eb1f1efSPawel Laszczak 					num_trbs = num_trbs + temp - 1;
4463eb1f1efSPawel Laszczak 
4473eb1f1efSPawel Laszczak 				trb_len = trb_len - (temp << 10);
4483eb1f1efSPawel Laszczak 			}
4493eb1f1efSPawel Laszczak 		}
4503eb1f1efSPawel Laszczak 
4513eb1f1efSPawel Laszczak 		full_len -= len;
4523eb1f1efSPawel Laszczak 		if (full_len == 0)
4533eb1f1efSPawel Laszczak 			break;
4543eb1f1efSPawel Laszczak 	}
4553eb1f1efSPawel Laszczak 
4563eb1f1efSPawel Laszczak 	return num_trbs;
4573eb1f1efSPawel Laszczak }
4583eb1f1efSPawel Laszczak 
4593eb1f1efSPawel Laszczak /*
4603eb1f1efSPawel Laszczak  * Function prepares the array with optimized AXI burst value for different
4613eb1f1efSPawel Laszczak  * transfer lengths. Controller handles the final data which are less
4623eb1f1efSPawel Laszczak  * then AXI burst size as single byte transactions.
4633eb1f1efSPawel Laszczak  * e.g.:
4643eb1f1efSPawel Laszczak  * Let's assume that driver prepares trb with trb->length 700 and burst size
4653eb1f1efSPawel Laszczak  * will be set to 128. In this case the controller will handle a first 512 as
4663eb1f1efSPawel Laszczak  * single AXI transaction but the next 188 bytes will be handled
4673eb1f1efSPawel Laszczak  * as 47 separate AXI transaction.
4683eb1f1efSPawel Laszczak  * The better solution is to use the burst size equal 16 and then we will
4693eb1f1efSPawel Laszczak  * have only 25 AXI transaction (10 * 64 + 15 *4).
4703eb1f1efSPawel Laszczak  */
cdsn2_isoc_burst_opt(struct cdns2_device * pdev)4713eb1f1efSPawel Laszczak static void cdsn2_isoc_burst_opt(struct cdns2_device *pdev)
4723eb1f1efSPawel Laszczak {
4733eb1f1efSPawel Laszczak 	int axi_burst_option[]  =  {1, 2, 4, 8, 16, 32, 64, 128};
4743eb1f1efSPawel Laszczak 	int best_burst;
4753eb1f1efSPawel Laszczak 	int array_size;
4763eb1f1efSPawel Laszczak 	int opt_burst;
4773eb1f1efSPawel Laszczak 	int trb_size;
4783eb1f1efSPawel Laszczak 	int i, j;
4793eb1f1efSPawel Laszczak 
4803eb1f1efSPawel Laszczak 	array_size = ARRAY_SIZE(axi_burst_option);
4813eb1f1efSPawel Laszczak 
4823eb1f1efSPawel Laszczak 	for (i = 0; i <= MAX_ISO_SIZE; i++) {
4833eb1f1efSPawel Laszczak 		trb_size = i / 4;
4843eb1f1efSPawel Laszczak 		best_burst = trb_size ? trb_size : 1;
4853eb1f1efSPawel Laszczak 
4863eb1f1efSPawel Laszczak 		for (j = 0; j < array_size; j++) {
4873eb1f1efSPawel Laszczak 			opt_burst = trb_size / axi_burst_option[j];
4883eb1f1efSPawel Laszczak 			opt_burst += trb_size % axi_burst_option[j];
4893eb1f1efSPawel Laszczak 
4903eb1f1efSPawel Laszczak 			if (opt_burst < best_burst) {
4913eb1f1efSPawel Laszczak 				best_burst = opt_burst;
4923eb1f1efSPawel Laszczak 				pdev->burst_opt[i] = axi_burst_option[j];
4933eb1f1efSPawel Laszczak 			}
4943eb1f1efSPawel Laszczak 		}
4953eb1f1efSPawel Laszczak 	}
4963eb1f1efSPawel Laszczak }
4973eb1f1efSPawel Laszczak 
cdns2_ep_tx_isoc(struct cdns2_endpoint * pep,struct cdns2_request * preq,int num_trbs)4983eb1f1efSPawel Laszczak static void cdns2_ep_tx_isoc(struct cdns2_endpoint *pep,
4993eb1f1efSPawel Laszczak 			     struct cdns2_request *preq,
5003eb1f1efSPawel Laszczak 			     int num_trbs)
5013eb1f1efSPawel Laszczak {
5023eb1f1efSPawel Laszczak 	struct scatterlist *sg = NULL;
5033eb1f1efSPawel Laszczak 	u32 remaining_packet_size = 0;
5043eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
5053eb1f1efSPawel Laszczak 	bool first_trb = true;
5063eb1f1efSPawel Laszczak 	dma_addr_t trb_dma;
5073eb1f1efSPawel Laszczak 	u32 trb_buff_len;
5083eb1f1efSPawel Laszczak 	u32 block_length;
5093eb1f1efSPawel Laszczak 	int td_idx = 0;
5103eb1f1efSPawel Laszczak 	int split_size;
5113eb1f1efSPawel Laszczak 	u32 full_len;
5123eb1f1efSPawel Laszczak 	int enqd_len;
5133eb1f1efSPawel Laszczak 	int sent_len;
5143eb1f1efSPawel Laszczak 	int sg_iter;
5153eb1f1efSPawel Laszczak 	u32 control;
5163eb1f1efSPawel Laszczak 	int num_tds;
5173eb1f1efSPawel Laszczak 	u32 length;
5183eb1f1efSPawel Laszczak 
5193eb1f1efSPawel Laszczak 	/*
5203eb1f1efSPawel Laszczak 	 * For OUT direction 1 TD per interval is enough
5213eb1f1efSPawel Laszczak 	 * because TRBs are not dumped by controller.
5223eb1f1efSPawel Laszczak 	 */
5233eb1f1efSPawel Laszczak 	num_tds = pep->dir ? pep->interval : 1;
5243eb1f1efSPawel Laszczak 	split_size = preq->request.num_sgs ? 1024 : 3072;
5253eb1f1efSPawel Laszczak 
5263eb1f1efSPawel Laszczak 	for (td_idx = 0; td_idx < num_tds; td_idx++) {
5273eb1f1efSPawel Laszczak 		if (preq->request.num_sgs) {
5283eb1f1efSPawel Laszczak 			sg = preq->request.sg;
5293eb1f1efSPawel Laszczak 			trb_dma = sg_dma_address(sg);
5303eb1f1efSPawel Laszczak 			block_length = sg_dma_len(sg);
5313eb1f1efSPawel Laszczak 		} else {
5323eb1f1efSPawel Laszczak 			trb_dma = preq->request.dma;
5333eb1f1efSPawel Laszczak 			block_length = preq->request.length;
5343eb1f1efSPawel Laszczak 		}
5353eb1f1efSPawel Laszczak 
5363eb1f1efSPawel Laszczak 		full_len = preq->request.length;
5373eb1f1efSPawel Laszczak 		sg_iter = preq->request.num_sgs ? preq->request.num_sgs : 1;
5383eb1f1efSPawel Laszczak 		remaining_packet_size = split_size;
5393eb1f1efSPawel Laszczak 
5403eb1f1efSPawel Laszczak 		for (enqd_len = 0;  enqd_len < full_len;
5413eb1f1efSPawel Laszczak 		     enqd_len += trb_buff_len) {
5423eb1f1efSPawel Laszczak 			if (remaining_packet_size == 0)
5433eb1f1efSPawel Laszczak 				remaining_packet_size = split_size;
5443eb1f1efSPawel Laszczak 
5453eb1f1efSPawel Laszczak 			/*
5463eb1f1efSPawel Laszczak 			 * Calculate TRB length.- buffer can't across 4KB
5473eb1f1efSPawel Laszczak 			 * and max packet size.
5483eb1f1efSPawel Laszczak 			 */
5493eb1f1efSPawel Laszczak 			trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(trb_dma);
5503eb1f1efSPawel Laszczak 			trb_buff_len = min(trb_buff_len, remaining_packet_size);
5513eb1f1efSPawel Laszczak 			trb_buff_len = min(trb_buff_len, block_length);
5523eb1f1efSPawel Laszczak 
5533eb1f1efSPawel Laszczak 			if (trb_buff_len > full_len - enqd_len)
5543eb1f1efSPawel Laszczak 				trb_buff_len = full_len - enqd_len;
5553eb1f1efSPawel Laszczak 
5563eb1f1efSPawel Laszczak 			control = TRB_TYPE(TRB_NORMAL);
5573eb1f1efSPawel Laszczak 
5583eb1f1efSPawel Laszczak 			/*
5593eb1f1efSPawel Laszczak 			 * For IN direction driver has to set the IOC for
5603eb1f1efSPawel Laszczak 			 * last TRB in last TD.
5613eb1f1efSPawel Laszczak 			 * For OUT direction driver must set IOC and ISP
5623eb1f1efSPawel Laszczak 			 * only for last TRB in each TDs.
5633eb1f1efSPawel Laszczak 			 */
5643eb1f1efSPawel Laszczak 			if (enqd_len + trb_buff_len >= full_len || !pep->dir)
5653eb1f1efSPawel Laszczak 				control |= TRB_IOC | TRB_ISP;
5663eb1f1efSPawel Laszczak 
5673eb1f1efSPawel Laszczak 			/*
5683eb1f1efSPawel Laszczak 			 * Don't give the first TRB to the hardware (by toggling
5693eb1f1efSPawel Laszczak 			 * the cycle bit) until we've finished creating all the
5703eb1f1efSPawel Laszczak 			 * other TRBs.
5713eb1f1efSPawel Laszczak 			 */
5723eb1f1efSPawel Laszczak 			if (first_trb) {
5733eb1f1efSPawel Laszczak 				first_trb = false;
5743eb1f1efSPawel Laszczak 				if (pep->ring.pcs == 0)
5753eb1f1efSPawel Laszczak 					control |= TRB_CYCLE;
5763eb1f1efSPawel Laszczak 			} else {
5773eb1f1efSPawel Laszczak 				control |= pep->ring.pcs;
5783eb1f1efSPawel Laszczak 			}
5793eb1f1efSPawel Laszczak 
5803eb1f1efSPawel Laszczak 			if (enqd_len + trb_buff_len < full_len)
5813eb1f1efSPawel Laszczak 				control |= TRB_CHAIN;
5823eb1f1efSPawel Laszczak 
5833eb1f1efSPawel Laszczak 			length = TRB_LEN(trb_buff_len) |
5843eb1f1efSPawel Laszczak 				 TRB_BURST(pep->pdev->burst_opt[trb_buff_len]);
5853eb1f1efSPawel Laszczak 
5863eb1f1efSPawel Laszczak 			trb = pep->ring.trbs + pep->ring.enqueue;
5873eb1f1efSPawel Laszczak 			trb->buffer = cpu_to_le32(TRB_BUFFER(trb_dma));
5883eb1f1efSPawel Laszczak 			trb->length = cpu_to_le32(length);
5893eb1f1efSPawel Laszczak 			trb->control = cpu_to_le32(control);
5903eb1f1efSPawel Laszczak 
5913eb1f1efSPawel Laszczak 			trb_dma += trb_buff_len;
5923eb1f1efSPawel Laszczak 			sent_len = trb_buff_len;
5933eb1f1efSPawel Laszczak 
5943eb1f1efSPawel Laszczak 			if (sg && sent_len >= block_length) {
5953eb1f1efSPawel Laszczak 				/* New sg entry */
5963eb1f1efSPawel Laszczak 				--sg_iter;
5973eb1f1efSPawel Laszczak 				sent_len -= block_length;
5983eb1f1efSPawel Laszczak 				if (sg_iter != 0) {
5993eb1f1efSPawel Laszczak 					sg = sg_next(sg);
6003eb1f1efSPawel Laszczak 					trb_dma = sg_dma_address(sg);
6013eb1f1efSPawel Laszczak 					block_length = sg_dma_len(sg);
6023eb1f1efSPawel Laszczak 				}
6033eb1f1efSPawel Laszczak 			}
6043eb1f1efSPawel Laszczak 
6053eb1f1efSPawel Laszczak 			remaining_packet_size -= trb_buff_len;
6063eb1f1efSPawel Laszczak 			block_length -= sent_len;
6073eb1f1efSPawel Laszczak 			preq->end_trb = pep->ring.enqueue;
6083eb1f1efSPawel Laszczak 
6093eb1f1efSPawel Laszczak 			cdns2_ep_inc_enq(&pep->ring);
6103eb1f1efSPawel Laszczak 		}
6113eb1f1efSPawel Laszczak 	}
6123eb1f1efSPawel Laszczak }
6133eb1f1efSPawel Laszczak 
cdns2_ep_tx_bulk(struct cdns2_endpoint * pep,struct cdns2_request * preq,int trbs_per_td)6143eb1f1efSPawel Laszczak static void cdns2_ep_tx_bulk(struct cdns2_endpoint *pep,
6153eb1f1efSPawel Laszczak 			     struct cdns2_request *preq,
6163eb1f1efSPawel Laszczak 			     int trbs_per_td)
6173eb1f1efSPawel Laszczak {
6183eb1f1efSPawel Laszczak 	struct scatterlist *sg = NULL;
6193eb1f1efSPawel Laszczak 	struct cdns2_ring *ring;
6203eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
6213eb1f1efSPawel Laszczak 	dma_addr_t trb_dma;
6223eb1f1efSPawel Laszczak 	int sg_iter = 0;
6233eb1f1efSPawel Laszczak 	u32 control;
6243eb1f1efSPawel Laszczak 	u32 length;
6253eb1f1efSPawel Laszczak 
6263eb1f1efSPawel Laszczak 	if (preq->request.num_sgs) {
6273eb1f1efSPawel Laszczak 		sg = preq->request.sg;
6283eb1f1efSPawel Laszczak 		trb_dma = sg_dma_address(sg);
6293eb1f1efSPawel Laszczak 		length = sg_dma_len(sg);
6303eb1f1efSPawel Laszczak 	} else {
6313eb1f1efSPawel Laszczak 		trb_dma = preq->request.dma;
6323eb1f1efSPawel Laszczak 		length = preq->request.length;
6333eb1f1efSPawel Laszczak 	}
6343eb1f1efSPawel Laszczak 
6353eb1f1efSPawel Laszczak 	ring = &pep->ring;
6363eb1f1efSPawel Laszczak 
6373eb1f1efSPawel Laszczak 	for (sg_iter = 0; sg_iter < trbs_per_td; sg_iter++) {
6383eb1f1efSPawel Laszczak 		control = TRB_TYPE(TRB_NORMAL) | ring->pcs | TRB_ISP;
6393eb1f1efSPawel Laszczak 		trb = pep->ring.trbs + ring->enqueue;
6403eb1f1efSPawel Laszczak 
6413eb1f1efSPawel Laszczak 		if (pep->dir && sg_iter == trbs_per_td - 1) {
6423eb1f1efSPawel Laszczak 			preq->end_trb = ring->enqueue;
6433eb1f1efSPawel Laszczak 			control = ring->pcs | TRB_TYPE(TRB_LINK) | TRB_CHAIN
6443eb1f1efSPawel Laszczak 				  | TRB_IOC;
6453eb1f1efSPawel Laszczak 			cdns2_ep_inc_enq(&pep->ring);
6463eb1f1efSPawel Laszczak 
6473eb1f1efSPawel Laszczak 			if (ring->enqueue == 0)
6483eb1f1efSPawel Laszczak 				control |= TRB_TOGGLE;
6493eb1f1efSPawel Laszczak 
6503eb1f1efSPawel Laszczak 			/* Point to next bad TRB. */
6513eb1f1efSPawel Laszczak 			trb->buffer = cpu_to_le32(pep->ring.dma +
6523eb1f1efSPawel Laszczak 						  (ring->enqueue * TRB_SIZE));
6533eb1f1efSPawel Laszczak 			trb->length = 0;
6543eb1f1efSPawel Laszczak 			trb->control = cpu_to_le32(control);
6553eb1f1efSPawel Laszczak 			break;
6563eb1f1efSPawel Laszczak 		}
6573eb1f1efSPawel Laszczak 
6583eb1f1efSPawel Laszczak 		/*
6593eb1f1efSPawel Laszczak 		 * Don't give the first TRB to the hardware (by toggling
6603eb1f1efSPawel Laszczak 		 * the cycle bit) until we've finished creating all the
6613eb1f1efSPawel Laszczak 		 * other TRBs.
6623eb1f1efSPawel Laszczak 		 */
6633eb1f1efSPawel Laszczak 		if (sg_iter == 0)
6643eb1f1efSPawel Laszczak 			control = control ^ TRB_CYCLE;
6653eb1f1efSPawel Laszczak 
6663eb1f1efSPawel Laszczak 		/* For last TRB in TD. */
6673eb1f1efSPawel Laszczak 		if (sg_iter == (trbs_per_td - (pep->dir ? 2 : 1)))
6683eb1f1efSPawel Laszczak 			control |= TRB_IOC;
6693eb1f1efSPawel Laszczak 		else
6703eb1f1efSPawel Laszczak 			control |= TRB_CHAIN;
6713eb1f1efSPawel Laszczak 
6723eb1f1efSPawel Laszczak 		trb->buffer = cpu_to_le32(trb_dma);
6733eb1f1efSPawel Laszczak 		trb->length = cpu_to_le32(TRB_BURST(pep->trb_burst_size) |
6743eb1f1efSPawel Laszczak 					   TRB_LEN(length));
6753eb1f1efSPawel Laszczak 		trb->control = cpu_to_le32(control);
6763eb1f1efSPawel Laszczak 
6773eb1f1efSPawel Laszczak 		if (sg && sg_iter < (trbs_per_td - 1)) {
6783eb1f1efSPawel Laszczak 			sg = sg_next(sg);
6793eb1f1efSPawel Laszczak 			trb_dma = sg_dma_address(sg);
6803eb1f1efSPawel Laszczak 			length = sg_dma_len(sg);
6813eb1f1efSPawel Laszczak 		}
6823eb1f1efSPawel Laszczak 
6833eb1f1efSPawel Laszczak 		preq->end_trb = ring->enqueue;
6843eb1f1efSPawel Laszczak 		cdns2_ep_inc_enq(&pep->ring);
6853eb1f1efSPawel Laszczak 	}
6863eb1f1efSPawel Laszczak }
6873eb1f1efSPawel Laszczak 
cdns2_set_drdy(struct cdns2_device * pdev,struct cdns2_endpoint * pep)6883eb1f1efSPawel Laszczak static void cdns2_set_drdy(struct cdns2_device *pdev,
6893eb1f1efSPawel Laszczak 			   struct cdns2_endpoint *pep)
6903eb1f1efSPawel Laszczak {
69107a3aef2SPawel Laszczak 	trace_cdns2_ring(pep);
69207a3aef2SPawel Laszczak 
6933eb1f1efSPawel Laszczak 	/*
6943eb1f1efSPawel Laszczak 	 * Memory barrier - Cycle Bit must be set before doorbell.
6953eb1f1efSPawel Laszczak 	 */
6963eb1f1efSPawel Laszczak 	dma_wmb();
6973eb1f1efSPawel Laszczak 
6983eb1f1efSPawel Laszczak 	/* Clearing TRBERR and DESCMIS before setting DRDY. */
6993eb1f1efSPawel Laszczak 	writel(DMA_EP_STS_TRBERR | DMA_EP_STS_DESCMIS,
7003eb1f1efSPawel Laszczak 	       &pdev->adma_regs->ep_sts);
7013eb1f1efSPawel Laszczak 	writel(DMA_EP_CMD_DRDY, &pdev->adma_regs->ep_cmd);
7023eb1f1efSPawel Laszczak 
7033eb1f1efSPawel Laszczak 	if (readl(&pdev->adma_regs->ep_sts) & DMA_EP_STS_TRBERR) {
7043eb1f1efSPawel Laszczak 		writel(DMA_EP_STS_TRBERR, &pdev->adma_regs->ep_sts);
7053eb1f1efSPawel Laszczak 		writel(DMA_EP_CMD_DRDY, &pdev->adma_regs->ep_cmd);
7063eb1f1efSPawel Laszczak 	}
70707a3aef2SPawel Laszczak 
70807a3aef2SPawel Laszczak 	trace_cdns2_doorbell_epx(pep, readl(&pdev->adma_regs->ep_traddr));
7093eb1f1efSPawel Laszczak }
7103eb1f1efSPawel Laszczak 
cdns2_prepare_first_isoc_transfer(struct cdns2_device * pdev,struct cdns2_endpoint * pep)7113eb1f1efSPawel Laszczak static int cdns2_prepare_first_isoc_transfer(struct cdns2_device *pdev,
7123eb1f1efSPawel Laszczak 					     struct cdns2_endpoint *pep)
7133eb1f1efSPawel Laszczak {
7143eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
7153eb1f1efSPawel Laszczak 	u32 buffer;
7163eb1f1efSPawel Laszczak 	u8 hw_ccs;
7173eb1f1efSPawel Laszczak 
7183eb1f1efSPawel Laszczak 	if ((readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY))
7193eb1f1efSPawel Laszczak 		return -EBUSY;
7203eb1f1efSPawel Laszczak 
7213eb1f1efSPawel Laszczak 	if (!pep->dir) {
7223eb1f1efSPawel Laszczak 		set_reg_bit_32(&pdev->adma_regs->ep_cfg, DMA_EP_CFG_ENABLE);
7233eb1f1efSPawel Laszczak 		writel(pep->ring.dma + pep->ring.dequeue,
7243eb1f1efSPawel Laszczak 		       &pdev->adma_regs->ep_traddr);
7253eb1f1efSPawel Laszczak 		return 0;
7263eb1f1efSPawel Laszczak 	}
7273eb1f1efSPawel Laszczak 
7283eb1f1efSPawel Laszczak 	/*
7293eb1f1efSPawel Laszczak 	 * The first packet after doorbell can be corrupted so,
7303eb1f1efSPawel Laszczak 	 * driver prepares 0 length packet as first packet.
7313eb1f1efSPawel Laszczak 	 */
7323eb1f1efSPawel Laszczak 	buffer = pep->ring.dma + pep->ring.dequeue * TRB_SIZE;
7333eb1f1efSPawel Laszczak 	hw_ccs = !!DMA_EP_STS_CCS(readl(&pdev->adma_regs->ep_sts));
7343eb1f1efSPawel Laszczak 
7353eb1f1efSPawel Laszczak 	trb = &pep->ring.trbs[TRBS_PER_SEGMENT];
7363eb1f1efSPawel Laszczak 	trb->length = 0;
7373eb1f1efSPawel Laszczak 	trb->buffer = cpu_to_le32(TRB_BUFFER(buffer));
7383eb1f1efSPawel Laszczak 	trb->control = cpu_to_le32((hw_ccs ? TRB_CYCLE : 0) | TRB_TYPE(TRB_NORMAL));
7393eb1f1efSPawel Laszczak 
7403eb1f1efSPawel Laszczak 	/*
7413eb1f1efSPawel Laszczak 	 * LINK TRB is used to force updating cycle bit in controller and
7423eb1f1efSPawel Laszczak 	 * move to correct place in transfer ring.
7433eb1f1efSPawel Laszczak 	 */
7443eb1f1efSPawel Laszczak 	trb++;
7453eb1f1efSPawel Laszczak 	trb->length = 0;
7463eb1f1efSPawel Laszczak 	trb->buffer = cpu_to_le32(TRB_BUFFER(buffer));
7473eb1f1efSPawel Laszczak 	trb->control = cpu_to_le32((hw_ccs ? TRB_CYCLE : 0) |
7483eb1f1efSPawel Laszczak 				    TRB_TYPE(TRB_LINK) | TRB_CHAIN);
7493eb1f1efSPawel Laszczak 
7503eb1f1efSPawel Laszczak 	if (hw_ccs !=  pep->ring.ccs)
7513eb1f1efSPawel Laszczak 		trb->control |= cpu_to_le32(TRB_TOGGLE);
7523eb1f1efSPawel Laszczak 
7533eb1f1efSPawel Laszczak 	set_reg_bit_32(&pdev->adma_regs->ep_cfg, DMA_EP_CFG_ENABLE);
7543eb1f1efSPawel Laszczak 	writel(pep->ring.dma + (TRBS_PER_SEGMENT * TRB_SIZE),
7553eb1f1efSPawel Laszczak 	       &pdev->adma_regs->ep_traddr);
7563eb1f1efSPawel Laszczak 
7573eb1f1efSPawel Laszczak 	return 0;
7583eb1f1efSPawel Laszczak }
7593eb1f1efSPawel Laszczak 
7603eb1f1efSPawel Laszczak /* Prepare and start transfer on no-default endpoint. */
cdns2_ep_run_transfer(struct cdns2_endpoint * pep,struct cdns2_request * preq)7613eb1f1efSPawel Laszczak static int cdns2_ep_run_transfer(struct cdns2_endpoint *pep,
7623eb1f1efSPawel Laszczak 				 struct cdns2_request *preq)
7633eb1f1efSPawel Laszczak {
7643eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
7653eb1f1efSPawel Laszczak 	struct cdns2_ring *ring;
7663eb1f1efSPawel Laszczak 	u32 togle_pcs = 1;
7673eb1f1efSPawel Laszczak 	int num_trbs;
7683eb1f1efSPawel Laszczak 	int ret;
7693eb1f1efSPawel Laszczak 
7703eb1f1efSPawel Laszczak 	cdns2_select_ep(pdev, pep->endpoint.address);
7713eb1f1efSPawel Laszczak 
7723eb1f1efSPawel Laszczak 	if (preq->request.sg)
7733eb1f1efSPawel Laszczak 		num_trbs = cdns2_count_sg_trbs(pep, &preq->request);
7743eb1f1efSPawel Laszczak 	else
7753eb1f1efSPawel Laszczak 		num_trbs = cdns2_count_trbs(pep, preq->request.dma,
7763eb1f1efSPawel Laszczak 					    preq->request.length);
7773eb1f1efSPawel Laszczak 
7783eb1f1efSPawel Laszczak 	ret = cdns2_prepare_ring(pdev, pep, num_trbs);
7793eb1f1efSPawel Laszczak 	if (ret)
7803eb1f1efSPawel Laszczak 		return ret;
7813eb1f1efSPawel Laszczak 
7823eb1f1efSPawel Laszczak 	ring = &pep->ring;
7833eb1f1efSPawel Laszczak 	preq->start_trb = ring->enqueue;
7843eb1f1efSPawel Laszczak 	preq->trb = ring->trbs + ring->enqueue;
7853eb1f1efSPawel Laszczak 
7863eb1f1efSPawel Laszczak 	if (usb_endpoint_xfer_isoc(pep->endpoint.desc)) {
7873eb1f1efSPawel Laszczak 		cdns2_ep_tx_isoc(pep, preq, num_trbs);
7883eb1f1efSPawel Laszczak 	} else {
7893eb1f1efSPawel Laszczak 		togle_pcs = cdns2_wa1_update_guard(pep, ring->trbs + ring->enqueue);
7903eb1f1efSPawel Laszczak 		cdns2_ep_tx_bulk(pep, preq, num_trbs);
7913eb1f1efSPawel Laszczak 	}
7923eb1f1efSPawel Laszczak 
7933eb1f1efSPawel Laszczak 	preq->num_of_trb = num_trbs;
7943eb1f1efSPawel Laszczak 
7953eb1f1efSPawel Laszczak 	/*
7963eb1f1efSPawel Laszczak 	 * Memory barrier - cycle bit must be set as the last operation.
7973eb1f1efSPawel Laszczak 	 */
7983eb1f1efSPawel Laszczak 	dma_wmb();
7993eb1f1efSPawel Laszczak 
8003eb1f1efSPawel Laszczak 	/* Give the TD to the consumer. */
8013eb1f1efSPawel Laszczak 	if (togle_pcs)
8023eb1f1efSPawel Laszczak 		preq->trb->control = preq->trb->control ^ cpu_to_le32(1);
8033eb1f1efSPawel Laszczak 
8043eb1f1efSPawel Laszczak 	cdns2_wa1_tray_restore_cycle_bit(pdev, pep);
8053eb1f1efSPawel Laszczak 	cdns2_dbg_request_trbs(pep, preq);
8063eb1f1efSPawel Laszczak 
8073eb1f1efSPawel Laszczak 	if (!pep->wa1_set && !(pep->ep_state & EP_STALLED) && !pep->skip) {
8083eb1f1efSPawel Laszczak 		if (pep->type == USB_ENDPOINT_XFER_ISOC) {
8093eb1f1efSPawel Laszczak 			ret = cdns2_prepare_first_isoc_transfer(pdev, pep);
8103eb1f1efSPawel Laszczak 			if (ret)
8113eb1f1efSPawel Laszczak 				return 0;
8123eb1f1efSPawel Laszczak 		}
8133eb1f1efSPawel Laszczak 
8143eb1f1efSPawel Laszczak 		cdns2_set_drdy(pdev, pep);
8153eb1f1efSPawel Laszczak 	}
8163eb1f1efSPawel Laszczak 
8173eb1f1efSPawel Laszczak 	return 0;
8183eb1f1efSPawel Laszczak }
8193eb1f1efSPawel Laszczak 
8203eb1f1efSPawel Laszczak /* Prepare and start transfer for all not started requests. */
cdns2_start_all_request(struct cdns2_device * pdev,struct cdns2_endpoint * pep)8213eb1f1efSPawel Laszczak static int cdns2_start_all_request(struct cdns2_device *pdev,
8223eb1f1efSPawel Laszczak 				   struct cdns2_endpoint *pep)
8233eb1f1efSPawel Laszczak {
8243eb1f1efSPawel Laszczak 	struct cdns2_request *preq;
8253eb1f1efSPawel Laszczak 	int ret;
8263eb1f1efSPawel Laszczak 
8273eb1f1efSPawel Laszczak 	while (!list_empty(&pep->deferred_list)) {
8283eb1f1efSPawel Laszczak 		preq = cdns2_next_preq(&pep->deferred_list);
8293eb1f1efSPawel Laszczak 
8303eb1f1efSPawel Laszczak 		ret = cdns2_ep_run_transfer(pep, preq);
8313eb1f1efSPawel Laszczak 		if (ret)
8323eb1f1efSPawel Laszczak 			return ret;
8333eb1f1efSPawel Laszczak 
8343eb1f1efSPawel Laszczak 		list_move_tail(&preq->list, &pep->pending_list);
8353eb1f1efSPawel Laszczak 	}
8363eb1f1efSPawel Laszczak 
8373eb1f1efSPawel Laszczak 	pep->ep_state &= ~EP_RING_FULL;
8383eb1f1efSPawel Laszczak 
8393eb1f1efSPawel Laszczak 	return 0;
8403eb1f1efSPawel Laszczak }
8413eb1f1efSPawel Laszczak 
8423eb1f1efSPawel Laszczak /*
8433eb1f1efSPawel Laszczak  * Check whether trb has been handled by DMA.
8443eb1f1efSPawel Laszczak  *
8453eb1f1efSPawel Laszczak  * Endpoint must be selected before invoking this function.
8463eb1f1efSPawel Laszczak  *
8473eb1f1efSPawel Laszczak  * Returns false if request has not been handled by DMA, else returns true.
8483eb1f1efSPawel Laszczak  *
8493eb1f1efSPawel Laszczak  * SR - start ring
8503eb1f1efSPawel Laszczak  * ER - end ring
8513eb1f1efSPawel Laszczak  * DQ = ring->dequeue - dequeue position
8523eb1f1efSPawel Laszczak  * EQ = ring->enqueue - enqueue position
8533eb1f1efSPawel Laszczak  * ST = preq->start_trb - index of first TRB in transfer ring
8543eb1f1efSPawel Laszczak  * ET = preq->end_trb - index of last TRB in transfer ring
8553eb1f1efSPawel Laszczak  * CI = current_index - index of processed TRB by DMA.
8563eb1f1efSPawel Laszczak  *
8573eb1f1efSPawel Laszczak  * As first step, we check if the TRB between the ST and ET.
8583eb1f1efSPawel Laszczak  * Then, we check if cycle bit for index pep->dequeue
8593eb1f1efSPawel Laszczak  * is correct.
8603eb1f1efSPawel Laszczak  *
8613eb1f1efSPawel Laszczak  * some rules:
8623eb1f1efSPawel Laszczak  * 1. ring->dequeue never equals to current_index.
8633eb1f1efSPawel Laszczak  * 2  ring->enqueue never exceed ring->dequeue
8643eb1f1efSPawel Laszczak  * 3. exception: ring->enqueue == ring->dequeue
8653eb1f1efSPawel Laszczak  *    and ring->free_trbs is zero.
8663eb1f1efSPawel Laszczak  *    This case indicate that TR is full.
8673eb1f1efSPawel Laszczak  *
8683eb1f1efSPawel Laszczak  * At below two cases, the request have been handled.
8693eb1f1efSPawel Laszczak  * Case 1 - ring->dequeue < current_index
8703eb1f1efSPawel Laszczak  *      SR ... EQ ... DQ ... CI ... ER
8713eb1f1efSPawel Laszczak  *      SR ... DQ ... CI ... EQ ... ER
8723eb1f1efSPawel Laszczak  *
8733eb1f1efSPawel Laszczak  * Case 2 - ring->dequeue > current_index
8743eb1f1efSPawel Laszczak  * This situation takes place when CI go through the LINK TRB at the end of
8753eb1f1efSPawel Laszczak  * transfer ring.
8763eb1f1efSPawel Laszczak  *      SR ... CI ... EQ ... DQ ... ER
8773eb1f1efSPawel Laszczak  */
cdns2_trb_handled(struct cdns2_endpoint * pep,struct cdns2_request * preq)8783eb1f1efSPawel Laszczak static bool cdns2_trb_handled(struct cdns2_endpoint *pep,
8793eb1f1efSPawel Laszczak 			      struct cdns2_request *preq)
8803eb1f1efSPawel Laszczak {
8813eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
8823eb1f1efSPawel Laszczak 	struct cdns2_ring *ring;
8833eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
8843eb1f1efSPawel Laszczak 	int current_index = 0;
8853eb1f1efSPawel Laszczak 	int handled = 0;
8863eb1f1efSPawel Laszczak 	int doorbell;
8873eb1f1efSPawel Laszczak 
8883eb1f1efSPawel Laszczak 	ring = &pep->ring;
8893eb1f1efSPawel Laszczak 	current_index = cdns2_get_dma_pos(pdev, pep);
8903eb1f1efSPawel Laszczak 	doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
8913eb1f1efSPawel Laszczak 
8923eb1f1efSPawel Laszczak 	/*
8933eb1f1efSPawel Laszczak 	 * Only ISO transfer can use 2 entries outside the standard
8943eb1f1efSPawel Laszczak 	 * Transfer Ring. First of them is used as zero length packet and the
8953eb1f1efSPawel Laszczak 	 * second as LINK TRB.
8963eb1f1efSPawel Laszczak 	 */
8973eb1f1efSPawel Laszczak 	if (current_index >= TRBS_PER_SEGMENT)
8983eb1f1efSPawel Laszczak 		goto finish;
8993eb1f1efSPawel Laszczak 
9003eb1f1efSPawel Laszczak 	/* Current trb doesn't belong to this request. */
9013eb1f1efSPawel Laszczak 	if (preq->start_trb < preq->end_trb) {
9023eb1f1efSPawel Laszczak 		if (ring->dequeue > preq->end_trb)
9033eb1f1efSPawel Laszczak 			goto finish;
9043eb1f1efSPawel Laszczak 
9053eb1f1efSPawel Laszczak 		if (ring->dequeue < preq->start_trb)
9063eb1f1efSPawel Laszczak 			goto finish;
9073eb1f1efSPawel Laszczak 	}
9083eb1f1efSPawel Laszczak 
9093eb1f1efSPawel Laszczak 	if (preq->start_trb > preq->end_trb && ring->dequeue > preq->end_trb &&
9103eb1f1efSPawel Laszczak 	    ring->dequeue < preq->start_trb)
9113eb1f1efSPawel Laszczak 		goto finish;
9123eb1f1efSPawel Laszczak 
9133eb1f1efSPawel Laszczak 	if (preq->start_trb == preq->end_trb && ring->dequeue != preq->end_trb)
9143eb1f1efSPawel Laszczak 		goto finish;
9153eb1f1efSPawel Laszczak 
9163eb1f1efSPawel Laszczak 	trb = &ring->trbs[ring->dequeue];
9173eb1f1efSPawel Laszczak 
9183eb1f1efSPawel Laszczak 	if ((le32_to_cpu(trb->control) & TRB_CYCLE) != ring->ccs)
9193eb1f1efSPawel Laszczak 		goto finish;
9203eb1f1efSPawel Laszczak 
9213eb1f1efSPawel Laszczak 	if (doorbell == 1 && current_index == ring->dequeue)
9223eb1f1efSPawel Laszczak 		goto finish;
9233eb1f1efSPawel Laszczak 
9243eb1f1efSPawel Laszczak 	/* The corner case for TRBS_PER_SEGMENT equal 2). */
9253eb1f1efSPawel Laszczak 	if (TRBS_PER_SEGMENT == 2 && pep->type != USB_ENDPOINT_XFER_ISOC) {
9263eb1f1efSPawel Laszczak 		handled = 1;
9273eb1f1efSPawel Laszczak 		goto finish;
9283eb1f1efSPawel Laszczak 	}
9293eb1f1efSPawel Laszczak 
9303eb1f1efSPawel Laszczak 	if (ring->enqueue == ring->dequeue &&
9313eb1f1efSPawel Laszczak 	    ring->free_trbs == 0) {
9323eb1f1efSPawel Laszczak 		handled = 1;
9333eb1f1efSPawel Laszczak 	} else if (ring->dequeue < current_index) {
9343eb1f1efSPawel Laszczak 		if ((current_index == (TRBS_PER_SEGMENT - 1)) &&
9353eb1f1efSPawel Laszczak 		    !ring->dequeue)
9363eb1f1efSPawel Laszczak 			goto finish;
9373eb1f1efSPawel Laszczak 
9383eb1f1efSPawel Laszczak 		handled = 1;
9393eb1f1efSPawel Laszczak 	} else if (ring->dequeue  > current_index) {
9403eb1f1efSPawel Laszczak 		handled = 1;
9413eb1f1efSPawel Laszczak 	}
9423eb1f1efSPawel Laszczak 
9433eb1f1efSPawel Laszczak finish:
94407a3aef2SPawel Laszczak 	trace_cdns2_request_handled(preq, current_index, handled);
9453eb1f1efSPawel Laszczak 
9463eb1f1efSPawel Laszczak 	return handled;
9473eb1f1efSPawel Laszczak }
9483eb1f1efSPawel Laszczak 
cdns2_skip_isoc_td(struct cdns2_device * pdev,struct cdns2_endpoint * pep,struct cdns2_request * preq)9493eb1f1efSPawel Laszczak static void cdns2_skip_isoc_td(struct cdns2_device *pdev,
9503eb1f1efSPawel Laszczak 			       struct cdns2_endpoint *pep,
9513eb1f1efSPawel Laszczak 			       struct cdns2_request *preq)
9523eb1f1efSPawel Laszczak {
9533eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
9543eb1f1efSPawel Laszczak 	int i;
9553eb1f1efSPawel Laszczak 
9563eb1f1efSPawel Laszczak 	trb = pep->ring.trbs + pep->ring.dequeue;
9573eb1f1efSPawel Laszczak 
9583eb1f1efSPawel Laszczak 	for (i = preq->finished_trb ; i < preq->num_of_trb; i++) {
9593eb1f1efSPawel Laszczak 		preq->finished_trb++;
96007a3aef2SPawel Laszczak 		trace_cdns2_complete_trb(pep, trb);
9613eb1f1efSPawel Laszczak 		cdns2_ep_inc_deq(&pep->ring);
9623eb1f1efSPawel Laszczak 		trb = cdns2_next_trb(pep, trb);
9633eb1f1efSPawel Laszczak 	}
9643eb1f1efSPawel Laszczak 
9653eb1f1efSPawel Laszczak 	cdns2_gadget_giveback(pep, preq, 0);
9663eb1f1efSPawel Laszczak 	cdns2_prepare_first_isoc_transfer(pdev, pep);
9673eb1f1efSPawel Laszczak 	pep->skip = false;
9683eb1f1efSPawel Laszczak 	cdns2_set_drdy(pdev, pep);
9693eb1f1efSPawel Laszczak }
9703eb1f1efSPawel Laszczak 
cdns2_transfer_completed(struct cdns2_device * pdev,struct cdns2_endpoint * pep)9713eb1f1efSPawel Laszczak static void cdns2_transfer_completed(struct cdns2_device *pdev,
9723eb1f1efSPawel Laszczak 				     struct cdns2_endpoint *pep)
9733eb1f1efSPawel Laszczak {
9743eb1f1efSPawel Laszczak 	struct cdns2_request *preq = NULL;
9753eb1f1efSPawel Laszczak 	bool request_handled = false;
9763eb1f1efSPawel Laszczak 	struct cdns2_trb *trb;
9773eb1f1efSPawel Laszczak 
9783eb1f1efSPawel Laszczak 	while (!list_empty(&pep->pending_list)) {
9793eb1f1efSPawel Laszczak 		preq = cdns2_next_preq(&pep->pending_list);
9803eb1f1efSPawel Laszczak 		trb = pep->ring.trbs + pep->ring.dequeue;
9813eb1f1efSPawel Laszczak 
9823eb1f1efSPawel Laszczak 		/*
9833eb1f1efSPawel Laszczak 		 * The TRB was changed as link TRB, and the request
9843eb1f1efSPawel Laszczak 		 * was handled at ep_dequeue.
9853eb1f1efSPawel Laszczak 		 */
9863eb1f1efSPawel Laszczak 		while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK &&
9873eb1f1efSPawel Laszczak 		       le32_to_cpu(trb->length)) {
98807a3aef2SPawel Laszczak 			trace_cdns2_complete_trb(pep, trb);
9893eb1f1efSPawel Laszczak 			cdns2_ep_inc_deq(&pep->ring);
9903eb1f1efSPawel Laszczak 			trb = pep->ring.trbs + pep->ring.dequeue;
9913eb1f1efSPawel Laszczak 		}
9923eb1f1efSPawel Laszczak 
9933eb1f1efSPawel Laszczak 		/*
9943eb1f1efSPawel Laszczak 		 * Re-select endpoint. It could be changed by other CPU
9953eb1f1efSPawel Laszczak 		 * during handling usb_gadget_giveback_request.
9963eb1f1efSPawel Laszczak 		 */
9973eb1f1efSPawel Laszczak 		cdns2_select_ep(pdev, pep->endpoint.address);
9983eb1f1efSPawel Laszczak 
9993eb1f1efSPawel Laszczak 		while (cdns2_trb_handled(pep, preq)) {
10003eb1f1efSPawel Laszczak 			preq->finished_trb++;
10013eb1f1efSPawel Laszczak 
10023eb1f1efSPawel Laszczak 			if (preq->finished_trb >= preq->num_of_trb)
10033eb1f1efSPawel Laszczak 				request_handled = true;
10043eb1f1efSPawel Laszczak 
10053eb1f1efSPawel Laszczak 			trb = pep->ring.trbs + pep->ring.dequeue;
100607a3aef2SPawel Laszczak 			trace_cdns2_complete_trb(pep, trb);
10073eb1f1efSPawel Laszczak 
10083eb1f1efSPawel Laszczak 			if (pep->dir && pep->type == USB_ENDPOINT_XFER_ISOC)
10093eb1f1efSPawel Laszczak 				/*
10103eb1f1efSPawel Laszczak 				 * For ISOC IN controller doens't update the
10113eb1f1efSPawel Laszczak 				 * trb->length.
10123eb1f1efSPawel Laszczak 				 */
10133eb1f1efSPawel Laszczak 				preq->request.actual = preq->request.length;
10143eb1f1efSPawel Laszczak 			else
10153eb1f1efSPawel Laszczak 				preq->request.actual +=
10163eb1f1efSPawel Laszczak 					TRB_LEN(le32_to_cpu(trb->length));
10173eb1f1efSPawel Laszczak 
10183eb1f1efSPawel Laszczak 			cdns2_ep_inc_deq(&pep->ring);
10193eb1f1efSPawel Laszczak 		}
10203eb1f1efSPawel Laszczak 
10213eb1f1efSPawel Laszczak 		if (request_handled) {
10223eb1f1efSPawel Laszczak 			cdns2_gadget_giveback(pep, preq, 0);
10233eb1f1efSPawel Laszczak 			request_handled = false;
10243eb1f1efSPawel Laszczak 		} else {
10253eb1f1efSPawel Laszczak 			goto prepare_next_td;
10263eb1f1efSPawel Laszczak 		}
10273eb1f1efSPawel Laszczak 
10283eb1f1efSPawel Laszczak 		if (pep->type != USB_ENDPOINT_XFER_ISOC &&
10293eb1f1efSPawel Laszczak 		    TRBS_PER_SEGMENT == 2)
10303eb1f1efSPawel Laszczak 			break;
10313eb1f1efSPawel Laszczak 	}
10323eb1f1efSPawel Laszczak 
10333eb1f1efSPawel Laszczak prepare_next_td:
10343eb1f1efSPawel Laszczak 	if (pep->skip && preq)
10353eb1f1efSPawel Laszczak 		cdns2_skip_isoc_td(pdev, pep, preq);
10363eb1f1efSPawel Laszczak 
10373eb1f1efSPawel Laszczak 	if (!(pep->ep_state & EP_STALLED) &&
10383eb1f1efSPawel Laszczak 	    !(pep->ep_state & EP_STALL_PENDING))
10393eb1f1efSPawel Laszczak 		cdns2_start_all_request(pdev, pep);
10403eb1f1efSPawel Laszczak }
10413eb1f1efSPawel Laszczak 
cdns2_wakeup(struct cdns2_device * pdev)10423eb1f1efSPawel Laszczak static void cdns2_wakeup(struct cdns2_device *pdev)
10433eb1f1efSPawel Laszczak {
10443eb1f1efSPawel Laszczak 	if (!pdev->may_wakeup)
10453eb1f1efSPawel Laszczak 		return;
10463eb1f1efSPawel Laszczak 
10473eb1f1efSPawel Laszczak 	/* Start driving resume signaling to indicate remote wakeup. */
10483eb1f1efSPawel Laszczak 	set_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_SIGRSUME);
10493eb1f1efSPawel Laszczak }
10503eb1f1efSPawel Laszczak 
cdns2_rearm_transfer(struct cdns2_endpoint * pep,u8 rearm)10513eb1f1efSPawel Laszczak static void cdns2_rearm_transfer(struct cdns2_endpoint *pep, u8 rearm)
10523eb1f1efSPawel Laszczak {
10533eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
10543eb1f1efSPawel Laszczak 
10553eb1f1efSPawel Laszczak 	cdns2_wa1_restore_cycle_bit(pep);
10563eb1f1efSPawel Laszczak 
10573eb1f1efSPawel Laszczak 	if (rearm) {
105807a3aef2SPawel Laszczak 		trace_cdns2_ring(pep);
105907a3aef2SPawel Laszczak 
10603eb1f1efSPawel Laszczak 		/* Cycle Bit must be updated before arming DMA. */
10613eb1f1efSPawel Laszczak 		dma_wmb();
10623eb1f1efSPawel Laszczak 
10633eb1f1efSPawel Laszczak 		writel(DMA_EP_CMD_DRDY, &pdev->adma_regs->ep_cmd);
10643eb1f1efSPawel Laszczak 
10653eb1f1efSPawel Laszczak 		cdns2_wakeup(pdev);
106607a3aef2SPawel Laszczak 
106707a3aef2SPawel Laszczak 		trace_cdns2_doorbell_epx(pep,
106807a3aef2SPawel Laszczak 					 readl(&pdev->adma_regs->ep_traddr));
10693eb1f1efSPawel Laszczak 	}
10703eb1f1efSPawel Laszczak }
10713eb1f1efSPawel Laszczak 
cdns2_handle_epx_interrupt(struct cdns2_endpoint * pep)10723eb1f1efSPawel Laszczak static void cdns2_handle_epx_interrupt(struct cdns2_endpoint *pep)
10733eb1f1efSPawel Laszczak {
10743eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
10753eb1f1efSPawel Laszczak 	u8 isoerror = 0;
10763eb1f1efSPawel Laszczak 	u32 ep_sts_reg;
10773eb1f1efSPawel Laszczak 	u32 val;
10783eb1f1efSPawel Laszczak 
10793eb1f1efSPawel Laszczak 	cdns2_select_ep(pdev, pep->endpoint.address);
10803eb1f1efSPawel Laszczak 
108107a3aef2SPawel Laszczak 	trace_cdns2_epx_irq(pdev, pep);
108207a3aef2SPawel Laszczak 
10833eb1f1efSPawel Laszczak 	ep_sts_reg = readl(&pdev->adma_regs->ep_sts);
10843eb1f1efSPawel Laszczak 	writel(ep_sts_reg, &pdev->adma_regs->ep_sts);
10853eb1f1efSPawel Laszczak 
10863eb1f1efSPawel Laszczak 	if (pep->type == USB_ENDPOINT_XFER_ISOC) {
10873eb1f1efSPawel Laszczak 		u8 mult;
10883eb1f1efSPawel Laszczak 		u8 cs;
10893eb1f1efSPawel Laszczak 
10903eb1f1efSPawel Laszczak 		mult = USB_EP_MAXP_MULT(pep->endpoint.desc->wMaxPacketSize);
10913eb1f1efSPawel Laszczak 		cs = pep->dir ? readb(&pdev->epx_regs->ep[pep->num - 1].txcs) :
10923eb1f1efSPawel Laszczak 				readb(&pdev->epx_regs->ep[pep->num - 1].rxcs);
10933eb1f1efSPawel Laszczak 		if (mult > 0)
10943eb1f1efSPawel Laszczak 			isoerror = EPX_CS_ERR(cs);
10953eb1f1efSPawel Laszczak 	}
10963eb1f1efSPawel Laszczak 
10973eb1f1efSPawel Laszczak 	/*
10983eb1f1efSPawel Laszczak 	 * Sometimes ISO Error for mult=1 or mult=2 is not propagated on time
10993eb1f1efSPawel Laszczak 	 * from USB module to DMA module. To protect against this driver
11003eb1f1efSPawel Laszczak 	 * checks also the txcs/rxcs registers.
11013eb1f1efSPawel Laszczak 	 */
11023eb1f1efSPawel Laszczak 	if ((ep_sts_reg & DMA_EP_STS_ISOERR) || isoerror) {
11033eb1f1efSPawel Laszczak 		clear_reg_bit_32(&pdev->adma_regs->ep_cfg, DMA_EP_CFG_ENABLE);
11043eb1f1efSPawel Laszczak 
11053eb1f1efSPawel Laszczak 		/* Wait for DBUSY cleared. */
11063eb1f1efSPawel Laszczak 		readl_poll_timeout_atomic(&pdev->adma_regs->ep_sts, val,
11073eb1f1efSPawel Laszczak 					  !(val & DMA_EP_STS_DBUSY), 1, 125);
11083eb1f1efSPawel Laszczak 
11093eb1f1efSPawel Laszczak 		writel(DMA_EP_CMD_DFLUSH, &pep->pdev->adma_regs->ep_cmd);
11103eb1f1efSPawel Laszczak 
11113eb1f1efSPawel Laszczak 		/* Wait for DFLUSH cleared. */
11123eb1f1efSPawel Laszczak 		readl_poll_timeout_atomic(&pep->pdev->adma_regs->ep_cmd, val,
11133eb1f1efSPawel Laszczak 					  !(val & DMA_EP_CMD_DFLUSH), 1, 10);
11143eb1f1efSPawel Laszczak 
11153eb1f1efSPawel Laszczak 		pep->skip = true;
11163eb1f1efSPawel Laszczak 	}
11173eb1f1efSPawel Laszczak 
11183eb1f1efSPawel Laszczak 	if (ep_sts_reg & DMA_EP_STS_TRBERR || pep->skip) {
11193eb1f1efSPawel Laszczak 		if (pep->ep_state & EP_STALL_PENDING &&
11203eb1f1efSPawel Laszczak 		    !(ep_sts_reg & DMA_EP_STS_DESCMIS))
11213eb1f1efSPawel Laszczak 			cdns2_ep_stall_flush(pep);
11223eb1f1efSPawel Laszczak 
11233eb1f1efSPawel Laszczak 		/*
11243eb1f1efSPawel Laszczak 		 * For isochronous transfer driver completes request on
11253eb1f1efSPawel Laszczak 		 * IOC or on TRBERR. IOC appears only when device receive
11263eb1f1efSPawel Laszczak 		 * OUT data packet. If host disable stream or lost some packet
11273eb1f1efSPawel Laszczak 		 * then the only way to finish all queued transfer is to do it
11283eb1f1efSPawel Laszczak 		 * on TRBERR event.
11293eb1f1efSPawel Laszczak 		 */
11303eb1f1efSPawel Laszczak 		if (pep->type == USB_ENDPOINT_XFER_ISOC && !pep->wa1_set) {
11313eb1f1efSPawel Laszczak 			if (!pep->dir)
11323eb1f1efSPawel Laszczak 				clear_reg_bit_32(&pdev->adma_regs->ep_cfg,
11333eb1f1efSPawel Laszczak 						 DMA_EP_CFG_ENABLE);
11343eb1f1efSPawel Laszczak 
11353eb1f1efSPawel Laszczak 			cdns2_transfer_completed(pdev, pep);
11363eb1f1efSPawel Laszczak 			if (pep->ep_state & EP_DEFERRED_DRDY) {
11373eb1f1efSPawel Laszczak 				pep->ep_state &= ~EP_DEFERRED_DRDY;
11383eb1f1efSPawel Laszczak 				cdns2_set_drdy(pdev, pep);
11393eb1f1efSPawel Laszczak 			}
11403eb1f1efSPawel Laszczak 
11413eb1f1efSPawel Laszczak 			return;
11423eb1f1efSPawel Laszczak 		}
11433eb1f1efSPawel Laszczak 
11443eb1f1efSPawel Laszczak 		cdns2_transfer_completed(pdev, pep);
11453eb1f1efSPawel Laszczak 
11463eb1f1efSPawel Laszczak 		if (!(pep->ep_state & EP_STALLED) &&
11473eb1f1efSPawel Laszczak 		    !(pep->ep_state & EP_STALL_PENDING)) {
11483eb1f1efSPawel Laszczak 			if (pep->ep_state & EP_DEFERRED_DRDY) {
11493eb1f1efSPawel Laszczak 				pep->ep_state &= ~EP_DEFERRED_DRDY;
11503eb1f1efSPawel Laszczak 				cdns2_start_all_request(pdev, pep);
11513eb1f1efSPawel Laszczak 			} else {
11523eb1f1efSPawel Laszczak 				cdns2_rearm_transfer(pep, pep->wa1_set);
11533eb1f1efSPawel Laszczak 			}
11543eb1f1efSPawel Laszczak 		}
11553eb1f1efSPawel Laszczak 
11563eb1f1efSPawel Laszczak 		return;
11573eb1f1efSPawel Laszczak 	}
11583eb1f1efSPawel Laszczak 
11593eb1f1efSPawel Laszczak 	if ((ep_sts_reg & DMA_EP_STS_IOC) || (ep_sts_reg & DMA_EP_STS_ISP))
11603eb1f1efSPawel Laszczak 		cdns2_transfer_completed(pdev, pep);
11613eb1f1efSPawel Laszczak }
11623eb1f1efSPawel Laszczak 
cdns2_disconnect_gadget(struct cdns2_device * pdev)11633eb1f1efSPawel Laszczak static void cdns2_disconnect_gadget(struct cdns2_device *pdev)
11643eb1f1efSPawel Laszczak {
11653eb1f1efSPawel Laszczak 	if (pdev->gadget_driver && pdev->gadget_driver->disconnect)
11663eb1f1efSPawel Laszczak 		pdev->gadget_driver->disconnect(&pdev->gadget);
11673eb1f1efSPawel Laszczak }
11683eb1f1efSPawel Laszczak 
cdns2_usb_irq_handler(int irq,void * data)11693eb1f1efSPawel Laszczak static irqreturn_t cdns2_usb_irq_handler(int irq, void *data)
11703eb1f1efSPawel Laszczak {
11713eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = data;
11723eb1f1efSPawel Laszczak 	unsigned long reg_ep_ists;
11733eb1f1efSPawel Laszczak 	u8 reg_usb_irq_m;
11743eb1f1efSPawel Laszczak 	u8 reg_ext_irq_m;
11753eb1f1efSPawel Laszczak 	u8 reg_usb_irq;
11763eb1f1efSPawel Laszczak 	u8 reg_ext_irq;
11773eb1f1efSPawel Laszczak 
11783eb1f1efSPawel Laszczak 	if (pdev->in_lpm)
11793eb1f1efSPawel Laszczak 		return IRQ_NONE;
11803eb1f1efSPawel Laszczak 
11813eb1f1efSPawel Laszczak 	reg_usb_irq_m = readb(&pdev->interrupt_regs->usbien);
11823eb1f1efSPawel Laszczak 	reg_ext_irq_m = readb(&pdev->interrupt_regs->extien);
11833eb1f1efSPawel Laszczak 
11843eb1f1efSPawel Laszczak 	/* Mask all sources of interrupt. */
11853eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->usbien);
11863eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->extien);
11873eb1f1efSPawel Laszczak 	writel(0, &pdev->adma_regs->ep_ien);
11883eb1f1efSPawel Laszczak 
11893eb1f1efSPawel Laszczak 	/* Clear interrupt sources. */
11903eb1f1efSPawel Laszczak 	writel(0, &pdev->adma_regs->ep_sts);
11913eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->usbirq);
11923eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->extirq);
11933eb1f1efSPawel Laszczak 
11943eb1f1efSPawel Laszczak 	reg_ep_ists = readl(&pdev->adma_regs->ep_ists);
11953eb1f1efSPawel Laszczak 	reg_usb_irq = readb(&pdev->interrupt_regs->usbirq);
11963eb1f1efSPawel Laszczak 	reg_ext_irq = readb(&pdev->interrupt_regs->extirq);
11973eb1f1efSPawel Laszczak 
11983eb1f1efSPawel Laszczak 	if (reg_ep_ists || (reg_usb_irq & reg_usb_irq_m) ||
11993eb1f1efSPawel Laszczak 	    (reg_ext_irq & reg_ext_irq_m))
12003eb1f1efSPawel Laszczak 		return IRQ_WAKE_THREAD;
12013eb1f1efSPawel Laszczak 
12023eb1f1efSPawel Laszczak 	writeb(USB_IEN_INIT, &pdev->interrupt_regs->usbien);
12033eb1f1efSPawel Laszczak 	writeb(EXTIRQ_WAKEUP, &pdev->interrupt_regs->extien);
12043eb1f1efSPawel Laszczak 	writel(~0, &pdev->adma_regs->ep_ien);
12053eb1f1efSPawel Laszczak 
12063eb1f1efSPawel Laszczak 	return IRQ_NONE;
12073eb1f1efSPawel Laszczak }
12083eb1f1efSPawel Laszczak 
cdns2_thread_usb_irq_handler(struct cdns2_device * pdev)12093eb1f1efSPawel Laszczak static irqreturn_t cdns2_thread_usb_irq_handler(struct cdns2_device *pdev)
12103eb1f1efSPawel Laszczak {
12113eb1f1efSPawel Laszczak 	u8 usb_irq, ext_irq;
12123eb1f1efSPawel Laszczak 	int speed;
12133eb1f1efSPawel Laszczak 	int i;
12143eb1f1efSPawel Laszczak 
12153eb1f1efSPawel Laszczak 	ext_irq = readb(&pdev->interrupt_regs->extirq) & EXTIRQ_WAKEUP;
12163eb1f1efSPawel Laszczak 	writeb(ext_irq, &pdev->interrupt_regs->extirq);
12173eb1f1efSPawel Laszczak 
12183eb1f1efSPawel Laszczak 	usb_irq = readb(&pdev->interrupt_regs->usbirq) & USB_IEN_INIT;
12193eb1f1efSPawel Laszczak 	writeb(usb_irq, &pdev->interrupt_regs->usbirq);
12203eb1f1efSPawel Laszczak 
12213eb1f1efSPawel Laszczak 	if (!ext_irq && !usb_irq)
12223eb1f1efSPawel Laszczak 		return IRQ_NONE;
12233eb1f1efSPawel Laszczak 
122407a3aef2SPawel Laszczak 	trace_cdns2_usb_irq(usb_irq, ext_irq);
122507a3aef2SPawel Laszczak 
12263eb1f1efSPawel Laszczak 	if (ext_irq & EXTIRQ_WAKEUP) {
12273eb1f1efSPawel Laszczak 		if (pdev->gadget_driver && pdev->gadget_driver->resume) {
12283eb1f1efSPawel Laszczak 			spin_unlock(&pdev->lock);
12293eb1f1efSPawel Laszczak 			pdev->gadget_driver->resume(&pdev->gadget);
12303eb1f1efSPawel Laszczak 			spin_lock(&pdev->lock);
12313eb1f1efSPawel Laszczak 		}
12323eb1f1efSPawel Laszczak 	}
12333eb1f1efSPawel Laszczak 
12343eb1f1efSPawel Laszczak 	if (usb_irq & USBIRQ_LPM) {
12353eb1f1efSPawel Laszczak 		u8 reg = readb(&pdev->usb_regs->lpmctrl);
12363eb1f1efSPawel Laszczak 
12373eb1f1efSPawel Laszczak 		/* LPM1 enter */
12383eb1f1efSPawel Laszczak 		if (!(reg & LPMCTRLLH_LPMNYET))
12393eb1f1efSPawel Laszczak 			writeb(0, &pdev->usb_regs->sleep_clkgate);
12403eb1f1efSPawel Laszczak 	}
12413eb1f1efSPawel Laszczak 
12423eb1f1efSPawel Laszczak 	if (usb_irq & USBIRQ_SUSPEND) {
12433eb1f1efSPawel Laszczak 		if (pdev->gadget_driver && pdev->gadget_driver->suspend) {
12443eb1f1efSPawel Laszczak 			spin_unlock(&pdev->lock);
12453eb1f1efSPawel Laszczak 			pdev->gadget_driver->suspend(&pdev->gadget);
12463eb1f1efSPawel Laszczak 			spin_lock(&pdev->lock);
12473eb1f1efSPawel Laszczak 		}
12483eb1f1efSPawel Laszczak 	}
12493eb1f1efSPawel Laszczak 
12503eb1f1efSPawel Laszczak 	if (usb_irq & USBIRQ_URESET) {
12513eb1f1efSPawel Laszczak 		if (pdev->gadget_driver) {
12523eb1f1efSPawel Laszczak 			pdev->dev_address = 0;
12533eb1f1efSPawel Laszczak 
12543eb1f1efSPawel Laszczak 			spin_unlock(&pdev->lock);
12553eb1f1efSPawel Laszczak 			usb_gadget_udc_reset(&pdev->gadget,
12563eb1f1efSPawel Laszczak 					     pdev->gadget_driver);
12573eb1f1efSPawel Laszczak 			spin_lock(&pdev->lock);
12583eb1f1efSPawel Laszczak 
12593eb1f1efSPawel Laszczak 			/*
12603eb1f1efSPawel Laszczak 			 * The USBIRQ_URESET is reported at the beginning of
12613eb1f1efSPawel Laszczak 			 * reset signal. 100ms is enough time to finish reset
12623eb1f1efSPawel Laszczak 			 * process. For high-speed reset procedure is completed
12633eb1f1efSPawel Laszczak 			 * when controller detect HS mode.
12643eb1f1efSPawel Laszczak 			 */
12653eb1f1efSPawel Laszczak 			for (i = 0; i < 100; i++) {
12663eb1f1efSPawel Laszczak 				mdelay(1);
12673eb1f1efSPawel Laszczak 				speed = cdns2_get_speed(pdev);
12683eb1f1efSPawel Laszczak 				if (speed == USB_SPEED_HIGH)
12693eb1f1efSPawel Laszczak 					break;
12703eb1f1efSPawel Laszczak 			}
12713eb1f1efSPawel Laszczak 
12723eb1f1efSPawel Laszczak 			pdev->gadget.speed = speed;
12733eb1f1efSPawel Laszczak 			cdns2_enable_l1(pdev, 0);
12743eb1f1efSPawel Laszczak 			cdns2_ep0_config(pdev);
12753eb1f1efSPawel Laszczak 			pdev->may_wakeup = 0;
12763eb1f1efSPawel Laszczak 		}
12773eb1f1efSPawel Laszczak 	}
12783eb1f1efSPawel Laszczak 
12793eb1f1efSPawel Laszczak 	if (usb_irq & USBIRQ_SUDAV) {
12803eb1f1efSPawel Laszczak 		pdev->ep0_stage = CDNS2_SETUP_STAGE;
12813eb1f1efSPawel Laszczak 		cdns2_handle_setup_packet(pdev);
12823eb1f1efSPawel Laszczak 	}
12833eb1f1efSPawel Laszczak 
12843eb1f1efSPawel Laszczak 	return IRQ_HANDLED;
12853eb1f1efSPawel Laszczak }
12863eb1f1efSPawel Laszczak 
12873eb1f1efSPawel Laszczak /* Deferred USB interrupt handler. */
cdns2_thread_irq_handler(int irq,void * data)12883eb1f1efSPawel Laszczak static irqreturn_t cdns2_thread_irq_handler(int irq, void *data)
12893eb1f1efSPawel Laszczak {
12903eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = data;
12913eb1f1efSPawel Laszczak 	unsigned long  dma_ep_ists;
12923eb1f1efSPawel Laszczak 	unsigned long flags;
12933eb1f1efSPawel Laszczak 	unsigned int bit;
12943eb1f1efSPawel Laszczak 
12953eb1f1efSPawel Laszczak 	local_bh_disable();
12963eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
12973eb1f1efSPawel Laszczak 
12983eb1f1efSPawel Laszczak 	cdns2_thread_usb_irq_handler(pdev);
12993eb1f1efSPawel Laszczak 
13003eb1f1efSPawel Laszczak 	dma_ep_ists = readl(&pdev->adma_regs->ep_ists);
13013eb1f1efSPawel Laszczak 	if (!dma_ep_ists)
13023eb1f1efSPawel Laszczak 		goto unlock;
13033eb1f1efSPawel Laszczak 
130407a3aef2SPawel Laszczak 	trace_cdns2_dma_ep_ists(dma_ep_ists);
130507a3aef2SPawel Laszczak 
13063eb1f1efSPawel Laszczak 	/* Handle default endpoint OUT. */
13073eb1f1efSPawel Laszczak 	if (dma_ep_ists & DMA_EP_ISTS_EP_OUT0)
13083eb1f1efSPawel Laszczak 		cdns2_handle_ep0_interrupt(pdev, USB_DIR_OUT);
13093eb1f1efSPawel Laszczak 
13103eb1f1efSPawel Laszczak 	/* Handle default endpoint IN. */
13113eb1f1efSPawel Laszczak 	if (dma_ep_ists & DMA_EP_ISTS_EP_IN0)
13123eb1f1efSPawel Laszczak 		cdns2_handle_ep0_interrupt(pdev, USB_DIR_IN);
13133eb1f1efSPawel Laszczak 
13143eb1f1efSPawel Laszczak 	dma_ep_ists &= ~(DMA_EP_ISTS_EP_OUT0 | DMA_EP_ISTS_EP_IN0);
13153eb1f1efSPawel Laszczak 
13163eb1f1efSPawel Laszczak 	for_each_set_bit(bit, &dma_ep_ists, sizeof(u32) * BITS_PER_BYTE) {
13173eb1f1efSPawel Laszczak 		u8 ep_idx = bit > 16 ? (bit - 16) * 2 : (bit * 2) - 1;
13183eb1f1efSPawel Laszczak 
13193eb1f1efSPawel Laszczak 		/*
13203eb1f1efSPawel Laszczak 		 * Endpoints in pdev->eps[] are held in order:
13213eb1f1efSPawel Laszczak 		 * ep0, ep1out, ep1in, ep2out, ep2in... ep15out, ep15in.
13223eb1f1efSPawel Laszczak 		 * but in dma_ep_ists in order:
13233eb1f1efSPawel Laszczak 		 * ep0 ep1out ep2out ... ep15out ep0in ep1in .. ep15in
13243eb1f1efSPawel Laszczak 		 */
13253eb1f1efSPawel Laszczak 		cdns2_handle_epx_interrupt(&pdev->eps[ep_idx]);
13263eb1f1efSPawel Laszczak 	}
13273eb1f1efSPawel Laszczak 
13283eb1f1efSPawel Laszczak unlock:
13293eb1f1efSPawel Laszczak 	writel(~0, &pdev->adma_regs->ep_ien);
13303eb1f1efSPawel Laszczak 	writeb(USB_IEN_INIT, &pdev->interrupt_regs->usbien);
13313eb1f1efSPawel Laszczak 	writeb(EXTIRQ_WAKEUP, &pdev->interrupt_regs->extien);
13323eb1f1efSPawel Laszczak 
13333eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
13343eb1f1efSPawel Laszczak 	local_bh_enable();
13353eb1f1efSPawel Laszczak 
13363eb1f1efSPawel Laszczak 	return IRQ_HANDLED;
13373eb1f1efSPawel Laszczak }
13383eb1f1efSPawel Laszczak 
13393eb1f1efSPawel Laszczak /* Calculates and assigns onchip memory for endpoints. */
cdns2_eps_onchip_buffer_init(struct cdns2_device * pdev)13403eb1f1efSPawel Laszczak static void cdns2_eps_onchip_buffer_init(struct cdns2_device *pdev)
13413eb1f1efSPawel Laszczak {
13423eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
13433eb1f1efSPawel Laszczak 	int min_buf_tx = 0;
13443eb1f1efSPawel Laszczak 	int min_buf_rx = 0;
13453eb1f1efSPawel Laszczak 	u16 tx_offset = 0;
13463eb1f1efSPawel Laszczak 	u16 rx_offset = 0;
13473eb1f1efSPawel Laszczak 	int free;
13483eb1f1efSPawel Laszczak 	int i;
13493eb1f1efSPawel Laszczak 
13503eb1f1efSPawel Laszczak 	for (i = 0; i < CDNS2_ENDPOINTS_NUM; i++) {
13513eb1f1efSPawel Laszczak 		pep = &pdev->eps[i];
13523eb1f1efSPawel Laszczak 
13533eb1f1efSPawel Laszczak 		if (!(pep->ep_state & EP_CLAIMED))
13543eb1f1efSPawel Laszczak 			continue;
13553eb1f1efSPawel Laszczak 
13563eb1f1efSPawel Laszczak 		if (pep->dir)
13573eb1f1efSPawel Laszczak 			min_buf_tx += pep->buffering;
13583eb1f1efSPawel Laszczak 		else
13593eb1f1efSPawel Laszczak 			min_buf_rx += pep->buffering;
13603eb1f1efSPawel Laszczak 	}
13613eb1f1efSPawel Laszczak 
13623eb1f1efSPawel Laszczak 	for (i = 0; i < CDNS2_ENDPOINTS_NUM; i++) {
13633eb1f1efSPawel Laszczak 		pep = &pdev->eps[i];
13643eb1f1efSPawel Laszczak 
13653eb1f1efSPawel Laszczak 		if (!(pep->ep_state & EP_CLAIMED))
13663eb1f1efSPawel Laszczak 			continue;
13673eb1f1efSPawel Laszczak 
13683eb1f1efSPawel Laszczak 		if (pep->dir) {
13693eb1f1efSPawel Laszczak 			free = pdev->onchip_tx_buf - min_buf_tx;
13703eb1f1efSPawel Laszczak 
13713eb1f1efSPawel Laszczak 			if (free + pep->buffering >= 4)
13723eb1f1efSPawel Laszczak 				free = 4;
13733eb1f1efSPawel Laszczak 			else
13743eb1f1efSPawel Laszczak 				free = free + pep->buffering;
13753eb1f1efSPawel Laszczak 
13763eb1f1efSPawel Laszczak 			min_buf_tx = min_buf_tx - pep->buffering + free;
13773eb1f1efSPawel Laszczak 
13783eb1f1efSPawel Laszczak 			pep->buffering = free;
13793eb1f1efSPawel Laszczak 
13803eb1f1efSPawel Laszczak 			writel(tx_offset,
13813eb1f1efSPawel Laszczak 			       &pdev->epx_regs->txstaddr[pep->num - 1]);
13823eb1f1efSPawel Laszczak 			pdev->epx_regs->txstaddr[pep->num - 1] = tx_offset;
13833eb1f1efSPawel Laszczak 
13843eb1f1efSPawel Laszczak 			dev_dbg(pdev->dev, "%s onchip address %04x, buffering: %d\n",
13853eb1f1efSPawel Laszczak 				pep->name, tx_offset, pep->buffering);
13863eb1f1efSPawel Laszczak 
13873eb1f1efSPawel Laszczak 			tx_offset += pep->buffering * 1024;
13883eb1f1efSPawel Laszczak 		} else {
13893eb1f1efSPawel Laszczak 			free = pdev->onchip_rx_buf - min_buf_rx;
13903eb1f1efSPawel Laszczak 
13913eb1f1efSPawel Laszczak 			if (free + pep->buffering >= 4)
13923eb1f1efSPawel Laszczak 				free = 4;
13933eb1f1efSPawel Laszczak 			else
13943eb1f1efSPawel Laszczak 				free = free + pep->buffering;
13953eb1f1efSPawel Laszczak 
13963eb1f1efSPawel Laszczak 			min_buf_rx = min_buf_rx - pep->buffering + free;
13973eb1f1efSPawel Laszczak 
13983eb1f1efSPawel Laszczak 			pep->buffering = free;
13993eb1f1efSPawel Laszczak 			writel(rx_offset,
14003eb1f1efSPawel Laszczak 			       &pdev->epx_regs->rxstaddr[pep->num - 1]);
14013eb1f1efSPawel Laszczak 
14023eb1f1efSPawel Laszczak 			dev_dbg(pdev->dev, "%s onchip address %04x, buffering: %d\n",
14033eb1f1efSPawel Laszczak 				pep->name, rx_offset, pep->buffering);
14043eb1f1efSPawel Laszczak 
14053eb1f1efSPawel Laszczak 			rx_offset += pep->buffering * 1024;
14063eb1f1efSPawel Laszczak 		}
14073eb1f1efSPawel Laszczak 	}
14083eb1f1efSPawel Laszczak }
14093eb1f1efSPawel Laszczak 
14103eb1f1efSPawel Laszczak /* Configure hardware endpoint. */
cdns2_ep_config(struct cdns2_endpoint * pep,bool enable)14113eb1f1efSPawel Laszczak static int cdns2_ep_config(struct cdns2_endpoint *pep, bool enable)
14123eb1f1efSPawel Laszczak {
14133eb1f1efSPawel Laszczak 	bool is_iso_ep = (pep->type == USB_ENDPOINT_XFER_ISOC);
14143eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
14153eb1f1efSPawel Laszczak 	u32 max_packet_size;
14163eb1f1efSPawel Laszczak 	u8 dir = 0;
14173eb1f1efSPawel Laszczak 	u8 ep_cfg;
14183eb1f1efSPawel Laszczak 	u8 mult;
14193eb1f1efSPawel Laszczak 	u32 val;
14203eb1f1efSPawel Laszczak 	int ret;
14213eb1f1efSPawel Laszczak 
14223eb1f1efSPawel Laszczak 	switch (pep->type) {
14233eb1f1efSPawel Laszczak 	case USB_ENDPOINT_XFER_INT:
14243eb1f1efSPawel Laszczak 		ep_cfg = EPX_CON_TYPE_INT;
14253eb1f1efSPawel Laszczak 		break;
14263eb1f1efSPawel Laszczak 	case USB_ENDPOINT_XFER_BULK:
14273eb1f1efSPawel Laszczak 		ep_cfg = EPX_CON_TYPE_BULK;
14283eb1f1efSPawel Laszczak 		break;
14293eb1f1efSPawel Laszczak 	default:
14303eb1f1efSPawel Laszczak 		mult = USB_EP_MAXP_MULT(pep->endpoint.desc->wMaxPacketSize);
14313eb1f1efSPawel Laszczak 		ep_cfg = mult << EPX_CON_ISOD_SHIFT;
14323eb1f1efSPawel Laszczak 		ep_cfg |= EPX_CON_TYPE_ISOC;
14333eb1f1efSPawel Laszczak 
14343eb1f1efSPawel Laszczak 		if (pep->dir) {
14353eb1f1efSPawel Laszczak 			set_reg_bit_8(&pdev->epx_regs->isoautoarm, BIT(pep->num));
14363eb1f1efSPawel Laszczak 			set_reg_bit_8(&pdev->epx_regs->isoautodump, BIT(pep->num));
14373eb1f1efSPawel Laszczak 			set_reg_bit_8(&pdev->epx_regs->isodctrl, BIT(pep->num));
14383eb1f1efSPawel Laszczak 		}
14393eb1f1efSPawel Laszczak 	}
14403eb1f1efSPawel Laszczak 
14413eb1f1efSPawel Laszczak 	switch (pdev->gadget.speed) {
14423eb1f1efSPawel Laszczak 	case USB_SPEED_FULL:
14433eb1f1efSPawel Laszczak 		max_packet_size = is_iso_ep ? 1023 : 64;
14443eb1f1efSPawel Laszczak 		break;
14453eb1f1efSPawel Laszczak 	case USB_SPEED_HIGH:
14463eb1f1efSPawel Laszczak 		max_packet_size = is_iso_ep ? 1024 : 512;
14473eb1f1efSPawel Laszczak 		break;
14483eb1f1efSPawel Laszczak 	default:
14493eb1f1efSPawel Laszczak 		/* All other speed are not supported. */
14503eb1f1efSPawel Laszczak 		return -EINVAL;
14513eb1f1efSPawel Laszczak 	}
14523eb1f1efSPawel Laszczak 
14533eb1f1efSPawel Laszczak 	ep_cfg |= (EPX_CON_VAL | (pep->buffering - 1));
14543eb1f1efSPawel Laszczak 
14553eb1f1efSPawel Laszczak 	if (pep->dir) {
14563eb1f1efSPawel Laszczak 		dir = FIFOCTRL_IO_TX;
14573eb1f1efSPawel Laszczak 		writew(max_packet_size, &pdev->epx_regs->txmaxpack[pep->num - 1]);
14583eb1f1efSPawel Laszczak 		writeb(ep_cfg, &pdev->epx_regs->ep[pep->num - 1].txcon);
14593eb1f1efSPawel Laszczak 	} else {
14603eb1f1efSPawel Laszczak 		writew(max_packet_size, &pdev->epx_regs->rxmaxpack[pep->num - 1]);
14613eb1f1efSPawel Laszczak 		writeb(ep_cfg, &pdev->epx_regs->ep[pep->num - 1].rxcon);
14623eb1f1efSPawel Laszczak 	}
14633eb1f1efSPawel Laszczak 
14643eb1f1efSPawel Laszczak 	writeb(pep->num | dir | FIFOCTRL_FIFOAUTO,
14653eb1f1efSPawel Laszczak 	       &pdev->usb_regs->fifoctrl);
14663eb1f1efSPawel Laszczak 	writeb(pep->num | dir, &pdev->epx_regs->endprst);
14673eb1f1efSPawel Laszczak 	writeb(pep->num | ENDPRST_FIFORST | ENDPRST_TOGRST | dir,
14683eb1f1efSPawel Laszczak 	       &pdev->epx_regs->endprst);
14693eb1f1efSPawel Laszczak 
14703eb1f1efSPawel Laszczak 	if (max_packet_size == 1024)
14713eb1f1efSPawel Laszczak 		pep->trb_burst_size = 128;
14723eb1f1efSPawel Laszczak 	else if (max_packet_size >= 512)
14733eb1f1efSPawel Laszczak 		pep->trb_burst_size = 64;
14743eb1f1efSPawel Laszczak 	else
14753eb1f1efSPawel Laszczak 		pep->trb_burst_size = 16;
14763eb1f1efSPawel Laszczak 
14773eb1f1efSPawel Laszczak 	cdns2_select_ep(pdev, pep->num | pep->dir);
14783eb1f1efSPawel Laszczak 	writel(DMA_EP_CMD_EPRST | DMA_EP_CMD_DFLUSH, &pdev->adma_regs->ep_cmd);
14793eb1f1efSPawel Laszczak 
14803eb1f1efSPawel Laszczak 	ret = readl_poll_timeout_atomic(&pdev->adma_regs->ep_cmd, val,
14813eb1f1efSPawel Laszczak 					!(val & (DMA_EP_CMD_DFLUSH |
14823eb1f1efSPawel Laszczak 					DMA_EP_CMD_EPRST)),
14833eb1f1efSPawel Laszczak 					1, 1000);
14843eb1f1efSPawel Laszczak 
14853eb1f1efSPawel Laszczak 	if (ret)
14863eb1f1efSPawel Laszczak 		return ret;
14873eb1f1efSPawel Laszczak 
14883eb1f1efSPawel Laszczak 	writel(DMA_EP_STS_TRBERR | DMA_EP_STS_ISOERR, &pdev->adma_regs->ep_sts_en);
14893eb1f1efSPawel Laszczak 
14903eb1f1efSPawel Laszczak 	if (enable)
14913eb1f1efSPawel Laszczak 		writel(DMA_EP_CFG_ENABLE, &pdev->adma_regs->ep_cfg);
14923eb1f1efSPawel Laszczak 
149307a3aef2SPawel Laszczak 	trace_cdns2_epx_hw_cfg(pdev, pep);
149407a3aef2SPawel Laszczak 
14953eb1f1efSPawel Laszczak 	dev_dbg(pdev->dev, "Configure %s: with MPS: %08x, ep con: %02x\n",
14963eb1f1efSPawel Laszczak 		pep->name, max_packet_size, ep_cfg);
14973eb1f1efSPawel Laszczak 
14983eb1f1efSPawel Laszczak 	return 0;
14993eb1f1efSPawel Laszczak }
15003eb1f1efSPawel Laszczak 
cdns2_gadget_ep_alloc_request(struct usb_ep * ep,gfp_t gfp_flags)15013eb1f1efSPawel Laszczak struct usb_request *cdns2_gadget_ep_alloc_request(struct usb_ep *ep,
15023eb1f1efSPawel Laszczak 						  gfp_t gfp_flags)
15033eb1f1efSPawel Laszczak {
15043eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep = ep_to_cdns2_ep(ep);
15053eb1f1efSPawel Laszczak 	struct cdns2_request *preq;
15063eb1f1efSPawel Laszczak 
15073eb1f1efSPawel Laszczak 	preq = kzalloc(sizeof(*preq), gfp_flags);
15083eb1f1efSPawel Laszczak 	if (!preq)
15093eb1f1efSPawel Laszczak 		return NULL;
15103eb1f1efSPawel Laszczak 
15113eb1f1efSPawel Laszczak 	preq->pep = pep;
15123eb1f1efSPawel Laszczak 
151307a3aef2SPawel Laszczak 	trace_cdns2_alloc_request(preq);
151407a3aef2SPawel Laszczak 
15153eb1f1efSPawel Laszczak 	return &preq->request;
15163eb1f1efSPawel Laszczak }
15173eb1f1efSPawel Laszczak 
cdns2_gadget_ep_free_request(struct usb_ep * ep,struct usb_request * request)15183eb1f1efSPawel Laszczak void cdns2_gadget_ep_free_request(struct usb_ep *ep,
15193eb1f1efSPawel Laszczak 				  struct usb_request *request)
15203eb1f1efSPawel Laszczak {
15213eb1f1efSPawel Laszczak 	struct cdns2_request *preq = to_cdns2_request(request);
15223eb1f1efSPawel Laszczak 
152307a3aef2SPawel Laszczak 	trace_cdns2_free_request(preq);
15243eb1f1efSPawel Laszczak 	kfree(preq);
15253eb1f1efSPawel Laszczak }
15263eb1f1efSPawel Laszczak 
cdns2_gadget_ep_enable(struct usb_ep * ep,const struct usb_endpoint_descriptor * desc)15273eb1f1efSPawel Laszczak static int cdns2_gadget_ep_enable(struct usb_ep *ep,
15283eb1f1efSPawel Laszczak 				  const struct usb_endpoint_descriptor *desc)
15293eb1f1efSPawel Laszczak {
15303eb1f1efSPawel Laszczak 	u32 reg = DMA_EP_STS_EN_TRBERREN;
15313eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
15323eb1f1efSPawel Laszczak 	struct cdns2_device *pdev;
15333eb1f1efSPawel Laszczak 	unsigned long flags;
15343eb1f1efSPawel Laszczak 	int enable = 1;
15353eb1f1efSPawel Laszczak 	int ret = 0;
15363eb1f1efSPawel Laszczak 
15373eb1f1efSPawel Laszczak 	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT ||
15383eb1f1efSPawel Laszczak 	    !desc->wMaxPacketSize) {
15393eb1f1efSPawel Laszczak 		return -EINVAL;
15403eb1f1efSPawel Laszczak 	}
15413eb1f1efSPawel Laszczak 
15423eb1f1efSPawel Laszczak 	pep = ep_to_cdns2_ep(ep);
15433eb1f1efSPawel Laszczak 	pdev = pep->pdev;
15443eb1f1efSPawel Laszczak 
15453eb1f1efSPawel Laszczak 	if (dev_WARN_ONCE(pdev->dev, pep->ep_state & EP_ENABLED,
15463eb1f1efSPawel Laszczak 			  "%s is already enabled\n", pep->name))
15473eb1f1efSPawel Laszczak 		return 0;
15483eb1f1efSPawel Laszczak 
15493eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
15503eb1f1efSPawel Laszczak 
15513eb1f1efSPawel Laszczak 	pep->type = usb_endpoint_type(desc);
15523eb1f1efSPawel Laszczak 	pep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0;
15533eb1f1efSPawel Laszczak 
15543eb1f1efSPawel Laszczak 	if (pdev->gadget.speed == USB_SPEED_FULL)
15553eb1f1efSPawel Laszczak 		if (pep->type == USB_ENDPOINT_XFER_INT)
15563eb1f1efSPawel Laszczak 			pep->interval = desc->bInterval;
15573eb1f1efSPawel Laszczak 
15583eb1f1efSPawel Laszczak 	if (pep->interval > ISO_MAX_INTERVAL &&
15593eb1f1efSPawel Laszczak 	    pep->type == USB_ENDPOINT_XFER_ISOC) {
15603eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "ISO period is limited to %d (current: %d)\n",
15613eb1f1efSPawel Laszczak 			ISO_MAX_INTERVAL, pep->interval);
15623eb1f1efSPawel Laszczak 
15633eb1f1efSPawel Laszczak 		ret =  -EINVAL;
15643eb1f1efSPawel Laszczak 		goto exit;
15653eb1f1efSPawel Laszczak 	}
15663eb1f1efSPawel Laszczak 
15673eb1f1efSPawel Laszczak 	/*
15683eb1f1efSPawel Laszczak 	 * During ISO OUT traffic DMA reads Transfer Ring for the EP which has
15693eb1f1efSPawel Laszczak 	 * never got doorbell.
15703eb1f1efSPawel Laszczak 	 * This issue was detected only on simulation, but to avoid this issue
15713eb1f1efSPawel Laszczak 	 * driver add protection against it. To fix it driver enable ISO OUT
15723eb1f1efSPawel Laszczak 	 * endpoint before setting DRBL. This special treatment of ISO OUT
15733eb1f1efSPawel Laszczak 	 * endpoints are recommended by controller specification.
15743eb1f1efSPawel Laszczak 	 */
15753eb1f1efSPawel Laszczak 	if (pep->type == USB_ENDPOINT_XFER_ISOC  && !pep->dir)
15763eb1f1efSPawel Laszczak 		enable = 0;
15773eb1f1efSPawel Laszczak 
15783eb1f1efSPawel Laszczak 	ret = cdns2_alloc_tr_segment(pep);
15793eb1f1efSPawel Laszczak 	if (ret)
15803eb1f1efSPawel Laszczak 		goto exit;
15813eb1f1efSPawel Laszczak 
15823eb1f1efSPawel Laszczak 	ret = cdns2_ep_config(pep, enable);
15833eb1f1efSPawel Laszczak 	if (ret) {
15843eb1f1efSPawel Laszczak 		cdns2_free_tr_segment(pep);
15853eb1f1efSPawel Laszczak 		ret =  -EINVAL;
15863eb1f1efSPawel Laszczak 		goto exit;
15873eb1f1efSPawel Laszczak 	}
15883eb1f1efSPawel Laszczak 
158907a3aef2SPawel Laszczak 	trace_cdns2_gadget_ep_enable(pep);
159007a3aef2SPawel Laszczak 
15913eb1f1efSPawel Laszczak 	pep->ep_state &= ~(EP_STALLED | EP_STALL_PENDING);
15923eb1f1efSPawel Laszczak 	pep->ep_state |= EP_ENABLED;
15933eb1f1efSPawel Laszczak 	pep->wa1_set = 0;
15943eb1f1efSPawel Laszczak 	pep->ring.enqueue = 0;
15953eb1f1efSPawel Laszczak 	pep->ring.dequeue = 0;
15963eb1f1efSPawel Laszczak 	reg = readl(&pdev->adma_regs->ep_sts);
15973eb1f1efSPawel Laszczak 	pep->ring.pcs = !!DMA_EP_STS_CCS(reg);
15983eb1f1efSPawel Laszczak 	pep->ring.ccs = !!DMA_EP_STS_CCS(reg);
15993eb1f1efSPawel Laszczak 
16003eb1f1efSPawel Laszczak 	writel(pep->ring.dma, &pdev->adma_regs->ep_traddr);
16013eb1f1efSPawel Laszczak 
16023eb1f1efSPawel Laszczak 	/* one TRB is reserved for link TRB used in DMULT mode*/
16033eb1f1efSPawel Laszczak 	pep->ring.free_trbs = TRBS_PER_SEGMENT - 1;
16043eb1f1efSPawel Laszczak 
16053eb1f1efSPawel Laszczak exit:
16063eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
16073eb1f1efSPawel Laszczak 
16083eb1f1efSPawel Laszczak 	return ret;
16093eb1f1efSPawel Laszczak }
16103eb1f1efSPawel Laszczak 
cdns2_gadget_ep_disable(struct usb_ep * ep)16113eb1f1efSPawel Laszczak static int cdns2_gadget_ep_disable(struct usb_ep *ep)
16123eb1f1efSPawel Laszczak {
16133eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
16143eb1f1efSPawel Laszczak 	struct cdns2_request *preq;
16153eb1f1efSPawel Laszczak 	struct cdns2_device *pdev;
16163eb1f1efSPawel Laszczak 	unsigned long flags;
16173eb1f1efSPawel Laszczak 	int val;
16183eb1f1efSPawel Laszczak 
16193eb1f1efSPawel Laszczak 	if (!ep)
16203eb1f1efSPawel Laszczak 		return -EINVAL;
16213eb1f1efSPawel Laszczak 
16223eb1f1efSPawel Laszczak 	pep = ep_to_cdns2_ep(ep);
16233eb1f1efSPawel Laszczak 	pdev = pep->pdev;
16243eb1f1efSPawel Laszczak 
16253eb1f1efSPawel Laszczak 	if (dev_WARN_ONCE(pdev->dev, !(pep->ep_state & EP_ENABLED),
16263eb1f1efSPawel Laszczak 			  "%s is already disabled\n", pep->name))
16273eb1f1efSPawel Laszczak 		return 0;
16283eb1f1efSPawel Laszczak 
16293eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
16303eb1f1efSPawel Laszczak 
163107a3aef2SPawel Laszczak 	trace_cdns2_gadget_ep_disable(pep);
163207a3aef2SPawel Laszczak 
16333eb1f1efSPawel Laszczak 	cdns2_select_ep(pdev, ep->desc->bEndpointAddress);
16343eb1f1efSPawel Laszczak 
16353eb1f1efSPawel Laszczak 	clear_reg_bit_32(&pdev->adma_regs->ep_cfg, DMA_EP_CFG_ENABLE);
16363eb1f1efSPawel Laszczak 
16373eb1f1efSPawel Laszczak 	/*
16383eb1f1efSPawel Laszczak 	 * Driver needs some time before resetting endpoint.
16393eb1f1efSPawel Laszczak 	 * It need waits for clearing DBUSY bit or for timeout expired.
16403eb1f1efSPawel Laszczak 	 * 10us is enough time for controller to stop transfer.
16413eb1f1efSPawel Laszczak 	 */
16423eb1f1efSPawel Laszczak 	readl_poll_timeout_atomic(&pdev->adma_regs->ep_sts, val,
16433eb1f1efSPawel Laszczak 				  !(val & DMA_EP_STS_DBUSY), 1, 10);
16443eb1f1efSPawel Laszczak 	writel(DMA_EP_CMD_EPRST, &pdev->adma_regs->ep_cmd);
16453eb1f1efSPawel Laszczak 
16463eb1f1efSPawel Laszczak 	readl_poll_timeout_atomic(&pdev->adma_regs->ep_cmd, val,
16473eb1f1efSPawel Laszczak 				  !(val & (DMA_EP_CMD_DFLUSH | DMA_EP_CMD_EPRST)),
16483eb1f1efSPawel Laszczak 				  1, 1000);
16493eb1f1efSPawel Laszczak 
16503eb1f1efSPawel Laszczak 	while (!list_empty(&pep->pending_list)) {
16513eb1f1efSPawel Laszczak 		preq = cdns2_next_preq(&pep->pending_list);
16523eb1f1efSPawel Laszczak 		cdns2_gadget_giveback(pep, preq, -ESHUTDOWN);
16533eb1f1efSPawel Laszczak 	}
16543eb1f1efSPawel Laszczak 
16553eb1f1efSPawel Laszczak 	while (!list_empty(&pep->deferred_list)) {
16563eb1f1efSPawel Laszczak 		preq = cdns2_next_preq(&pep->deferred_list);
16573eb1f1efSPawel Laszczak 		cdns2_gadget_giveback(pep, preq, -ESHUTDOWN);
16583eb1f1efSPawel Laszczak 	}
16593eb1f1efSPawel Laszczak 
16603eb1f1efSPawel Laszczak 	ep->desc = NULL;
16613eb1f1efSPawel Laszczak 	pep->ep_state &= ~EP_ENABLED;
16623eb1f1efSPawel Laszczak 
16633eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
16643eb1f1efSPawel Laszczak 
16653eb1f1efSPawel Laszczak 	return 0;
16663eb1f1efSPawel Laszczak }
16673eb1f1efSPawel Laszczak 
cdns2_ep_enqueue(struct cdns2_endpoint * pep,struct cdns2_request * preq,gfp_t gfp_flags)16683eb1f1efSPawel Laszczak static int cdns2_ep_enqueue(struct cdns2_endpoint *pep,
16693eb1f1efSPawel Laszczak 			    struct cdns2_request *preq,
16703eb1f1efSPawel Laszczak 			    gfp_t gfp_flags)
16713eb1f1efSPawel Laszczak {
16723eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
16733eb1f1efSPawel Laszczak 	struct usb_request *request;
16743eb1f1efSPawel Laszczak 	int ret;
16753eb1f1efSPawel Laszczak 
16763eb1f1efSPawel Laszczak 	request = &preq->request;
16773eb1f1efSPawel Laszczak 	request->actual = 0;
16783eb1f1efSPawel Laszczak 	request->status = -EINPROGRESS;
16793eb1f1efSPawel Laszczak 
16803eb1f1efSPawel Laszczak 	ret = usb_gadget_map_request_by_dev(pdev->dev, request, pep->dir);
168107a3aef2SPawel Laszczak 	if (ret) {
168207a3aef2SPawel Laszczak 		trace_cdns2_request_enqueue_error(preq);
16833eb1f1efSPawel Laszczak 		return ret;
168407a3aef2SPawel Laszczak 	}
16853eb1f1efSPawel Laszczak 
16863eb1f1efSPawel Laszczak 	list_add_tail(&preq->list, &pep->deferred_list);
168707a3aef2SPawel Laszczak 	trace_cdns2_request_enqueue(preq);
16883eb1f1efSPawel Laszczak 
16893eb1f1efSPawel Laszczak 	if (!(pep->ep_state & EP_STALLED) && !(pep->ep_state & EP_STALL_PENDING))
16903eb1f1efSPawel Laszczak 		cdns2_start_all_request(pdev, pep);
16913eb1f1efSPawel Laszczak 
16923eb1f1efSPawel Laszczak 	return 0;
16933eb1f1efSPawel Laszczak }
16943eb1f1efSPawel Laszczak 
cdns2_gadget_ep_queue(struct usb_ep * ep,struct usb_request * request,gfp_t gfp_flags)16953eb1f1efSPawel Laszczak static int cdns2_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
16963eb1f1efSPawel Laszczak 				 gfp_t gfp_flags)
16973eb1f1efSPawel Laszczak {
16983eb1f1efSPawel Laszczak 	struct usb_request *zlp_request;
16993eb1f1efSPawel Laszczak 	struct cdns2_request *preq;
17003eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
17013eb1f1efSPawel Laszczak 	struct cdns2_device *pdev;
17023eb1f1efSPawel Laszczak 	unsigned long flags;
17033eb1f1efSPawel Laszczak 	int ret;
17043eb1f1efSPawel Laszczak 
17053eb1f1efSPawel Laszczak 	if (!request || !ep)
17063eb1f1efSPawel Laszczak 		return -EINVAL;
17073eb1f1efSPawel Laszczak 
17083eb1f1efSPawel Laszczak 	pep = ep_to_cdns2_ep(ep);
17093eb1f1efSPawel Laszczak 	pdev = pep->pdev;
17103eb1f1efSPawel Laszczak 
17113eb1f1efSPawel Laszczak 	if (!(pep->ep_state & EP_ENABLED)) {
17123eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "%s: can't queue to disabled endpoint\n",
17133eb1f1efSPawel Laszczak 			pep->name);
17143eb1f1efSPawel Laszczak 		return -EINVAL;
17153eb1f1efSPawel Laszczak 	}
17163eb1f1efSPawel Laszczak 
17173eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
17183eb1f1efSPawel Laszczak 
17193eb1f1efSPawel Laszczak 	preq =  to_cdns2_request(request);
17203eb1f1efSPawel Laszczak 	ret = cdns2_ep_enqueue(pep, preq, gfp_flags);
17213eb1f1efSPawel Laszczak 
17223eb1f1efSPawel Laszczak 	if (ret == 0 && request->zero && request->length &&
17233eb1f1efSPawel Laszczak 	    (request->length % ep->maxpacket == 0)) {
17243eb1f1efSPawel Laszczak 		struct cdns2_request *preq;
17253eb1f1efSPawel Laszczak 
17263eb1f1efSPawel Laszczak 		zlp_request = cdns2_gadget_ep_alloc_request(ep, GFP_ATOMIC);
17273eb1f1efSPawel Laszczak 		zlp_request->buf = pdev->zlp_buf;
17283eb1f1efSPawel Laszczak 		zlp_request->length = 0;
17293eb1f1efSPawel Laszczak 
17303eb1f1efSPawel Laszczak 		preq = to_cdns2_request(zlp_request);
17313eb1f1efSPawel Laszczak 		ret = cdns2_ep_enqueue(pep, preq, gfp_flags);
17323eb1f1efSPawel Laszczak 	}
17333eb1f1efSPawel Laszczak 
17343eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
17353eb1f1efSPawel Laszczak 	return ret;
17363eb1f1efSPawel Laszczak }
17373eb1f1efSPawel Laszczak 
cdns2_gadget_ep_dequeue(struct usb_ep * ep,struct usb_request * request)17383eb1f1efSPawel Laszczak int cdns2_gadget_ep_dequeue(struct usb_ep *ep,
17393eb1f1efSPawel Laszczak 			    struct usb_request *request)
17403eb1f1efSPawel Laszczak {
17413eb1f1efSPawel Laszczak 	struct cdns2_request *preq, *preq_temp, *cur_preq;
17423eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
17433eb1f1efSPawel Laszczak 	struct cdns2_trb *link_trb;
17443eb1f1efSPawel Laszczak 	u8 req_on_hw_ring = 0;
17453eb1f1efSPawel Laszczak 	unsigned long flags;
17463eb1f1efSPawel Laszczak 	u32 buffer;
17473eb1f1efSPawel Laszczak 	int val, i;
17483eb1f1efSPawel Laszczak 
17493eb1f1efSPawel Laszczak 	if (!ep || !request || !ep->desc)
17503eb1f1efSPawel Laszczak 		return -EINVAL;
17513eb1f1efSPawel Laszczak 
17523eb1f1efSPawel Laszczak 	pep = ep_to_cdns2_ep(ep);
17533eb1f1efSPawel Laszczak 	if (!pep->endpoint.desc) {
17543eb1f1efSPawel Laszczak 		dev_err(pep->pdev->dev, "%s: can't dequeue to disabled endpoint\n",
17553eb1f1efSPawel Laszczak 			pep->name);
17563eb1f1efSPawel Laszczak 		return -ESHUTDOWN;
17573eb1f1efSPawel Laszczak 	}
17583eb1f1efSPawel Laszczak 
17593eb1f1efSPawel Laszczak 	/* Requests has been dequeued during disabling endpoint. */
17603eb1f1efSPawel Laszczak 	if (!(pep->ep_state & EP_ENABLED))
17613eb1f1efSPawel Laszczak 		return 0;
17623eb1f1efSPawel Laszczak 
17633eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pep->pdev->lock, flags);
17643eb1f1efSPawel Laszczak 
17653eb1f1efSPawel Laszczak 	cur_preq = to_cdns2_request(request);
176607a3aef2SPawel Laszczak 	trace_cdns2_request_dequeue(cur_preq);
17673eb1f1efSPawel Laszczak 
17683eb1f1efSPawel Laszczak 	list_for_each_entry_safe(preq, preq_temp, &pep->pending_list, list) {
17693eb1f1efSPawel Laszczak 		if (cur_preq == preq) {
17703eb1f1efSPawel Laszczak 			req_on_hw_ring = 1;
17713eb1f1efSPawel Laszczak 			goto found;
17723eb1f1efSPawel Laszczak 		}
17733eb1f1efSPawel Laszczak 	}
17743eb1f1efSPawel Laszczak 
17753eb1f1efSPawel Laszczak 	list_for_each_entry_safe(preq, preq_temp, &pep->deferred_list, list) {
17763eb1f1efSPawel Laszczak 		if (cur_preq == preq)
17773eb1f1efSPawel Laszczak 			goto found;
17783eb1f1efSPawel Laszczak 	}
17793eb1f1efSPawel Laszczak 
17803eb1f1efSPawel Laszczak 	goto not_found;
17813eb1f1efSPawel Laszczak 
17823eb1f1efSPawel Laszczak found:
17833eb1f1efSPawel Laszczak 	link_trb = preq->trb;
17843eb1f1efSPawel Laszczak 
17853eb1f1efSPawel Laszczak 	/* Update ring only if removed request is on pending_req_list list. */
17863eb1f1efSPawel Laszczak 	if (req_on_hw_ring && link_trb) {
17873eb1f1efSPawel Laszczak 		/* Stop DMA */
17883eb1f1efSPawel Laszczak 		writel(DMA_EP_CMD_DFLUSH, &pep->pdev->adma_regs->ep_cmd);
17893eb1f1efSPawel Laszczak 
17903eb1f1efSPawel Laszczak 		/* Wait for DFLUSH cleared. */
17913eb1f1efSPawel Laszczak 		readl_poll_timeout_atomic(&pep->pdev->adma_regs->ep_cmd, val,
17923eb1f1efSPawel Laszczak 					  !(val & DMA_EP_CMD_DFLUSH), 1, 1000);
17933eb1f1efSPawel Laszczak 
17943eb1f1efSPawel Laszczak 		buffer = cpu_to_le32(TRB_BUFFER(pep->ring.dma +
17953eb1f1efSPawel Laszczak 				    ((preq->end_trb + 1) * TRB_SIZE)));
17963eb1f1efSPawel Laszczak 
17973eb1f1efSPawel Laszczak 		for (i = 0; i < preq->num_of_trb; i++) {
17983eb1f1efSPawel Laszczak 			link_trb->buffer = buffer;
17993eb1f1efSPawel Laszczak 			link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control)
18003eb1f1efSPawel Laszczak 					    & TRB_CYCLE) | TRB_CHAIN |
18013eb1f1efSPawel Laszczak 					    TRB_TYPE(TRB_LINK));
18023eb1f1efSPawel Laszczak 
180307a3aef2SPawel Laszczak 			trace_cdns2_queue_trb(pep, link_trb);
18043eb1f1efSPawel Laszczak 			link_trb = cdns2_next_trb(pep, link_trb);
18053eb1f1efSPawel Laszczak 		}
18063eb1f1efSPawel Laszczak 
18073eb1f1efSPawel Laszczak 		if (pep->wa1_trb == preq->trb)
18083eb1f1efSPawel Laszczak 			cdns2_wa1_restore_cycle_bit(pep);
18093eb1f1efSPawel Laszczak 	}
18103eb1f1efSPawel Laszczak 
18113eb1f1efSPawel Laszczak 	cdns2_gadget_giveback(pep, cur_preq, -ECONNRESET);
18123eb1f1efSPawel Laszczak 
18133eb1f1efSPawel Laszczak 	preq = cdns2_next_preq(&pep->pending_list);
18143eb1f1efSPawel Laszczak 	if (preq)
18153eb1f1efSPawel Laszczak 		cdns2_rearm_transfer(pep, 1);
18163eb1f1efSPawel Laszczak 
18173eb1f1efSPawel Laszczak not_found:
18183eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pep->pdev->lock, flags);
18193eb1f1efSPawel Laszczak 	return 0;
18203eb1f1efSPawel Laszczak }
18213eb1f1efSPawel Laszczak 
cdns2_halt_endpoint(struct cdns2_device * pdev,struct cdns2_endpoint * pep,int value)18223eb1f1efSPawel Laszczak int cdns2_halt_endpoint(struct cdns2_device *pdev,
18233eb1f1efSPawel Laszczak 			struct cdns2_endpoint *pep,
18243eb1f1efSPawel Laszczak 			int value)
18253eb1f1efSPawel Laszczak {
18263eb1f1efSPawel Laszczak 	u8 __iomem *conf;
18273eb1f1efSPawel Laszczak 	int dir = 0;
18283eb1f1efSPawel Laszczak 
18293eb1f1efSPawel Laszczak 	if (!(pep->ep_state & EP_ENABLED))
18303eb1f1efSPawel Laszczak 		return -EPERM;
18313eb1f1efSPawel Laszczak 
18323eb1f1efSPawel Laszczak 	if (pep->dir) {
18333eb1f1efSPawel Laszczak 		dir = ENDPRST_IO_TX;
18343eb1f1efSPawel Laszczak 		conf = &pdev->epx_regs->ep[pep->num - 1].txcon;
18353eb1f1efSPawel Laszczak 	} else {
18363eb1f1efSPawel Laszczak 		conf = &pdev->epx_regs->ep[pep->num - 1].rxcon;
18373eb1f1efSPawel Laszczak 	}
18383eb1f1efSPawel Laszczak 
18393eb1f1efSPawel Laszczak 	if (!value) {
18403eb1f1efSPawel Laszczak 		struct cdns2_trb *trb = NULL;
18413eb1f1efSPawel Laszczak 		struct cdns2_request *preq;
18423eb1f1efSPawel Laszczak 		struct cdns2_trb trb_tmp;
18433eb1f1efSPawel Laszczak 
18443eb1f1efSPawel Laszczak 		preq = cdns2_next_preq(&pep->pending_list);
18453eb1f1efSPawel Laszczak 		if (preq) {
18463eb1f1efSPawel Laszczak 			trb = preq->trb;
18473eb1f1efSPawel Laszczak 			if (trb) {
18483eb1f1efSPawel Laszczak 				trb_tmp = *trb;
18493eb1f1efSPawel Laszczak 				trb->control = trb->control ^ cpu_to_le32(TRB_CYCLE);
18503eb1f1efSPawel Laszczak 			}
18513eb1f1efSPawel Laszczak 		}
18523eb1f1efSPawel Laszczak 
185307a3aef2SPawel Laszczak 		trace_cdns2_ep_halt(pep, 0, 0);
185407a3aef2SPawel Laszczak 
18553eb1f1efSPawel Laszczak 		/* Resets Sequence Number */
18563eb1f1efSPawel Laszczak 		writeb(dir | pep->num, &pdev->epx_regs->endprst);
18573eb1f1efSPawel Laszczak 		writeb(dir | ENDPRST_TOGRST | pep->num,
18583eb1f1efSPawel Laszczak 		       &pdev->epx_regs->endprst);
18593eb1f1efSPawel Laszczak 
18603eb1f1efSPawel Laszczak 		clear_reg_bit_8(conf, EPX_CON_STALL);
18613eb1f1efSPawel Laszczak 
18623eb1f1efSPawel Laszczak 		pep->ep_state &= ~(EP_STALLED | EP_STALL_PENDING);
18633eb1f1efSPawel Laszczak 
18643eb1f1efSPawel Laszczak 		if (preq) {
18653eb1f1efSPawel Laszczak 			if (trb)
18663eb1f1efSPawel Laszczak 				*trb = trb_tmp;
18673eb1f1efSPawel Laszczak 
18683eb1f1efSPawel Laszczak 			cdns2_rearm_transfer(pep, 1);
18693eb1f1efSPawel Laszczak 		}
18703eb1f1efSPawel Laszczak 
18713eb1f1efSPawel Laszczak 		cdns2_start_all_request(pdev, pep);
18723eb1f1efSPawel Laszczak 	} else {
187307a3aef2SPawel Laszczak 		trace_cdns2_ep_halt(pep, 1, 0);
18743eb1f1efSPawel Laszczak 		set_reg_bit_8(conf, EPX_CON_STALL);
18753eb1f1efSPawel Laszczak 		writeb(dir | pep->num, &pdev->epx_regs->endprst);
18763eb1f1efSPawel Laszczak 		writeb(dir | ENDPRST_FIFORST | pep->num,
18773eb1f1efSPawel Laszczak 		       &pdev->epx_regs->endprst);
18783eb1f1efSPawel Laszczak 		pep->ep_state |= EP_STALLED;
18793eb1f1efSPawel Laszczak 	}
18803eb1f1efSPawel Laszczak 
18813eb1f1efSPawel Laszczak 	return 0;
18823eb1f1efSPawel Laszczak }
18833eb1f1efSPawel Laszczak 
18843eb1f1efSPawel Laszczak /* Sets/clears stall on selected endpoint. */
cdns2_gadget_ep_set_halt(struct usb_ep * ep,int value)18853eb1f1efSPawel Laszczak static int cdns2_gadget_ep_set_halt(struct usb_ep *ep, int value)
18863eb1f1efSPawel Laszczak {
18873eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep = ep_to_cdns2_ep(ep);
18883eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = pep->pdev;
18893eb1f1efSPawel Laszczak 	struct cdns2_request *preq;
18903eb1f1efSPawel Laszczak 	unsigned long flags = 0;
18913eb1f1efSPawel Laszczak 	int ret;
18923eb1f1efSPawel Laszczak 
18933eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
18943eb1f1efSPawel Laszczak 
18953eb1f1efSPawel Laszczak 	preq = cdns2_next_preq(&pep->pending_list);
18963eb1f1efSPawel Laszczak 	if (value && preq) {
189707a3aef2SPawel Laszczak 		trace_cdns2_ep_busy_try_halt_again(pep);
18983eb1f1efSPawel Laszczak 		ret = -EAGAIN;
18993eb1f1efSPawel Laszczak 		goto done;
19003eb1f1efSPawel Laszczak 	}
19013eb1f1efSPawel Laszczak 
19023eb1f1efSPawel Laszczak 	if (!value)
19033eb1f1efSPawel Laszczak 		pep->ep_state &= ~EP_WEDGE;
19043eb1f1efSPawel Laszczak 
19053eb1f1efSPawel Laszczak 	ret = cdns2_halt_endpoint(pdev, pep, value);
19063eb1f1efSPawel Laszczak 
19073eb1f1efSPawel Laszczak done:
19083eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
19093eb1f1efSPawel Laszczak 	return ret;
19103eb1f1efSPawel Laszczak }
19113eb1f1efSPawel Laszczak 
cdns2_gadget_ep_set_wedge(struct usb_ep * ep)19123eb1f1efSPawel Laszczak static int cdns2_gadget_ep_set_wedge(struct usb_ep *ep)
19133eb1f1efSPawel Laszczak {
19143eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep = ep_to_cdns2_ep(ep);
19153eb1f1efSPawel Laszczak 
19163eb1f1efSPawel Laszczak 	cdns2_gadget_ep_set_halt(ep, 1);
19173eb1f1efSPawel Laszczak 	pep->ep_state |= EP_WEDGE;
19183eb1f1efSPawel Laszczak 
19193eb1f1efSPawel Laszczak 	return 0;
19203eb1f1efSPawel Laszczak }
19213eb1f1efSPawel Laszczak 
19223eb1f1efSPawel Laszczak static struct
cdns2_find_available_ep(struct cdns2_device * pdev,struct usb_endpoint_descriptor * desc)19233eb1f1efSPawel Laszczak cdns2_endpoint *cdns2_find_available_ep(struct cdns2_device *pdev,
19243eb1f1efSPawel Laszczak 					struct usb_endpoint_descriptor *desc)
19253eb1f1efSPawel Laszczak {
19263eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
19273eb1f1efSPawel Laszczak 	struct usb_ep *ep;
19283eb1f1efSPawel Laszczak 	int ep_correct;
19293eb1f1efSPawel Laszczak 
19303eb1f1efSPawel Laszczak 	list_for_each_entry(ep, &pdev->gadget.ep_list, ep_list) {
19313eb1f1efSPawel Laszczak 		unsigned long num;
19323eb1f1efSPawel Laszczak 		int ret;
19333eb1f1efSPawel Laszczak 		/* ep name pattern likes epXin or epXout. */
19343eb1f1efSPawel Laszczak 		char c[2] = {ep->name[2], '\0'};
19353eb1f1efSPawel Laszczak 
19363eb1f1efSPawel Laszczak 		ret = kstrtoul(c, 10, &num);
19373eb1f1efSPawel Laszczak 		if (ret)
19383eb1f1efSPawel Laszczak 			return ERR_PTR(ret);
19393eb1f1efSPawel Laszczak 		pep = ep_to_cdns2_ep(ep);
19403eb1f1efSPawel Laszczak 
19413eb1f1efSPawel Laszczak 		if (pep->num != num)
19423eb1f1efSPawel Laszczak 			continue;
19433eb1f1efSPawel Laszczak 
19443eb1f1efSPawel Laszczak 		ep_correct = (pep->endpoint.caps.dir_in &&
19453eb1f1efSPawel Laszczak 			      usb_endpoint_dir_in(desc)) ||
19463eb1f1efSPawel Laszczak 			     (pep->endpoint.caps.dir_out &&
19473eb1f1efSPawel Laszczak 			      usb_endpoint_dir_out(desc));
19483eb1f1efSPawel Laszczak 
19493eb1f1efSPawel Laszczak 		if (ep_correct && !(pep->ep_state & EP_CLAIMED))
19503eb1f1efSPawel Laszczak 			return pep;
19513eb1f1efSPawel Laszczak 	}
19523eb1f1efSPawel Laszczak 
19533eb1f1efSPawel Laszczak 	return ERR_PTR(-ENOENT);
19543eb1f1efSPawel Laszczak }
19553eb1f1efSPawel Laszczak 
19563eb1f1efSPawel Laszczak /*
19573eb1f1efSPawel Laszczak  * Function used to recognize which endpoints will be used to optimize
19583eb1f1efSPawel Laszczak  * on-chip memory usage.
19593eb1f1efSPawel Laszczak  */
19603eb1f1efSPawel Laszczak static struct
cdns2_gadget_match_ep(struct usb_gadget * gadget,struct usb_endpoint_descriptor * desc,struct usb_ss_ep_comp_descriptor * comp_desc)19613eb1f1efSPawel Laszczak usb_ep *cdns2_gadget_match_ep(struct usb_gadget *gadget,
19623eb1f1efSPawel Laszczak 			      struct usb_endpoint_descriptor *desc,
19633eb1f1efSPawel Laszczak 			      struct usb_ss_ep_comp_descriptor *comp_desc)
19643eb1f1efSPawel Laszczak {
19653eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
19663eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
19673eb1f1efSPawel Laszczak 	unsigned long flags;
19683eb1f1efSPawel Laszczak 
19693eb1f1efSPawel Laszczak 	pep = cdns2_find_available_ep(pdev, desc);
19703eb1f1efSPawel Laszczak 	if (IS_ERR(pep)) {
19713eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "no available ep\n");
19723eb1f1efSPawel Laszczak 		return NULL;
19733eb1f1efSPawel Laszczak 	}
19743eb1f1efSPawel Laszczak 
19753eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
19763eb1f1efSPawel Laszczak 
19773eb1f1efSPawel Laszczak 	if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_ISOC)
19783eb1f1efSPawel Laszczak 		pep->buffering = 4;
19793eb1f1efSPawel Laszczak 	else
19803eb1f1efSPawel Laszczak 		pep->buffering = 1;
19813eb1f1efSPawel Laszczak 
19823eb1f1efSPawel Laszczak 	pep->ep_state |= EP_CLAIMED;
19833eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
19843eb1f1efSPawel Laszczak 
19853eb1f1efSPawel Laszczak 	return &pep->endpoint;
19863eb1f1efSPawel Laszczak }
19873eb1f1efSPawel Laszczak 
19883eb1f1efSPawel Laszczak static const struct usb_ep_ops cdns2_gadget_ep_ops = {
19893eb1f1efSPawel Laszczak 	.enable = cdns2_gadget_ep_enable,
19903eb1f1efSPawel Laszczak 	.disable = cdns2_gadget_ep_disable,
19913eb1f1efSPawel Laszczak 	.alloc_request = cdns2_gadget_ep_alloc_request,
19923eb1f1efSPawel Laszczak 	.free_request = cdns2_gadget_ep_free_request,
19933eb1f1efSPawel Laszczak 	.queue = cdns2_gadget_ep_queue,
19943eb1f1efSPawel Laszczak 	.dequeue = cdns2_gadget_ep_dequeue,
19953eb1f1efSPawel Laszczak 	.set_halt = cdns2_gadget_ep_set_halt,
19963eb1f1efSPawel Laszczak 	.set_wedge = cdns2_gadget_ep_set_wedge,
19973eb1f1efSPawel Laszczak };
19983eb1f1efSPawel Laszczak 
cdns2_gadget_get_frame(struct usb_gadget * gadget)19993eb1f1efSPawel Laszczak static int cdns2_gadget_get_frame(struct usb_gadget *gadget)
20003eb1f1efSPawel Laszczak {
20013eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
20023eb1f1efSPawel Laszczak 
20033eb1f1efSPawel Laszczak 	return readw(&pdev->usb_regs->frmnr);
20043eb1f1efSPawel Laszczak }
20053eb1f1efSPawel Laszczak 
cdns2_gadget_wakeup(struct usb_gadget * gadget)20063eb1f1efSPawel Laszczak static int cdns2_gadget_wakeup(struct usb_gadget *gadget)
20073eb1f1efSPawel Laszczak {
20083eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
20093eb1f1efSPawel Laszczak 	unsigned long flags;
20103eb1f1efSPawel Laszczak 
20113eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
20123eb1f1efSPawel Laszczak 	cdns2_wakeup(pdev);
20133eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
20143eb1f1efSPawel Laszczak 
20153eb1f1efSPawel Laszczak 	return 0;
20163eb1f1efSPawel Laszczak }
20173eb1f1efSPawel Laszczak 
cdns2_gadget_set_selfpowered(struct usb_gadget * gadget,int is_selfpowered)20183eb1f1efSPawel Laszczak static int cdns2_gadget_set_selfpowered(struct usb_gadget *gadget,
20193eb1f1efSPawel Laszczak 					int is_selfpowered)
20203eb1f1efSPawel Laszczak {
20213eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
20223eb1f1efSPawel Laszczak 	unsigned long flags;
20233eb1f1efSPawel Laszczak 
20243eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
20253eb1f1efSPawel Laszczak 	pdev->is_selfpowered = !!is_selfpowered;
20263eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
20273eb1f1efSPawel Laszczak 	return 0;
20283eb1f1efSPawel Laszczak }
20293eb1f1efSPawel Laszczak 
20303eb1f1efSPawel Laszczak /*  Disable interrupts and begin the controller halting process. */
cdns2_quiesce(struct cdns2_device * pdev)20313eb1f1efSPawel Laszczak static void cdns2_quiesce(struct cdns2_device *pdev)
20323eb1f1efSPawel Laszczak {
20333eb1f1efSPawel Laszczak 	set_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_DISCON);
20343eb1f1efSPawel Laszczak 
20353eb1f1efSPawel Laszczak 	/* Disable interrupt. */
20363eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->extien),
20373eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->usbien),
20383eb1f1efSPawel Laszczak 	writew(0, &pdev->adma_regs->ep_ien);
20393eb1f1efSPawel Laszczak 
20403eb1f1efSPawel Laszczak 	/* Clear interrupt line. */
20413eb1f1efSPawel Laszczak 	writeb(0x0, &pdev->interrupt_regs->usbirq);
20423eb1f1efSPawel Laszczak }
20433eb1f1efSPawel Laszczak 
cdns2_gadget_config(struct cdns2_device * pdev)20443eb1f1efSPawel Laszczak static void cdns2_gadget_config(struct cdns2_device *pdev)
20453eb1f1efSPawel Laszczak {
20463eb1f1efSPawel Laszczak 	cdns2_ep0_config(pdev);
20473eb1f1efSPawel Laszczak 
20483eb1f1efSPawel Laszczak 	/* Enable DMA interrupts for all endpoints. */
20493eb1f1efSPawel Laszczak 	writel(~0x0, &pdev->adma_regs->ep_ien);
20503eb1f1efSPawel Laszczak 	cdns2_enable_l1(pdev, 0);
20513eb1f1efSPawel Laszczak 	writeb(USB_IEN_INIT, &pdev->interrupt_regs->usbien);
20523eb1f1efSPawel Laszczak 	writeb(EXTIRQ_WAKEUP, &pdev->interrupt_regs->extien);
20533eb1f1efSPawel Laszczak 	writel(DMA_CONF_DMULT, &pdev->adma_regs->conf);
20543eb1f1efSPawel Laszczak }
20553eb1f1efSPawel Laszczak 
cdns2_gadget_pullup(struct usb_gadget * gadget,int is_on)20563eb1f1efSPawel Laszczak static int cdns2_gadget_pullup(struct usb_gadget *gadget, int is_on)
20573eb1f1efSPawel Laszczak {
20583eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
20593eb1f1efSPawel Laszczak 	unsigned long flags;
20603eb1f1efSPawel Laszczak 
206107a3aef2SPawel Laszczak 	trace_cdns2_pullup(is_on);
206207a3aef2SPawel Laszczak 
20633eb1f1efSPawel Laszczak 	/*
20643eb1f1efSPawel Laszczak 	 * Disable events handling while controller is being
20653eb1f1efSPawel Laszczak 	 * enabled/disabled.
20663eb1f1efSPawel Laszczak 	 */
20673eb1f1efSPawel Laszczak 	disable_irq(pdev->irq);
20683eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
20693eb1f1efSPawel Laszczak 
20703eb1f1efSPawel Laszczak 	if (is_on) {
20713eb1f1efSPawel Laszczak 		cdns2_gadget_config(pdev);
20723eb1f1efSPawel Laszczak 		clear_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_DISCON);
20733eb1f1efSPawel Laszczak 	} else {
20743eb1f1efSPawel Laszczak 		cdns2_quiesce(pdev);
20753eb1f1efSPawel Laszczak 	}
20763eb1f1efSPawel Laszczak 
20773eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
20783eb1f1efSPawel Laszczak 	enable_irq(pdev->irq);
20793eb1f1efSPawel Laszczak 
20803eb1f1efSPawel Laszczak 	return 0;
20813eb1f1efSPawel Laszczak }
20823eb1f1efSPawel Laszczak 
cdns2_gadget_udc_start(struct usb_gadget * gadget,struct usb_gadget_driver * driver)20833eb1f1efSPawel Laszczak static int cdns2_gadget_udc_start(struct usb_gadget *gadget,
20843eb1f1efSPawel Laszczak 				  struct usb_gadget_driver *driver)
20853eb1f1efSPawel Laszczak {
20863eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
20873eb1f1efSPawel Laszczak 	enum usb_device_speed max_speed = driver->max_speed;
20883eb1f1efSPawel Laszczak 	unsigned long flags;
20893eb1f1efSPawel Laszczak 
20903eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
20913eb1f1efSPawel Laszczak 	pdev->gadget_driver = driver;
20923eb1f1efSPawel Laszczak 
20933eb1f1efSPawel Laszczak 	/* Limit speed if necessary. */
20943eb1f1efSPawel Laszczak 	max_speed = min(driver->max_speed, gadget->max_speed);
20953eb1f1efSPawel Laszczak 
20963eb1f1efSPawel Laszczak 	switch (max_speed) {
20973eb1f1efSPawel Laszczak 	case USB_SPEED_FULL:
20983eb1f1efSPawel Laszczak 		writeb(SPEEDCTRL_HSDISABLE, &pdev->usb_regs->speedctrl);
20993eb1f1efSPawel Laszczak 		break;
21003eb1f1efSPawel Laszczak 	case USB_SPEED_HIGH:
21013eb1f1efSPawel Laszczak 		writeb(0, &pdev->usb_regs->speedctrl);
21023eb1f1efSPawel Laszczak 		break;
21033eb1f1efSPawel Laszczak 	default:
21043eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "invalid maximum_speed parameter %d\n",
21053eb1f1efSPawel Laszczak 			max_speed);
21063eb1f1efSPawel Laszczak 		fallthrough;
21073eb1f1efSPawel Laszczak 	case USB_SPEED_UNKNOWN:
21083eb1f1efSPawel Laszczak 		/* Default to highspeed. */
21093eb1f1efSPawel Laszczak 		max_speed = USB_SPEED_HIGH;
21103eb1f1efSPawel Laszczak 		break;
21113eb1f1efSPawel Laszczak 	}
21123eb1f1efSPawel Laszczak 
21133eb1f1efSPawel Laszczak 	/* Reset all USB endpoints. */
21143eb1f1efSPawel Laszczak 	writeb(ENDPRST_IO_TX, &pdev->usb_regs->endprst);
21153eb1f1efSPawel Laszczak 	writeb(ENDPRST_FIFORST | ENDPRST_TOGRST | ENDPRST_IO_TX,
21163eb1f1efSPawel Laszczak 	       &pdev->usb_regs->endprst);
21173eb1f1efSPawel Laszczak 	writeb(ENDPRST_FIFORST | ENDPRST_TOGRST, &pdev->usb_regs->endprst);
21183eb1f1efSPawel Laszczak 
21193eb1f1efSPawel Laszczak 	cdns2_eps_onchip_buffer_init(pdev);
21203eb1f1efSPawel Laszczak 
21213eb1f1efSPawel Laszczak 	cdns2_gadget_config(pdev);
21223eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
21233eb1f1efSPawel Laszczak 
21243eb1f1efSPawel Laszczak 	return 0;
21253eb1f1efSPawel Laszczak }
21263eb1f1efSPawel Laszczak 
cdns2_gadget_udc_stop(struct usb_gadget * gadget)21273eb1f1efSPawel Laszczak static int cdns2_gadget_udc_stop(struct usb_gadget *gadget)
21283eb1f1efSPawel Laszczak {
21293eb1f1efSPawel Laszczak 	struct cdns2_device *pdev = gadget_to_cdns2_device(gadget);
21303eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
21313eb1f1efSPawel Laszczak 	u32 bEndpointAddress;
21323eb1f1efSPawel Laszczak 	struct usb_ep *ep;
21333eb1f1efSPawel Laszczak 	int val;
21343eb1f1efSPawel Laszczak 
21353eb1f1efSPawel Laszczak 	pdev->gadget_driver = NULL;
21363eb1f1efSPawel Laszczak 	pdev->gadget.speed = USB_SPEED_UNKNOWN;
21373eb1f1efSPawel Laszczak 
21383eb1f1efSPawel Laszczak 	list_for_each_entry(ep, &pdev->gadget.ep_list, ep_list) {
21393eb1f1efSPawel Laszczak 		pep = ep_to_cdns2_ep(ep);
21403eb1f1efSPawel Laszczak 		bEndpointAddress = pep->num | pep->dir;
21413eb1f1efSPawel Laszczak 		cdns2_select_ep(pdev, bEndpointAddress);
21423eb1f1efSPawel Laszczak 		writel(DMA_EP_CMD_EPRST, &pdev->adma_regs->ep_cmd);
21433eb1f1efSPawel Laszczak 		readl_poll_timeout_atomic(&pdev->adma_regs->ep_cmd, val,
21443eb1f1efSPawel Laszczak 					  !(val & DMA_EP_CMD_EPRST), 1, 100);
21453eb1f1efSPawel Laszczak 	}
21463eb1f1efSPawel Laszczak 
21473eb1f1efSPawel Laszczak 	cdns2_quiesce(pdev);
21483eb1f1efSPawel Laszczak 
21493eb1f1efSPawel Laszczak 	writeb(ENDPRST_IO_TX, &pdev->usb_regs->endprst);
21503eb1f1efSPawel Laszczak 	writeb(ENDPRST_FIFORST | ENDPRST_TOGRST | ENDPRST_IO_TX,
21513eb1f1efSPawel Laszczak 	       &pdev->epx_regs->endprst);
21523eb1f1efSPawel Laszczak 	writeb(ENDPRST_FIFORST | ENDPRST_TOGRST, &pdev->epx_regs->endprst);
21533eb1f1efSPawel Laszczak 
21543eb1f1efSPawel Laszczak 	return 0;
21553eb1f1efSPawel Laszczak }
21563eb1f1efSPawel Laszczak 
21573eb1f1efSPawel Laszczak static const struct usb_gadget_ops cdns2_gadget_ops = {
21583eb1f1efSPawel Laszczak 	.get_frame = cdns2_gadget_get_frame,
21593eb1f1efSPawel Laszczak 	.wakeup = cdns2_gadget_wakeup,
21603eb1f1efSPawel Laszczak 	.set_selfpowered = cdns2_gadget_set_selfpowered,
21613eb1f1efSPawel Laszczak 	.pullup = cdns2_gadget_pullup,
21623eb1f1efSPawel Laszczak 	.udc_start = cdns2_gadget_udc_start,
21633eb1f1efSPawel Laszczak 	.udc_stop = cdns2_gadget_udc_stop,
21643eb1f1efSPawel Laszczak 	.match_ep = cdns2_gadget_match_ep,
21653eb1f1efSPawel Laszczak };
21663eb1f1efSPawel Laszczak 
cdns2_free_all_eps(struct cdns2_device * pdev)21673eb1f1efSPawel Laszczak static void cdns2_free_all_eps(struct cdns2_device *pdev)
21683eb1f1efSPawel Laszczak {
21693eb1f1efSPawel Laszczak 	int i;
21703eb1f1efSPawel Laszczak 
21713eb1f1efSPawel Laszczak 	for (i = 0; i < CDNS2_ENDPOINTS_NUM; i++)
21723eb1f1efSPawel Laszczak 		cdns2_free_tr_segment(&pdev->eps[i]);
21733eb1f1efSPawel Laszczak }
21743eb1f1efSPawel Laszczak 
21753eb1f1efSPawel Laszczak /* Initializes software endpoints of gadget. */
cdns2_init_eps(struct cdns2_device * pdev)21763eb1f1efSPawel Laszczak static int cdns2_init_eps(struct cdns2_device *pdev)
21773eb1f1efSPawel Laszczak {
21783eb1f1efSPawel Laszczak 	struct cdns2_endpoint *pep;
21793eb1f1efSPawel Laszczak 	int i;
21803eb1f1efSPawel Laszczak 
21813eb1f1efSPawel Laszczak 	for (i = 0; i < CDNS2_ENDPOINTS_NUM; i++) {
21823eb1f1efSPawel Laszczak 		bool direction = !(i & 1); /* Start from OUT endpoint. */
21833eb1f1efSPawel Laszczak 		u8 epnum = ((i + 1) >> 1);
21843eb1f1efSPawel Laszczak 
21853eb1f1efSPawel Laszczak 		/*
21863eb1f1efSPawel Laszczak 		 * Endpoints are being held in pdev->eps[] in form:
21873eb1f1efSPawel Laszczak 		 * ep0, ep1out, ep1in ... ep15out, ep15in.
21883eb1f1efSPawel Laszczak 		 */
21893eb1f1efSPawel Laszczak 		if (!CDNS2_IF_EP_EXIST(pdev, epnum, direction))
21903eb1f1efSPawel Laszczak 			continue;
21913eb1f1efSPawel Laszczak 
21923eb1f1efSPawel Laszczak 		pep = &pdev->eps[i];
21933eb1f1efSPawel Laszczak 		pep->pdev = pdev;
21943eb1f1efSPawel Laszczak 		pep->num = epnum;
21953eb1f1efSPawel Laszczak 		/* 0 for OUT, 1 for IN. */
21963eb1f1efSPawel Laszczak 		pep->dir = direction ? USB_DIR_IN : USB_DIR_OUT;
21973eb1f1efSPawel Laszczak 		pep->idx = i;
21983eb1f1efSPawel Laszczak 
21993eb1f1efSPawel Laszczak 		/* Ep0in and ep0out are represented by pdev->eps[0]. */
22003eb1f1efSPawel Laszczak 		if (!epnum) {
22013eb1f1efSPawel Laszczak 			int ret;
22023eb1f1efSPawel Laszczak 
22033eb1f1efSPawel Laszczak 			snprintf(pep->name, sizeof(pep->name), "ep%d%s",
22043eb1f1efSPawel Laszczak 				 epnum, "BiDir");
22053eb1f1efSPawel Laszczak 
22063eb1f1efSPawel Laszczak 			cdns2_init_ep0(pdev, pep);
22073eb1f1efSPawel Laszczak 
22083eb1f1efSPawel Laszczak 			ret = cdns2_alloc_tr_segment(pep);
22093eb1f1efSPawel Laszczak 			if (ret) {
22103eb1f1efSPawel Laszczak 				dev_err(pdev->dev, "Failed to init ep0\n");
22113eb1f1efSPawel Laszczak 				return ret;
22123eb1f1efSPawel Laszczak 			}
22133eb1f1efSPawel Laszczak 		} else {
22143eb1f1efSPawel Laszczak 			snprintf(pep->name, sizeof(pep->name), "ep%d%s",
22153eb1f1efSPawel Laszczak 				 epnum, !!direction ? "in" : "out");
22163eb1f1efSPawel Laszczak 			pep->endpoint.name = pep->name;
22173eb1f1efSPawel Laszczak 
22183eb1f1efSPawel Laszczak 			usb_ep_set_maxpacket_limit(&pep->endpoint, 1024);
22193eb1f1efSPawel Laszczak 			pep->endpoint.ops = &cdns2_gadget_ep_ops;
22203eb1f1efSPawel Laszczak 			list_add_tail(&pep->endpoint.ep_list, &pdev->gadget.ep_list);
22213eb1f1efSPawel Laszczak 
22223eb1f1efSPawel Laszczak 			pep->endpoint.caps.dir_in = direction;
22233eb1f1efSPawel Laszczak 			pep->endpoint.caps.dir_out = !direction;
22243eb1f1efSPawel Laszczak 
22253eb1f1efSPawel Laszczak 			pep->endpoint.caps.type_iso = 1;
22263eb1f1efSPawel Laszczak 			pep->endpoint.caps.type_bulk = 1;
22273eb1f1efSPawel Laszczak 			pep->endpoint.caps.type_int = 1;
22283eb1f1efSPawel Laszczak 		}
22293eb1f1efSPawel Laszczak 
22303eb1f1efSPawel Laszczak 		pep->endpoint.name = pep->name;
22313eb1f1efSPawel Laszczak 		pep->ep_state = 0;
22323eb1f1efSPawel Laszczak 
22333eb1f1efSPawel Laszczak 		dev_dbg(pdev->dev, "Init %s, SupType: CTRL: %s, INT: %s, "
22343eb1f1efSPawel Laszczak 			"BULK: %s, ISOC %s, SupDir IN: %s, OUT: %s\n",
22353eb1f1efSPawel Laszczak 			pep->name,
22363eb1f1efSPawel Laszczak 			(pep->endpoint.caps.type_control) ? "yes" : "no",
22373eb1f1efSPawel Laszczak 			(pep->endpoint.caps.type_int) ? "yes" : "no",
22383eb1f1efSPawel Laszczak 			(pep->endpoint.caps.type_bulk) ? "yes" : "no",
22393eb1f1efSPawel Laszczak 			(pep->endpoint.caps.type_iso) ? "yes" : "no",
22403eb1f1efSPawel Laszczak 			(pep->endpoint.caps.dir_in) ? "yes" : "no",
22413eb1f1efSPawel Laszczak 			(pep->endpoint.caps.dir_out) ? "yes" : "no");
22423eb1f1efSPawel Laszczak 
22433eb1f1efSPawel Laszczak 		INIT_LIST_HEAD(&pep->pending_list);
22443eb1f1efSPawel Laszczak 		INIT_LIST_HEAD(&pep->deferred_list);
22453eb1f1efSPawel Laszczak 	}
22463eb1f1efSPawel Laszczak 
22473eb1f1efSPawel Laszczak 	return 0;
22483eb1f1efSPawel Laszczak }
22493eb1f1efSPawel Laszczak 
cdns2_gadget_start(struct cdns2_device * pdev)22503eb1f1efSPawel Laszczak static int cdns2_gadget_start(struct cdns2_device *pdev)
22513eb1f1efSPawel Laszczak {
22523eb1f1efSPawel Laszczak 	u32 max_speed;
22533eb1f1efSPawel Laszczak 	void *buf;
22543eb1f1efSPawel Laszczak 	int ret;
22553eb1f1efSPawel Laszczak 
22563eb1f1efSPawel Laszczak 	pdev->usb_regs = pdev->regs;
22573eb1f1efSPawel Laszczak 	pdev->ep0_regs = pdev->regs;
22583eb1f1efSPawel Laszczak 	pdev->epx_regs = pdev->regs;
22593eb1f1efSPawel Laszczak 	pdev->interrupt_regs = pdev->regs;
22603eb1f1efSPawel Laszczak 	pdev->adma_regs = pdev->regs + CDNS2_ADMA_REGS_OFFSET;
22613eb1f1efSPawel Laszczak 
22623eb1f1efSPawel Laszczak 	/* Reset controller. */
2263*f224f372SPawel Laszczak 	writeb(CPUCTRL_SW_RST | CPUCTRL_UPCLK | CPUCTRL_WUEN,
2264*f224f372SPawel Laszczak 	       &pdev->usb_regs->cpuctrl);
2265*f224f372SPawel Laszczak 	usleep_range(5, 10);
22663eb1f1efSPawel Laszczak 
22673eb1f1efSPawel Laszczak 	usb_initialize_gadget(pdev->dev, &pdev->gadget, NULL);
22683eb1f1efSPawel Laszczak 
22693eb1f1efSPawel Laszczak 	device_property_read_u16(pdev->dev, "cdns,on-chip-tx-buff-size",
22703eb1f1efSPawel Laszczak 				 &pdev->onchip_tx_buf);
22713eb1f1efSPawel Laszczak 	device_property_read_u16(pdev->dev, "cdns,on-chip-rx-buff-size",
22723eb1f1efSPawel Laszczak 				 &pdev->onchip_rx_buf);
22733eb1f1efSPawel Laszczak 	device_property_read_u32(pdev->dev, "cdns,avail-endpoints",
22743eb1f1efSPawel Laszczak 				 &pdev->eps_supported);
22753eb1f1efSPawel Laszczak 
22763eb1f1efSPawel Laszczak 	/*
22773eb1f1efSPawel Laszczak 	 * Driver assumes that each USBHS controller has at least
22783eb1f1efSPawel Laszczak 	 * one IN and one OUT non control endpoint.
22793eb1f1efSPawel Laszczak 	 */
22803eb1f1efSPawel Laszczak 	if (!pdev->onchip_tx_buf && !pdev->onchip_rx_buf) {
22813eb1f1efSPawel Laszczak 		ret = -EINVAL;
22823eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "Invalid on-chip memory configuration\n");
22833eb1f1efSPawel Laszczak 		goto put_gadget;
22843eb1f1efSPawel Laszczak 	}
22853eb1f1efSPawel Laszczak 
22863eb1f1efSPawel Laszczak 	if (!(pdev->eps_supported & ~0x00010001)) {
22873eb1f1efSPawel Laszczak 		ret = -EINVAL;
22883eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "No hardware endpoints available\n");
22893eb1f1efSPawel Laszczak 		goto put_gadget;
22903eb1f1efSPawel Laszczak 	}
22913eb1f1efSPawel Laszczak 
22923eb1f1efSPawel Laszczak 	max_speed = usb_get_maximum_speed(pdev->dev);
22933eb1f1efSPawel Laszczak 
22943eb1f1efSPawel Laszczak 	switch (max_speed) {
22953eb1f1efSPawel Laszczak 	case USB_SPEED_FULL:
22963eb1f1efSPawel Laszczak 	case USB_SPEED_HIGH:
22973eb1f1efSPawel Laszczak 		break;
22983eb1f1efSPawel Laszczak 	default:
22993eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "invalid maximum_speed parameter %d\n",
23003eb1f1efSPawel Laszczak 			max_speed);
23013eb1f1efSPawel Laszczak 		fallthrough;
23023eb1f1efSPawel Laszczak 	case USB_SPEED_UNKNOWN:
23033eb1f1efSPawel Laszczak 		max_speed = USB_SPEED_HIGH;
23043eb1f1efSPawel Laszczak 		break;
23053eb1f1efSPawel Laszczak 	}
23063eb1f1efSPawel Laszczak 
23073eb1f1efSPawel Laszczak 	pdev->gadget.max_speed = max_speed;
23083eb1f1efSPawel Laszczak 	pdev->gadget.speed = USB_SPEED_UNKNOWN;
23093eb1f1efSPawel Laszczak 	pdev->gadget.ops = &cdns2_gadget_ops;
23103eb1f1efSPawel Laszczak 	pdev->gadget.name = "usbhs-gadget";
23113eb1f1efSPawel Laszczak 	pdev->gadget.quirk_avoids_skb_reserve = 1;
23123eb1f1efSPawel Laszczak 	pdev->gadget.irq = pdev->irq;
23133eb1f1efSPawel Laszczak 
23143eb1f1efSPawel Laszczak 	spin_lock_init(&pdev->lock);
23153eb1f1efSPawel Laszczak 	INIT_WORK(&pdev->pending_status_wq, cdns2_pending_setup_status_handler);
23163eb1f1efSPawel Laszczak 
23173eb1f1efSPawel Laszczak 	/* Initialize endpoint container. */
23183eb1f1efSPawel Laszczak 	INIT_LIST_HEAD(&pdev->gadget.ep_list);
23193eb1f1efSPawel Laszczak 	pdev->eps_dma_pool = dma_pool_create("cdns2_eps_dma_pool", pdev->dev,
23203eb1f1efSPawel Laszczak 					     TR_SEG_SIZE, 8, 0);
23213eb1f1efSPawel Laszczak 	if (!pdev->eps_dma_pool) {
23223eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "Failed to create TRB dma pool\n");
23233eb1f1efSPawel Laszczak 		ret = -ENOMEM;
23243eb1f1efSPawel Laszczak 		goto put_gadget;
23253eb1f1efSPawel Laszczak 	}
23263eb1f1efSPawel Laszczak 
23273eb1f1efSPawel Laszczak 	ret = cdns2_init_eps(pdev);
23283eb1f1efSPawel Laszczak 	if (ret) {
23293eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "Failed to create endpoints\n");
23303eb1f1efSPawel Laszczak 		goto destroy_dma_pool;
23313eb1f1efSPawel Laszczak 	}
23323eb1f1efSPawel Laszczak 
23333eb1f1efSPawel Laszczak 	pdev->gadget.sg_supported = 1;
23343eb1f1efSPawel Laszczak 
23353eb1f1efSPawel Laszczak 	pdev->zlp_buf = kzalloc(CDNS2_EP_ZLP_BUF_SIZE, GFP_KERNEL);
23363eb1f1efSPawel Laszczak 	if (!pdev->zlp_buf) {
23373eb1f1efSPawel Laszczak 		ret = -ENOMEM;
23383eb1f1efSPawel Laszczak 		goto destroy_dma_pool;
23393eb1f1efSPawel Laszczak 	}
23403eb1f1efSPawel Laszczak 
23413eb1f1efSPawel Laszczak 	/* Allocate memory for setup packet buffer. */
23423eb1f1efSPawel Laszczak 	buf = dma_alloc_coherent(pdev->dev, 8, &pdev->ep0_preq.request.dma,
23433eb1f1efSPawel Laszczak 				 GFP_DMA);
23443eb1f1efSPawel Laszczak 	pdev->ep0_preq.request.buf = buf;
23453eb1f1efSPawel Laszczak 
23463eb1f1efSPawel Laszczak 	if (!pdev->ep0_preq.request.buf) {
23473eb1f1efSPawel Laszczak 		ret = -ENOMEM;
23483eb1f1efSPawel Laszczak 		goto free_zlp_buf;
23493eb1f1efSPawel Laszczak 	}
23503eb1f1efSPawel Laszczak 
23513eb1f1efSPawel Laszczak 	/* Add USB gadget device. */
23523eb1f1efSPawel Laszczak 	ret = usb_add_gadget(&pdev->gadget);
23533eb1f1efSPawel Laszczak 	if (ret < 0) {
23543eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "Failed to add gadget\n");
23553eb1f1efSPawel Laszczak 		goto free_ep0_buf;
23563eb1f1efSPawel Laszczak 	}
23573eb1f1efSPawel Laszczak 
23583eb1f1efSPawel Laszczak 	return 0;
23593eb1f1efSPawel Laszczak 
23603eb1f1efSPawel Laszczak free_ep0_buf:
23613eb1f1efSPawel Laszczak 	dma_free_coherent(pdev->dev, 8, pdev->ep0_preq.request.buf,
23623eb1f1efSPawel Laszczak 			  pdev->ep0_preq.request.dma);
23633eb1f1efSPawel Laszczak free_zlp_buf:
23643eb1f1efSPawel Laszczak 	kfree(pdev->zlp_buf);
23653eb1f1efSPawel Laszczak destroy_dma_pool:
23663eb1f1efSPawel Laszczak 	dma_pool_destroy(pdev->eps_dma_pool);
23673eb1f1efSPawel Laszczak put_gadget:
23683eb1f1efSPawel Laszczak 	usb_put_gadget(&pdev->gadget);
23693eb1f1efSPawel Laszczak 
23703eb1f1efSPawel Laszczak 	return ret;
23713eb1f1efSPawel Laszczak }
23723eb1f1efSPawel Laszczak 
cdns2_gadget_suspend(struct cdns2_device * pdev)23733eb1f1efSPawel Laszczak int cdns2_gadget_suspend(struct cdns2_device *pdev)
23743eb1f1efSPawel Laszczak {
23753eb1f1efSPawel Laszczak 	unsigned long flags;
23763eb1f1efSPawel Laszczak 
23773eb1f1efSPawel Laszczak 	cdns2_disconnect_gadget(pdev);
23783eb1f1efSPawel Laszczak 
23793eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
23803eb1f1efSPawel Laszczak 	pdev->gadget.speed = USB_SPEED_UNKNOWN;
23813eb1f1efSPawel Laszczak 
238207a3aef2SPawel Laszczak 	trace_cdns2_device_state("notattached");
23833eb1f1efSPawel Laszczak 	usb_gadget_set_state(&pdev->gadget, USB_STATE_NOTATTACHED);
23843eb1f1efSPawel Laszczak 	cdns2_enable_l1(pdev, 0);
23853eb1f1efSPawel Laszczak 
23863eb1f1efSPawel Laszczak 	/* Disable interrupt for device. */
23873eb1f1efSPawel Laszczak 	writeb(0, &pdev->interrupt_regs->usbien);
23883eb1f1efSPawel Laszczak 	writel(0, &pdev->adma_regs->ep_ien);
23893eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
23903eb1f1efSPawel Laszczak 
23913eb1f1efSPawel Laszczak 	return 0;
23923eb1f1efSPawel Laszczak }
23933eb1f1efSPawel Laszczak 
cdns2_gadget_resume(struct cdns2_device * pdev,bool hibernated)23943eb1f1efSPawel Laszczak int cdns2_gadget_resume(struct cdns2_device *pdev, bool hibernated)
23953eb1f1efSPawel Laszczak {
23963eb1f1efSPawel Laszczak 	unsigned long flags;
23973eb1f1efSPawel Laszczak 
23983eb1f1efSPawel Laszczak 	spin_lock_irqsave(&pdev->lock, flags);
23993eb1f1efSPawel Laszczak 
24003eb1f1efSPawel Laszczak 	if (!pdev->gadget_driver) {
24013eb1f1efSPawel Laszczak 		spin_unlock_irqrestore(&pdev->lock, flags);
24023eb1f1efSPawel Laszczak 		return 0;
24033eb1f1efSPawel Laszczak 	}
24043eb1f1efSPawel Laszczak 
24053eb1f1efSPawel Laszczak 	cdns2_gadget_config(pdev);
24063eb1f1efSPawel Laszczak 
24073eb1f1efSPawel Laszczak 	if (hibernated)
24083eb1f1efSPawel Laszczak 		clear_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_DISCON);
24093eb1f1efSPawel Laszczak 
24103eb1f1efSPawel Laszczak 	spin_unlock_irqrestore(&pdev->lock, flags);
24113eb1f1efSPawel Laszczak 
24123eb1f1efSPawel Laszczak 	return 0;
24133eb1f1efSPawel Laszczak }
24143eb1f1efSPawel Laszczak 
cdns2_gadget_remove(struct cdns2_device * pdev)24153eb1f1efSPawel Laszczak void cdns2_gadget_remove(struct cdns2_device *pdev)
24163eb1f1efSPawel Laszczak {
24173eb1f1efSPawel Laszczak 	pm_runtime_mark_last_busy(pdev->dev);
24183eb1f1efSPawel Laszczak 	pm_runtime_put_autosuspend(pdev->dev);
24193eb1f1efSPawel Laszczak 
24203eb1f1efSPawel Laszczak 	usb_del_gadget(&pdev->gadget);
24213eb1f1efSPawel Laszczak 	cdns2_free_all_eps(pdev);
24223eb1f1efSPawel Laszczak 
24233eb1f1efSPawel Laszczak 	dma_pool_destroy(pdev->eps_dma_pool);
24243eb1f1efSPawel Laszczak 	kfree(pdev->zlp_buf);
24253eb1f1efSPawel Laszczak 	usb_put_gadget(&pdev->gadget);
24263eb1f1efSPawel Laszczak }
24273eb1f1efSPawel Laszczak 
cdns2_gadget_init(struct cdns2_device * pdev)24283eb1f1efSPawel Laszczak int cdns2_gadget_init(struct cdns2_device *pdev)
24293eb1f1efSPawel Laszczak {
24303eb1f1efSPawel Laszczak 	int ret;
24313eb1f1efSPawel Laszczak 
24323eb1f1efSPawel Laszczak 	/* Ensure 32-bit DMA Mask. */
24333eb1f1efSPawel Laszczak 	ret = dma_set_mask_and_coherent(pdev->dev, DMA_BIT_MASK(32));
24343eb1f1efSPawel Laszczak 	if (ret) {
24353eb1f1efSPawel Laszczak 		dev_err(pdev->dev, "Failed to set dma mask: %d\n", ret);
24363eb1f1efSPawel Laszczak 		return ret;
24373eb1f1efSPawel Laszczak 	}
24383eb1f1efSPawel Laszczak 
24393eb1f1efSPawel Laszczak 	pm_runtime_get_sync(pdev->dev);
24403eb1f1efSPawel Laszczak 
24413eb1f1efSPawel Laszczak 	cdsn2_isoc_burst_opt(pdev);
24423eb1f1efSPawel Laszczak 
24433eb1f1efSPawel Laszczak 	ret = cdns2_gadget_start(pdev);
24443eb1f1efSPawel Laszczak 	if (ret) {
24453eb1f1efSPawel Laszczak 		pm_runtime_put_sync(pdev->dev);
24463eb1f1efSPawel Laszczak 		return ret;
24473eb1f1efSPawel Laszczak 	}
24483eb1f1efSPawel Laszczak 
24493eb1f1efSPawel Laszczak 	/*
24503eb1f1efSPawel Laszczak 	 * Because interrupt line can be shared with other components in
24513eb1f1efSPawel Laszczak 	 * driver it can't use IRQF_ONESHOT flag here.
24523eb1f1efSPawel Laszczak 	 */
24533eb1f1efSPawel Laszczak 	ret = devm_request_threaded_irq(pdev->dev, pdev->irq,
24543eb1f1efSPawel Laszczak 					cdns2_usb_irq_handler,
24553eb1f1efSPawel Laszczak 					cdns2_thread_irq_handler,
24563eb1f1efSPawel Laszczak 					IRQF_SHARED,
24573eb1f1efSPawel Laszczak 					dev_name(pdev->dev),
24583eb1f1efSPawel Laszczak 					pdev);
24593eb1f1efSPawel Laszczak 	if (ret)
24603eb1f1efSPawel Laszczak 		goto err0;
24613eb1f1efSPawel Laszczak 
24623eb1f1efSPawel Laszczak 	return 0;
24633eb1f1efSPawel Laszczak 
24643eb1f1efSPawel Laszczak err0:
24653eb1f1efSPawel Laszczak 	cdns2_gadget_remove(pdev);
24663eb1f1efSPawel Laszczak 
24673eb1f1efSPawel Laszczak 	return ret;
24683eb1f1efSPawel Laszczak }
2469