18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bdc_cmd.c - BRCM BDC USB3.0 device controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Broadcom Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Ashwini Pahuja 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "bdc.h" 138c2ecf20Sopenharmony_ci#include "bdc_cmd.h" 148c2ecf20Sopenharmony_ci#include "bdc_dbg.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* Issues a cmd to cmd processor and waits for cmd completion */ 178c2ecf20Sopenharmony_cistatic int bdc_issue_cmd(struct bdc *bdc, u32 cmd_sc, u32 param0, 188c2ecf20Sopenharmony_ci u32 param1, u32 param2) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci u32 timeout = BDC_CMD_TIMEOUT; 218c2ecf20Sopenharmony_ci u32 cmd_status; 228c2ecf20Sopenharmony_ci u32 temp; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci bdc_writel(bdc->regs, BDC_CMDPAR0, param0); 258c2ecf20Sopenharmony_ci bdc_writel(bdc->regs, BDC_CMDPAR1, param1); 268c2ecf20Sopenharmony_ci bdc_writel(bdc->regs, BDC_CMDPAR2, param2); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* Issue the cmd */ 298c2ecf20Sopenharmony_ci /* Make sure the cmd params are written before asking HW to exec cmd */ 308c2ecf20Sopenharmony_ci wmb(); 318c2ecf20Sopenharmony_ci bdc_writel(bdc->regs, BDC_CMDSC, cmd_sc | BDC_CMD_CWS | BDC_CMD_SRD); 328c2ecf20Sopenharmony_ci do { 338c2ecf20Sopenharmony_ci temp = bdc_readl(bdc->regs, BDC_CMDSC); 348c2ecf20Sopenharmony_ci dev_dbg_ratelimited(bdc->dev, "cmdsc=%x", temp); 358c2ecf20Sopenharmony_ci cmd_status = BDC_CMD_CST(temp); 368c2ecf20Sopenharmony_ci if (cmd_status != BDC_CMDS_BUSY) { 378c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, 388c2ecf20Sopenharmony_ci "command completed cmd_sts:%x\n", cmd_status); 398c2ecf20Sopenharmony_ci return cmd_status; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci udelay(1); 428c2ecf20Sopenharmony_ci } while (timeout--); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci dev_err(bdc->dev, 458c2ecf20Sopenharmony_ci "command operation timedout cmd_status=%d\n", cmd_status); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return cmd_status; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Submits cmd and analyze the return value of bdc_issue_cmd */ 518c2ecf20Sopenharmony_cistatic int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc, 528c2ecf20Sopenharmony_ci u32 param0, u32 param1, u32 param2) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u32 temp, cmd_status; 558c2ecf20Sopenharmony_ci int ret; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci temp = bdc_readl(bdc->regs, BDC_CMDSC); 588c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, 598c2ecf20Sopenharmony_ci "%s:CMDSC:%08x cmdsc:%08x param0=%08x param1=%08x param2=%08x\n", 608c2ecf20Sopenharmony_ci __func__, temp, cmd_sc, param0, param1, param2); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci cmd_status = BDC_CMD_CST(temp); 638c2ecf20Sopenharmony_ci if (cmd_status == BDC_CMDS_BUSY) { 648c2ecf20Sopenharmony_ci dev_err(bdc->dev, "command processor busy: %x\n", cmd_status); 658c2ecf20Sopenharmony_ci return -EBUSY; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci ret = bdc_issue_cmd(bdc, cmd_sc, param0, param1, param2); 688c2ecf20Sopenharmony_ci switch (ret) { 698c2ecf20Sopenharmony_ci case BDC_CMDS_SUCC: 708c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "command completed successfully\n"); 718c2ecf20Sopenharmony_ci ret = 0; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci case BDC_CMDS_PARA: 758c2ecf20Sopenharmony_ci dev_err(bdc->dev, "command parameter error\n"); 768c2ecf20Sopenharmony_ci ret = -EINVAL; 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci case BDC_CMDS_STAT: 808c2ecf20Sopenharmony_ci dev_err(bdc->dev, "Invalid device/ep state\n"); 818c2ecf20Sopenharmony_ci ret = -EINVAL; 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci case BDC_CMDS_FAIL: 858c2ecf20Sopenharmony_ci dev_err(bdc->dev, "Command failed?\n"); 868c2ecf20Sopenharmony_ci ret = -EAGAIN; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci case BDC_CMDS_INTL: 908c2ecf20Sopenharmony_ci dev_err(bdc->dev, "BDC Internal error\n"); 918c2ecf20Sopenharmony_ci ret = -ECONNRESET; 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci case BDC_CMDS_BUSY: 958c2ecf20Sopenharmony_ci dev_err(bdc->dev, 968c2ecf20Sopenharmony_ci "command timedout waited for %dusec\n", 978c2ecf20Sopenharmony_ci BDC_CMD_TIMEOUT); 988c2ecf20Sopenharmony_ci ret = -ECONNRESET; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci default: 1018c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "Unknown command completion code:%x\n", ret); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Deconfigure the endpoint from HW */ 1088c2ecf20Sopenharmony_ciint bdc_dconfig_ep(struct bdc *bdc, struct bdc_ep *ep) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u32 cmd_sc; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci cmd_sc = BDC_SUB_CMD_DRP_EP|BDC_CMD_EPN(ep->ep_num)|BDC_CMD_EPC; 1138c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s ep->ep_num =%d cmd_sc=%x\n", __func__, 1148c2ecf20Sopenharmony_ci ep->ep_num, cmd_sc); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* Reinitalize the bdlist after config ep command */ 1208c2ecf20Sopenharmony_cistatic void ep_bd_list_reinit(struct bdc_ep *ep) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct bdc *bdc = ep->bdc; 1238c2ecf20Sopenharmony_ci struct bdc_bd *bd; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ep->bd_list.eqp_bdi = 0; 1268c2ecf20Sopenharmony_ci ep->bd_list.hwd_bdi = 0; 1278c2ecf20Sopenharmony_ci bd = ep->bd_list.bd_table_array[0]->start_bd; 1288c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s ep:%p bd:%p\n", __func__, ep, bd); 1298c2ecf20Sopenharmony_ci memset(bd, 0, sizeof(struct bdc_bd)); 1308c2ecf20Sopenharmony_ci bd->offset[3] |= cpu_to_le32(BD_SBF); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Configure an endpoint */ 1348c2ecf20Sopenharmony_ciint bdc_config_ep(struct bdc *bdc, struct bdc_ep *ep) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci const struct usb_ss_ep_comp_descriptor *comp_desc; 1378c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc; 1388c2ecf20Sopenharmony_ci u32 param0, param1, param2, cmd_sc; 1398c2ecf20Sopenharmony_ci u32 mps, mbs, mul, si; 1408c2ecf20Sopenharmony_ci int ret; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci desc = ep->desc; 1438c2ecf20Sopenharmony_ci comp_desc = ep->comp_desc; 1448c2ecf20Sopenharmony_ci cmd_sc = mul = mbs = param2 = 0; 1458c2ecf20Sopenharmony_ci param0 = lower_32_bits(ep->bd_list.bd_table_array[0]->dma); 1468c2ecf20Sopenharmony_ci param1 = upper_32_bits(ep->bd_list.bd_table_array[0]->dma); 1478c2ecf20Sopenharmony_ci cpu_to_le32s(¶m0); 1488c2ecf20Sopenharmony_ci cpu_to_le32s(¶m1); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s: param0=%08x param1=%08x", 1518c2ecf20Sopenharmony_ci __func__, param0, param1); 1528c2ecf20Sopenharmony_ci si = desc->bInterval; 1538c2ecf20Sopenharmony_ci si = clamp_val(si, 1, 16) - 1; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci mps = usb_endpoint_maxp(desc); 1568c2ecf20Sopenharmony_ci mps &= 0x7ff; 1578c2ecf20Sopenharmony_ci param2 |= mps << MP_SHIFT; 1588c2ecf20Sopenharmony_ci param2 |= usb_endpoint_type(desc) << EPT_SHIFT; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci switch (bdc->gadget.speed) { 1618c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 1628c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(desc) || 1638c2ecf20Sopenharmony_ci usb_endpoint_xfer_isoc(desc)) { 1648c2ecf20Sopenharmony_ci param2 |= si; 1658c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc) && comp_desc) 1668c2ecf20Sopenharmony_ci mul = comp_desc->bmAttributes; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci param2 |= mul << EPM_SHIFT; 1708c2ecf20Sopenharmony_ci if (comp_desc) 1718c2ecf20Sopenharmony_ci mbs = comp_desc->bMaxBurst; 1728c2ecf20Sopenharmony_ci param2 |= mbs << MB_SHIFT; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 1768c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc) || 1778c2ecf20Sopenharmony_ci usb_endpoint_xfer_int(desc)) { 1788c2ecf20Sopenharmony_ci param2 |= si; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci mbs = usb_endpoint_maxp_mult(desc); 1818c2ecf20Sopenharmony_ci param2 |= mbs << MB_SHIFT; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 1868c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 1878c2ecf20Sopenharmony_ci /* the hardware accepts SI in 125usec range */ 1888c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(desc)) 1898c2ecf20Sopenharmony_ci si += 3; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* 1928c2ecf20Sopenharmony_ci * FS Int endpoints can have si of 1-255ms but the controller 1938c2ecf20Sopenharmony_ci * accepts 2^bInterval*125usec, so convert ms to nearest power 1948c2ecf20Sopenharmony_ci * of 2 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(desc)) 1978c2ecf20Sopenharmony_ci si = fls(desc->bInterval * 8) - 1; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci param2 |= si; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci default: 2028c2ecf20Sopenharmony_ci dev_err(bdc->dev, "UNKNOWN speed ERR\n"); 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci cmd_sc |= BDC_CMD_EPC|BDC_CMD_EPN(ep->ep_num)|BDC_SUB_CMD_ADD_EP; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "cmd_sc=%x param2=%08x\n", cmd_sc, param2); 2098c2ecf20Sopenharmony_ci ret = bdc_submit_cmd(bdc, cmd_sc, param0, param1, param2); 2108c2ecf20Sopenharmony_ci if (ret) { 2118c2ecf20Sopenharmony_ci dev_err(bdc->dev, "command failed :%x\n", ret); 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci ep_bd_list_reinit(ep); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Change the HW deq pointer, if this command is successful, HW will start 2218c2ecf20Sopenharmony_ci * fetching the next bd from address dma_addr. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ciint bdc_ep_bla(struct bdc *bdc, struct bdc_ep *ep, dma_addr_t dma_addr) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci u32 param0, param1; 2268c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s: add=%08llx\n", __func__, 2298c2ecf20Sopenharmony_ci (unsigned long long)(dma_addr)); 2308c2ecf20Sopenharmony_ci param0 = lower_32_bits(dma_addr); 2318c2ecf20Sopenharmony_ci param1 = upper_32_bits(dma_addr); 2328c2ecf20Sopenharmony_ci cpu_to_le32s(¶m0); 2338c2ecf20Sopenharmony_ci cpu_to_le32s(¶m1); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci cmd_sc |= BDC_CMD_EPN(ep->ep_num)|BDC_CMD_BLA; 2368c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "cmd_sc=%x\n", cmd_sc); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* Set the address sent bu Host in SET_ADD request */ 2428c2ecf20Sopenharmony_ciint bdc_address_device(struct bdc *bdc, u32 add) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 2458c2ecf20Sopenharmony_ci u32 param2; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s: add=%d\n", __func__, add); 2488c2ecf20Sopenharmony_ci cmd_sc |= BDC_SUB_CMD_ADD|BDC_CMD_DVC; 2498c2ecf20Sopenharmony_ci param2 = add & 0x7f; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* Send a Function Wake notification packet using FH command */ 2558c2ecf20Sopenharmony_ciint bdc_function_wake_fh(struct bdc *bdc, u8 intf) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci u32 param0, param1; 2588c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci param0 = param1 = 0; 2618c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s intf=%d\n", __func__, intf); 2628c2ecf20Sopenharmony_ci cmd_sc |= BDC_CMD_FH; 2638c2ecf20Sopenharmony_ci param0 |= TRA_PACKET; 2648c2ecf20Sopenharmony_ci param0 |= (bdc->dev_addr << 25); 2658c2ecf20Sopenharmony_ci param1 |= DEV_NOTF_TYPE; 2668c2ecf20Sopenharmony_ci param1 |= (FWK_SUBTYPE<<4); 2678c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "param0=%08x param1=%08x\n", param0, param1); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* Send a Function Wake notification packet using DNC command */ 2738c2ecf20Sopenharmony_ciint bdc_function_wake(struct bdc *bdc, u8 intf) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 2768c2ecf20Sopenharmony_ci u32 param2 = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s intf=%d", __func__, intf); 2798c2ecf20Sopenharmony_ci param2 |= intf; 2808c2ecf20Sopenharmony_ci cmd_sc |= BDC_SUB_CMD_FWK|BDC_CMD_DNC; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Stall the endpoint */ 2868c2ecf20Sopenharmony_ciint bdc_ep_set_stall(struct bdc *bdc, int epnum) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s epnum=%d\n", __func__, epnum); 2918c2ecf20Sopenharmony_ci /* issue a stall endpoint command */ 2928c2ecf20Sopenharmony_ci cmd_sc |= BDC_SUB_CMD_EP_STL | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* resets the endpoint, called when host sends CLEAR_FEATURE(HALT) */ 2988c2ecf20Sopenharmony_ciint bdc_ep_clear_stall(struct bdc *bdc, int epnum) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct bdc_ep *ep; 3018c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 3028c2ecf20Sopenharmony_ci int ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s: epnum=%d\n", __func__, epnum); 3058c2ecf20Sopenharmony_ci ep = bdc->bdc_ep_array[epnum]; 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * If we are not in stalled then stall Endpoint and issue clear stall, 3088c2ecf20Sopenharmony_ci * his will reset the seq number for non EP0. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (epnum != 1) { 3118c2ecf20Sopenharmony_ci /* if the endpoint it not stallled */ 3128c2ecf20Sopenharmony_ci if (!(ep->flags & BDC_EP_STALL)) { 3138c2ecf20Sopenharmony_ci ret = bdc_ep_set_stall(bdc, epnum); 3148c2ecf20Sopenharmony_ci if (ret) 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci /* Preserve the seq number for ep0 only */ 3198c2ecf20Sopenharmony_ci if (epnum != 1) 3208c2ecf20Sopenharmony_ci cmd_sc |= BDC_CMD_EPO_RST_SN; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* issue a reset endpoint command */ 3238c2ecf20Sopenharmony_ci cmd_sc |= BDC_SUB_CMD_EP_RST | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); 3268c2ecf20Sopenharmony_ci if (ret) { 3278c2ecf20Sopenharmony_ci dev_err(bdc->dev, "command failed:%x\n", ret); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci bdc_notify_xfr(bdc, epnum); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return ret; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* Stop the endpoint, called when software wants to dequeue some request */ 3368c2ecf20Sopenharmony_ciint bdc_stop_ep(struct bdc *bdc, int epnum) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct bdc_ep *ep; 3398c2ecf20Sopenharmony_ci u32 cmd_sc = 0; 3408c2ecf20Sopenharmony_ci int ret; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ep = bdc->bdc_ep_array[epnum]; 3438c2ecf20Sopenharmony_ci dev_dbg(bdc->dev, "%s: ep:%s ep->flags:%08x\n", __func__, 3448c2ecf20Sopenharmony_ci ep->name, ep->flags); 3458c2ecf20Sopenharmony_ci /* Endpoint has to be in running state to execute stop ep command */ 3468c2ecf20Sopenharmony_ci if (!(ep->flags & BDC_EP_ENABLED)) { 3478c2ecf20Sopenharmony_ci dev_err(bdc->dev, "stop endpoint called for disabled ep\n"); 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if ((ep->flags & BDC_EP_STALL) || (ep->flags & BDC_EP_STOP)) 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* issue a stop endpoint command */ 3548c2ecf20Sopenharmony_ci cmd_sc |= BDC_CMD_EP0_XSD | BDC_SUB_CMD_EP_STP 3558c2ecf20Sopenharmony_ci | BDC_CMD_EPN(epnum) | BDC_CMD_EPO; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0); 3588c2ecf20Sopenharmony_ci if (ret) { 3598c2ecf20Sopenharmony_ci dev_err(bdc->dev, 3608c2ecf20Sopenharmony_ci "stop endpoint command didn't complete:%d ep:%s\n", 3618c2ecf20Sopenharmony_ci ret, ep->name); 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci ep->flags |= BDC_EP_STOP; 3658c2ecf20Sopenharmony_ci bdc_dump_epsts(bdc); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 369