Loading Documentation/devicetree/bindings/usb/dwc3.txt +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ Optional properties: during bus suspend. - snps,usb3-u1u2-disable: If present, disable U1U2 low power modes in Superspeed mode - snps,usb2-l1-disable: If present, disable L1 low power modes in Highspeed mode - normal-eps-in-gsi-mode: If present, two normal EPS (1 In, 1 Out) can be used in GSI mode This is usually a subnode to DWC3 glue to which it is connected. Loading drivers/usb/dwc3/core.c +2 −0 Original line number Diff line number Diff line Loading @@ -1284,6 +1284,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,usb3-u1u2-disable"); dwc->usb2_l1_disable = device_property_read_bool(dev, "snps,usb2-l1-disable"); dwc->normal_eps_in_gsi_mode = device_property_read_bool(dev, "normal-eps-in-gsi-mode"); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, 500); pm_runtime_use_autosuspend(dev); Loading drivers/usb/dwc3/core.h +5 −0 Original line number Diff line number Diff line Loading @@ -620,6 +620,7 @@ struct dwc3_ep_events { * @dbg_ep_events_ts: timestamp for previous event counters * @fifo_depth: allocated TXFIFO depth * @ep_cfg_init_params: Used by GSI EP to save EP_CFG init_cmd params * @gsi_db_reg_addr: Address of GSI DB register mapped to this EP */ struct dwc3_ep { struct usb_ep endpoint; Loading Loading @@ -676,6 +677,7 @@ struct dwc3_ep { struct timespec dbg_ep_events_ts; int fifo_depth; struct dwc3_gadget_ep_cmd_params ep_cfg_init_params; void __iomem *gsi_db_reg_addr; }; enum dwc3_phy { Loading Loading @@ -989,6 +991,8 @@ struct dwc3_scratchpad_array { * @create_reg_debugfs: create debugfs entry to allow dwc3 register dump * @xhci_imod_value: imod value to use with xhci * @core_id: usb core id to differentiate different controller * @normal_eps_in_gsi_mode: if true, two normal EPS (1 In, 1 Out) can be used in * GSI mode */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -1191,6 +1195,7 @@ struct dwc3 { u32 xhci_imod_value; int core_id; int retries_on_error; bool normal_eps_in_gsi_mode; }; /* -------------------------------------------------------------------------- */ Loading drivers/usb/dwc3/dwc3-msm.c +102 −11 Original line number Diff line number Diff line Loading @@ -203,7 +203,7 @@ static const char * const gsi_op_strings[] = { "ENABLE_GSI", "UPDATE_XFER", "RING_DB", "END_XFER", "GET_CH_INFO", "GET_XFER_IDX", "PREPARE_TRBS", "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; "EP_DISABLE", "EP_UPDATE_DB" }; /* Input bits to state machine (mdwc->inputs) */ Loading Loading @@ -312,6 +312,8 @@ struct dwc3_msm { u64 dummy_gsi_db; dma_addr_t dummy_gsi_db_dma; u64 dummy_gevntcnt; dma_addr_t dummy_gevntcnt_dma; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -864,6 +866,7 @@ static void gsi_get_channel_info(struct usb_ep *ep, int last_trb_index = 0; struct dwc3 *dwc = dep->dwc; struct usb_gsi_request *request = ch_info->ch_req; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); /* Provide physical USB addresses for DEPCMD and GEVENTCNT registers */ ch_info->depcmd_low_addr = (u32)(dwc->reg_phys + Loading Loading @@ -898,14 +901,28 @@ static void gsi_get_channel_info(struct usb_ep *ep, /* Store last 16 bits of LINK TRB address as per GSI hw requirement */ ch_info->last_trb_addr = (dwc3_trb_dma_offset(dep, &dep->trb_pool[last_trb_index - 1]) & 0x0000FFFF); dev_dbg(dwc->dev, "depcmd_laddr=%x last_trb_addr=%x\n", ch_info->depcmd_low_addr, ch_info->last_trb_addr); /* * Check if NORMAL EP is used with GSI. In that case USB driver * processes events and GSI shouldn't access GEVNTCOUNT(0) register. */ if (ep->ep_intr_num) { ch_info->gevntcount_low_addr = (u32)(dwc->reg_phys + DWC3_GEVNTCOUNT(ep->ep_intr_num)); ch_info->gevntcount_hi_addr = 0; dev_dbg(dwc->dev, "depcmd_laddr=%x last_trb_addr=%x gevtcnt_laddr=%x gevtcnt_haddr=%x", ch_info->depcmd_low_addr, ch_info->last_trb_addr, dev_dbg(dwc->dev, "gevtcnt_laddr=%x gevtcnt_haddr=%x\n", ch_info->gevntcount_low_addr, ch_info->gevntcount_hi_addr); } else { ch_info->gevntcount_low_addr = (u32)mdwc->dummy_gevntcnt_dma; ch_info->gevntcount_hi_addr = (u32)((u64)mdwc->dummy_gevntcnt_dma >> 32); dev_dbg(dwc->dev, "Dummy GEVNTCNT Addr %pK: %llx %x (LSB)\n", &mdwc->dummy_gevntcnt, (unsigned long long)mdwc->dummy_gevntcnt_dma, (u32)mdwc->dummy_gevntcnt_dma); } } /* Loading @@ -929,8 +946,15 @@ static int gsi_startxfer_for_ep(struct usb_ep *ep) } memset(¶ms, 0, sizeof(params)); params.param0 = GSI_TRB_ADDR_BIT_53_MASK | GSI_TRB_ADDR_BIT_55_MASK; /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (ep->ep_intr_num) { params.param0 = GSI_TRB_ADDR_BIT_53_MASK | GSI_TRB_ADDR_BIT_55_MASK; params.param0 |= (ep->ep_intr_num << 16); } params.param1 = lower_32_bits(dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); cmd = DWC3_DEPCMD_STARTTRANSFER; Loading @@ -957,7 +981,18 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); int n = ep->ep_intr_num - 1; int n; /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } n = ep->ep_intr_num - 1; dwc3_msm_write_reg(mdwc->base, GSI_RING_BASE_ADDR_L(n), dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); Loading Loading @@ -991,6 +1026,21 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, dwc3_msm_read_reg(mdwc->base, GSI_DBL_ADDR_L(n))); } static void dwc3_msm_gsi_db_update(struct dwc3_ep *dep, dma_addr_t offset) { struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); if (!dep->gsi_db_reg_addr) { dev_err(mdwc->dev, "Failed to update GSI DBL\n"); return; } writel_relaxed(offset, dep->gsi_db_reg_addr); dev_dbg(mdwc->dev, "Writing TRB addr: %pa to %pK\n", &offset, dep->gsi_db_reg_addr); } /* * Rings Doorbell for GSI Channel * Loading @@ -1016,6 +1066,8 @@ static void gsi_ring_db(struct usb_ep *ep, struct usb_gsi_request *request) return; } dep->gsi_db_reg_addr = gsi_dbl_address_lsb; gsi_dbl_address_msb = devm_ioremap_nocache(mdwc->dev, request->db_reg_phs_addr_msb, sizeof(u32)); if (!gsi_dbl_address_msb) { Loading Loading @@ -1399,6 +1451,15 @@ static void gsi_enable(struct usb_ep *ep) struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } dwc3_msm_write_reg_field(mdwc->base, GSI_GENERAL_CFG_REG, GSI_CLK_EN_MASK, 1); dwc3_msm_write_reg_field(mdwc->base, Loading Loading @@ -1435,6 +1496,12 @@ static void gsi_set_clear_dbell(struct usb_ep *ep, else gsi_enable_ep_events(ep); /* Nothing to be done if NORMAL EP is used with GSI */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } dwc3_msm_write_reg_field(mdwc->base, GSI_GENERAL_CFG_REG, BLOCK_GSI_WR_GO_MASK, block_db); } Loading Loading @@ -1490,6 +1557,7 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, struct gsi_channel_info *ch_info; bool block_db; unsigned long flags; dma_addr_t offset; dbg_log_string("%s(%d):%s", ep->name, ep->ep_num, gsi_op_to_string(op)); Loading Loading @@ -1555,6 +1623,10 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, case GSI_EP_OP_DISABLE: ret = ep->ops->disable(ep); break; case GSI_EP_OP_UPDATE_DB: offset = *(dma_addr_t *)op_data; dwc3_msm_gsi_db_update(dep, offset); break; default: dev_err(mdwc->dev, "%s: Invalid opcode GSI EP\n", __func__); } Loading Loading @@ -2065,6 +2137,19 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, dev_err(dwc->dev, "failed to map dummy doorbell buffer\n"); mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL; } /* * Set-up dummy GEVNTCOUNT address to be passed on to GSI for * normal (non HW-accelerated) EPs. */ mdwc->dummy_gevntcnt_dma = dma_map_single(dwc->sysdev, &mdwc->dummy_gevntcnt, sizeof(mdwc->dummy_gevntcnt), DMA_FROM_DEVICE); if (dma_mapping_error(dwc->sysdev, mdwc->dummy_gevntcnt_dma)) { dev_err(dwc->dev, "failed to map dummy geventcount\n"); mdwc->dummy_gevntcnt_dma = (dma_addr_t)NULL; } break; case DWC3_GSI_EVT_BUF_SETUP: dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_SETUP\n"); Loading Loading @@ -2138,6 +2223,12 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma); } if (mdwc->dummy_gevntcnt_dma) { dma_unmap_single(dwc->sysdev, mdwc->dummy_gevntcnt_dma, sizeof(mdwc->dummy_gevntcnt), DMA_FROM_DEVICE); mdwc->dummy_gevntcnt_dma = (dma_addr_t)NULL; } if (mdwc->dummy_gsi_db_dma) { dma_unmap_single(dwc->sysdev, mdwc->dummy_gsi_db_dma, sizeof(mdwc->dummy_gsi_db), Loading drivers/usb/dwc3/gadget.c +33 −5 Original line number Diff line number Diff line Loading @@ -2390,8 +2390,8 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { /* -------------------------------------------------------------------------- */ #define NUM_GSI_OUT_EPS 1 #define NUM_GSI_IN_EPS 2 #define NUM_GSI_OUT_EPS(dwc) (dwc->normal_eps_in_gsi_mode ? 2 : 1) #define NUM_GSI_IN_EPS(dwc) (dwc->normal_eps_in_gsi_mode ? 3 : 2) static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, u8 num, u32 direction) Loading @@ -2399,13 +2399,13 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, struct dwc3_ep *dep; u8 i, gsi_ep_count, gsi_ep_index = 0; gsi_ep_count = NUM_GSI_OUT_EPS + NUM_GSI_IN_EPS; gsi_ep_count = NUM_GSI_OUT_EPS(dwc) + NUM_GSI_IN_EPS(dwc); /* OUT GSI EPs based on direction field */ if (gsi_ep_count && !direction) gsi_ep_count = NUM_GSI_OUT_EPS; gsi_ep_count = NUM_GSI_OUT_EPS(dwc); /* IN GSI EPs */ else if (gsi_ep_count && direction) gsi_ep_count = NUM_GSI_IN_EPS; gsi_ep_count = NUM_GSI_IN_EPS(dwc); for (i = 0; i < num; i++) { u8 epnum = (i << 1) | (direction ? 1 : 0); Loading Loading @@ -2710,6 +2710,25 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } static void dwc3_gsi_ep_transfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep) { struct usb_ep *ep = &dep->endpoint; struct dwc3_trb *trb; dma_addr_t offset; trb = &dep->trb_pool[dep->trb_dequeue]; while (trb->ctrl & DWC3_TRBCTL_LINK_TRB) { dwc3_ep_inc_trb(&dep->trb_dequeue); trb = &dep->trb_pool[dep->trb_dequeue]; } if (!(trb->ctrl & DWC3_TRB_CTRL_HWO)) { offset = dwc3_trb_dma_offset(dep, trb); usb_gsi_ep_op(ep, (void *)&offset, GSI_EP_OP_UPDATE_DB); dwc3_ep_inc_trb(&dep->trb_dequeue); } } static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { Loading @@ -2721,6 +2740,15 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, if (event->status & DEPEVT_STATUS_BUSERR) status = -ECONNRESET; /* * Check if NORMAL EP is used with GSI. * In that case dwc3 driver recevies EP events from hardware and * updates GSI doorbell with completed TRB. */ if (dep->endpoint.ep_type == EP_TYPE_GSI) { dwc3_gsi_ep_transfer_complete(dwc, dep); return; } clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); if (clean_busy && (!dep->endpoint.desc || is_xfer_complete || Loading Loading
Documentation/devicetree/bindings/usb/dwc3.txt +1 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ Optional properties: during bus suspend. - snps,usb3-u1u2-disable: If present, disable U1U2 low power modes in Superspeed mode - snps,usb2-l1-disable: If present, disable L1 low power modes in Highspeed mode - normal-eps-in-gsi-mode: If present, two normal EPS (1 In, 1 Out) can be used in GSI mode This is usually a subnode to DWC3 glue to which it is connected. Loading
drivers/usb/dwc3/core.c +2 −0 Original line number Diff line number Diff line Loading @@ -1284,6 +1284,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,usb3-u1u2-disable"); dwc->usb2_l1_disable = device_property_read_bool(dev, "snps,usb2-l1-disable"); dwc->normal_eps_in_gsi_mode = device_property_read_bool(dev, "normal-eps-in-gsi-mode"); if (dwc->enable_bus_suspend) { pm_runtime_set_autosuspend_delay(dev, 500); pm_runtime_use_autosuspend(dev); Loading
drivers/usb/dwc3/core.h +5 −0 Original line number Diff line number Diff line Loading @@ -620,6 +620,7 @@ struct dwc3_ep_events { * @dbg_ep_events_ts: timestamp for previous event counters * @fifo_depth: allocated TXFIFO depth * @ep_cfg_init_params: Used by GSI EP to save EP_CFG init_cmd params * @gsi_db_reg_addr: Address of GSI DB register mapped to this EP */ struct dwc3_ep { struct usb_ep endpoint; Loading Loading @@ -676,6 +677,7 @@ struct dwc3_ep { struct timespec dbg_ep_events_ts; int fifo_depth; struct dwc3_gadget_ep_cmd_params ep_cfg_init_params; void __iomem *gsi_db_reg_addr; }; enum dwc3_phy { Loading Loading @@ -989,6 +991,8 @@ struct dwc3_scratchpad_array { * @create_reg_debugfs: create debugfs entry to allow dwc3 register dump * @xhci_imod_value: imod value to use with xhci * @core_id: usb core id to differentiate different controller * @normal_eps_in_gsi_mode: if true, two normal EPS (1 In, 1 Out) can be used in * GSI mode */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; Loading Loading @@ -1191,6 +1195,7 @@ struct dwc3 { u32 xhci_imod_value; int core_id; int retries_on_error; bool normal_eps_in_gsi_mode; }; /* -------------------------------------------------------------------------- */ Loading
drivers/usb/dwc3/dwc3-msm.c +102 −11 Original line number Diff line number Diff line Loading @@ -203,7 +203,7 @@ static const char * const gsi_op_strings[] = { "ENABLE_GSI", "UPDATE_XFER", "RING_DB", "END_XFER", "GET_CH_INFO", "GET_XFER_IDX", "PREPARE_TRBS", "FREE_TRBS", "SET_CLR_BLOCK_DBL", "CHECK_FOR_SUSP", "EP_DISABLE" }; "EP_DISABLE", "EP_UPDATE_DB" }; /* Input bits to state machine (mdwc->inputs) */ Loading Loading @@ -312,6 +312,8 @@ struct dwc3_msm { u64 dummy_gsi_db; dma_addr_t dummy_gsi_db_dma; u64 dummy_gevntcnt; dma_addr_t dummy_gevntcnt_dma; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ Loading Loading @@ -864,6 +866,7 @@ static void gsi_get_channel_info(struct usb_ep *ep, int last_trb_index = 0; struct dwc3 *dwc = dep->dwc; struct usb_gsi_request *request = ch_info->ch_req; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); /* Provide physical USB addresses for DEPCMD and GEVENTCNT registers */ ch_info->depcmd_low_addr = (u32)(dwc->reg_phys + Loading Loading @@ -898,14 +901,28 @@ static void gsi_get_channel_info(struct usb_ep *ep, /* Store last 16 bits of LINK TRB address as per GSI hw requirement */ ch_info->last_trb_addr = (dwc3_trb_dma_offset(dep, &dep->trb_pool[last_trb_index - 1]) & 0x0000FFFF); dev_dbg(dwc->dev, "depcmd_laddr=%x last_trb_addr=%x\n", ch_info->depcmd_low_addr, ch_info->last_trb_addr); /* * Check if NORMAL EP is used with GSI. In that case USB driver * processes events and GSI shouldn't access GEVNTCOUNT(0) register. */ if (ep->ep_intr_num) { ch_info->gevntcount_low_addr = (u32)(dwc->reg_phys + DWC3_GEVNTCOUNT(ep->ep_intr_num)); ch_info->gevntcount_hi_addr = 0; dev_dbg(dwc->dev, "depcmd_laddr=%x last_trb_addr=%x gevtcnt_laddr=%x gevtcnt_haddr=%x", ch_info->depcmd_low_addr, ch_info->last_trb_addr, dev_dbg(dwc->dev, "gevtcnt_laddr=%x gevtcnt_haddr=%x\n", ch_info->gevntcount_low_addr, ch_info->gevntcount_hi_addr); } else { ch_info->gevntcount_low_addr = (u32)mdwc->dummy_gevntcnt_dma; ch_info->gevntcount_hi_addr = (u32)((u64)mdwc->dummy_gevntcnt_dma >> 32); dev_dbg(dwc->dev, "Dummy GEVNTCNT Addr %pK: %llx %x (LSB)\n", &mdwc->dummy_gevntcnt, (unsigned long long)mdwc->dummy_gevntcnt_dma, (u32)mdwc->dummy_gevntcnt_dma); } } /* Loading @@ -929,8 +946,15 @@ static int gsi_startxfer_for_ep(struct usb_ep *ep) } memset(¶ms, 0, sizeof(params)); params.param0 = GSI_TRB_ADDR_BIT_53_MASK | GSI_TRB_ADDR_BIT_55_MASK; /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (ep->ep_intr_num) { params.param0 = GSI_TRB_ADDR_BIT_53_MASK | GSI_TRB_ADDR_BIT_55_MASK; params.param0 |= (ep->ep_intr_num << 16); } params.param1 = lower_32_bits(dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); cmd = DWC3_DEPCMD_STARTTRANSFER; Loading @@ -957,7 +981,18 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); int n = ep->ep_intr_num - 1; int n; /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } n = ep->ep_intr_num - 1; dwc3_msm_write_reg(mdwc->base, GSI_RING_BASE_ADDR_L(n), dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); Loading Loading @@ -991,6 +1026,21 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, dwc3_msm_read_reg(mdwc->base, GSI_DBL_ADDR_L(n))); } static void dwc3_msm_gsi_db_update(struct dwc3_ep *dep, dma_addr_t offset) { struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); if (!dep->gsi_db_reg_addr) { dev_err(mdwc->dev, "Failed to update GSI DBL\n"); return; } writel_relaxed(offset, dep->gsi_db_reg_addr); dev_dbg(mdwc->dev, "Writing TRB addr: %pa to %pK\n", &offset, dep->gsi_db_reg_addr); } /* * Rings Doorbell for GSI Channel * Loading @@ -1016,6 +1066,8 @@ static void gsi_ring_db(struct usb_ep *ep, struct usb_gsi_request *request) return; } dep->gsi_db_reg_addr = gsi_dbl_address_lsb; gsi_dbl_address_msb = devm_ioremap_nocache(mdwc->dev, request->db_reg_phs_addr_msb, sizeof(u32)); if (!gsi_dbl_address_msb) { Loading Loading @@ -1399,6 +1451,15 @@ static void gsi_enable(struct usb_ep *ep) struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); /* * Check if NORMAL EP is used with GSI. In that case USB driver * updates GSI doorbell and USB GSI wrapper h/w isn't involved. */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } dwc3_msm_write_reg_field(mdwc->base, GSI_GENERAL_CFG_REG, GSI_CLK_EN_MASK, 1); dwc3_msm_write_reg_field(mdwc->base, Loading Loading @@ -1435,6 +1496,12 @@ static void gsi_set_clear_dbell(struct usb_ep *ep, else gsi_enable_ep_events(ep); /* Nothing to be done if NORMAL EP is used with GSI */ if (!ep->ep_intr_num) { dev_dbg(mdwc->dev, "%s: is no-op for normal EP\n", __func__); return; } dwc3_msm_write_reg_field(mdwc->base, GSI_GENERAL_CFG_REG, BLOCK_GSI_WR_GO_MASK, block_db); } Loading Loading @@ -1490,6 +1557,7 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, struct gsi_channel_info *ch_info; bool block_db; unsigned long flags; dma_addr_t offset; dbg_log_string("%s(%d):%s", ep->name, ep->ep_num, gsi_op_to_string(op)); Loading Loading @@ -1555,6 +1623,10 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, case GSI_EP_OP_DISABLE: ret = ep->ops->disable(ep); break; case GSI_EP_OP_UPDATE_DB: offset = *(dma_addr_t *)op_data; dwc3_msm_gsi_db_update(dep, offset); break; default: dev_err(mdwc->dev, "%s: Invalid opcode GSI EP\n", __func__); } Loading Loading @@ -2065,6 +2137,19 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, dev_err(dwc->dev, "failed to map dummy doorbell buffer\n"); mdwc->dummy_gsi_db_dma = (dma_addr_t)NULL; } /* * Set-up dummy GEVNTCOUNT address to be passed on to GSI for * normal (non HW-accelerated) EPs. */ mdwc->dummy_gevntcnt_dma = dma_map_single(dwc->sysdev, &mdwc->dummy_gevntcnt, sizeof(mdwc->dummy_gevntcnt), DMA_FROM_DEVICE); if (dma_mapping_error(dwc->sysdev, mdwc->dummy_gevntcnt_dma)) { dev_err(dwc->dev, "failed to map dummy geventcount\n"); mdwc->dummy_gevntcnt_dma = (dma_addr_t)NULL; } break; case DWC3_GSI_EVT_BUF_SETUP: dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_SETUP\n"); Loading Loading @@ -2138,6 +2223,12 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, dma_free_coherent(dwc->sysdev, evt->length, evt->buf, evt->dma); } if (mdwc->dummy_gevntcnt_dma) { dma_unmap_single(dwc->sysdev, mdwc->dummy_gevntcnt_dma, sizeof(mdwc->dummy_gevntcnt), DMA_FROM_DEVICE); mdwc->dummy_gevntcnt_dma = (dma_addr_t)NULL; } if (mdwc->dummy_gsi_db_dma) { dma_unmap_single(dwc->sysdev, mdwc->dummy_gsi_db_dma, sizeof(mdwc->dummy_gsi_db), Loading
drivers/usb/dwc3/gadget.c +33 −5 Original line number Diff line number Diff line Loading @@ -2390,8 +2390,8 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { /* -------------------------------------------------------------------------- */ #define NUM_GSI_OUT_EPS 1 #define NUM_GSI_IN_EPS 2 #define NUM_GSI_OUT_EPS(dwc) (dwc->normal_eps_in_gsi_mode ? 2 : 1) #define NUM_GSI_IN_EPS(dwc) (dwc->normal_eps_in_gsi_mode ? 3 : 2) static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, u8 num, u32 direction) Loading @@ -2399,13 +2399,13 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, struct dwc3_ep *dep; u8 i, gsi_ep_count, gsi_ep_index = 0; gsi_ep_count = NUM_GSI_OUT_EPS + NUM_GSI_IN_EPS; gsi_ep_count = NUM_GSI_OUT_EPS(dwc) + NUM_GSI_IN_EPS(dwc); /* OUT GSI EPs based on direction field */ if (gsi_ep_count && !direction) gsi_ep_count = NUM_GSI_OUT_EPS; gsi_ep_count = NUM_GSI_OUT_EPS(dwc); /* IN GSI EPs */ else if (gsi_ep_count && direction) gsi_ep_count = NUM_GSI_IN_EPS; gsi_ep_count = NUM_GSI_IN_EPS(dwc); for (i = 0; i < num; i++) { u8 epnum = (i << 1) | (direction ? 1 : 0); Loading Loading @@ -2710,6 +2710,25 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } static void dwc3_gsi_ep_transfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep) { struct usb_ep *ep = &dep->endpoint; struct dwc3_trb *trb; dma_addr_t offset; trb = &dep->trb_pool[dep->trb_dequeue]; while (trb->ctrl & DWC3_TRBCTL_LINK_TRB) { dwc3_ep_inc_trb(&dep->trb_dequeue); trb = &dep->trb_pool[dep->trb_dequeue]; } if (!(trb->ctrl & DWC3_TRB_CTRL_HWO)) { offset = dwc3_trb_dma_offset(dep, trb); usb_gsi_ep_op(ep, (void *)&offset, GSI_EP_OP_UPDATE_DB); dwc3_ep_inc_trb(&dep->trb_dequeue); } } static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { Loading @@ -2721,6 +2740,15 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, if (event->status & DEPEVT_STATUS_BUSERR) status = -ECONNRESET; /* * Check if NORMAL EP is used with GSI. * In that case dwc3 driver recevies EP events from hardware and * updates GSI doorbell with completed TRB. */ if (dep->endpoint.ep_type == EP_TYPE_GSI) { dwc3_gsi_ep_transfer_complete(dwc, dep); return; } clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); if (clean_busy && (!dep->endpoint.desc || is_xfer_complete || Loading