Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2550a50d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: Add support for RmNet CV2X instance"

parents de5b1d1f 0d3cc847
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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.

+2 −0
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
@@ -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;
@@ -1191,6 +1195,7 @@ struct dwc3 {
	u32			xhci_imod_value;
	int			core_id;
	int			retries_on_error;
	bool			normal_eps_in_gsi_mode;
};

/* -------------------------------------------------------------------------- */
+102 −11
Original line number Diff line number Diff line
@@ -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) */

@@ -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 */
@@ -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 +
@@ -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);
	}
}

/*
@@ -929,8 +946,15 @@ static int gsi_startxfer_for_ep(struct usb_ep *ep)
	}

	memset(&params, 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;
@@ -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]));
@@ -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
*
@@ -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) {
@@ -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,
@@ -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);
}
@@ -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));

@@ -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__);
	}
@@ -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");
@@ -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),
+33 −5
Original line number Diff line number Diff line
@@ -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)
@@ -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);
@@ -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)
{
@@ -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