usb: gadget: tegra: Enable AHB prefetch
Krishna Yarlagadda [Wed, 18 Apr 2012 04:40:46 +0000 (09:40 +0530)]
Enable AHB prefetch and call dma_sync
to avoid memory coherency issues

Bug 921109

Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-on: http://git-master/r/92257
(cherry picked from commit e8fac4b6f3460928442d6c9dadec301ccf57fb0b)

Change-Id: I2788e94d3609bfdd6d112f0b5386a653af15075e
Reviewed-on: http://git-master/r/93819
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Tested-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>

Conflicts:

drivers/usb/gadget/fsl_udc_core.c

Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>

drivers/usb/gadget/fsl_tegra_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fsl_usb2_udc.h

index b254258..31b476a 100644 (file)
@@ -153,3 +153,18 @@ bool fsl_udc_charger_detect(void)
 {
        return tegra_usb_phy_charger_detect(phy);
 }
+
+void fsl_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.
+        */
+       tegra_usb_phy_memory_prefetch_off(phy);
+}
+
+void fsl_udc_ep_barrier(void)
+{
+       tegra_usb_phy_memory_prefetch_on(phy);
+}
index 6a50d2d..ac96d33 100644 (file)
@@ -879,6 +879,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
                        return;
        }
 
+#if defined(CONFIG_ARCH_TEGRA)
+       fsl_udc_ep_barrier();
+#endif
+
        fsl_prime_ep(ep, req->head);
 }
 
@@ -956,6 +960,10 @@ static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
        struct ep_td_struct     *last_dtd = NULL, *dtd;
        dma_addr_t dma;
 
+#if defined(CONFIG_ARCH_TEGRA)
+       fsl_udc_dtd_prepare();
+#endif
+
        do {
                dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
                if (dtd == NULL)
@@ -1942,6 +1950,13 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
        actual = curr_req->req.length;
 
        for (j = 0; j < curr_req->dtd_count; j++) {
+#ifdef CONFIG_ARCH_TEGRA
+               /* Fence read for coherency of AHB master intiated writes */
+               readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+#endif
+               dma_sync_single_for_cpu(udc->gadget.dev.parent, curr_td->td_dma,
+                       sizeof(struct ep_td_struct), DMA_FROM_DEVICE);
+
                remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
                                        & DTD_PACKET_SIZE)
                                >> DTD_LENGTH_BIT_POS;
index 7d0637c..efadcd3 100644 (file)
@@ -735,6 +735,8 @@ void fsl_udc_clk_resume(bool is_dpd);
 void fsl_udc_clk_enable(void);
 void fsl_udc_clk_disable(void);
 bool fsl_udc_charger_detect(void);
+void fsl_udc_dtd_prepare(void);
+void fsl_udc_ep_barrier(void);
 #else
 static inline int fsl_udc_clk_init(struct platform_device *pdev)
 {
@@ -762,6 +764,12 @@ static inline bool fsl_udc_charger_detect(void)
 {
        return false;
 }
+void fsl_udc_dtd_prepare(void)
+{
+}
+void fsl_udc_ep_barrier(void)
+{
+}
 #endif
 
 #endif