15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2df2069acSChunfeng Yun /* 3df2069acSChunfeng Yun * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling 4df2069acSChunfeng Yun * 5df2069acSChunfeng Yun * Copyright (c) 2016 MediaTek Inc. 6df2069acSChunfeng Yun * 7df2069acSChunfeng Yun * Author: Chunfeng.Yun <chunfeng.yun@mediatek.com> 8df2069acSChunfeng Yun */ 9df2069acSChunfeng Yun 10f3b28e5eSChunfeng Yun #include <linux/iopoll.h> 11fe7c994aSChunfeng Yun #include <linux/usb/composite.h> 12fe7c994aSChunfeng Yun 13df2069acSChunfeng Yun #include "mtu3.h" 1483374e03SChunfeng Yun #include "mtu3_debug.h" 1583374e03SChunfeng Yun #include "mtu3_trace.h" 16df2069acSChunfeng Yun 17df2069acSChunfeng Yun /* ep0 is always mtu3->in_eps[0] */ 18df2069acSChunfeng Yun #define next_ep0_request(mtu) next_request((mtu)->ep0) 19df2069acSChunfeng Yun 20df2069acSChunfeng Yun /* for high speed test mode; see USB 2.0 spec 7.1.20 */ 21df2069acSChunfeng Yun static const u8 mtu3_test_packet[53] = { 22df2069acSChunfeng Yun /* implicit SYNC then DATA0 to start */ 23df2069acSChunfeng Yun 24df2069acSChunfeng Yun /* JKJKJKJK x9 */ 25df2069acSChunfeng Yun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26df2069acSChunfeng Yun /* JJKKJJKK x8 */ 27df2069acSChunfeng Yun 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 28df2069acSChunfeng Yun /* JJJJKKKK x8 */ 29df2069acSChunfeng Yun 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 30df2069acSChunfeng Yun /* JJJJJJJKKKKKKK x8 */ 31df2069acSChunfeng Yun 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 32df2069acSChunfeng Yun /* JJJJJJJK x8 */ 33df2069acSChunfeng Yun 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 34df2069acSChunfeng Yun /* JKKKKKKK x10, JK */ 35df2069acSChunfeng Yun 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e, 36df2069acSChunfeng Yun /* implicit CRC16 then EOP to end */ 37df2069acSChunfeng Yun }; 38df2069acSChunfeng Yun 39df2069acSChunfeng Yun static char *decode_ep0_state(struct mtu3 *mtu) 40df2069acSChunfeng Yun { 41df2069acSChunfeng Yun switch (mtu->ep0_state) { 42df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 43df2069acSChunfeng Yun return "SETUP"; 44df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 45df2069acSChunfeng Yun return "IN"; 46df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 47df2069acSChunfeng Yun return "OUT"; 48df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 49df2069acSChunfeng Yun return "TX-END"; 50df2069acSChunfeng Yun case MU3D_EP0_STATE_STALL: 51df2069acSChunfeng Yun return "STALL"; 52df2069acSChunfeng Yun default: 53df2069acSChunfeng Yun return "??"; 54df2069acSChunfeng Yun } 55df2069acSChunfeng Yun } 56df2069acSChunfeng Yun 57df2069acSChunfeng Yun static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req) 58df2069acSChunfeng Yun { 59df2069acSChunfeng Yun mtu3_req_complete(mtu->ep0, req, 0); 60df2069acSChunfeng Yun } 61df2069acSChunfeng Yun 62df2069acSChunfeng Yun static int 63df2069acSChunfeng Yun forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 64df2069acSChunfeng Yun __releases(mtu->lock) 65df2069acSChunfeng Yun __acquires(mtu->lock) 66df2069acSChunfeng Yun { 67df2069acSChunfeng Yun int ret; 68df2069acSChunfeng Yun 69df2069acSChunfeng Yun if (!mtu->gadget_driver) 70df2069acSChunfeng Yun return -EOPNOTSUPP; 71df2069acSChunfeng Yun 72df2069acSChunfeng Yun spin_unlock(&mtu->lock); 73df2069acSChunfeng Yun ret = mtu->gadget_driver->setup(&mtu->g, setup); 74df2069acSChunfeng Yun spin_lock(&mtu->lock); 75df2069acSChunfeng Yun 76df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret); 77df2069acSChunfeng Yun return ret; 78df2069acSChunfeng Yun } 79df2069acSChunfeng Yun 80df2069acSChunfeng Yun static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len) 81df2069acSChunfeng Yun { 82df2069acSChunfeng Yun void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 83df2069acSChunfeng Yun u16 index = 0; 84df2069acSChunfeng Yun 85df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n", 86df2069acSChunfeng Yun __func__, mep->epnum, len, src); 87df2069acSChunfeng Yun 88df2069acSChunfeng Yun if (len >= 4) { 89df2069acSChunfeng Yun iowrite32_rep(fifo, src, len >> 2); 90df2069acSChunfeng Yun index = len & ~0x03; 91df2069acSChunfeng Yun } 92df2069acSChunfeng Yun if (len & 0x02) { 93df2069acSChunfeng Yun writew(*(u16 *)&src[index], fifo); 94df2069acSChunfeng Yun index += 2; 95df2069acSChunfeng Yun } 96df2069acSChunfeng Yun if (len & 0x01) 97df2069acSChunfeng Yun writeb(src[index], fifo); 98df2069acSChunfeng Yun } 99df2069acSChunfeng Yun 100df2069acSChunfeng Yun static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len) 101df2069acSChunfeng Yun { 102df2069acSChunfeng Yun void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 103df2069acSChunfeng Yun u32 value; 104df2069acSChunfeng Yun u16 index = 0; 105df2069acSChunfeng Yun 106df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n", 107df2069acSChunfeng Yun __func__, mep->epnum, len, dst); 108df2069acSChunfeng Yun 109df2069acSChunfeng Yun if (len >= 4) { 110df2069acSChunfeng Yun ioread32_rep(fifo, dst, len >> 2); 111df2069acSChunfeng Yun index = len & ~0x03; 112df2069acSChunfeng Yun } 113df2069acSChunfeng Yun if (len & 0x3) { 114df2069acSChunfeng Yun value = readl(fifo); 115df2069acSChunfeng Yun memcpy(&dst[index], &value, len & 0x3); 116df2069acSChunfeng Yun } 117df2069acSChunfeng Yun 118df2069acSChunfeng Yun } 119df2069acSChunfeng Yun 120df2069acSChunfeng Yun static void ep0_load_test_packet(struct mtu3 *mtu) 121df2069acSChunfeng Yun { 122df2069acSChunfeng Yun /* 123df2069acSChunfeng Yun * because the length of test packet is less than max packet of HS ep0, 124df2069acSChunfeng Yun * write it into fifo directly. 125df2069acSChunfeng Yun */ 126df2069acSChunfeng Yun ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet)); 127df2069acSChunfeng Yun } 128df2069acSChunfeng Yun 129df2069acSChunfeng Yun /* 130df2069acSChunfeng Yun * A. send STALL for setup transfer without data stage: 131df2069acSChunfeng Yun * set SENDSTALL and SETUPPKTRDY at the same time; 132df2069acSChunfeng Yun * B. send STALL for other cases: 133df2069acSChunfeng Yun * set SENDSTALL only. 134df2069acSChunfeng Yun */ 135df2069acSChunfeng Yun static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) 136df2069acSChunfeng Yun { 137df2069acSChunfeng Yun struct mtu3 *mtu = mep0->mtu; 138df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 139df2069acSChunfeng Yun u32 csr; 140df2069acSChunfeng Yun 141df2069acSChunfeng Yun /* EP0_SENTSTALL is W1C */ 142df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 143df2069acSChunfeng Yun if (set) 144df2069acSChunfeng Yun csr |= EP0_SENDSTALL | pktrdy; 145df2069acSChunfeng Yun else 146df2069acSChunfeng Yun csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; 147df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); 148df2069acSChunfeng Yun 149fe7c994aSChunfeng Yun mtu->delayed_status = false; 150df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 151df2069acSChunfeng Yun 152df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", 153df2069acSChunfeng Yun set ? "SEND" : "CLEAR", decode_ep0_state(mtu)); 154df2069acSChunfeng Yun } 155df2069acSChunfeng Yun 15671460342SChunfeng Yun static void ep0_do_status_stage(struct mtu3 *mtu) 15771460342SChunfeng Yun { 15871460342SChunfeng Yun void __iomem *mbase = mtu->mac_base; 15971460342SChunfeng Yun u32 value; 16071460342SChunfeng Yun 16171460342SChunfeng Yun value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 16271460342SChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND); 16371460342SChunfeng Yun } 16471460342SChunfeng Yun 165df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq); 166df2069acSChunfeng Yun 167df2069acSChunfeng Yun static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req) 168df2069acSChunfeng Yun {} 169df2069acSChunfeng Yun 170a29de31bSChunfeng Yun static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req) 171a29de31bSChunfeng Yun { 172a29de31bSChunfeng Yun struct mtu3_request *mreq; 173a29de31bSChunfeng Yun struct mtu3 *mtu; 174a29de31bSChunfeng Yun struct usb_set_sel_req sel; 175a29de31bSChunfeng Yun 176a29de31bSChunfeng Yun memcpy(&sel, req->buf, sizeof(sel)); 177a29de31bSChunfeng Yun 178a29de31bSChunfeng Yun mreq = to_mtu3_request(req); 179a29de31bSChunfeng Yun mtu = mreq->mtu; 180a29de31bSChunfeng Yun dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n", 181a29de31bSChunfeng Yun sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel); 182a29de31bSChunfeng Yun } 183a29de31bSChunfeng Yun 184a29de31bSChunfeng Yun /* queue data stage to handle 6 byte SET_SEL request */ 185a29de31bSChunfeng Yun static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 186a29de31bSChunfeng Yun { 187a29de31bSChunfeng Yun int ret; 188a29de31bSChunfeng Yun u16 length = le16_to_cpu(setup->wLength); 189a29de31bSChunfeng Yun 190a29de31bSChunfeng Yun if (unlikely(length != 6)) { 191a29de31bSChunfeng Yun dev_err(mtu->dev, "%s wrong wLength:%d\n", 192a29de31bSChunfeng Yun __func__, length); 193a29de31bSChunfeng Yun return -EINVAL; 194a29de31bSChunfeng Yun } 195a29de31bSChunfeng Yun 196a29de31bSChunfeng Yun mtu->ep0_req.mep = mtu->ep0; 197a29de31bSChunfeng Yun mtu->ep0_req.request.length = 6; 198a29de31bSChunfeng Yun mtu->ep0_req.request.buf = mtu->setup_buf; 199a29de31bSChunfeng Yun mtu->ep0_req.request.complete = ep0_set_sel_complete; 200a29de31bSChunfeng Yun ret = ep0_queue(mtu->ep0, &mtu->ep0_req); 201a29de31bSChunfeng Yun 202a29de31bSChunfeng Yun return ret < 0 ? ret : 1; 203a29de31bSChunfeng Yun } 204a29de31bSChunfeng Yun 205df2069acSChunfeng Yun static int 206df2069acSChunfeng Yun ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 207df2069acSChunfeng Yun { 208df2069acSChunfeng Yun struct mtu3_ep *mep = NULL; 209df2069acSChunfeng Yun int handled = 1; 210df2069acSChunfeng Yun u8 result[2] = {0, 0}; 211df2069acSChunfeng Yun u8 epnum = 0; 212df2069acSChunfeng Yun int is_in; 213df2069acSChunfeng Yun 214df2069acSChunfeng Yun switch (setup->bRequestType & USB_RECIP_MASK) { 215df2069acSChunfeng Yun case USB_RECIP_DEVICE: 216df2069acSChunfeng Yun result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED; 217df2069acSChunfeng Yun result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; 2184d79e042SChunfeng Yun 2194d79e042SChunfeng Yun if (mtu->g.speed >= USB_SPEED_SUPER) { 220a29de31bSChunfeng Yun result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED; 221a29de31bSChunfeng Yun result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED; 222a29de31bSChunfeng Yun } 223a29de31bSChunfeng Yun 224a29de31bSChunfeng Yun dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__, 225a29de31bSChunfeng Yun result[0], mtu->u1_enable, mtu->u2_enable); 226a29de31bSChunfeng Yun 227df2069acSChunfeng Yun break; 228df2069acSChunfeng Yun case USB_RECIP_INTERFACE: 229df2069acSChunfeng Yun break; 230df2069acSChunfeng Yun case USB_RECIP_ENDPOINT: 231df2069acSChunfeng Yun epnum = (u8) le16_to_cpu(setup->wIndex); 232df2069acSChunfeng Yun is_in = epnum & USB_DIR_IN; 233df2069acSChunfeng Yun epnum &= USB_ENDPOINT_NUMBER_MASK; 234df2069acSChunfeng Yun 235df2069acSChunfeng Yun if (epnum >= mtu->num_eps) { 236df2069acSChunfeng Yun handled = -EINVAL; 237df2069acSChunfeng Yun break; 238df2069acSChunfeng Yun } 239df2069acSChunfeng Yun if (!epnum) 240df2069acSChunfeng Yun break; 241df2069acSChunfeng Yun 242df2069acSChunfeng Yun mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 243df2069acSChunfeng Yun if (!mep->desc) { 244df2069acSChunfeng Yun handled = -EINVAL; 245df2069acSChunfeng Yun break; 246df2069acSChunfeng Yun } 247df2069acSChunfeng Yun if (mep->flags & MTU3_EP_STALL) 248df2069acSChunfeng Yun result[0] |= 1 << USB_ENDPOINT_HALT; 249df2069acSChunfeng Yun 250df2069acSChunfeng Yun break; 251df2069acSChunfeng Yun default: 252df2069acSChunfeng Yun /* class, vendor, etc ... delegate */ 253df2069acSChunfeng Yun handled = 0; 254df2069acSChunfeng Yun break; 255df2069acSChunfeng Yun } 256df2069acSChunfeng Yun 257df2069acSChunfeng Yun if (handled > 0) { 258df2069acSChunfeng Yun int ret; 259df2069acSChunfeng Yun 260df2069acSChunfeng Yun /* prepare a data stage for GET_STATUS */ 261df2069acSChunfeng Yun dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result); 262df2069acSChunfeng Yun memcpy(mtu->setup_buf, result, sizeof(result)); 263df2069acSChunfeng Yun mtu->ep0_req.mep = mtu->ep0; 264df2069acSChunfeng Yun mtu->ep0_req.request.length = 2; 265df2069acSChunfeng Yun mtu->ep0_req.request.buf = &mtu->setup_buf; 266df2069acSChunfeng Yun mtu->ep0_req.request.complete = ep0_dummy_complete; 267df2069acSChunfeng Yun ret = ep0_queue(mtu->ep0, &mtu->ep0_req); 268df2069acSChunfeng Yun if (ret < 0) 269df2069acSChunfeng Yun handled = ret; 270df2069acSChunfeng Yun } 271df2069acSChunfeng Yun return handled; 272df2069acSChunfeng Yun } 273df2069acSChunfeng Yun 274df2069acSChunfeng Yun static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 275df2069acSChunfeng Yun { 276df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 277df2069acSChunfeng Yun int handled = 1; 278f3b28e5eSChunfeng Yun u32 value; 279df2069acSChunfeng Yun 280df2069acSChunfeng Yun switch (le16_to_cpu(setup->wIndex) >> 8) { 281df2069acSChunfeng Yun case TEST_J: 282df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_J\n"); 283df2069acSChunfeng Yun mtu->test_mode_nr = TEST_J_MODE; 284df2069acSChunfeng Yun break; 285df2069acSChunfeng Yun case TEST_K: 286df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_K\n"); 287df2069acSChunfeng Yun mtu->test_mode_nr = TEST_K_MODE; 288df2069acSChunfeng Yun break; 289df2069acSChunfeng Yun case TEST_SE0_NAK: 290df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_SE0_NAK\n"); 291df2069acSChunfeng Yun mtu->test_mode_nr = TEST_SE0_NAK_MODE; 292df2069acSChunfeng Yun break; 293df2069acSChunfeng Yun case TEST_PACKET: 294df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_PACKET\n"); 295df2069acSChunfeng Yun mtu->test_mode_nr = TEST_PACKET_MODE; 296df2069acSChunfeng Yun break; 297df2069acSChunfeng Yun default: 298df2069acSChunfeng Yun handled = -EINVAL; 299df2069acSChunfeng Yun goto out; 300df2069acSChunfeng Yun } 301df2069acSChunfeng Yun 302df2069acSChunfeng Yun mtu->test_mode = true; 303df2069acSChunfeng Yun 304df2069acSChunfeng Yun /* no TX completion interrupt, and need restart platform after test */ 305df2069acSChunfeng Yun if (mtu->test_mode_nr == TEST_PACKET_MODE) 306df2069acSChunfeng Yun ep0_load_test_packet(mtu); 307df2069acSChunfeng Yun 308f3b28e5eSChunfeng Yun /* send status before entering test mode. */ 30971460342SChunfeng Yun ep0_do_status_stage(mtu); 310f3b28e5eSChunfeng Yun 311f3b28e5eSChunfeng Yun /* wait for ACK status sent by host */ 3123d7678e2SChunfeng Yun readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value, 313f3b28e5eSChunfeng Yun !(value & EP0_DATAEND), 100, 5000); 314f3b28e5eSChunfeng Yun 315df2069acSChunfeng Yun mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr); 316df2069acSChunfeng Yun 317df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 318df2069acSChunfeng Yun 319df2069acSChunfeng Yun out: 320df2069acSChunfeng Yun return handled; 321df2069acSChunfeng Yun } 322df2069acSChunfeng Yun 323df2069acSChunfeng Yun static int ep0_handle_feature_dev(struct mtu3 *mtu, 324df2069acSChunfeng Yun struct usb_ctrlrequest *setup, bool set) 325df2069acSChunfeng Yun { 326a29de31bSChunfeng Yun void __iomem *mbase = mtu->mac_base; 327df2069acSChunfeng Yun int handled = -EINVAL; 328a29de31bSChunfeng Yun u32 lpc; 329df2069acSChunfeng Yun 330df2069acSChunfeng Yun switch (le16_to_cpu(setup->wValue)) { 331df2069acSChunfeng Yun case USB_DEVICE_REMOTE_WAKEUP: 332df2069acSChunfeng Yun mtu->may_wakeup = !!set; 333df2069acSChunfeng Yun handled = 1; 334df2069acSChunfeng Yun break; 335df2069acSChunfeng Yun case USB_DEVICE_TEST_MODE: 336df2069acSChunfeng Yun if (!set || (mtu->g.speed != USB_SPEED_HIGH) || 337df2069acSChunfeng Yun (le16_to_cpu(setup->wIndex) & 0xff)) 338df2069acSChunfeng Yun break; 339df2069acSChunfeng Yun 340df2069acSChunfeng Yun handled = handle_test_mode(mtu, setup); 341df2069acSChunfeng Yun break; 342a29de31bSChunfeng Yun case USB_DEVICE_U1_ENABLE: 3434d79e042SChunfeng Yun if (mtu->g.speed < USB_SPEED_SUPER || 344a29de31bSChunfeng Yun mtu->g.state != USB_STATE_CONFIGURED) 345a29de31bSChunfeng Yun break; 346a29de31bSChunfeng Yun 347a29de31bSChunfeng Yun lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); 348a29de31bSChunfeng Yun if (set) 349e8029724SChunfeng Yun lpc |= SW_U1_REQUEST_ENABLE; 350a29de31bSChunfeng Yun else 351e8029724SChunfeng Yun lpc &= ~SW_U1_REQUEST_ENABLE; 352a29de31bSChunfeng Yun mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); 353a29de31bSChunfeng Yun 354a29de31bSChunfeng Yun mtu->u1_enable = !!set; 355a29de31bSChunfeng Yun handled = 1; 356a29de31bSChunfeng Yun break; 357a29de31bSChunfeng Yun case USB_DEVICE_U2_ENABLE: 3584d79e042SChunfeng Yun if (mtu->g.speed < USB_SPEED_SUPER || 359a29de31bSChunfeng Yun mtu->g.state != USB_STATE_CONFIGURED) 360a29de31bSChunfeng Yun break; 361a29de31bSChunfeng Yun 362a29de31bSChunfeng Yun lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); 363a29de31bSChunfeng Yun if (set) 364e8029724SChunfeng Yun lpc |= SW_U2_REQUEST_ENABLE; 365a29de31bSChunfeng Yun else 366e8029724SChunfeng Yun lpc &= ~SW_U2_REQUEST_ENABLE; 367a29de31bSChunfeng Yun mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); 368a29de31bSChunfeng Yun 369a29de31bSChunfeng Yun mtu->u2_enable = !!set; 370a29de31bSChunfeng Yun handled = 1; 371a29de31bSChunfeng Yun break; 372df2069acSChunfeng Yun default: 373df2069acSChunfeng Yun handled = -EINVAL; 374df2069acSChunfeng Yun break; 375df2069acSChunfeng Yun } 376df2069acSChunfeng Yun return handled; 377df2069acSChunfeng Yun } 378df2069acSChunfeng Yun 379df2069acSChunfeng Yun static int ep0_handle_feature(struct mtu3 *mtu, 380df2069acSChunfeng Yun struct usb_ctrlrequest *setup, bool set) 381df2069acSChunfeng Yun { 382df2069acSChunfeng Yun struct mtu3_ep *mep; 383df2069acSChunfeng Yun int handled = -EINVAL; 384df2069acSChunfeng Yun int is_in; 385df2069acSChunfeng Yun u16 value; 386df2069acSChunfeng Yun u16 index; 387df2069acSChunfeng Yun u8 epnum; 388df2069acSChunfeng Yun 389df2069acSChunfeng Yun value = le16_to_cpu(setup->wValue); 390df2069acSChunfeng Yun index = le16_to_cpu(setup->wIndex); 391df2069acSChunfeng Yun 392df2069acSChunfeng Yun switch (setup->bRequestType & USB_RECIP_MASK) { 393df2069acSChunfeng Yun case USB_RECIP_DEVICE: 394df2069acSChunfeng Yun handled = ep0_handle_feature_dev(mtu, setup, set); 395df2069acSChunfeng Yun break; 396a29de31bSChunfeng Yun case USB_RECIP_INTERFACE: 397a29de31bSChunfeng Yun /* superspeed only */ 3984d79e042SChunfeng Yun if (value == USB_INTRF_FUNC_SUSPEND && 3994d79e042SChunfeng Yun mtu->g.speed >= USB_SPEED_SUPER) { 400a29de31bSChunfeng Yun /* 401a29de31bSChunfeng Yun * forward the request because function drivers 402a29de31bSChunfeng Yun * should handle it 403a29de31bSChunfeng Yun */ 404a29de31bSChunfeng Yun handled = 0; 405a29de31bSChunfeng Yun } 406a29de31bSChunfeng Yun break; 407df2069acSChunfeng Yun case USB_RECIP_ENDPOINT: 408df2069acSChunfeng Yun epnum = index & USB_ENDPOINT_NUMBER_MASK; 409df2069acSChunfeng Yun if (epnum == 0 || epnum >= mtu->num_eps || 410df2069acSChunfeng Yun value != USB_ENDPOINT_HALT) 411df2069acSChunfeng Yun break; 412df2069acSChunfeng Yun 413df2069acSChunfeng Yun is_in = index & USB_DIR_IN; 414df2069acSChunfeng Yun mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 415df2069acSChunfeng Yun if (!mep->desc) 416df2069acSChunfeng Yun break; 417df2069acSChunfeng Yun 418df2069acSChunfeng Yun handled = 1; 419df2069acSChunfeng Yun /* ignore request if endpoint is wedged */ 420df2069acSChunfeng Yun if (mep->wedged) 421df2069acSChunfeng Yun break; 422df2069acSChunfeng Yun 423df2069acSChunfeng Yun mtu3_ep_stall_set(mep, set); 424df2069acSChunfeng Yun break; 425df2069acSChunfeng Yun default: 426df2069acSChunfeng Yun /* class, vendor, etc ... delegate */ 427df2069acSChunfeng Yun handled = 0; 428df2069acSChunfeng Yun break; 429df2069acSChunfeng Yun } 430df2069acSChunfeng Yun return handled; 431df2069acSChunfeng Yun } 432df2069acSChunfeng Yun 433df2069acSChunfeng Yun /* 434df2069acSChunfeng Yun * handle all control requests can be handled 435df2069acSChunfeng Yun * returns: 436df2069acSChunfeng Yun * negative errno - error happened 437df2069acSChunfeng Yun * zero - need delegate SETUP to gadget driver 438df2069acSChunfeng Yun * positive - already handled 439df2069acSChunfeng Yun */ 440df2069acSChunfeng Yun static int handle_standard_request(struct mtu3 *mtu, 441df2069acSChunfeng Yun struct usb_ctrlrequest *setup) 442df2069acSChunfeng Yun { 443df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 444df2069acSChunfeng Yun enum usb_device_state state = mtu->g.state; 445df2069acSChunfeng Yun int handled = -EINVAL; 446df2069acSChunfeng Yun u32 dev_conf; 447df2069acSChunfeng Yun u16 value; 448df2069acSChunfeng Yun 449df2069acSChunfeng Yun value = le16_to_cpu(setup->wValue); 450df2069acSChunfeng Yun 451df2069acSChunfeng Yun /* the gadget driver handles everything except what we must handle */ 452df2069acSChunfeng Yun switch (setup->bRequest) { 453df2069acSChunfeng Yun case USB_REQ_SET_ADDRESS: 454df2069acSChunfeng Yun /* change it after the status stage */ 455df2069acSChunfeng Yun mtu->address = (u8) (value & 0x7f); 456df2069acSChunfeng Yun dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address); 457df2069acSChunfeng Yun 458df2069acSChunfeng Yun dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF); 459df2069acSChunfeng Yun dev_conf &= ~DEV_ADDR_MSK; 460df2069acSChunfeng Yun dev_conf |= DEV_ADDR(mtu->address); 461df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf); 462df2069acSChunfeng Yun 463df2069acSChunfeng Yun if (mtu->address) 464df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS); 465df2069acSChunfeng Yun else 466df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT); 467df2069acSChunfeng Yun 468df2069acSChunfeng Yun handled = 1; 469df2069acSChunfeng Yun break; 470df2069acSChunfeng Yun case USB_REQ_SET_CONFIGURATION: 471df2069acSChunfeng Yun if (state == USB_STATE_ADDRESS) { 472df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, 473df2069acSChunfeng Yun USB_STATE_CONFIGURED); 474df2069acSChunfeng Yun } else if (state == USB_STATE_CONFIGURED) { 475df2069acSChunfeng Yun /* 476df2069acSChunfeng Yun * USB2 spec sec 9.4.7, if wValue is 0 then dev 477df2069acSChunfeng Yun * is moved to addressed state 478df2069acSChunfeng Yun */ 479df2069acSChunfeng Yun if (!value) 480df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, 481df2069acSChunfeng Yun USB_STATE_ADDRESS); 482df2069acSChunfeng Yun } 483df2069acSChunfeng Yun handled = 0; 484df2069acSChunfeng Yun break; 485df2069acSChunfeng Yun case USB_REQ_CLEAR_FEATURE: 486df2069acSChunfeng Yun handled = ep0_handle_feature(mtu, setup, 0); 487df2069acSChunfeng Yun break; 488df2069acSChunfeng Yun case USB_REQ_SET_FEATURE: 489df2069acSChunfeng Yun handled = ep0_handle_feature(mtu, setup, 1); 490df2069acSChunfeng Yun break; 491df2069acSChunfeng Yun case USB_REQ_GET_STATUS: 492df2069acSChunfeng Yun handled = ep0_get_status(mtu, setup); 493df2069acSChunfeng Yun break; 494a29de31bSChunfeng Yun case USB_REQ_SET_SEL: 495a29de31bSChunfeng Yun handled = ep0_set_sel(mtu, setup); 496a29de31bSChunfeng Yun break; 497df2069acSChunfeng Yun case USB_REQ_SET_ISOCH_DELAY: 498df2069acSChunfeng Yun handled = 1; 499df2069acSChunfeng Yun break; 500df2069acSChunfeng Yun default: 501df2069acSChunfeng Yun /* delegate SET_CONFIGURATION, etc */ 502df2069acSChunfeng Yun handled = 0; 503df2069acSChunfeng Yun } 504df2069acSChunfeng Yun 505df2069acSChunfeng Yun return handled; 506df2069acSChunfeng Yun } 507df2069acSChunfeng Yun 508df2069acSChunfeng Yun /* receive an data packet (OUT) */ 509df2069acSChunfeng Yun static void ep0_rx_state(struct mtu3 *mtu) 510df2069acSChunfeng Yun { 511df2069acSChunfeng Yun struct mtu3_request *mreq; 512df2069acSChunfeng Yun struct usb_request *req; 513df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 514df2069acSChunfeng Yun u32 maxp; 515df2069acSChunfeng Yun u32 csr; 516df2069acSChunfeng Yun u16 count = 0; 517df2069acSChunfeng Yun 518df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 519df2069acSChunfeng Yun 520df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 521df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 522df2069acSChunfeng Yun req = &mreq->request; 523df2069acSChunfeng Yun 524df2069acSChunfeng Yun /* read packet and ack; or stall because of gadget driver bug */ 525df2069acSChunfeng Yun if (req) { 526df2069acSChunfeng Yun void *buf = req->buf + req->actual; 527df2069acSChunfeng Yun unsigned int len = req->length - req->actual; 528df2069acSChunfeng Yun 529df2069acSChunfeng Yun /* read the buffer */ 530df2069acSChunfeng Yun count = mtu3_readl(mbase, U3D_RXCOUNT0); 531df2069acSChunfeng Yun if (count > len) { 532df2069acSChunfeng Yun req->status = -EOVERFLOW; 533df2069acSChunfeng Yun count = len; 534df2069acSChunfeng Yun } 535df2069acSChunfeng Yun ep0_read_fifo(mtu->ep0, buf, count); 536df2069acSChunfeng Yun req->actual += count; 537df2069acSChunfeng Yun csr |= EP0_RXPKTRDY; 538df2069acSChunfeng Yun 539df2069acSChunfeng Yun maxp = mtu->g.ep0->maxpacket; 540df2069acSChunfeng Yun if (count < maxp || req->actual == req->length) { 541df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 542df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0 state: %s\n", 543df2069acSChunfeng Yun decode_ep0_state(mtu)); 544df2069acSChunfeng Yun 545df2069acSChunfeng Yun csr |= EP0_DATAEND; 546df2069acSChunfeng Yun } else { 547df2069acSChunfeng Yun req = NULL; 548df2069acSChunfeng Yun } 549df2069acSChunfeng Yun } else { 550df2069acSChunfeng Yun csr |= EP0_RXPKTRDY | EP0_SENDSTALL; 551df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__); 552df2069acSChunfeng Yun } 553df2069acSChunfeng Yun 554df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, csr); 555df2069acSChunfeng Yun 556df2069acSChunfeng Yun /* give back the request if have received all data */ 557df2069acSChunfeng Yun if (req) 558df2069acSChunfeng Yun ep0_req_giveback(mtu, req); 559df2069acSChunfeng Yun 560df2069acSChunfeng Yun } 561df2069acSChunfeng Yun 562df2069acSChunfeng Yun /* transmitting to the host (IN) */ 563df2069acSChunfeng Yun static void ep0_tx_state(struct mtu3 *mtu) 564df2069acSChunfeng Yun { 565df2069acSChunfeng Yun struct mtu3_request *mreq = next_ep0_request(mtu); 566df2069acSChunfeng Yun struct usb_request *req; 567df2069acSChunfeng Yun u32 csr; 568df2069acSChunfeng Yun u8 *src; 569288ee3c3SChunfeng Yun u32 count; 570df2069acSChunfeng Yun u32 maxp; 571df2069acSChunfeng Yun 572df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 573df2069acSChunfeng Yun 574df2069acSChunfeng Yun if (!mreq) 575df2069acSChunfeng Yun return; 576df2069acSChunfeng Yun 577df2069acSChunfeng Yun maxp = mtu->g.ep0->maxpacket; 578df2069acSChunfeng Yun req = &mreq->request; 579df2069acSChunfeng Yun 580df2069acSChunfeng Yun /* load the data */ 581df2069acSChunfeng Yun src = (u8 *)req->buf + req->actual; 582df2069acSChunfeng Yun count = min(maxp, req->length - req->actual); 583df2069acSChunfeng Yun if (count) 584df2069acSChunfeng Yun ep0_write_fifo(mtu->ep0, src, count); 585df2069acSChunfeng Yun 586df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n", 587df2069acSChunfeng Yun __func__, req->actual, req->length, count, maxp, req->zero); 588df2069acSChunfeng Yun 589df2069acSChunfeng Yun req->actual += count; 590df2069acSChunfeng Yun 591df2069acSChunfeng Yun if ((count < maxp) 592df2069acSChunfeng Yun || ((req->actual == req->length) && !req->zero)) 593df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_TX_END; 594df2069acSChunfeng Yun 595df2069acSChunfeng Yun /* send it out, triggering a "txpktrdy cleared" irq */ 596df2069acSChunfeng Yun csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 597df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY); 598df2069acSChunfeng Yun 599df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__, 600df2069acSChunfeng Yun mtu3_readl(mtu->mac_base, U3D_EP0CSR)); 601df2069acSChunfeng Yun } 602df2069acSChunfeng Yun 603df2069acSChunfeng Yun static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 604df2069acSChunfeng Yun { 605df2069acSChunfeng Yun struct mtu3_request *mreq; 606df2069acSChunfeng Yun u32 count; 607df2069acSChunfeng Yun u32 csr; 608df2069acSChunfeng Yun 609df2069acSChunfeng Yun csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 610df2069acSChunfeng Yun count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0); 611df2069acSChunfeng Yun 612df2069acSChunfeng Yun ep0_read_fifo(mtu->ep0, (u8 *)setup, count); 613df2069acSChunfeng Yun 614df2069acSChunfeng Yun dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n", 615df2069acSChunfeng Yun setup->bRequestType, setup->bRequest, 616df2069acSChunfeng Yun le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), 617df2069acSChunfeng Yun le16_to_cpu(setup->wLength)); 618df2069acSChunfeng Yun 619df2069acSChunfeng Yun /* clean up any leftover transfers */ 620df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 621df2069acSChunfeng Yun if (mreq) 622df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 623df2069acSChunfeng Yun 624df2069acSChunfeng Yun if (le16_to_cpu(setup->wLength) == 0) { 625df2069acSChunfeng Yun ; /* no data stage, nothing to do */ 626df2069acSChunfeng Yun } else if (setup->bRequestType & USB_DIR_IN) { 627df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, 628df2069acSChunfeng Yun csr | EP0_SETUPPKTRDY | EP0_DPHTX); 629df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_TX; 630df2069acSChunfeng Yun } else { 631df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, 632df2069acSChunfeng Yun (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX)); 633df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_RX; 634df2069acSChunfeng Yun } 635df2069acSChunfeng Yun } 636df2069acSChunfeng Yun 637df2069acSChunfeng Yun static int ep0_handle_setup(struct mtu3 *mtu) 638df2069acSChunfeng Yun __releases(mtu->lock) 639df2069acSChunfeng Yun __acquires(mtu->lock) 640df2069acSChunfeng Yun { 641df2069acSChunfeng Yun struct usb_ctrlrequest setup; 642df2069acSChunfeng Yun struct mtu3_request *mreq; 643df2069acSChunfeng Yun int handled = 0; 644df2069acSChunfeng Yun 645df2069acSChunfeng Yun ep0_read_setup(mtu, &setup); 64683374e03SChunfeng Yun trace_mtu3_handle_setup(&setup); 647df2069acSChunfeng Yun 648df2069acSChunfeng Yun if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 649df2069acSChunfeng Yun handled = handle_standard_request(mtu, &setup); 650df2069acSChunfeng Yun 651df2069acSChunfeng Yun dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n", 652df2069acSChunfeng Yun handled, decode_ep0_state(mtu)); 653df2069acSChunfeng Yun 654df2069acSChunfeng Yun if (handled < 0) 655df2069acSChunfeng Yun goto stall; 656df2069acSChunfeng Yun else if (handled > 0) 657df2069acSChunfeng Yun goto finish; 658df2069acSChunfeng Yun 659df2069acSChunfeng Yun handled = forward_to_driver(mtu, &setup); 660df2069acSChunfeng Yun if (handled < 0) { 661df2069acSChunfeng Yun stall: 662df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled); 663df2069acSChunfeng Yun 664df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 665df2069acSChunfeng Yun le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY); 666df2069acSChunfeng Yun 667df2069acSChunfeng Yun return 0; 668df2069acSChunfeng Yun } 669df2069acSChunfeng Yun 670df2069acSChunfeng Yun finish: 671df2069acSChunfeng Yun if (mtu->test_mode) { 672df2069acSChunfeng Yun ; /* nothing to do */ 673fe7c994aSChunfeng Yun } else if (handled == USB_GADGET_DELAYED_STATUS) { 674*b1a71c90SChunfeng Yun 675*b1a71c90SChunfeng Yun mreq = next_ep0_request(mtu); 676*b1a71c90SChunfeng Yun if (mreq) { 677*b1a71c90SChunfeng Yun /* already asked us to continue delayed status */ 678*b1a71c90SChunfeng Yun ep0_do_status_stage(mtu); 679*b1a71c90SChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 680*b1a71c90SChunfeng Yun } else { 681*b1a71c90SChunfeng Yun /* do delayed STATUS stage till receive ep0_queue */ 682fe7c994aSChunfeng Yun mtu->delayed_status = true; 683*b1a71c90SChunfeng Yun } 684df2069acSChunfeng Yun } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ 685df2069acSChunfeng Yun 68671460342SChunfeng Yun ep0_do_status_stage(mtu); 687df2069acSChunfeng Yun /* complete zlp request directly */ 688df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 689df2069acSChunfeng Yun if (mreq && !mreq->request.length) 690df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 691df2069acSChunfeng Yun } 692df2069acSChunfeng Yun 693df2069acSChunfeng Yun return 0; 694df2069acSChunfeng Yun } 695df2069acSChunfeng Yun 696df2069acSChunfeng Yun irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) 697df2069acSChunfeng Yun { 698df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 699df2069acSChunfeng Yun struct mtu3_request *mreq; 700df2069acSChunfeng Yun u32 int_status; 701df2069acSChunfeng Yun irqreturn_t ret = IRQ_NONE; 702df2069acSChunfeng Yun u32 csr; 703df2069acSChunfeng Yun u32 len; 704df2069acSChunfeng Yun 705df2069acSChunfeng Yun int_status = mtu3_readl(mbase, U3D_EPISR); 706df2069acSChunfeng Yun int_status &= mtu3_readl(mbase, U3D_EPIER); 707df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */ 708df2069acSChunfeng Yun 709df2069acSChunfeng Yun /* only handle ep0's */ 71094552090SChunfeng Yun if (!(int_status & (EP0ISR | SETUPENDISR))) 711df2069acSChunfeng Yun return IRQ_NONE; 712df2069acSChunfeng Yun 71394552090SChunfeng Yun /* abort current SETUP, and process new one */ 71494552090SChunfeng Yun if (int_status & SETUPENDISR) 71594552090SChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 71694552090SChunfeng Yun 717df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR); 718df2069acSChunfeng Yun 719df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr); 720df2069acSChunfeng Yun 721df2069acSChunfeng Yun /* we sent a stall.. need to clear it now.. */ 722df2069acSChunfeng Yun if (csr & EP0_SENTSTALL) { 723df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, false, 0); 724df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR); 725df2069acSChunfeng Yun ret = IRQ_HANDLED; 726df2069acSChunfeng Yun } 727df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 72883374e03SChunfeng Yun mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu)); 729df2069acSChunfeng Yun 730df2069acSChunfeng Yun switch (mtu->ep0_state) { 731df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 732df2069acSChunfeng Yun /* irq on clearing txpktrdy */ 733df2069acSChunfeng Yun if ((csr & EP0_FIFOFULL) == 0) { 734df2069acSChunfeng Yun ep0_tx_state(mtu); 735df2069acSChunfeng Yun ret = IRQ_HANDLED; 736df2069acSChunfeng Yun } 737df2069acSChunfeng Yun break; 738df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 739df2069acSChunfeng Yun /* irq on set rxpktrdy */ 740df2069acSChunfeng Yun if (csr & EP0_RXPKTRDY) { 741df2069acSChunfeng Yun ep0_rx_state(mtu); 742df2069acSChunfeng Yun ret = IRQ_HANDLED; 743df2069acSChunfeng Yun } 744df2069acSChunfeng Yun break; 745df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 746df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, 747df2069acSChunfeng Yun (csr & EP0_W1C_BITS) | EP0_DATAEND); 748df2069acSChunfeng Yun 749df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 750df2069acSChunfeng Yun if (mreq) 751df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 752df2069acSChunfeng Yun 753df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 754df2069acSChunfeng Yun ret = IRQ_HANDLED; 755df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 756df2069acSChunfeng Yun break; 757df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 758df2069acSChunfeng Yun if (!(csr & EP0_SETUPPKTRDY)) 759df2069acSChunfeng Yun break; 760df2069acSChunfeng Yun 761df2069acSChunfeng Yun len = mtu3_readl(mbase, U3D_RXCOUNT0); 762df2069acSChunfeng Yun if (len != 8) { 763df2069acSChunfeng Yun dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len); 764df2069acSChunfeng Yun break; 765df2069acSChunfeng Yun } 766df2069acSChunfeng Yun 767df2069acSChunfeng Yun ep0_handle_setup(mtu); 768df2069acSChunfeng Yun ret = IRQ_HANDLED; 769df2069acSChunfeng Yun break; 770df2069acSChunfeng Yun default: 771df2069acSChunfeng Yun /* can't happen */ 772df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 0); 773df2069acSChunfeng Yun WARN_ON(1); 774df2069acSChunfeng Yun break; 775df2069acSChunfeng Yun } 776df2069acSChunfeng Yun 777df2069acSChunfeng Yun return ret; 778df2069acSChunfeng Yun } 779df2069acSChunfeng Yun 780df2069acSChunfeng Yun 781df2069acSChunfeng Yun static int mtu3_ep0_enable(struct usb_ep *ep, 782df2069acSChunfeng Yun const struct usb_endpoint_descriptor *desc) 783df2069acSChunfeng Yun { 784df2069acSChunfeng Yun /* always enabled */ 785df2069acSChunfeng Yun return -EINVAL; 786df2069acSChunfeng Yun } 787df2069acSChunfeng Yun 788df2069acSChunfeng Yun static int mtu3_ep0_disable(struct usb_ep *ep) 789df2069acSChunfeng Yun { 790df2069acSChunfeng Yun /* always enabled */ 791df2069acSChunfeng Yun return -EINVAL; 792df2069acSChunfeng Yun } 793df2069acSChunfeng Yun 794df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) 795df2069acSChunfeng Yun { 796df2069acSChunfeng Yun struct mtu3 *mtu = mep->mtu; 797df2069acSChunfeng Yun 798df2069acSChunfeng Yun mreq->mtu = mtu; 799df2069acSChunfeng Yun mreq->request.actual = 0; 800df2069acSChunfeng Yun mreq->request.status = -EINPROGRESS; 801df2069acSChunfeng Yun 802df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, 803df2069acSChunfeng Yun mep->name, decode_ep0_state(mtu), mreq->request.length); 804df2069acSChunfeng Yun 805df2069acSChunfeng Yun switch (mtu->ep0_state) { 806df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 807df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: /* control-OUT data */ 808df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: /* control-IN data */ 809df2069acSChunfeng Yun break; 810df2069acSChunfeng Yun default: 811df2069acSChunfeng Yun dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__, 812df2069acSChunfeng Yun decode_ep0_state(mtu)); 813df2069acSChunfeng Yun return -EINVAL; 814df2069acSChunfeng Yun } 815df2069acSChunfeng Yun 816fe7c994aSChunfeng Yun if (mtu->delayed_status) { 817fe7c994aSChunfeng Yun 818fe7c994aSChunfeng Yun mtu->delayed_status = false; 81971460342SChunfeng Yun ep0_do_status_stage(mtu); 820fe7c994aSChunfeng Yun /* needn't giveback the request for handling delay STATUS */ 821fe7c994aSChunfeng Yun return 0; 822fe7c994aSChunfeng Yun } 823fe7c994aSChunfeng Yun 824fe7c994aSChunfeng Yun if (!list_empty(&mep->req_list)) 825fe7c994aSChunfeng Yun return -EBUSY; 826fe7c994aSChunfeng Yun 827df2069acSChunfeng Yun list_add_tail(&mreq->list, &mep->req_list); 828df2069acSChunfeng Yun 829df2069acSChunfeng Yun /* sequence #1, IN ... start writing the data */ 830df2069acSChunfeng Yun if (mtu->ep0_state == MU3D_EP0_STATE_TX) 831df2069acSChunfeng Yun ep0_tx_state(mtu); 832df2069acSChunfeng Yun 833df2069acSChunfeng Yun return 0; 834df2069acSChunfeng Yun } 835df2069acSChunfeng Yun 836df2069acSChunfeng Yun static int mtu3_ep0_queue(struct usb_ep *ep, 837df2069acSChunfeng Yun struct usb_request *req, gfp_t gfp) 838df2069acSChunfeng Yun { 839df2069acSChunfeng Yun struct mtu3_ep *mep; 840df2069acSChunfeng Yun struct mtu3_request *mreq; 841df2069acSChunfeng Yun struct mtu3 *mtu; 842df2069acSChunfeng Yun unsigned long flags; 843df2069acSChunfeng Yun int ret = 0; 844df2069acSChunfeng Yun 845df2069acSChunfeng Yun if (!ep || !req) 846df2069acSChunfeng Yun return -EINVAL; 847df2069acSChunfeng Yun 848df2069acSChunfeng Yun mep = to_mtu3_ep(ep); 849df2069acSChunfeng Yun mtu = mep->mtu; 850df2069acSChunfeng Yun mreq = to_mtu3_request(req); 851df2069acSChunfeng Yun 852df2069acSChunfeng Yun spin_lock_irqsave(&mtu->lock, flags); 853df2069acSChunfeng Yun ret = ep0_queue(mep, mreq); 854df2069acSChunfeng Yun spin_unlock_irqrestore(&mtu->lock, flags); 855df2069acSChunfeng Yun return ret; 856df2069acSChunfeng Yun } 857df2069acSChunfeng Yun 858df2069acSChunfeng Yun static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) 859df2069acSChunfeng Yun { 860df2069acSChunfeng Yun /* we just won't support this */ 861df2069acSChunfeng Yun return -EINVAL; 862df2069acSChunfeng Yun } 863df2069acSChunfeng Yun 864df2069acSChunfeng Yun static int mtu3_ep0_halt(struct usb_ep *ep, int value) 865df2069acSChunfeng Yun { 866df2069acSChunfeng Yun struct mtu3_ep *mep; 867df2069acSChunfeng Yun struct mtu3 *mtu; 868df2069acSChunfeng Yun unsigned long flags; 869df2069acSChunfeng Yun int ret = 0; 870df2069acSChunfeng Yun 871df2069acSChunfeng Yun if (!ep || !value) 872df2069acSChunfeng Yun return -EINVAL; 873df2069acSChunfeng Yun 874df2069acSChunfeng Yun mep = to_mtu3_ep(ep); 875df2069acSChunfeng Yun mtu = mep->mtu; 876df2069acSChunfeng Yun 877df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 878df2069acSChunfeng Yun 879df2069acSChunfeng Yun spin_lock_irqsave(&mtu->lock, flags); 880df2069acSChunfeng Yun 881df2069acSChunfeng Yun if (!list_empty(&mep->req_list)) { 882df2069acSChunfeng Yun ret = -EBUSY; 883df2069acSChunfeng Yun goto cleanup; 884df2069acSChunfeng Yun } 885df2069acSChunfeng Yun 886df2069acSChunfeng Yun switch (mtu->ep0_state) { 887df2069acSChunfeng Yun /* 888df2069acSChunfeng Yun * stalls are usually issued after parsing SETUP packet, either 889df2069acSChunfeng Yun * directly in irq context from setup() or else later. 890df2069acSChunfeng Yun */ 891df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 892df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 893df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 894df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 895df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 0); 896df2069acSChunfeng Yun break; 897df2069acSChunfeng Yun default: 898df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0 can't halt in state %s\n", 899df2069acSChunfeng Yun decode_ep0_state(mtu)); 900df2069acSChunfeng Yun ret = -EINVAL; 901df2069acSChunfeng Yun } 902df2069acSChunfeng Yun 903df2069acSChunfeng Yun cleanup: 904df2069acSChunfeng Yun spin_unlock_irqrestore(&mtu->lock, flags); 905df2069acSChunfeng Yun return ret; 906df2069acSChunfeng Yun } 907df2069acSChunfeng Yun 908df2069acSChunfeng Yun const struct usb_ep_ops mtu3_ep0_ops = { 909df2069acSChunfeng Yun .enable = mtu3_ep0_enable, 910df2069acSChunfeng Yun .disable = mtu3_ep0_disable, 911df2069acSChunfeng Yun .alloc_request = mtu3_alloc_request, 912df2069acSChunfeng Yun .free_request = mtu3_free_request, 913df2069acSChunfeng Yun .queue = mtu3_ep0_queue, 914df2069acSChunfeng Yun .dequeue = mtu3_ep0_dequeue, 915df2069acSChunfeng Yun .set_halt = mtu3_ep0_halt, 916df2069acSChunfeng Yun }; 917