|
@@ -51,16 +51,73 @@ static void __iomem *twd_base;
|
|
|
|
|
|
#define IRQ_LOCALTIMER 29
|
|
|
|
|
|
-#ifdef CONFIG_OMAP4_ERRATA_I688
|
|
|
+#ifdef CONFIG_OMAP_INTERCONNECT_BARRIER
|
|
|
+
|
|
|
/* Used to implement memory barrier on DRAM path */
|
|
|
#define OMAP4_DRAM_BARRIER_VA 0xfe600000
|
|
|
|
|
|
-void __iomem *dram_sync, *sram_sync;
|
|
|
+static void __iomem *dram_sync, *sram_sync;
|
|
|
+static phys_addr_t dram_sync_paddr;
|
|
|
+static u32 dram_sync_size;
|
|
|
+
|
|
|
+/*
|
|
|
+ * The OMAP4 bus structure contains asynchrnous bridges which can buffer
|
|
|
+ * data writes from the MPU. These asynchronous bridges can be found on
|
|
|
+ * paths between the MPU to EMIF, and the MPU to L3 interconnects.
|
|
|
+ *
|
|
|
+ * We need to be careful about re-ordering which can happen as a result
|
|
|
+ * of different accesses being performed via different paths, and
|
|
|
+ * therefore different asynchronous bridges.
|
|
|
+ */
|
|
|
|
|
|
-static phys_addr_t paddr;
|
|
|
-static u32 size;
|
|
|
+/*
|
|
|
+ * OMAP4 interconnect barrier which is called for each mb() and wmb().
|
|
|
+ * This is to ensure that normal paths to DRAM (normal memory, cacheable
|
|
|
+ * accesses) are properly synchronised with writes to DMA coherent memory
|
|
|
+ * (normal memory, uncacheable) and device writes.
|
|
|
+ *
|
|
|
+ * The mb() and wmb() barriers only operate only on the MPU->MA->EMIF
|
|
|
+ * path, as we need to ensure that data is visible to other system
|
|
|
+ * masters prior to writes to those system masters being seen.
|
|
|
+ *
|
|
|
+ * Note: the SRAM path is not synchronised via mb() and wmb().
|
|
|
+ */
|
|
|
+static void omap4_mb(void)
|
|
|
+{
|
|
|
+ if (dram_sync)
|
|
|
+ writel_relaxed(0, dram_sync);
|
|
|
+}
|
|
|
|
|
|
-void omap_bus_sync(void)
|
|
|
+/*
|
|
|
+ * OMAP4 Errata i688 - asynchronous bridge corruption when entering WFI.
|
|
|
+ *
|
|
|
+ * If a data is stalled inside asynchronous bridge because of back
|
|
|
+ * pressure, it may be accepted multiple times, creating pointer
|
|
|
+ * misalignment that will corrupt next transfers on that data path until
|
|
|
+ * next reset of the system. No recovery procedure once the issue is hit,
|
|
|
+ * the path remains consistently broken.
|
|
|
+ *
|
|
|
+ * Async bridges can be found on paths between MPU to EMIF and MPU to L3
|
|
|
+ * interconnects.
|
|
|
+ *
|
|
|
+ * This situation can happen only when the idle is initiated by a Master
|
|
|
+ * Request Disconnection (which is trigged by software when executing WFI
|
|
|
+ * on the CPU).
|
|
|
+ *
|
|
|
+ * The work-around for this errata needs all the initiators connected
|
|
|
+ * through an async bridge to ensure that data path is properly drained
|
|
|
+ * before issuing WFI. This condition will be met if one Strongly ordered
|
|
|
+ * access is performed to the target right before executing the WFI.
|
|
|
+ *
|
|
|
+ * In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained.
|
|
|
+ * IO barrier ensure that there is no synchronisation loss on initiators
|
|
|
+ * operating on both interconnect port simultaneously.
|
|
|
+ *
|
|
|
+ * This is a stronger version of the OMAP4 memory barrier below, and
|
|
|
+ * operates on both the MPU->MA->EMIF path but also the MPU->OCP path
|
|
|
+ * as well, and is necessary prior to executing a WFI.
|
|
|
+ */
|
|
|
+void omap_interconnect_sync(void)
|
|
|
{
|
|
|
if (dram_sync && sram_sync) {
|
|
|
writel_relaxed(readl_relaxed(dram_sync), dram_sync);
|
|
@@ -68,7 +125,6 @@ void omap_bus_sync(void)
|
|
|
isb();
|
|
|
}
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omap_bus_sync);
|
|
|
|
|
|
static int __init omap4_sram_init(void)
|
|
|
{
|
|
@@ -79,7 +135,7 @@ static int __init omap4_sram_init(void)
|
|
|
if (!np)
|
|
|
pr_warn("%s:Unable to allocate sram needed to handle errata I688\n",
|
|
|
__func__);
|
|
|
- sram_pool = of_get_named_gen_pool(np, "sram", 0);
|
|
|
+ sram_pool = of_gen_pool_get(np, "sram", 0);
|
|
|
if (!sram_pool)
|
|
|
pr_warn("%s:Unable to get sram pool needed to handle errata I688\n",
|
|
|
__func__);
|
|
@@ -91,13 +147,10 @@ static int __init omap4_sram_init(void)
|
|
|
omap_arch_initcall(omap4_sram_init);
|
|
|
|
|
|
/* Steal one page physical memory for barrier implementation */
|
|
|
-int __init omap_barrier_reserve_memblock(void)
|
|
|
+void __init omap_barrier_reserve_memblock(void)
|
|
|
{
|
|
|
-
|
|
|
- size = ALIGN(PAGE_SIZE, SZ_1M);
|
|
|
- paddr = arm_memblock_steal(size, SZ_1M);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ dram_sync_size = ALIGN(PAGE_SIZE, SZ_1M);
|
|
|
+ dram_sync_paddr = arm_memblock_steal(dram_sync_size, SZ_1M);
|
|
|
}
|
|
|
|
|
|
void __init omap_barriers_init(void)
|
|
@@ -105,19 +158,18 @@ void __init omap_barriers_init(void)
|
|
|
struct map_desc dram_io_desc[1];
|
|
|
|
|
|
dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA;
|
|
|
- dram_io_desc[0].pfn = __phys_to_pfn(paddr);
|
|
|
- dram_io_desc[0].length = size;
|
|
|
+ dram_io_desc[0].pfn = __phys_to_pfn(dram_sync_paddr);
|
|
|
+ dram_io_desc[0].length = dram_sync_size;
|
|
|
dram_io_desc[0].type = MT_MEMORY_RW_SO;
|
|
|
iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc));
|
|
|
dram_sync = (void __iomem *) dram_io_desc[0].virtual;
|
|
|
|
|
|
- pr_info("OMAP4: Map 0x%08llx to 0x%08lx for dram barrier\n",
|
|
|
- (long long) paddr, dram_io_desc[0].virtual);
|
|
|
+ pr_info("OMAP4: Map %pa to %p for dram barrier\n",
|
|
|
+ &dram_sync_paddr, dram_sync);
|
|
|
|
|
|
+ soc_mb = omap4_mb;
|
|
|
}
|
|
|
-#else
|
|
|
-void __init omap_barriers_init(void)
|
|
|
-{}
|
|
|
+
|
|
|
#endif
|
|
|
|
|
|
void gic_dist_disable(void)
|