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

Commit 961306d1 authored by Ajay Agarwal's avatar Ajay Agarwal
Browse files

usb: dwc3: Add support for variable number of GSI endpoints



Currently, the gadget driver fixes the number of GSI IN EPs to 2
and OUT EPs to 1. But some targets have more HW accelerated EPs
available for use.
Add new property 'num-gsi-eps' from glue driver to dwc3 child
node to initialize variable number of GSI EPs based on devicetree
property 'qcom,num-gsi-evt-buffs'.

Change-Id: Iab99a8398440fc1b44563e4080c39868835f932b
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent bab04d12
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ Optional properties:
 - snps,usb3-u1u2-disable: If present, disable U1U2 low power modes in Superspeed mode
 - snps,disable-clk-gating: If present, disable controller's internal clock gating.
   Default it is enabled.
 - num-gsi-eps: Number of GSI based hardware accelerated endpoints

 - in addition all properties from usb-xhci.txt from the current directory are
   supported as well
+1 −0
Original line number Diff line number Diff line
@@ -1169,6 +1169,7 @@ static void dwc3_get_properties(struct dwc3 *dwc)
					"snps,usb3-u1u2-disable");
	dwc->disable_clk_gating = device_property_read_bool(dev,
					"snps,disable-clk-gating");
	device_property_read_u32(dev, "num-gsi-eps", &dwc->num_gsi_eps);

	dwc->dis_metastability_quirk = device_property_read_bool(dev,
				"snps,dis_metastability_quirk");
+2 −0
Original line number Diff line number Diff line
@@ -994,6 +994,7 @@ struct dwc3_scratchpad_array {
 * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
 * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
 * @last_run_stop: timestamp denoting the last run_stop update
 * @num_gsi_eps: number of GSI based hardware accelerated endpoints
 */
struct dwc3 {
	struct work_struct	drd_work;
@@ -1212,6 +1213,7 @@ struct dwc3 {
	bool			host_poweroff_in_pm_suspend;
	int			retries_on_error;
	ktime_t			last_run_stop;
	u32			num_gsi_eps;
};

#define work_to_dwc(w)		(container_of((w), struct dwc3, drd_work))
+87 −26
Original line number Diff line number Diff line
@@ -330,6 +330,9 @@ struct dwc3_msm {

	u64			dummy_gsi_db;
	dma_addr_t		dummy_gsi_db_dma;

	struct device_node *dwc3_node;
	struct property *num_gsi_eps;
};

#define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -3599,6 +3602,62 @@ static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p)

	return NOTIFY_OK;
}

static int dwc3_msm_populate_gsi_params(struct dwc3_msm *mdwc)
{
	struct device_node *node = mdwc->dev->of_node;
	struct device *dev = mdwc->dev;
	struct property *prop = NULL;
	const void *p_val;
	void *value;
	int size = 0;

	p_val = of_get_property(node, "qcom,num-gsi-evt-buffs", &size);
	if (!size) {
		dev_dbg(dev, "GSI EPs not being used\n");
		return 0;
	}

	of_property_read_u32(node, "qcom,num-gsi-evt-buffs",
				&mdwc->num_gsi_event_buffers);
	value = devm_kzalloc(dev, size, GFP_KERNEL);
	if (!value)
		return -ENOMEM;

	memcpy(value, p_val, size);
	prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
	if (!prop)
		return -ENOMEM;

	prop->name = "num-gsi-eps";
	prop->value = value;
	prop->length = size;
	mdwc->num_gsi_eps = prop;

	of_get_property(node, "qcom,gsi-reg-offset", &size);
	if (!size) {
		dev_err(dev, "err provide qcom,gsi-reg-offset\n");
		return -EINVAL;
	}

	mdwc->gsi_reg = devm_kzalloc(dev, size, GFP_KERNEL);
	if (!mdwc->gsi_reg)
		return -ENOMEM;

	mdwc->gsi_reg_offset_cnt =
			(size / sizeof(*mdwc->gsi_reg));
	if (mdwc->gsi_reg_offset_cnt != GSI_REG_MAX) {
		dev_err(dev, "invalid reg offset count\n");
		return -EINVAL;
	}

	of_property_read_u32_array(dev->of_node,
		"qcom,gsi-reg-offset", mdwc->gsi_reg,
		mdwc->gsi_reg_offset_cnt);

	return 0;
}

static int dwc3_msm_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node, *dwc3_node;
@@ -3606,7 +3665,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	struct dwc3_msm *mdwc;
	struct dwc3	*dwc;
	struct resource *res;
	int ret = 0, size = 0, i;
	int ret = 0, i;
	u32 val;
	unsigned long irq_type;

@@ -3768,31 +3827,9 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		dev_err(&pdev->dev,
			"unable to read platform data tx fifo size\n");

	ret = of_property_read_u32(node, "qcom,num-gsi-evt-buffs",
				&mdwc->num_gsi_event_buffers);

	if (mdwc->num_gsi_event_buffers) {
		of_get_property(node, "qcom,gsi-reg-offset", &size);
		if (size) {
			mdwc->gsi_reg = devm_kzalloc(dev, size, GFP_KERNEL);
			if (!mdwc->gsi_reg)
				return -ENOMEM;

			mdwc->gsi_reg_offset_cnt =
					(size / sizeof(*mdwc->gsi_reg));
			if (mdwc->gsi_reg_offset_cnt != GSI_REG_MAX) {
				dev_err(dev, "invalid reg offset count\n");
				return -EINVAL;
			}

			of_property_read_u32_array(dev->of_node,
				"qcom,gsi-reg-offset", mdwc->gsi_reg,
				mdwc->gsi_reg_offset_cnt);
		} else {
			dev_err(dev, "err provide qcom,gsi-reg-offset\n");
			return -EINVAL;
		}
	}
	ret = dwc3_msm_populate_gsi_params(mdwc);
	if (ret)
		goto err;

	mdwc->use_pdc_interrupts = of_property_read_bool(node,
				"qcom,use-pdc-interrupts");
@@ -3823,10 +3860,23 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		goto uninit_iommu;
	}

	if (mdwc->num_gsi_eps) {
		mdwc->dwc3_node = dwc3_node;
		ret = of_add_property(dwc3_node, mdwc->num_gsi_eps);
		if (ret) {
			dev_err(&pdev->dev, "failed to add 'num-gsi-eps' prop: %d\n",
						ret);
			of_node_put(dwc3_node);
			goto uninit_iommu;
		}
	}

	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
	if (ret) {
		dev_err(&pdev->dev,
				"failed to add create dwc3 core\n");
		if (mdwc->num_gsi_eps)
			of_remove_property(dwc3_node, mdwc->num_gsi_eps);
		of_node_put(dwc3_node);
		goto uninit_iommu;
	}
@@ -3990,6 +4040,11 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	platform_device_put(mdwc->dwc3);
	if (mdwc->bus_perf_client)
		msm_bus_scale_unregister_client(mdwc->bus_perf_client);
	if (mdwc->num_gsi_eps) {
		of_node_get(mdwc->dwc3_node);
		of_remove_property(mdwc->dwc3_node, mdwc->num_gsi_eps);
		of_node_put(mdwc->dwc3_node);
	}

uninit_iommu:
	of_platform_depopulate(&pdev->dev);
@@ -4048,6 +4103,12 @@ static int dwc3_msm_remove(struct platform_device *pdev)
	platform_device_put(mdwc->dwc3);
	of_platform_depopulate(&pdev->dev);

	if (mdwc->num_gsi_eps) {
		of_node_get(mdwc->dwc3_node);
		of_remove_property(mdwc->dwc3_node, mdwc->num_gsi_eps);
		of_node_put(mdwc->dwc3_node);
	}

	pm_runtime_disable(mdwc->dev);
	pm_runtime_barrier(mdwc->dev);
	pm_runtime_put_sync(mdwc->dev);
+5 −4
Original line number Diff line number Diff line
@@ -2651,8 +2651,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->num_gsi_eps / 2)
#define NUM_GSI_IN_EPS(dwc)	((dwc->num_gsi_eps + 1) / 2)

static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
{
@@ -2681,11 +2681,12 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
		dwc->eps[epnum] = dep;

		/* Reserve EPs at the end for GSI */
		if (!direction && num > out_count - NUM_GSI_OUT_EPS - 1) {
		if (!direction && num > out_count - NUM_GSI_OUT_EPS(dwc) - 1) {
			snprintf(dep->name, sizeof(dep->name), "gsi-epout%d",
					num);
			dep->endpoint.ep_type = EP_TYPE_GSI;
		} else if (direction && num > in_count - NUM_GSI_IN_EPS - 1) {
		} else if (direction &&
				num > in_count - NUM_GSI_IN_EPS(dwc) - 1) {
			snprintf(dep->name, sizeof(dep->name), "gsi-epin%d",
					num);
			dep->endpoint.ep_type = EP_TYPE_GSI;