aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorSantosh Shilimkar <santosh.shilimkar@ti.com>2011-06-25 21:04:31 -0400
committerKevin Hilman <khilman@ti.com>2011-12-08 14:29:01 -0500
commit137d105d50f6e6c373c1aa759f59045e6239cf66 (patch)
treedf510af5dfcaa172005adce4261ff06c60c76fca /arch/arm
parent49404dd09f5dc78c247c6044c60d7be7768a71bc (diff)
ARM: OMAP4: Fix errata i688 with MPU interconnect barriers.
On OMAP4 SOC, intecronnects has many write buffers in the async bridges and they need to be drained before CPU enters into standby state. Patch 'OMAP4: PM: Add CPUX OFF mode support' added CPU PM support but OMAP errata i688 (Async Bridge Corruption) needs to be taken care to avoid issues like system freeze, CPU deadlocks, random crashes with register accesses, synchronisation loss on initiators operating on both interconnect port simultaneously. As per the errata, 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 bridge can be found on path between MPU to EMIF and MPU to L3 interconnect. This situation can happen only when the idle is initiated by a Master Request Disconnection (which is trigged by software when executing WFI on CPU). The work-around for this errata needs all the initiators connected through async bridge must 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. Thanks to Russell for a tip to conver assembly function to C fuction there by reducing 40 odd lines of code from the patch. Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Richard Woodruff <r-woodruff2@ti.com> Acked-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Tested-by: Vishwanath BS <vishwanath.bs@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Kconfig21
-rw-r--r--arch/arm/mach-omap2/include/mach/barriers.h31
-rw-r--r--arch/arm/mach-omap2/io.c9
-rw-r--r--arch/arm/mach-omap2/omap4-common.c51
-rw-r--r--arch/arm/mach-omap2/sleep44xx.S8
-rw-r--r--arch/arm/plat-omap/include/plat/sram.h6
-rw-r--r--arch/arm/plat-omap/sram.c8
7 files changed, 133 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index b6625130831d..50f43942c1aa 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -353,6 +353,27 @@ config OMAP3_SDRC_AC_TIMING
353 wish to say no. Selecting yes without understanding what is 353 wish to say no. Selecting yes without understanding what is
354 going on could result in system crashes; 354 going on could result in system crashes;
355 355
356config OMAP4_ERRATA_I688
357 bool "OMAP4 errata: Async Bridge Corruption"
358 depends on ARCH_OMAP4
359 select ARCH_HAS_BARRIERS
360 help
361 If a data is stalled inside asynchronous bridge because of back
362 pressure, it may be accepted multiple times, creating pointer
363 misalignment that will corrupt next transfers on that data path
364 until next reset of the system (No recovery procedure once the
365 issue is hit, the path remains consistently broken). Async bridge
366 can be found on path between MPU to EMIF and MPU to L3 interconnect.
367 This situation can happen only when the idle is initiated by a
368 Master Request Disconnection (which is trigged by software when
369 executing WFI on CPU).
370 The work-around for this errata needs all the initiators connected
371 through async bridge must ensure that data path is properly drained
372 before issuing WFI. This condition will be met if one Strongly ordered
373 access is performed to the target right before executing the WFI.
374 In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained.
375 IO barrier ensure that there is no synchronisation loss on initiators
376 operating on both interconnect port simultaneously.
356endmenu 377endmenu
357 378
358endif 379endif
diff --git a/arch/arm/mach-omap2/include/mach/barriers.h b/arch/arm/mach-omap2/include/mach/barriers.h
new file mode 100644
index 000000000000..4fa72c7cc7cd
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/barriers.h
@@ -0,0 +1,31 @@
1/*
2 * OMAP memory barrier header.
3 *
4 * Copyright (C) 2011 Texas Instruments, Inc.
5 * Santosh Shilimkar <santosh.shilimkar@ti.com>
6 * Richard Woodruff <r-woodruff2@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifndef __MACH_BARRIERS_H
23#define __MACH_BARRIERS_H
24
25extern void omap_bus_sync(void);
26
27#define rmb() dsb()
28#define wmb() do { dsb(); outer_sync(); omap_bus_sync(); } while (0)
29#define mb() wmb()
30
31#endif /* __MACH_BARRIERS_H */
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 3f565dd2ea8d..65843390e7f0 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -237,6 +237,15 @@ static struct map_desc omap44xx_io_desc[] __initdata = {
237 .length = L4_EMU_44XX_SIZE, 237 .length = L4_EMU_44XX_SIZE,
238 .type = MT_DEVICE, 238 .type = MT_DEVICE,
239 }, 239 },
240#ifdef CONFIG_OMAP4_ERRATA_I688
241 {
242 .virtual = OMAP4_SRAM_VA,
243 .pfn = __phys_to_pfn(OMAP4_SRAM_PA),
244 .length = PAGE_SIZE,
245 .type = MT_MEMORY_SO,
246 },
247#endif
248
240}; 249};
241#endif 250#endif
242 251
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 1b93d31fe8e9..bc16c818c6b7 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -15,11 +15,14 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/memblock.h>
18 19
19#include <asm/hardware/gic.h> 20#include <asm/hardware/gic.h>
20#include <asm/hardware/cache-l2x0.h> 21#include <asm/hardware/cache-l2x0.h>
22#include <asm/mach/map.h>
21 23
22#include <plat/irqs.h> 24#include <plat/irqs.h>
25#include <plat/sram.h>
23 26
24#include <mach/hardware.h> 27#include <mach/hardware.h>
25#include <mach/omap-wakeupgen.h> 28#include <mach/omap-wakeupgen.h>
@@ -33,6 +36,54 @@ static void __iomem *l2cache_base;
33 36
34static void __iomem *sar_ram_base; 37static void __iomem *sar_ram_base;
35 38
39#ifdef CONFIG_OMAP4_ERRATA_I688
40/* Used to implement memory barrier on DRAM path */
41#define OMAP4_DRAM_BARRIER_VA 0xfe600000
42
43void __iomem *dram_sync, *sram_sync;
44
45void omap_bus_sync(void)
46{
47 if (dram_sync && sram_sync) {
48 writel_relaxed(readl_relaxed(dram_sync), dram_sync);
49 writel_relaxed(readl_relaxed(sram_sync), sram_sync);
50 isb();
51 }
52}
53
54static int __init omap_barriers_init(void)
55{
56 struct map_desc dram_io_desc[1];
57 phys_addr_t paddr;
58 u32 size;
59
60 if (!cpu_is_omap44xx())
61 return -ENODEV;
62
63 size = ALIGN(PAGE_SIZE, SZ_1M);
64 paddr = memblock_alloc(size, SZ_1M);
65 if (!paddr) {
66 pr_err("%s: failed to reserve 4 Kbytes\n", __func__);
67 return -ENOMEM;
68 }
69 memblock_free(paddr, size);
70 memblock_remove(paddr, size);
71 dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA;
72 dram_io_desc[0].pfn = __phys_to_pfn(paddr);
73 dram_io_desc[0].length = size;
74 dram_io_desc[0].type = MT_MEMORY_SO;
75 iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc));
76 dram_sync = (void __iomem *) dram_io_desc[0].virtual;
77 sram_sync = (void __iomem *) OMAP4_SRAM_VA;
78
79 pr_info("OMAP4: Map 0x%08llx to 0x%08lx for dram barrier\n",
80 (long long) paddr, dram_io_desc[0].virtual);
81
82 return 0;
83}
84core_initcall(omap_barriers_init);
85#endif
86
36void __init gic_init_irq(void) 87void __init gic_init_irq(void)
37{ 88{
38 void __iomem *omap_irq_base; 89 void __iomem *omap_irq_base;
diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
index 3154b63def35..abd283400490 100644
--- a/arch/arm/mach-omap2/sleep44xx.S
+++ b/arch/arm/mach-omap2/sleep44xx.S
@@ -325,8 +325,16 @@ skip_l2en:
325ENDPROC(omap4_cpu_resume) 325ENDPROC(omap4_cpu_resume)
326#endif 326#endif
327 327
328#ifndef CONFIG_OMAP4_ERRATA_I688
329ENTRY(omap_bus_sync)
330 mov pc, lr
331ENDPROC(omap_bus_sync)
332#endif
333
328ENTRY(omap_do_wfi) 334ENTRY(omap_do_wfi)
329 stmfd sp!, {lr} 335 stmfd sp!, {lr}
336 /* Drain interconnect write buffers. */
337 bl omap_bus_sync
330 338
331 /* 339 /*
332 * Execute an ISB instruction to ensure that all of the 340 * Execute an ISB instruction to ensure that all of the
diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h
index f500fc34d065..75aa1b2bef51 100644
--- a/arch/arm/plat-omap/include/plat/sram.h
+++ b/arch/arm/plat-omap/include/plat/sram.h
@@ -95,6 +95,10 @@ static inline void omap_push_sram_idle(void) {}
95 */ 95 */
96#define OMAP2_SRAM_PA 0x40200000 96#define OMAP2_SRAM_PA 0x40200000
97#define OMAP3_SRAM_PA 0x40200000 97#define OMAP3_SRAM_PA 0x40200000
98#ifdef CONFIG_OMAP4_ERRATA_I688
99#define OMAP4_SRAM_PA 0x40304000
100#define OMAP4_SRAM_VA 0xfe404000
101#else
98#define OMAP4_SRAM_PA 0x40300000 102#define OMAP4_SRAM_PA 0x40300000
99 103#endif
100#endif 104#endif
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 8b28664d1c62..ad6a71a00cef 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -40,7 +40,11 @@
40#define OMAP1_SRAM_PA 0x20000000 40#define OMAP1_SRAM_PA 0x20000000
41#define OMAP2_SRAM_PUB_PA (OMAP2_SRAM_PA + 0xf800) 41#define OMAP2_SRAM_PUB_PA (OMAP2_SRAM_PA + 0xf800)
42#define OMAP3_SRAM_PUB_PA (OMAP3_SRAM_PA + 0x8000) 42#define OMAP3_SRAM_PUB_PA (OMAP3_SRAM_PA + 0x8000)
43#ifdef CONFIG_OMAP4_ERRATA_I688
44#define OMAP4_SRAM_PUB_PA OMAP4_SRAM_PA
45#else
43#define OMAP4_SRAM_PUB_PA (OMAP4_SRAM_PA + 0x4000) 46#define OMAP4_SRAM_PUB_PA (OMAP4_SRAM_PA + 0x4000)
47#endif
44 48
45#if defined(CONFIG_ARCH_OMAP2PLUS) 49#if defined(CONFIG_ARCH_OMAP2PLUS)
46#define SRAM_BOOTLOADER_SZ 0x00 50#define SRAM_BOOTLOADER_SZ 0x00
@@ -163,6 +167,10 @@ static void __init omap_map_sram(void)
163 if (omap_sram_size == 0) 167 if (omap_sram_size == 0)
164 return; 168 return;
165 169
170#ifdef CONFIG_OMAP4_ERRATA_I688
171 omap_sram_start += PAGE_SIZE;
172 omap_sram_size -= SZ_16K;
173#endif
166 if (cpu_is_omap34xx()) { 174 if (cpu_is_omap34xx()) {
167 /* 175 /*
168 * SRAM must be marked as non-cached on OMAP3 since the 176 * SRAM must be marked as non-cached on OMAP3 since the