[J-core] Kernel patches series for J2 support via device tree

Rich Felker dalias at libc.org
Tue Apr 26 22:51:46 EDT 2016


Attached is my current pending Linux kernel patch series for J2
support, in git-am mbox format. It consists of several pending patches
for issues affecting sh/nommu, baseline uniprocessor J2 support,
device drivers for J-core peripherals (interrupt controller,
timer/rtc, spi controller), defconfig and device tree, and a couple
small hacks (disabling sdcard rescan, timer interrupt led-flasher).
The patches are against 4.6-rc4 but at this point it's sufficiently
stabilized that they should apply cleanly on later rc's and 4.6 final
once it's available.

Soon I'll repost just the J2 parts on the linux-sh list (as a proper
patch-series thread) but I wanted to post it here first to give the
J-core community a chance to try it out and catch any stupid mistakes
I may have made preparing it.

Device tree bindings (still drafts; we need to register these
officially) have changed, so if you have an earlier kernel/dtb from
ELC or the website, make sure you rebuild the device tree:

./scripts/dtc/dtc -o dt.dtb arch/sh/boot/dts/j2_mimas_v2.dts

and put the resulting new dt.dtb on the SD card. Alternatively you can
configure the kernel for built-in device tree "j2_mimas_v2".

The provided j2_defconfig should work almost out of the box, but you
need to set your cross-compiler prefix ("sh2eb-linux-muslfdpic-" works
if you have my cross compiler) and paths to userspace files for the
initramfs. In principle you could put an ext2 fs as the second
partition on the SD card and use it as the root device instead of
initramfs, but this is untested and likely to be slow.

Hopefully I didn't miss anything important. Let me know if you run
into problems and I'll try to help sort them out.

Rich
-------------- next part --------------
>From dd197fd3d17074844d16077fe400c410e7713dea Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Wed, 9 Dec 2015 19:37:53 +0000
Subject: [PATCH 01/16] ramfs: fix VM_MAYSHARE mappings for NOMMU

The nommu do_mmap expects f_op->get_unmapped_area to either succeed or
return -ENOSYS for VM_MAYSHARE (e.g. private read-only) mappings.
Returning addr in the non-MAP_SHARED case was completely wrong, and
only happened to work because addr was 0. However, it prevented
VM_MAYSHARE mappings from sharing backing with the fs cache, and
forced such mappings (including shareable program text) to be copied
whenever the number of mappings transitioned from 0 to 1, impacting
performance and memory usage. Subsequent mappings beyond the first
still correctly shared memory with the first.

Instead, treat VM_MAYSHARE identically to VM_SHARED at the file ops
level; do_mmap already handles the semantic differences between them.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 fs/ramfs/file-nommu.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index a586467..be3ddd1 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -211,14 +211,11 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
 	struct page **pages = NULL, **ptr, *page;
 	loff_t isize;
 
-	if (!(flags & MAP_SHARED))
-		return addr;
-
 	/* the mapping mustn't extend beyond the EOF */
 	lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	isize = i_size_read(inode);
 
-	ret = -EINVAL;
+	ret = -ENOSYS;
 	maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	if (pgoff >= maxpages)
 		goto out;
@@ -227,7 +224,6 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
 		goto out;
 
 	/* gang-find the pages */
-	ret = -ENOMEM;
 	pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL);
 	if (!pages)
 		goto out_free;
@@ -263,7 +259,7 @@ out:
  */
 static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	if (!(vma->vm_flags & VM_SHARED))
+	if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE)))
 		return -ENOSYS;
 
 	file_accessed(file);
-- 
2.8.1


>From 1369a46479c205a2506106dbd12c6ff74884e470 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Mon, 25 Apr 2016 03:01:18 +0000
Subject: [PATCH 02/16] futex: fix shared futex operations on nommu

The shared get_futex_key code does not work on nommu, but is not
needed anyway because it's impossible for a given backing to have
multiple distinct virtual addresses on nommu. Simply disable these
code paths by refraining from setting FLAG_SHARED when CONFIG_MMU is
not enabled.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 kernel/futex.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/kernel/futex.c b/kernel/futex.c
index a5d2e74..ed6f475 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -3131,8 +3131,10 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 	int cmd = op & FUTEX_CMD_MASK;
 	unsigned int flags = 0;
 
+#ifdef CONFIG_MMU
 	if (!(op & FUTEX_PRIVATE_FLAG))
 		flags |= FLAGS_SHARED;
+#endif
 
 	if (op & FUTEX_CLOCK_REALTIME) {
 		flags |= FLAGS_CLOCKRT;
-- 
2.8.1


>From ed8ee1562132edc19afb45eea346482f14d53f1e Mon Sep 17 00:00:00 2001
From: Pan Xinhui <xinhui.pan at linux.vnet.ibm.com>
Date: Wed, 20 Apr 2016 14:41:00 +0800
Subject: [PATCH 03/16] sh: cmpxchg: fix a bit shift bug in big_endian os

Correct bitoff in big endian OS.
Current code works correctly for 1 byte but not for 2 bytes.

Fixes: 3226aad81aa6 ("sh: support 1 and 2 byte xchg")
Signed-off-by: Pan Xinhui <xinhui.pan at linux.vnet.ibm.com>
Acked-by: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/include/asm/cmpxchg-xchg.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/sh/include/asm/cmpxchg-xchg.h b/arch/sh/include/asm/cmpxchg-xchg.h
index 7219719..1e881f5 100644
--- a/arch/sh/include/asm/cmpxchg-xchg.h
+++ b/arch/sh/include/asm/cmpxchg-xchg.h
@@ -21,7 +21,7 @@ static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size)
 	int off = (unsigned long)ptr % sizeof(u32);
 	volatile u32 *p = ptr - off;
 #ifdef __BIG_ENDIAN
-	int bitoff = (sizeof(u32) - 1 - off) * BITS_PER_BYTE;
+	int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 #else
 	int bitoff = off * BITS_PER_BYTE;
 #endif
-- 
2.8.1


>From a3c632bb3d0e38d7b5c7c9cb5d8f2a38a3017ea1 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Sat, 26 Mar 2016 01:24:30 +0000
Subject: [PATCH 04/16] sh: add support for linking a builtin device tree blob
 in the kernel

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/Kconfig             | 20 ++++++++++++++++++++
 arch/sh/Makefile            |  2 ++
 arch/sh/boards/of-generic.c | 15 ++++++++++++---
 arch/sh/boot/dts/Makefile   |  3 +++
 arch/sh/kernel/setup.c      |  4 ++++
 5 files changed, 41 insertions(+), 3 deletions(-)
 create mode 100644 arch/sh/boot/dts/Makefile

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 7ed20fc..0223e5e 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -745,6 +745,26 @@ endmenu
 
 menu "Boot options"
 
+config USE_BUILTIN_DTB
+	bool "Use builtin DTB"
+	default n
+	depends on SH_DEVICE_TREE
+	help
+	  Link a device tree blob for particular hardware into the kernel,
+	  suppressing use of the DTB pointer provided by the bootloader.
+	  This option should only be used with legacy bootloaders that are
+	  not capable of providing a DTB to the kernel, or for experimental
+	  hardware without stable device tree bindings.
+
+config BUILTIN_DTB_SOURCE
+	string "Source file for builtin DTB"
+	default ""
+	depends on USE_BUILTIN_DTB
+	help
+	  Base name (without suffix, relative to arch/sh/boot/dts) for the
+	  a DTS file that will be used to produce the DTB linked into the
+	  kernel.
+
 config ZERO_PAGE_OFFSET
 	hex
 	default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index bf5b3f5..3b2c8b4 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -130,6 +130,8 @@ head-y	:= arch/sh/kernel/head_$(BITS).o
 core-y				+= arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/
 core-$(CONFIG_SH_FPU_EMU)	+= arch/sh/math-emu/
 
+core-$(CONFIG_USE_BUILTIN_DTB)	+= arch/sh/boot/dts/
+
 # Mach groups
 machdir-$(CONFIG_SOLUTION_ENGINE)		+= mach-se
 machdir-$(CONFIG_SH_HP6XX)			+= mach-hp6xx
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
index bf3a166..57d45dc 100644
--- a/arch/sh/boards/of-generic.c
+++ b/arch/sh/boards/of-generic.c
@@ -126,13 +126,22 @@ static void __init sh_of_time_init(void)
 
 static void __init sh_of_setup(char **cmdline_p)
 {
+	struct device_node *root;
+
+#ifdef CONFIG_USE_BUILTIN_DTB
+	unflatten_and_copy_device_tree();
+#else
 	unflatten_device_tree();
+#endif
 
 	board_time_init = sh_of_time_init;
 
-	sh_mv.mv_name = of_flat_dt_get_machine_name();
-	if (!sh_mv.mv_name)
-		sh_mv.mv_name = "Unknown SH model";
+	sh_mv.mv_name = "Unknown SH model";
+	root = of_find_node_by_path("/");
+	if (root) {
+		of_property_read_string(root, "model", &sh_mv.mv_name);
+		of_node_put(root);
+	}
 
 	sh_of_smp_probe();
 }
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
new file mode 100644
index 0000000..e5ce3a0
--- /dev/null
+++ b/arch/sh/boot/dts/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+
+clean-files := *.dtb.S
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 5d34605..5b9eb70 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -251,7 +251,11 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
 	/* Avoid calling an __init function on secondary cpus. */
 	if (done) return;
 
+#ifdef CONFIG_USE_BUILTIN_DTB
+	dt_virt = __dtb_start;
+#else
 	dt_virt = phys_to_virt(dt_phys);
+#endif
 
 	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
 		pr_crit("Error: invalid device tree blob"
-- 
2.8.1


>From 58fd9c25d2bfc8da20957c48cc2dbf4e7f62c61d Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Fri, 1 Apr 2016 20:10:19 +0000
Subject: [PATCH 05/16] sh: make sigcontext definition consistent across
 fpu/nofpu models

Up until now, the SH version of the sigcontext structure, and thus
mcontext_t/ucontext_t, varied depending on the cpu model the kernel
was built to run on. SH-4 (including SH-4A) and SH-2A used the form
with space for FPU registers, and everything else used a form that
omitted them.

>From a userspace perspective, however, the structure layout must be
fixed for a given ABI. Traditionally glibc and uClibc used the form
with space for FPU registers only when __SH4__ (which implies FPU;
__SH4_NOFPU__ is the predefined macro for SH-4 but with no-FPU ABI)
was defined. As a result:

- SH-4 no-FPU programs never matched kernel sigcontext.

- SH-3 programs did not match kernel sigcontext if run on SH-4,
  despite an apparent intent that they be compatible.

- SH-2 and SH-2A programs (using uClibc) did not match kernel
  sigcontext if run on SH-2A.

The mismatch might seem inconsequential because it occurs at the end
of the sigcontext structure, but sigcontext is embedded as uc_mcontext
in ucontext_t, where it is followed by uc_sigmask, an important member
for signal handlers to have access to. In particular, access to
uc_sigmask is necessary for a correct implementation of thread
cancellation.

It would be possible to retain support for both sigcontext ABIs via a
personality mechanism, but since many configurations were already
broken and nobody noticed, and since there are very few if any users
of legacy no-FPU models anymore, I have opted to just remove the
variation and always include space for the FPU registers in
sigcontext. This was proposed and discussed on a thread "SH sigcontext
ABI is broken" cross-posted to linux-sh, libc-alpha, and musl libc
lists in June 2015, and no objections were raised.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/include/uapi/asm/sigcontext.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/sh/include/uapi/asm/sigcontext.h b/arch/sh/include/uapi/asm/sigcontext.h
index 8ce1435..faa5d08 100644
--- a/arch/sh/include/uapi/asm/sigcontext.h
+++ b/arch/sh/include/uapi/asm/sigcontext.h
@@ -25,8 +25,6 @@ struct sigcontext {
 	unsigned long sc_mach;
 	unsigned long sc_macl;
 
-#if defined(__SH4__) || defined(CONFIG_CPU_SH4) || \
-    defined(__SH2A__) || defined(CONFIG_CPU_SH2A)
 	/* FPU registers */
 	unsigned long sc_fpregs[16];
 	unsigned long sc_xfpregs[16];
@@ -34,7 +32,6 @@ struct sigcontext {
 	unsigned int sc_fpul;
 	unsigned int sc_ownedfp;
 #endif
-#endif
 };
 
 #endif /* __ASM_SH_SIGCONTEXT_H */
-- 
2.8.1


>From 1d3c0e12345558578f7853688322b3da5718c8d9 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Tue, 22 Mar 2016 22:02:23 +0000
Subject: [PATCH 06/16] sh: disable aliased page logic on NOMMU models

SH3/4 (with MMU) have a virtually indexed cache, requiring explicit
work to avoid consistency problems arising from having the same
physical address range cached in multiple cache lines. This is
unneeded for the NOMMU case, and some of the resulting code paths
(kmap_coherent) don't work. SH2 only avoided this problem by having a
4-way associative cache with way size equal to the page size (4k),
yielding no cache index bits outside of the page offset and thus no
aliases.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/kernel/cpu/init.c | 4 ++++
 arch/sh/mm/cache.c        | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 0d7360d..bfd9e27 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -323,9 +323,13 @@ asmlinkage void cpu_init(void)
 	cache_init();
 
 	if (raw_smp_processor_id() == 0) {
+#ifdef CONFIG_MMU
 		shm_align_mask = max_t(unsigned long,
 				       current_cpu_data.dcache.way_size - 1,
 				       PAGE_SIZE - 1);
+#else
+		shm_align_mask = PAGE_SIZE - 1;
+#endif
 
 		/* Boot CPU sets the cache shape */
 		detect_cache_shape();
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index e58cfbf..776d664 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -244,7 +244,11 @@ void flush_cache_sigtramp(unsigned long address)
 
 static void compute_alias(struct cache_info *c)
 {
+#ifdef CONFIG_MMU
 	c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
+#else
+	c->alias_mask = 0;
+#endif
 	c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0;
 }
 
-- 
2.8.1


>From f91f7bfef76fad5f973be77d94a85b88afd1abed Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Mon, 25 Apr 2016 02:55:51 +0000
Subject: [PATCH 07/16] sh: fix futex/robust_list on nommu models

The futex cmpxchg runtime testing in kernel/futex.c depends on
accesses to address 0 producing EFAULT, which obviously does not work
on nommu. Since SH always has cmpxchg, disable the broken runtime
detection.

At some point this should be fixed at the kernel/futex.c level. UP
machines can always provide a working cmpxchg with interrupt masking,
and SMP cannot function without a working cmpxchg anyway.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 0223e5e..4fa5894 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -44,6 +44,7 @@ config SUPERH
 	select OLD_SIGSUSPEND
 	select OLD_SIGACTION
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_FUTEX_CMPXCHG if FUTEX
 	help
 	  The SuperH is a RISC processor targeted for use in embedded systems
 	  and consumer electronics; it was also used in the Sega Dreamcast
-- 
2.8.1


>From 30651576b10cbc1a71bbfd49091c845aa52a70cb Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Thu, 17 Mar 2016 23:09:37 +0000
Subject: [PATCH 08/16] sh: add support for J-Core J2 processor

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/Kconfig                 |  8 ++++++
 arch/sh/Makefile                |  1 +
 arch/sh/include/asm/processor.h |  2 +-
 arch/sh/kernel/cpu/init.c       | 40 +++++++++++++++++++++++++++-
 arch/sh/kernel/cpu/proc.c       |  1 +
 arch/sh/kernel/cpu/sh2/entry.S  |  5 ++++
 arch/sh/kernel/cpu/sh2/probe.c  | 11 ++++++++
 arch/sh/mm/Makefile             |  3 ++-
 arch/sh/mm/cache-j2.c           | 58 +++++++++++++++++++++++++++++++++++++++++
 arch/sh/mm/cache.c              |  6 ++++-
 10 files changed, 131 insertions(+), 4 deletions(-)
 create mode 100644 arch/sh/mm/cache-j2.c

diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 4fa5894..efb0af4 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -182,6 +182,10 @@ config CPU_SH2A
 	select CPU_SH2
 	select UNCACHED_MAPPING
 
+config CPU_J2
+	bool
+	select CPU_SH2
+
 config CPU_SH3
 	bool
 	select CPU_HAS_INTEVT
@@ -248,6 +252,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
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 3b2c8b4..0047666 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -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,)
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 1506897..f9a0994 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -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,
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index bfd9e27..9de52b9 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -14,6 +14,10 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/log2.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+#include <linux/smp.h>
+#include <linux/cpumask.h>
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
@@ -106,7 +110,41 @@ void __attribute__ ((weak)) l2_cache_init(void)
 /*
  * Generic first-level cache init
  */
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_CPU_J2)
+extern u32 j2_ccr_base, j2_ccr_cpu_offset;
+static int __init scan_cache(unsigned long node, const char *uname,
+			     int depth, void *data)
+{
+	const __be32 *prop;
+
+	if (!of_flat_dt_is_compatible(node, "jcore,cache"))
+		return 0;
+
+	j2_ccr_base = of_flat_dt_translate_address(node);
+
+	prop = fdt_getprop(initial_boot_params, node, "cpu-offset", NULL);
+	if (prop)
+		j2_ccr_cpu_offset = dt_mem_next_cell(1, &prop);
+
+	return 1;
+}
+static void __ref cache_init(void)
+{
+	static int done = 0;
+
+	/* Avoid calling an __init function on secondary cpus. */
+	if (!done) {
+		of_scan_flat_dt(scan_cache, NULL);
+		done = 1;
+	}
+
+	if (!j2_ccr_base)
+		return;
+
+	__raw_writel(0x80000303,
+		     j2_ccr_base + hard_smp_processor_id() * j2_ccr_cpu_offset);
+}
+#elif defined(CONFIG_SUPERH32)
 static void cache_init(void)
 {
 	unsigned long ccr, flags;
diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c
index 9e6624c..4df4b28 100644
--- a/arch/sh/kernel/cpu/proc.c
+++ b/arch/sh/kernel/cpu/proc.c
@@ -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"
 };
 
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index a150595..354f344 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -147,6 +147,11 @@ ENTRY(exception_handler)
 	mov	#31,r8
 	cmp/hs	r8,r9
 	bt	trap_entry	! 64 > vec >= 31  is trap
+	mov	#16,r8
+#ifdef CONFIG_CPU_J2
+	cmp/hs	r8,r9
+	bt	interrupt_entry	! 31 > vec >= 16 is interrupt
+#endif
 
 	mov.l	4f,r8
 	mov	r9,r4
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
index 6c687ae..d8dbb81 100644
--- a/arch/sh/kernel/cpu/sh2/probe.c
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -24,10 +24,21 @@ void cpu_probe(void)
 	boot_cpu_data.dcache.linesz		= L1_CACHE_BYTES;
 	boot_cpu_data.dcache.flags		= 0;
 #endif
+
+#if defined(CONFIG_CPU_J2)
+	boot_cpu_data.type			= CPU_J2;
+	/* FIXME: cache properties should come from device tree. */
+	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;
 }
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index cee6b99..92c3bd9 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -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
index 0000000..893119a
--- /dev/null
+++ b/arch/sh/mm/cache-j2.c
@@ -0,0 +1,58 @@
+/*
+ * arch/sh/mm/cache-j2.c
+ *
+ * Copyright (C) 2015 SEI
+ *
+ * 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>
+
+u32 j2_ccr_base, j2_ccr_cpu_offset;
+
+static void j2_flush_icache(void *args)
+{
+	unsigned cpu;
+	for_each_possible_cpu(cpu)
+		__raw_writel(0x80000103, j2_ccr_base + cpu*j2_ccr_cpu_offset);
+}
+
+static void j2_flush_dcache(void *args)
+{
+	unsigned cpu;
+	for_each_possible_cpu(cpu)
+		__raw_writel(0x80000203, j2_ccr_base + cpu*j2_ccr_cpu_offset);
+}
+
+static void j2_flush_both(void *args)
+{
+	unsigned cpu;
+	for_each_possible_cpu(cpu)
+		__raw_writel(0x80000303, j2_ccr_base + cpu*j2_ccr_cpu_offset);
+}
+
+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));
+}
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index 776d664..70cc52f 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -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();
-- 
2.8.1


>From 524c4225c9d0663f868e56c2ea3ffede4188bffd Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Fri, 22 Apr 2016 23:29:13 +0000
Subject: [PATCH 09/16] sh: add AT_HWCAP flag for J-Core cas.l instruction

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/include/uapi/asm/cpu-features.h | 1 +
 arch/sh/kernel/cpu/sh2/probe.c          | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/arch/sh/include/uapi/asm/cpu-features.h b/arch/sh/include/uapi/asm/cpu-features.h
index 694abe4..2f1bc85 100644
--- a/arch/sh/include/uapi/asm/cpu-features.h
+++ b/arch/sh/include/uapi/asm/cpu-features.h
@@ -22,5 +22,6 @@
 #define CPU_HAS_L2_CACHE	0x0080	/* Secondary cache / URAM */
 #define CPU_HAS_OP32		0x0100	/* 32-bit instruction support */
 #define CPU_HAS_PTEAEX		0x0200	/* PTE ASID Extension support */
+#define CPU_HAS_CAS_L		0x0400	/* cas.l atomic compare-and-swap */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
index d8dbb81..ecf8360 100644
--- a/arch/sh/kernel/cpu/sh2/probe.c
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -33,6 +33,8 @@ void cpu_probe(void)
 	boot_cpu_data.dcache.entry_shift	= 5;
 	boot_cpu_data.dcache.linesz		= 32;
 	boot_cpu_data.dcache.flags		= 0;
+
+	boot_cpu_data.flags |= CPU_HAS_CAS_L;
 #else
 	/*
 	 * SH-2 doesn't have separate caches
-- 
2.8.1


>From 8b4949c180c01b3ff35fd7436e55dc023e5a3bac Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Thu, 17 Mar 2016 23:12:12 +0000
Subject: [PATCH 10/16] irqchip: add J-Core AIC driver

Signed-off-by: Rich Felker <dalias at libc.org>
---
 drivers/irqchip/Kconfig         |  6 +++
 drivers/irqchip/Makefile        |  1 +
 drivers/irqchip/irq-jcore-aic.c | 95 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)
 create mode 100644 drivers/irqchip/irq-jcore-aic.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 3e12479..f1592f3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -244,3 +244,9 @@ config IRQ_MXS
 config MVEBU_ODMI
 	bool
 	select GENERIC_MSI_IRQ_DOMAIN
+
+config JCORE_AIC
+	bool "J-Core integrated AIC"
+	select IRQ_DOMAIN
+	help
+	  Support for the J-Core integrated AIC.
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b03cfcb..51717095 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
 obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
+obj-$(CONFIG_JCORE_AIC)			+= irq-jcore-aic.o
diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c
new file mode 100644
index 0000000..68178fb
--- /dev/null
+++ b/drivers/irqchip/irq-jcore-aic.c
@@ -0,0 +1,95 @@
+/*
+ * J-Core SoC AIC driver
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define AIC1_INTPRI 8
+
+struct aic_data {
+	unsigned char __iomem *base;
+	u32 cpu_offset;
+	struct irq_chip chip;
+	struct irq_domain *domain;
+	struct notifier_block nb;
+} aic_data;
+
+static int aic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
+{
+	struct aic_data *aic = d->host_data;
+
+	irq_set_chip_data(irq, aic);
+	irq_set_chip_and_handler(irq, &aic->chip, handle_simple_irq);
+	irq_set_probe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops aic_irqdomain_ops = {
+	.map = aic_irqdomain_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static void noop(struct irq_data *data)
+{
+}
+
+static void aic1_localenable(struct aic_data *aic)
+{
+	unsigned cpu = smp_processor_id();
+	pr_info("Local AIC enable on cpu %u\n", cpu);
+	writel(0xffffffff, aic->base + cpu * aic->cpu_offset + AIC1_INTPRI);
+}
+
+static int aic1_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		aic1_localenable(container_of(self, struct aic_data, nb));
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+int __init aic_irq_of_init(struct device_node *node, struct device_node *parent)
+{
+	struct aic_data *aic = &aic_data;
+
+	aic->base = of_iomap(node, 0);
+	of_property_read_u32(node, "cpu-offset", &aic->cpu_offset);
+
+	pr_info("Initializing J-Core AIC at %p\n", aic->base);
+
+	if (of_device_is_compatible(node, "jcore,aic1")) {
+		/* For aic1, need to enabled zero-priority-by-default irqs */
+		aic->nb.notifier_call = aic1_cpu_notify;
+		register_cpu_notifier(&aic->nb);
+		aic1_localenable(aic);
+	}
+
+	aic->chip.name = node->name;
+	aic->chip.irq_mask = noop;
+	aic->chip.irq_unmask = noop;
+
+	aic->domain = irq_domain_add_linear(node, 128, &aic_irqdomain_ops, aic);
+	irq_create_strict_mappings(aic->domain, 16, 16, 112);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(jcore_aic2, "jcore,aic2", aic_irq_of_init);
+IRQCHIP_DECLARE(jcore_aic1, "jcore,aic1", aic_irq_of_init);
-- 
2.8.1


>From 119f72d3766ec1f6c4309b90d9741c17fc66f57e Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Thu, 17 Mar 2016 23:12:57 +0000
Subject: [PATCH 11/16] clocksource: add J-Core PIT/RTC driver

Signed-off-by: Rich Felker <dalias at libc.org>
---
 drivers/clocksource/Kconfig     |   4 +
 drivers/clocksource/Makefile    |   2 +
 drivers/clocksource/jcore-pit.c | 176 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 182 insertions(+)
 create mode 100644 drivers/clocksource/jcore-pit.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index c346be6..f41f9ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -411,4 +411,8 @@ config CLKSRC_ST_LPC
 	  Enable this option to use the Low Power controller timer
 	  as clocksource.
 
+config CLKSRC_JCORE_PIT
+	bool "J-Core integrated PIT/RTC"
+	depends on GENERIC_CLOCKEVENTS
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index dc2b899..cf9f1d4 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -65,3 +65,5 @@ obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)		+= numachip.o
+
+obj-$(CONFIG_CLKSRC_JCORE_PIT)		+= jcore-pit.o
diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c
new file mode 100644
index 0000000..a4fde51
--- /dev/null
+++ b/drivers/clocksource/jcore-pit.c
@@ -0,0 +1,176 @@
+/*
+ * J-Core SoC PIT/RTC driver
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/profile.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqchip.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+static unsigned char __iomem *pit_base;
+static int pit_irq;
+static u32 percpu_offset;
+static u32 enable_val;
+
+static struct clock_event_device __percpu *pit_percpu;
+
+#define REG_PITEN 0x00
+#define REG_THROT 0x10
+#define REG_COUNT 0x14
+#define REG_BUSPD 0x18
+#define REG_SECHI 0x20
+#define REG_SECLO 0x24
+#define REG_NSEC  0x28
+
+static cycle_t rtc_read(struct clocksource *cs)
+{
+	u32 sechi, seclo, nsec, sechi0, seclo0;
+
+	sechi = __raw_readl(pit_base + REG_SECHI);
+	seclo = __raw_readl(pit_base + REG_SECLO);
+	do {
+		sechi0 = sechi;
+		seclo0 = seclo;
+		nsec  = __raw_readl(pit_base + REG_NSEC);
+		sechi = __raw_readl(pit_base + REG_SECHI);
+		seclo = __raw_readl(pit_base + REG_SECLO);
+	} while (sechi0 != sechi || seclo0 != seclo);
+
+	return ((u64)sechi << 32 | seclo) * 1000000000 + nsec;
+}
+
+struct clocksource rtc_csd = {
+	.name = "rtc",
+	.rating = 400,
+	.read = rtc_read,
+	.mult = 1,
+	.shift = 0,
+	.mask = CLOCKSOURCE_MASK(64),
+	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int pit_disable(struct clock_event_device *ced)
+{
+	unsigned cpu = smp_processor_id();
+	writel(0, pit_base + percpu_offset*cpu + REG_PITEN);
+	return 0;
+}
+
+static int pit_set(unsigned long delta, struct clock_event_device *ced)
+{
+	unsigned cpu = smp_processor_id();
+
+	pit_disable(ced);
+
+	writel(delta, pit_base + percpu_offset*cpu + REG_THROT);
+	writel(enable_val, pit_base + percpu_offset*cpu + REG_PITEN);
+
+	return 0;
+}
+
+static int pit_set_periodic(struct clock_event_device *ced)
+{
+	unsigned cpu = smp_processor_id();
+	unsigned long per = readl(pit_base + percpu_offset*cpu + REG_BUSPD);
+
+	return pit_set(DIV_ROUND_CLOSEST(1000000000, HZ*per), ced);
+}
+
+static int pit_local_init(struct clock_event_device *ced)
+{
+	unsigned cpu = smp_processor_id();
+	unsigned long per = readl(pit_base + percpu_offset*cpu + REG_BUSPD);
+
+	pr_info("Local PIT init on cpu %u\n", cpu);
+
+	ced->name = "pit";
+	ced->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+		| CLOCK_EVT_FEAT_PERCPU;
+	ced->cpumask = cpumask_of(cpu);
+	ced->rating = 400;
+	ced->irq = pit_irq;
+	ced->set_state_shutdown = pit_disable;
+	ced->set_state_periodic = pit_set_periodic;
+	ced->set_state_oneshot = pit_disable;
+	ced->set_next_event = pit_set;
+
+	clockevents_config_and_register(ced, DIV_ROUND_CLOSEST(1000000000, per),
+	                                1, 0xffffffff);
+
+	pit_set_periodic(ced);
+
+	return 0;
+}
+
+static int pit_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		pit_local_init(this_cpu_ptr(pit_percpu));
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block pit_cpu_nb = {
+	.notifier_call = pit_cpu_notify,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ced = this_cpu_ptr(dev_id);
+
+	if (clockevent_state_oneshot(ced)) pit_disable(ced);
+
+	ced->event_handler(ced);
+
+	return IRQ_HANDLED;
+}
+
+static void __init pit_init(struct device_node *node)
+{
+	unsigned long hwirq;
+	int err;
+
+	pit_base = of_iomap(node, 0);
+	pit_irq = irq_of_parse_and_map(node, 0);
+	of_property_read_u32(node, "cpu-offset", &percpu_offset);
+
+	pr_info("Initializing J-Core PIT at %p IRQ %d\n", pit_base, pit_irq);
+
+	clocksource_register_hz(&rtc_csd, 1000000000);
+
+	pit_percpu = alloc_percpu(struct clock_event_device);
+	register_cpu_notifier(&pit_cpu_nb);
+
+	err = request_irq(pit_irq, timer_interrupt,
+		IRQF_TIMER | IRQF_PERCPU, "pit", pit_percpu);
+	if (err) pr_err("pit irq request failed: %d\n", err);
+
+	hwirq = irq_get_irq_data(pit_irq)->hwirq;
+	enable_val = (1<<26) | ((hwirq&0x3c)<<18) | (hwirq<<12);
+
+	pit_local_init(this_cpu_ptr(pit_percpu));
+}
+
+CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", pit_init);
-- 
2.8.1


>From dacbaf562d65f6231da6359c55388589afb32e6e Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Fri, 25 Mar 2016 00:16:26 +0000
Subject: [PATCH 12/16] led pulse hacks for J-Core PIT

---
 drivers/clocksource/jcore-pit.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c
index a4fde51..91e974a 100644
--- a/drivers/clocksource/jcore-pit.c
+++ b/drivers/clocksource/jcore-pit.c
@@ -140,6 +140,11 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *ced = this_cpu_ptr(dev_id);
 
+//	static int cnt[2];
+//	if (!cnt[smp_processor_id()]--) { cnt[smp_processor_id()]=50;
+//	*(volatile u32*)0xabcd0000 ^= 0x10 << smp_processor_id(); }
+  	*(volatile u32*)0xabcd0000 ^= 0x10 << smp_processor_id();
+
 	if (clockevent_state_oneshot(ced)) pit_disable(ced);
 
 	ced->event_handler(ced);
-- 
2.8.1


>From 17b0af0e645cf475faba9ef7f45da375a5f7891c Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Sun, 3 Apr 2016 05:12:45 +0000
Subject: [PATCH 13/16] spi: add driver for J-Core SPI controller

Signed-off-by: Rich Felker <dalias at libc.org>
---
 drivers/spi/Kconfig     |   4 +
 drivers/spi/Makefile    |   1 +
 drivers/spi/spi-jcore.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 271 insertions(+)
 create mode 100644 drivers/spi/spi-jcore.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 9d8c84b..5bd2ccf 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -285,6 +285,10 @@ config SPI_IMX
 	  This enables using the Freescale i.MX SPI controllers in master
 	  mode.
 
+config SPI_JCORE
+	tristate "J-Core SPI Master"
+	depends on OF
+
 config SPI_LM70_LLP
 	tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
 	depends on PARPORT
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index fbb255c..6a34124 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
 obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o
 obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o
 obj-$(CONFIG_SPI_IMX)			+= spi-imx.o
+obj-$(CONFIG_SPI_JCORE)			+= spi-jcore.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
 obj-$(CONFIG_SPI_LP8841_RTC)		+= spi-lp8841-rtc.o
 obj-$(CONFIG_SPI_MESON_SPIFC)		+= spi-meson-spifc.o
diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c
new file mode 100644
index 0000000..552304c
--- /dev/null
+++ b/drivers/spi/spi-jcore.c
@@ -0,0 +1,266 @@
+/*
+ * J-Core SPI controller driver
+ *
+ * Copyright (C) 2012-2016 SEI Inc.
+ *
+ * Current version by Rich Felker
+ * Based loosely on initial version by Oleksandr G Zhadan
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+#define USE_MESSAGE_MODE 1
+
+#define DRV_NAME "jcore_spi"
+
+#define MAX_SPI_SPEED			12500000	/* 12.5 MHz */
+
+#define CTRL_REG		0x0
+#define DATA_REG		0x4
+
+#define SPI_NOCHIP_CS	0
+#define SPI_FLASH_CS	1
+#define SPI_CONF_CS	2
+#define SPI_SD_CS	2
+#define SPI_CODEC_CS	3
+
+#define JCORE_SPI_CTRL_ACS		0x01
+#define JCORE_SPI_CTRL_XMIT		0x02
+#define JCORE_SPI_STAT_BUSY		0x02
+#define JCORE_SPI_CTRL_CCS		0x04
+#define JCORE_SPI_CTRL_LOOP		0x08
+#define JCORE_SPI_CTRL_DCS		0x10
+
+#define JCORE_SPI_WAIT_RDY_MAX_LOOP	2000000	/* in usec */
+
+struct jcore_spi {
+	struct spi_master *master;
+	void __iomem *base;
+	volatile unsigned int ctrlReg;
+	unsigned int csReg;
+	unsigned int speedReg;
+	unsigned int speed_hz;
+};
+
+static void jcore_spi_wait_till_ready(struct jcore_spi *hw, int timeout)
+{
+	while (timeout--) {
+		hw->ctrlReg = readl(hw->base + CTRL_REG);
+		if (!(hw->ctrlReg & JCORE_SPI_STAT_BUSY))
+			return;
+		cpu_relax();
+	}
+	pr_err("%s: Timeout..\n", __func__);
+}
+
+static void jcore_spi_program(struct jcore_spi *hw)
+{
+	jcore_spi_wait_till_ready(hw, JCORE_SPI_WAIT_RDY_MAX_LOOP);
+	writel(hw->csReg | hw->speedReg, hw->base + CTRL_REG);	
+}
+
+static void jcore_spi_chipsel(struct spi_device *spi, bool value)
+{
+	struct jcore_spi *hw = spi_master_get_devdata(spi->master);
+
+	pr_debug("%s: CS=%d\n", __func__, value);
+
+	hw->csReg = ( JCORE_SPI_CTRL_ACS | JCORE_SPI_CTRL_CCS | JCORE_SPI_CTRL_DCS )
+		^ (!value << 2*spi->chip_select);
+
+	jcore_spi_program(hw);
+}
+
+static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
+{
+	if (speed == hw->speed_hz) return;
+	hw->speed_hz = speed;
+	hw->speedReg = ((MAX_SPI_SPEED / speed) - 1) << 27;
+	jcore_spi_program(hw);
+	pr_debug("%s: speed=%d pre=0x%x\n", __func__, speed, hw->speedReg);
+}
+
+static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t)
+{
+	struct jcore_spi *hw = spi_master_get_devdata(master);
+
+	void *ctrl_reg = hw->base + CTRL_REG;
+	void *data_reg = hw->base + DATA_REG;
+	int timeout;
+	int xmit;
+	int status;
+
+	/* data buffers */
+	const unsigned char *tx;
+	unsigned char *rx;
+	int len;
+	int count;
+
+	jcore_spi_baudrate(hw, t->speed_hz);
+
+	xmit = hw->csReg | hw->speedReg | JCORE_SPI_CTRL_XMIT;
+	tx = t->tx_buf;
+	rx = t->rx_buf;
+	len = t->len;
+
+	for (count = 0; count < len; count++) {
+		timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
+		do status = readl(ctrl_reg);
+		while ((status & JCORE_SPI_STAT_BUSY) && --timeout);
+		if (!timeout) break;
+
+		writel(tx ? *tx++ : 0, data_reg);
+		writel(xmit, ctrl_reg);
+
+		timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
+		do status = readl(ctrl_reg);
+		while ((status & JCORE_SPI_STAT_BUSY) && --timeout);
+		if (!timeout) break;
+
+		if (rx) *rx++ = readl(data_reg);
+	}
+
+#if !USE_MESSAGE_MODE
+	spi_finalize_current_transfer(master);
+#endif
+
+	return count<len ? -EREMOTEIO : 0;
+}
+
+#if USE_MESSAGE_MODE
+static int jcore_spi_transfer_one_message(struct spi_master *master,
+					struct spi_message *msg)
+{
+	struct spi_device *spi = msg->spi;
+	struct spi_transfer *xfer;
+	bool keep_cs = false;
+	int ret = 0;
+
+	jcore_spi_chipsel(spi, false);
+
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		ret = jcore_spi_txrx(master, spi, xfer);
+		if (ret) break;
+		if (xfer->delay_usecs)
+			udelay(xfer->delay_usecs);
+		if (xfer->cs_change) {
+			if (list_is_last(&xfer->transfer_list,
+					 &msg->transfers)) {
+				keep_cs = true;
+			} else {
+				jcore_spi_chipsel(spi, true);
+				udelay(10);
+				jcore_spi_chipsel(spi, false);
+			}
+		}
+		msg->actual_length += xfer->len;
+	}
+
+	if (!keep_cs)
+		jcore_spi_chipsel(spi, true);
+
+	msg->status = ret;
+
+	spi_finalize_current_message(master);
+
+	return ret;
+}
+#endif
+
+static int jcore_spi_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct jcore_spi *hw;
+	struct spi_master *master;
+	struct resource *res;
+	int err = -ENODEV;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
+	if (!master)
+		return err;
+
+	/* setup the master state. */
+	master->num_chipselect = 3;
+	master->mode_bits = SPI_MODE_3;
+#if USE_MESSAGE_MODE
+	master->transfer_one_message = jcore_spi_transfer_one_message;
+#else
+	master->transfer_one = jcore_spi_txrx;
+#endif
+	master->set_cs = jcore_spi_chipsel;
+	master->dev.of_node = node;
+
+	hw = spi_master_get_devdata(master);
+	hw->master = master;
+	platform_set_drvdata(pdev, hw);
+
+	/* find and map our resources */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto exit_busy;
+	if (!devm_request_mem_region
+	    (&pdev->dev, res->start, resource_size(res), pdev->name))
+		goto exit_busy;
+	hw->base =
+	    devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+	if (!hw->base)
+		goto exit_busy;
+
+	jcore_spi_baudrate(hw, 400000);
+
+	pdev->dev.dma_mask = 0;
+	/* register our spi controller */
+	err = spi_register_master(master);
+	if (err)
+		goto exit;
+	dev_info(&pdev->dev, "base %p, noirq\n", hw->base);
+
+	return 0;
+
+exit_busy:
+	err = -EBUSY;
+exit:
+	platform_set_drvdata(pdev, NULL);
+	spi_master_put(master);
+	return err;
+}
+
+static int jcore_spi_remove(struct platform_device *dev)
+{
+	struct jcore_spi *hw = platform_get_drvdata(dev);
+	struct spi_master *master = hw->master;
+
+	platform_set_drvdata(dev, NULL);
+	spi_master_put(master);
+	return 0;
+}
+
+static const struct of_device_id jcore_spi_of_match[] = {
+	{ .compatible = "jcore,spi2" },
+	{},
+};
+
+static struct platform_driver jcore_spi_driver = {
+	.probe = jcore_spi_probe,
+	.remove = jcore_spi_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = NULL,
+		.of_match_table = jcore_spi_of_match,
+	},
+};
+
+module_platform_driver(jcore_spi_driver);
+
+MODULE_DESCRIPTION("J-Core SPI driver");
+MODULE_AUTHOR("Rich Felker <dalias at libc.org>");
+MODULE_ALIAS("platform:" DRV_NAME);
-- 
2.8.1


>From a183c3cf26980949d786f24b9fb12fb511d4288f Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Thu, 7 Apr 2016 14:49:09 +0000
Subject: [PATCH 14/16] mmc: disable rescan for card change

This is a hack to fix a nasty bug: the rescan is completely
unsynchronized with use of the spi bus for spi-based mmc, and thus
clobbers in-progress transfers when it happens. No idea what the right
fix is.
---
 drivers/mmc/core/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 41b1e76..38b73b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2634,8 +2634,9 @@ void mmc_rescan(struct work_struct *work)
 	mmc_release_host(host);
 
  out:
-	if (host->caps & MMC_CAP_NEEDS_POLL)
-		mmc_schedule_delayed_work(&host->detect, HZ);
+//	if (host->caps & MMC_CAP_NEEDS_POLL)
+//		mmc_schedule_delayed_work(&host->detect, HZ);
+;
 }
 
 void mmc_start_host(struct mmc_host *host)
-- 
2.8.1


>From 3a8131035bc1601a93c7d5cc72342a68ec270a78 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Wed, 27 Apr 2016 00:11:38 +0000
Subject: [PATCH 15/16] sh: add defconfig for J-Core J2

This defconfig is intended not to be specific to a particular board;
it enables drivers for all currently-supported hardware, and should be
updated to include additional drivers as they are added.

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/configs/j2_defconfig | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 arch/sh/configs/j2_defconfig

diff --git a/arch/sh/configs/j2_defconfig b/arch/sh/configs/j2_defconfig
new file mode 100644
index 0000000..fca167f
--- /dev/null
+++ b/arch/sh/configs/j2_defconfig
@@ -0,0 +1,38 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_CPU_SUBTYPE_J2=y
+CONFIG_MEMORY_START=0x10000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_DEVICE_TREE=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttyUL0 earlycon"
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_UARTLITE=y
+CONFIG_SERIAL_UARTLITE_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_SPI=y
+CONFIG_SPI_JCORE=y
+CONFIG_WATCHDOG=y
+CONFIG_MMC=y
+CONFIG_MMC_SPI=y
+CONFIG_CLKSRC_JCORE_PIT=y
+CONFIG_JCORE_AIC=y
+CONFIG_EXT4_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
-- 
2.8.1


>From 68f6aae367ebc5886b6465cc9a395fe5d1b9ed43 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias at libc.org>
Date: Thu, 7 Apr 2016 15:01:53 +0000
Subject: [PATCH 16/16] sh: add device tree source for J2 FPGA on Mimas v2
 board

Signed-off-by: Rich Felker <dalias at libc.org>
---
 arch/sh/boot/dts/j2_mimas_v2.dts | 98 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100755 arch/sh/boot/dts/j2_mimas_v2.dts

diff --git a/arch/sh/boot/dts/j2_mimas_v2.dts b/arch/sh/boot/dts/j2_mimas_v2.dts
new file mode 100755
index 0000000..0d509f9
--- /dev/null
+++ b/arch/sh/boot/dts/j2_mimas_v2.dts
@@ -0,0 +1,98 @@
+/dts-v1/;
+
+/ {
+	compatible = "jcore,j2-soc";
+	model = "J2 FPGA SoC on Mimas v2 board";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	interrupt-parent = <&aic>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "jcore,j2";
+			reg = < 0 >;
+			clock-frequency = < 50000000 >;
+		};
+	};
+
+	memory at 10000000 {
+		device_type = "memory";
+		reg = < 0x10000000 0x4000000 >;
+	};
+
+	chosen {
+		stdout-path = "/soc at abcd0000/serial at 100";
+	};
+
+	soc at abcd0000 {
+		compatible = "simple-bus";
+		ranges = <0 0xabcd0000 0x100000>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		aic: interrupt-controller {
+			compatible = "jcore,aic1";
+			reg = < 0x200 0x10 >;
+			cpu-offset = < 0x300 >;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		cache-controller {
+			compatible = "jcore,cache";
+			reg = < 0xc0 4 >;
+			cpu-offset = < 4 >;
+		};
+
+		timer {
+			compatible = "jcore,pit";
+			reg = < 0x200 0x30 >;
+			cpu-offset = < 0x300 >;
+			interrupts = < 0x48 >;
+		};
+
+		ethernet {
+			compatible = "jcore,emac";
+			reg = < 0x10000 0x2000 >;
+			//interrupts = < 0x60 >;
+			interrupts = < 0x11 >;
+		};
+
+		spi {
+			compatible = "jcore,spi2";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			spi-max-frequency = <12500000>;
+
+			reg = < 0x40 0x8 >;
+
+			sdcard at 1 {
+				compatible = "mmc-spi-slot";
+				reg = <0>;
+				spi-max-frequency = <12500000>;
+				voltage-ranges = <3200 3400>;
+				mode = <0>;
+			};
+		};
+
+		serial at 100 {
+			clock-frequency = <125000000>;
+			compatible = "jcore,uartlite", "xlnx,xps-uartlite-1.00.a";
+			current-speed = <115200>;
+			device_type = "serial";
+			//interrupts = < 0x5d >;
+			interrupts = < 0x12 >;
+			port-number = <0>;
+			reg = < 0x100 0x10 >;
+		};
+	};
+};
-- 
2.8.1



More information about the J-core mailing list