xref: /rk3399_rockchip-uboot/drivers/usb/cdns3/ep0.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
1f6ce6072SVignesh Raghavendra // SPDX-License-Identifier: GPL-2.0
2f6ce6072SVignesh Raghavendra /*
3f6ce6072SVignesh Raghavendra  * Cadence USBSS DRD Driver - gadget side.
4f6ce6072SVignesh Raghavendra  *
5f6ce6072SVignesh Raghavendra  * Copyright (C) 2018 Cadence Design Systems.
6f6ce6072SVignesh Raghavendra  * Copyright (C) 2017-2018 NXP
7f6ce6072SVignesh Raghavendra  *
8f6ce6072SVignesh Raghavendra  * Authors: Pawel Jez <pjez@cadence.com>,
9f6ce6072SVignesh Raghavendra  *          Pawel Laszczak <pawell@cadence.com>
10f6ce6072SVignesh Raghavendra  *          Peter Chen <peter.chen@nxp.com>
11f6ce6072SVignesh Raghavendra  */
12f6ce6072SVignesh Raghavendra 
13*6a2b8f48SVignesh Raghavendra #include <cpu_func.h>
14f6ce6072SVignesh Raghavendra #include <linux/usb/composite.h>
15f6ce6072SVignesh Raghavendra #include <linux/iopoll.h>
16f6ce6072SVignesh Raghavendra 
17f6ce6072SVignesh Raghavendra #include "gadget.h"
18f6ce6072SVignesh Raghavendra #include "trace.h"
19f6ce6072SVignesh Raghavendra 
20f6ce6072SVignesh Raghavendra #define readl_poll_timeout_atomic readl_poll_timeout
21f6ce6072SVignesh Raghavendra #define usleep_range(a, b) udelay((b))
22f6ce6072SVignesh Raghavendra 
23f6ce6072SVignesh Raghavendra static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = {
24f6ce6072SVignesh Raghavendra 	.bLength = USB_DT_ENDPOINT_SIZE,
25f6ce6072SVignesh Raghavendra 	.bDescriptorType = USB_DT_ENDPOINT,
26f6ce6072SVignesh Raghavendra 	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
27f6ce6072SVignesh Raghavendra };
28f6ce6072SVignesh Raghavendra 
29f6ce6072SVignesh Raghavendra /**
30f6ce6072SVignesh Raghavendra  * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware
31f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
32f6ce6072SVignesh Raghavendra  * @dma_addr: physical address where data is/will be stored
33f6ce6072SVignesh Raghavendra  * @length: data length
34f6ce6072SVignesh Raghavendra  * @erdy: set it to 1 when ERDY packet should be sent -
35f6ce6072SVignesh Raghavendra  *        exit from flow control state
36f6ce6072SVignesh Raghavendra  */
cdns3_ep0_run_transfer(struct cdns3_device * priv_dev,dma_addr_t dma_addr,unsigned int length,int erdy,int zlp)37f6ce6072SVignesh Raghavendra static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev,
38f6ce6072SVignesh Raghavendra 				   dma_addr_t dma_addr,
39f6ce6072SVignesh Raghavendra 				   unsigned int length, int erdy, int zlp)
40f6ce6072SVignesh Raghavendra {
41f6ce6072SVignesh Raghavendra 	struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
42f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
43f6ce6072SVignesh Raghavendra 
44f6ce6072SVignesh Raghavendra 	priv_ep->trb_pool[0].buffer = TRB_BUFFER(dma_addr);
45f6ce6072SVignesh Raghavendra 	priv_ep->trb_pool[0].length = TRB_LEN(length);
46f6ce6072SVignesh Raghavendra 
47f6ce6072SVignesh Raghavendra 	if (zlp) {
48f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_TYPE(TRB_NORMAL);
49f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[1].buffer = TRB_BUFFER(dma_addr);
50f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[1].length = TRB_LEN(0);
51f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[1].control = TRB_CYCLE | TRB_IOC |
52f6ce6072SVignesh Raghavendra 		    TRB_TYPE(TRB_NORMAL);
53f6ce6072SVignesh Raghavendra 	} else {
54f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_IOC |
55f6ce6072SVignesh Raghavendra 		    TRB_TYPE(TRB_NORMAL);
56f6ce6072SVignesh Raghavendra 		priv_ep->trb_pool[1].control = 0;
57f6ce6072SVignesh Raghavendra 	}
58f6ce6072SVignesh Raghavendra 
59f6ce6072SVignesh Raghavendra 	/* Flush both TRBs */
60f6ce6072SVignesh Raghavendra 	flush_dcache_range((unsigned long)priv_ep->trb_pool,
61f6ce6072SVignesh Raghavendra 			   (unsigned long)priv_ep->trb_pool +
62f6ce6072SVignesh Raghavendra 			   ROUND(sizeof(struct cdns3_trb) * 2,
63f6ce6072SVignesh Raghavendra 				 CONFIG_SYS_CACHELINE_SIZE));
64f6ce6072SVignesh Raghavendra 
65f6ce6072SVignesh Raghavendra 	trace_cdns3_prepare_trb(priv_ep, priv_ep->trb_pool);
66f6ce6072SVignesh Raghavendra 
67f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, priv_dev->ep0_data_dir);
68f6ce6072SVignesh Raghavendra 
69f6ce6072SVignesh Raghavendra 	writel(EP_STS_TRBERR, &regs->ep_sts);
70f6ce6072SVignesh Raghavendra 	writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma), &regs->ep_traddr);
71f6ce6072SVignesh Raghavendra 	trace_cdns3_doorbell_ep0(priv_dev->ep0_data_dir ? "ep0in" : "ep0out",
72f6ce6072SVignesh Raghavendra 				 readl(&regs->ep_traddr));
73f6ce6072SVignesh Raghavendra 
74f6ce6072SVignesh Raghavendra 	/* TRB should be prepared before starting transfer. */
75f6ce6072SVignesh Raghavendra 	writel(EP_CMD_DRDY, &regs->ep_cmd);
76f6ce6072SVignesh Raghavendra 
77f6ce6072SVignesh Raghavendra 	/* Resume controller before arming transfer. */
78f6ce6072SVignesh Raghavendra 	__cdns3_gadget_wakeup(priv_dev);
79f6ce6072SVignesh Raghavendra 
80f6ce6072SVignesh Raghavendra 	if (erdy)
81f6ce6072SVignesh Raghavendra 		writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd);
82f6ce6072SVignesh Raghavendra }
83f6ce6072SVignesh Raghavendra 
84f6ce6072SVignesh Raghavendra /**
85f6ce6072SVignesh Raghavendra  * cdns3_ep0_delegate_req - Returns status of handling setup packet
86f6ce6072SVignesh Raghavendra  * Setup is handled by gadget driver
87f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
88f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
89f6ce6072SVignesh Raghavendra  *
90f6ce6072SVignesh Raghavendra  * Returns zero on success or negative value on failure
91f6ce6072SVignesh Raghavendra  */
cdns3_ep0_delegate_req(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)92f6ce6072SVignesh Raghavendra static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev,
93f6ce6072SVignesh Raghavendra 				  struct usb_ctrlrequest *ctrl_req)
94f6ce6072SVignesh Raghavendra {
95f6ce6072SVignesh Raghavendra 	int ret;
96f6ce6072SVignesh Raghavendra 
97f6ce6072SVignesh Raghavendra 	spin_unlock(&priv_dev->lock);
98f6ce6072SVignesh Raghavendra 	priv_dev->setup_pending = 1;
99f6ce6072SVignesh Raghavendra 	ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req);
100f6ce6072SVignesh Raghavendra 	priv_dev->setup_pending = 0;
101f6ce6072SVignesh Raghavendra 	spin_lock(&priv_dev->lock);
102f6ce6072SVignesh Raghavendra 	return ret;
103f6ce6072SVignesh Raghavendra }
104f6ce6072SVignesh Raghavendra 
cdns3_prepare_setup_packet(struct cdns3_device * priv_dev)105f6ce6072SVignesh Raghavendra static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev)
106f6ce6072SVignesh Raghavendra {
107f6ce6072SVignesh Raghavendra 	priv_dev->ep0_data_dir = 0;
108f6ce6072SVignesh Raghavendra 	priv_dev->ep0_stage = CDNS3_SETUP_STAGE;
109f6ce6072SVignesh Raghavendra 	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
110f6ce6072SVignesh Raghavendra 			       sizeof(struct usb_ctrlrequest), 0, 0);
111f6ce6072SVignesh Raghavendra }
112f6ce6072SVignesh Raghavendra 
cdns3_ep0_complete_setup(struct cdns3_device * priv_dev,u8 send_stall,u8 send_erdy)113f6ce6072SVignesh Raghavendra static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev,
114f6ce6072SVignesh Raghavendra 				     u8 send_stall, u8 send_erdy)
115f6ce6072SVignesh Raghavendra {
116f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
117f6ce6072SVignesh Raghavendra 	struct usb_request *request;
118f6ce6072SVignesh Raghavendra 
119f6ce6072SVignesh Raghavendra 	request = cdns3_next_request(&priv_ep->pending_req_list);
120f6ce6072SVignesh Raghavendra 	if (request)
121f6ce6072SVignesh Raghavendra 		list_del_init(&request->list);
122f6ce6072SVignesh Raghavendra 
123f6ce6072SVignesh Raghavendra 	if (send_stall) {
124f6ce6072SVignesh Raghavendra 		trace_cdns3_halt(priv_ep, send_stall, 0);
125f6ce6072SVignesh Raghavendra 		/* set_stall on ep0 */
126f6ce6072SVignesh Raghavendra 		cdns3_select_ep(priv_dev, 0x00);
127f6ce6072SVignesh Raghavendra 		writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd);
128f6ce6072SVignesh Raghavendra 	} else {
129f6ce6072SVignesh Raghavendra 		cdns3_prepare_setup_packet(priv_dev);
130f6ce6072SVignesh Raghavendra 	}
131f6ce6072SVignesh Raghavendra 
132f6ce6072SVignesh Raghavendra 	priv_dev->ep0_stage = CDNS3_SETUP_STAGE;
133f6ce6072SVignesh Raghavendra 	writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL,
134f6ce6072SVignesh Raghavendra 	       &priv_dev->regs->ep_cmd);
135f6ce6072SVignesh Raghavendra 
136f6ce6072SVignesh Raghavendra 	cdns3_allow_enable_l1(priv_dev, 1);
137f6ce6072SVignesh Raghavendra }
138f6ce6072SVignesh Raghavendra 
139f6ce6072SVignesh Raghavendra /**
140f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request
141f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
142f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
143f6ce6072SVignesh Raghavendra  *
144f6ce6072SVignesh Raghavendra  * Returns 0 if success, USB_GADGET_DELAYED_STATUS on deferred status stage,
145f6ce6072SVignesh Raghavendra  * error code on error
146f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_set_configuration(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)147f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev,
148f6ce6072SVignesh Raghavendra 					   struct usb_ctrlrequest *ctrl_req)
149f6ce6072SVignesh Raghavendra {
150f6ce6072SVignesh Raghavendra 	enum usb_device_state device_state = priv_dev->gadget.state;
151f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep;
152f6ce6072SVignesh Raghavendra 	u32 config = le16_to_cpu(ctrl_req->wValue);
153f6ce6072SVignesh Raghavendra 	int result = 0;
154f6ce6072SVignesh Raghavendra 	int i;
155f6ce6072SVignesh Raghavendra 
156f6ce6072SVignesh Raghavendra 	switch (device_state) {
157f6ce6072SVignesh Raghavendra 	case USB_STATE_ADDRESS:
158f6ce6072SVignesh Raghavendra 		/* Configure non-control EPs */
159f6ce6072SVignesh Raghavendra 		for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) {
160f6ce6072SVignesh Raghavendra 			priv_ep = priv_dev->eps[i];
161f6ce6072SVignesh Raghavendra 			if (!priv_ep)
162f6ce6072SVignesh Raghavendra 				continue;
163f6ce6072SVignesh Raghavendra 
164f6ce6072SVignesh Raghavendra 			if (priv_ep->flags & EP_CLAIMED)
165f6ce6072SVignesh Raghavendra 				cdns3_ep_config(priv_ep);
166f6ce6072SVignesh Raghavendra 		}
167f6ce6072SVignesh Raghavendra 
168f6ce6072SVignesh Raghavendra 		result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
169f6ce6072SVignesh Raghavendra 
170f6ce6072SVignesh Raghavendra 		if (result)
171f6ce6072SVignesh Raghavendra 			return result;
172f6ce6072SVignesh Raghavendra 
173f6ce6072SVignesh Raghavendra 		if (config) {
174f6ce6072SVignesh Raghavendra 			cdns3_set_hw_configuration(priv_dev);
175f6ce6072SVignesh Raghavendra 		} else {
176f6ce6072SVignesh Raghavendra 			cdns3_hw_reset_eps_config(priv_dev);
177f6ce6072SVignesh Raghavendra 			usb_gadget_set_state(&priv_dev->gadget,
178f6ce6072SVignesh Raghavendra 					     USB_STATE_ADDRESS);
179f6ce6072SVignesh Raghavendra 		}
180f6ce6072SVignesh Raghavendra 		break;
181f6ce6072SVignesh Raghavendra 	case USB_STATE_CONFIGURED:
182f6ce6072SVignesh Raghavendra 		result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
183f6ce6072SVignesh Raghavendra 
184f6ce6072SVignesh Raghavendra 		if (!config && !result) {
185f6ce6072SVignesh Raghavendra 			cdns3_hw_reset_eps_config(priv_dev);
186f6ce6072SVignesh Raghavendra 			usb_gadget_set_state(&priv_dev->gadget,
187f6ce6072SVignesh Raghavendra 					     USB_STATE_ADDRESS);
188f6ce6072SVignesh Raghavendra 		}
189f6ce6072SVignesh Raghavendra 		break;
190f6ce6072SVignesh Raghavendra 	default:
191f6ce6072SVignesh Raghavendra 		result = -EINVAL;
192f6ce6072SVignesh Raghavendra 	}
193f6ce6072SVignesh Raghavendra 
194f6ce6072SVignesh Raghavendra 	return result;
195f6ce6072SVignesh Raghavendra }
196f6ce6072SVignesh Raghavendra 
197f6ce6072SVignesh Raghavendra /**
198f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request
199f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
200f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
201f6ce6072SVignesh Raghavendra  *
202f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
203f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_set_address(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)204f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev,
205f6ce6072SVignesh Raghavendra 				     struct usb_ctrlrequest *ctrl_req)
206f6ce6072SVignesh Raghavendra {
207f6ce6072SVignesh Raghavendra 	enum usb_device_state device_state = priv_dev->gadget.state;
208f6ce6072SVignesh Raghavendra 	u32 reg;
209f6ce6072SVignesh Raghavendra 	u32 addr;
210f6ce6072SVignesh Raghavendra 
211f6ce6072SVignesh Raghavendra 	addr = le16_to_cpu(ctrl_req->wValue);
212f6ce6072SVignesh Raghavendra 
213f6ce6072SVignesh Raghavendra 	if (addr > USB_DEVICE_MAX_ADDRESS) {
214f6ce6072SVignesh Raghavendra 		dev_err(priv_dev->dev,
215f6ce6072SVignesh Raghavendra 			"Device address (%d) cannot be greater than %d\n",
216f6ce6072SVignesh Raghavendra 			addr, USB_DEVICE_MAX_ADDRESS);
217f6ce6072SVignesh Raghavendra 		return -EINVAL;
218f6ce6072SVignesh Raghavendra 	}
219f6ce6072SVignesh Raghavendra 
220f6ce6072SVignesh Raghavendra 	if (device_state == USB_STATE_CONFIGURED) {
221f6ce6072SVignesh Raghavendra 		dev_err(priv_dev->dev,
222f6ce6072SVignesh Raghavendra 			"can't set_address from configured state\n");
223f6ce6072SVignesh Raghavendra 		return -EINVAL;
224f6ce6072SVignesh Raghavendra 	}
225f6ce6072SVignesh Raghavendra 
226f6ce6072SVignesh Raghavendra 	reg = readl(&priv_dev->regs->usb_cmd);
227f6ce6072SVignesh Raghavendra 
228f6ce6072SVignesh Raghavendra 	writel(reg | USB_CMD_FADDR(addr) | USB_CMD_SET_ADDR,
229f6ce6072SVignesh Raghavendra 	       &priv_dev->regs->usb_cmd);
230f6ce6072SVignesh Raghavendra 
231f6ce6072SVignesh Raghavendra 	usb_gadget_set_state(&priv_dev->gadget,
232f6ce6072SVignesh Raghavendra 			     (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT));
233f6ce6072SVignesh Raghavendra 
234f6ce6072SVignesh Raghavendra 	return 0;
235f6ce6072SVignesh Raghavendra }
236f6ce6072SVignesh Raghavendra 
237f6ce6072SVignesh Raghavendra /**
238f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request
239f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
240f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
241f6ce6072SVignesh Raghavendra  *
242f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
243f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_get_status(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl)244f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev,
245f6ce6072SVignesh Raghavendra 				    struct usb_ctrlrequest *ctrl)
246f6ce6072SVignesh Raghavendra {
247f6ce6072SVignesh Raghavendra 	__le16 *response_pkt;
248f6ce6072SVignesh Raghavendra 	u16 usb_status = 0;
249f6ce6072SVignesh Raghavendra 	u32 recip;
250f6ce6072SVignesh Raghavendra 
251f6ce6072SVignesh Raghavendra 	recip = ctrl->bRequestType & USB_RECIP_MASK;
252f6ce6072SVignesh Raghavendra 
253f6ce6072SVignesh Raghavendra 	switch (recip) {
254f6ce6072SVignesh Raghavendra 	case USB_RECIP_DEVICE:
255f6ce6072SVignesh Raghavendra 		/* self powered */
256f6ce6072SVignesh Raghavendra 		if (priv_dev->is_selfpowered)
257f6ce6072SVignesh Raghavendra 			usb_status = BIT(USB_DEVICE_SELF_POWERED);
258f6ce6072SVignesh Raghavendra 
259f6ce6072SVignesh Raghavendra 		if (priv_dev->wake_up_flag)
260f6ce6072SVignesh Raghavendra 			usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP);
261f6ce6072SVignesh Raghavendra 
262f6ce6072SVignesh Raghavendra 		if (priv_dev->gadget.speed != USB_SPEED_SUPER)
263f6ce6072SVignesh Raghavendra 			break;
264f6ce6072SVignesh Raghavendra 
265f6ce6072SVignesh Raghavendra 		if (priv_dev->u1_allowed)
266f6ce6072SVignesh Raghavendra 			usb_status |= BIT(USB_DEV_STAT_U1_ENABLED);
267f6ce6072SVignesh Raghavendra 
268f6ce6072SVignesh Raghavendra 		if (priv_dev->u2_allowed)
269f6ce6072SVignesh Raghavendra 			usb_status |= BIT(USB_DEV_STAT_U2_ENABLED);
270f6ce6072SVignesh Raghavendra 
271f6ce6072SVignesh Raghavendra 		break;
272f6ce6072SVignesh Raghavendra 	case USB_RECIP_INTERFACE:
273f6ce6072SVignesh Raghavendra 		return cdns3_ep0_delegate_req(priv_dev, ctrl);
274f6ce6072SVignesh Raghavendra 	case USB_RECIP_ENDPOINT:
275f6ce6072SVignesh Raghavendra 		/* check if endpoint is stalled */
276f6ce6072SVignesh Raghavendra 		cdns3_select_ep(priv_dev, ctrl->wIndex);
277f6ce6072SVignesh Raghavendra 		if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts)))
278f6ce6072SVignesh Raghavendra 			usb_status =  BIT(USB_ENDPOINT_HALT);
279f6ce6072SVignesh Raghavendra 		break;
280f6ce6072SVignesh Raghavendra 	default:
281f6ce6072SVignesh Raghavendra 		return -EINVAL;
282f6ce6072SVignesh Raghavendra 	}
283f6ce6072SVignesh Raghavendra 
284f6ce6072SVignesh Raghavendra 	response_pkt = (__le16 *)priv_dev->setup_buf;
285f6ce6072SVignesh Raghavendra 	*response_pkt = cpu_to_le16(usb_status);
286f6ce6072SVignesh Raghavendra 
287f6ce6072SVignesh Raghavendra 	/* Flush setup response */
288f6ce6072SVignesh Raghavendra 	flush_dcache_range((unsigned long)priv_dev->setup_buf,
289f6ce6072SVignesh Raghavendra 			   (unsigned long)priv_dev->setup_buf +
290f6ce6072SVignesh Raghavendra 			   ROUND(sizeof(struct usb_ctrlrequest),
291f6ce6072SVignesh Raghavendra 				 CONFIG_SYS_CACHELINE_SIZE));
292f6ce6072SVignesh Raghavendra 
293f6ce6072SVignesh Raghavendra 	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
294f6ce6072SVignesh Raghavendra 			       sizeof(*response_pkt), 1, 0);
295f6ce6072SVignesh Raghavendra 	return 0;
296f6ce6072SVignesh Raghavendra }
297f6ce6072SVignesh Raghavendra 
cdns3_ep0_feature_handle_device(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl,int set)298f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev,
299f6ce6072SVignesh Raghavendra 					   struct usb_ctrlrequest *ctrl,
300f6ce6072SVignesh Raghavendra 					   int set)
301f6ce6072SVignesh Raghavendra {
302f6ce6072SVignesh Raghavendra 	enum usb_device_state state;
303f6ce6072SVignesh Raghavendra 	enum usb_device_speed speed;
304f6ce6072SVignesh Raghavendra 	int ret = 0;
305f6ce6072SVignesh Raghavendra 	u16 tmode;
306f6ce6072SVignesh Raghavendra 
307f6ce6072SVignesh Raghavendra 	state = priv_dev->gadget.state;
308f6ce6072SVignesh Raghavendra 	speed = priv_dev->gadget.speed;
309f6ce6072SVignesh Raghavendra 
310f6ce6072SVignesh Raghavendra 	switch (ctrl->wValue) {
311f6ce6072SVignesh Raghavendra 	case USB_DEVICE_REMOTE_WAKEUP:
312f6ce6072SVignesh Raghavendra 		priv_dev->wake_up_flag = !!set;
313f6ce6072SVignesh Raghavendra 		break;
314f6ce6072SVignesh Raghavendra 	case USB_DEVICE_U1_ENABLE:
315f6ce6072SVignesh Raghavendra 		if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER)
316f6ce6072SVignesh Raghavendra 			return -EINVAL;
317f6ce6072SVignesh Raghavendra 
318f6ce6072SVignesh Raghavendra 		priv_dev->u1_allowed = !!set;
319f6ce6072SVignesh Raghavendra 		break;
320f6ce6072SVignesh Raghavendra 	case USB_DEVICE_U2_ENABLE:
321f6ce6072SVignesh Raghavendra 		if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER)
322f6ce6072SVignesh Raghavendra 			return -EINVAL;
323f6ce6072SVignesh Raghavendra 
324f6ce6072SVignesh Raghavendra 		priv_dev->u2_allowed = !!set;
325f6ce6072SVignesh Raghavendra 		break;
326f6ce6072SVignesh Raghavendra 	case USB_DEVICE_LTM_ENABLE:
327f6ce6072SVignesh Raghavendra 		ret = -EINVAL;
328f6ce6072SVignesh Raghavendra 		break;
329f6ce6072SVignesh Raghavendra 	case USB_DEVICE_TEST_MODE:
330f6ce6072SVignesh Raghavendra 		if (state != USB_STATE_CONFIGURED || speed > USB_SPEED_HIGH)
331f6ce6072SVignesh Raghavendra 			return -EINVAL;
332f6ce6072SVignesh Raghavendra 
333f6ce6072SVignesh Raghavendra 		tmode = le16_to_cpu(ctrl->wIndex);
334f6ce6072SVignesh Raghavendra 
335f6ce6072SVignesh Raghavendra 		if (!set || (tmode & 0xff) != 0)
336f6ce6072SVignesh Raghavendra 			return -EINVAL;
337f6ce6072SVignesh Raghavendra 
338f6ce6072SVignesh Raghavendra 		switch (tmode >> 8) {
339f6ce6072SVignesh Raghavendra 		case TEST_J:
340f6ce6072SVignesh Raghavendra 		case TEST_K:
341f6ce6072SVignesh Raghavendra 		case TEST_SE0_NAK:
342f6ce6072SVignesh Raghavendra 		case TEST_PACKET:
343f6ce6072SVignesh Raghavendra 			cdns3_ep0_complete_setup(priv_dev, 0, 1);
344f6ce6072SVignesh Raghavendra 			/**
345f6ce6072SVignesh Raghavendra 			 *  Little delay to give the controller some time
346f6ce6072SVignesh Raghavendra 			 * for sending status stage.
347f6ce6072SVignesh Raghavendra 			 * This time should be less then 3ms.
348f6ce6072SVignesh Raghavendra 			 */
349f6ce6072SVignesh Raghavendra 			usleep_range(1000, 2000);
350f6ce6072SVignesh Raghavendra 			cdns3_set_register_bit(&priv_dev->regs->usb_cmd,
351f6ce6072SVignesh Raghavendra 					       USB_CMD_STMODE |
352f6ce6072SVignesh Raghavendra 					       USB_STS_TMODE_SEL(tmode - 1));
353f6ce6072SVignesh Raghavendra 			break;
354f6ce6072SVignesh Raghavendra 		default:
355f6ce6072SVignesh Raghavendra 			ret = -EINVAL;
356f6ce6072SVignesh Raghavendra 		}
357f6ce6072SVignesh Raghavendra 		break;
358f6ce6072SVignesh Raghavendra 	default:
359f6ce6072SVignesh Raghavendra 		ret = -EINVAL;
360f6ce6072SVignesh Raghavendra 	}
361f6ce6072SVignesh Raghavendra 
362f6ce6072SVignesh Raghavendra 	return ret;
363f6ce6072SVignesh Raghavendra }
364f6ce6072SVignesh Raghavendra 
cdns3_ep0_feature_handle_intf(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl,int set)365f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_intf(struct cdns3_device *priv_dev,
366f6ce6072SVignesh Raghavendra 					 struct usb_ctrlrequest *ctrl,
367f6ce6072SVignesh Raghavendra 					 int set)
368f6ce6072SVignesh Raghavendra {
369f6ce6072SVignesh Raghavendra 	u32 wValue;
370f6ce6072SVignesh Raghavendra 	int ret = 0;
371f6ce6072SVignesh Raghavendra 
372f6ce6072SVignesh Raghavendra 	wValue = le16_to_cpu(ctrl->wValue);
373f6ce6072SVignesh Raghavendra 
374f6ce6072SVignesh Raghavendra 	switch (wValue) {
375f6ce6072SVignesh Raghavendra 	case USB_INTRF_FUNC_SUSPEND:
376f6ce6072SVignesh Raghavendra 		break;
377f6ce6072SVignesh Raghavendra 	default:
378f6ce6072SVignesh Raghavendra 		ret = -EINVAL;
379f6ce6072SVignesh Raghavendra 	}
380f6ce6072SVignesh Raghavendra 
381f6ce6072SVignesh Raghavendra 	return ret;
382f6ce6072SVignesh Raghavendra }
383f6ce6072SVignesh Raghavendra 
cdns3_ep0_feature_handle_endpoint(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl,int set)384f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev,
385f6ce6072SVignesh Raghavendra 					     struct usb_ctrlrequest *ctrl,
386f6ce6072SVignesh Raghavendra 					     int set)
387f6ce6072SVignesh Raghavendra {
388f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep;
389f6ce6072SVignesh Raghavendra 	int ret = 0;
390f6ce6072SVignesh Raghavendra 	u8 index;
391f6ce6072SVignesh Raghavendra 
392f6ce6072SVignesh Raghavendra 	if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT)
393f6ce6072SVignesh Raghavendra 		return -EINVAL;
394f6ce6072SVignesh Raghavendra 
395f6ce6072SVignesh Raghavendra 	if (!(ctrl->wIndex & ~USB_DIR_IN))
396f6ce6072SVignesh Raghavendra 		return 0;
397f6ce6072SVignesh Raghavendra 
398f6ce6072SVignesh Raghavendra 	index = cdns3_ep_addr_to_index(ctrl->wIndex);
399f6ce6072SVignesh Raghavendra 	priv_ep = priv_dev->eps[index];
400f6ce6072SVignesh Raghavendra 
401f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, ctrl->wIndex);
402f6ce6072SVignesh Raghavendra 
403f6ce6072SVignesh Raghavendra 	if (set)
404f6ce6072SVignesh Raghavendra 		__cdns3_gadget_ep_set_halt(priv_ep);
405f6ce6072SVignesh Raghavendra 	else if (!(priv_ep->flags & EP_WEDGE))
406f6ce6072SVignesh Raghavendra 		ret = __cdns3_gadget_ep_clear_halt(priv_ep);
407f6ce6072SVignesh Raghavendra 
408f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, 0x00);
409f6ce6072SVignesh Raghavendra 
410f6ce6072SVignesh Raghavendra 	return ret;
411f6ce6072SVignesh Raghavendra }
412f6ce6072SVignesh Raghavendra 
413f6ce6072SVignesh Raghavendra /**
414f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_handle_feature -
415f6ce6072SVignesh Raghavendra  * Handling of GET/SET_FEATURE standard USB request
416f6ce6072SVignesh Raghavendra  *
417f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
418f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
419f6ce6072SVignesh Raghavendra  * @set: must be set to 1 for SET_FEATURE request
420f6ce6072SVignesh Raghavendra  *
421f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
422f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_handle_feature(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl,int set)423f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev,
424f6ce6072SVignesh Raghavendra 					struct usb_ctrlrequest *ctrl,
425f6ce6072SVignesh Raghavendra 					int set)
426f6ce6072SVignesh Raghavendra {
427f6ce6072SVignesh Raghavendra 	int ret = 0;
428f6ce6072SVignesh Raghavendra 	u32 recip;
429f6ce6072SVignesh Raghavendra 
430f6ce6072SVignesh Raghavendra 	recip = ctrl->bRequestType & USB_RECIP_MASK;
431f6ce6072SVignesh Raghavendra 
432f6ce6072SVignesh Raghavendra 	switch (recip) {
433f6ce6072SVignesh Raghavendra 	case USB_RECIP_DEVICE:
434f6ce6072SVignesh Raghavendra 		ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set);
435f6ce6072SVignesh Raghavendra 		break;
436f6ce6072SVignesh Raghavendra 	case USB_RECIP_INTERFACE:
437f6ce6072SVignesh Raghavendra 		ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set);
438f6ce6072SVignesh Raghavendra 		break;
439f6ce6072SVignesh Raghavendra 	case USB_RECIP_ENDPOINT:
440f6ce6072SVignesh Raghavendra 		ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set);
441f6ce6072SVignesh Raghavendra 		break;
442f6ce6072SVignesh Raghavendra 	default:
443f6ce6072SVignesh Raghavendra 		return -EINVAL;
444f6ce6072SVignesh Raghavendra 	}
445f6ce6072SVignesh Raghavendra 
446f6ce6072SVignesh Raghavendra 	return ret;
447f6ce6072SVignesh Raghavendra }
448f6ce6072SVignesh Raghavendra 
449f6ce6072SVignesh Raghavendra /**
450f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request
451f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
452f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
453f6ce6072SVignesh Raghavendra  *
454f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
455f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_set_sel(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)456f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev,
457f6ce6072SVignesh Raghavendra 				 struct usb_ctrlrequest *ctrl_req)
458f6ce6072SVignesh Raghavendra {
459f6ce6072SVignesh Raghavendra 	if (priv_dev->gadget.state < USB_STATE_ADDRESS)
460f6ce6072SVignesh Raghavendra 		return -EINVAL;
461f6ce6072SVignesh Raghavendra 
462f6ce6072SVignesh Raghavendra 	if (ctrl_req->wLength != 6) {
463f6ce6072SVignesh Raghavendra 		dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n",
464f6ce6072SVignesh Raghavendra 			ctrl_req->wLength);
465f6ce6072SVignesh Raghavendra 		return -EINVAL;
466f6ce6072SVignesh Raghavendra 	}
467f6ce6072SVignesh Raghavendra 
468f6ce6072SVignesh Raghavendra 	cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 6, 1, 0);
469f6ce6072SVignesh Raghavendra 	return 0;
470f6ce6072SVignesh Raghavendra }
471f6ce6072SVignesh Raghavendra 
472f6ce6072SVignesh Raghavendra /**
473f6ce6072SVignesh Raghavendra  * cdns3_req_ep0_set_isoch_delay -
474f6ce6072SVignesh Raghavendra  * Handling of GET_ISOCH_DELAY standard USB request
475f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
476f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
477f6ce6072SVignesh Raghavendra  *
478f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
479f6ce6072SVignesh Raghavendra  */
cdns3_req_ep0_set_isoch_delay(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)480f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_isoch_delay(struct cdns3_device *priv_dev,
481f6ce6072SVignesh Raghavendra 					 struct usb_ctrlrequest *ctrl_req)
482f6ce6072SVignesh Raghavendra {
483f6ce6072SVignesh Raghavendra 	if (ctrl_req->wIndex || ctrl_req->wLength)
484f6ce6072SVignesh Raghavendra 		return -EINVAL;
485f6ce6072SVignesh Raghavendra 
486f6ce6072SVignesh Raghavendra 	priv_dev->isoch_delay = ctrl_req->wValue;
487f6ce6072SVignesh Raghavendra 
488f6ce6072SVignesh Raghavendra 	return 0;
489f6ce6072SVignesh Raghavendra }
490f6ce6072SVignesh Raghavendra 
491f6ce6072SVignesh Raghavendra /**
492f6ce6072SVignesh Raghavendra  * cdns3_ep0_standard_request - Handling standard USB requests
493f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
494f6ce6072SVignesh Raghavendra  * @ctrl_req: pointer to received setup packet
495f6ce6072SVignesh Raghavendra  *
496f6ce6072SVignesh Raghavendra  * Returns 0 if success, error code on error
497f6ce6072SVignesh Raghavendra  */
cdns3_ep0_standard_request(struct cdns3_device * priv_dev,struct usb_ctrlrequest * ctrl_req)498f6ce6072SVignesh Raghavendra static int cdns3_ep0_standard_request(struct cdns3_device *priv_dev,
499f6ce6072SVignesh Raghavendra 				      struct usb_ctrlrequest *ctrl_req)
500f6ce6072SVignesh Raghavendra {
501f6ce6072SVignesh Raghavendra 	int ret;
502f6ce6072SVignesh Raghavendra 
503f6ce6072SVignesh Raghavendra 	switch (ctrl_req->bRequest) {
504f6ce6072SVignesh Raghavendra 	case USB_REQ_SET_ADDRESS:
505f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req);
506f6ce6072SVignesh Raghavendra 		break;
507f6ce6072SVignesh Raghavendra 	case USB_REQ_SET_CONFIGURATION:
508f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req);
509f6ce6072SVignesh Raghavendra 		break;
510f6ce6072SVignesh Raghavendra 	case USB_REQ_GET_STATUS:
511f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req);
512f6ce6072SVignesh Raghavendra 		break;
513f6ce6072SVignesh Raghavendra 	case USB_REQ_CLEAR_FEATURE:
514f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0);
515f6ce6072SVignesh Raghavendra 		break;
516f6ce6072SVignesh Raghavendra 	case USB_REQ_SET_FEATURE:
517f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1);
518f6ce6072SVignesh Raghavendra 		break;
519f6ce6072SVignesh Raghavendra 	case USB_REQ_SET_SEL:
520f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req);
521f6ce6072SVignesh Raghavendra 		break;
522f6ce6072SVignesh Raghavendra 	case USB_REQ_SET_ISOCH_DELAY:
523f6ce6072SVignesh Raghavendra 		ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req);
524f6ce6072SVignesh Raghavendra 		break;
525f6ce6072SVignesh Raghavendra 	default:
526f6ce6072SVignesh Raghavendra 		ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
527f6ce6072SVignesh Raghavendra 		break;
528f6ce6072SVignesh Raghavendra 	}
529f6ce6072SVignesh Raghavendra 
530f6ce6072SVignesh Raghavendra 	return ret;
531f6ce6072SVignesh Raghavendra }
532f6ce6072SVignesh Raghavendra 
__pending_setup_status_handler(struct cdns3_device * priv_dev)533f6ce6072SVignesh Raghavendra static void __pending_setup_status_handler(struct cdns3_device *priv_dev)
534f6ce6072SVignesh Raghavendra {
535f6ce6072SVignesh Raghavendra 	struct usb_request *request = priv_dev->pending_status_request;
536f6ce6072SVignesh Raghavendra 
537f6ce6072SVignesh Raghavendra 	if (priv_dev->status_completion_no_call && request &&
538f6ce6072SVignesh Raghavendra 	    request->complete) {
539f6ce6072SVignesh Raghavendra 		request->complete(&priv_dev->eps[0]->endpoint, request);
540f6ce6072SVignesh Raghavendra 		priv_dev->status_completion_no_call = 0;
541f6ce6072SVignesh Raghavendra 	}
542f6ce6072SVignesh Raghavendra }
543f6ce6072SVignesh Raghavendra 
cdns3_pending_setup_status_handler(struct work_struct * work)544f6ce6072SVignesh Raghavendra void cdns3_pending_setup_status_handler(struct work_struct *work)
545f6ce6072SVignesh Raghavendra {
546f6ce6072SVignesh Raghavendra 	struct cdns3_device *priv_dev = container_of(work, struct cdns3_device,
547f6ce6072SVignesh Raghavendra 			pending_status_wq);
548f6ce6072SVignesh Raghavendra 	unsigned long flags;
549f6ce6072SVignesh Raghavendra 
550f6ce6072SVignesh Raghavendra 	spin_lock_irqsave(&priv_dev->lock, flags);
551f6ce6072SVignesh Raghavendra 	__pending_setup_status_handler(priv_dev);
552f6ce6072SVignesh Raghavendra 	spin_unlock_irqrestore(&priv_dev->lock, flags);
553f6ce6072SVignesh Raghavendra }
554f6ce6072SVignesh Raghavendra 
555f6ce6072SVignesh Raghavendra /**
556f6ce6072SVignesh Raghavendra  * cdns3_ep0_setup_phase - Handling setup USB requests
557f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
558f6ce6072SVignesh Raghavendra  */
cdns3_ep0_setup_phase(struct cdns3_device * priv_dev)559f6ce6072SVignesh Raghavendra static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev)
560f6ce6072SVignesh Raghavendra {
561f6ce6072SVignesh Raghavendra 	struct usb_ctrlrequest *ctrl = priv_dev->setup_buf;
562f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
563f6ce6072SVignesh Raghavendra 	int result;
564f6ce6072SVignesh Raghavendra 
565f6ce6072SVignesh Raghavendra 	priv_dev->ep0_data_dir = ctrl->bRequestType & USB_DIR_IN;
566f6ce6072SVignesh Raghavendra 
567f6ce6072SVignesh Raghavendra 	trace_cdns3_ctrl_req(ctrl);
568f6ce6072SVignesh Raghavendra 
569f6ce6072SVignesh Raghavendra 	if (!list_empty(&priv_ep->pending_req_list)) {
570f6ce6072SVignesh Raghavendra 		struct usb_request *request;
571f6ce6072SVignesh Raghavendra 
572f6ce6072SVignesh Raghavendra 		request = cdns3_next_request(&priv_ep->pending_req_list);
573f6ce6072SVignesh Raghavendra 		priv_ep->dir = priv_dev->ep0_data_dir;
574f6ce6072SVignesh Raghavendra 		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request),
575f6ce6072SVignesh Raghavendra 				      -ECONNRESET);
576f6ce6072SVignesh Raghavendra 	}
577f6ce6072SVignesh Raghavendra 
578f6ce6072SVignesh Raghavendra 	if (le16_to_cpu(ctrl->wLength))
579f6ce6072SVignesh Raghavendra 		priv_dev->ep0_stage = CDNS3_DATA_STAGE;
580f6ce6072SVignesh Raghavendra 	else
581f6ce6072SVignesh Raghavendra 		priv_dev->ep0_stage = CDNS3_STATUS_STAGE;
582f6ce6072SVignesh Raghavendra 
583f6ce6072SVignesh Raghavendra 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
584f6ce6072SVignesh Raghavendra 		result = cdns3_ep0_standard_request(priv_dev, ctrl);
585f6ce6072SVignesh Raghavendra 	else
586f6ce6072SVignesh Raghavendra 		result = cdns3_ep0_delegate_req(priv_dev, ctrl);
587f6ce6072SVignesh Raghavendra 
588f6ce6072SVignesh Raghavendra 	if (result == USB_GADGET_DELAYED_STATUS)
589f6ce6072SVignesh Raghavendra 		return;
590f6ce6072SVignesh Raghavendra 
591f6ce6072SVignesh Raghavendra 	if (result < 0)
592f6ce6072SVignesh Raghavendra 		cdns3_ep0_complete_setup(priv_dev, 1, 1);
593f6ce6072SVignesh Raghavendra 	else if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE)
594f6ce6072SVignesh Raghavendra 		cdns3_ep0_complete_setup(priv_dev, 0, 1);
595f6ce6072SVignesh Raghavendra }
596f6ce6072SVignesh Raghavendra 
cdns3_transfer_completed(struct cdns3_device * priv_dev)597f6ce6072SVignesh Raghavendra static void cdns3_transfer_completed(struct cdns3_device *priv_dev)
598f6ce6072SVignesh Raghavendra {
599f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = priv_dev->eps[0];
600f6ce6072SVignesh Raghavendra 
601f6ce6072SVignesh Raghavendra 	if (!list_empty(&priv_ep->pending_req_list)) {
602f6ce6072SVignesh Raghavendra 		struct usb_request *request;
603f6ce6072SVignesh Raghavendra 
604f6ce6072SVignesh Raghavendra 		trace_cdns3_complete_trb(priv_ep, priv_ep->trb_pool);
605f6ce6072SVignesh Raghavendra 		request = cdns3_next_request(&priv_ep->pending_req_list);
606f6ce6072SVignesh Raghavendra 
607f6ce6072SVignesh Raghavendra 		/* Invalidate TRB before accessing it */
608f6ce6072SVignesh Raghavendra 		invalidate_dcache_range((unsigned long)priv_ep->trb_pool,
609f6ce6072SVignesh Raghavendra 					(unsigned long)priv_ep->trb_pool +
610f6ce6072SVignesh Raghavendra 					ROUND(sizeof(struct cdns3_trb),
611f6ce6072SVignesh Raghavendra 					      CONFIG_SYS_CACHELINE_SIZE));
612f6ce6072SVignesh Raghavendra 
613f6ce6072SVignesh Raghavendra 		request->actual =
614f6ce6072SVignesh Raghavendra 			TRB_LEN(le32_to_cpu(priv_ep->trb_pool->length));
615f6ce6072SVignesh Raghavendra 
616f6ce6072SVignesh Raghavendra 		priv_ep->dir = priv_dev->ep0_data_dir;
617f6ce6072SVignesh Raghavendra 		cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), 0);
618f6ce6072SVignesh Raghavendra 	}
619f6ce6072SVignesh Raghavendra 
620f6ce6072SVignesh Raghavendra 	cdns3_ep0_complete_setup(priv_dev, 0, 0);
621f6ce6072SVignesh Raghavendra }
622f6ce6072SVignesh Raghavendra 
623f6ce6072SVignesh Raghavendra /**
624f6ce6072SVignesh Raghavendra  * cdns3_check_new_setup - Check if controller receive new SETUP packet.
625f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
626f6ce6072SVignesh Raghavendra  *
627f6ce6072SVignesh Raghavendra  * The SETUP packet can be kept in on-chip memory or in system memory.
628f6ce6072SVignesh Raghavendra  */
cdns3_check_new_setup(struct cdns3_device * priv_dev)629f6ce6072SVignesh Raghavendra static bool cdns3_check_new_setup(struct cdns3_device *priv_dev)
630f6ce6072SVignesh Raghavendra {
631f6ce6072SVignesh Raghavendra 	u32 ep_sts_reg;
632f6ce6072SVignesh Raghavendra 
633f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT);
634f6ce6072SVignesh Raghavendra 	ep_sts_reg = readl(&priv_dev->regs->ep_sts);
635f6ce6072SVignesh Raghavendra 
636f6ce6072SVignesh Raghavendra 	return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT));
637f6ce6072SVignesh Raghavendra }
638f6ce6072SVignesh Raghavendra 
639f6ce6072SVignesh Raghavendra /**
640f6ce6072SVignesh Raghavendra  * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
641f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
642f6ce6072SVignesh Raghavendra  * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction
643f6ce6072SVignesh Raghavendra  */
cdns3_check_ep0_interrupt_proceed(struct cdns3_device * priv_dev,int dir)644f6ce6072SVignesh Raghavendra void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
645f6ce6072SVignesh Raghavendra {
646f6ce6072SVignesh Raghavendra 	u32 ep_sts_reg;
647f6ce6072SVignesh Raghavendra 
648f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, dir);
649f6ce6072SVignesh Raghavendra 
650f6ce6072SVignesh Raghavendra 	ep_sts_reg = readl(&priv_dev->regs->ep_sts);
651f6ce6072SVignesh Raghavendra 	writel(ep_sts_reg, &priv_dev->regs->ep_sts);
652f6ce6072SVignesh Raghavendra 
653f6ce6072SVignesh Raghavendra 	trace_cdns3_ep0_irq(priv_dev, ep_sts_reg);
654f6ce6072SVignesh Raghavendra 
655f6ce6072SVignesh Raghavendra 	__pending_setup_status_handler(priv_dev);
656f6ce6072SVignesh Raghavendra 
657f6ce6072SVignesh Raghavendra 	if (ep_sts_reg & EP_STS_SETUP)
658f6ce6072SVignesh Raghavendra 		priv_dev->wait_for_setup = 1;
659f6ce6072SVignesh Raghavendra 
660f6ce6072SVignesh Raghavendra 	if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) {
661f6ce6072SVignesh Raghavendra 		priv_dev->wait_for_setup = 0;
662f6ce6072SVignesh Raghavendra 		cdns3_allow_enable_l1(priv_dev, 0);
663f6ce6072SVignesh Raghavendra 		cdns3_ep0_setup_phase(priv_dev);
664f6ce6072SVignesh Raghavendra 	} else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
665f6ce6072SVignesh Raghavendra 		priv_dev->ep0_data_dir = dir;
666f6ce6072SVignesh Raghavendra 		cdns3_transfer_completed(priv_dev);
667f6ce6072SVignesh Raghavendra 	}
668f6ce6072SVignesh Raghavendra 
669f6ce6072SVignesh Raghavendra 	if (ep_sts_reg & EP_STS_DESCMIS) {
670f6ce6072SVignesh Raghavendra 		if (dir == 0 && !priv_dev->setup_pending)
671f6ce6072SVignesh Raghavendra 			cdns3_prepare_setup_packet(priv_dev);
672f6ce6072SVignesh Raghavendra 	}
673f6ce6072SVignesh Raghavendra }
674f6ce6072SVignesh Raghavendra 
675f6ce6072SVignesh Raghavendra /**
676f6ce6072SVignesh Raghavendra  * cdns3_gadget_ep0_enable
677f6ce6072SVignesh Raghavendra  * Function shouldn't be called by gadget driver,
678f6ce6072SVignesh Raghavendra  * endpoint 0 is allways active
679f6ce6072SVignesh Raghavendra  */
cdns3_gadget_ep0_enable(struct usb_ep * ep,const struct usb_endpoint_descriptor * desc)680f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_enable(struct usb_ep *ep,
681f6ce6072SVignesh Raghavendra 				   const struct usb_endpoint_descriptor *desc)
682f6ce6072SVignesh Raghavendra {
683f6ce6072SVignesh Raghavendra 	return -EINVAL;
684f6ce6072SVignesh Raghavendra }
685f6ce6072SVignesh Raghavendra 
686f6ce6072SVignesh Raghavendra /**
687f6ce6072SVignesh Raghavendra  * cdns3_gadget_ep0_disable
688f6ce6072SVignesh Raghavendra  * Function shouldn't be called by gadget driver,
689f6ce6072SVignesh Raghavendra  * endpoint 0 is allways active
690f6ce6072SVignesh Raghavendra  */
cdns3_gadget_ep0_disable(struct usb_ep * ep)691f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_disable(struct usb_ep *ep)
692f6ce6072SVignesh Raghavendra {
693f6ce6072SVignesh Raghavendra 	return -EINVAL;
694f6ce6072SVignesh Raghavendra }
695f6ce6072SVignesh Raghavendra 
696f6ce6072SVignesh Raghavendra /**
697f6ce6072SVignesh Raghavendra  * cdns3_gadget_ep0_set_halt
698f6ce6072SVignesh Raghavendra  * @ep: pointer to endpoint zero object
699f6ce6072SVignesh Raghavendra  * @value: 1 for set stall, 0 for clear stall
700f6ce6072SVignesh Raghavendra  *
701f6ce6072SVignesh Raghavendra  * Returns 0
702f6ce6072SVignesh Raghavendra  */
cdns3_gadget_ep0_set_halt(struct usb_ep * ep,int value)703f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
704f6ce6072SVignesh Raghavendra {
705f6ce6072SVignesh Raghavendra 	/* TODO */
706f6ce6072SVignesh Raghavendra 	return 0;
707f6ce6072SVignesh Raghavendra }
708f6ce6072SVignesh Raghavendra 
709f6ce6072SVignesh Raghavendra /**
710f6ce6072SVignesh Raghavendra  * cdns3_gadget_ep0_queue Transfer data on endpoint zero
711f6ce6072SVignesh Raghavendra  * @ep: pointer to endpoint zero object
712f6ce6072SVignesh Raghavendra  * @request: pointer to request object
713f6ce6072SVignesh Raghavendra  * @gfp_flags: gfp flags
714f6ce6072SVignesh Raghavendra  *
715f6ce6072SVignesh Raghavendra  * Returns 0 on success, error code elsewhere
716f6ce6072SVignesh Raghavendra  */
cdns3_gadget_ep0_queue(struct usb_ep * ep,struct usb_request * request,gfp_t gfp_flags)717f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
718f6ce6072SVignesh Raghavendra 				  struct usb_request *request,
719f6ce6072SVignesh Raghavendra 				  gfp_t gfp_flags)
720f6ce6072SVignesh Raghavendra {
721f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
722f6ce6072SVignesh Raghavendra 	struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
723f6ce6072SVignesh Raghavendra 	unsigned long flags;
724f6ce6072SVignesh Raghavendra 	int erdy_sent = 0;
725f6ce6072SVignesh Raghavendra 	int ret = 0;
726f6ce6072SVignesh Raghavendra 	u8 zlp = 0;
727f6ce6072SVignesh Raghavendra 
728f6ce6072SVignesh Raghavendra 	trace_cdns3_ep0_queue(priv_dev, request);
729f6ce6072SVignesh Raghavendra 
730f6ce6072SVignesh Raghavendra 	/* cancel the request if controller receive new SETUP packet. */
731f6ce6072SVignesh Raghavendra 	if (cdns3_check_new_setup(priv_dev))
732f6ce6072SVignesh Raghavendra 		return -ECONNRESET;
733f6ce6072SVignesh Raghavendra 
734f6ce6072SVignesh Raghavendra 	/* send STATUS stage. Should be called only for SET_CONFIGURATION */
735f6ce6072SVignesh Raghavendra 	if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) {
736f6ce6072SVignesh Raghavendra 		spin_lock_irqsave(&priv_dev->lock, flags);
737f6ce6072SVignesh Raghavendra 		cdns3_select_ep(priv_dev, 0x00);
738f6ce6072SVignesh Raghavendra 
739f6ce6072SVignesh Raghavendra 		erdy_sent = !priv_dev->hw_configured_flag;
740f6ce6072SVignesh Raghavendra 		cdns3_set_hw_configuration(priv_dev);
741f6ce6072SVignesh Raghavendra 
742f6ce6072SVignesh Raghavendra 		if (!erdy_sent)
743f6ce6072SVignesh Raghavendra 			cdns3_ep0_complete_setup(priv_dev, 0, 1);
744f6ce6072SVignesh Raghavendra 
745f6ce6072SVignesh Raghavendra 		cdns3_allow_enable_l1(priv_dev, 1);
746f6ce6072SVignesh Raghavendra 
747f6ce6072SVignesh Raghavendra 		request->actual = 0;
748f6ce6072SVignesh Raghavendra 		priv_dev->status_completion_no_call = true;
749f6ce6072SVignesh Raghavendra 		priv_dev->pending_status_request = request;
750f6ce6072SVignesh Raghavendra 		spin_unlock_irqrestore(&priv_dev->lock, flags);
751f6ce6072SVignesh Raghavendra 
752f6ce6072SVignesh Raghavendra 		/*
753f6ce6072SVignesh Raghavendra 		 * Since there is no completion interrupt for status stage,
754f6ce6072SVignesh Raghavendra 		 * it needs to call ->completion in software after
755f6ce6072SVignesh Raghavendra 		 * ep0_queue is back.
756f6ce6072SVignesh Raghavendra 		 */
757f6ce6072SVignesh Raghavendra #ifndef __UBOOT__
758f6ce6072SVignesh Raghavendra 		queue_work(system_freezable_wq, &priv_dev->pending_status_wq);
759f6ce6072SVignesh Raghavendra #else
760f6ce6072SVignesh Raghavendra 		__pending_setup_status_handler(priv_dev);
761f6ce6072SVignesh Raghavendra #endif
762f6ce6072SVignesh Raghavendra 		return 0;
763f6ce6072SVignesh Raghavendra 	}
764f6ce6072SVignesh Raghavendra 
765f6ce6072SVignesh Raghavendra 	spin_lock_irqsave(&priv_dev->lock, flags);
766f6ce6072SVignesh Raghavendra 	if (!list_empty(&priv_ep->pending_req_list)) {
767f6ce6072SVignesh Raghavendra 		dev_err(priv_dev->dev,
768f6ce6072SVignesh Raghavendra 			"can't handle multiple requests for ep0\n");
769f6ce6072SVignesh Raghavendra 		spin_unlock_irqrestore(&priv_dev->lock, flags);
770f6ce6072SVignesh Raghavendra 		return -EBUSY;
771f6ce6072SVignesh Raghavendra 	}
772f6ce6072SVignesh Raghavendra 
773f6ce6072SVignesh Raghavendra 	ret = usb_gadget_map_request(&priv_dev->gadget, request,
774f6ce6072SVignesh Raghavendra 				     priv_dev->ep0_data_dir);
775f6ce6072SVignesh Raghavendra 	if (ret) {
776f6ce6072SVignesh Raghavendra 		spin_unlock_irqrestore(&priv_dev->lock, flags);
777f6ce6072SVignesh Raghavendra 		dev_err(priv_dev->dev, "failed to map request\n");
778f6ce6072SVignesh Raghavendra 		return -EINVAL;
779f6ce6072SVignesh Raghavendra 	}
780f6ce6072SVignesh Raghavendra 
781f6ce6072SVignesh Raghavendra 	request->status = -EINPROGRESS;
782f6ce6072SVignesh Raghavendra 	list_add_tail(&request->list, &priv_ep->pending_req_list);
783f6ce6072SVignesh Raghavendra 
784f6ce6072SVignesh Raghavendra 	if (request->zero && request->length &&
785f6ce6072SVignesh Raghavendra 	    (request->length % ep->maxpacket == 0))
786f6ce6072SVignesh Raghavendra 		zlp = 1;
787f6ce6072SVignesh Raghavendra 
788f6ce6072SVignesh Raghavendra 	cdns3_ep0_run_transfer(priv_dev, request->dma, request->length, 1, zlp);
789f6ce6072SVignesh Raghavendra 
790f6ce6072SVignesh Raghavendra 	spin_unlock_irqrestore(&priv_dev->lock, flags);
791f6ce6072SVignesh Raghavendra 
792f6ce6072SVignesh Raghavendra 	return ret;
793f6ce6072SVignesh Raghavendra }
794f6ce6072SVignesh Raghavendra 
795f6ce6072SVignesh Raghavendra /**
796f6ce6072SVignesh Raghavendra  * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint
797f6ce6072SVignesh Raghavendra  * @ep: endpoint object
798f6ce6072SVignesh Raghavendra  *
799f6ce6072SVignesh Raghavendra  * Returns 0
800f6ce6072SVignesh Raghavendra  */
cdns3_gadget_ep_set_wedge(struct usb_ep * ep)801f6ce6072SVignesh Raghavendra int cdns3_gadget_ep_set_wedge(struct usb_ep *ep)
802f6ce6072SVignesh Raghavendra {
803f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
804f6ce6072SVignesh Raghavendra 
805f6ce6072SVignesh Raghavendra 	dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name);
806f6ce6072SVignesh Raghavendra 	cdns3_gadget_ep_set_halt(ep, 1);
807f6ce6072SVignesh Raghavendra 	priv_ep->flags |= EP_WEDGE;
808f6ce6072SVignesh Raghavendra 
809f6ce6072SVignesh Raghavendra 	return 0;
810f6ce6072SVignesh Raghavendra }
811f6ce6072SVignesh Raghavendra 
812f6ce6072SVignesh Raghavendra const struct usb_ep_ops cdns3_gadget_ep0_ops = {
813f6ce6072SVignesh Raghavendra 	.enable = cdns3_gadget_ep0_enable,
814f6ce6072SVignesh Raghavendra 	.disable = cdns3_gadget_ep0_disable,
815f6ce6072SVignesh Raghavendra 	.alloc_request = cdns3_gadget_ep_alloc_request,
816f6ce6072SVignesh Raghavendra 	.free_request = cdns3_gadget_ep_free_request,
817f6ce6072SVignesh Raghavendra 	.queue = cdns3_gadget_ep0_queue,
818f6ce6072SVignesh Raghavendra 	.dequeue = cdns3_gadget_ep_dequeue,
819f6ce6072SVignesh Raghavendra 	.set_halt = cdns3_gadget_ep0_set_halt,
820f6ce6072SVignesh Raghavendra 	.set_wedge = cdns3_gadget_ep_set_wedge,
821f6ce6072SVignesh Raghavendra };
822f6ce6072SVignesh Raghavendra 
823f6ce6072SVignesh Raghavendra /**
824f6ce6072SVignesh Raghavendra  * cdns3_ep0_config - Configures default endpoint
825f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
826f6ce6072SVignesh Raghavendra  *
827f6ce6072SVignesh Raghavendra  * Functions sets parameters: maximal packet size and enables interrupts
828f6ce6072SVignesh Raghavendra  */
cdns3_ep0_config(struct cdns3_device * priv_dev)829f6ce6072SVignesh Raghavendra void cdns3_ep0_config(struct cdns3_device *priv_dev)
830f6ce6072SVignesh Raghavendra {
831f6ce6072SVignesh Raghavendra 	struct cdns3_usb_regs __iomem *regs;
832f6ce6072SVignesh Raghavendra 	struct cdns3_endpoint *priv_ep;
833f6ce6072SVignesh Raghavendra 	u32 max_packet_size = 64;
834f6ce6072SVignesh Raghavendra 
835f6ce6072SVignesh Raghavendra 	regs = priv_dev->regs;
836f6ce6072SVignesh Raghavendra 
837f6ce6072SVignesh Raghavendra 	if (priv_dev->gadget.speed == USB_SPEED_SUPER)
838f6ce6072SVignesh Raghavendra 		max_packet_size = 512;
839f6ce6072SVignesh Raghavendra 
840f6ce6072SVignesh Raghavendra 	priv_ep = priv_dev->eps[0];
841f6ce6072SVignesh Raghavendra 
842f6ce6072SVignesh Raghavendra 	if (!list_empty(&priv_ep->pending_req_list)) {
843f6ce6072SVignesh Raghavendra 		struct usb_request *request;
844f6ce6072SVignesh Raghavendra 
845f6ce6072SVignesh Raghavendra 		request = cdns3_next_request(&priv_ep->pending_req_list);
846f6ce6072SVignesh Raghavendra 		list_del_init(&request->list);
847f6ce6072SVignesh Raghavendra 	}
848f6ce6072SVignesh Raghavendra 
849f6ce6072SVignesh Raghavendra 	priv_dev->u1_allowed = 0;
850f6ce6072SVignesh Raghavendra 	priv_dev->u2_allowed = 0;
851f6ce6072SVignesh Raghavendra 
852f6ce6072SVignesh Raghavendra 	priv_dev->gadget.ep0->maxpacket = max_packet_size;
853f6ce6072SVignesh Raghavendra 	cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
854f6ce6072SVignesh Raghavendra 
855f6ce6072SVignesh Raghavendra 	/* init ep out */
856f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, USB_DIR_OUT);
857f6ce6072SVignesh Raghavendra 
858f6ce6072SVignesh Raghavendra 	if (priv_dev->dev_ver >= DEV_VER_V3) {
859f6ce6072SVignesh Raghavendra 		cdns3_set_register_bit(&priv_dev->regs->dtrans,
860f6ce6072SVignesh Raghavendra 				       BIT(0) | BIT(16));
861f6ce6072SVignesh Raghavendra 		cdns3_set_register_bit(&priv_dev->regs->tdl_from_trb,
862f6ce6072SVignesh Raghavendra 				       BIT(0) | BIT(16));
863f6ce6072SVignesh Raghavendra 	}
864f6ce6072SVignesh Raghavendra 
865f6ce6072SVignesh Raghavendra 	writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
866f6ce6072SVignesh Raghavendra 	       &regs->ep_cfg);
867f6ce6072SVignesh Raghavendra 
868f6ce6072SVignesh Raghavendra 	writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN,
869f6ce6072SVignesh Raghavendra 	       &regs->ep_sts_en);
870f6ce6072SVignesh Raghavendra 
871f6ce6072SVignesh Raghavendra 	/* init ep in */
872f6ce6072SVignesh Raghavendra 	cdns3_select_ep(priv_dev, USB_DIR_IN);
873f6ce6072SVignesh Raghavendra 
874f6ce6072SVignesh Raghavendra 	writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size),
875f6ce6072SVignesh Raghavendra 	       &regs->ep_cfg);
876f6ce6072SVignesh Raghavendra 
877f6ce6072SVignesh Raghavendra 	writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, &regs->ep_sts_en);
878f6ce6072SVignesh Raghavendra 
879f6ce6072SVignesh Raghavendra 	cdns3_set_register_bit(&regs->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS);
880f6ce6072SVignesh Raghavendra }
881f6ce6072SVignesh Raghavendra 
882f6ce6072SVignesh Raghavendra /**
883f6ce6072SVignesh Raghavendra  * cdns3_init_ep0 Initializes software endpoint 0 of gadget
884f6ce6072SVignesh Raghavendra  * @priv_dev: extended gadget object
885f6ce6072SVignesh Raghavendra  * @ep_priv: extended endpoint object
886f6ce6072SVignesh Raghavendra  *
887f6ce6072SVignesh Raghavendra  * Returns 0 on success else error code.
888f6ce6072SVignesh Raghavendra  */
cdns3_init_ep0(struct cdns3_device * priv_dev,struct cdns3_endpoint * priv_ep)889f6ce6072SVignesh Raghavendra int cdns3_init_ep0(struct cdns3_device *priv_dev,
890f6ce6072SVignesh Raghavendra 		   struct cdns3_endpoint *priv_ep)
891f6ce6072SVignesh Raghavendra {
892f6ce6072SVignesh Raghavendra 	sprintf(priv_ep->name, "ep0");
893f6ce6072SVignesh Raghavendra 
894f6ce6072SVignesh Raghavendra 	/* fill linux fields */
895f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.ops = &cdns3_gadget_ep0_ops;
896f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.maxburst = 1;
897f6ce6072SVignesh Raghavendra 	usb_ep_set_maxpacket_limit(&priv_ep->endpoint,
898f6ce6072SVignesh Raghavendra 				   CDNS3_EP0_MAX_PACKET_LIMIT);
899f6ce6072SVignesh Raghavendra #ifndef __UBOOT__
900f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.address = 0;
901f6ce6072SVignesh Raghavendra #endif
902f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.caps.type_control = 1;
903f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.caps.dir_in = 1;
904f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.caps.dir_out = 1;
905f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.name = priv_ep->name;
906f6ce6072SVignesh Raghavendra 	priv_ep->endpoint.desc = &cdns3_gadget_ep0_desc;
907f6ce6072SVignesh Raghavendra 	priv_dev->gadget.ep0 = &priv_ep->endpoint;
908f6ce6072SVignesh Raghavendra 	priv_ep->type = USB_ENDPOINT_XFER_CONTROL;
909f6ce6072SVignesh Raghavendra 
910f6ce6072SVignesh Raghavendra 	return cdns3_allocate_trb_pool(priv_ep);
911f6ce6072SVignesh Raghavendra }
912