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

Commit 9f5a3d56 authored by Mayank Rana's avatar Mayank Rana
Browse files

USB: msm_otg: Add support for AHB2AHB Bypass Mode in device mode



With AHB2AHB Bypass Mode, USB 2.0 Core is running using PNOC clock
and runs synchronous to PNOC which provides better throughput.
AHB2AHB Bypass mode can be enable with USB controller using
USB_AHBMODE register. It has below requirement :
- It should be enable before setting kicking USB controller
(i.e. setting R/S bit).
- PNOC should be running at MAX speed to get better throughput.
- While doing asynchronous clock reset with USB core, it is required
to disable this functionality as PNOC clock can't be disable and
re-enable as it is performed with other USB core clock.

CRs-Fixed: 550553
Change-Id: I9feac91b8885a393a13a039e9c89d63d0af2aed6
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent c5f82809
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -93,6 +93,11 @@ Optional properties :
	wakeup during USB low-power mode SW workaround will be applied. When
	this workaround is applied, the PHCD and the FPR bits are written
	to the PORTSC register in the same register write operation.
- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
	mode with device controller for better throughput. With this mode, USB Core
	runs using PNOC clock and synchronous to it. Hence it is must to have proper
	"qcom,msm_bus,vectors" to have high bus frequency. User shouldn't try to
	enable this feature without proper bus voting.

Example HSUSB OTG controller device node :
	usb@f9690000 {
+4 −0
Original line number Diff line number Diff line
@@ -303,6 +303,10 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
				1 << (pdata->log2_itc-1);

		is_l1_supported = pdata->l1_supported;
		/* Set ahb2ahb bypass flag if it is requested. */
		if (pdata->enable_ahb2ahb_bypass)
			ci13xxx_msm_udc_driver.flags |=
				CI13XXX_ENABLE_AHB2AHB_BYPASS;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+13 −0
Original line number Diff line number Diff line
@@ -406,6 +406,13 @@ static int hw_device_state(u32 dma)
			udc->udc_driver->notify_event(udc,
				CI13XXX_CONTROLLER_CONNECT_EVENT);

		/* Set BIT(31) to enable AHB2AHB Bypass functionality */
		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
			pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
					__func__, hw_aread(ABS_AHBMODE, ~0));
		}

		/* interrupt, error, port change, reset, sleep/suspend */
		hw_cwrite(CAP_USBINTR, ~0,
			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
@@ -413,6 +420,12 @@ static int hw_device_state(u32 dma)
	} else {
		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
		hw_cwrite(CAP_USBINTR, ~0, 0);
		/* Clear BIT(31) to disable AHB2AHB Bypass functionality */
		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
			pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
					__func__, hw_aread(ABS_AHBMODE, ~0));
		}
	}
	return 0;
}
+4 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct ci13xxx_udc_driver {
#define CI13XXX_DISABLE_STREAMING	BIT(3)
#define CI13XXX_ZERO_ITC		BIT(4)
#define CI13XXX_IS_OTG			BIT(5)
#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)

#define CI13XXX_CONTROLLER_RESET_EVENT			0
#define CI13XXX_CONTROLLER_CONNECT_EVENT		1
@@ -200,6 +201,9 @@ struct ci13xxx {
/* TESTMODE */
#define TESTMODE_FORCE        BIT(0)

/* AHB_MODE */
#define AHB2AHB_BYPASS	      BIT(31)

/* USBCMD */
#define USBCMD_RS             BIT(0)
#define USBCMD_RST            BIT(1)
+18 −0
Original line number Diff line number Diff line
@@ -472,6 +472,20 @@ static int msm_otg_phy_reset(struct msm_otg *motg)
	int ret;
	struct msm_otg_platform_data *pdata = motg->pdata;

	/*
	 * AHB2AHB Bypass mode shouldn't be enable before doing
	 * async clock reset. If it is enable, disable the same.
	 */
	val = readl_relaxed(USB_AHBMODE);
	if (val & AHB2AHB_BYPASS) {
		pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
						__func__, val);
		val &= ~AHB2AHB_BYPASS_BIT_MASK;
		writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
		pr_err("%s(): AHBMODE: %x\n", __func__,
				readl_relaxed(USB_AHBMODE));
	}

	ret = msm_otg_link_clk_reset(motg, 1);
	if (ret)
		return ret;
@@ -3942,6 +3956,8 @@ static struct platform_device *msm_otg_add_pdev(
		ci_pdata.log2_itc = otg_pdata->log2_itc;
		ci_pdata.usb_core_id = 0;
		ci_pdata.l1_supported = otg_pdata->l1_supported;
		ci_pdata.enable_ahb2ahb_bypass =
				otg_pdata->enable_ahb2ahb_bypass;
		retval = platform_device_add_data(pdev, &ci_pdata,
			sizeof(ci_pdata));
		if (retval)
@@ -4273,6 +4289,8 @@ struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)

	pdata->l1_supported = of_property_read_bool(node,
				"qcom,hsusb-l1-supported");
	pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
				"qcom,ahb-async-bridge-bypass");

	res_gpio = of_get_named_gpio(node, "qcom,hsusb-otg-vddmin-gpio", 0);
	if (res_gpio < 0)
Loading