18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Chunfeng.Yun <chunfeng.yun@mediatek.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 118c2ecf20Sopenharmony_ci#include <linux/usb/composite.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "mtu3.h" 148c2ecf20Sopenharmony_ci#include "mtu3_debug.h" 158c2ecf20Sopenharmony_ci#include "mtu3_trace.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* ep0 is always mtu3->in_eps[0] */ 188c2ecf20Sopenharmony_ci#define next_ep0_request(mtu) next_request((mtu)->ep0) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* for high speed test mode; see USB 2.0 spec 7.1.20 */ 218c2ecf20Sopenharmony_cistatic const u8 mtu3_test_packet[53] = { 228c2ecf20Sopenharmony_ci /* implicit SYNC then DATA0 to start */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* JKJKJKJK x9 */ 258c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 268c2ecf20Sopenharmony_ci /* JJKKJJKK x8 */ 278c2ecf20Sopenharmony_ci 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 288c2ecf20Sopenharmony_ci /* JJJJKKKK x8 */ 298c2ecf20Sopenharmony_ci 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 308c2ecf20Sopenharmony_ci /* JJJJJJJKKKKKKK x8 */ 318c2ecf20Sopenharmony_ci 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 328c2ecf20Sopenharmony_ci /* JJJJJJJK x8 */ 338c2ecf20Sopenharmony_ci 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 348c2ecf20Sopenharmony_ci /* JKKKKKKK x10, JK */ 358c2ecf20Sopenharmony_ci 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e, 368c2ecf20Sopenharmony_ci /* implicit CRC16 then EOP to end */ 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic char *decode_ep0_state(struct mtu3 *mtu) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci switch (mtu->ep0_state) { 428c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_SETUP: 438c2ecf20Sopenharmony_ci return "SETUP"; 448c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX: 458c2ecf20Sopenharmony_ci return "IN"; 468c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_RX: 478c2ecf20Sopenharmony_ci return "OUT"; 488c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX_END: 498c2ecf20Sopenharmony_ci return "TX-END"; 508c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_STALL: 518c2ecf20Sopenharmony_ci return "STALL"; 528c2ecf20Sopenharmony_ci default: 538c2ecf20Sopenharmony_ci return "??"; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci mtu3_req_complete(mtu->ep0, req, 0); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int 638c2ecf20Sopenharmony_ciforward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 648c2ecf20Sopenharmony_ci__releases(mtu->lock) 658c2ecf20Sopenharmony_ci__acquires(mtu->lock) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!mtu->gadget_driver) 708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci spin_unlock(&mtu->lock); 738c2ecf20Sopenharmony_ci ret = mtu->gadget_driver->setup(&mtu->g, setup); 748c2ecf20Sopenharmony_ci spin_lock(&mtu->lock); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret); 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 838c2ecf20Sopenharmony_ci u16 index = 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n", 868c2ecf20Sopenharmony_ci __func__, mep->epnum, len, src); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (len >= 4) { 898c2ecf20Sopenharmony_ci iowrite32_rep(fifo, src, len >> 2); 908c2ecf20Sopenharmony_ci index = len & ~0x03; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci if (len & 0x02) { 938c2ecf20Sopenharmony_ci writew(*(u16 *)&src[index], fifo); 948c2ecf20Sopenharmony_ci index += 2; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci if (len & 0x01) 978c2ecf20Sopenharmony_ci writeb(src[index], fifo); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 1038c2ecf20Sopenharmony_ci u32 value; 1048c2ecf20Sopenharmony_ci u16 index = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n", 1078c2ecf20Sopenharmony_ci __func__, mep->epnum, len, dst); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (len >= 4) { 1108c2ecf20Sopenharmony_ci ioread32_rep(fifo, dst, len >> 2); 1118c2ecf20Sopenharmony_ci index = len & ~0x03; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci if (len & 0x3) { 1148c2ecf20Sopenharmony_ci value = readl(fifo); 1158c2ecf20Sopenharmony_ci memcpy(&dst[index], &value, len & 0x3); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void ep0_load_test_packet(struct mtu3 *mtu) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * because the length of test packet is less than max packet of HS ep0, 1248c2ecf20Sopenharmony_ci * write it into fifo directly. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet)); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * A. send STALL for setup transfer without data stage: 1318c2ecf20Sopenharmony_ci * set SENDSTALL and SETUPPKTRDY at the same time; 1328c2ecf20Sopenharmony_ci * B. send STALL for other cases: 1338c2ecf20Sopenharmony_ci * set SENDSTALL only. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct mtu3 *mtu = mep0->mtu; 1388c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 1398c2ecf20Sopenharmony_ci u32 csr; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* EP0_SENTSTALL is W1C */ 1428c2ecf20Sopenharmony_ci csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 1438c2ecf20Sopenharmony_ci if (set) 1448c2ecf20Sopenharmony_ci csr |= EP0_SENDSTALL | pktrdy; 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; 1478c2ecf20Sopenharmony_ci mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci mtu->delayed_status = false; 1508c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_SETUP; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", 1538c2ecf20Sopenharmony_ci set ? "SEND" : "CLEAR", decode_ep0_state(mtu)); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void ep0_do_status_stage(struct mtu3 *mtu) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 1598c2ecf20Sopenharmony_ci u32 value; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci value = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 1628c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_EP0CSR, value | EP0_SETUPPKTRDY | EP0_DATAEND); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req) 1688c2ecf20Sopenharmony_ci{} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 1738c2ecf20Sopenharmony_ci struct mtu3 *mtu; 1748c2ecf20Sopenharmony_ci struct usb_set_sel_req sel; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci memcpy(&sel, req->buf, sizeof(sel)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci mreq = to_mtu3_request(req); 1798c2ecf20Sopenharmony_ci mtu = mreq->mtu; 1808c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n", 1818c2ecf20Sopenharmony_ci sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* queue data stage to handle 6 byte SET_SEL request */ 1858c2ecf20Sopenharmony_cistatic int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci u16 length = le16_to_cpu(setup->wLength); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (unlikely(length != 6)) { 1918c2ecf20Sopenharmony_ci dev_err(mtu->dev, "%s wrong wLength:%d\n", 1928c2ecf20Sopenharmony_ci __func__, length); 1938c2ecf20Sopenharmony_ci return -EINVAL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci mtu->ep0_req.mep = mtu->ep0; 1978c2ecf20Sopenharmony_ci mtu->ep0_req.request.length = 6; 1988c2ecf20Sopenharmony_ci mtu->ep0_req.request.buf = mtu->setup_buf; 1998c2ecf20Sopenharmony_ci mtu->ep0_req.request.complete = ep0_set_sel_complete; 2008c2ecf20Sopenharmony_ci ret = ep0_queue(mtu->ep0, &mtu->ep0_req); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return ret < 0 ? ret : 1; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int 2068c2ecf20Sopenharmony_ciep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct mtu3_ep *mep = NULL; 2098c2ecf20Sopenharmony_ci int handled = 1; 2108c2ecf20Sopenharmony_ci u8 result[2] = {0, 0}; 2118c2ecf20Sopenharmony_ci u8 epnum = 0; 2128c2ecf20Sopenharmony_ci int is_in; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci switch (setup->bRequestType & USB_RECIP_MASK) { 2158c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 2168c2ecf20Sopenharmony_ci result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED; 2178c2ecf20Sopenharmony_ci result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (mtu->g.speed >= USB_SPEED_SUPER) { 2208c2ecf20Sopenharmony_ci result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED; 2218c2ecf20Sopenharmony_ci result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__, 2258c2ecf20Sopenharmony_ci result[0], mtu->u1_enable, mtu->u2_enable); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 2318c2ecf20Sopenharmony_ci epnum = (u8) le16_to_cpu(setup->wIndex); 2328c2ecf20Sopenharmony_ci is_in = epnum & USB_DIR_IN; 2338c2ecf20Sopenharmony_ci epnum &= USB_ENDPOINT_NUMBER_MASK; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (epnum >= mtu->num_eps) { 2368c2ecf20Sopenharmony_ci handled = -EINVAL; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci if (!epnum) 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 2438c2ecf20Sopenharmony_ci if (!mep->desc) { 2448c2ecf20Sopenharmony_ci handled = -EINVAL; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci if (mep->flags & MTU3_EP_STALL) 2488c2ecf20Sopenharmony_ci result[0] |= 1 << USB_ENDPOINT_HALT; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci default: 2528c2ecf20Sopenharmony_ci /* class, vendor, etc ... delegate */ 2538c2ecf20Sopenharmony_ci handled = 0; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (handled > 0) { 2588c2ecf20Sopenharmony_ci int ret; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* prepare a data stage for GET_STATUS */ 2618c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result); 2628c2ecf20Sopenharmony_ci memcpy(mtu->setup_buf, result, sizeof(result)); 2638c2ecf20Sopenharmony_ci mtu->ep0_req.mep = mtu->ep0; 2648c2ecf20Sopenharmony_ci mtu->ep0_req.request.length = 2; 2658c2ecf20Sopenharmony_ci mtu->ep0_req.request.buf = &mtu->setup_buf; 2668c2ecf20Sopenharmony_ci mtu->ep0_req.request.complete = ep0_dummy_complete; 2678c2ecf20Sopenharmony_ci ret = ep0_queue(mtu->ep0, &mtu->ep0_req); 2688c2ecf20Sopenharmony_ci if (ret < 0) 2698c2ecf20Sopenharmony_ci handled = ret; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci return handled; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 2778c2ecf20Sopenharmony_ci int handled = 1; 2788c2ecf20Sopenharmony_ci u32 value; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci switch (le16_to_cpu(setup->wIndex) >> 8) { 2818c2ecf20Sopenharmony_ci case USB_TEST_J: 2828c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "USB_TEST_J\n"); 2838c2ecf20Sopenharmony_ci mtu->test_mode_nr = TEST_J_MODE; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case USB_TEST_K: 2868c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "USB_TEST_K\n"); 2878c2ecf20Sopenharmony_ci mtu->test_mode_nr = TEST_K_MODE; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case USB_TEST_SE0_NAK: 2908c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "USB_TEST_SE0_NAK\n"); 2918c2ecf20Sopenharmony_ci mtu->test_mode_nr = TEST_SE0_NAK_MODE; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci case USB_TEST_PACKET: 2948c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "USB_TEST_PACKET\n"); 2958c2ecf20Sopenharmony_ci mtu->test_mode_nr = TEST_PACKET_MODE; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci default: 2988c2ecf20Sopenharmony_ci handled = -EINVAL; 2998c2ecf20Sopenharmony_ci goto out; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci mtu->test_mode = true; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* no TX completion interrupt, and need restart platform after test */ 3058c2ecf20Sopenharmony_ci if (mtu->test_mode_nr == TEST_PACKET_MODE) 3068c2ecf20Sopenharmony_ci ep0_load_test_packet(mtu); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* send status before entering test mode. */ 3098c2ecf20Sopenharmony_ci ep0_do_status_stage(mtu); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* wait for ACK status sent by host */ 3128c2ecf20Sopenharmony_ci readl_poll_timeout_atomic(mbase + U3D_EP0CSR, value, 3138c2ecf20Sopenharmony_ci !(value & EP0_DATAEND), 100, 5000); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_SETUP; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciout: 3208c2ecf20Sopenharmony_ci return handled; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int ep0_handle_feature_dev(struct mtu3 *mtu, 3248c2ecf20Sopenharmony_ci struct usb_ctrlrequest *setup, bool set) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 3278c2ecf20Sopenharmony_ci int handled = -EINVAL; 3288c2ecf20Sopenharmony_ci u32 lpc; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci switch (le16_to_cpu(setup->wValue)) { 3318c2ecf20Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 3328c2ecf20Sopenharmony_ci mtu->may_wakeup = !!set; 3338c2ecf20Sopenharmony_ci handled = 1; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case USB_DEVICE_TEST_MODE: 3368c2ecf20Sopenharmony_ci if (!set || (mtu->g.speed != USB_SPEED_HIGH) || 3378c2ecf20Sopenharmony_ci (le16_to_cpu(setup->wIndex) & 0xff)) 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci handled = handle_test_mode(mtu, setup); 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci case USB_DEVICE_U1_ENABLE: 3438c2ecf20Sopenharmony_ci if (mtu->g.speed < USB_SPEED_SUPER || 3448c2ecf20Sopenharmony_ci mtu->g.state != USB_STATE_CONFIGURED) 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); 3488c2ecf20Sopenharmony_ci if (set) 3498c2ecf20Sopenharmony_ci lpc |= SW_U1_REQUEST_ENABLE; 3508c2ecf20Sopenharmony_ci else 3518c2ecf20Sopenharmony_ci lpc &= ~SW_U1_REQUEST_ENABLE; 3528c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mtu->u1_enable = !!set; 3558c2ecf20Sopenharmony_ci handled = 1; 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case USB_DEVICE_U2_ENABLE: 3588c2ecf20Sopenharmony_ci if (mtu->g.speed < USB_SPEED_SUPER || 3598c2ecf20Sopenharmony_ci mtu->g.state != USB_STATE_CONFIGURED) 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); 3638c2ecf20Sopenharmony_ci if (set) 3648c2ecf20Sopenharmony_ci lpc |= SW_U2_REQUEST_ENABLE; 3658c2ecf20Sopenharmony_ci else 3668c2ecf20Sopenharmony_ci lpc &= ~SW_U2_REQUEST_ENABLE; 3678c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci mtu->u2_enable = !!set; 3708c2ecf20Sopenharmony_ci handled = 1; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci default: 3738c2ecf20Sopenharmony_ci handled = -EINVAL; 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci return handled; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int ep0_handle_feature(struct mtu3 *mtu, 3808c2ecf20Sopenharmony_ci struct usb_ctrlrequest *setup, bool set) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct mtu3_ep *mep; 3838c2ecf20Sopenharmony_ci int handled = -EINVAL; 3848c2ecf20Sopenharmony_ci int is_in; 3858c2ecf20Sopenharmony_ci u16 value; 3868c2ecf20Sopenharmony_ci u16 index; 3878c2ecf20Sopenharmony_ci u8 epnum; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci value = le16_to_cpu(setup->wValue); 3908c2ecf20Sopenharmony_ci index = le16_to_cpu(setup->wIndex); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci switch (setup->bRequestType & USB_RECIP_MASK) { 3938c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 3948c2ecf20Sopenharmony_ci handled = ep0_handle_feature_dev(mtu, setup, set); 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 3978c2ecf20Sopenharmony_ci /* superspeed only */ 3988c2ecf20Sopenharmony_ci if (value == USB_INTRF_FUNC_SUSPEND && 3998c2ecf20Sopenharmony_ci mtu->g.speed >= USB_SPEED_SUPER) { 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * forward the request because function drivers 4028c2ecf20Sopenharmony_ci * should handle it 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci handled = 0; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 4088c2ecf20Sopenharmony_ci epnum = index & USB_ENDPOINT_NUMBER_MASK; 4098c2ecf20Sopenharmony_ci if (epnum == 0 || epnum >= mtu->num_eps || 4108c2ecf20Sopenharmony_ci value != USB_ENDPOINT_HALT) 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci is_in = index & USB_DIR_IN; 4148c2ecf20Sopenharmony_ci mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 4158c2ecf20Sopenharmony_ci if (!mep->desc) 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci handled = 1; 4198c2ecf20Sopenharmony_ci /* ignore request if endpoint is wedged */ 4208c2ecf20Sopenharmony_ci if (mep->flags & MTU3_EP_WEDGE) 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci mtu3_ep_stall_set(mep, set); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci default: 4268c2ecf20Sopenharmony_ci /* class, vendor, etc ... delegate */ 4278c2ecf20Sopenharmony_ci handled = 0; 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci return handled; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* 4348c2ecf20Sopenharmony_ci * handle all control requests can be handled 4358c2ecf20Sopenharmony_ci * returns: 4368c2ecf20Sopenharmony_ci * negative errno - error happened 4378c2ecf20Sopenharmony_ci * zero - need delegate SETUP to gadget driver 4388c2ecf20Sopenharmony_ci * positive - already handled 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_cistatic int handle_standard_request(struct mtu3 *mtu, 4418c2ecf20Sopenharmony_ci struct usb_ctrlrequest *setup) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 4448c2ecf20Sopenharmony_ci enum usb_device_state state = mtu->g.state; 4458c2ecf20Sopenharmony_ci int handled = -EINVAL; 4468c2ecf20Sopenharmony_ci u32 dev_conf; 4478c2ecf20Sopenharmony_ci u16 value; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci value = le16_to_cpu(setup->wValue); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* the gadget driver handles everything except what we must handle */ 4528c2ecf20Sopenharmony_ci switch (setup->bRequest) { 4538c2ecf20Sopenharmony_ci case USB_REQ_SET_ADDRESS: 4548c2ecf20Sopenharmony_ci /* change it after the status stage */ 4558c2ecf20Sopenharmony_ci mtu->address = (u8) (value & 0x7f); 4568c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF); 4598c2ecf20Sopenharmony_ci dev_conf &= ~DEV_ADDR_MSK; 4608c2ecf20Sopenharmony_ci dev_conf |= DEV_ADDR(mtu->address); 4618c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (mtu->address) 4648c2ecf20Sopenharmony_ci usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS); 4658c2ecf20Sopenharmony_ci else 4668c2ecf20Sopenharmony_ci usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci handled = 1; 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 4718c2ecf20Sopenharmony_ci if (state == USB_STATE_ADDRESS) { 4728c2ecf20Sopenharmony_ci usb_gadget_set_state(&mtu->g, 4738c2ecf20Sopenharmony_ci USB_STATE_CONFIGURED); 4748c2ecf20Sopenharmony_ci } else if (state == USB_STATE_CONFIGURED) { 4758c2ecf20Sopenharmony_ci /* 4768c2ecf20Sopenharmony_ci * USB2 spec sec 9.4.7, if wValue is 0 then dev 4778c2ecf20Sopenharmony_ci * is moved to addressed state 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci if (!value) 4808c2ecf20Sopenharmony_ci usb_gadget_set_state(&mtu->g, 4818c2ecf20Sopenharmony_ci USB_STATE_ADDRESS); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci handled = 0; 4848c2ecf20Sopenharmony_ci break; 4858c2ecf20Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 4868c2ecf20Sopenharmony_ci handled = ep0_handle_feature(mtu, setup, 0); 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci case USB_REQ_SET_FEATURE: 4898c2ecf20Sopenharmony_ci handled = ep0_handle_feature(mtu, setup, 1); 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci case USB_REQ_GET_STATUS: 4928c2ecf20Sopenharmony_ci handled = ep0_get_status(mtu, setup); 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case USB_REQ_SET_SEL: 4958c2ecf20Sopenharmony_ci handled = ep0_set_sel(mtu, setup); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci case USB_REQ_SET_ISOCH_DELAY: 4988c2ecf20Sopenharmony_ci handled = 1; 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci default: 5018c2ecf20Sopenharmony_ci /* delegate SET_CONFIGURATION, etc */ 5028c2ecf20Sopenharmony_ci handled = 0; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return handled; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/* receive an data packet (OUT) */ 5098c2ecf20Sopenharmony_cistatic void ep0_rx_state(struct mtu3 *mtu) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 5128c2ecf20Sopenharmony_ci struct usb_request *req; 5138c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 5148c2ecf20Sopenharmony_ci u32 maxp; 5158c2ecf20Sopenharmony_ci u32 csr; 5168c2ecf20Sopenharmony_ci u16 count = 0; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s\n", __func__); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 5218c2ecf20Sopenharmony_ci mreq = next_ep0_request(mtu); 5228c2ecf20Sopenharmony_ci req = &mreq->request; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* read packet and ack; or stall because of gadget driver bug */ 5258c2ecf20Sopenharmony_ci if (req) { 5268c2ecf20Sopenharmony_ci void *buf = req->buf + req->actual; 5278c2ecf20Sopenharmony_ci unsigned int len = req->length - req->actual; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* read the buffer */ 5308c2ecf20Sopenharmony_ci count = mtu3_readl(mbase, U3D_RXCOUNT0); 5318c2ecf20Sopenharmony_ci if (count > len) { 5328c2ecf20Sopenharmony_ci req->status = -EOVERFLOW; 5338c2ecf20Sopenharmony_ci count = len; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci ep0_read_fifo(mtu->ep0, buf, count); 5368c2ecf20Sopenharmony_ci req->actual += count; 5378c2ecf20Sopenharmony_ci csr |= EP0_RXPKTRDY; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci maxp = mtu->g.ep0->maxpacket; 5408c2ecf20Sopenharmony_ci if (count < maxp || req->actual == req->length) { 5418c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_SETUP; 5428c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "ep0 state: %s\n", 5438c2ecf20Sopenharmony_ci decode_ep0_state(mtu)); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci csr |= EP0_DATAEND; 5468c2ecf20Sopenharmony_ci } else { 5478c2ecf20Sopenharmony_ci req = NULL; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci } else { 5508c2ecf20Sopenharmony_ci csr |= EP0_RXPKTRDY | EP0_SENDSTALL; 5518c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_EP0CSR, csr); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* give back the request if have received all data */ 5578c2ecf20Sopenharmony_ci if (req) 5588c2ecf20Sopenharmony_ci ep0_req_giveback(mtu, req); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* transmitting to the host (IN) */ 5638c2ecf20Sopenharmony_cistatic void ep0_tx_state(struct mtu3 *mtu) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct mtu3_request *mreq = next_ep0_request(mtu); 5668c2ecf20Sopenharmony_ci struct usb_request *req; 5678c2ecf20Sopenharmony_ci u32 csr; 5688c2ecf20Sopenharmony_ci u8 *src; 5698c2ecf20Sopenharmony_ci u32 count; 5708c2ecf20Sopenharmony_ci u32 maxp; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s\n", __func__); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (!mreq) 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci maxp = mtu->g.ep0->maxpacket; 5788c2ecf20Sopenharmony_ci req = &mreq->request; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* load the data */ 5818c2ecf20Sopenharmony_ci src = (u8 *)req->buf + req->actual; 5828c2ecf20Sopenharmony_ci count = min(maxp, req->length - req->actual); 5838c2ecf20Sopenharmony_ci if (count) 5848c2ecf20Sopenharmony_ci ep0_write_fifo(mtu->ep0, src, count); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n", 5878c2ecf20Sopenharmony_ci __func__, req->actual, req->length, count, maxp, req->zero); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci req->actual += count; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if ((count < maxp) 5928c2ecf20Sopenharmony_ci || ((req->actual == req->length) && !req->zero)) 5938c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_TX_END; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* send it out, triggering a "txpktrdy cleared" irq */ 5968c2ecf20Sopenharmony_ci csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 5978c2ecf20Sopenharmony_ci mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__, 6008c2ecf20Sopenharmony_ci mtu3_readl(mtu->mac_base, U3D_EP0CSR)); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 6068c2ecf20Sopenharmony_ci u32 count; 6078c2ecf20Sopenharmony_ci u32 csr; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 6108c2ecf20Sopenharmony_ci count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ep0_read_fifo(mtu->ep0, (u8 *)setup, count); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n", 6158c2ecf20Sopenharmony_ci setup->bRequestType, setup->bRequest, 6168c2ecf20Sopenharmony_ci le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), 6178c2ecf20Sopenharmony_ci le16_to_cpu(setup->wLength)); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* clean up any leftover transfers */ 6208c2ecf20Sopenharmony_ci mreq = next_ep0_request(mtu); 6218c2ecf20Sopenharmony_ci if (mreq) 6228c2ecf20Sopenharmony_ci ep0_req_giveback(mtu, &mreq->request); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (le16_to_cpu(setup->wLength) == 0) { 6258c2ecf20Sopenharmony_ci ; /* no data stage, nothing to do */ 6268c2ecf20Sopenharmony_ci } else if (setup->bRequestType & USB_DIR_IN) { 6278c2ecf20Sopenharmony_ci mtu3_writel(mtu->mac_base, U3D_EP0CSR, 6288c2ecf20Sopenharmony_ci csr | EP0_SETUPPKTRDY | EP0_DPHTX); 6298c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_TX; 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci mtu3_writel(mtu->mac_base, U3D_EP0CSR, 6328c2ecf20Sopenharmony_ci (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX)); 6338c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_RX; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int ep0_handle_setup(struct mtu3 *mtu) 6388c2ecf20Sopenharmony_ci__releases(mtu->lock) 6398c2ecf20Sopenharmony_ci__acquires(mtu->lock) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct usb_ctrlrequest setup; 6428c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 6438c2ecf20Sopenharmony_ci int handled = 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci ep0_read_setup(mtu, &setup); 6468c2ecf20Sopenharmony_ci trace_mtu3_handle_setup(&setup); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 6498c2ecf20Sopenharmony_ci handled = handle_standard_request(mtu, &setup); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n", 6528c2ecf20Sopenharmony_ci handled, decode_ep0_state(mtu)); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (handled < 0) 6558c2ecf20Sopenharmony_ci goto stall; 6568c2ecf20Sopenharmony_ci else if (handled > 0) 6578c2ecf20Sopenharmony_ci goto finish; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci handled = forward_to_driver(mtu, &setup); 6608c2ecf20Sopenharmony_ci if (handled < 0) { 6618c2ecf20Sopenharmony_cistall: 6628c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ep0_stall_set(mtu->ep0, true, 6658c2ecf20Sopenharmony_ci le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cifinish: 6718c2ecf20Sopenharmony_ci if (mtu->test_mode) { 6728c2ecf20Sopenharmony_ci ; /* nothing to do */ 6738c2ecf20Sopenharmony_ci } else if (handled == USB_GADGET_DELAYED_STATUS) { 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci mreq = next_ep0_request(mtu); 6768c2ecf20Sopenharmony_ci if (mreq) { 6778c2ecf20Sopenharmony_ci /* already asked us to continue delayed status */ 6788c2ecf20Sopenharmony_ci ep0_do_status_stage(mtu); 6798c2ecf20Sopenharmony_ci ep0_req_giveback(mtu, &mreq->request); 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci /* do delayed STATUS stage till receive ep0_queue */ 6828c2ecf20Sopenharmony_ci mtu->delayed_status = true; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ep0_do_status_stage(mtu); 6878c2ecf20Sopenharmony_ci /* complete zlp request directly */ 6888c2ecf20Sopenharmony_ci mreq = next_ep0_request(mtu); 6898c2ecf20Sopenharmony_ci if (mreq && !mreq->request.length) 6908c2ecf20Sopenharmony_ci ep0_req_giveback(mtu, &mreq->request); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ciirqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci void __iomem *mbase = mtu->mac_base; 6998c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 7008c2ecf20Sopenharmony_ci u32 int_status; 7018c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 7028c2ecf20Sopenharmony_ci u32 csr; 7038c2ecf20Sopenharmony_ci u32 len; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci int_status = mtu3_readl(mbase, U3D_EPISR); 7068c2ecf20Sopenharmony_ci int_status &= mtu3_readl(mbase, U3D_EPIER); 7078c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */ 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* only handle ep0's */ 7108c2ecf20Sopenharmony_ci if (!(int_status & (EP0ISR | SETUPENDISR))) 7118c2ecf20Sopenharmony_ci return IRQ_NONE; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* abort current SETUP, and process new one */ 7148c2ecf20Sopenharmony_ci if (int_status & SETUPENDISR) 7158c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_SETUP; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci csr = mtu3_readl(mbase, U3D_EP0CSR); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* we sent a stall.. need to clear it now.. */ 7228c2ecf20Sopenharmony_ci if (csr & EP0_SENTSTALL) { 7238c2ecf20Sopenharmony_ci ep0_stall_set(mtu->ep0, false, 0); 7248c2ecf20Sopenharmony_ci csr = mtu3_readl(mbase, U3D_EP0CSR); 7258c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 7288c2ecf20Sopenharmony_ci mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu)); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci switch (mtu->ep0_state) { 7318c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX: 7328c2ecf20Sopenharmony_ci /* irq on clearing txpktrdy */ 7338c2ecf20Sopenharmony_ci if ((csr & EP0_FIFOFULL) == 0) { 7348c2ecf20Sopenharmony_ci ep0_tx_state(mtu); 7358c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_RX: 7398c2ecf20Sopenharmony_ci /* irq on set rxpktrdy */ 7408c2ecf20Sopenharmony_ci if (csr & EP0_RXPKTRDY) { 7418c2ecf20Sopenharmony_ci ep0_rx_state(mtu); 7428c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX_END: 7468c2ecf20Sopenharmony_ci mtu3_writel(mbase, U3D_EP0CSR, 7478c2ecf20Sopenharmony_ci (csr & EP0_W1C_BITS) | EP0_DATAEND); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci mreq = next_ep0_request(mtu); 7508c2ecf20Sopenharmony_ci if (mreq) 7518c2ecf20Sopenharmony_ci ep0_req_giveback(mtu, &mreq->request); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci mtu->ep0_state = MU3D_EP0_STATE_SETUP; 7548c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7558c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_SETUP: 7588c2ecf20Sopenharmony_ci if (!(csr & EP0_SETUPPKTRDY)) 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci len = mtu3_readl(mbase, U3D_RXCOUNT0); 7628c2ecf20Sopenharmony_ci if (len != 8) { 7638c2ecf20Sopenharmony_ci dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len); 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci ep0_handle_setup(mtu); 7688c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci default: 7718c2ecf20Sopenharmony_ci /* can't happen */ 7728c2ecf20Sopenharmony_ci ep0_stall_set(mtu->ep0, true, 0); 7738c2ecf20Sopenharmony_ci WARN_ON(1); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return ret; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int mtu3_ep0_enable(struct usb_ep *ep, 7828c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci /* always enabled */ 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic int mtu3_ep0_disable(struct usb_ep *ep) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci /* always enabled */ 7918c2ecf20Sopenharmony_ci return -EINVAL; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct mtu3 *mtu = mep->mtu; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci mreq->mtu = mtu; 7998c2ecf20Sopenharmony_ci mreq->request.actual = 0; 8008c2ecf20Sopenharmony_ci mreq->request.status = -EINPROGRESS; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, 8038c2ecf20Sopenharmony_ci mep->name, decode_ep0_state(mtu), mreq->request.length); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci switch (mtu->ep0_state) { 8068c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_SETUP: 8078c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_RX: /* control-OUT data */ 8088c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX: /* control-IN data */ 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci default: 8118c2ecf20Sopenharmony_ci dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__, 8128c2ecf20Sopenharmony_ci decode_ep0_state(mtu)); 8138c2ecf20Sopenharmony_ci return -EINVAL; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (mtu->delayed_status) { 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci mtu->delayed_status = false; 8198c2ecf20Sopenharmony_ci ep0_do_status_stage(mtu); 8208c2ecf20Sopenharmony_ci /* needn't giveback the request for handling delay STATUS */ 8218c2ecf20Sopenharmony_ci return 0; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!list_empty(&mep->req_list)) 8258c2ecf20Sopenharmony_ci return -EBUSY; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci list_add_tail(&mreq->list, &mep->req_list); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* sequence #1, IN ... start writing the data */ 8308c2ecf20Sopenharmony_ci if (mtu->ep0_state == MU3D_EP0_STATE_TX) 8318c2ecf20Sopenharmony_ci ep0_tx_state(mtu); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int mtu3_ep0_queue(struct usb_ep *ep, 8378c2ecf20Sopenharmony_ci struct usb_request *req, gfp_t gfp) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct mtu3_ep *mep; 8408c2ecf20Sopenharmony_ci struct mtu3_request *mreq; 8418c2ecf20Sopenharmony_ci struct mtu3 *mtu; 8428c2ecf20Sopenharmony_ci unsigned long flags; 8438c2ecf20Sopenharmony_ci int ret = 0; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (!ep || !req) 8468c2ecf20Sopenharmony_ci return -EINVAL; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci mep = to_mtu3_ep(ep); 8498c2ecf20Sopenharmony_ci mtu = mep->mtu; 8508c2ecf20Sopenharmony_ci mreq = to_mtu3_request(req); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci spin_lock_irqsave(&mtu->lock, flags); 8538c2ecf20Sopenharmony_ci ret = ep0_queue(mep, mreq); 8548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mtu->lock, flags); 8558c2ecf20Sopenharmony_ci return ret; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci /* we just won't support this */ 8618c2ecf20Sopenharmony_ci return -EINVAL; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int mtu3_ep0_halt(struct usb_ep *ep, int value) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct mtu3_ep *mep; 8678c2ecf20Sopenharmony_ci struct mtu3 *mtu; 8688c2ecf20Sopenharmony_ci unsigned long flags; 8698c2ecf20Sopenharmony_ci int ret = 0; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (!ep || !value) 8728c2ecf20Sopenharmony_ci return -EINVAL; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci mep = to_mtu3_ep(ep); 8758c2ecf20Sopenharmony_ci mtu = mep->mtu; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "%s\n", __func__); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci spin_lock_irqsave(&mtu->lock, flags); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (!list_empty(&mep->req_list)) { 8828c2ecf20Sopenharmony_ci ret = -EBUSY; 8838c2ecf20Sopenharmony_ci goto cleanup; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci switch (mtu->ep0_state) { 8878c2ecf20Sopenharmony_ci /* 8888c2ecf20Sopenharmony_ci * stalls are usually issued after parsing SETUP packet, either 8898c2ecf20Sopenharmony_ci * directly in irq context from setup() or else later. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX: 8928c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_TX_END: 8938c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_RX: 8948c2ecf20Sopenharmony_ci case MU3D_EP0_STATE_SETUP: 8958c2ecf20Sopenharmony_ci ep0_stall_set(mtu->ep0, true, 0); 8968c2ecf20Sopenharmony_ci break; 8978c2ecf20Sopenharmony_ci default: 8988c2ecf20Sopenharmony_ci dev_dbg(mtu->dev, "ep0 can't halt in state %s\n", 8998c2ecf20Sopenharmony_ci decode_ep0_state(mtu)); 9008c2ecf20Sopenharmony_ci ret = -EINVAL; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cicleanup: 9048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mtu->lock, flags); 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ciconst struct usb_ep_ops mtu3_ep0_ops = { 9098c2ecf20Sopenharmony_ci .enable = mtu3_ep0_enable, 9108c2ecf20Sopenharmony_ci .disable = mtu3_ep0_disable, 9118c2ecf20Sopenharmony_ci .alloc_request = mtu3_alloc_request, 9128c2ecf20Sopenharmony_ci .free_request = mtu3_free_request, 9138c2ecf20Sopenharmony_ci .queue = mtu3_ep0_queue, 9148c2ecf20Sopenharmony_ci .dequeue = mtu3_ep0_dequeue, 9158c2ecf20Sopenharmony_ci .set_halt = mtu3_ep0_halt, 9168c2ecf20Sopenharmony_ci}; 917