1f6ce6072SVignesh Raghavendra // SPDX-License-Identifier: GPL-2.0 2f6ce6072SVignesh Raghavendra /* 3f6ce6072SVignesh Raghavendra * Cadence USBSS DRD Driver - gadget side. 4f6ce6072SVignesh Raghavendra * 5f6ce6072SVignesh Raghavendra * Copyright (C) 2018 Cadence Design Systems. 6f6ce6072SVignesh Raghavendra * Copyright (C) 2017-2018 NXP 7f6ce6072SVignesh Raghavendra * 8f6ce6072SVignesh Raghavendra * Authors: Pawel Jez <pjez@cadence.com>, 9f6ce6072SVignesh Raghavendra * Pawel Laszczak <pawell@cadence.com> 10f6ce6072SVignesh Raghavendra * Peter Chen <peter.chen@nxp.com> 11f6ce6072SVignesh Raghavendra */ 12f6ce6072SVignesh Raghavendra 13*6a2b8f48SVignesh Raghavendra #include <cpu_func.h> 14f6ce6072SVignesh Raghavendra #include <linux/usb/composite.h> 15f6ce6072SVignesh Raghavendra #include <linux/iopoll.h> 16f6ce6072SVignesh Raghavendra 17f6ce6072SVignesh Raghavendra #include "gadget.h" 18f6ce6072SVignesh Raghavendra #include "trace.h" 19f6ce6072SVignesh Raghavendra 20f6ce6072SVignesh Raghavendra #define readl_poll_timeout_atomic readl_poll_timeout 21f6ce6072SVignesh Raghavendra #define usleep_range(a, b) udelay((b)) 22f6ce6072SVignesh Raghavendra 23f6ce6072SVignesh Raghavendra static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { 24f6ce6072SVignesh Raghavendra .bLength = USB_DT_ENDPOINT_SIZE, 25f6ce6072SVignesh Raghavendra .bDescriptorType = USB_DT_ENDPOINT, 26f6ce6072SVignesh Raghavendra .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 27f6ce6072SVignesh Raghavendra }; 28f6ce6072SVignesh Raghavendra 29f6ce6072SVignesh Raghavendra /** 30f6ce6072SVignesh Raghavendra * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware 31f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 32f6ce6072SVignesh Raghavendra * @dma_addr: physical address where data is/will be stored 33f6ce6072SVignesh Raghavendra * @length: data length 34f6ce6072SVignesh Raghavendra * @erdy: set it to 1 when ERDY packet should be sent - 35f6ce6072SVignesh Raghavendra * exit from flow control state 36f6ce6072SVignesh Raghavendra */ 37f6ce6072SVignesh Raghavendra static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, 38f6ce6072SVignesh Raghavendra dma_addr_t dma_addr, 39f6ce6072SVignesh Raghavendra unsigned int length, int erdy, int zlp) 40f6ce6072SVignesh Raghavendra { 41f6ce6072SVignesh Raghavendra struct cdns3_usb_regs __iomem *regs = priv_dev->regs; 42f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = priv_dev->eps[0]; 43f6ce6072SVignesh Raghavendra 44f6ce6072SVignesh Raghavendra priv_ep->trb_pool[0].buffer = TRB_BUFFER(dma_addr); 45f6ce6072SVignesh Raghavendra priv_ep->trb_pool[0].length = TRB_LEN(length); 46f6ce6072SVignesh Raghavendra 47f6ce6072SVignesh Raghavendra if (zlp) { 48f6ce6072SVignesh Raghavendra priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_TYPE(TRB_NORMAL); 49f6ce6072SVignesh Raghavendra priv_ep->trb_pool[1].buffer = TRB_BUFFER(dma_addr); 50f6ce6072SVignesh Raghavendra priv_ep->trb_pool[1].length = TRB_LEN(0); 51f6ce6072SVignesh Raghavendra priv_ep->trb_pool[1].control = TRB_CYCLE | TRB_IOC | 52f6ce6072SVignesh Raghavendra TRB_TYPE(TRB_NORMAL); 53f6ce6072SVignesh Raghavendra } else { 54f6ce6072SVignesh Raghavendra priv_ep->trb_pool[0].control = TRB_CYCLE | TRB_IOC | 55f6ce6072SVignesh Raghavendra TRB_TYPE(TRB_NORMAL); 56f6ce6072SVignesh Raghavendra priv_ep->trb_pool[1].control = 0; 57f6ce6072SVignesh Raghavendra } 58f6ce6072SVignesh Raghavendra 59f6ce6072SVignesh Raghavendra /* Flush both TRBs */ 60f6ce6072SVignesh Raghavendra flush_dcache_range((unsigned long)priv_ep->trb_pool, 61f6ce6072SVignesh Raghavendra (unsigned long)priv_ep->trb_pool + 62f6ce6072SVignesh Raghavendra ROUND(sizeof(struct cdns3_trb) * 2, 63f6ce6072SVignesh Raghavendra CONFIG_SYS_CACHELINE_SIZE)); 64f6ce6072SVignesh Raghavendra 65f6ce6072SVignesh Raghavendra trace_cdns3_prepare_trb(priv_ep, priv_ep->trb_pool); 66f6ce6072SVignesh Raghavendra 67f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, priv_dev->ep0_data_dir); 68f6ce6072SVignesh Raghavendra 69f6ce6072SVignesh Raghavendra writel(EP_STS_TRBERR, ®s->ep_sts); 70f6ce6072SVignesh Raghavendra writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma), ®s->ep_traddr); 71f6ce6072SVignesh Raghavendra trace_cdns3_doorbell_ep0(priv_dev->ep0_data_dir ? "ep0in" : "ep0out", 72f6ce6072SVignesh Raghavendra readl(®s->ep_traddr)); 73f6ce6072SVignesh Raghavendra 74f6ce6072SVignesh Raghavendra /* TRB should be prepared before starting transfer. */ 75f6ce6072SVignesh Raghavendra writel(EP_CMD_DRDY, ®s->ep_cmd); 76f6ce6072SVignesh Raghavendra 77f6ce6072SVignesh Raghavendra /* Resume controller before arming transfer. */ 78f6ce6072SVignesh Raghavendra __cdns3_gadget_wakeup(priv_dev); 79f6ce6072SVignesh Raghavendra 80f6ce6072SVignesh Raghavendra if (erdy) 81f6ce6072SVignesh Raghavendra writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); 82f6ce6072SVignesh Raghavendra } 83f6ce6072SVignesh Raghavendra 84f6ce6072SVignesh Raghavendra /** 85f6ce6072SVignesh Raghavendra * cdns3_ep0_delegate_req - Returns status of handling setup packet 86f6ce6072SVignesh Raghavendra * Setup is handled by gadget driver 87f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 88f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 89f6ce6072SVignesh Raghavendra * 90f6ce6072SVignesh Raghavendra * Returns zero on success or negative value on failure 91f6ce6072SVignesh Raghavendra */ 92f6ce6072SVignesh Raghavendra static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, 93f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 94f6ce6072SVignesh Raghavendra { 95f6ce6072SVignesh Raghavendra int ret; 96f6ce6072SVignesh Raghavendra 97f6ce6072SVignesh Raghavendra spin_unlock(&priv_dev->lock); 98f6ce6072SVignesh Raghavendra priv_dev->setup_pending = 1; 99f6ce6072SVignesh Raghavendra ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); 100f6ce6072SVignesh Raghavendra priv_dev->setup_pending = 0; 101f6ce6072SVignesh Raghavendra spin_lock(&priv_dev->lock); 102f6ce6072SVignesh Raghavendra return ret; 103f6ce6072SVignesh Raghavendra } 104f6ce6072SVignesh Raghavendra 105f6ce6072SVignesh Raghavendra static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) 106f6ce6072SVignesh Raghavendra { 107f6ce6072SVignesh Raghavendra priv_dev->ep0_data_dir = 0; 108f6ce6072SVignesh Raghavendra priv_dev->ep0_stage = CDNS3_SETUP_STAGE; 109f6ce6072SVignesh Raghavendra cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 110f6ce6072SVignesh Raghavendra sizeof(struct usb_ctrlrequest), 0, 0); 111f6ce6072SVignesh Raghavendra } 112f6ce6072SVignesh Raghavendra 113f6ce6072SVignesh Raghavendra static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev, 114f6ce6072SVignesh Raghavendra u8 send_stall, u8 send_erdy) 115f6ce6072SVignesh Raghavendra { 116f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = priv_dev->eps[0]; 117f6ce6072SVignesh Raghavendra struct usb_request *request; 118f6ce6072SVignesh Raghavendra 119f6ce6072SVignesh Raghavendra request = cdns3_next_request(&priv_ep->pending_req_list); 120f6ce6072SVignesh Raghavendra if (request) 121f6ce6072SVignesh Raghavendra list_del_init(&request->list); 122f6ce6072SVignesh Raghavendra 123f6ce6072SVignesh Raghavendra if (send_stall) { 124f6ce6072SVignesh Raghavendra trace_cdns3_halt(priv_ep, send_stall, 0); 125f6ce6072SVignesh Raghavendra /* set_stall on ep0 */ 126f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, 0x00); 127f6ce6072SVignesh Raghavendra writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd); 128f6ce6072SVignesh Raghavendra } else { 129f6ce6072SVignesh Raghavendra cdns3_prepare_setup_packet(priv_dev); 130f6ce6072SVignesh Raghavendra } 131f6ce6072SVignesh Raghavendra 132f6ce6072SVignesh Raghavendra priv_dev->ep0_stage = CDNS3_SETUP_STAGE; 133f6ce6072SVignesh Raghavendra writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL, 134f6ce6072SVignesh Raghavendra &priv_dev->regs->ep_cmd); 135f6ce6072SVignesh Raghavendra 136f6ce6072SVignesh Raghavendra cdns3_allow_enable_l1(priv_dev, 1); 137f6ce6072SVignesh Raghavendra } 138f6ce6072SVignesh Raghavendra 139f6ce6072SVignesh Raghavendra /** 140f6ce6072SVignesh Raghavendra * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request 141f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 142f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 143f6ce6072SVignesh Raghavendra * 144f6ce6072SVignesh Raghavendra * Returns 0 if success, USB_GADGET_DELAYED_STATUS on deferred status stage, 145f6ce6072SVignesh Raghavendra * error code on error 146f6ce6072SVignesh Raghavendra */ 147f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, 148f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 149f6ce6072SVignesh Raghavendra { 150f6ce6072SVignesh Raghavendra enum usb_device_state device_state = priv_dev->gadget.state; 151f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep; 152f6ce6072SVignesh Raghavendra u32 config = le16_to_cpu(ctrl_req->wValue); 153f6ce6072SVignesh Raghavendra int result = 0; 154f6ce6072SVignesh Raghavendra int i; 155f6ce6072SVignesh Raghavendra 156f6ce6072SVignesh Raghavendra switch (device_state) { 157f6ce6072SVignesh Raghavendra case USB_STATE_ADDRESS: 158f6ce6072SVignesh Raghavendra /* Configure non-control EPs */ 159f6ce6072SVignesh Raghavendra for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { 160f6ce6072SVignesh Raghavendra priv_ep = priv_dev->eps[i]; 161f6ce6072SVignesh Raghavendra if (!priv_ep) 162f6ce6072SVignesh Raghavendra continue; 163f6ce6072SVignesh Raghavendra 164f6ce6072SVignesh Raghavendra if (priv_ep->flags & EP_CLAIMED) 165f6ce6072SVignesh Raghavendra cdns3_ep_config(priv_ep); 166f6ce6072SVignesh Raghavendra } 167f6ce6072SVignesh Raghavendra 168f6ce6072SVignesh Raghavendra result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); 169f6ce6072SVignesh Raghavendra 170f6ce6072SVignesh Raghavendra if (result) 171f6ce6072SVignesh Raghavendra return result; 172f6ce6072SVignesh Raghavendra 173f6ce6072SVignesh Raghavendra if (config) { 174f6ce6072SVignesh Raghavendra cdns3_set_hw_configuration(priv_dev); 175f6ce6072SVignesh Raghavendra } else { 176f6ce6072SVignesh Raghavendra cdns3_hw_reset_eps_config(priv_dev); 177f6ce6072SVignesh Raghavendra usb_gadget_set_state(&priv_dev->gadget, 178f6ce6072SVignesh Raghavendra USB_STATE_ADDRESS); 179f6ce6072SVignesh Raghavendra } 180f6ce6072SVignesh Raghavendra break; 181f6ce6072SVignesh Raghavendra case USB_STATE_CONFIGURED: 182f6ce6072SVignesh Raghavendra result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); 183f6ce6072SVignesh Raghavendra 184f6ce6072SVignesh Raghavendra if (!config && !result) { 185f6ce6072SVignesh Raghavendra cdns3_hw_reset_eps_config(priv_dev); 186f6ce6072SVignesh Raghavendra usb_gadget_set_state(&priv_dev->gadget, 187f6ce6072SVignesh Raghavendra USB_STATE_ADDRESS); 188f6ce6072SVignesh Raghavendra } 189f6ce6072SVignesh Raghavendra break; 190f6ce6072SVignesh Raghavendra default: 191f6ce6072SVignesh Raghavendra result = -EINVAL; 192f6ce6072SVignesh Raghavendra } 193f6ce6072SVignesh Raghavendra 194f6ce6072SVignesh Raghavendra return result; 195f6ce6072SVignesh Raghavendra } 196f6ce6072SVignesh Raghavendra 197f6ce6072SVignesh Raghavendra /** 198f6ce6072SVignesh Raghavendra * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request 199f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 200f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 201f6ce6072SVignesh Raghavendra * 202f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 203f6ce6072SVignesh Raghavendra */ 204f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, 205f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 206f6ce6072SVignesh Raghavendra { 207f6ce6072SVignesh Raghavendra enum usb_device_state device_state = priv_dev->gadget.state; 208f6ce6072SVignesh Raghavendra u32 reg; 209f6ce6072SVignesh Raghavendra u32 addr; 210f6ce6072SVignesh Raghavendra 211f6ce6072SVignesh Raghavendra addr = le16_to_cpu(ctrl_req->wValue); 212f6ce6072SVignesh Raghavendra 213f6ce6072SVignesh Raghavendra if (addr > USB_DEVICE_MAX_ADDRESS) { 214f6ce6072SVignesh Raghavendra dev_err(priv_dev->dev, 215f6ce6072SVignesh Raghavendra "Device address (%d) cannot be greater than %d\n", 216f6ce6072SVignesh Raghavendra addr, USB_DEVICE_MAX_ADDRESS); 217f6ce6072SVignesh Raghavendra return -EINVAL; 218f6ce6072SVignesh Raghavendra } 219f6ce6072SVignesh Raghavendra 220f6ce6072SVignesh Raghavendra if (device_state == USB_STATE_CONFIGURED) { 221f6ce6072SVignesh Raghavendra dev_err(priv_dev->dev, 222f6ce6072SVignesh Raghavendra "can't set_address from configured state\n"); 223f6ce6072SVignesh Raghavendra return -EINVAL; 224f6ce6072SVignesh Raghavendra } 225f6ce6072SVignesh Raghavendra 226f6ce6072SVignesh Raghavendra reg = readl(&priv_dev->regs->usb_cmd); 227f6ce6072SVignesh Raghavendra 228f6ce6072SVignesh Raghavendra writel(reg | USB_CMD_FADDR(addr) | USB_CMD_SET_ADDR, 229f6ce6072SVignesh Raghavendra &priv_dev->regs->usb_cmd); 230f6ce6072SVignesh Raghavendra 231f6ce6072SVignesh Raghavendra usb_gadget_set_state(&priv_dev->gadget, 232f6ce6072SVignesh Raghavendra (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT)); 233f6ce6072SVignesh Raghavendra 234f6ce6072SVignesh Raghavendra return 0; 235f6ce6072SVignesh Raghavendra } 236f6ce6072SVignesh Raghavendra 237f6ce6072SVignesh Raghavendra /** 238f6ce6072SVignesh Raghavendra * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request 239f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 240f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 241f6ce6072SVignesh Raghavendra * 242f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 243f6ce6072SVignesh Raghavendra */ 244f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, 245f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl) 246f6ce6072SVignesh Raghavendra { 247f6ce6072SVignesh Raghavendra __le16 *response_pkt; 248f6ce6072SVignesh Raghavendra u16 usb_status = 0; 249f6ce6072SVignesh Raghavendra u32 recip; 250f6ce6072SVignesh Raghavendra 251f6ce6072SVignesh Raghavendra recip = ctrl->bRequestType & USB_RECIP_MASK; 252f6ce6072SVignesh Raghavendra 253f6ce6072SVignesh Raghavendra switch (recip) { 254f6ce6072SVignesh Raghavendra case USB_RECIP_DEVICE: 255f6ce6072SVignesh Raghavendra /* self powered */ 256f6ce6072SVignesh Raghavendra if (priv_dev->is_selfpowered) 257f6ce6072SVignesh Raghavendra usb_status = BIT(USB_DEVICE_SELF_POWERED); 258f6ce6072SVignesh Raghavendra 259f6ce6072SVignesh Raghavendra if (priv_dev->wake_up_flag) 260f6ce6072SVignesh Raghavendra usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP); 261f6ce6072SVignesh Raghavendra 262f6ce6072SVignesh Raghavendra if (priv_dev->gadget.speed != USB_SPEED_SUPER) 263f6ce6072SVignesh Raghavendra break; 264f6ce6072SVignesh Raghavendra 265f6ce6072SVignesh Raghavendra if (priv_dev->u1_allowed) 266f6ce6072SVignesh Raghavendra usb_status |= BIT(USB_DEV_STAT_U1_ENABLED); 267f6ce6072SVignesh Raghavendra 268f6ce6072SVignesh Raghavendra if (priv_dev->u2_allowed) 269f6ce6072SVignesh Raghavendra usb_status |= BIT(USB_DEV_STAT_U2_ENABLED); 270f6ce6072SVignesh Raghavendra 271f6ce6072SVignesh Raghavendra break; 272f6ce6072SVignesh Raghavendra case USB_RECIP_INTERFACE: 273f6ce6072SVignesh Raghavendra return cdns3_ep0_delegate_req(priv_dev, ctrl); 274f6ce6072SVignesh Raghavendra case USB_RECIP_ENDPOINT: 275f6ce6072SVignesh Raghavendra /* check if endpoint is stalled */ 276f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, ctrl->wIndex); 277f6ce6072SVignesh Raghavendra if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts))) 278f6ce6072SVignesh Raghavendra usb_status = BIT(USB_ENDPOINT_HALT); 279f6ce6072SVignesh Raghavendra break; 280f6ce6072SVignesh Raghavendra default: 281f6ce6072SVignesh Raghavendra return -EINVAL; 282f6ce6072SVignesh Raghavendra } 283f6ce6072SVignesh Raghavendra 284f6ce6072SVignesh Raghavendra response_pkt = (__le16 *)priv_dev->setup_buf; 285f6ce6072SVignesh Raghavendra *response_pkt = cpu_to_le16(usb_status); 286f6ce6072SVignesh Raghavendra 287f6ce6072SVignesh Raghavendra /* Flush setup response */ 288f6ce6072SVignesh Raghavendra flush_dcache_range((unsigned long)priv_dev->setup_buf, 289f6ce6072SVignesh Raghavendra (unsigned long)priv_dev->setup_buf + 290f6ce6072SVignesh Raghavendra ROUND(sizeof(struct usb_ctrlrequest), 291f6ce6072SVignesh Raghavendra CONFIG_SYS_CACHELINE_SIZE)); 292f6ce6072SVignesh Raghavendra 293f6ce6072SVignesh Raghavendra cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 294f6ce6072SVignesh Raghavendra sizeof(*response_pkt), 1, 0); 295f6ce6072SVignesh Raghavendra return 0; 296f6ce6072SVignesh Raghavendra } 297f6ce6072SVignesh Raghavendra 298f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev, 299f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl, 300f6ce6072SVignesh Raghavendra int set) 301f6ce6072SVignesh Raghavendra { 302f6ce6072SVignesh Raghavendra enum usb_device_state state; 303f6ce6072SVignesh Raghavendra enum usb_device_speed speed; 304f6ce6072SVignesh Raghavendra int ret = 0; 305f6ce6072SVignesh Raghavendra u16 tmode; 306f6ce6072SVignesh Raghavendra 307f6ce6072SVignesh Raghavendra state = priv_dev->gadget.state; 308f6ce6072SVignesh Raghavendra speed = priv_dev->gadget.speed; 309f6ce6072SVignesh Raghavendra 310f6ce6072SVignesh Raghavendra switch (ctrl->wValue) { 311f6ce6072SVignesh Raghavendra case USB_DEVICE_REMOTE_WAKEUP: 312f6ce6072SVignesh Raghavendra priv_dev->wake_up_flag = !!set; 313f6ce6072SVignesh Raghavendra break; 314f6ce6072SVignesh Raghavendra case USB_DEVICE_U1_ENABLE: 315f6ce6072SVignesh Raghavendra if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) 316f6ce6072SVignesh Raghavendra return -EINVAL; 317f6ce6072SVignesh Raghavendra 318f6ce6072SVignesh Raghavendra priv_dev->u1_allowed = !!set; 319f6ce6072SVignesh Raghavendra break; 320f6ce6072SVignesh Raghavendra case USB_DEVICE_U2_ENABLE: 321f6ce6072SVignesh Raghavendra if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) 322f6ce6072SVignesh Raghavendra return -EINVAL; 323f6ce6072SVignesh Raghavendra 324f6ce6072SVignesh Raghavendra priv_dev->u2_allowed = !!set; 325f6ce6072SVignesh Raghavendra break; 326f6ce6072SVignesh Raghavendra case USB_DEVICE_LTM_ENABLE: 327f6ce6072SVignesh Raghavendra ret = -EINVAL; 328f6ce6072SVignesh Raghavendra break; 329f6ce6072SVignesh Raghavendra case USB_DEVICE_TEST_MODE: 330f6ce6072SVignesh Raghavendra if (state != USB_STATE_CONFIGURED || speed > USB_SPEED_HIGH) 331f6ce6072SVignesh Raghavendra return -EINVAL; 332f6ce6072SVignesh Raghavendra 333f6ce6072SVignesh Raghavendra tmode = le16_to_cpu(ctrl->wIndex); 334f6ce6072SVignesh Raghavendra 335f6ce6072SVignesh Raghavendra if (!set || (tmode & 0xff) != 0) 336f6ce6072SVignesh Raghavendra return -EINVAL; 337f6ce6072SVignesh Raghavendra 338f6ce6072SVignesh Raghavendra switch (tmode >> 8) { 339f6ce6072SVignesh Raghavendra case TEST_J: 340f6ce6072SVignesh Raghavendra case TEST_K: 341f6ce6072SVignesh Raghavendra case TEST_SE0_NAK: 342f6ce6072SVignesh Raghavendra case TEST_PACKET: 343f6ce6072SVignesh Raghavendra cdns3_ep0_complete_setup(priv_dev, 0, 1); 344f6ce6072SVignesh Raghavendra /** 345f6ce6072SVignesh Raghavendra * Little delay to give the controller some time 346f6ce6072SVignesh Raghavendra * for sending status stage. 347f6ce6072SVignesh Raghavendra * This time should be less then 3ms. 348f6ce6072SVignesh Raghavendra */ 349f6ce6072SVignesh Raghavendra usleep_range(1000, 2000); 350f6ce6072SVignesh Raghavendra cdns3_set_register_bit(&priv_dev->regs->usb_cmd, 351f6ce6072SVignesh Raghavendra USB_CMD_STMODE | 352f6ce6072SVignesh Raghavendra USB_STS_TMODE_SEL(tmode - 1)); 353f6ce6072SVignesh Raghavendra break; 354f6ce6072SVignesh Raghavendra default: 355f6ce6072SVignesh Raghavendra ret = -EINVAL; 356f6ce6072SVignesh Raghavendra } 357f6ce6072SVignesh Raghavendra break; 358f6ce6072SVignesh Raghavendra default: 359f6ce6072SVignesh Raghavendra ret = -EINVAL; 360f6ce6072SVignesh Raghavendra } 361f6ce6072SVignesh Raghavendra 362f6ce6072SVignesh Raghavendra return ret; 363f6ce6072SVignesh Raghavendra } 364f6ce6072SVignesh Raghavendra 365f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_intf(struct cdns3_device *priv_dev, 366f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl, 367f6ce6072SVignesh Raghavendra int set) 368f6ce6072SVignesh Raghavendra { 369f6ce6072SVignesh Raghavendra u32 wValue; 370f6ce6072SVignesh Raghavendra int ret = 0; 371f6ce6072SVignesh Raghavendra 372f6ce6072SVignesh Raghavendra wValue = le16_to_cpu(ctrl->wValue); 373f6ce6072SVignesh Raghavendra 374f6ce6072SVignesh Raghavendra switch (wValue) { 375f6ce6072SVignesh Raghavendra case USB_INTRF_FUNC_SUSPEND: 376f6ce6072SVignesh Raghavendra break; 377f6ce6072SVignesh Raghavendra default: 378f6ce6072SVignesh Raghavendra ret = -EINVAL; 379f6ce6072SVignesh Raghavendra } 380f6ce6072SVignesh Raghavendra 381f6ce6072SVignesh Raghavendra return ret; 382f6ce6072SVignesh Raghavendra } 383f6ce6072SVignesh Raghavendra 384f6ce6072SVignesh Raghavendra static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev, 385f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl, 386f6ce6072SVignesh Raghavendra int set) 387f6ce6072SVignesh Raghavendra { 388f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep; 389f6ce6072SVignesh Raghavendra int ret = 0; 390f6ce6072SVignesh Raghavendra u8 index; 391f6ce6072SVignesh Raghavendra 392f6ce6072SVignesh Raghavendra if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT) 393f6ce6072SVignesh Raghavendra return -EINVAL; 394f6ce6072SVignesh Raghavendra 395f6ce6072SVignesh Raghavendra if (!(ctrl->wIndex & ~USB_DIR_IN)) 396f6ce6072SVignesh Raghavendra return 0; 397f6ce6072SVignesh Raghavendra 398f6ce6072SVignesh Raghavendra index = cdns3_ep_addr_to_index(ctrl->wIndex); 399f6ce6072SVignesh Raghavendra priv_ep = priv_dev->eps[index]; 400f6ce6072SVignesh Raghavendra 401f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, ctrl->wIndex); 402f6ce6072SVignesh Raghavendra 403f6ce6072SVignesh Raghavendra if (set) 404f6ce6072SVignesh Raghavendra __cdns3_gadget_ep_set_halt(priv_ep); 405f6ce6072SVignesh Raghavendra else if (!(priv_ep->flags & EP_WEDGE)) 406f6ce6072SVignesh Raghavendra ret = __cdns3_gadget_ep_clear_halt(priv_ep); 407f6ce6072SVignesh Raghavendra 408f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, 0x00); 409f6ce6072SVignesh Raghavendra 410f6ce6072SVignesh Raghavendra return ret; 411f6ce6072SVignesh Raghavendra } 412f6ce6072SVignesh Raghavendra 413f6ce6072SVignesh Raghavendra /** 414f6ce6072SVignesh Raghavendra * cdns3_req_ep0_handle_feature - 415f6ce6072SVignesh Raghavendra * Handling of GET/SET_FEATURE standard USB request 416f6ce6072SVignesh Raghavendra * 417f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 418f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 419f6ce6072SVignesh Raghavendra * @set: must be set to 1 for SET_FEATURE request 420f6ce6072SVignesh Raghavendra * 421f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 422f6ce6072SVignesh Raghavendra */ 423f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev, 424f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl, 425f6ce6072SVignesh Raghavendra int set) 426f6ce6072SVignesh Raghavendra { 427f6ce6072SVignesh Raghavendra int ret = 0; 428f6ce6072SVignesh Raghavendra u32 recip; 429f6ce6072SVignesh Raghavendra 430f6ce6072SVignesh Raghavendra recip = ctrl->bRequestType & USB_RECIP_MASK; 431f6ce6072SVignesh Raghavendra 432f6ce6072SVignesh Raghavendra switch (recip) { 433f6ce6072SVignesh Raghavendra case USB_RECIP_DEVICE: 434f6ce6072SVignesh Raghavendra ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set); 435f6ce6072SVignesh Raghavendra break; 436f6ce6072SVignesh Raghavendra case USB_RECIP_INTERFACE: 437f6ce6072SVignesh Raghavendra ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set); 438f6ce6072SVignesh Raghavendra break; 439f6ce6072SVignesh Raghavendra case USB_RECIP_ENDPOINT: 440f6ce6072SVignesh Raghavendra ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set); 441f6ce6072SVignesh Raghavendra break; 442f6ce6072SVignesh Raghavendra default: 443f6ce6072SVignesh Raghavendra return -EINVAL; 444f6ce6072SVignesh Raghavendra } 445f6ce6072SVignesh Raghavendra 446f6ce6072SVignesh Raghavendra return ret; 447f6ce6072SVignesh Raghavendra } 448f6ce6072SVignesh Raghavendra 449f6ce6072SVignesh Raghavendra /** 450f6ce6072SVignesh Raghavendra * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request 451f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 452f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 453f6ce6072SVignesh Raghavendra * 454f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 455f6ce6072SVignesh Raghavendra */ 456f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev, 457f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 458f6ce6072SVignesh Raghavendra { 459f6ce6072SVignesh Raghavendra if (priv_dev->gadget.state < USB_STATE_ADDRESS) 460f6ce6072SVignesh Raghavendra return -EINVAL; 461f6ce6072SVignesh Raghavendra 462f6ce6072SVignesh Raghavendra if (ctrl_req->wLength != 6) { 463f6ce6072SVignesh Raghavendra dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n", 464f6ce6072SVignesh Raghavendra ctrl_req->wLength); 465f6ce6072SVignesh Raghavendra return -EINVAL; 466f6ce6072SVignesh Raghavendra } 467f6ce6072SVignesh Raghavendra 468f6ce6072SVignesh Raghavendra cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 6, 1, 0); 469f6ce6072SVignesh Raghavendra return 0; 470f6ce6072SVignesh Raghavendra } 471f6ce6072SVignesh Raghavendra 472f6ce6072SVignesh Raghavendra /** 473f6ce6072SVignesh Raghavendra * cdns3_req_ep0_set_isoch_delay - 474f6ce6072SVignesh Raghavendra * Handling of GET_ISOCH_DELAY standard USB request 475f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 476f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 477f6ce6072SVignesh Raghavendra * 478f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 479f6ce6072SVignesh Raghavendra */ 480f6ce6072SVignesh Raghavendra static int cdns3_req_ep0_set_isoch_delay(struct cdns3_device *priv_dev, 481f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 482f6ce6072SVignesh Raghavendra { 483f6ce6072SVignesh Raghavendra if (ctrl_req->wIndex || ctrl_req->wLength) 484f6ce6072SVignesh Raghavendra return -EINVAL; 485f6ce6072SVignesh Raghavendra 486f6ce6072SVignesh Raghavendra priv_dev->isoch_delay = ctrl_req->wValue; 487f6ce6072SVignesh Raghavendra 488f6ce6072SVignesh Raghavendra return 0; 489f6ce6072SVignesh Raghavendra } 490f6ce6072SVignesh Raghavendra 491f6ce6072SVignesh Raghavendra /** 492f6ce6072SVignesh Raghavendra * cdns3_ep0_standard_request - Handling standard USB requests 493f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 494f6ce6072SVignesh Raghavendra * @ctrl_req: pointer to received setup packet 495f6ce6072SVignesh Raghavendra * 496f6ce6072SVignesh Raghavendra * Returns 0 if success, error code on error 497f6ce6072SVignesh Raghavendra */ 498f6ce6072SVignesh Raghavendra static int cdns3_ep0_standard_request(struct cdns3_device *priv_dev, 499f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl_req) 500f6ce6072SVignesh Raghavendra { 501f6ce6072SVignesh Raghavendra int ret; 502f6ce6072SVignesh Raghavendra 503f6ce6072SVignesh Raghavendra switch (ctrl_req->bRequest) { 504f6ce6072SVignesh Raghavendra case USB_REQ_SET_ADDRESS: 505f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req); 506f6ce6072SVignesh Raghavendra break; 507f6ce6072SVignesh Raghavendra case USB_REQ_SET_CONFIGURATION: 508f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req); 509f6ce6072SVignesh Raghavendra break; 510f6ce6072SVignesh Raghavendra case USB_REQ_GET_STATUS: 511f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req); 512f6ce6072SVignesh Raghavendra break; 513f6ce6072SVignesh Raghavendra case USB_REQ_CLEAR_FEATURE: 514f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0); 515f6ce6072SVignesh Raghavendra break; 516f6ce6072SVignesh Raghavendra case USB_REQ_SET_FEATURE: 517f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1); 518f6ce6072SVignesh Raghavendra break; 519f6ce6072SVignesh Raghavendra case USB_REQ_SET_SEL: 520f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req); 521f6ce6072SVignesh Raghavendra break; 522f6ce6072SVignesh Raghavendra case USB_REQ_SET_ISOCH_DELAY: 523f6ce6072SVignesh Raghavendra ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req); 524f6ce6072SVignesh Raghavendra break; 525f6ce6072SVignesh Raghavendra default: 526f6ce6072SVignesh Raghavendra ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req); 527f6ce6072SVignesh Raghavendra break; 528f6ce6072SVignesh Raghavendra } 529f6ce6072SVignesh Raghavendra 530f6ce6072SVignesh Raghavendra return ret; 531f6ce6072SVignesh Raghavendra } 532f6ce6072SVignesh Raghavendra 533f6ce6072SVignesh Raghavendra static void __pending_setup_status_handler(struct cdns3_device *priv_dev) 534f6ce6072SVignesh Raghavendra { 535f6ce6072SVignesh Raghavendra struct usb_request *request = priv_dev->pending_status_request; 536f6ce6072SVignesh Raghavendra 537f6ce6072SVignesh Raghavendra if (priv_dev->status_completion_no_call && request && 538f6ce6072SVignesh Raghavendra request->complete) { 539f6ce6072SVignesh Raghavendra request->complete(&priv_dev->eps[0]->endpoint, request); 540f6ce6072SVignesh Raghavendra priv_dev->status_completion_no_call = 0; 541f6ce6072SVignesh Raghavendra } 542f6ce6072SVignesh Raghavendra } 543f6ce6072SVignesh Raghavendra 544f6ce6072SVignesh Raghavendra void cdns3_pending_setup_status_handler(struct work_struct *work) 545f6ce6072SVignesh Raghavendra { 546f6ce6072SVignesh Raghavendra struct cdns3_device *priv_dev = container_of(work, struct cdns3_device, 547f6ce6072SVignesh Raghavendra pending_status_wq); 548f6ce6072SVignesh Raghavendra unsigned long flags; 549f6ce6072SVignesh Raghavendra 550f6ce6072SVignesh Raghavendra spin_lock_irqsave(&priv_dev->lock, flags); 551f6ce6072SVignesh Raghavendra __pending_setup_status_handler(priv_dev); 552f6ce6072SVignesh Raghavendra spin_unlock_irqrestore(&priv_dev->lock, flags); 553f6ce6072SVignesh Raghavendra } 554f6ce6072SVignesh Raghavendra 555f6ce6072SVignesh Raghavendra /** 556f6ce6072SVignesh Raghavendra * cdns3_ep0_setup_phase - Handling setup USB requests 557f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 558f6ce6072SVignesh Raghavendra */ 559f6ce6072SVignesh Raghavendra static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) 560f6ce6072SVignesh Raghavendra { 561f6ce6072SVignesh Raghavendra struct usb_ctrlrequest *ctrl = priv_dev->setup_buf; 562f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = priv_dev->eps[0]; 563f6ce6072SVignesh Raghavendra int result; 564f6ce6072SVignesh Raghavendra 565f6ce6072SVignesh Raghavendra priv_dev->ep0_data_dir = ctrl->bRequestType & USB_DIR_IN; 566f6ce6072SVignesh Raghavendra 567f6ce6072SVignesh Raghavendra trace_cdns3_ctrl_req(ctrl); 568f6ce6072SVignesh Raghavendra 569f6ce6072SVignesh Raghavendra if (!list_empty(&priv_ep->pending_req_list)) { 570f6ce6072SVignesh Raghavendra struct usb_request *request; 571f6ce6072SVignesh Raghavendra 572f6ce6072SVignesh Raghavendra request = cdns3_next_request(&priv_ep->pending_req_list); 573f6ce6072SVignesh Raghavendra priv_ep->dir = priv_dev->ep0_data_dir; 574f6ce6072SVignesh Raghavendra cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), 575f6ce6072SVignesh Raghavendra -ECONNRESET); 576f6ce6072SVignesh Raghavendra } 577f6ce6072SVignesh Raghavendra 578f6ce6072SVignesh Raghavendra if (le16_to_cpu(ctrl->wLength)) 579f6ce6072SVignesh Raghavendra priv_dev->ep0_stage = CDNS3_DATA_STAGE; 580f6ce6072SVignesh Raghavendra else 581f6ce6072SVignesh Raghavendra priv_dev->ep0_stage = CDNS3_STATUS_STAGE; 582f6ce6072SVignesh Raghavendra 583f6ce6072SVignesh Raghavendra if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 584f6ce6072SVignesh Raghavendra result = cdns3_ep0_standard_request(priv_dev, ctrl); 585f6ce6072SVignesh Raghavendra else 586f6ce6072SVignesh Raghavendra result = cdns3_ep0_delegate_req(priv_dev, ctrl); 587f6ce6072SVignesh Raghavendra 588f6ce6072SVignesh Raghavendra if (result == USB_GADGET_DELAYED_STATUS) 589f6ce6072SVignesh Raghavendra return; 590f6ce6072SVignesh Raghavendra 591f6ce6072SVignesh Raghavendra if (result < 0) 592f6ce6072SVignesh Raghavendra cdns3_ep0_complete_setup(priv_dev, 1, 1); 593f6ce6072SVignesh Raghavendra else if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) 594f6ce6072SVignesh Raghavendra cdns3_ep0_complete_setup(priv_dev, 0, 1); 595f6ce6072SVignesh Raghavendra } 596f6ce6072SVignesh Raghavendra 597f6ce6072SVignesh Raghavendra static void cdns3_transfer_completed(struct cdns3_device *priv_dev) 598f6ce6072SVignesh Raghavendra { 599f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = priv_dev->eps[0]; 600f6ce6072SVignesh Raghavendra 601f6ce6072SVignesh Raghavendra if (!list_empty(&priv_ep->pending_req_list)) { 602f6ce6072SVignesh Raghavendra struct usb_request *request; 603f6ce6072SVignesh Raghavendra 604f6ce6072SVignesh Raghavendra trace_cdns3_complete_trb(priv_ep, priv_ep->trb_pool); 605f6ce6072SVignesh Raghavendra request = cdns3_next_request(&priv_ep->pending_req_list); 606f6ce6072SVignesh Raghavendra 607f6ce6072SVignesh Raghavendra /* Invalidate TRB before accessing it */ 608f6ce6072SVignesh Raghavendra invalidate_dcache_range((unsigned long)priv_ep->trb_pool, 609f6ce6072SVignesh Raghavendra (unsigned long)priv_ep->trb_pool + 610f6ce6072SVignesh Raghavendra ROUND(sizeof(struct cdns3_trb), 611f6ce6072SVignesh Raghavendra CONFIG_SYS_CACHELINE_SIZE)); 612f6ce6072SVignesh Raghavendra 613f6ce6072SVignesh Raghavendra request->actual = 614f6ce6072SVignesh Raghavendra TRB_LEN(le32_to_cpu(priv_ep->trb_pool->length)); 615f6ce6072SVignesh Raghavendra 616f6ce6072SVignesh Raghavendra priv_ep->dir = priv_dev->ep0_data_dir; 617f6ce6072SVignesh Raghavendra cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), 0); 618f6ce6072SVignesh Raghavendra } 619f6ce6072SVignesh Raghavendra 620f6ce6072SVignesh Raghavendra cdns3_ep0_complete_setup(priv_dev, 0, 0); 621f6ce6072SVignesh Raghavendra } 622f6ce6072SVignesh Raghavendra 623f6ce6072SVignesh Raghavendra /** 624f6ce6072SVignesh Raghavendra * cdns3_check_new_setup - Check if controller receive new SETUP packet. 625f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 626f6ce6072SVignesh Raghavendra * 627f6ce6072SVignesh Raghavendra * The SETUP packet can be kept in on-chip memory or in system memory. 628f6ce6072SVignesh Raghavendra */ 629f6ce6072SVignesh Raghavendra static bool cdns3_check_new_setup(struct cdns3_device *priv_dev) 630f6ce6072SVignesh Raghavendra { 631f6ce6072SVignesh Raghavendra u32 ep_sts_reg; 632f6ce6072SVignesh Raghavendra 633f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT); 634f6ce6072SVignesh Raghavendra ep_sts_reg = readl(&priv_dev->regs->ep_sts); 635f6ce6072SVignesh Raghavendra 636f6ce6072SVignesh Raghavendra return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT)); 637f6ce6072SVignesh Raghavendra } 638f6ce6072SVignesh Raghavendra 639f6ce6072SVignesh Raghavendra /** 640f6ce6072SVignesh Raghavendra * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 641f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 642f6ce6072SVignesh Raghavendra * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction 643f6ce6072SVignesh Raghavendra */ 644f6ce6072SVignesh Raghavendra void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) 645f6ce6072SVignesh Raghavendra { 646f6ce6072SVignesh Raghavendra u32 ep_sts_reg; 647f6ce6072SVignesh Raghavendra 648f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, dir); 649f6ce6072SVignesh Raghavendra 650f6ce6072SVignesh Raghavendra ep_sts_reg = readl(&priv_dev->regs->ep_sts); 651f6ce6072SVignesh Raghavendra writel(ep_sts_reg, &priv_dev->regs->ep_sts); 652f6ce6072SVignesh Raghavendra 653f6ce6072SVignesh Raghavendra trace_cdns3_ep0_irq(priv_dev, ep_sts_reg); 654f6ce6072SVignesh Raghavendra 655f6ce6072SVignesh Raghavendra __pending_setup_status_handler(priv_dev); 656f6ce6072SVignesh Raghavendra 657f6ce6072SVignesh Raghavendra if (ep_sts_reg & EP_STS_SETUP) 658f6ce6072SVignesh Raghavendra priv_dev->wait_for_setup = 1; 659f6ce6072SVignesh Raghavendra 660f6ce6072SVignesh Raghavendra if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) { 661f6ce6072SVignesh Raghavendra priv_dev->wait_for_setup = 0; 662f6ce6072SVignesh Raghavendra cdns3_allow_enable_l1(priv_dev, 0); 663f6ce6072SVignesh Raghavendra cdns3_ep0_setup_phase(priv_dev); 664f6ce6072SVignesh Raghavendra } else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { 665f6ce6072SVignesh Raghavendra priv_dev->ep0_data_dir = dir; 666f6ce6072SVignesh Raghavendra cdns3_transfer_completed(priv_dev); 667f6ce6072SVignesh Raghavendra } 668f6ce6072SVignesh Raghavendra 669f6ce6072SVignesh Raghavendra if (ep_sts_reg & EP_STS_DESCMIS) { 670f6ce6072SVignesh Raghavendra if (dir == 0 && !priv_dev->setup_pending) 671f6ce6072SVignesh Raghavendra cdns3_prepare_setup_packet(priv_dev); 672f6ce6072SVignesh Raghavendra } 673f6ce6072SVignesh Raghavendra } 674f6ce6072SVignesh Raghavendra 675f6ce6072SVignesh Raghavendra /** 676f6ce6072SVignesh Raghavendra * cdns3_gadget_ep0_enable 677f6ce6072SVignesh Raghavendra * Function shouldn't be called by gadget driver, 678f6ce6072SVignesh Raghavendra * endpoint 0 is allways active 679f6ce6072SVignesh Raghavendra */ 680f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_enable(struct usb_ep *ep, 681f6ce6072SVignesh Raghavendra const struct usb_endpoint_descriptor *desc) 682f6ce6072SVignesh Raghavendra { 683f6ce6072SVignesh Raghavendra return -EINVAL; 684f6ce6072SVignesh Raghavendra } 685f6ce6072SVignesh Raghavendra 686f6ce6072SVignesh Raghavendra /** 687f6ce6072SVignesh Raghavendra * cdns3_gadget_ep0_disable 688f6ce6072SVignesh Raghavendra * Function shouldn't be called by gadget driver, 689f6ce6072SVignesh Raghavendra * endpoint 0 is allways active 690f6ce6072SVignesh Raghavendra */ 691f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_disable(struct usb_ep *ep) 692f6ce6072SVignesh Raghavendra { 693f6ce6072SVignesh Raghavendra return -EINVAL; 694f6ce6072SVignesh Raghavendra } 695f6ce6072SVignesh Raghavendra 696f6ce6072SVignesh Raghavendra /** 697f6ce6072SVignesh Raghavendra * cdns3_gadget_ep0_set_halt 698f6ce6072SVignesh Raghavendra * @ep: pointer to endpoint zero object 699f6ce6072SVignesh Raghavendra * @value: 1 for set stall, 0 for clear stall 700f6ce6072SVignesh Raghavendra * 701f6ce6072SVignesh Raghavendra * Returns 0 702f6ce6072SVignesh Raghavendra */ 703f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) 704f6ce6072SVignesh Raghavendra { 705f6ce6072SVignesh Raghavendra /* TODO */ 706f6ce6072SVignesh Raghavendra return 0; 707f6ce6072SVignesh Raghavendra } 708f6ce6072SVignesh Raghavendra 709f6ce6072SVignesh Raghavendra /** 710f6ce6072SVignesh Raghavendra * cdns3_gadget_ep0_queue Transfer data on endpoint zero 711f6ce6072SVignesh Raghavendra * @ep: pointer to endpoint zero object 712f6ce6072SVignesh Raghavendra * @request: pointer to request object 713f6ce6072SVignesh Raghavendra * @gfp_flags: gfp flags 714f6ce6072SVignesh Raghavendra * 715f6ce6072SVignesh Raghavendra * Returns 0 on success, error code elsewhere 716f6ce6072SVignesh Raghavendra */ 717f6ce6072SVignesh Raghavendra static int cdns3_gadget_ep0_queue(struct usb_ep *ep, 718f6ce6072SVignesh Raghavendra struct usb_request *request, 719f6ce6072SVignesh Raghavendra gfp_t gfp_flags) 720f6ce6072SVignesh Raghavendra { 721f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); 722f6ce6072SVignesh Raghavendra struct cdns3_device *priv_dev = priv_ep->cdns3_dev; 723f6ce6072SVignesh Raghavendra unsigned long flags; 724f6ce6072SVignesh Raghavendra int erdy_sent = 0; 725f6ce6072SVignesh Raghavendra int ret = 0; 726f6ce6072SVignesh Raghavendra u8 zlp = 0; 727f6ce6072SVignesh Raghavendra 728f6ce6072SVignesh Raghavendra trace_cdns3_ep0_queue(priv_dev, request); 729f6ce6072SVignesh Raghavendra 730f6ce6072SVignesh Raghavendra /* cancel the request if controller receive new SETUP packet. */ 731f6ce6072SVignesh Raghavendra if (cdns3_check_new_setup(priv_dev)) 732f6ce6072SVignesh Raghavendra return -ECONNRESET; 733f6ce6072SVignesh Raghavendra 734f6ce6072SVignesh Raghavendra /* send STATUS stage. Should be called only for SET_CONFIGURATION */ 735f6ce6072SVignesh Raghavendra if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) { 736f6ce6072SVignesh Raghavendra spin_lock_irqsave(&priv_dev->lock, flags); 737f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, 0x00); 738f6ce6072SVignesh Raghavendra 739f6ce6072SVignesh Raghavendra erdy_sent = !priv_dev->hw_configured_flag; 740f6ce6072SVignesh Raghavendra cdns3_set_hw_configuration(priv_dev); 741f6ce6072SVignesh Raghavendra 742f6ce6072SVignesh Raghavendra if (!erdy_sent) 743f6ce6072SVignesh Raghavendra cdns3_ep0_complete_setup(priv_dev, 0, 1); 744f6ce6072SVignesh Raghavendra 745f6ce6072SVignesh Raghavendra cdns3_allow_enable_l1(priv_dev, 1); 746f6ce6072SVignesh Raghavendra 747f6ce6072SVignesh Raghavendra request->actual = 0; 748f6ce6072SVignesh Raghavendra priv_dev->status_completion_no_call = true; 749f6ce6072SVignesh Raghavendra priv_dev->pending_status_request = request; 750f6ce6072SVignesh Raghavendra spin_unlock_irqrestore(&priv_dev->lock, flags); 751f6ce6072SVignesh Raghavendra 752f6ce6072SVignesh Raghavendra /* 753f6ce6072SVignesh Raghavendra * Since there is no completion interrupt for status stage, 754f6ce6072SVignesh Raghavendra * it needs to call ->completion in software after 755f6ce6072SVignesh Raghavendra * ep0_queue is back. 756f6ce6072SVignesh Raghavendra */ 757f6ce6072SVignesh Raghavendra #ifndef __UBOOT__ 758f6ce6072SVignesh Raghavendra queue_work(system_freezable_wq, &priv_dev->pending_status_wq); 759f6ce6072SVignesh Raghavendra #else 760f6ce6072SVignesh Raghavendra __pending_setup_status_handler(priv_dev); 761f6ce6072SVignesh Raghavendra #endif 762f6ce6072SVignesh Raghavendra return 0; 763f6ce6072SVignesh Raghavendra } 764f6ce6072SVignesh Raghavendra 765f6ce6072SVignesh Raghavendra spin_lock_irqsave(&priv_dev->lock, flags); 766f6ce6072SVignesh Raghavendra if (!list_empty(&priv_ep->pending_req_list)) { 767f6ce6072SVignesh Raghavendra dev_err(priv_dev->dev, 768f6ce6072SVignesh Raghavendra "can't handle multiple requests for ep0\n"); 769f6ce6072SVignesh Raghavendra spin_unlock_irqrestore(&priv_dev->lock, flags); 770f6ce6072SVignesh Raghavendra return -EBUSY; 771f6ce6072SVignesh Raghavendra } 772f6ce6072SVignesh Raghavendra 773f6ce6072SVignesh Raghavendra ret = usb_gadget_map_request(&priv_dev->gadget, request, 774f6ce6072SVignesh Raghavendra priv_dev->ep0_data_dir); 775f6ce6072SVignesh Raghavendra if (ret) { 776f6ce6072SVignesh Raghavendra spin_unlock_irqrestore(&priv_dev->lock, flags); 777f6ce6072SVignesh Raghavendra dev_err(priv_dev->dev, "failed to map request\n"); 778f6ce6072SVignesh Raghavendra return -EINVAL; 779f6ce6072SVignesh Raghavendra } 780f6ce6072SVignesh Raghavendra 781f6ce6072SVignesh Raghavendra request->status = -EINPROGRESS; 782f6ce6072SVignesh Raghavendra list_add_tail(&request->list, &priv_ep->pending_req_list); 783f6ce6072SVignesh Raghavendra 784f6ce6072SVignesh Raghavendra if (request->zero && request->length && 785f6ce6072SVignesh Raghavendra (request->length % ep->maxpacket == 0)) 786f6ce6072SVignesh Raghavendra zlp = 1; 787f6ce6072SVignesh Raghavendra 788f6ce6072SVignesh Raghavendra cdns3_ep0_run_transfer(priv_dev, request->dma, request->length, 1, zlp); 789f6ce6072SVignesh Raghavendra 790f6ce6072SVignesh Raghavendra spin_unlock_irqrestore(&priv_dev->lock, flags); 791f6ce6072SVignesh Raghavendra 792f6ce6072SVignesh Raghavendra return ret; 793f6ce6072SVignesh Raghavendra } 794f6ce6072SVignesh Raghavendra 795f6ce6072SVignesh Raghavendra /** 796f6ce6072SVignesh Raghavendra * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint 797f6ce6072SVignesh Raghavendra * @ep: endpoint object 798f6ce6072SVignesh Raghavendra * 799f6ce6072SVignesh Raghavendra * Returns 0 800f6ce6072SVignesh Raghavendra */ 801f6ce6072SVignesh Raghavendra int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) 802f6ce6072SVignesh Raghavendra { 803f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); 804f6ce6072SVignesh Raghavendra 805f6ce6072SVignesh Raghavendra dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name); 806f6ce6072SVignesh Raghavendra cdns3_gadget_ep_set_halt(ep, 1); 807f6ce6072SVignesh Raghavendra priv_ep->flags |= EP_WEDGE; 808f6ce6072SVignesh Raghavendra 809f6ce6072SVignesh Raghavendra return 0; 810f6ce6072SVignesh Raghavendra } 811f6ce6072SVignesh Raghavendra 812f6ce6072SVignesh Raghavendra const struct usb_ep_ops cdns3_gadget_ep0_ops = { 813f6ce6072SVignesh Raghavendra .enable = cdns3_gadget_ep0_enable, 814f6ce6072SVignesh Raghavendra .disable = cdns3_gadget_ep0_disable, 815f6ce6072SVignesh Raghavendra .alloc_request = cdns3_gadget_ep_alloc_request, 816f6ce6072SVignesh Raghavendra .free_request = cdns3_gadget_ep_free_request, 817f6ce6072SVignesh Raghavendra .queue = cdns3_gadget_ep0_queue, 818f6ce6072SVignesh Raghavendra .dequeue = cdns3_gadget_ep_dequeue, 819f6ce6072SVignesh Raghavendra .set_halt = cdns3_gadget_ep0_set_halt, 820f6ce6072SVignesh Raghavendra .set_wedge = cdns3_gadget_ep_set_wedge, 821f6ce6072SVignesh Raghavendra }; 822f6ce6072SVignesh Raghavendra 823f6ce6072SVignesh Raghavendra /** 824f6ce6072SVignesh Raghavendra * cdns3_ep0_config - Configures default endpoint 825f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 826f6ce6072SVignesh Raghavendra * 827f6ce6072SVignesh Raghavendra * Functions sets parameters: maximal packet size and enables interrupts 828f6ce6072SVignesh Raghavendra */ 829f6ce6072SVignesh Raghavendra void cdns3_ep0_config(struct cdns3_device *priv_dev) 830f6ce6072SVignesh Raghavendra { 831f6ce6072SVignesh Raghavendra struct cdns3_usb_regs __iomem *regs; 832f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep; 833f6ce6072SVignesh Raghavendra u32 max_packet_size = 64; 834f6ce6072SVignesh Raghavendra 835f6ce6072SVignesh Raghavendra regs = priv_dev->regs; 836f6ce6072SVignesh Raghavendra 837f6ce6072SVignesh Raghavendra if (priv_dev->gadget.speed == USB_SPEED_SUPER) 838f6ce6072SVignesh Raghavendra max_packet_size = 512; 839f6ce6072SVignesh Raghavendra 840f6ce6072SVignesh Raghavendra priv_ep = priv_dev->eps[0]; 841f6ce6072SVignesh Raghavendra 842f6ce6072SVignesh Raghavendra if (!list_empty(&priv_ep->pending_req_list)) { 843f6ce6072SVignesh Raghavendra struct usb_request *request; 844f6ce6072SVignesh Raghavendra 845f6ce6072SVignesh Raghavendra request = cdns3_next_request(&priv_ep->pending_req_list); 846f6ce6072SVignesh Raghavendra list_del_init(&request->list); 847f6ce6072SVignesh Raghavendra } 848f6ce6072SVignesh Raghavendra 849f6ce6072SVignesh Raghavendra priv_dev->u1_allowed = 0; 850f6ce6072SVignesh Raghavendra priv_dev->u2_allowed = 0; 851f6ce6072SVignesh Raghavendra 852f6ce6072SVignesh Raghavendra priv_dev->gadget.ep0->maxpacket = max_packet_size; 853f6ce6072SVignesh Raghavendra cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); 854f6ce6072SVignesh Raghavendra 855f6ce6072SVignesh Raghavendra /* init ep out */ 856f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, USB_DIR_OUT); 857f6ce6072SVignesh Raghavendra 858f6ce6072SVignesh Raghavendra if (priv_dev->dev_ver >= DEV_VER_V3) { 859f6ce6072SVignesh Raghavendra cdns3_set_register_bit(&priv_dev->regs->dtrans, 860f6ce6072SVignesh Raghavendra BIT(0) | BIT(16)); 861f6ce6072SVignesh Raghavendra cdns3_set_register_bit(&priv_dev->regs->tdl_from_trb, 862f6ce6072SVignesh Raghavendra BIT(0) | BIT(16)); 863f6ce6072SVignesh Raghavendra } 864f6ce6072SVignesh Raghavendra 865f6ce6072SVignesh Raghavendra writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), 866f6ce6072SVignesh Raghavendra ®s->ep_cfg); 867f6ce6072SVignesh Raghavendra 868f6ce6072SVignesh Raghavendra writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, 869f6ce6072SVignesh Raghavendra ®s->ep_sts_en); 870f6ce6072SVignesh Raghavendra 871f6ce6072SVignesh Raghavendra /* init ep in */ 872f6ce6072SVignesh Raghavendra cdns3_select_ep(priv_dev, USB_DIR_IN); 873f6ce6072SVignesh Raghavendra 874f6ce6072SVignesh Raghavendra writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), 875f6ce6072SVignesh Raghavendra ®s->ep_cfg); 876f6ce6072SVignesh Raghavendra 877f6ce6072SVignesh Raghavendra writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); 878f6ce6072SVignesh Raghavendra 879f6ce6072SVignesh Raghavendra cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); 880f6ce6072SVignesh Raghavendra } 881f6ce6072SVignesh Raghavendra 882f6ce6072SVignesh Raghavendra /** 883f6ce6072SVignesh Raghavendra * cdns3_init_ep0 Initializes software endpoint 0 of gadget 884f6ce6072SVignesh Raghavendra * @priv_dev: extended gadget object 885f6ce6072SVignesh Raghavendra * @ep_priv: extended endpoint object 886f6ce6072SVignesh Raghavendra * 887f6ce6072SVignesh Raghavendra * Returns 0 on success else error code. 888f6ce6072SVignesh Raghavendra */ 889f6ce6072SVignesh Raghavendra int cdns3_init_ep0(struct cdns3_device *priv_dev, 890f6ce6072SVignesh Raghavendra struct cdns3_endpoint *priv_ep) 891f6ce6072SVignesh Raghavendra { 892f6ce6072SVignesh Raghavendra sprintf(priv_ep->name, "ep0"); 893f6ce6072SVignesh Raghavendra 894f6ce6072SVignesh Raghavendra /* fill linux fields */ 895f6ce6072SVignesh Raghavendra priv_ep->endpoint.ops = &cdns3_gadget_ep0_ops; 896f6ce6072SVignesh Raghavendra priv_ep->endpoint.maxburst = 1; 897f6ce6072SVignesh Raghavendra usb_ep_set_maxpacket_limit(&priv_ep->endpoint, 898f6ce6072SVignesh Raghavendra CDNS3_EP0_MAX_PACKET_LIMIT); 899f6ce6072SVignesh Raghavendra #ifndef __UBOOT__ 900f6ce6072SVignesh Raghavendra priv_ep->endpoint.address = 0; 901f6ce6072SVignesh Raghavendra #endif 902f6ce6072SVignesh Raghavendra priv_ep->endpoint.caps.type_control = 1; 903f6ce6072SVignesh Raghavendra priv_ep->endpoint.caps.dir_in = 1; 904f6ce6072SVignesh Raghavendra priv_ep->endpoint.caps.dir_out = 1; 905f6ce6072SVignesh Raghavendra priv_ep->endpoint.name = priv_ep->name; 906f6ce6072SVignesh Raghavendra priv_ep->endpoint.desc = &cdns3_gadget_ep0_desc; 907f6ce6072SVignesh Raghavendra priv_dev->gadget.ep0 = &priv_ep->endpoint; 908f6ce6072SVignesh Raghavendra priv_ep->type = USB_ENDPOINT_XFER_CONTROL; 909f6ce6072SVignesh Raghavendra 910f6ce6072SVignesh Raghavendra return cdns3_allocate_trb_pool(priv_ep); 911f6ce6072SVignesh Raghavendra } 912