sh: add support for J-Core J2 processor
authorRich Felker <dalias@libc.org>
Thu, 17 Mar 2016 23:09:37 +0000 (23:09 +0000)
committerRich Felker <dalias@libc.org>
Fri, 5 Aug 2016 03:29:31 +0000 (03:29 +0000)
At the CPU/ISA level, the J2 is compatible with SH-2, and thus the
changes to add J2 support build on existing SH-2 support. However, J2
does not duplicate the memory-mapped SH-2 features like the cache
interface. Instead, the cache interfaces is described in the device
tree, and new code is added to be able to access the flat device tree
at early boot before it is unflattened.

Support is also added for receiving interrupts on trap numbers in the
range 16 to 31, since the J-Core aic1 interrupt controller generates
these traps. This range was unused but nominally for hardware
exceptions on SH-2, and a few values in this range were used for
exceptions on SH-2A, but SH-2A has its own version of the relevant
code.

No individual cpu subtypes are added for J2 since the intent moving
forward is to represent SoCs with device tree rather than as
hard-coded subtypes in the kernel. The CPU_SUBTYPE_J2 Kconfig item
exists only to fit into the existing cpu selection mechanism until it
is overhauled.

Signed-off-by: Rich Felker <dalias@libc.org>
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/include/asm/processor.h
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/proc.c
arch/sh/kernel/cpu/sh2/entry.S
arch/sh/kernel/cpu/sh2/probe.c
arch/sh/mm/Makefile
arch/sh/mm/cache-j2.c [new file with mode: 0644]
arch/sh/mm/cache.c

index df6339d7bf72fbff5a085ea675e202793625ba04..2ef6f652bc500dd65e1b409fe465039c3622daaa 100644 (file)
@@ -186,6 +186,12 @@ config CPU_SH2A
        select CPU_SH2
        select UNCACHED_MAPPING
 
+config CPU_J2
+       bool
+       select CPU_SH2
+       select OF
+       select OF_EARLY_FLATTREE
+
 config CPU_SH3
        bool
        select CPU_HAS_INTEVT
@@ -252,6 +258,10 @@ config CPU_SUBTYPE_SH7619
        select CPU_SH2
        select SYS_SUPPORTS_SH_CMT
 
+config CPU_SUBTYPE_J2
+       bool "Support J2 processor"
+       select CPU_J2
+
 # SH-2A Processor Support
 
 config CPU_SUBTYPE_SH7201
index 3b2c8b4827d0b9b82d81a1acb352ad360a38cd95..00476662ac2c07ba1e0a3bb427e114ae2f5a7650 100644 (file)
@@ -31,6 +31,7 @@ isa-y                                 := $(isa-y)-up
 endif
 
 cflags-$(CONFIG_CPU_SH2)               := $(call cc-option,-m2,)
+cflags-$(CONFIG_CPU_J2)                        := $(call cc-option,-mj2,)
 cflags-$(CONFIG_CPU_SH2A)              += $(call cc-option,-m2a,) \
                                           $(call cc-option,-m2a-nofpu,) \
                                           $(call cc-option,-m4-nofpu,)
index 1506897648aa17ce0d594b2d1068fc7988a70095..f9a09942a32d37249b43ec4139762aaafa16443d 100644 (file)
@@ -15,7 +15,7 @@
  */
 enum cpu_type {
        /* SH-2 types */
-       CPU_SH7619,
+       CPU_SH7619, CPU_J2,
 
        /* SH-2A types */
        CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269,
index bfd9e2798008051a6b18c69ccf0357d9bfd13210..c8b3be1b54e6e810e4f116fe2264d7a79f267b14 100644 (file)
@@ -106,7 +106,7 @@ void __attribute__ ((weak)) l2_cache_init(void)
 /*
  * Generic first-level cache init
  */
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_CPU_J2)
 static void cache_init(void)
 {
        unsigned long ccr, flags;
index 9e6624c9108bcf77bbc525909195c2a0cb6e5d69..4df4b284f5915bcbb21a6e2fd809bf7baa44c75d 100644 (file)
@@ -27,6 +27,7 @@ static const char *cpu_name[] = {
        [CPU_MXG]       = "MX-G",       [CPU_SH7723]    = "SH7723",
        [CPU_SH7366]    = "SH7366",     [CPU_SH7724]    = "SH7724",
        [CPU_SH7372]    = "SH7372",     [CPU_SH7734]    = "SH7734",
+       [CPU_J2]        = "J2",
        [CPU_SH_NONE]   = "Unknown"
 };
 
index a1505956ef28b4f0fd694cc4d1c609281b782811..16bde0efaca37b68dd696f1164bbd8b11e64a319 100644 (file)
@@ -147,6 +147,11 @@ ENTRY(exception_handler)
        mov     #31,r8
        cmp/hs  r8,r9
        bt      trap_entry      ! 64 > vec >= 31  is trap
+#ifdef CONFIG_CPU_J2
+       mov     #16,r8
+       cmp/hs  r8,r9
+       bt      interrupt_entry ! 31 > vec >= 16 is interrupt
+#endif
 
        mov.l   4f,r8
        mov     r9,r4
index 6c687ae812ef6aa89087d3bced828ee580d2a325..152184007964002d740dc149c687ddc960748b85 100644 (file)
  * for more details.
  */
 #include <linux/init.h>
+#include <linux/of_fdt.h>
+#include <linux/smp.h>
+#include <linux/io.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
-void cpu_probe(void)
+#if defined(CONFIG_CPU_J2)
+extern u32 __iomem *j2_ccr_base;
+static int __init scan_cache(unsigned long node, const char *uname,
+                            int depth, void *data)
+{
+       if (!of_flat_dt_is_compatible(node, "jcore,cache"))
+               return 0;
+
+       j2_ccr_base = (u32 __iomem *)of_flat_dt_translate_address(node);
+
+       return 1;
+}
+#endif
+
+void __ref cpu_probe(void)
 {
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
        boot_cpu_data.type                      = CPU_SH7619;
@@ -24,10 +41,28 @@ void cpu_probe(void)
        boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
        boot_cpu_data.dcache.flags              = 0;
 #endif
+
+#if defined(CONFIG_CPU_J2)
+       unsigned cpu = hard_smp_processor_id();
+       if (cpu == 0) of_scan_flat_dt(scan_cache, NULL);
+       if (j2_ccr_base) __raw_writel(0x80000303, j2_ccr_base + 4*cpu);
+       if (cpu != 0) return;
+       boot_cpu_data.type                      = CPU_J2;
+
+       /* These defaults are appropriate for the original/current
+        * J2 cache. Once there is a proper framework for getting cache
+        * info from device tree, we should switch to that. */
+       boot_cpu_data.dcache.ways               = 1;
+       boot_cpu_data.dcache.sets               = 256;
+       boot_cpu_data.dcache.entry_shift        = 5;
+       boot_cpu_data.dcache.linesz             = 32;
+       boot_cpu_data.dcache.flags              = 0;
+#else
        /*
         * SH-2 doesn't have separate caches
         */
        boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+#endif
        boot_cpu_data.icache = boot_cpu_data.dcache;
        boot_cpu_data.family = CPU_FAMILY_SH2;
 }
index cee6b9999d86011781e6a973270967c7e937762f..92c3bd96aee56fea8df2c393d1810b827849da57 100644 (file)
@@ -4,7 +4,8 @@
 
 obj-y                  := alignment.o cache.o init.o consistent.o mmap.o
 
-cacheops-$(CONFIG_CPU_SH2)             := cache-sh2.o
+cacheops-$(CONFIG_CPU_J2)              := cache-j2.o
+cacheops-$(CONFIG_CPU_SUBTYPE_SH7619)  := cache-sh2.o
 cacheops-$(CONFIG_CPU_SH2A)            := cache-sh2a.o
 cacheops-$(CONFIG_CPU_SH3)             := cache-sh3.o
 cacheops-$(CONFIG_CPU_SH4)             := cache-sh4.o flush-sh4.o
diff --git a/arch/sh/mm/cache-j2.c b/arch/sh/mm/cache-j2.c
new file mode 100644 (file)
index 0000000..391698b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * arch/sh/mm/cache-j2.c
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpumask.h>
+
+#include <asm/cache.h>
+#include <asm/addrspace.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+
+#define ICACHE_ENABLE  0x1
+#define DCACHE_ENABLE  0x2
+#define CACHE_ENABLE   (ICACHE_ENABLE | DCACHE_ENABLE)
+#define ICACHE_FLUSH   0x100
+#define DCACHE_FLUSH   0x200
+#define CACHE_FLUSH    (ICACHE_FLUSH | DCACHE_FLUSH)
+
+u32 __iomem *j2_ccr_base;
+
+static void j2_flush_icache(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | ICACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+static void j2_flush_dcache(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | DCACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+static void j2_flush_both(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | CACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+void __init j2_cache_init(void)
+{
+       if (!j2_ccr_base)
+               return;
+
+       local_flush_cache_all = j2_flush_both;
+       local_flush_cache_mm = j2_flush_both;
+       local_flush_cache_dup_mm = j2_flush_both;
+       local_flush_cache_page = j2_flush_both;
+       local_flush_cache_range = j2_flush_both;
+       local_flush_dcache_page = j2_flush_dcache;
+       local_flush_icache_range = j2_flush_icache;
+       local_flush_icache_page = j2_flush_icache;
+       local_flush_cache_sigtramp = j2_flush_icache;
+
+       pr_info("Initial J2 CCR is %.8x\n", __raw_readl(j2_ccr_base));
+}
index 776d664a40c5f2fd4298f25b5ec010605ac0532d..70cc52f2fab82860b920978e7f1a6a16acdf3203 100644 (file)
@@ -309,7 +309,11 @@ void __init cpu_cache_init(void)
        if (unlikely(cache_disabled))
                goto skip;
 
-       if (boot_cpu_data.family == CPU_FAMILY_SH2) {
+       if (boot_cpu_data.type == CPU_J2) {
+               extern void __weak j2_cache_init(void);
+
+               j2_cache_init();
+       } else if (boot_cpu_data.family == CPU_FAMILY_SH2) {
                extern void __weak sh2_cache_init(void);
 
                sh2_cache_init();