162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author:  Chunfeng.Yun <chunfeng.yun@mediatek.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/iopoll.h>
1162306a36Sopenharmony_ci#include <linux/usb/composite.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "mtu3.h"
1462306a36Sopenharmony_ci#include "mtu3_debug.h"
1562306a36Sopenharmony_ci#include "mtu3_trace.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* ep0 is always mtu3->in_eps[0] */
1862306a36Sopenharmony_ci#define	next_ep0_request(mtu)	next_request((mtu)->ep0)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* for high speed test mode; see USB 2.0 spec 7.1.20 */
2162306a36Sopenharmony_cistatic const u8 mtu3_test_packet[53] = {
2262306a36Sopenharmony_ci	/* implicit SYNC then DATA0 to start */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/* JKJKJKJK x9 */
2562306a36Sopenharmony_ci	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2662306a36Sopenharmony_ci	/* JJKKJJKK x8 */
2762306a36Sopenharmony_ci	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
2862306a36Sopenharmony_ci	/* JJJJKKKK x8 */
2962306a36Sopenharmony_ci	0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
3062306a36Sopenharmony_ci	/* JJJJJJJKKKKKKK x8 */
3162306a36Sopenharmony_ci	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3262306a36Sopenharmony_ci	/* JJJJJJJK x8 */
3362306a36Sopenharmony_ci	0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
3462306a36Sopenharmony_ci	/* JKKKKKKK x10, JK */
3562306a36Sopenharmony_ci	0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e,
3662306a36Sopenharmony_ci	/* implicit CRC16 then EOP to end */
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic char *decode_ep0_state(struct mtu3 *mtu)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	switch (mtu->ep0_state) {
4262306a36Sopenharmony_ci	case MU3D_EP0_STATE_SETUP:
4362306a36Sopenharmony_ci		return "SETUP";
4462306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX:
4562306a36Sopenharmony_ci		return "IN";
4662306a36Sopenharmony_ci	case MU3D_EP0_STATE_RX:
4762306a36Sopenharmony_ci		return "OUT";
4862306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX_END:
4962306a36Sopenharmony_ci		return "TX-END";
5062306a36Sopenharmony_ci	case MU3D_EP0_STATE_STALL:
5162306a36Sopenharmony_ci		return "STALL";
5262306a36Sopenharmony_ci	default:
5362306a36Sopenharmony_ci		return "??";
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	mtu3_req_complete(mtu->ep0, req, 0);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int
6362306a36Sopenharmony_ciforward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
6462306a36Sopenharmony_ci__releases(mtu->lock)
6562306a36Sopenharmony_ci__acquires(mtu->lock)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (!mtu->gadget_driver || !mtu->async_callbacks)
7062306a36Sopenharmony_ci		return -EOPNOTSUPP;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	spin_unlock(&mtu->lock);
7362306a36Sopenharmony_ci	ret = mtu->gadget_driver->setup(&mtu->g, setup);
7462306a36Sopenharmony_ci	spin_lock(&mtu->lock);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret);
7762306a36Sopenharmony_ci	return ret;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
8362306a36Sopenharmony_ci	u16 index = 0;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n",
8662306a36Sopenharmony_ci		__func__, mep->epnum, len, src);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (len >= 4) {
8962306a36Sopenharmony_ci		iowrite32_rep(fifo, src, len >> 2);
9062306a36Sopenharmony_ci		index = len & ~0x03;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci	if (len & 0x02) {
9362306a36Sopenharmony_ci		writew(*(u16 *)&src[index], fifo);
9462306a36Sopenharmony_ci		index += 2;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci	if (len & 0x01)
9762306a36Sopenharmony_ci		writeb(src[index], fifo);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
10362306a36Sopenharmony_ci	u32 value;
10462306a36Sopenharmony_ci	u16 index = 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n",
10762306a36Sopenharmony_ci		 __func__, mep->epnum, len, dst);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (len >= 4) {
11062306a36Sopenharmony_ci		ioread32_rep(fifo, dst, len >> 2);
11162306a36Sopenharmony_ci		index = len & ~0x03;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	if (len & 0x3) {
11462306a36Sopenharmony_ci		value = readl(fifo);
11562306a36Sopenharmony_ci		memcpy(&dst[index], &value, len & 0x3);
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void ep0_load_test_packet(struct mtu3 *mtu)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * because the length of test packet is less than max packet of HS ep0,
12462306a36Sopenharmony_ci	 * write it into fifo directly.
12562306a36Sopenharmony_ci	 */
12662306a36Sopenharmony_ci	ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet));
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci * A. send STALL for setup transfer without data stage:
13162306a36Sopenharmony_ci *		set SENDSTALL and SETUPPKTRDY at the same time;
13262306a36Sopenharmony_ci * B. send STALL for other cases:
13362306a36Sopenharmony_ci *		set SENDSTALL only.
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_cistatic void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct mtu3 *mtu = mep0->mtu;
13862306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
13962306a36Sopenharmony_ci	u32 csr;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* EP0_SENTSTALL is W1C */
14262306a36Sopenharmony_ci	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
14362306a36Sopenharmony_ci	if (set)
14462306a36Sopenharmony_ci		csr |= EP0_SENDSTALL | pktrdy;
14562306a36Sopenharmony_ci	else
14662306a36Sopenharmony_ci		csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
14762306a36Sopenharmony_ci	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	mtu->delayed_status = false;
15062306a36Sopenharmony_ci	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n",
15362306a36Sopenharmony_ci		set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void ep0_do_status_stage(struct mtu3 *mtu)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
15962306a36Sopenharmony_ci	u32 value;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
16262306a36Sopenharmony_ci	mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
16862306a36Sopenharmony_ci{}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct mtu3_request *mreq;
17362306a36Sopenharmony_ci	struct mtu3 *mtu;
17462306a36Sopenharmony_ci	struct usb_set_sel_req sel;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	memcpy(&sel, req->buf, sizeof(sel));
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	mreq = to_mtu3_request(req);
17962306a36Sopenharmony_ci	mtu = mreq->mtu;
18062306a36Sopenharmony_ci	dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n",
18162306a36Sopenharmony_ci		sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/* queue data stage to handle 6 byte SET_SEL request */
18562306a36Sopenharmony_cistatic int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	int ret;
18862306a36Sopenharmony_ci	u16 length = le16_to_cpu(setup->wLength);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (unlikely(length != 6)) {
19162306a36Sopenharmony_ci		dev_err(mtu->dev, "%s wrong wLength:%d\n",
19262306a36Sopenharmony_ci			__func__, length);
19362306a36Sopenharmony_ci		return -EINVAL;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	mtu->ep0_req.mep = mtu->ep0;
19762306a36Sopenharmony_ci	mtu->ep0_req.request.length = 6;
19862306a36Sopenharmony_ci	mtu->ep0_req.request.buf = mtu->setup_buf;
19962306a36Sopenharmony_ci	mtu->ep0_req.request.complete = ep0_set_sel_complete;
20062306a36Sopenharmony_ci	ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return ret < 0 ? ret : 1;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int
20662306a36Sopenharmony_ciep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct mtu3_ep *mep = NULL;
20962306a36Sopenharmony_ci	int handled = 1;
21062306a36Sopenharmony_ci	u8 result[2] = {0, 0};
21162306a36Sopenharmony_ci	u8 epnum = 0;
21262306a36Sopenharmony_ci	int is_in;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	switch (setup->bRequestType & USB_RECIP_MASK) {
21562306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
21662306a36Sopenharmony_ci		result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
21762306a36Sopenharmony_ci		result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		if (mtu->g.speed >= USB_SPEED_SUPER) {
22062306a36Sopenharmony_ci			result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
22162306a36Sopenharmony_ci			result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__,
22562306a36Sopenharmony_ci			result[0], mtu->u1_enable, mtu->u2_enable);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		break;
22862306a36Sopenharmony_ci	case USB_RECIP_INTERFACE:
22962306a36Sopenharmony_ci		/* status of function remote wakeup, forward request */
23062306a36Sopenharmony_ci		handled = 0;
23162306a36Sopenharmony_ci		break;
23262306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
23362306a36Sopenharmony_ci		epnum = (u8) le16_to_cpu(setup->wIndex);
23462306a36Sopenharmony_ci		is_in = epnum & USB_DIR_IN;
23562306a36Sopenharmony_ci		epnum &= USB_ENDPOINT_NUMBER_MASK;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		if (epnum >= mtu->num_eps) {
23862306a36Sopenharmony_ci			handled = -EINVAL;
23962306a36Sopenharmony_ci			break;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci		if (!epnum)
24262306a36Sopenharmony_ci			break;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
24562306a36Sopenharmony_ci		if (!mep->desc) {
24662306a36Sopenharmony_ci			handled = -EINVAL;
24762306a36Sopenharmony_ci			break;
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci		if (mep->flags & MTU3_EP_STALL)
25062306a36Sopenharmony_ci			result[0] |= 1 << USB_ENDPOINT_HALT;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		break;
25362306a36Sopenharmony_ci	default:
25462306a36Sopenharmony_ci		/* class, vendor, etc ... delegate */
25562306a36Sopenharmony_ci		handled = 0;
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (handled > 0) {
26062306a36Sopenharmony_ci		int ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		/* prepare a data stage for GET_STATUS */
26362306a36Sopenharmony_ci		dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result);
26462306a36Sopenharmony_ci		memcpy(mtu->setup_buf, result, sizeof(result));
26562306a36Sopenharmony_ci		mtu->ep0_req.mep = mtu->ep0;
26662306a36Sopenharmony_ci		mtu->ep0_req.request.length = 2;
26762306a36Sopenharmony_ci		mtu->ep0_req.request.buf = &mtu->setup_buf;
26862306a36Sopenharmony_ci		mtu->ep0_req.request.complete = ep0_dummy_complete;
26962306a36Sopenharmony_ci		ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
27062306a36Sopenharmony_ci		if (ret < 0)
27162306a36Sopenharmony_ci			handled = ret;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	return handled;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
27962306a36Sopenharmony_ci	int handled = 1;
28062306a36Sopenharmony_ci	u32 value;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	switch (le16_to_cpu(setup->wIndex) >> 8) {
28362306a36Sopenharmony_ci	case USB_TEST_J:
28462306a36Sopenharmony_ci		dev_dbg(mtu->dev, "USB_TEST_J\n");
28562306a36Sopenharmony_ci		mtu->test_mode_nr = TEST_J_MODE;
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	case USB_TEST_K:
28862306a36Sopenharmony_ci		dev_dbg(mtu->dev, "USB_TEST_K\n");
28962306a36Sopenharmony_ci		mtu->test_mode_nr = TEST_K_MODE;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	case USB_TEST_SE0_NAK:
29262306a36Sopenharmony_ci		dev_dbg(mtu->dev, "USB_TEST_SE0_NAK\n");
29362306a36Sopenharmony_ci		mtu->test_mode_nr = TEST_SE0_NAK_MODE;
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	case USB_TEST_PACKET:
29662306a36Sopenharmony_ci		dev_dbg(mtu->dev, "USB_TEST_PACKET\n");
29762306a36Sopenharmony_ci		mtu->test_mode_nr = TEST_PACKET_MODE;
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	default:
30062306a36Sopenharmony_ci		handled = -EINVAL;
30162306a36Sopenharmony_ci		goto out;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	mtu->test_mode = true;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* no TX completion interrupt, and need restart platform after test */
30762306a36Sopenharmony_ci	if (mtu->test_mode_nr == TEST_PACKET_MODE)
30862306a36Sopenharmony_ci		ep0_load_test_packet(mtu);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* send status before entering test mode. */
31162306a36Sopenharmony_ci	ep0_do_status_stage(mtu);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* wait for ACK status sent by host */
31462306a36Sopenharmony_ci	readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value,
31562306a36Sopenharmony_ci			!(value & EP0_DATAEND), 100, 5000);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciout:
32262306a36Sopenharmony_ci	return handled;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int ep0_handle_feature_dev(struct mtu3 *mtu,
32662306a36Sopenharmony_ci		struct usb_ctrlrequest *setup, bool set)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
32962306a36Sopenharmony_ci	int handled = -EINVAL;
33062306a36Sopenharmony_ci	u32 lpc;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	switch (le16_to_cpu(setup->wValue)) {
33362306a36Sopenharmony_ci	case USB_DEVICE_REMOTE_WAKEUP:
33462306a36Sopenharmony_ci		mtu->may_wakeup = !!set;
33562306a36Sopenharmony_ci		handled = 1;
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case USB_DEVICE_TEST_MODE:
33862306a36Sopenharmony_ci		if (!set || (mtu->g.speed != USB_SPEED_HIGH) ||
33962306a36Sopenharmony_ci			(le16_to_cpu(setup->wIndex) & 0xff))
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		handled = handle_test_mode(mtu, setup);
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	case USB_DEVICE_U1_ENABLE:
34562306a36Sopenharmony_ci		if (mtu->g.speed < USB_SPEED_SUPER ||
34662306a36Sopenharmony_ci		    mtu->g.state != USB_STATE_CONFIGURED)
34762306a36Sopenharmony_ci			break;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
35062306a36Sopenharmony_ci		if (set)
35162306a36Sopenharmony_ci			lpc |= SW_U1_REQUEST_ENABLE;
35262306a36Sopenharmony_ci		else
35362306a36Sopenharmony_ci			lpc &= ~SW_U1_REQUEST_ENABLE;
35462306a36Sopenharmony_ci		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		mtu->u1_enable = !!set;
35762306a36Sopenharmony_ci		handled = 1;
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	case USB_DEVICE_U2_ENABLE:
36062306a36Sopenharmony_ci		if (mtu->g.speed < USB_SPEED_SUPER ||
36162306a36Sopenharmony_ci		    mtu->g.state != USB_STATE_CONFIGURED)
36262306a36Sopenharmony_ci			break;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
36562306a36Sopenharmony_ci		if (set)
36662306a36Sopenharmony_ci			lpc |= SW_U2_REQUEST_ENABLE;
36762306a36Sopenharmony_ci		else
36862306a36Sopenharmony_ci			lpc &= ~SW_U2_REQUEST_ENABLE;
36962306a36Sopenharmony_ci		mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		mtu->u2_enable = !!set;
37262306a36Sopenharmony_ci		handled = 1;
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	default:
37562306a36Sopenharmony_ci		handled = -EINVAL;
37662306a36Sopenharmony_ci		break;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	return handled;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int ep0_handle_feature(struct mtu3 *mtu,
38262306a36Sopenharmony_ci		struct usb_ctrlrequest *setup, bool set)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct mtu3_ep *mep;
38562306a36Sopenharmony_ci	int handled = -EINVAL;
38662306a36Sopenharmony_ci	int is_in;
38762306a36Sopenharmony_ci	u16 value;
38862306a36Sopenharmony_ci	u16 index;
38962306a36Sopenharmony_ci	u8 epnum;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	value = le16_to_cpu(setup->wValue);
39262306a36Sopenharmony_ci	index = le16_to_cpu(setup->wIndex);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	switch (setup->bRequestType & USB_RECIP_MASK) {
39562306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
39662306a36Sopenharmony_ci		handled = ep0_handle_feature_dev(mtu, setup, set);
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	case USB_RECIP_INTERFACE:
39962306a36Sopenharmony_ci		/* superspeed only */
40062306a36Sopenharmony_ci		if (value == USB_INTRF_FUNC_SUSPEND &&
40162306a36Sopenharmony_ci		    mtu->g.speed >= USB_SPEED_SUPER) {
40262306a36Sopenharmony_ci			/* forward the request for function suspend */
40362306a36Sopenharmony_ci			mtu->may_wakeup = !!(index & USB_INTRF_FUNC_SUSPEND_RW);
40462306a36Sopenharmony_ci			handled = 0;
40562306a36Sopenharmony_ci		}
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
40862306a36Sopenharmony_ci		epnum = index & USB_ENDPOINT_NUMBER_MASK;
40962306a36Sopenharmony_ci		if (epnum == 0 || epnum >= mtu->num_eps ||
41062306a36Sopenharmony_ci			value != USB_ENDPOINT_HALT)
41162306a36Sopenharmony_ci			break;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		is_in = index & USB_DIR_IN;
41462306a36Sopenharmony_ci		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
41562306a36Sopenharmony_ci		if (!mep->desc)
41662306a36Sopenharmony_ci			break;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		handled = 1;
41962306a36Sopenharmony_ci		/* ignore request if endpoint is wedged */
42062306a36Sopenharmony_ci		if (mep->flags & MTU3_EP_WEDGE)
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		mtu3_ep_stall_set(mep, set);
42462306a36Sopenharmony_ci		break;
42562306a36Sopenharmony_ci	default:
42662306a36Sopenharmony_ci		/* class, vendor, etc ... delegate */
42762306a36Sopenharmony_ci		handled = 0;
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci	return handled;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/*
43462306a36Sopenharmony_ci * handle all control requests can be handled
43562306a36Sopenharmony_ci * returns:
43662306a36Sopenharmony_ci *	negative errno - error happened
43762306a36Sopenharmony_ci *	zero - need delegate SETUP to gadget driver
43862306a36Sopenharmony_ci *	positive - already handled
43962306a36Sopenharmony_ci */
44062306a36Sopenharmony_cistatic int handle_standard_request(struct mtu3 *mtu,
44162306a36Sopenharmony_ci			  struct usb_ctrlrequest *setup)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
44462306a36Sopenharmony_ci	enum usb_device_state state = mtu->g.state;
44562306a36Sopenharmony_ci	int handled = -EINVAL;
44662306a36Sopenharmony_ci	u32 dev_conf;
44762306a36Sopenharmony_ci	u16 value;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	value = le16_to_cpu(setup->wValue);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* the gadget driver handles everything except what we must handle */
45262306a36Sopenharmony_ci	switch (setup->bRequest) {
45362306a36Sopenharmony_ci	case USB_REQ_SET_ADDRESS:
45462306a36Sopenharmony_ci		/* change it after the status stage */
45562306a36Sopenharmony_ci		mtu->address = (u8) (value & 0x7f);
45662306a36Sopenharmony_ci		dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF);
45962306a36Sopenharmony_ci		dev_conf &= ~DEV_ADDR_MSK;
46062306a36Sopenharmony_ci		dev_conf |= DEV_ADDR(mtu->address);
46162306a36Sopenharmony_ci		mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		if (mtu->address)
46462306a36Sopenharmony_ci			usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS);
46562306a36Sopenharmony_ci		else
46662306a36Sopenharmony_ci			usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		handled = 1;
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	case USB_REQ_SET_CONFIGURATION:
47162306a36Sopenharmony_ci		if (state == USB_STATE_ADDRESS) {
47262306a36Sopenharmony_ci			usb_gadget_set_state(&mtu->g,
47362306a36Sopenharmony_ci					USB_STATE_CONFIGURED);
47462306a36Sopenharmony_ci		} else if (state == USB_STATE_CONFIGURED) {
47562306a36Sopenharmony_ci			/*
47662306a36Sopenharmony_ci			 * USB2 spec sec 9.4.7, if wValue is 0 then dev
47762306a36Sopenharmony_ci			 * is moved to addressed state
47862306a36Sopenharmony_ci			 */
47962306a36Sopenharmony_ci			if (!value)
48062306a36Sopenharmony_ci				usb_gadget_set_state(&mtu->g,
48162306a36Sopenharmony_ci						USB_STATE_ADDRESS);
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci		handled = 0;
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	case USB_REQ_CLEAR_FEATURE:
48662306a36Sopenharmony_ci		handled = ep0_handle_feature(mtu, setup, 0);
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	case USB_REQ_SET_FEATURE:
48962306a36Sopenharmony_ci		handled = ep0_handle_feature(mtu, setup, 1);
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	case USB_REQ_GET_STATUS:
49262306a36Sopenharmony_ci		handled = ep0_get_status(mtu, setup);
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	case USB_REQ_SET_SEL:
49562306a36Sopenharmony_ci		handled = ep0_set_sel(mtu, setup);
49662306a36Sopenharmony_ci		break;
49762306a36Sopenharmony_ci	case USB_REQ_SET_ISOCH_DELAY:
49862306a36Sopenharmony_ci		handled = 1;
49962306a36Sopenharmony_ci		break;
50062306a36Sopenharmony_ci	default:
50162306a36Sopenharmony_ci		/* delegate SET_CONFIGURATION, etc */
50262306a36Sopenharmony_ci		handled = 0;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return handled;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/* receive an data packet (OUT) */
50962306a36Sopenharmony_cistatic void ep0_rx_state(struct mtu3 *mtu)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct mtu3_request *mreq;
51262306a36Sopenharmony_ci	struct usb_request *req;
51362306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
51462306a36Sopenharmony_ci	u32 maxp;
51562306a36Sopenharmony_ci	u32 csr;
51662306a36Sopenharmony_ci	u16 count = 0;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s\n", __func__);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
52162306a36Sopenharmony_ci	mreq = next_ep0_request(mtu);
52262306a36Sopenharmony_ci	req = &mreq->request;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* read packet and ack; or stall because of gadget driver bug */
52562306a36Sopenharmony_ci	if (req) {
52662306a36Sopenharmony_ci		void *buf = req->buf + req->actual;
52762306a36Sopenharmony_ci		unsigned int len = req->length - req->actual;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		/* read the buffer */
53062306a36Sopenharmony_ci		count = mtu3_readl(mbase, U3D_RXCOUNT0);
53162306a36Sopenharmony_ci		if (count > len) {
53262306a36Sopenharmony_ci			req->status = -EOVERFLOW;
53362306a36Sopenharmony_ci			count = len;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci		ep0_read_fifo(mtu->ep0, buf, count);
53662306a36Sopenharmony_ci		req->actual += count;
53762306a36Sopenharmony_ci		csr |= EP0_RXPKTRDY;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		maxp = mtu->g.ep0->maxpacket;
54062306a36Sopenharmony_ci		if (count < maxp || req->actual == req->length) {
54162306a36Sopenharmony_ci			mtu->ep0_state = MU3D_EP0_STATE_SETUP;
54262306a36Sopenharmony_ci			dev_dbg(mtu->dev, "ep0 state: %s\n",
54362306a36Sopenharmony_ci				decode_ep0_state(mtu));
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci			csr |= EP0_DATAEND;
54662306a36Sopenharmony_ci		} else {
54762306a36Sopenharmony_ci			req = NULL;
54862306a36Sopenharmony_ci		}
54962306a36Sopenharmony_ci	} else {
55062306a36Sopenharmony_ci		csr |= EP0_RXPKTRDY | EP0_SENDSTALL;
55162306a36Sopenharmony_ci		dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__);
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	mtu3_writel(mbase, U3D_EP0CSR, csr);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* give back the request if have received all data */
55762306a36Sopenharmony_ci	if (req)
55862306a36Sopenharmony_ci		ep0_req_giveback(mtu, req);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/* transmitting to the host (IN) */
56362306a36Sopenharmony_cistatic void ep0_tx_state(struct mtu3 *mtu)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct mtu3_request *mreq = next_ep0_request(mtu);
56662306a36Sopenharmony_ci	struct usb_request *req;
56762306a36Sopenharmony_ci	u32 csr;
56862306a36Sopenharmony_ci	u8 *src;
56962306a36Sopenharmony_ci	u32 count;
57062306a36Sopenharmony_ci	u32 maxp;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s\n", __func__);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (!mreq)
57562306a36Sopenharmony_ci		return;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	maxp = mtu->g.ep0->maxpacket;
57862306a36Sopenharmony_ci	req = &mreq->request;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* load the data */
58162306a36Sopenharmony_ci	src = (u8 *)req->buf + req->actual;
58262306a36Sopenharmony_ci	count = min(maxp, req->length - req->actual);
58362306a36Sopenharmony_ci	if (count)
58462306a36Sopenharmony_ci		ep0_write_fifo(mtu->ep0, src, count);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n",
58762306a36Sopenharmony_ci		 __func__, req->actual, req->length, count, maxp, req->zero);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	req->actual += count;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if ((count < maxp)
59262306a36Sopenharmony_ci		|| ((req->actual == req->length) && !req->zero))
59362306a36Sopenharmony_ci		mtu->ep0_state = MU3D_EP0_STATE_TX_END;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* send it out, triggering a "txpktrdy cleared" irq */
59662306a36Sopenharmony_ci	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
59762306a36Sopenharmony_ci	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__,
60062306a36Sopenharmony_ci		mtu3_readl(mtu->mac_base, U3D_EP0CSR));
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct mtu3_request *mreq;
60662306a36Sopenharmony_ci	u32 count;
60762306a36Sopenharmony_ci	u32 csr;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
61062306a36Sopenharmony_ci	count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ep0_read_fifo(mtu->ep0, (u8 *)setup, count);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n",
61562306a36Sopenharmony_ci		 setup->bRequestType, setup->bRequest,
61662306a36Sopenharmony_ci		 le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex),
61762306a36Sopenharmony_ci		 le16_to_cpu(setup->wLength));
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* clean up any leftover transfers */
62062306a36Sopenharmony_ci	mreq = next_ep0_request(mtu);
62162306a36Sopenharmony_ci	if (mreq)
62262306a36Sopenharmony_ci		ep0_req_giveback(mtu, &mreq->request);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (le16_to_cpu(setup->wLength) == 0) {
62562306a36Sopenharmony_ci		;	/* no data stage, nothing to do */
62662306a36Sopenharmony_ci	} else if (setup->bRequestType & USB_DIR_IN) {
62762306a36Sopenharmony_ci		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
62862306a36Sopenharmony_ci			csr | EP0_SETUPPKTRDY | EP0_DPHTX);
62962306a36Sopenharmony_ci		mtu->ep0_state = MU3D_EP0_STATE_TX;
63062306a36Sopenharmony_ci	} else {
63162306a36Sopenharmony_ci		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
63262306a36Sopenharmony_ci			(csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX));
63362306a36Sopenharmony_ci		mtu->ep0_state = MU3D_EP0_STATE_RX;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic int ep0_handle_setup(struct mtu3 *mtu)
63862306a36Sopenharmony_ci__releases(mtu->lock)
63962306a36Sopenharmony_ci__acquires(mtu->lock)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct usb_ctrlrequest setup;
64262306a36Sopenharmony_ci	struct mtu3_request *mreq;
64362306a36Sopenharmony_ci	int handled = 0;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	ep0_read_setup(mtu, &setup);
64662306a36Sopenharmony_ci	trace_mtu3_handle_setup(&setup);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
64962306a36Sopenharmony_ci		handled = handle_standard_request(mtu, &setup);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n",
65262306a36Sopenharmony_ci		 handled, decode_ep0_state(mtu));
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (handled < 0)
65562306a36Sopenharmony_ci		goto stall;
65662306a36Sopenharmony_ci	else if (handled > 0)
65762306a36Sopenharmony_ci		goto finish;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	handled = forward_to_driver(mtu, &setup);
66062306a36Sopenharmony_ci	if (handled < 0) {
66162306a36Sopenharmony_cistall:
66262306a36Sopenharmony_ci		dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		ep0_stall_set(mtu->ep0, true,
66562306a36Sopenharmony_ci			le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		return 0;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cifinish:
67162306a36Sopenharmony_ci	if (mtu->test_mode) {
67262306a36Sopenharmony_ci		;	/* nothing to do */
67362306a36Sopenharmony_ci	} else if (handled == USB_GADGET_DELAYED_STATUS) {
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		mreq = next_ep0_request(mtu);
67662306a36Sopenharmony_ci		if (mreq) {
67762306a36Sopenharmony_ci			/* already asked us to continue delayed status */
67862306a36Sopenharmony_ci			ep0_do_status_stage(mtu);
67962306a36Sopenharmony_ci			ep0_req_giveback(mtu, &mreq->request);
68062306a36Sopenharmony_ci		} else {
68162306a36Sopenharmony_ci			/* do delayed STATUS stage till receive ep0_queue */
68262306a36Sopenharmony_ci			mtu->delayed_status = true;
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci	} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		ep0_do_status_stage(mtu);
68762306a36Sopenharmony_ci		/* complete zlp request directly */
68862306a36Sopenharmony_ci		mreq = next_ep0_request(mtu);
68962306a36Sopenharmony_ci		if (mreq && !mreq->request.length)
69062306a36Sopenharmony_ci			ep0_req_giveback(mtu, &mreq->request);
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ciirqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	void __iomem *mbase = mtu->mac_base;
69962306a36Sopenharmony_ci	struct mtu3_request *mreq;
70062306a36Sopenharmony_ci	u32 int_status;
70162306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
70262306a36Sopenharmony_ci	u32 csr;
70362306a36Sopenharmony_ci	u32 len;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	int_status = mtu3_readl(mbase, U3D_EPISR);
70662306a36Sopenharmony_ci	int_status &= mtu3_readl(mbase, U3D_EPIER);
70762306a36Sopenharmony_ci	mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* only handle ep0's */
71062306a36Sopenharmony_ci	if (!(int_status & (EP0ISR | SETUPENDISR)))
71162306a36Sopenharmony_ci		return IRQ_NONE;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* abort current SETUP, and process new one */
71462306a36Sopenharmony_ci	if (int_status & SETUPENDISR)
71562306a36Sopenharmony_ci		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	csr = mtu3_readl(mbase, U3D_EP0CSR);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* we sent a stall.. need to clear it now.. */
72262306a36Sopenharmony_ci	if (csr & EP0_SENTSTALL) {
72362306a36Sopenharmony_ci		ep0_stall_set(mtu->ep0, false, 0);
72462306a36Sopenharmony_ci		csr = mtu3_readl(mbase, U3D_EP0CSR);
72562306a36Sopenharmony_ci		ret = IRQ_HANDLED;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci	dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
72862306a36Sopenharmony_ci	mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu));
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	switch (mtu->ep0_state) {
73162306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX:
73262306a36Sopenharmony_ci		/* irq on clearing txpktrdy */
73362306a36Sopenharmony_ci		if ((csr & EP0_FIFOFULL) == 0) {
73462306a36Sopenharmony_ci			ep0_tx_state(mtu);
73562306a36Sopenharmony_ci			ret = IRQ_HANDLED;
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci		break;
73862306a36Sopenharmony_ci	case MU3D_EP0_STATE_RX:
73962306a36Sopenharmony_ci		/* irq on set rxpktrdy */
74062306a36Sopenharmony_ci		if (csr & EP0_RXPKTRDY) {
74162306a36Sopenharmony_ci			ep0_rx_state(mtu);
74262306a36Sopenharmony_ci			ret = IRQ_HANDLED;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci		break;
74562306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX_END:
74662306a36Sopenharmony_ci		mtu3_writel(mbase, U3D_EP0CSR,
74762306a36Sopenharmony_ci			(csr & EP0_W1C_BITS) | EP0_DATAEND);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci		mreq = next_ep0_request(mtu);
75062306a36Sopenharmony_ci		if (mreq)
75162306a36Sopenharmony_ci			ep0_req_giveback(mtu, &mreq->request);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
75462306a36Sopenharmony_ci		ret = IRQ_HANDLED;
75562306a36Sopenharmony_ci		dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
75662306a36Sopenharmony_ci		break;
75762306a36Sopenharmony_ci	case MU3D_EP0_STATE_SETUP:
75862306a36Sopenharmony_ci		if (!(csr & EP0_SETUPPKTRDY))
75962306a36Sopenharmony_ci			break;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		len = mtu3_readl(mbase, U3D_RXCOUNT0);
76262306a36Sopenharmony_ci		if (len != 8) {
76362306a36Sopenharmony_ci			dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len);
76462306a36Sopenharmony_ci			break;
76562306a36Sopenharmony_ci		}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		ep0_handle_setup(mtu);
76862306a36Sopenharmony_ci		ret = IRQ_HANDLED;
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci	default:
77162306a36Sopenharmony_ci		/* can't happen */
77262306a36Sopenharmony_ci		ep0_stall_set(mtu->ep0, true, 0);
77362306a36Sopenharmony_ci		WARN_ON(1);
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int mtu3_ep0_enable(struct usb_ep *ep,
78262306a36Sopenharmony_ci	const struct usb_endpoint_descriptor *desc)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	/* always enabled */
78562306a36Sopenharmony_ci	return -EINVAL;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic int mtu3_ep0_disable(struct usb_ep *ep)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	/* always enabled */
79162306a36Sopenharmony_ci	return -EINVAL;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	struct mtu3 *mtu = mep->mtu;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	mreq->mtu = mtu;
79962306a36Sopenharmony_ci	mreq->request.actual = 0;
80062306a36Sopenharmony_ci	mreq->request.status = -EINPROGRESS;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,
80362306a36Sopenharmony_ci		mep->name, decode_ep0_state(mtu), mreq->request.length);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	switch (mtu->ep0_state) {
80662306a36Sopenharmony_ci	case MU3D_EP0_STATE_SETUP:
80762306a36Sopenharmony_ci	case MU3D_EP0_STATE_RX:	/* control-OUT data */
80862306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX:	/* control-IN data */
80962306a36Sopenharmony_ci		break;
81062306a36Sopenharmony_ci	default:
81162306a36Sopenharmony_ci		dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__,
81262306a36Sopenharmony_ci			decode_ep0_state(mtu));
81362306a36Sopenharmony_ci		return -EINVAL;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (mtu->delayed_status) {
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		mtu->delayed_status = false;
81962306a36Sopenharmony_ci		ep0_do_status_stage(mtu);
82062306a36Sopenharmony_ci		/* needn't giveback the request for handling delay STATUS */
82162306a36Sopenharmony_ci		return 0;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (!list_empty(&mep->req_list))
82562306a36Sopenharmony_ci		return -EBUSY;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	list_add_tail(&mreq->list, &mep->req_list);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* sequence #1, IN ... start writing the data */
83062306a36Sopenharmony_ci	if (mtu->ep0_state == MU3D_EP0_STATE_TX)
83162306a36Sopenharmony_ci		ep0_tx_state(mtu);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	return 0;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int mtu3_ep0_queue(struct usb_ep *ep,
83762306a36Sopenharmony_ci	struct usb_request *req, gfp_t gfp)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct mtu3_ep *mep;
84062306a36Sopenharmony_ci	struct mtu3_request *mreq;
84162306a36Sopenharmony_ci	struct mtu3 *mtu;
84262306a36Sopenharmony_ci	unsigned long flags;
84362306a36Sopenharmony_ci	int ret = 0;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (!ep || !req)
84662306a36Sopenharmony_ci		return -EINVAL;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	mep = to_mtu3_ep(ep);
84962306a36Sopenharmony_ci	mtu = mep->mtu;
85062306a36Sopenharmony_ci	mreq = to_mtu3_request(req);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	spin_lock_irqsave(&mtu->lock, flags);
85362306a36Sopenharmony_ci	ret = ep0_queue(mep, mreq);
85462306a36Sopenharmony_ci	spin_unlock_irqrestore(&mtu->lock, flags);
85562306a36Sopenharmony_ci	return ret;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	/* we just won't support this */
86162306a36Sopenharmony_ci	return -EINVAL;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int mtu3_ep0_halt(struct usb_ep *ep, int value)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct mtu3_ep *mep;
86762306a36Sopenharmony_ci	struct mtu3 *mtu;
86862306a36Sopenharmony_ci	unsigned long flags;
86962306a36Sopenharmony_ci	int ret = 0;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (!ep || !value)
87262306a36Sopenharmony_ci		return -EINVAL;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	mep = to_mtu3_ep(ep);
87562306a36Sopenharmony_ci	mtu = mep->mtu;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	dev_dbg(mtu->dev, "%s\n", __func__);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	spin_lock_irqsave(&mtu->lock, flags);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (!list_empty(&mep->req_list)) {
88262306a36Sopenharmony_ci		ret = -EBUSY;
88362306a36Sopenharmony_ci		goto cleanup;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	switch (mtu->ep0_state) {
88762306a36Sopenharmony_ci	/*
88862306a36Sopenharmony_ci	 * stalls are usually issued after parsing SETUP packet, either
88962306a36Sopenharmony_ci	 * directly in irq context from setup() or else later.
89062306a36Sopenharmony_ci	 */
89162306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX:
89262306a36Sopenharmony_ci	case MU3D_EP0_STATE_TX_END:
89362306a36Sopenharmony_ci	case MU3D_EP0_STATE_RX:
89462306a36Sopenharmony_ci	case MU3D_EP0_STATE_SETUP:
89562306a36Sopenharmony_ci		ep0_stall_set(mtu->ep0, true, 0);
89662306a36Sopenharmony_ci		break;
89762306a36Sopenharmony_ci	default:
89862306a36Sopenharmony_ci		dev_dbg(mtu->dev, "ep0 can't halt in state %s\n",
89962306a36Sopenharmony_ci			decode_ep0_state(mtu));
90062306a36Sopenharmony_ci		ret = -EINVAL;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cicleanup:
90462306a36Sopenharmony_ci	spin_unlock_irqrestore(&mtu->lock, flags);
90562306a36Sopenharmony_ci	return ret;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ciconst struct usb_ep_ops mtu3_ep0_ops = {
90962306a36Sopenharmony_ci	.enable = mtu3_ep0_enable,
91062306a36Sopenharmony_ci	.disable = mtu3_ep0_disable,
91162306a36Sopenharmony_ci	.alloc_request = mtu3_alloc_request,
91262306a36Sopenharmony_ci	.free_request = mtu3_free_request,
91362306a36Sopenharmony_ci	.queue = mtu3_ep0_queue,
91462306a36Sopenharmony_ci	.dequeue = mtu3_ep0_dequeue,
91562306a36Sopenharmony_ci	.set_halt = mtu3_ep0_halt,
91662306a36Sopenharmony_ci};
917