xref: /openbmc/u-boot/drivers/usb/gadget/aspeed_udc.c (revision 70552e37)
193265845Sneal_liu // SPDX-License-Identifier: GPL-2.0
293265845Sneal_liu /*
393265845Sneal_liu  * Copyright (C) ASPEED Technology Inc.
493265845Sneal_liu  *
593265845Sneal_liu  */
693265845Sneal_liu 
7*70552e37SNeal Liu #include <malloc.h>
893265845Sneal_liu #include <asm/io.h>
993265845Sneal_liu #include <asm/byteorder.h>
10*70552e37SNeal Liu #include <asm/cache.h>
11*70552e37SNeal Liu #include <asm/dma-mapping.h>
1293265845Sneal_liu #include <common.h>
1393265845Sneal_liu #include <config.h>
1493265845Sneal_liu #include <dm.h>
1593265845Sneal_liu #include <fdtdec.h>
1693265845Sneal_liu #include <reset.h>
17*70552e37SNeal Liu #include <linux/usb/ch9.h>
18*70552e37SNeal Liu #include <linux/usb/gadget.h>
19*70552e37SNeal Liu #include <linux/usb/otg.h>
2093265845Sneal_liu 
21*70552e37SNeal Liu #include "aspeed_udc.h"
2293265845Sneal_liu 
2393265845Sneal_liu /* number of endpoints on this UDC */
2493265845Sneal_liu #define UDC_MAX_ENDPOINTS	21
25*70552e37SNeal Liu #define EP_DMA_SIZE		2048
2693265845Sneal_liu 
27*70552e37SNeal Liu /* define to use descriptor mode */
28*70552e37SNeal Liu #define AST_EP_DESC_MODE
2993265845Sneal_liu 
30*70552e37SNeal Liu /* could be 32/256 stages */
31*70552e37SNeal Liu #define AST_EP_NUM_OF_DESC	256
3293265845Sneal_liu 
3393265845Sneal_liu /*************************************************************************************/
3493265845Sneal_liu #define AST_VHUB_CTRL				0x00
3593265845Sneal_liu #define AST_VHUB_CONF				0x04
3693265845Sneal_liu #define AST_VHUB_IER				0x08
3793265845Sneal_liu #define AST_VHUB_ISR				0x0C
3893265845Sneal_liu #define AST_VHUB_EP_ACK_IER			0x10
3993265845Sneal_liu #define AST_VHUB_EP_NAK_IER			0x14
4093265845Sneal_liu #define AST_VHUB_EP_ACK_ISR			0x18
4193265845Sneal_liu #define AST_VHUB_EP_NAK_ISR			0x1C
4293265845Sneal_liu #define AST_VHUB_DEV_RESET			0x20
4393265845Sneal_liu #define AST_VHUB_USB_STS			0x24
4493265845Sneal_liu #define AST_VHUB_EP_DATA			0x28
4593265845Sneal_liu #define AST_VHUB_ISO_TX_FAIL			0x2C
4693265845Sneal_liu #define AST_VHUB_EP0_CTRL			0x30
4793265845Sneal_liu #define AST_VHUB_EP0_DATA_BUFF			0x34
4893265845Sneal_liu #define AST_VHUB_EP1_CTRL			0x38
4993265845Sneal_liu #define AST_VHUB_EP1_STS_CHG			0x3C
5093265845Sneal_liu 
5193265845Sneal_liu #define AST_VHUB_SETUP_DATA0			0x80
5293265845Sneal_liu #define AST_VHUB_SETUP_DATA1			0x84
5393265845Sneal_liu 
5493265845Sneal_liu /*  ************************************************************************************/
5593265845Sneal_liu /* AST_VHUB_CTRL				0x00 */
5693265845Sneal_liu #define ROOT_PHY_CLK_EN				BIT(31)
57*70552e37SNeal Liu #define EP_LONG_DESC_MODE			BIT(18)
5893265845Sneal_liu #define ROOT_PHY_RESET_DIS			BIT(11)
5993265845Sneal_liu #define ROOT_UPSTREAM_EN			BIT(0)
6093265845Sneal_liu 
6193265845Sneal_liu /* AST_VHUB_ISR					0x0C */
6293265845Sneal_liu #define ISR_EP_NAK				BIT(17)
6393265845Sneal_liu #define ISR_EP_ACK_STALL			BIT(16)
6493265845Sneal_liu #define ISR_DEVICE7				BIT(15)
6593265845Sneal_liu #define ISR_DEVICE6				BIT(14)
6693265845Sneal_liu #define ISR_DEVICE5				BIT(13)
6793265845Sneal_liu #define ISR_DEVICE4				BIT(12)
6893265845Sneal_liu #define ISR_DEVICE3				BIT(11)
6993265845Sneal_liu #define ISR_DEVICE2				BIT(10)
7093265845Sneal_liu #define ISR_DEVICE1				BIT(9)
7193265845Sneal_liu #define ISR_SUSPEND_RESUME			BIT(8)
7293265845Sneal_liu #define ISR_BUS_SUSPEND				BIT(7)
7393265845Sneal_liu #define ISR_BUS_RESET				BIT(6)
7493265845Sneal_liu #define ISR_HUB_EP1_IN_DATA_ACK			BIT(5)
7593265845Sneal_liu #define ISR_HUB_EP0_IN_DATA_NAK			BIT(4)
7693265845Sneal_liu #define ISR_HUB_EP0_IN_ACK_STALL		BIT(3)
7793265845Sneal_liu #define ISR_HUB_EP0_OUT_NAK			BIT(2)
7893265845Sneal_liu #define ISR_HUB_EP0_OUT_ACK_STALL		BIT(1)
7993265845Sneal_liu #define ISR_HUB_EP0_SETUP			BIT(0)
8093265845Sneal_liu 
8193265845Sneal_liu /* AST_VHUB_USB_STS				0x24 */
8293265845Sneal_liu #define USB_BUS_HIGH_SPEED			BIT(27)
8393265845Sneal_liu 
8493265845Sneal_liu /* AST_VHUB_EP0_CTRL				0x30 */
8593265845Sneal_liu #define EP0_GET_RX_LEN(x)			(((x) >> 16) & 0x7f)
8693265845Sneal_liu #define EP0_TX_LEN(x)				(((x) & 0x7f) << 8)
8793265845Sneal_liu #define EP0_RX_BUFF_RDY				BIT(2)
8893265845Sneal_liu #define EP0_TX_BUFF_RDY				BIT(1)
8993265845Sneal_liu #define EP0_STALL				BIT(0)
9093265845Sneal_liu 
9193265845Sneal_liu #define AST_UDC_DEV_CTRL			0x00
9293265845Sneal_liu #define AST_UDC_DEV_ISR				0x04
9393265845Sneal_liu #define AST_UDC_DEV_EP0_CTRL			0x08
9493265845Sneal_liu #define AST_UDC_DEV_EP0_DATA_BUFF		0x0C
9593265845Sneal_liu 
9693265845Sneal_liu /*************************************************************************************/
9793265845Sneal_liu #define AST_EP_BASE				0x200
9893265845Sneal_liu #define AST_EP_OFFSET				0x10
9993265845Sneal_liu #define AST_EP_CONFIG				0x00
10093265845Sneal_liu #define AST_EP_DMA_CTRL				0x04
10193265845Sneal_liu #define AST_EP_DMA_BUFF				0x08
10293265845Sneal_liu #define AST_EP_DMA_STS				0x0C
10393265845Sneal_liu 
10493265845Sneal_liu /*************************************************************************************/
10593265845Sneal_liu /* AST_EP_CONFIG				0x00 */
10693265845Sneal_liu #define EP_SET_MAX_PKT(x)			(((x) & 0x3ff) << 16)
10793265845Sneal_liu #define EP_SET_EP_STALL				BIT(12)
10893265845Sneal_liu #define EP_SET_EP_NUM(x)			(((x) & 0xf) << 8)
10993265845Sneal_liu #define EP_TYPE_BULK_IN				(0x2 << 4)
11093265845Sneal_liu #define EP_TYPE_BULK_OUT			(0x3 << 4)
11193265845Sneal_liu #define EP_TYPE_INT_IN				(0x4 << 4)
11293265845Sneal_liu #define EP_TYPE_INT_OUT				(0x5 << 4)
11393265845Sneal_liu #define EP_TYPE_ISO_IN				(0x6 << 4)
11493265845Sneal_liu #define EP_TYPE_ISO_OUT				(0x7 << 4)
11593265845Sneal_liu #define EP_ENABLE				BIT(0)
11693265845Sneal_liu 
11793265845Sneal_liu /* AST_EP_DMA_CTRL				0x04 */
118*70552e37SNeal Liu #define EP_DMA_IN_LONG_MODE			BIT(3)
119*70552e37SNeal Liu #define EP_RESET_DESC_OP			BIT(2)
12093265845Sneal_liu #define EP_SINGLE_DESC_MODE			BIT(1)
121*70552e37SNeal Liu #define EP_DESC_OP_ENABLE			BIT(0)
12293265845Sneal_liu 
12393265845Sneal_liu /* AST_EP_DMA_STS				0x0C */
12493265845Sneal_liu #define AST_EP_TX_DATA_BYTE(x)			(((x) & 0x3ff) << 16)
12593265845Sneal_liu #define AST_EP_START_TRANS			BIT(0)
12693265845Sneal_liu 
127*70552e37SNeal Liu /* Desc W1 IN */
128*70552e37SNeal Liu #define VHUB_DSC1_IN_INTERRUPT			BIT(31)
129*70552e37SNeal Liu #define VHUB_DSC1_IN_SPID_DATA0			(0 << 14)
130*70552e37SNeal Liu #define VHUB_DSC1_IN_SPID_DATA2			BIT(14)
131*70552e37SNeal Liu #define VHUB_DSC1_IN_SPID_DATA1			(2 << 14)
132*70552e37SNeal Liu #define VHUB_DSC1_IN_SPID_MDATA			(3 << 14)
133*70552e37SNeal Liu #define VHUB_DSC1_IN_SET_LEN(x)			((x) & 0xfff)
134*70552e37SNeal Liu #define VHUB_DSC1_IN_LEN(x)			((x) & 0xfff)
135*70552e37SNeal Liu #define VHUB_DSC1_OUT_LEN(x)			((x) & 0x7ff)
13693265845Sneal_liu 
137*70552e37SNeal Liu #define AST_SETUP_DEBUG
138*70552e37SNeal Liu #define AST_UDC_DEBUG
139*70552e37SNeal Liu #define AST_EP_DEBUG
14093265845Sneal_liu 
141*70552e37SNeal Liu #ifdef AST_SETUP_DEBUG
142*70552e37SNeal Liu #define SETUP_DBG(fmt, args...) pr_debug("%s() " fmt, __func__, ##args)
143*70552e37SNeal Liu #else
144*70552e37SNeal Liu #define SETUP_DBG(fmt, args...)
145*70552e37SNeal Liu #endif
146*70552e37SNeal Liu 
147*70552e37SNeal Liu #ifdef AST_UDC_DEBUG
148*70552e37SNeal Liu #define UDC_DBG(fmt, args...) pr_debug("%s() " fmt, __func__, ##args)
149*70552e37SNeal Liu #else
150*70552e37SNeal Liu #define UDC_DBG(fmt, args...)
151*70552e37SNeal Liu #endif
152*70552e37SNeal Liu 
153*70552e37SNeal Liu #ifdef AST_EP_DEBUG
154*70552e37SNeal Liu #define EP_DBG(fmt, args...) pr_debug("%s() " fmt, __func__, ##args)
155*70552e37SNeal Liu #else
156*70552e37SNeal Liu #define EP_DBG(fmt, args...)
157*70552e37SNeal Liu #endif
158*70552e37SNeal Liu 
aspeed_udc_done(struct aspeed_udc_ep * ep,struct aspeed_udc_request * req,int status)159*70552e37SNeal Liu static void aspeed_udc_done(struct aspeed_udc_ep *ep,
160*70552e37SNeal Liu 			    struct aspeed_udc_request *req, int status)
16193265845Sneal_liu {
162*70552e37SNeal Liu 	EP_DBG("%s len: (%d/%d) buf: %p, dir: %s\n",
163*70552e37SNeal Liu 	       ep->ep.name, req->req.actual, req->req.length, req->req.buf,
164*70552e37SNeal Liu 	       ep->ep_dir ? "IN" : "OUT");
16593265845Sneal_liu 
166*70552e37SNeal Liu 	list_del(&req->queue);
16793265845Sneal_liu 
168*70552e37SNeal Liu 	if (req->req.status == -EINPROGRESS)
169*70552e37SNeal Liu 		req->req.status = status;
17093265845Sneal_liu 	else
171*70552e37SNeal Liu 		status = req->req.status;
17293265845Sneal_liu 
173*70552e37SNeal Liu 	if (status && status != -ESHUTDOWN)
174*70552e37SNeal Liu 		EP_DBG("%s done %p, status %d\n", ep->ep.name, req, status);
17593265845Sneal_liu 
176*70552e37SNeal Liu 	usb_gadget_giveback_request(&ep->ep, &req->req);
17793265845Sneal_liu }
17893265845Sneal_liu 
ast_udc_ep0_data_tx(struct aspeed_udc_priv * udc,u8 * tx_data,u32 len)179*70552e37SNeal Liu void ast_udc_ep0_data_tx(struct aspeed_udc_priv *udc, u8 *tx_data, u32 len)
18093265845Sneal_liu {
181*70552e37SNeal Liu 	u32 reg = udc->udc_base;
18293265845Sneal_liu 
183*70552e37SNeal Liu 	if (len) {
184*70552e37SNeal Liu 		memcpy(udc->ep0_ctrl_buf, tx_data, len);
18593265845Sneal_liu 
186*70552e37SNeal Liu 		writel(udc->ep0_ctrl_dma, reg + AST_VHUB_EP0_DATA_BUFF);
187*70552e37SNeal Liu 		writel(EP0_TX_LEN(len), reg + AST_VHUB_EP0_CTRL);
188*70552e37SNeal Liu 		writel(EP0_TX_LEN(len) | EP0_TX_BUFF_RDY,
189*70552e37SNeal Liu 		       reg + AST_VHUB_EP0_CTRL);
19093265845Sneal_liu 
191*70552e37SNeal Liu 		udc->is_udc_control_tx = 1;
19293265845Sneal_liu 
19393265845Sneal_liu 	} else {
194*70552e37SNeal Liu 		writel(EP0_TX_BUFF_RDY, reg + AST_VHUB_EP0_CTRL);
19593265845Sneal_liu 	}
19693265845Sneal_liu }
19793265845Sneal_liu 
aspeed_udc_getstatus(struct aspeed_udc_priv * udc)198*70552e37SNeal Liu static void aspeed_udc_getstatus(struct aspeed_udc_priv *udc)
19993265845Sneal_liu {
200*70552e37SNeal Liu 	u32 reg = udc->udc_base;
201*70552e37SNeal Liu 	u32 status = 0;
202*70552e37SNeal Liu 	int epnum;
20393265845Sneal_liu 
204*70552e37SNeal Liu 	switch (udc->root_setup->bRequestType & USB_RECIP_MASK) {
205*70552e37SNeal Liu 	case USB_RECIP_DEVICE:
206*70552e37SNeal Liu 		/* Get device status */
207*70552e37SNeal Liu 		status = 1 << USB_DEVICE_SELF_POWERED;
208*70552e37SNeal Liu 		break;
209*70552e37SNeal Liu 	case USB_RECIP_INTERFACE:
210*70552e37SNeal Liu 		break;
211*70552e37SNeal Liu 	case USB_RECIP_ENDPOINT:
212*70552e37SNeal Liu 		epnum = udc->root_setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
213*70552e37SNeal Liu 		status = udc->ep[epnum].stopped;
214*70552e37SNeal Liu 		break;
215*70552e37SNeal Liu 	default:
216*70552e37SNeal Liu 		goto stall;
217*70552e37SNeal Liu 	}
218*70552e37SNeal Liu 
219*70552e37SNeal Liu 	EP_DBG("%s: response status: %d\n", __func__, status);
220*70552e37SNeal Liu 	ast_udc_ep0_data_tx(udc, (u8 *)&status, sizeof(status));
221*70552e37SNeal Liu 
22293265845Sneal_liu 	return;
223*70552e37SNeal Liu 
224*70552e37SNeal Liu stall:
225*70552e37SNeal Liu 	pr_err("Can't respond to %s request\n", __func__);
226*70552e37SNeal Liu 	writel(readl(reg + AST_VHUB_EP0_CTRL) | EP0_STALL,
227*70552e37SNeal Liu 	       reg + AST_VHUB_EP0_CTRL);
22893265845Sneal_liu }
22993265845Sneal_liu 
aspeed_udc_nuke(struct aspeed_udc_ep * ep,int status)230*70552e37SNeal Liu static void aspeed_udc_nuke(struct aspeed_udc_ep *ep, int status)
23193265845Sneal_liu {
232*70552e37SNeal Liu 	if (!&ep->queue)
23393265845Sneal_liu 		return;
234*70552e37SNeal Liu 
235*70552e37SNeal Liu 	while (!list_empty(&ep->queue)) {
236*70552e37SNeal Liu 		struct aspeed_udc_request *req;
237*70552e37SNeal Liu 
238*70552e37SNeal Liu 		req = list_entry(ep->queue.next, struct aspeed_udc_request,
239*70552e37SNeal Liu 				 queue);
240*70552e37SNeal Liu 		aspeed_udc_done(ep, req, status);
241*70552e37SNeal Liu 	}
24293265845Sneal_liu }
24393265845Sneal_liu 
aspeed_udc_setup_handle(struct aspeed_udc_priv * udc)244*70552e37SNeal Liu static void aspeed_udc_setup_handle(struct aspeed_udc_priv *udc)
24593265845Sneal_liu {
246*70552e37SNeal Liu 	u8 bRequestType = udc->root_setup->bRequestType;
247*70552e37SNeal Liu 	u8 bRequest = udc->root_setup->bRequest;
248*70552e37SNeal Liu 	u16 ep_num = udc->root_setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
249*70552e37SNeal Liu 	struct aspeed_udc_request *req;
250*70552e37SNeal Liu 	u32 base = udc->udc_base;
251*70552e37SNeal Liu 	int i = 0;
252*70552e37SNeal Liu 	int ret;
25393265845Sneal_liu 
254*70552e37SNeal Liu 	SETUP_DBG("%s: %x, %s: %x, %s: %x, %s: %x, %s: %d\n",
255*70552e37SNeal Liu 		  "bRequestType", bRequestType, "bRequest", bRequest,
256*70552e37SNeal Liu 		  "wValue", udc->root_setup->wValue,
257*70552e37SNeal Liu 		  "wIndex", udc->root_setup->wIndex,
258*70552e37SNeal Liu 		  "wLength", udc->root_setup->wLength);
25993265845Sneal_liu 
260*70552e37SNeal Liu 	list_for_each_entry(req, &udc->ep[0].queue, queue) {
261*70552e37SNeal Liu 		i++;
262*70552e37SNeal Liu 		pr_err("[%d] there is req %x in ep0 queue\n", i, (u32)req);
26393265845Sneal_liu 	}
26493265845Sneal_liu 
265*70552e37SNeal Liu 	aspeed_udc_nuke(&udc->ep[0], -ETIMEDOUT);
26693265845Sneal_liu 
267*70552e37SNeal Liu 	udc->ep[0].ep_dir = bRequestType & USB_DIR_IN;
26893265845Sneal_liu 
269*70552e37SNeal Liu 	if ((bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
270*70552e37SNeal Liu 		switch (bRequest) {
27193265845Sneal_liu 		case USB_REQ_SET_ADDRESS:
272*70552e37SNeal Liu 			SETUP_DBG("Set addr: %x\n", udc->root_setup->wValue);
273*70552e37SNeal Liu 
274*70552e37SNeal Liu 			if (readl(base + AST_VHUB_USB_STS) &
275*70552e37SNeal Liu 			    USB_BUS_HIGH_SPEED)
276*70552e37SNeal Liu 				udc->gadget.speed = USB_SPEED_HIGH;
277*70552e37SNeal Liu 			else
278*70552e37SNeal Liu 				udc->gadget.speed = USB_SPEED_FULL;
279*70552e37SNeal Liu 
280*70552e37SNeal Liu 			writel(udc->root_setup->wValue, base + AST_VHUB_CONF);
281*70552e37SNeal Liu 			writel(EP0_TX_BUFF_RDY, base + AST_VHUB_EP0_CTRL);
28293265845Sneal_liu 			break;
28393265845Sneal_liu 
284*70552e37SNeal Liu 		case USB_REQ_CLEAR_FEATURE:
285*70552e37SNeal Liu 			SETUP_DBG("USB_REQ_CLEAR_FEATURE ep: %d\n", ep_num);
286*70552e37SNeal Liu 			writel(EP0_TX_BUFF_RDY, base + AST_VHUB_EP0_CTRL);
287*70552e37SNeal Liu 			break;
288*70552e37SNeal Liu 
289*70552e37SNeal Liu 		case USB_REQ_SET_FEATURE:
290*70552e37SNeal Liu 			SETUP_DBG("USB_REQ_SET_FEATURE ep: %d\n", ep_num);
291*70552e37SNeal Liu 			break;
292*70552e37SNeal Liu 
293*70552e37SNeal Liu 		case USB_REQ_GET_STATUS:
294*70552e37SNeal Liu 			SETUP_DBG("USB_REQ_GET_STATUS\n");
295*70552e37SNeal Liu 			aspeed_udc_getstatus(udc);
29693265845Sneal_liu 			break;
29793265845Sneal_liu 
29893265845Sneal_liu 		default:
299*70552e37SNeal Liu 			ret = udc->gadget_driver->setup(&udc->gadget,
300*70552e37SNeal Liu 				udc->root_setup);
301*70552e37SNeal Liu 			if (ret < 0)
302*70552e37SNeal Liu 				pr_err("Gadget setup failed, ret: 0x%x\n",
303*70552e37SNeal Liu 				       ret);
30493265845Sneal_liu 			break;
30593265845Sneal_liu 		}
30693265845Sneal_liu 
30793265845Sneal_liu 	} else {
308*70552e37SNeal Liu 		SETUP_DBG("non-standard request type\n");
309*70552e37SNeal Liu 		ret = udc->gadget_driver->setup(&udc->gadget, udc->root_setup);
310*70552e37SNeal Liu 		if (ret < 0)
311*70552e37SNeal Liu 			pr_err("Gadget setup failed, ret: 0x%x\n", ret);
312*70552e37SNeal Liu 	}
31393265845Sneal_liu }
31493265845Sneal_liu 
aspeed_udc_ep0_queue(struct aspeed_udc_ep * ep,struct aspeed_udc_request * req)315*70552e37SNeal Liu static void aspeed_udc_ep0_queue(struct aspeed_udc_ep *ep,
316*70552e37SNeal Liu 				 struct aspeed_udc_request *req)
31793265845Sneal_liu {
318*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = ep->udc;
319*70552e37SNeal Liu 	u16 tx_len;
320*70552e37SNeal Liu 	u32 reg;
321*70552e37SNeal Liu 
322*70552e37SNeal Liu 	if ((req->req.length - req->req.actual) > ep->ep.maxpacket)
323*70552e37SNeal Liu 		tx_len = ep->ep.maxpacket;
324*70552e37SNeal Liu 	else
325*70552e37SNeal Liu 		tx_len = req->req.length - req->req.actual;
326*70552e37SNeal Liu 
327*70552e37SNeal Liu 	writel(req->req.dma + req->req.actual,
328*70552e37SNeal Liu 	       udc->udc_base + AST_VHUB_EP0_DATA_BUFF);
329*70552e37SNeal Liu 
330*70552e37SNeal Liu 	SETUP_DBG("ep0 REQ buf: %x, dma: %x , txlen: %d (%d/%d) ,dir: %s\n",
331*70552e37SNeal Liu 		  (u32)req->req.buf, req->req.dma + req->req.actual,
332*70552e37SNeal Liu 		  tx_len, req->req.actual, req->req.length,
333*70552e37SNeal Liu 		  ep->ep_dir ? "IN" : "OUT");
334*70552e37SNeal Liu 
335*70552e37SNeal Liu 	reg = udc->udc_base + AST_VHUB_EP0_CTRL;
336*70552e37SNeal Liu 	if (ep->ep_dir) {
337*70552e37SNeal Liu 		req->req.actual += tx_len;
338*70552e37SNeal Liu 		writel(EP0_TX_LEN(tx_len), reg);
339*70552e37SNeal Liu 		writel(EP0_TX_LEN(tx_len) | EP0_TX_BUFF_RDY, reg);
340*70552e37SNeal Liu 
341*70552e37SNeal Liu 	} else {
342*70552e37SNeal Liu 		if (!req->req.length) {
343*70552e37SNeal Liu 			writel(EP0_TX_BUFF_RDY, reg);
344*70552e37SNeal Liu 			ep->ep_dir = 0x80;
345*70552e37SNeal Liu 		} else {
346*70552e37SNeal Liu 			writel(EP0_RX_BUFF_RDY, reg);
347*70552e37SNeal Liu 		}
348*70552e37SNeal Liu 	}
349*70552e37SNeal Liu }
350*70552e37SNeal Liu 
aspeed_udc_ep0_rx(struct aspeed_udc_priv * udc)351*70552e37SNeal Liu static void aspeed_udc_ep0_rx(struct aspeed_udc_priv *udc)
352*70552e37SNeal Liu {
353*70552e37SNeal Liu 	SETUP_DBG("%s: enter\n", __func__);
354*70552e37SNeal Liu 
355*70552e37SNeal Liu 	writel(udc->ep0_ctrl_dma, udc->udc_base + AST_VHUB_EP0_DATA_BUFF);
356*70552e37SNeal Liu 	writel(EP0_RX_BUFF_RDY, udc->udc_base + AST_VHUB_EP0_CTRL);
357*70552e37SNeal Liu }
358*70552e37SNeal Liu 
aspeed_udc_ep0_tx(struct aspeed_udc_priv * udc)359*70552e37SNeal Liu static void aspeed_udc_ep0_tx(struct aspeed_udc_priv *udc)
360*70552e37SNeal Liu {
361*70552e37SNeal Liu 	SETUP_DBG("%s: enter\n", __func__);
362*70552e37SNeal Liu 
363*70552e37SNeal Liu 	writel(udc->ep0_ctrl_dma, udc->udc_base + AST_VHUB_EP0_DATA_BUFF);
364*70552e37SNeal Liu 	writel(EP0_TX_BUFF_RDY, udc->udc_base + AST_VHUB_EP0_CTRL);
365*70552e37SNeal Liu }
366*70552e37SNeal Liu 
aspeed_udc_ep0_in(struct aspeed_udc_priv * udc)367*70552e37SNeal Liu static void aspeed_udc_ep0_in(struct aspeed_udc_priv *udc)
368*70552e37SNeal Liu {
369*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = &udc->ep[0];
370*70552e37SNeal Liu 	struct aspeed_udc_request *req;
371*70552e37SNeal Liu 
372*70552e37SNeal Liu 	if (list_empty(&ep->queue)) {
373*70552e37SNeal Liu 		if (udc->is_udc_control_tx) {
374*70552e37SNeal Liu 			SETUP_DBG("is_udc_control_tx\n");
375*70552e37SNeal Liu 			aspeed_udc_ep0_rx(udc);
376*70552e37SNeal Liu 			udc->is_udc_control_tx = 0;
377*70552e37SNeal Liu 		}
378*70552e37SNeal Liu 		return;
379*70552e37SNeal Liu 
380*70552e37SNeal Liu 	} else {
381*70552e37SNeal Liu 		req = list_entry(ep->queue.next, struct aspeed_udc_request,
382*70552e37SNeal Liu 				 queue);
383*70552e37SNeal Liu 	}
384*70552e37SNeal Liu 
385*70552e37SNeal Liu 	SETUP_DBG("req=%x (%d/%d)\n", (u32)req, req->req.length,
386*70552e37SNeal Liu 		  req->req.actual);
387*70552e37SNeal Liu 
388*70552e37SNeal Liu 	if (req->req.length == req->req.actual) {
389*70552e37SNeal Liu 		if (req->req.length)
390*70552e37SNeal Liu 			aspeed_udc_ep0_rx(udc);
391*70552e37SNeal Liu 
392*70552e37SNeal Liu 		if (ep->ep_dir)
393*70552e37SNeal Liu 			aspeed_udc_done(ep, req, 0);
394*70552e37SNeal Liu 
395*70552e37SNeal Liu 	} else {
396*70552e37SNeal Liu 		aspeed_udc_ep0_queue(ep, req);
397*70552e37SNeal Liu 	}
398*70552e37SNeal Liu }
399*70552e37SNeal Liu 
aspeed_udc_ep0_out(struct aspeed_udc_priv * udc)400*70552e37SNeal Liu void aspeed_udc_ep0_out(struct aspeed_udc_priv *udc)
401*70552e37SNeal Liu {
402*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = &udc->ep[0];
403*70552e37SNeal Liu 	struct aspeed_udc_request *req;
404*70552e37SNeal Liu 	u16 rx_len;
405*70552e37SNeal Liu 
406*70552e37SNeal Liu 	rx_len = EP0_GET_RX_LEN(readl(udc->udc_base + AST_VHUB_EP0_CTRL));
407*70552e37SNeal Liu 
408*70552e37SNeal Liu 	if (list_empty(&ep->queue))
409*70552e37SNeal Liu 		return;
410*70552e37SNeal Liu 
411*70552e37SNeal Liu 	req = list_entry(ep->queue.next, struct aspeed_udc_request,
412*70552e37SNeal Liu 			 queue);
413*70552e37SNeal Liu 
414*70552e37SNeal Liu 	req->req.actual += rx_len;
415*70552e37SNeal Liu 
416*70552e37SNeal Liu 	SETUP_DBG("req %x (%d/%d)\n", (u32)req, req->req.length,
417*70552e37SNeal Liu 		  req->req.actual);
418*70552e37SNeal Liu 
419*70552e37SNeal Liu 	if (rx_len < ep->ep.maxpacket ||
420*70552e37SNeal Liu 	    req->req.actual == req->req.length) {
421*70552e37SNeal Liu 		aspeed_udc_ep0_tx(udc);
422*70552e37SNeal Liu 		if (!ep->ep_dir)
423*70552e37SNeal Liu 			aspeed_udc_done(ep, req, 0);
424*70552e37SNeal Liu 
425*70552e37SNeal Liu 	} else {
426*70552e37SNeal Liu 		ep->ep_dir = 0;
427*70552e37SNeal Liu 		aspeed_udc_ep0_queue(ep, req);
428*70552e37SNeal Liu 	}
429*70552e37SNeal Liu }
430*70552e37SNeal Liu 
aspeed_dma_descriptor_setup(struct aspeed_udc_ep * ep,unsigned int dma_address,u32 tx_len,struct aspeed_udc_request * req)431*70552e37SNeal Liu static int aspeed_dma_descriptor_setup(struct aspeed_udc_ep *ep,
432*70552e37SNeal Liu 				       unsigned int dma_address, u32 tx_len,
433*70552e37SNeal Liu 				       struct aspeed_udc_request *req)
434*70552e37SNeal Liu {
435*70552e37SNeal Liu 	u32 packet_len;
436*70552e37SNeal Liu 	u32 chunk;
437*70552e37SNeal Liu 	int i;
438*70552e37SNeal Liu 
439*70552e37SNeal Liu 	if (!ep->dma_desc_list) {
440*70552e37SNeal Liu 		pr_err("%s: %s %s\n", __func__, ep->ep.name,
441*70552e37SNeal Liu 		       "failed due to empty DMA descriptor list");
442*70552e37SNeal Liu 		return -1;
443*70552e37SNeal Liu 	}
444*70552e37SNeal Liu 
445*70552e37SNeal Liu 	packet_len = tx_len;
446*70552e37SNeal Liu 	chunk = ep->chunk_max;
447*70552e37SNeal Liu 	i = 0;
448*70552e37SNeal Liu 	while (packet_len > 0) {
449*70552e37SNeal Liu 		EP_DBG("%s: %s:%d, %s:0x%x, %s:%d %s:%d (%s:0x%x)\n",
450*70552e37SNeal Liu 		       ep->ep.name,
451*70552e37SNeal Liu 		       "wptr", ep->dma_desc_list_wptr,
452*70552e37SNeal Liu 		       "dma_address", dma_address,
453*70552e37SNeal Liu 		       "packet_len", packet_len,
454*70552e37SNeal Liu 		       "chunk", chunk,
455*70552e37SNeal Liu 		       "tx_len", tx_len);
456*70552e37SNeal Liu 
457*70552e37SNeal Liu 		ep->dma_desc_list[ep->dma_desc_list_wptr].des_0 =
458*70552e37SNeal Liu 			(dma_address + (i * chunk));
459*70552e37SNeal Liu 
460*70552e37SNeal Liu 		/* last packet */
461*70552e37SNeal Liu 		if (packet_len <= chunk)
462*70552e37SNeal Liu 			ep->dma_desc_list[ep->dma_desc_list_wptr].des_1 =
463*70552e37SNeal Liu 				packet_len | VHUB_DSC1_IN_INTERRUPT;
464*70552e37SNeal Liu 		else
465*70552e37SNeal Liu 			ep->dma_desc_list[ep->dma_desc_list_wptr].des_1 =
466*70552e37SNeal Liu 				chunk;
467*70552e37SNeal Liu 
468*70552e37SNeal Liu 		EP_DBG("wptr:%d, req:%x, dma_desc_list 0x%x 0x%x\n",
469*70552e37SNeal Liu 		       ep->dma_desc_list_wptr, (u32)req,
470*70552e37SNeal Liu 		       ep->dma_desc_list[ep->dma_desc_list_wptr].des_0,
471*70552e37SNeal Liu 		       ep->dma_desc_list[ep->dma_desc_list_wptr].des_1);
472*70552e37SNeal Liu 
473*70552e37SNeal Liu 		if (i == 0)
474*70552e37SNeal Liu 			req->saved_dma_wptr = ep->dma_desc_list_wptr;
475*70552e37SNeal Liu 
476*70552e37SNeal Liu 		ep->dma_desc_list_wptr++;
477*70552e37SNeal Liu 		i++;
478*70552e37SNeal Liu 		if (ep->dma_desc_list_wptr >= AST_EP_NUM_OF_DESC)
479*70552e37SNeal Liu 			ep->dma_desc_list_wptr = 0;
480*70552e37SNeal Liu 		if (packet_len >= chunk)
481*70552e37SNeal Liu 			packet_len -= chunk;
482*70552e37SNeal Liu 		else
483*70552e37SNeal Liu 			break;
484*70552e37SNeal Liu 	}
485*70552e37SNeal Liu 
486*70552e37SNeal Liu 	if (req->req.zero)
487*70552e37SNeal Liu 		pr_info("TODO: Send an extra zero length packet\n");
488*70552e37SNeal Liu 
489*70552e37SNeal Liu 	return 0;
490*70552e37SNeal Liu }
491*70552e37SNeal Liu 
aspeed_udc_ep_dma_desc_mode(struct aspeed_udc_ep * ep,struct aspeed_udc_request * req)492*70552e37SNeal Liu static void aspeed_udc_ep_dma_desc_mode(struct aspeed_udc_ep *ep,
493*70552e37SNeal Liu 					struct aspeed_udc_request *req)
494*70552e37SNeal Liu {
495*70552e37SNeal Liu 	u32 max_req_size;
496*70552e37SNeal Liu 	u32 dma_conf;
497*70552e37SNeal Liu 	u32 tx_len;
498*70552e37SNeal Liu 	int ret;
499*70552e37SNeal Liu 
500*70552e37SNeal Liu 	max_req_size = ep->chunk_max * (AST_EP_NUM_OF_DESC - 1);
501*70552e37SNeal Liu 
502*70552e37SNeal Liu 	if ((req->req.length - req->req.actual) > max_req_size)
503*70552e37SNeal Liu 		tx_len = max_req_size;
504*70552e37SNeal Liu 	else
505*70552e37SNeal Liu 		tx_len = req->req.length - req->req.actual;
506*70552e37SNeal Liu 
507*70552e37SNeal Liu 	EP_DBG("%s: req(0x%x) dma:0x%x, len:0x%x, actual:0x%x, %s:%d, %s:%x\n",
508*70552e37SNeal Liu 	       ep->ep.name, (u32)req, req->req.dma, req->req.length,
509*70552e37SNeal Liu 	       req->req.actual, "tx_len", tx_len,
510*70552e37SNeal Liu 	       "dir", ep->ep_dir);
511*70552e37SNeal Liu 
512*70552e37SNeal Liu 	if ((req->req.dma % 4) != 0) {
513*70552e37SNeal Liu 		pr_err("Not supported=> 1: %s : %x len (%d/%d) dir %x\n",
514*70552e37SNeal Liu 		       ep->ep.name, req->req.dma, req->req.actual,
515*70552e37SNeal Liu 		       req->req.length, ep->ep_dir);
516*70552e37SNeal Liu 	} else {
517*70552e37SNeal Liu 		writel(EP_RESET_DESC_OP, ep->ep_base + AST_EP_DMA_CTRL);
518*70552e37SNeal Liu 		ret = aspeed_dma_descriptor_setup(ep, req->req.dma +
519*70552e37SNeal Liu 						  req->req.actual,
520*70552e37SNeal Liu 						  tx_len, req);
521*70552e37SNeal Liu 		if (!ret)
522*70552e37SNeal Liu 			req->actual_dma_length += tx_len;
523*70552e37SNeal Liu 
524*70552e37SNeal Liu 		writel(ep->dma_desc_dma_handle, ep->ep_base + AST_EP_DMA_BUFF);
525*70552e37SNeal Liu 		dma_conf = EP_DESC_OP_ENABLE;
526*70552e37SNeal Liu 		if (ep->ep_dir)
527*70552e37SNeal Liu 			dma_conf |= EP_DMA_IN_LONG_MODE;
528*70552e37SNeal Liu 		writel(dma_conf, ep->ep_base + AST_EP_DMA_CTRL);
529*70552e37SNeal Liu 
530*70552e37SNeal Liu 		writel(ep->dma_desc_list_wptr,
531*70552e37SNeal Liu 		       ep->ep_base + AST_EP_DMA_STS);
532*70552e37SNeal Liu 	}
533*70552e37SNeal Liu }
534*70552e37SNeal Liu 
aspeed_udc_ep_dma(struct aspeed_udc_ep * ep,struct aspeed_udc_request * req)535*70552e37SNeal Liu static void aspeed_udc_ep_dma(struct aspeed_udc_ep *ep,
536*70552e37SNeal Liu 			      struct aspeed_udc_request *req)
537*70552e37SNeal Liu {
538*70552e37SNeal Liu 	u16 tx_len;
539*70552e37SNeal Liu 
540*70552e37SNeal Liu 	if ((req->req.length - req->req.actual) > ep->ep.maxpacket)
541*70552e37SNeal Liu 		tx_len = ep->ep.maxpacket;
542*70552e37SNeal Liu 	else
543*70552e37SNeal Liu 		tx_len = req->req.length - req->req.actual;
544*70552e37SNeal Liu 
545*70552e37SNeal Liu 	EP_DBG("req(0x%x) dma: 0x%x, length: 0x%x, actual: 0x%x\n",
546*70552e37SNeal Liu 	       (u32)req, req->req.dma, req->req.length, req->req.actual);
547*70552e37SNeal Liu 
548*70552e37SNeal Liu 	EP_DBG("%s: len: %d, dir(0x%x): %s\n",
549*70552e37SNeal Liu 	       ep->ep.name, tx_len, ep->ep_dir,
550*70552e37SNeal Liu 	       ep->ep_dir ? "IN" : "OUT");
551*70552e37SNeal Liu 
552*70552e37SNeal Liu 	writel(req->req.dma + req->req.actual, ep->ep_base + AST_EP_DMA_BUFF);
553*70552e37SNeal Liu 	writel(AST_EP_TX_DATA_BYTE(tx_len), ep->ep_base + AST_EP_DMA_STS);
554*70552e37SNeal Liu 	writel(AST_EP_TX_DATA_BYTE(tx_len) | AST_EP_START_TRANS,
555*70552e37SNeal Liu 	       ep->ep_base + AST_EP_DMA_STS);
556*70552e37SNeal Liu }
557*70552e37SNeal Liu 
aspeed_udc_ep_enable(struct usb_ep * _ep,const struct usb_endpoint_descriptor * desc)558*70552e37SNeal Liu static int aspeed_udc_ep_enable(struct usb_ep *_ep,
559*70552e37SNeal Liu 				const struct usb_endpoint_descriptor *desc)
560*70552e37SNeal Liu {
561*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = container_of(_ep, struct aspeed_udc_ep, ep);
562*70552e37SNeal Liu 	u16 nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
563*70552e37SNeal Liu 	u16 maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
564*70552e37SNeal Liu 	u8 epnum = usb_endpoint_num(desc);
565*70552e37SNeal Liu 	u32 ep_conf = 0;
566*70552e37SNeal Liu 	u8 dir_in;
567*70552e37SNeal Liu 	u8 type;
568*70552e37SNeal Liu 
569*70552e37SNeal Liu 	EP_DBG("%s, set ep #%d, maxpacket %d ,wmax %d trans:%d\n", ep->ep.name,
570*70552e37SNeal Liu 	       epnum, maxpacket, le16_to_cpu(desc->wMaxPacketSize), nr_trans);
571*70552e37SNeal Liu 
572*70552e37SNeal Liu 	if (!_ep || !ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
573*70552e37SNeal Liu 		pr_err("bad ep or descriptor %s %d, %s: %d, %s: %d\n",
574*70552e37SNeal Liu 		       _ep->name, desc->bDescriptorType,
575*70552e37SNeal Liu 		       "maxpacket", maxpacket,
576*70552e37SNeal Liu 		       "ep maxpacket", ep->ep.maxpacket);
577*70552e37SNeal Liu 		return -EINVAL;
578*70552e37SNeal Liu 	}
579*70552e37SNeal Liu 
580*70552e37SNeal Liu 	ep->ep.desc = desc;
581*70552e37SNeal Liu 	ep->stopped = 0;
582*70552e37SNeal Liu 	ep->ep.maxpacket = maxpacket;
583*70552e37SNeal Liu 
584*70552e37SNeal Liu 	if (maxpacket > 1024) {
585*70552e37SNeal Liu 		pr_err("maxpacket is out-of-range: 0x%x\n", maxpacket);
586*70552e37SNeal Liu 		maxpacket = 1024;
587*70552e37SNeal Liu 	}
588*70552e37SNeal Liu 
589*70552e37SNeal Liu 	if (maxpacket == 1024)
590*70552e37SNeal Liu 		ep_conf = 0;
591*70552e37SNeal Liu 	else
592*70552e37SNeal Liu 		ep_conf = EP_SET_MAX_PKT(maxpacket);
593*70552e37SNeal Liu 
594*70552e37SNeal Liu 	ep_conf |= EP_SET_EP_NUM(epnum);
595*70552e37SNeal Liu 
596*70552e37SNeal Liu 	type = usb_endpoint_type(desc);
597*70552e37SNeal Liu 	dir_in = usb_endpoint_dir_in(desc);
598*70552e37SNeal Liu 	ep->ep_dir = dir_in;
599*70552e37SNeal Liu 
600*70552e37SNeal Liu 	ep->chunk_max = ep->ep.maxpacket;
601*70552e37SNeal Liu 	if (ep->ep_dir) {
602*70552e37SNeal Liu 		ep->chunk_max <<= 3;
603*70552e37SNeal Liu 		while (ep->chunk_max > 4095)
604*70552e37SNeal Liu 			ep->chunk_max -= ep->ep.maxpacket;
605*70552e37SNeal Liu 	}
606*70552e37SNeal Liu 
607*70552e37SNeal Liu 	EP_DBG("epnum %d, type %d, dir_in %d\n", epnum, type, dir_in);
608*70552e37SNeal Liu 	switch (type) {
609*70552e37SNeal Liu 	case USB_ENDPOINT_XFER_ISOC:
610*70552e37SNeal Liu 		if (dir_in)
611*70552e37SNeal Liu 			ep_conf |= EP_TYPE_ISO_IN;
612*70552e37SNeal Liu 		else
613*70552e37SNeal Liu 			ep_conf |= EP_TYPE_ISO_OUT;
614*70552e37SNeal Liu 		break;
615*70552e37SNeal Liu 	case USB_ENDPOINT_XFER_BULK:
616*70552e37SNeal Liu 		if (dir_in)
617*70552e37SNeal Liu 			ep_conf |= EP_TYPE_BULK_IN;
618*70552e37SNeal Liu 		else
619*70552e37SNeal Liu 			ep_conf |= EP_TYPE_BULK_OUT;
620*70552e37SNeal Liu 		break;
621*70552e37SNeal Liu 	case USB_ENDPOINT_XFER_INT:
622*70552e37SNeal Liu 		if (dir_in)
623*70552e37SNeal Liu 			ep_conf |= EP_TYPE_INT_IN;
624*70552e37SNeal Liu 		else
625*70552e37SNeal Liu 			ep_conf |= EP_TYPE_INT_OUT;
626*70552e37SNeal Liu 		break;
627*70552e37SNeal Liu 	}
628*70552e37SNeal Liu 
629*70552e37SNeal Liu 	writel(EP_RESET_DESC_OP, ep->ep_base + AST_EP_DMA_CTRL);
630*70552e37SNeal Liu 	writel(EP_SINGLE_DESC_MODE, ep->ep_base + AST_EP_DMA_CTRL);
631*70552e37SNeal Liu 	writel(0, ep->ep_base + AST_EP_DMA_STS);
632*70552e37SNeal Liu 
633*70552e37SNeal Liu 	writel(ep_conf | EP_ENABLE, ep->ep_base + AST_EP_CONFIG);
634*70552e37SNeal Liu 
635*70552e37SNeal Liu 	EP_DBG("read ep %d seting: 0x%08X\n", epnum,
636*70552e37SNeal Liu 	       readl(ep->ep_base + AST_EP_CONFIG));
637*70552e37SNeal Liu 
638*70552e37SNeal Liu 	return 0;
639*70552e37SNeal Liu }
640*70552e37SNeal Liu 
aspeed_udc_ep_disable(struct usb_ep * _ep)641*70552e37SNeal Liu static int aspeed_udc_ep_disable(struct usb_ep *_ep)
642*70552e37SNeal Liu {
643*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = container_of(_ep, struct aspeed_udc_ep, ep);
644*70552e37SNeal Liu 
645*70552e37SNeal Liu 	EP_DBG("%s\n", _ep->name);
646*70552e37SNeal Liu 
647*70552e37SNeal Liu 	ep->ep.desc = NULL;
648*70552e37SNeal Liu 	ep->stopped = 1;
649*70552e37SNeal Liu 	writel(0, ep->ep_base + AST_EP_CONFIG);
650*70552e37SNeal Liu 
651*70552e37SNeal Liu 	return 0;
652*70552e37SNeal Liu }
653*70552e37SNeal Liu 
aspeed_udc_ep_alloc_request(struct usb_ep * _ep,gfp_t gfp_flags)654*70552e37SNeal Liu static struct usb_request *aspeed_udc_ep_alloc_request(struct usb_ep *_ep,
655*70552e37SNeal Liu 						       gfp_t gfp_flags)
656*70552e37SNeal Liu {
657*70552e37SNeal Liu 	struct aspeed_udc_request *req;
658*70552e37SNeal Liu 
659*70552e37SNeal Liu 	EP_DBG("%s\n", _ep->name);
660*70552e37SNeal Liu 	req = kzalloc(sizeof(*req), gfp_flags);
661*70552e37SNeal Liu 	if (!req)
662*70552e37SNeal Liu 		return NULL;
663*70552e37SNeal Liu 
664*70552e37SNeal Liu 	INIT_LIST_HEAD(&req->queue);
665*70552e37SNeal Liu 	return &req->req;
666*70552e37SNeal Liu }
667*70552e37SNeal Liu 
aspeed_udc_ep_free_request(struct usb_ep * _ep,struct usb_request * _req)668*70552e37SNeal Liu static void aspeed_udc_ep_free_request(struct usb_ep *_ep,
669*70552e37SNeal Liu 				       struct usb_request *_req)
670*70552e37SNeal Liu {
671*70552e37SNeal Liu 	struct aspeed_udc_request *req;
672*70552e37SNeal Liu 
673*70552e37SNeal Liu 	EP_DBG("%s\n", _ep->name);
674*70552e37SNeal Liu 	req = container_of(_req, struct aspeed_udc_request, req);
675*70552e37SNeal Liu 	kfree(req);
676*70552e37SNeal Liu }
677*70552e37SNeal Liu 
aspeed_udc_ep_queue(struct usb_ep * _ep,struct usb_request * _req,gfp_t gfp_flags)678*70552e37SNeal Liu static int aspeed_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
679*70552e37SNeal Liu 			       gfp_t gfp_flags)
680*70552e37SNeal Liu {
681*70552e37SNeal Liu 	struct aspeed_udc_request *req = req_to_aspeed_udc_req(_req);
682*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = ep_to_aspeed_udc_ep(_ep);
683*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = ep->udc;
684*70552e37SNeal Liu 	unsigned long flags = 0;
685*70552e37SNeal Liu 
686*70552e37SNeal Liu 	if (unlikely(!_req || !_req->complete || !_req->buf || !_ep))
687*70552e37SNeal Liu 		return -EINVAL;
688*70552e37SNeal Liu 
689*70552e37SNeal Liu 	if (ep->stopped) {
690*70552e37SNeal Liu 		pr_err("%s : is stop\n", _ep->name);
691*70552e37SNeal Liu 		return -1;
692*70552e37SNeal Liu 	}
693*70552e37SNeal Liu 
694*70552e37SNeal Liu 	spin_lock_irqsave(&udc->lock, flags);
695*70552e37SNeal Liu 
696*70552e37SNeal Liu 	list_add_tail(&req->queue, &ep->queue);
697*70552e37SNeal Liu 
698*70552e37SNeal Liu 	req->actual_dma_length = 0;
699*70552e37SNeal Liu 	req->req.actual = 0;
700*70552e37SNeal Liu 	req->req.status = -EINPROGRESS;
701*70552e37SNeal Liu 
702*70552e37SNeal Liu 	if (usb_gadget_map_request(&udc->gadget, &req->req, ep->ep_dir)) {
703*70552e37SNeal Liu 		pr_err("Map request failed\n");
704*70552e37SNeal Liu 		return -1;
705*70552e37SNeal Liu 	}
706*70552e37SNeal Liu 
707*70552e37SNeal Liu 	EP_DBG("%s: req(0x%x) dma:0x%x, len:%d, actual:0x%x\n",
708*70552e37SNeal Liu 	       ep->name, (u32)req, req->req.dma,
709*70552e37SNeal Liu 	       req->req.length, req->req.actual);
710*70552e37SNeal Liu 
711*70552e37SNeal Liu 	if (!ep->ep.desc) { /* ep0 */
712*70552e37SNeal Liu 		if ((req->req.dma % 4) != 0) {
713*70552e37SNeal Liu 			pr_err("ep0 request dma is not 4 bytes align\n");
714*70552e37SNeal Liu 			return -1;
715*70552e37SNeal Liu 		}
716*70552e37SNeal Liu 		aspeed_udc_ep0_queue(ep, req);
717*70552e37SNeal Liu 
718*70552e37SNeal Liu 	} else {
719*70552e37SNeal Liu 		if (list_is_singular(&ep->queue)) {
720*70552e37SNeal Liu 			if (udc->desc_mode)
721*70552e37SNeal Liu 				aspeed_udc_ep_dma_desc_mode(ep, req);
722*70552e37SNeal Liu 			else
723*70552e37SNeal Liu 				aspeed_udc_ep_dma(ep, req);
724*70552e37SNeal Liu 		}
725*70552e37SNeal Liu 	}
726*70552e37SNeal Liu 
727*70552e37SNeal Liu 	spin_unlock_irqrestore(&udc->lock, flags);
728*70552e37SNeal Liu 
729*70552e37SNeal Liu 	return 0;
730*70552e37SNeal Liu }
731*70552e37SNeal Liu 
aspeed_udc_ep_dequeue(struct usb_ep * _ep,struct usb_request * _req)732*70552e37SNeal Liu static int aspeed_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
733*70552e37SNeal Liu {
734*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = ep_to_aspeed_udc_ep(_ep);
735*70552e37SNeal Liu 	struct aspeed_udc_request *req;
736*70552e37SNeal Liu 
737*70552e37SNeal Liu 	EP_DBG("%s\n", _ep->name);
738*70552e37SNeal Liu 
739*70552e37SNeal Liu 	if (!_ep)
740*70552e37SNeal Liu 		return -EINVAL;
741*70552e37SNeal Liu 
742*70552e37SNeal Liu 	list_for_each_entry(req, &ep->queue, queue) {
743*70552e37SNeal Liu 		if (&req->req == _req) {
744*70552e37SNeal Liu 			list_del_init(&req->queue);
745*70552e37SNeal Liu 			_req->status = -ECONNRESET;
746*70552e37SNeal Liu 			break;
747*70552e37SNeal Liu 		}
748*70552e37SNeal Liu 	}
749*70552e37SNeal Liu 	if (&req->req != _req) {
750*70552e37SNeal Liu 		pr_err("Cannot find REQ in ep queue\n");
751*70552e37SNeal Liu 		return -EINVAL;
752*70552e37SNeal Liu 	}
753*70552e37SNeal Liu 
754*70552e37SNeal Liu 	aspeed_udc_done(ep, req, -ESHUTDOWN);
755*70552e37SNeal Liu 
756*70552e37SNeal Liu 	return 0;
757*70552e37SNeal Liu }
758*70552e37SNeal Liu 
aspeed_udc_ep_set_halt(struct usb_ep * _ep,int value)759*70552e37SNeal Liu static int aspeed_udc_ep_set_halt(struct usb_ep *_ep, int value)
760*70552e37SNeal Liu {
761*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = ep_to_aspeed_udc_ep(_ep);
762*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = ep->udc;
763*70552e37SNeal Liu 	u32 reg;
764*70552e37SNeal Liu 	u32 val;
765*70552e37SNeal Liu 
766*70552e37SNeal Liu 	EP_DBG("%s: %d\n", _ep->name, value);
767*70552e37SNeal Liu 	if (!_ep)
768*70552e37SNeal Liu 		return -EINVAL;
769*70552e37SNeal Liu 
770*70552e37SNeal Liu 	if (!strncmp(_ep->name, "ep0", 3)) {
771*70552e37SNeal Liu 		reg = udc->udc_base + AST_VHUB_EP0_CTRL;
772*70552e37SNeal Liu 		if (value)
773*70552e37SNeal Liu 			val = readl(reg) | EP0_STALL;
774*70552e37SNeal Liu 		else
775*70552e37SNeal Liu 			val = readl(reg) & ~EP0_STALL;
776*70552e37SNeal Liu 
777*70552e37SNeal Liu 	} else {
778*70552e37SNeal Liu 		reg = ep->ep_base + AST_EP_CONFIG;
779*70552e37SNeal Liu 		if (value)
780*70552e37SNeal Liu 			val = readl(reg) | EP_SET_EP_STALL;
781*70552e37SNeal Liu 		else
782*70552e37SNeal Liu 			val = readl(reg) & ~EP_SET_EP_STALL;
783*70552e37SNeal Liu 
784*70552e37SNeal Liu 		ep->stopped = value ? 1 : 0;
785*70552e37SNeal Liu 	}
786*70552e37SNeal Liu 
787*70552e37SNeal Liu 	writel(val, reg);
788*70552e37SNeal Liu 
789*70552e37SNeal Liu 	return 0;
790*70552e37SNeal Liu }
791*70552e37SNeal Liu 
aspeed_udc_ep_handle_desc_mode(struct aspeed_udc_priv * udc,u16 ep_num)792*70552e37SNeal Liu static void aspeed_udc_ep_handle_desc_mode(struct aspeed_udc_priv *udc,
793*70552e37SNeal Liu 					   u16 ep_num)
794*70552e37SNeal Liu {
795*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = &udc->ep[ep_num];
796*70552e37SNeal Liu 	struct aspeed_udc_request *req;
797*70552e37SNeal Liu 	u32 processing_status;
798*70552e37SNeal Liu 	u32 wr_ptr, rd_ptr;
799*70552e37SNeal Liu 	u16 total_len = 0;
800*70552e37SNeal Liu 	u16 len_in_desc;
801*70552e37SNeal Liu 	u16 len;
802*70552e37SNeal Liu 	int i;
803*70552e37SNeal Liu 
804*70552e37SNeal Liu 	if (list_empty(&ep->queue)) {
805*70552e37SNeal Liu 		pr_err("%s ep req queue is empty!!!\n", ep->ep.name);
806*70552e37SNeal Liu 		return;
807*70552e37SNeal Liu 	}
808*70552e37SNeal Liu 
809*70552e37SNeal Liu 	EP_DBG("%s handle\n", ep->ep.name);
810*70552e37SNeal Liu 
811*70552e37SNeal Liu 	req = list_first_entry(&ep->queue, struct aspeed_udc_request, queue);
812*70552e37SNeal Liu 
813*70552e37SNeal Liu 	processing_status = (readl(ep->ep_base + AST_EP_DMA_CTRL) >> 4) & 0xf;
814*70552e37SNeal Liu 	if (processing_status != 0 && processing_status != 8) {
815*70552e37SNeal Liu 		pr_err("Desc process status: 0x%x\n", processing_status);
816*70552e37SNeal Liu 		return;
817*70552e37SNeal Liu 	}
818*70552e37SNeal Liu 
819*70552e37SNeal Liu 	rd_ptr = (readl(ep->ep_base + AST_EP_DMA_STS) >> 8) & 0xFF;
820*70552e37SNeal Liu 	wr_ptr = (readl(ep->ep_base + AST_EP_DMA_STS)) & 0xFF;
821*70552e37SNeal Liu 
822*70552e37SNeal Liu 	EP_DBG("req(0x%x) length: 0x%x, actual: 0x%x, rd_ptr:%d, wr_ptr:%d\n",
823*70552e37SNeal Liu 	       (u32)req, req->req.length, req->req.actual, rd_ptr, wr_ptr);
824*70552e37SNeal Liu 
825*70552e37SNeal Liu 	if (rd_ptr != wr_ptr) {
826*70552e37SNeal Liu 		pr_err("%s: Desc is not empy. %s:%d,  %s:%d\n",
827*70552e37SNeal Liu 		       __func__, "rd_ptr", rd_ptr, "wr_ptr", wr_ptr);
828*70552e37SNeal Liu 		return;
829*70552e37SNeal Liu 	}
830*70552e37SNeal Liu 
831*70552e37SNeal Liu 	i = req->saved_dma_wptr;
832*70552e37SNeal Liu 	do {
833*70552e37SNeal Liu 		if (ep->ep_dir)
834*70552e37SNeal Liu 			len_in_desc =
835*70552e37SNeal Liu 				VHUB_DSC1_IN_LEN(ep->dma_desc_list[i].des_1);
836*70552e37SNeal Liu 		else
837*70552e37SNeal Liu 			len_in_desc =
838*70552e37SNeal Liu 				VHUB_DSC1_OUT_LEN(ep->dma_desc_list[i].des_1);
839*70552e37SNeal Liu 		total_len += len_in_desc;
840*70552e37SNeal Liu 		i++;
841*70552e37SNeal Liu 		if (i >= AST_EP_NUM_OF_DESC)
842*70552e37SNeal Liu 			i = 0;
843*70552e37SNeal Liu 	} while (i != wr_ptr);
844*70552e37SNeal Liu 
845*70552e37SNeal Liu 	len = total_len;
846*70552e37SNeal Liu 	req->req.actual += len;
847*70552e37SNeal Liu 
848*70552e37SNeal Liu 	EP_DBG("%s: total transfer len:0x%x\n", ep->ep.name, len);
849*70552e37SNeal Liu 
850*70552e37SNeal Liu 	if (req->req.length <= req->req.actual || len < ep->ep.maxpacket) {
851*70552e37SNeal Liu 		usb_gadget_unmap_request(&udc->gadget, &req->req, ep->ep_dir);
852*70552e37SNeal Liu 		if ((req->req.dma % 4) != 0) {
853*70552e37SNeal Liu 			pr_err("Not supported in desc_mode\n");
854*70552e37SNeal Liu 			return;
855*70552e37SNeal Liu 		}
856*70552e37SNeal Liu 
857*70552e37SNeal Liu 		aspeed_udc_done(ep, req, 0);
858*70552e37SNeal Liu 
859*70552e37SNeal Liu 		if (!list_empty(&ep->queue)) {
860*70552e37SNeal Liu 			req = list_first_entry(&ep->queue,
861*70552e37SNeal Liu 					       struct aspeed_udc_request,
862*70552e37SNeal Liu 					       queue);
863*70552e37SNeal Liu 
864*70552e37SNeal Liu 			EP_DBG("%s: next req(0x%x) dma 0x%x\n", ep->ep.name,
865*70552e37SNeal Liu 			       (u32)req, req->req.dma);
866*70552e37SNeal Liu 
867*70552e37SNeal Liu 			if (req->actual_dma_length == req->req.actual)
868*70552e37SNeal Liu 				aspeed_udc_ep_dma_desc_mode(ep, req);
869*70552e37SNeal Liu 			else
870*70552e37SNeal Liu 				EP_DBG("%s: skip req(0x%x) dma(%d %d)\n",
871*70552e37SNeal Liu 				       ep->ep.name, (u32)req,
872*70552e37SNeal Liu 				       req->actual_dma_length,
873*70552e37SNeal Liu 				       req->req.actual);
874*70552e37SNeal Liu 		}
875*70552e37SNeal Liu 
876*70552e37SNeal Liu 	} else {
877*70552e37SNeal Liu 		EP_DBG("%s: not done, keep trigger dma\n", ep->ep.name);
878*70552e37SNeal Liu 		if (req->actual_dma_length == req->req.actual)
879*70552e37SNeal Liu 			aspeed_udc_ep_dma_desc_mode(ep, req);
880*70552e37SNeal Liu 		else
881*70552e37SNeal Liu 			EP_DBG("%s: skip req(0x%x) dma (%d %d)\n",
882*70552e37SNeal Liu 			       ep->ep.name, (u32)req,
883*70552e37SNeal Liu 			       req->actual_dma_length,
884*70552e37SNeal Liu 			       req->req.actual);
885*70552e37SNeal Liu 	}
886*70552e37SNeal Liu 
887*70552e37SNeal Liu 	EP_DBG("%s exits\n", ep->ep.name);
888*70552e37SNeal Liu }
889*70552e37SNeal Liu 
aspeed_udc_ep_handle(struct aspeed_udc_priv * udc,u16 ep_num)890*70552e37SNeal Liu static void aspeed_udc_ep_handle(struct aspeed_udc_priv *udc, u16 ep_num)
891*70552e37SNeal Liu {
892*70552e37SNeal Liu 	struct aspeed_udc_ep *ep = &udc->ep[ep_num];
893*70552e37SNeal Liu 	struct aspeed_udc_request *req;
894*70552e37SNeal Liu 	u16 len = 0;
895*70552e37SNeal Liu 
896*70552e37SNeal Liu 	EP_DBG("%s handle\n", ep->ep.name);
897*70552e37SNeal Liu 
898*70552e37SNeal Liu 	if (list_empty(&ep->queue))
899*70552e37SNeal Liu 		return;
900*70552e37SNeal Liu 
901*70552e37SNeal Liu 	req = list_first_entry(&ep->queue, struct aspeed_udc_request, queue);
902*70552e37SNeal Liu 	len = (readl(ep->ep_base + AST_EP_DMA_STS) >> 16) & 0x7ff;
903*70552e37SNeal Liu 
904*70552e37SNeal Liu 	EP_DBG("%s req: length: 0x%x, actual: 0x%x, len: 0x%x\n",
905*70552e37SNeal Liu 	       ep->ep.name, req->req.length, req->req.actual, len);
906*70552e37SNeal Liu 
907*70552e37SNeal Liu 	req->req.actual += len;
908*70552e37SNeal Liu 
909*70552e37SNeal Liu 	if (req->req.length == req->req.actual || len < ep->ep.maxpacket) {
910*70552e37SNeal Liu 		usb_gadget_unmap_request(&udc->gadget, &req->req, ep->ep_dir);
911*70552e37SNeal Liu 
912*70552e37SNeal Liu 		aspeed_udc_done(ep, req, 0);
913*70552e37SNeal Liu 		if (!list_empty(&ep->queue)) {
914*70552e37SNeal Liu 			req = list_first_entry(&ep->queue,
915*70552e37SNeal Liu 					       struct aspeed_udc_request,
916*70552e37SNeal Liu 					       queue);
917*70552e37SNeal Liu 			aspeed_udc_ep_dma(ep, req);
918*70552e37SNeal Liu 		}
919*70552e37SNeal Liu 
920*70552e37SNeal Liu 	} else {
921*70552e37SNeal Liu 		aspeed_udc_ep_dma(ep, req);
922*70552e37SNeal Liu 	}
923*70552e37SNeal Liu }
924*70552e37SNeal Liu 
aspeed_udc_isr(struct aspeed_udc_priv * udc)925*70552e37SNeal Liu static void aspeed_udc_isr(struct aspeed_udc_priv *udc)
926*70552e37SNeal Liu {
927*70552e37SNeal Liu 	u32 base = udc->udc_base;
928*70552e37SNeal Liu 	u32 isr = readl(base + AST_VHUB_ISR);
92993265845Sneal_liu 	u32 ep_isr;
93093265845Sneal_liu 	int i;
93193265845Sneal_liu 
932*70552e37SNeal Liu 	isr &= 0x3ffff;
93393265845Sneal_liu 	if (!isr)
93493265845Sneal_liu 		return;
93593265845Sneal_liu 
936*70552e37SNeal Liu //	pr_info("%s: isr: 0x%x\n", __func__, isr);
93793265845Sneal_liu 	if (isr & ISR_BUS_RESET) {
938*70552e37SNeal Liu 		UDC_DBG("ISR_BUS_RESET\n");
939*70552e37SNeal Liu 		writel(ISR_BUS_RESET, base + AST_VHUB_ISR);
94093265845Sneal_liu 	}
94193265845Sneal_liu 
94293265845Sneal_liu 	if (isr & ISR_BUS_SUSPEND) {
943*70552e37SNeal Liu 		UDC_DBG("ISR_BUS_SUSPEND\n");
944*70552e37SNeal Liu 		writel(ISR_BUS_SUSPEND, base + AST_VHUB_ISR);
94593265845Sneal_liu 	}
94693265845Sneal_liu 
94793265845Sneal_liu 	if (isr & ISR_SUSPEND_RESUME) {
948*70552e37SNeal Liu 		UDC_DBG("ISR_SUSPEND_RESUME\n");
949*70552e37SNeal Liu 		writel(ISR_SUSPEND_RESUME, base + AST_VHUB_ISR);
95093265845Sneal_liu 	}
95193265845Sneal_liu 
95293265845Sneal_liu 	if (isr & ISR_HUB_EP0_IN_ACK_STALL) {
953*70552e37SNeal Liu 		UDC_DBG("ISR_HUB_EP0_IN_ACK_STALL\n");
954*70552e37SNeal Liu 		writel(ISR_HUB_EP0_IN_ACK_STALL, base + AST_VHUB_ISR);
955*70552e37SNeal Liu 		aspeed_udc_ep0_in(udc);
95693265845Sneal_liu 	}
95793265845Sneal_liu 
95893265845Sneal_liu 	if (isr & ISR_HUB_EP0_OUT_ACK_STALL) {
959*70552e37SNeal Liu 		UDC_DBG("ISR_HUB_EP0_OUT_ACK_STALL\n");
960*70552e37SNeal Liu 		writel(ISR_HUB_EP0_OUT_ACK_STALL, base + AST_VHUB_ISR);
961*70552e37SNeal Liu 		aspeed_udc_ep0_out(udc);
96293265845Sneal_liu 	}
96393265845Sneal_liu 
96493265845Sneal_liu 	if (isr & ISR_HUB_EP0_OUT_NAK) {
965*70552e37SNeal Liu 		UDC_DBG("ISR_HUB_EP0_OUT_NAK\n");
966*70552e37SNeal Liu 		writel(ISR_HUB_EP0_OUT_NAK, base + AST_VHUB_ISR);
96793265845Sneal_liu 	}
96893265845Sneal_liu 
96993265845Sneal_liu 	if (isr & ISR_HUB_EP0_IN_DATA_NAK) {
970*70552e37SNeal Liu 		UDC_DBG("ISR_HUB_EP0_IN_DATA_NAK\n");
971*70552e37SNeal Liu 		writel(ISR_HUB_EP0_IN_DATA_NAK, base + AST_VHUB_ISR);
97293265845Sneal_liu 	}
97393265845Sneal_liu 
97493265845Sneal_liu 	if (isr & ISR_HUB_EP0_SETUP) {
975*70552e37SNeal Liu 		UDC_DBG("SETUP\n");
976*70552e37SNeal Liu 		writel(ISR_HUB_EP0_SETUP, base + AST_VHUB_ISR);
977*70552e37SNeal Liu 		aspeed_udc_setup_handle(udc);
97893265845Sneal_liu 	}
97993265845Sneal_liu 
98093265845Sneal_liu 	if (isr & ISR_HUB_EP1_IN_DATA_ACK) {
98193265845Sneal_liu 		// HUB Bitmap control
982*70552e37SNeal Liu 		pr_err("Error: EP1 IN ACK\n");
983*70552e37SNeal Liu 		writel(ISR_HUB_EP1_IN_DATA_ACK, base + AST_VHUB_ISR);
984*70552e37SNeal Liu 		writel(0x00, base + AST_VHUB_EP1_STS_CHG);
98593265845Sneal_liu 	}
98693265845Sneal_liu 
98793265845Sneal_liu 	if (isr & ISR_EP_ACK_STALL) {
988*70552e37SNeal Liu 		ep_isr = readl(base + AST_VHUB_EP_ACK_ISR);
989*70552e37SNeal Liu 		UDC_DBG("ISR_EP_ACK_STALL, ep_ack_isr: 0x%x\n", ep_isr);
990*70552e37SNeal Liu 
99193265845Sneal_liu 		for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
99293265845Sneal_liu 			if (ep_isr & (0x1 << i)) {
993*70552e37SNeal Liu 				writel(BIT(i), base + AST_VHUB_EP_ACK_ISR);
994*70552e37SNeal Liu 				if (udc->desc_mode)
995*70552e37SNeal Liu 					aspeed_udc_ep_handle_desc_mode(udc, i);
996*70552e37SNeal Liu 				else
997*70552e37SNeal Liu 					aspeed_udc_ep_handle(udc, i);
99893265845Sneal_liu 			}
99993265845Sneal_liu 		}
100093265845Sneal_liu 	}
100193265845Sneal_liu 
100293265845Sneal_liu 	if (isr & ISR_EP_NAK) {
1003*70552e37SNeal Liu 		UDC_DBG("ISR_EP_NAK\n");
1004*70552e37SNeal Liu 		writel(ISR_EP_NAK, base + AST_VHUB_ISR);
100593265845Sneal_liu 	}
100693265845Sneal_liu }
100793265845Sneal_liu 
1008*70552e37SNeal Liu static const struct usb_ep_ops aspeed_udc_ep_ops = {
1009*70552e37SNeal Liu 	.enable = aspeed_udc_ep_enable,
1010*70552e37SNeal Liu 	.disable = aspeed_udc_ep_disable,
1011*70552e37SNeal Liu 	.alloc_request = aspeed_udc_ep_alloc_request,
1012*70552e37SNeal Liu 	.free_request = aspeed_udc_ep_free_request,
1013*70552e37SNeal Liu 	.queue = aspeed_udc_ep_queue,
1014*70552e37SNeal Liu 	.dequeue = aspeed_udc_ep_dequeue,
1015*70552e37SNeal Liu 	.set_halt = aspeed_udc_ep_set_halt,
1016*70552e37SNeal Liu };
1017*70552e37SNeal Liu 
aspeed_udc_ep_init(struct aspeed_udc_priv * udc)1018*70552e37SNeal Liu static void aspeed_udc_ep_init(struct aspeed_udc_priv *udc)
101993265845Sneal_liu {
1020*70552e37SNeal Liu 	struct aspeed_udc_ep *ep;
1021*70552e37SNeal Liu 	int i;
1022*70552e37SNeal Liu 
1023*70552e37SNeal Liu 	for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
1024*70552e37SNeal Liu 		ep = &udc->ep[i];
1025*70552e37SNeal Liu 		snprintf(ep->name, sizeof(ep->name), "ep%d", i);
1026*70552e37SNeal Liu 		ep->ep.name = ep->name;
1027*70552e37SNeal Liu 		ep->ep.ops = &aspeed_udc_ep_ops;
1028*70552e37SNeal Liu 
1029*70552e37SNeal Liu 		if (i) {
1030*70552e37SNeal Liu 			ep->ep_buf = udc->ep0_ctrl_buf + (i * EP_DMA_SIZE);
1031*70552e37SNeal Liu 			ep->ep_dma = udc->ep0_ctrl_dma + (i * EP_DMA_SIZE);
1032*70552e37SNeal Liu 			usb_ep_set_maxpacket_limit(&ep->ep, 1024);
1033*70552e37SNeal Liu 			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
1034*70552e37SNeal Liu 
1035*70552e37SNeal Liu 			/* allocate endpoint descrptor list (Note: must be DMA memory) */
1036*70552e37SNeal Liu 			if (udc->desc_mode) {
1037*70552e37SNeal Liu 				ep->dma_desc_list =
1038*70552e37SNeal Liu 					dma_alloc_coherent(AST_EP_NUM_OF_DESC *
1039*70552e37SNeal Liu 						sizeof(struct aspeed_ep_desc),
1040*70552e37SNeal Liu 						(unsigned long *)
1041*70552e37SNeal Liu 						&ep->dma_desc_dma_handle
1042*70552e37SNeal Liu 						);
1043*70552e37SNeal Liu 				ep->dma_desc_list_wptr = 0;
104493265845Sneal_liu 			}
104593265845Sneal_liu 
104693265845Sneal_liu 		} else {
1047*70552e37SNeal Liu 			usb_ep_set_maxpacket_limit(&ep->ep, 64);
1048*70552e37SNeal Liu 		}
1049*70552e37SNeal Liu 
1050*70552e37SNeal Liu 		ep->ep_base = udc->udc_base + AST_EP_BASE + (AST_EP_OFFSET * i);
1051*70552e37SNeal Liu 		ep->udc = udc;
1052*70552e37SNeal Liu 
1053*70552e37SNeal Liu 		INIT_LIST_HEAD(&ep->queue);
105493265845Sneal_liu 	}
105593265845Sneal_liu }
105693265845Sneal_liu 
aspeed_gadget_getframe(struct usb_gadget * gadget)1057*70552e37SNeal Liu static int aspeed_gadget_getframe(struct usb_gadget *gadget)
105893265845Sneal_liu {
1059*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = gadget_to_aspeed_udc(gadget);
1060*70552e37SNeal Liu 
1061*70552e37SNeal Liu 	return (readl(udc->udc_base + AST_VHUB_USB_STS) >> 16) & 0x7ff;
106293265845Sneal_liu }
106393265845Sneal_liu 
aspeed_gadget_wakeup(struct usb_gadget * gadget)1064*70552e37SNeal Liu static int aspeed_gadget_wakeup(struct usb_gadget *gadget)
106593265845Sneal_liu {
1066*70552e37SNeal Liu 	UDC_DBG("TODO\n");
1067*70552e37SNeal Liu 	return 0;
106893265845Sneal_liu }
106993265845Sneal_liu 
1070*70552e37SNeal Liu /*
1071*70552e37SNeal Liu  * activate/deactivate link with host; minimize power usage for
1072*70552e37SNeal Liu  * inactive links by cutting clocks and transceiver power.
107393265845Sneal_liu  */
aspeed_gadget_pullup(struct usb_gadget * gadget,int is_on)1074*70552e37SNeal Liu static int aspeed_gadget_pullup(struct usb_gadget *gadget, int is_on)
1075*70552e37SNeal Liu {
1076*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = gadget_to_aspeed_udc(gadget);
1077*70552e37SNeal Liu 	u32 reg = udc->udc_base + AST_VHUB_CTRL;
107893265845Sneal_liu 
1079*70552e37SNeal Liu 	UDC_DBG("is_on: %d\n", is_on);
1080*70552e37SNeal Liu 
1081*70552e37SNeal Liu 	if (is_on)
1082*70552e37SNeal Liu 		writel(readl(reg) | ROOT_UPSTREAM_EN, reg);
1083*70552e37SNeal Liu 	else
1084*70552e37SNeal Liu 		writel(readl(reg) & ~ROOT_UPSTREAM_EN, reg);
1085*70552e37SNeal Liu 
1086*70552e37SNeal Liu 	return 0;
108793265845Sneal_liu }
108893265845Sneal_liu 
aspeed_gadget_start(struct usb_gadget * gadget,struct usb_gadget_driver * driver)1089*70552e37SNeal Liu static int aspeed_gadget_start(struct usb_gadget *gadget,
1090*70552e37SNeal Liu 			       struct usb_gadget_driver *driver)
109193265845Sneal_liu {
1092*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = gadget_to_aspeed_udc(gadget);
109393265845Sneal_liu 
1094*70552e37SNeal Liu 	if (!udc)
1095*70552e37SNeal Liu 		return -ENODEV;
1096*70552e37SNeal Liu 
1097*70552e37SNeal Liu 	udc->gadget_driver = driver;
1098*70552e37SNeal Liu 
1099*70552e37SNeal Liu 	return 0;
1100*70552e37SNeal Liu }
1101*70552e37SNeal Liu 
aspeed_gadget_stop(struct usb_gadget * gadget)1102*70552e37SNeal Liu static int aspeed_gadget_stop(struct usb_gadget *gadget)
1103*70552e37SNeal Liu {
1104*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = gadget_to_aspeed_udc(gadget);
1105*70552e37SNeal Liu 	u32 reg = udc->udc_base + AST_VHUB_CTRL;
1106*70552e37SNeal Liu 
1107*70552e37SNeal Liu 	writel(readl(reg) & ~ROOT_UPSTREAM_EN, reg);
1108*70552e37SNeal Liu 
1109*70552e37SNeal Liu 	udc->gadget.speed = USB_SPEED_UNKNOWN;
1110*70552e37SNeal Liu 	udc->gadget_driver = NULL;
1111*70552e37SNeal Liu 
1112*70552e37SNeal Liu 	usb_gadget_set_state(&udc->gadget, USB_STATE_NOTATTACHED);
1113*70552e37SNeal Liu 
1114*70552e37SNeal Liu 	return 0;
1115*70552e37SNeal Liu }
1116*70552e37SNeal Liu 
1117*70552e37SNeal Liu static const struct usb_gadget_ops aspeed_gadget_ops = {
1118*70552e37SNeal Liu 	.get_frame		= aspeed_gadget_getframe,
1119*70552e37SNeal Liu 	.wakeup			= aspeed_gadget_wakeup,
1120*70552e37SNeal Liu 	.pullup			= aspeed_gadget_pullup,
1121*70552e37SNeal Liu 	.udc_start		= aspeed_gadget_start,
1122*70552e37SNeal Liu 	.udc_stop		= aspeed_gadget_stop,
1123*70552e37SNeal Liu };
1124*70552e37SNeal Liu 
dm_usb_gadget_handle_interrupts(struct udevice * dev)1125*70552e37SNeal Liu int dm_usb_gadget_handle_interrupts(struct udevice *dev)
1126*70552e37SNeal Liu {
1127*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = dev_get_priv(dev);
1128*70552e37SNeal Liu 
1129*70552e37SNeal Liu 	aspeed_udc_isr(udc);
1130*70552e37SNeal Liu 
1131*70552e37SNeal Liu 	return 0;
1132*70552e37SNeal Liu }
1133*70552e37SNeal Liu 
udc_init(struct aspeed_udc_priv * udc)1134*70552e37SNeal Liu static int udc_init(struct aspeed_udc_priv *udc)
1135*70552e37SNeal Liu {
1136*70552e37SNeal Liu 	u32 base;
1137*70552e37SNeal Liu 
1138*70552e37SNeal Liu 	if (!udc) {
1139*70552e37SNeal Liu 		dev_err(udc->dev, "Error: udc driver is not init yet");
114093265845Sneal_liu 		return -1;
114193265845Sneal_liu 	}
114293265845Sneal_liu 
1143*70552e37SNeal Liu 	base = udc->udc_base;
114493265845Sneal_liu 
1145*70552e37SNeal Liu 	writel(ROOT_PHY_CLK_EN | ROOT_PHY_RESET_DIS, base + AST_VHUB_CTRL);
114693265845Sneal_liu 
1147*70552e37SNeal Liu 	writel(0, base + AST_VHUB_DEV_RESET);
114893265845Sneal_liu 
1149*70552e37SNeal Liu 	writel(~BIT(18), base + AST_VHUB_ISR);
1150*70552e37SNeal Liu 	writel(~BIT(18), base + AST_VHUB_IER);
115193265845Sneal_liu 
1152*70552e37SNeal Liu 	writel(~BIT(UDC_MAX_ENDPOINTS), base + AST_VHUB_EP_ACK_ISR);
1153*70552e37SNeal Liu 	writel(~BIT(UDC_MAX_ENDPOINTS), base + AST_VHUB_EP_ACK_IER);
1154*70552e37SNeal Liu 
1155*70552e37SNeal Liu 	writel(0, base + AST_VHUB_EP0_CTRL);
1156*70552e37SNeal Liu 	writel(0, base + AST_VHUB_EP1_CTRL);
1157*70552e37SNeal Liu 
1158*70552e37SNeal Liu #ifdef AST_EP_DESC_MODE
1159*70552e37SNeal Liu 	if (AST_EP_NUM_OF_DESC == 256)
1160*70552e37SNeal Liu 		writel(readl(base + AST_VHUB_CTRL) | EP_LONG_DESC_MODE,
1161*70552e37SNeal Liu 		       base + AST_VHUB_CTRL);
1162*70552e37SNeal Liu #endif
116393265845Sneal_liu 
116493265845Sneal_liu 	return 0;
116593265845Sneal_liu }
116693265845Sneal_liu 
aspeed_udc_probe(struct udevice * dev)116793265845Sneal_liu static int aspeed_udc_probe(struct udevice *dev)
116893265845Sneal_liu {
116993265845Sneal_liu 	struct aspeed_udc_priv *udc = dev_get_priv(dev);
117093265845Sneal_liu 	struct reset_ctl udc_reset_ctl;
117193265845Sneal_liu 	int ret;
117293265845Sneal_liu 
1173*70552e37SNeal Liu 	dev_info(dev, "Start aspeed udc...\n");
1174*70552e37SNeal Liu 
117593265845Sneal_liu 	ret = reset_get_by_index(dev, 0, &udc_reset_ctl);
117693265845Sneal_liu 	if (ret) {
1177*70552e37SNeal Liu 		dev_err(dev, "%s: Failed to get udc reset signal\n", __func__);
117893265845Sneal_liu 		return ret;
117993265845Sneal_liu 	}
118093265845Sneal_liu 
118193265845Sneal_liu 	reset_assert(&udc_reset_ctl);
118293265845Sneal_liu 
118393265845Sneal_liu 	// Wait 10ms for PLL locking
118493265845Sneal_liu 	mdelay(10);
118593265845Sneal_liu 	reset_deassert(&udc_reset_ctl);
118693265845Sneal_liu 
118793265845Sneal_liu 	udc->init = 1;
1188*70552e37SNeal Liu 	ret = udc_init(udc);
1189*70552e37SNeal Liu 	if (ret) {
1190*70552e37SNeal Liu 		dev_err(dev, "%s: udc_init failed\n", __func__);
1191*70552e37SNeal Liu 		return -EINVAL;
1192*70552e37SNeal Liu 	}
1193*70552e37SNeal Liu 
1194*70552e37SNeal Liu 	udc->gadget.ops			= &aspeed_gadget_ops;
1195*70552e37SNeal Liu 	udc->gadget.ep0			= &udc->ep[0].ep;
1196*70552e37SNeal Liu 	udc->gadget.max_speed		= udc->maximum_speed;
1197*70552e37SNeal Liu 	udc->gadget.speed		= USB_SPEED_UNKNOWN;
1198*70552e37SNeal Liu 	udc->root_setup			= (struct usb_ctrlrequest *)
1199*70552e37SNeal Liu 					(udc->udc_base + AST_VHUB_SETUP_DATA0);
1200*70552e37SNeal Liu #ifdef AST_EP_DESC_MODE
1201*70552e37SNeal Liu 	udc->desc_mode			= 1;
1202*70552e37SNeal Liu #else
1203*70552e37SNeal Liu 	udc->desc_mode			= 0;
1204*70552e37SNeal Liu #endif
1205*70552e37SNeal Liu 	pr_info("%s: desc_mode: %d\n", __func__, udc->desc_mode);
1206*70552e37SNeal Liu 
1207*70552e37SNeal Liu 	/*
1208*70552e37SNeal Liu 	 * Allocate DMA buffers for all EP0s in one chunk,
1209*70552e37SNeal Liu 	 * one per port and one for the vHub itself
1210*70552e37SNeal Liu 	 */
1211*70552e37SNeal Liu 	udc->ep0_ctrl_buf =
1212*70552e37SNeal Liu 		dma_alloc_coherent(EP_DMA_SIZE * UDC_MAX_ENDPOINTS,
1213*70552e37SNeal Liu 				   (unsigned long *)&udc->ep0_ctrl_dma);
1214*70552e37SNeal Liu 
1215*70552e37SNeal Liu 	INIT_LIST_HEAD(&udc->gadget.ep_list);
1216*70552e37SNeal Liu 
1217*70552e37SNeal Liu 	aspeed_udc_ep_init(udc);
1218*70552e37SNeal Liu 
1219*70552e37SNeal Liu 	ret = usb_add_gadget_udc((struct device *)udc->dev, &udc->gadget);
1220*70552e37SNeal Liu 	if (ret) {
1221*70552e37SNeal Liu 		dev_err(udc->dev, "failed to register udc\n");
1222*70552e37SNeal Liu 		return ret;
1223*70552e37SNeal Liu 	}
122493265845Sneal_liu 
122593265845Sneal_liu 	return 0;
122693265845Sneal_liu }
122793265845Sneal_liu 
aspeed_udc_ofdata_to_platdata(struct udevice * dev)122893265845Sneal_liu static int aspeed_udc_ofdata_to_platdata(struct udevice *dev)
122993265845Sneal_liu {
1230*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = dev_get_priv(dev);
1231*70552e37SNeal Liu 	int node = dev_of_offset(dev);
123293265845Sneal_liu 
1233*70552e37SNeal Liu 	udc->udc_base = (u32)devfdt_get_addr_index(dev, 0);
1234*70552e37SNeal Liu 	udc->dev = dev;
1235*70552e37SNeal Liu 
1236*70552e37SNeal Liu 	udc->maximum_speed = usb_get_maximum_speed(node);
1237*70552e37SNeal Liu 	if (udc->maximum_speed == USB_SPEED_UNKNOWN) {
1238*70552e37SNeal Liu 		printf("Invalid usb maximum speed\n");
1239*70552e37SNeal Liu 		return -ENODEV;
1240*70552e37SNeal Liu 	}
1241*70552e37SNeal Liu 
1242*70552e37SNeal Liu 	return 0;
1243*70552e37SNeal Liu }
1244*70552e37SNeal Liu 
aspeed_udc_remove(struct udevice * dev)1245*70552e37SNeal Liu static int aspeed_udc_remove(struct udevice *dev)
1246*70552e37SNeal Liu {
1247*70552e37SNeal Liu 	struct aspeed_udc_priv *udc = dev_get_priv(dev);
1248*70552e37SNeal Liu 
1249*70552e37SNeal Liu 	usb_del_gadget_udc(&udc->gadget);
1250*70552e37SNeal Liu 	if (udc->gadget_driver)
1251*70552e37SNeal Liu 		return -EBUSY;
1252*70552e37SNeal Liu 
1253*70552e37SNeal Liu 	writel(readl(udc->udc_base + AST_VHUB_CTRL) & ~ROOT_UPSTREAM_EN,
1254*70552e37SNeal Liu 	       udc->udc_base + AST_VHUB_CTRL);
1255*70552e37SNeal Liu 
1256*70552e37SNeal Liu 	dma_free_coherent(udc->ep0_ctrl_buf);
125793265845Sneal_liu 
125893265845Sneal_liu 	return 0;
125993265845Sneal_liu }
126093265845Sneal_liu 
126193265845Sneal_liu static const struct udevice_id aspeed_udc_ids[] = {
126293265845Sneal_liu 	{ .compatible = "aspeed,ast2600-usb-vhub" },
126393265845Sneal_liu 	{ }
126493265845Sneal_liu };
126593265845Sneal_liu 
1266*70552e37SNeal Liu U_BOOT_DRIVER(aspeed_udc_generic) = {
1267*70552e37SNeal Liu 	.name			= "aspeed_udc_generic",
1268*70552e37SNeal Liu 	.id			= UCLASS_USB_GADGET_GENERIC,
126993265845Sneal_liu 	.of_match		= aspeed_udc_ids,
127093265845Sneal_liu 	.probe			= aspeed_udc_probe,
1271*70552e37SNeal Liu 	.remove			= aspeed_udc_remove,
127293265845Sneal_liu 	.ofdata_to_platdata	= aspeed_udc_ofdata_to_platdata,
127393265845Sneal_liu 	.priv_auto_alloc_size	= sizeof(struct aspeed_udc_priv),
127493265845Sneal_liu };
1275