summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arc/include/asm/io.h95
-rw-r--r--arch/arc/lib/cache.c10
-rw-r--r--board/synopsys/axs101/axs101.c2
-rw-r--r--configs/axs103_defconfig2
4 files changed, 86 insertions, 23 deletions
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index b6f7724..42e7f22 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -10,6 +10,46 @@
#include <linux/types.h>
#include <asm/byteorder.h>
+#ifdef CONFIG_ISA_ARCV2
+
+/*
+ * ARCv2 based HS38 cores are in-order issue, but still weakly ordered
+ * due to micro-arch buffering/queuing of load/store, cache hit vs. miss ...
+ *
+ * Explicit barrier provided by DMB instruction
+ * - Operand supports fine grained load/store/load+store semantics
+ * - Ensures that selected memory operation issued before it will complete
+ * before any subsequent memory operation of same type
+ * - DMB guarantees SMP as well as local barrier semantics
+ * (asm-generic/barrier.h ensures sane smp_*mb if not defined here, i.e.
+ * UP: barrier(), SMP: smp_*mb == *mb)
+ * - DSYNC provides DMB+completion_of_cache_bpu_maintenance_ops hence not needed
+ * in the general case. Plus it only provides full barrier.
+ */
+
+#define mb() asm volatile("dmb 3\n" : : : "memory")
+#define rmb() asm volatile("dmb 1\n" : : : "memory")
+#define wmb() asm volatile("dmb 2\n" : : : "memory")
+
+#else
+
+/*
+ * ARCompact based cores (ARC700) only have SYNC instruction which is super
+ * heavy weight as it flushes the pipeline as well.
+ * There are no real SMP implementations of such cores.
+ */
+
+#define mb() asm volatile("sync\n" : : : "memory")
+#endif
+
+#ifdef CONFIG_ISA_ARCV2
+#define __iormb() rmb()
+#define __iowmb() wmb()
+#else
+#define __iormb() do { } while (0)
+#define __iowmb() do { } while (0)
+#endif
+
/*
* Given a physical address and a length, return a virtual address
* that can be used to access the memory range with the caching
@@ -72,18 +112,6 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
return w;
}
-#define readb __raw_readb
-
-static inline u16 readw(const volatile void __iomem *addr)
-{
- return __le16_to_cpu(__raw_readw(addr));
-}
-
-static inline u32 readl(const volatile void __iomem *addr)
-{
- return __le32_to_cpu(__raw_readl(addr));
-}
-
static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
{
__asm__ __volatile__("stb%U1 %0, %1\n"
@@ -108,10 +136,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
: "memory");
}
-#define writeb __raw_writeb
-#define writew(b, addr) __raw_writew(__cpu_to_le16(b), addr)
-#define writel(b, addr) __raw_writel(__cpu_to_le32(b), addr)
-
static inline int __raw_readsb(unsigned int addr, void *data, int bytelen)
{
__asm__ __volatile__ ("1:ld.di r8, [r0]\n"
@@ -184,6 +208,45 @@ static inline int __raw_writesl(unsigned int addr, void *data, int longlen)
return longlen;
}
+/*
+ * MMIO can also get buffered/optimized in micro-arch, so barriers needed
+ * Based on ARM model for the typical use case
+ *
+ * <ST [DMA buffer]>
+ * <writel MMIO "go" reg>
+ * or:
+ * <readl MMIO "status" reg>
+ * <LD [DMA buffer]>
+ *
+ * http://lkml.kernel.org/r/20150622133656.GG1583@arm.com
+ */
+#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
+#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
+#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+
+#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
+#define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
+#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
+
+/*
+ * Relaxed API for drivers which can handle barrier ordering themselves
+ *
+ * Also these are defined to perform little endian accesses.
+ * To provide the typical device register semantics of fixed endian,
+ * swap the byte order for Big Endian
+ *
+ * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de
+ */
+#define readb_relaxed(c) __raw_readb(c)
+#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
+ __raw_readw(c)); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+ __raw_readl(c)); __r; })
+
+#define writeb_relaxed(v,c) __raw_writeb(v,c)
+#define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c)
+#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c)
+
#define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v), a)
#define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a))
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c
index d1fb661..b6ec831 100644
--- a/arch/arc/lib/cache.c
+++ b/arch/arc/lib/cache.c
@@ -209,6 +209,9 @@ void cache_init(void)
read_decode_cache_bcr_arcv2();
if (ioc_exists) {
+ flush_dcache_all();
+ invalidate_dcache_all();
+
/* IO coherency base - 0x8z */
write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000);
/* IO coherency aperture size - 512Mb: 0x8z-0xAz */
@@ -417,13 +420,10 @@ void flush_cache(unsigned long start, unsigned long size)
void invalidate_dcache_all(void)
{
-#ifdef CONFIG_ISA_ARCV2
- if (!ioc_exists)
-#endif
- __dc_entire_op(OP_INV);
+ __dc_entire_op(OP_INV);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists && !ioc_exists)
+ if (slc_exists)
__slc_entire_op(OP_INV);
#endif
}
diff --git a/board/synopsys/axs101/axs101.c b/board/synopsys/axs101/axs101.c
index 84ee2bf..a5e774b 100644
--- a/board/synopsys/axs101/axs101.c
+++ b/board/synopsys/axs101/axs101.c
@@ -54,7 +54,7 @@ void smp_set_core_boot_addr(unsigned long addr, int corenr)
writel(addr, (void __iomem *)RESET_VECTOR_ADDR);
/* Make sure other cores see written value in memory */
- flush_dcache_range(RESET_VECTOR_ADDR, RESET_VECTOR_ADDR + sizeof(int));
+ flush_dcache_all();
}
void smp_kick_all_cpus(void)
diff --git a/configs/axs103_defconfig b/configs/axs103_defconfig
index 96a3de6..c8474de 100644
--- a/configs/axs103_defconfig
+++ b/configs/axs103_defconfig
@@ -1,7 +1,7 @@
CONFIG_ARC=y
CONFIG_ISA_ARCV2=y
CONFIG_DM_SERIAL=y
-CONFIG_SYS_CLK_FREQ=50000000
+CONFIG_SYS_CLK_FREQ=100000000
CONFIG_SYS_TEXT_BASE=0x81000000
CONFIG_DEFAULT_DEVICE_TREE="axs10x"
CONFIG_BOOTDELAY=3