usb: otg: Add workaround for PNOC performance issue
PNOC (Peripheral NOC) present on some MSM targets has
a hardware BUG which degrades the USB peripheral performance.
Fix this by adding a software workaround that changes the
USB mem-type attribute value (from 0 to 2) via VMIDMT.
Change-Id: I2249f1aa81c457032c6f8818f5c5d3820bea66d3
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 12fbfec..186a58d 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -22,10 +22,13 @@
1 - PHY control
2 - PMIC control
3 - User control (via debugfs)
-- qcom,hsusb-otg-disable-reset: It present then core is RESET only during
- init, otherwise core is RESET for every cable disconnect as well
Optional properties :
+- qcom,hsusb-otg-disable-reset: If present then core is RESET only during
+ init, otherwise core is RESET for every cable disconnect as well
+- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
+ performance issue is applied which requires changing the mem-type
+ attribute via VMIDMT.
- qcom,hsusb-otg-default-mode: The default USB mode after boot-up.
Applicable only when OTG is controlled by user. Can be one of
0 - None. Low power mode
@@ -56,6 +59,7 @@
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <1>;
qcom,hsusb-otg-disable-reset;
+ qcom,hsusb-otg-pnoc-errata-fix;
qcom,hsusb-otg-default-mode = <2>;
qcom,hsusb-otg-phy-init-seq = <0x01 0x90 0xffffffff>;
qcom,hsusb-otg-power-budget = <500>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8e6f1e6..4934afa 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -99,6 +99,7 @@
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <1>;
qcom,hsusb-otg-disable-reset;
+ qcom,hsusb-otg-pnoc-errata-fix;
qcom,msm_bus,name = "usb2";
qcom,msm_bus,num_cases = <2>;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f27e0eb..bd3b700 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -42,6 +42,7 @@
#include <linux/power_supply.h>
#include <linux/mhl_8334.h>
+#include <mach/scm.h>
#include <mach/clk.h>
#include <mach/mpm.h>
#include <mach/msm_xo.h>
@@ -3433,6 +3434,38 @@
debugfs_remove_recursive(msm_otg_dbg_root);
}
+#define MSM_OTG_CMD_ID 0x09
+#define MSM_OTG_DEVICE_ID 0x04
+#define MSM_OTG_VMID_IDX 0xFF
+#define MSM_OTG_MEM_TYPE 0x02
+struct msm_otg_scm_cmd_buf {
+ unsigned int device_id;
+ unsigned int vmid_idx;
+ unsigned int mem_type;
+} __attribute__ ((__packed__));
+
+static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
+{
+ int ret;
+ struct msm_otg_platform_data *pdata = motg->pdata;
+ struct msm_otg_scm_cmd_buf cmd_buf;
+
+ if (!pdata->pnoc_errata_fix)
+ return;
+
+ dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
+
+ cmd_buf.device_id = MSM_OTG_DEVICE_ID;
+ cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
+ cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
+
+ ret = scm_call(SCM_SVC_CP, MSM_OTG_CMD_ID, &cmd_buf,
+ sizeof(cmd_buf), NULL, 0);
+
+ if (ret)
+ dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
+}
+
static u64 msm_otg_dma_mask = DMA_BIT_MASK(64);
static struct platform_device *msm_otg_add_pdev(
struct platform_device *ofdev, const char *name)
@@ -3546,6 +3579,8 @@
&pdata->pmic_id_irq);
pdata->disable_reset_on_disconnect = of_property_read_bool(node,
"qcom,hsusb-otg-disable-reset");
+ pdata->pnoc_errata_fix = of_property_read_bool(node,
+ "qcom,hsusb-otg-pnoc-errata-fix");
return pdata;
}
@@ -3744,6 +3779,9 @@
}
clk_prepare_enable(motg->core_clk);
+ /* Check if USB mem_type change is needed to workaround PNOC hw issue */
+ msm_otg_pnoc_errata_fix(motg);
+
writel(0, USB_USBINTR);
writel(0, USB_OTGSC);
/* Ensure that above STOREs are completed before enabling interrupts */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d45889c..9294c27 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -192,6 +192,8 @@
* @mhl_enable: indicates MHL connector or not.
* @disable_reset_on_disconnect: perform USB PHY and LINK reset
* on USB cable disconnection.
+ * @pnoc_errata_fix: workaround needed for PNOC hardware bug that
+ * affects USB performance.
* @enable_lpm_on_suspend: Enable the USB core to go into Low
* Power Mode, when USB bus is suspended but cable
* is connected.
@@ -213,6 +215,7 @@
unsigned int mpm_otgsessvld_int;
bool mhl_enable;
bool disable_reset_on_disconnect;
+ bool pnoc_errata_fix;
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
struct msm_bus_scale_pdata *bus_scale_table;