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