summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2010-05-04 16:45:22 +0530
committerGary King <gking@nvidia.com>2010-05-07 16:44:18 -0700
commitc7707ab96e0ed9f7b841635d739ac16633ffd1a7 (patch)
tree500333c3659d69e204557d9f60b7ae1861b0614a
parent2293a1f7ac9ac8aca9180c5f245bca7cc95b6dea (diff)
udc/tegra: configure memory prefetcher for USB
When we are programming two DTDs very close to each other, the second DTD is being prefetched before it is actually written to DDR. To prevent this, we disable prefetcher before programming any new DTD and re-enable it before priming endpoint. Bug 597487 Change-Id: Iaf15a2bfb10cfc24d34bcb4b3093c1c6c48d5d22 Reviewed-on: http://git-master/r/1149 Reviewed-by: Gary King <gking@nvidia.com> Reviewed-by: Pavan Kunapuli <pkunapuli@nvidia.com> Tested-by: Pavan Kunapuli <pkunapuli@nvidia.com>
-rwxr-xr-xarch/arm/mach-tegra/include/nvddk_usbphy.h10
-rwxr-xr-x[-rw-r--r--]arch/arm/mach-tegra/nvddk/nvddk_usbphy.c6
-rw-r--r--arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap16.c9
-rw-r--r--arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap20.c40
-rw-r--r--arch/arm/mach-tegra/nvddk/nvddk_usbphy_priv.h2
-rwxr-xr-xarch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c23
-rwxr-xr-xdrivers/usb/gadget/fsl_udc_core.c4
-rwxr-xr-xdrivers/usb/gadget/fsl_usb2_udc.h15
-rwxr-xr-xdrivers/usb/gadget/tegra_udc.c15
9 files changed, 98 insertions, 26 deletions
diff --git a/arch/arm/mach-tegra/include/nvddk_usbphy.h b/arch/arm/mach-tegra/include/nvddk_usbphy.h
index ef1be673e8d4..4dd8a2a63aac 100755
--- a/arch/arm/mach-tegra/include/nvddk_usbphy.h
+++ b/arch/arm/mach-tegra/include/nvddk_usbphy.h
@@ -162,7 +162,6 @@ typedef enum
*/
NvDdkUsbPhyIoctlType_UsbBusyHintsOnOff,
-
NvDdkUsbPhyIoctlType_Num,
/**
* Ignore -- Forces compilers to make 32-bit enums.
@@ -242,7 +241,6 @@ typedef struct NvDdkUsbPhyIoctl_UsbBusyHintsOnOffInputArgsRec
NvU32 BoostDurationMs;
} NvDdkUsbPhyIoctl_UsbBusyHintsOnOffInputArgs;
-
/**
* Opens the Usb Phy, allocates the resources and initializes the phy.
*
@@ -320,6 +318,14 @@ NvError NvDdkUsbPhyIoctl(
*/
NvError NvDdkUsbPhyWaitForStableClock(NvDdkUsbPhyHandle hUsbPhy);
+/**
+ * Configures Prefetcher for USB.
+ *
+ * @param hUsbPhy Handle acquired during the NvDdkUsbPhyOpen() call.
+ * @param Enable If NV_TRUE, prefetcher is enabled, else disabled.
+ *
+ */
+void NvDdkUsbPhyMemoryPrefetch(NvDdkUsbPhyHandle hUsbPhy, NvBool Enable);
#if defined(__cplusplus)
}
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
index 7f15b34f6b9c..194f604c20fb 100644..100755
--- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
+++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c
@@ -773,6 +773,12 @@ NvDdkUsbPhyWaitForStableClock(
return hUsbPhy->WaitForStableClock(hUsbPhy);
}
+void NvDdkUsbPhyMemoryPrefetch(NvDdkUsbPhyHandle hUsbPhy, NvBool Enable)
+{
+ NV_ASSERT(hUsbPhy);
+
+ hUsbPhy->MemoryPrefetch(hUsbPhy, Enable);
+}
NvError
NvDdkUsbPhyIoctl(
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap16.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap16.c
index 4d73061beb27..e3d2a8e63df3 100644
--- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap16.c
+++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap16.c
@@ -939,7 +939,13 @@ Ap16UsbPhyWaitForStableClock(
return NvSuccess;
}
-
+static void
+Ap16UsbPhyMemoryPrefetch(
+ NvDdkUsbPhy *pUsbphy, NvBool Enable)
+{
+ // USB prefetcher configuration not implemented for AP16.
+ return;
+}
static NvError
Ap16UsbPhyPowerUp(
NvDdkUsbPhy *pUsbPhy)
@@ -1029,6 +1035,7 @@ Ap16UsbPhyOpenHwInterface(
pUsbPhy->PowerDown = Ap16UsbPhyPowerDown;
pUsbPhy->Ioctl = Ap16UsbPhyIoctl;
pUsbPhy->WaitForStableClock = Ap16UsbPhyWaitForStableClock;
+ pUsbPhy->MemoryPrefetch = Ap16UsbPhyMemoryPrefetch;
pUsbPhy->CloseHwInterface = Ap16UsbPhyClose;
pUsbPhy->SaveContext = Ap16PhySaveContext;
pUsbPhy->RestoreContext = Ap16PhyRestoreContext;
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap20.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap20.c
index 159873da6aca..245e447327c7 100644
--- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap20.c
+++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_ap20.c
@@ -46,6 +46,7 @@
#include "nvrm_hardware_access.h"
#include "nvddk_usbphy_priv.h"
#include "nvodm_query.h"
+#include "ap20/arahb_arbc.h"
/* Defines for USB register read and writes */
#define USB_REG_RD(reg)\
@@ -1248,6 +1249,44 @@ Ap20UsbPhyWaitForStableClock(
return NvSuccess;
}
+static void Ap20UsbPhyMemoryPrefetch(NvDdkUsbPhy* pUsbPhy, NvBool Enable)
+{
+ NvU32 regVal = 0;
+
+ if (Enable)
+ {
+ // Setup the AHB MEM configuration for USB performance.
+ // Enabling the AHB prefetch bits for USB1.
+ // 64kiloByte boundaries.
+ // 4096 cycles before prefetched data is invalidated due to inactivity.
+ regVal = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, ENABLE, 1) |
+ NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG1, AHB_MST_ID, AHBDMA)|
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, ADDR_BNDRY, 0xC) |
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, SPEC_THROTTLE, 0x0) |
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, INACTIVITY_TIMEOUT, 0x1000);
+ NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
+ AHB_AHB_MEM_PREFETCH_CFG1_0, regVal);
+
+ regVal = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, ENABLE, 1) |
+ NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG2, AHB_MST_ID, USB)|
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, ADDR_BNDRY, 0xC) |
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, SPEC_THROTTLE, 0x0) |
+ NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, INACTIVITY_TIMEOUT, 0x1000);
+ NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
+ AHB_AHB_MEM_PREFETCH_CFG2_0, regVal);
+ }
+ else
+ {
+ regVal = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, ENABLE, 0);
+ NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
+ AHB_AHB_MEM_PREFETCH_CFG1_0, regVal);
+
+ regVal = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, ENABLE, 0);
+ NV_REGW( pUsbPhy->hRmDevice, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
+ AHB_AHB_MEM_PREFETCH_CFG2_0, regVal);
+ }
+}
+
static NvError
Ap20UsbPhyPowerUp(
NvDdkUsbPhy *pUsbPhy)
@@ -1492,6 +1531,7 @@ Ap20UsbPhyOpenHwInterface(
pUsbPhy->PowerDown = Ap20UsbPhyPowerDown;
pUsbPhy->Ioctl = Ap20UsbPhyIoctl;
pUsbPhy->WaitForStableClock = Ap20UsbPhyWaitForStableClock;
+ pUsbPhy->MemoryPrefetch = Ap20UsbPhyMemoryPrefetch;
pUsbPhy->CloseHwInterface = Ap20UsbPhyClose;
pUsbPhy->SaveContext = Ap20PhySaveContext;
pUsbPhy->RestoreContext = Ap20PhyRestoreContext;
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_priv.h b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_priv.h
index 8088eb63a1f9..16d78608b655 100644
--- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy_priv.h
+++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy_priv.h
@@ -185,6 +185,8 @@ typedef struct NvDdkUsbPhyRec
NvError (*PowerDown)(NvDdkUsbPhyHandle hUsbPhy);
// Pointer to the h/w specific WaitForStableClock function.
NvError (*WaitForStableClock)(NvDdkUsbPhyHandle hUsbPhy);
+ // Pointer to the h/w specific usb prefetcher function
+ void (*MemoryPrefetch)(NvDdkUsbPhyHandle hUsbPhy, NvBool Enable);
// Pointer to the h/w specific CloseHwInterface function.
void (*CloseHwInterface)(NvDdkUsbPhyHandle hUsbPhy);
// Pointer to save context function
diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
index a1433660c50a..d589049ed4b4 100755
--- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
@@ -152,29 +152,6 @@ void NvRmPrivAp20SetupMc(NvRmDeviceHandle hRm)
NV_ASSERT(!"MC LL Path not enabled!");
// For AP20, no need to program any MC timeout registers here. Default
// values should be good enough.
-
- // Setup the AHB MEM configuration for USB performance.
- // Enabling the AHB prefetch bits for USB1 USB2 and USB3.
- // 64kiloByte boundaries
- // 4096 cycles before prefetched data is invalidated due to inactivity.
- reg = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, ENABLE, 1) |
- NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG1, AHB_MST_ID, AHBDMA)|
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, ADDR_BNDRY, 0xC) |
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, SPEC_THROTTLE, 0x0) |
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG1, INACTIVITY_TIMEOUT, 0x1000);
- NV_REGW( hRm, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
- AHB_AHB_MEM_PREFETCH_CFG1_0, reg );
-
- reg = NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, ENABLE, 1) |
- NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG2, AHB_MST_ID, USB)|
- NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG2, AHB_MST_ID, USB2)|
- NV_DRF_DEF(AHB_AHB_MEM, PREFETCH_CFG2, AHB_MST_ID, USB3)|
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, ADDR_BNDRY, 0xC) |
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, SPEC_THROTTLE, 0x0) |
- NV_DRF_NUM(AHB_AHB_MEM, PREFETCH_CFG2, INACTIVITY_TIMEOUT, 0x1000);
- NV_REGW( hRm, NvRmPrivModuleID_Ahb_Arb_Ctrl, 0,
- AHB_AHB_MEM_PREFETCH_CFG2_0, reg );
-
}
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 7f4149747b1a..c34350523437 100755
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -719,6 +719,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
/* Ensure that updates to the QH will occure before priming. */
wmb();
+ platform_udc_ep_barrier();
+
/* Prime endpoint by writing 1 to ENDPTPRIME */
temp = ep_is_in(ep)
? (1 << (ep_index(ep) + 16))
@@ -802,6 +804,8 @@ static int fsl_req_to_dtd(struct fsl_req *req)
struct ep_td_struct *last_dtd = NULL, *dtd;
dma_addr_t dma;
+ platform_udc_dtd_prepare();
+
do {
dtd = fsl_build_dtd(req, &count, &dma, &is_last);
if (dtd == NULL)
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 5cdd6e983c8c..5594069d4d60 100755
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -625,6 +625,17 @@ extern void platform_udc_clk_release(void);
extern void platform_udc_clk_suspend(void);
extern void platform_udc_clk_resume(void);
extern bool platform_udc_charger_detection(void);
+
+#ifdef CONFIG_ARCH_TEGRA
+#define platform_udc_dtd_prepare __glue(_UDC_NAME,_udc_dtd_prepare)
+#define platform_udc_ep_barrier __glue(_UDC_NAME,_udc_ep_barrier)
+extern void platform_udc_dtd_prepare(void);
+extern void platform_udc_ep_barrier(void);
+#else
+static inline void platform_udc_dtd_prepare(void) { }
+static inline void platform_udc_ep_barrier(void) { }
+#endif
+
#else
static inline int platform_udc_clk_init(struct platform_device *pdev)
{
@@ -638,6 +649,10 @@ static inline bool platform_udc_charger_detection(void)
{
return 0;
}
+static inline void platform_udc_dtd_prepare(void)
+{ }
+static inline void platform_udc_ep_barrier(void)
+{ }
#endif
#endif
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
index a455a85741cb..413bcf58ab3a 100755
--- a/drivers/usb/gadget/tegra_udc.c
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -92,3 +92,18 @@ bool tegra_udc_charger_detection(void)
return Status.ChargerDetected;
}
+
+void tegra_udc_dtd_prepare(void)
+{
+ /* When we are programming two DTDs very close to each other,
+ * the second DTD is being prefetched before it is actually written
+ * to DDR. To prevent this, we disable prefetcher before programming
+ * any new DTD and re-enable it before priming endpoint.
+ */
+ NvDdkUsbPhyMemoryPrefetch(s_hUsbPhy, NV_FALSE);
+}
+
+void tegra_udc_ep_barrier(void)
+{
+ NvDdkUsbPhyMemoryPrefetch(s_hUsbPhy, NV_TRUE);
+}