select GENERIC_ATOMIC64
select HAVE_UID16
select VIRT_TO_BUS
-
+ select IRQ_DOMAIN
+ select OF
+ select OF_IRQ
+ select OF_FLATTREE
+ select HAVE_MEMBLOCK
+ select OF_EARLY_FLATTREE
+ select SERIAL_EARLYCON
+ select COMMON_CLK
+ select CLKSRC_OF
+ select GENERIC_CLOCKEVENTS
+
config MMU
def_bool n
config GENERIC_HARDIRQS
def_bool y
-config GENERIC_CALIBRATE_DELAY
- def_bool y
-
config GENERIC_TIME
def_bool y
select CPU_RX64M
endchoice
+config RX_BUILTIN_DTB
+ string "Builtin DTB"
+ default ""
+
config CPU_RX610
bool
select RX_ICUA
+ select RX_TPU
+ select RX_CMT
config CPU_RX62N
bool
source "fs/Kconfig"
-source "arch/rx/Kconfig.debug"
+menu "Kernel Hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
source "security/Kconfig"
LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
core-y += arch/$(ARCH)/kernel/ \
- arch/$(ARCH)/mm/ \
- arch/$(ARCH)/boards/ \
- arch/$(ARCH)/lib/
-libs-y += $(LIBGCC)
+ arch/$(ARCH)/mm/
+
+ifneq '$(CONFIG_RX_BUILTIN_DTB)' '""'
+core-y += arch/$(ARCH)/boot/dts/
+endif
+
+libs-y += arch/$(ARCH)/lib/ $(LIBGCC)
boot := arch/$(ARCH)/boot
+%.dtb %.dtb.S %.dtb.o: | scripts
+ $(Q)$(MAKE) $(build)=arch/$(ARCH)/boot/dts arch/$(ARCH)/boot/dts/$@
+
+PHONY += dtbs
+dtbs: scripts
+ $(Q)$(MAKE) $(build)=arch/$(ARCH)/boot/dts
+
archmrproper:
archclean:
--- /dev/null
+ifneq '$(CONFIG_RX_BUILTIN_DTB)' '""'
+BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_RX_BUILTIN_DTB)).dtb.o
+endif
+
+obj-y += $(BUILTIN_DTB)
+
+dtb-$(CONFIG_RX_SIM) := rx_sim.dtb
+
+dtstree := $(srctree)/$(src)
+dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
+always := $(dtb-y)
+clean-files := *.dtb.S *.dtb
--- /dev/null
+/dts-v1/;
+/ {
+ compatible = "gnu,gdbsim";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&rxicu>;
+
+ chosen {
+ bootargs = "earlycon=rxsim";
+ stdout-path = <&sci0>;
+ };
+ aliases {
+ serial0 = &sci0;
+ serial1 = &sci1;
+ };
+
+ xclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <12000000>;
+ clock-output-names = "xtal";
+ };
+ iclk: iclk {
+ compatible = "renesas,rx-mul-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0x00080020 4>;
+ renesas,offset = <24>;
+ renesas,maxfreq = <100000000>;
+ };
+ pclk: pclk {
+ compatible = "renesas,rx-mul-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0x00080020 4>;
+ renesas,offset = <8>;
+ renesas,maxfreq = <50000000>;
+ };
+ bclk: bclk {
+ compatible = "renesas,rx-mul-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0x00080020 4>;
+ renesas,offset = <16>;
+ renesas,maxfreq = <50000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "renesas,rx";
+ clock-frequency = <96000000>;
+ mem-cycle = <2>;
+ };
+ };
+ memory@01000000 {
+ device_type = "memory";
+ reg = <0x01000000 0x01000000>;
+ };
+
+ rxicu: interrupt-controller@87000 {
+ compatible = "renesas,rx-icu";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x00087000 0x600>;
+ };
+
+ tpu: timer@00088100 {
+ compatible = "renesas,rx-tpu";
+ reg = <0x00088100 0x70>;
+ clocks = <&pclk>;
+ clock-names = "fck";
+ };
+ cmt: timer@00088000 {
+ compatible = "renesas,rx-cmt";
+ reg = <0x00088000 0x70>;
+ clocks = <&pclk>;
+ interrupts = <28 0>;
+ };
+
+ sci0: serial@00088240 {
+ compatible = "renesas,sci";
+ reg = <0x00088240 8>;
+ interrupts = <214 0>, <215 0>, <216 0>, <217 0>;
+ clocks = <&pclk>;
+ clock-names = "sci_ick";
+ };
+
+ sci1: serial@00088248 {
+ compatible = "renesas,sci";
+ reg = <0x00088248 8>;
+ interrupts = <218 0>, <219 0>, <220 0>, <221 0>;
+ clocks = <&pclk>;
+ clock-names = "sci_ick";
+ };
+};
--- /dev/null
+#ifndef __ARCH_RX_CMPXCHG__
+#define __ARCH_RX_CMPXCHG__
+
+#define xchg(ptr, x) \
+ ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
+ sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+extern void __bad_xchg_size(void);
+
+static inline unsigned long __xchg(unsigned long x,
+ volatile void *ptr, int size)
+{
+ switch (size) {
+ case 1:
+ __asm__ __volatile__
+ ("xchg %1.b,%0"
+ : "=&r" (x), "=Q" (*__xg(ptr)));
+ break;
+ case 2:
+ __asm__ __volatile__
+ ("xchg %1.w,%0"
+ : "=&r" (x), "=Q" (*__xg(ptr)));
+ break;
+ case 4:
+ __asm__ __volatile__
+ ("xchg %1.l,%0"
+ : "=&r" (x), "=Q" (*__xg(ptr)));
+ break;
+ default:
+ __bad_xchg_size();
+ }
+ return x;
+}
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n) \
+ ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#endif /* __ARCH_RX_CMPXCHG__ */
--- /dev/null
+#ifndef __ASM_RX_SWITCH_TO_H__
+#define __ASM_RX_SWITCH_TO_H__
+
+#define switch_to(prev,next,last) \
+do { \
+__asm__ volatile("switch_to:"); \
+ __asm__ volatile("pushm r1-r15\n\t" \
+ "mov.l #1f,%0\n\t" \
+ "mov.l r0,%1\n\t" \
+ "mov.l %3,r0\n\t" \
+ "jmp %2\n" \
+ "1:\n\t" \
+ "popm r1-r15\n\t" \
+ ::"m"(prev->thread.pc), \
+ "m"(prev->thread.sp), \
+ "r"(next->thread.pc), \
+ "g"(next->thread.sp)); \
+ last = prev; \
+} while(0)
+
+#endif
--- /dev/null
+#define __ARCH_NOMMU
+
+#include <asm-generic/unistd.h>
extra-y := vmlinux.lds
-obj-y := head.o process.o traps.o irq.o time.o signal.o \
- setup.o syscalls.o entry.o ptrace.o dma-nommu.o \
- timer/ cpu/
+obj-y := head.o process.o traps.o irq.o signal.o \
+ setup.o syscalls.o entry.o ptrace.o dma-nommu.o
-obj-$(CONFIG_EARLY_PRINTK) += early-printk.o
+obj-$(CONFIG_RX_GDB_SIM) += sim-console.o
bra resume_userspace
work_resched:
bsr schedule
- clrpsw i
- mov TI_FLAGS[r13],r14
- tst #_TIF_WORK_MASK,r14
- bne work_pending
+ bra resume_userspace
restore_all:
mov.l OFF_USP[r0],r1
mvtc r1,usp
mov.l #setup_bsc,r1
jsr r1
- /* copy rw data for ram */
+ /* copy rw data to ram */
mov.l #__data_romtop,r2
mov.l #_sdata,r1
mov.l #_edata,r3
sub r1,r3
smovf
+ sub r4,r4
#endif
#else
/* setup args */
- mov.l #12, r5
+ sub r4,r4
+ mov #12, r5
int #255
- mov.l r1,r2
- mov.l #0x400,r1
- mov.l #13, r5
+ mov r1,r2
+ mov #boot_command_line,r1
+ mov #13, r5
int #255
+ cmp #1,r1
+ beq 2f
/* r1 - argc */
/* r2 -length */
/* skip argv[0] */
- mov.l r1,r4
- mov.l r2,r3
- mov.l #0x400,r1
- mov.l #0,r2
+ mov r1,r4
+ mov r2,r3
+ mov #boot_command_line,r1
+ mov #0,r2
suntil.b
- mov.l r3,r5
- mov.l r1,r2
- mov.l #0x400,r1
+ mov r3,r5
+ mov r1,r2
+ mov #boot_command_line,r1
smovf
- mov.l #0x400,r1
- mov.l #0,r2
+ mov #boot_command_line,r1
+ mov #0,r2
sub #1,r4
- mov.l r5,r3
+ mov r5,r3
1:
suntil.b
sub #1,r1
add #1,r1
sub #1,r4
bne 1b
+ sub #1,r1
mov.b #0,[r1]
+ mov #-1,r4
+2:
#endif
/* clear BSS */
- mov.l #_sbss,r1
- mov.l #_ebss,r3
+ mov #_sbss,r1
+ mov #_ebss,r3
sub r1,r3
shlr #2,r3
- mov.l #0,r2
+ mov #0,r2
sstr.l
+ mov r4,r1
+ mov #rx_fdt_init,r2
+ jsr r2
/* exception handler setup */
#if defined(CONFIG_RAMKERNEL)
- mov.l #install_exception_entry,r1
+ mov #install_exception_entry,r1
jsr r1
#endif
/* start kernel */
- mov.l #init_thread_union, r1
+ mov #init_thread_union, r1
add #PAGE_SIZE, r1, r0
- mov.l #start_kernel, r1
+ mov #start_kernel, r1
jmp r1
.weak setup_bsc
/*
* arch/rx/kernel/irq.c
*
- * Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp>
+ * Copyright (C) 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*
*/
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/seq_file.h>
+#include <linux/irqchip.h>
#include <asm/processor.h>
#include <asm/io.h>
extern unsigned long rx_exp_table[32];
static unsigned long *interrupt_vector[NR_IRQS];
-#define EXT_IRQ0 64
-#define EXT_IRQS 16
-#define IR (0x00087000)
-#define IER (0x00087200)
-#define IRQER (0x0008c300)
-
-void rx_force_interrupt(unsigned int no)
-{
- __raw_writeb(1, (void __iomem *)(IR + no));
-}
-
void __init setup_vector(void)
{
int i;
void __init init_IRQ(void)
{
setup_vector();
- setup_rx_irq_desc();
+ irqchip_init();
}
asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/fs.h>
-#include <linux/fb.h>
#include <linux/console.h>
-#include <linux/genhd.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/initrd.h>
-#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
unsigned long memory_start;
unsigned long memory_end;
-#define COMMAND_LINE ((char *)0x400)
-
static struct resource code_resource = {
.name = "Kernel code",
};
extern void *_sbss, *_ebss;
extern void *_end;
-void early_device_register(void);
+void __init rx_fdt_init(void *fdt)
+{
+ char saved_command_line[512];
-void __init setup_arch(char **cmdline_p)
+ *saved_command_line = 0;
+ if (fdt == (void *)-1) {
+ memcpy(saved_command_line, boot_command_line,
+ sizeof(saved_command_line));
+ fdt = NULL;
+ }
+ if (!fdt)
+ fdt = __dtb_start;
+
+ early_init_dt_scan(fdt);
+ memblock_allow_resize();
+ if (*saved_command_line) {
+ memcpy(boot_command_line, saved_command_line,
+ sizeof(saved_command_line));
+ }
+}
+
+static void __init bootmem_init(void)
{
int bootmap_size;
+ unsigned long ram_start_pfn;
+ unsigned long free_ram_start_pfn;
+ unsigned long ram_end_pfn;
+ struct memblock_region *region;
-#ifdef CONFIG_CMDLINE
- if (*COMMAND_LINE == 0)
- memcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif
- if(*boot_command_line == '\0')
- memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
- *cmdline_p = boot_command_line;
+ memory_end = memory_start = 0;
-#ifdef DEBUG
- if (strlen(boot_command_line))
- printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
-#endif
+ /* Find main memory where is the kernel */
+ for_each_memblock(memory, region) {
+ memory_start = region->base;
+ memory_end = region->base + region->size;
+ }
- memory_start = (unsigned long) &_end;
+ if (!memory_end)
+ panic("No memory!");
- /* allow for ROMFS on the end of the kernel */
- if (memcmp((void *)memory_start, "-rom1fs-", 8) == 0) {
-#if defined(CONFIG_BLK_DEV_INITRD)
- initrd_start = memory_start;
- initrd_end = memory_start += be32_to_cpu(((unsigned long *) (memory_start))[2]);
-#else
- memory_start += be32_to_cpu(((unsigned long *) memory_start)[2]);
-#endif
- }
- memory_start = PAGE_ALIGN(memory_start);
-#if !defined(CONFIG_BLKDEV_RESERVE)
- memory_end = (unsigned long) &_ramend; /* by now the stack is part of the init task */
-#else
- if ((memory_end < CONFIG_BLKDEV_RESERVE_ADDRESS) &&
- (memory_end > CONFIG_BLKDEV_RESERVE_ADDRESS))
- /* overlap userarea */
- memory_end = CONFIG_BLKDEV_RESERVE_ADDRESS;
-#endif
+ ram_start_pfn = PFN_UP(memory_start);
+ /* free_ram_start_pfn is first page after kernel */
+ free_ram_start_pfn = PFN_UP(__pa(&_end));
+ ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
+
+ max_pfn = ram_end_pfn;
- init_mm.start_code = (unsigned long) &_stext;
- init_mm.end_code = (unsigned long) &_etext;
- init_mm.end_data = (unsigned long) &_edata;
- init_mm.brk = (unsigned long) &_end;
-
- code_resource.start = virt_to_bus(&_stext);
- code_resource.end = virt_to_bus(&_etext)-1;
- data_resource.start = virt_to_bus(&_sdata);
- data_resource.end = virt_to_bus(&_edata)-1;
- bss_resource.start = virt_to_bus(&_sbss);
- bss_resource.end = virt_to_bus(&_ebss)-1;
-
-
-#ifdef DEBUG
- printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
- "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
- (int) &_sdata, (int) &_edata,
- (int) &_sbss, (int) &_ebss);
- printk(KERN_DEBUG "KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x "
- "STACK=0x%06x-0x%06x\n",
- (int) &_ebss, (int) memory_start,
- (int) memory_start, (int) memory_end,
- (int) memory_end, (int) &_ramend);
-#endif
/*
* give all the memory to the bootmap allocator, tell it to put the
* boot mem_map at the start of memory
*/
- bootmap_size = init_bootmem_node(
- NODE_DATA(0),
- memory_start >> PAGE_SHIFT, /* map goes here */
- memory_start >> PAGE_SHIFT,
- memory_end >> PAGE_SHIFT);
+ bootmap_size = init_bootmem_node(NODE_DATA(0),
+ free_ram_start_pfn,
+ 0,
+ ram_end_pfn);
/*
* free the usable memory, we have to make sure we do not free
* the bootmem bitmap so we then reserve it after freeing it :-)
*/
- free_bootmem(memory_start, memory_end - memory_start);
- reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
- /* Let earlyprintk output early console messages */
- early_device_register();
+ free_bootmem(PFN_PHYS(free_ram_start_pfn),
+ (ram_end_pfn - free_ram_start_pfn) << PAGE_SHIFT);
+ reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size,
+ BOOTMEM_DEFAULT);
+
+ for_each_memblock(reserved, region) {
+ reserve_bootmem(region->base, region->size, BOOTMEM_DEFAULT);
+ }
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+ unflatten_and_copy_device_tree();
+
+ init_mm.start_code = (unsigned long) &_stext;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = 0;
+
+ *cmdline_p = boot_command_line;
+
parse_early_param();
- early_platform_driver_probe("earlyprintk", 1, 1);
+ bootmem_init();
/*
* get kmalloc into gear
*/
insert_resource(&iomem_resource, &code_resource);
insert_resource(&iomem_resource, &data_resource);
insert_resource(&iomem_resource, &bss_resource);
-#ifdef DEBUG
- printk(KERN_DEBUG "Done setup_arch\n");
-#endif
}
/*
.stop = c_stop,
.show = show_cpuinfo,
};
+
+static int __init device_probe(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ return 0;
+}
+
+device_initcall(device_probe);
+
+void __init time_init(void)
+{
+ of_clk_init(NULL);
+ clocksource_probe();
+}
+
+void __init calibrate_delay(void)
+{
+ struct device_node *cpu;
+ int freq;
+ int cycle;
+
+ cpu = of_find_compatible_node(NULL, NULL, "renesas,rx");
+ of_property_read_s32(cpu, "clock-frequency", &freq);
+ of_property_read_s32(cpu, "mem-cycle", &cycle);
+ loops_per_jiffy = freq / HZ / cycle;
+ pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
+ loops_per_jiffy / (500000 / HZ),
+ (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
+}
--- /dev/null
+#include <linux/syscalls.h>
+#include <linux/signal.h>
+#include <linux/unistd.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+#define sys_mmap2 sys_mmap_pgoff
+
+asmlinkage int sys_rt_sigreturn(void);
+
+void *_sys_call_table[__NR_syscalls] = {
+#include <asm/unistd.h>
+};
-obj-y=delay.o
+lib-y := delay.o memcpy.o memset.o
--- /dev/null
+ .global memcpy
+ .text
+memcpy:
+ mov r1,r4
+ smovf
+ mov r4,r1
+ rts
--- /dev/null
+ .global memset
+ .text
+memset:
+ mov r1,r4
+ sstr
+ mov r4,r1
+ rts
obj-y += xilinx/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/
+obj-$(CONFIG_RX) += rx/
--- /dev/null
+obj-$(CONFIG_CPU_RX610) += clk-multi.o
+obj-$(CONFIG_CPU_RX62N) += clk-multi.o
--- /dev/null
+/*
+ * RX610/RX62N clock multiply driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#define MIN_FREQ 8000000
+
+static DEFINE_SPINLOCK(clklock);
+
+struct pll_clock {
+ struct clk_hw hw;
+ void __iomem *sckcr;
+ int offset;
+ int maxfreq;
+};
+
+#define to_pll_clock(_hw) container_of(_hw, struct pll_clock, hw)
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clock *pll_clock = to_pll_clock(hw);
+ unsigned long sckcr;
+ int mul;
+
+ sckcr = ioread32(pll_clock->sckcr);
+ sckcr >>= pll_clock->offset;
+ mul = 1 << (3 - sckcr);
+
+ return parent_rate * mul;
+}
+
+static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct pll_clock *pll_clock = to_pll_clock(hw);
+ int i, m = -1;
+ long offset[4];
+
+ if (rate > pll_clock->maxfreq)
+ rate = pll_clock->maxfreq;
+ if (rate < MIN_FREQ)
+ rate = MIN_FREQ;
+
+ for (i = 0; i < 4; i++)
+ offset[i] = abs(rate - (*prate * (1 << i)));
+ for (i = 0; i < 4; i++)
+ if (m < 0)
+ m = i;
+ else
+ m = (offset[i] < offset[m])?i:m;
+
+ return *prate * (1 << m);
+}
+
+static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int pll;
+ unsigned long val;
+ unsigned long flags;
+ struct pll_clock *pll_clock = to_pll_clock(hw);
+
+ pll = 3 - ffs(rate / parent_rate);
+ spin_lock_irqsave(&clklock, flags);
+ val = ioread32(pll_clock->sckcr);
+ val &= ~(0x0f << pll_clock->offset);
+ val |= pll << pll_clock->offset;
+ iowrite32(val, pll_clock->sckcr);
+ while (ioread32(pll_clock->sckcr) != val);
+ spin_unlock_irqrestore(&clklock, flags);
+ return 0;
+}
+
+static const struct clk_ops pll_ops = {
+ .recalc_rate = pll_recalc_rate,
+ .round_rate = pll_round_rate,
+ .set_rate = pll_set_rate,
+};
+
+static void __init rx_mul_clk_setup(struct device_node *node)
+{
+ int num_parents;
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct pll_clock *pll_clock;
+ struct clk_init_data init;
+
+ num_parents = of_clk_get_parent_count(node);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found", clk_name);
+ return;
+ }
+
+
+ pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL);
+ if (!pll_clock)
+ return;
+
+ pll_clock->sckcr = of_iomap(node, 0);
+ if (pll_clock->sckcr == NULL) {
+ pr_err("%s: failed to map sckcr register", clk_name);
+ goto free_clock;
+ }
+ of_property_read_u32(node,"renesas,offset", &pll_clock->offset);
+ of_property_read_u32(node,"renesas,maxfreq", &pll_clock->maxfreq);
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.name = clk_name;
+ init.ops = &pll_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ pll_clock->hw.init = &init;
+
+ clk = clk_register(NULL, &pll_clock->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register %s div clock (%ld)\n",
+ __func__, clk_name, PTR_ERR(clk));
+ goto unmap_sckcr;
+ }
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+
+unmap_sckcr:
+ iounmap(pll_clock->sckcr);
+free_clock:
+ kfree(pll_clock);
+}
+
+CLK_OF_DECLARE(rx_mul_clk, "renesas,rx-mul-clock",
+ rx_mul_clk_setup);
This enables the clocksource for the H8300 platform with the
H8S2678 CPU.
+config RX_TPU
+ bool
+
config CLKSRC_IMX_GPT
bool "Clocksource using i.MX GPT" if COMPILE_TEST
depends on (ARM || ARM64) && HAVE_CLK
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o
+obj-$(CONFIG_RX_TPU) += rx_tpu.o
+obj-$(CONFIG_RX_CMT) += rx_cmt.o
--- /dev/null
+/*
+ * RX CMT Driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+enum {
+ STR = 0,
+ CMCR = 2,
+ CMCNT = 4,
+ CMCOR = 6
+};
+
+#define SCALE 128
+#define FLAG_STARTED 1
+
+struct cmt_priv {
+ struct clock_event_device ced;
+ void __iomem *base;
+ unsigned long flags;
+ unsigned int rate;
+};
+
+static irqreturn_t cmt_interrupt(int irq, void *dev_id)
+{
+ struct cmt_priv *p = dev_id;
+
+ if (clockevent_state_oneshot(&p->ced))
+ iowrite16(0x0000, p->base + STR);
+
+ p->ced.event_handler(&p->ced);
+ return IRQ_HANDLED;
+}
+
+static void cmt_set_next(struct cmt_priv *p, unsigned long delta)
+{
+ if (delta >= 0x10000)
+ pr_warn("delta out of range\n");
+ iowrite16(delta, p->base + CMCOR);
+ iowrite16(0x0000, p->base + CMCNT);
+}
+
+static int cmt_enable(struct cmt_priv *p)
+{
+ iowrite16(0xffff, p->base + CMCOR);
+ iowrite16(0x0000, p->base + CMCNT);
+ iowrite16(0x00c2, p->base + CMCR);
+ iowrite16(0x0001, p->base + STR);
+
+ return 0;
+}
+
+static int cmt_start(struct cmt_priv *p)
+{
+ int ret;
+
+ if ((p->flags & FLAG_STARTED))
+ return 0;
+
+ ret = cmt_enable(p);
+ if (!ret)
+ p->flags |= FLAG_STARTED;
+
+ return ret;
+}
+
+static void cmt_stop(struct cmt_priv *p)
+{
+ iowrite16be(0x0000, p->base + STR);
+}
+
+static inline struct cmt_priv *ced_to_priv(struct clock_event_device *ced)
+{
+ return container_of(ced, struct cmt_priv, ced);
+}
+
+static void cmt_clock_event_start(struct cmt_priv *p, unsigned long delta)
+{
+ struct clock_event_device *ced = &p->ced;
+
+ cmt_start(p);
+
+ ced->shift = 32;
+ ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
+ ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
+ ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
+
+ cmt_set_next(p, delta);
+}
+
+static int cmt_clock_event_shutdown(struct clock_event_device *ced)
+{
+ cmt_stop(ced_to_priv(ced));
+ return 0;
+}
+
+static int cmt_clock_event_periodic(struct clock_event_device *ced)
+{
+ struct cmt_priv *p = ced_to_priv(ced);
+
+ pr_info("%s: used for periodic clock events\n", ced->name);
+ cmt_stop(p);
+ cmt_clock_event_start(p, (p->rate + HZ/2) / HZ);
+
+ return 0;
+}
+
+static int cmt_clock_event_oneshot(struct clock_event_device *ced)
+{
+ struct cmt_priv *p = ced_to_priv(ced);
+
+ pr_info("%s: used for oneshot clock events\n", ced->name);
+ cmt_stop(p);
+ cmt_clock_event_start(p, 0x10000);
+
+ return 0;
+}
+
+static int cmt_clock_event_next(unsigned long delta,
+ struct clock_event_device *ced)
+{
+ struct cmt_priv *p = ced_to_priv(ced);
+
+ BUG_ON(!clockevent_state_oneshot(ced));
+ cmt_set_next(p, delta - 1);
+
+ return 0;
+}
+
+static struct cmt_priv cmt_priv = {
+ .ced = {
+ .name = "rx-cmt",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .set_next_event = cmt_clock_event_next,
+ .set_state_shutdown = cmt_clock_event_shutdown,
+ .set_state_periodic = cmt_clock_event_periodic,
+ .set_state_oneshot = cmt_clock_event_oneshot,
+ },
+};
+
+static void __init cmt_init(struct device_node *node)
+{
+ void __iomem *base;
+ int irq;
+ int ret = 0;
+ int rate;
+ struct clk *clk;
+
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("failed to get clock for clockevent\n");
+ return;
+ }
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("failed to map registers for clockevent\n");
+ goto free_clk;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ pr_err("failed to get irq for clockevent\n");
+ goto unmap_reg;
+ }
+
+ cmt_priv.base = base;
+
+ rate = clk_get_rate(clk) / SCALE;
+ if (!rate) {
+ pr_err("Failed to get rate for the clocksource\n");
+ goto unmap_reg;
+ }
+ cmt_priv.rate = rate;
+
+ ret = request_irq(irq, cmt_interrupt,
+ IRQF_TIMER, cmt_priv.ced.name, &cmt_priv);
+ if (ret < 0) {
+ pr_err("failed to request irq %d for clockevent\n", irq);
+ goto unmap_reg;
+ }
+
+ clockevents_config_and_register(&cmt_priv.ced, rate, 1, 0x0000ffff);
+
+ return;
+unmap_reg:
+ iounmap(base);
+free_clk:
+ clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(rx_cmt, "renesas,rx-cmt", cmt_init);
--- /dev/null
+/*
+ * RX TPU Driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clocksource.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TCR 0x0
+#define TSR 0x5
+#define TCNT 0x6
+
+#define TCFV 0x10
+
+struct tpu_priv {
+ struct clocksource cs;
+ void __iomem *mapbase1;
+ void __iomem *mapbase2;
+ raw_spinlock_t lock;
+ unsigned int cs_enabled;
+};
+
+static inline unsigned long read_tcnt32(struct tpu_priv *p)
+{
+ unsigned long tcnt;
+
+ tcnt = ioread16(p->mapbase1 + TCNT) << 16;
+ tcnt |= ioread16(p->mapbase2 + TCNT);
+ return tcnt;
+}
+
+static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
+{
+ unsigned long v1, v2, v3;
+ int o1, o2;
+
+ o1 = ioread8(p->mapbase1 + TSR) & TCFV;
+
+ /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+ do {
+ o2 = o1;
+ v1 = read_tcnt32(p);
+ v2 = read_tcnt32(p);
+ v3 = read_tcnt32(p);
+ o1 = ioread8(p->mapbase1 + TSR) & TCFV;
+ } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+ || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
+
+ *val = v2;
+ return o1;
+}
+
+static inline struct tpu_priv *cs_to_priv(struct clocksource *cs)
+{
+ return container_of(cs, struct tpu_priv, cs);
+}
+
+static cycle_t tpu_clocksource_read(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+ unsigned long flags;
+ unsigned long long value;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+ if (tpu_get_counter(p, &value))
+ value += 0x100000000;
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+
+ return value;
+}
+
+static int tpu_clocksource_enable(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+
+ WARN_ON(p->cs_enabled);
+
+ iowrite16(0, p->mapbase1 + TCNT);
+ iowrite16(0, p->mapbase2 + TCNT);
+ iowrite8(0x0f, p->mapbase1 + TCR);
+ iowrite8(0x03, p->mapbase2 + TCR);
+
+ p->cs_enabled = true;
+ return 0;
+}
+
+static void tpu_clocksource_disable(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+
+ WARN_ON(!p->cs_enabled);
+
+ iowrite8(0, p->mapbase1 + TCR);
+ iowrite8(0, p->mapbase2 + TCR);
+ p->cs_enabled = false;
+}
+
+static struct tpu_priv tpu_priv = {
+ .cs = {
+ .name = "RX_TPU",
+ .rating = 200,
+ .read = tpu_clocksource_read,
+ .enable = tpu_clocksource_enable,
+ .disable = tpu_clocksource_disable,
+ .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ },
+};
+
+static void __init rx_tpu_init(struct device_node *node)
+{
+ void __iomem *base;
+ struct clk *clk;
+
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("failed to get clock for clocksource\n");
+ return;
+ }
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("failed to map registers for clocksource\n");
+ goto free_clk;
+ }
+
+ tpu_priv.mapbase1 = base + 0x20;
+ tpu_priv.mapbase2 = base + 0x30;
+ iowrite8(ioread8(base) | 0x06, base);
+ clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64);
+
+ return;
+
+free_clk:
+ clk_put(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(rx_tpu, "renesas,rx-tpu", rx_tpu_init);
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o
obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o
+obj-$(CONFIG_RX) += irq-renesas-rxicu.o
--- /dev/null
+/*
+ * RX interrupt controller driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/io.h>
+
+#define IRBASE 0x0000
+#define IERBASE 0x0200
+#define IPRBASE 0x0300
+
+#define IR (icu_base + IRBASE)
+#define IER (icu_base + IERBASE)
+#define IPR (icu_base + IPRBASE)
+
+static void *icu_base;
+
+static void disable_icua_irq(struct irq_data *data)
+{
+ void __iomem *ier = (void *)(IER + (data->irq >> 3));
+ unsigned char val;
+ val = ioread8(ier);
+ val &= ~(1 << (data->irq & 7));
+ iowrite8(val, ier);
+}
+
+static void enable_icua_irq(struct irq_data *data)
+{
+ void __iomem *ier = (void *)(IER + (data->irq >> 3));
+ unsigned char val;
+ val = ioread8(ier);
+ val |= 1 << (data->irq & 7);
+ iowrite8(val, ier);
+}
+
+static void icua_eoi(struct irq_data *data)
+{
+ iowrite8(0, (void *)(IR + data->irq));
+}
+
+static struct irq_chip chip = {
+ .name = "RX-ICUa",
+ .irq_mask = disable_icua_irq,
+ .irq_unmask = enable_icua_irq,
+ .irq_eoi = icua_eoi,
+ .irq_mask_ack = disable_icua_irq,
+};
+
+static int irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw_irq_num)
+{
+ irq_set_chip_and_handler(virq, &chip, handle_fasteoi_irq);
+
+ return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+ .map = irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int __init rx_icu_of_init(struct device_node *icu,
+ struct device_node *parent)
+{
+ struct irq_domain *domain;
+ int i;
+
+ icu_base = of_iomap(icu, 0);
+ domain = irq_domain_add_linear(icu, NR_IRQS, &irq_ops, NULL);
+ BUG_ON(!domain);
+ irq_set_default_host(domain);
+ irq_domain_associate_many(domain, 0, 0, NR_IRQS);
+ for (i = 0; i < 0x90; i++)
+ __raw_writeb(1, (void __iomem *)(IPR + i));
+ return 0;
+}
+
+IRQCHIP_DECLARE(rxicu, "renesas,rx-icu", rx_icu_of_init);