diff options
-rw-r--r-- | Documentation/devicetree/booting-without-of.txt | 13 | ||||
-rw-r--r-- | arch/sh/boards/Kconfig | 15 | ||||
-rw-r--r-- | arch/sh/boards/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/boards/of-generic.c | 113 | ||||
-rw-r--r-- | arch/sh/kernel/head_32.S | 13 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 27 |
6 files changed, 183 insertions, 0 deletions
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt index 04d34f6a58f3..3f1437fbca6b 100644 --- a/Documentation/devicetree/booting-without-of.txt +++ b/Documentation/devicetree/booting-without-of.txt | |||
@@ -16,6 +16,7 @@ Table of Contents | |||
16 | 2) Entry point for arch/powerpc | 16 | 2) Entry point for arch/powerpc |
17 | 3) Entry point for arch/x86 | 17 | 3) Entry point for arch/x86 |
18 | 4) Entry point for arch/mips/bmips | 18 | 4) Entry point for arch/mips/bmips |
19 | 5) Entry point for arch/sh | ||
19 | 20 | ||
20 | II - The DT block format | 21 | II - The DT block format |
21 | 1) Header | 22 | 1) Header |
@@ -316,6 +317,18 @@ it with special cases. | |||
316 | This convention is defined for 32-bit systems only, as there are not | 317 | This convention is defined for 32-bit systems only, as there are not |
317 | currently any 64-bit BMIPS implementations. | 318 | currently any 64-bit BMIPS implementations. |
318 | 319 | ||
320 | 5) Entry point for arch/sh | ||
321 | -------------------------- | ||
322 | |||
323 | Device-tree-compatible SH bootloaders are expected to provide the physical | ||
324 | address of the device tree blob in r4. Since legacy bootloaders did not | ||
325 | guarantee any particular initial register state, kernels built to | ||
326 | inter-operate with old bootloaders must either use a builtin DTB or | ||
327 | select a legacy board option (something other than CONFIG_SH_DEVICE_TREE) | ||
328 | that does not use device tree. Support for the latter is being phased out | ||
329 | in favor of device tree. | ||
330 | |||
331 | |||
319 | II - The DT block format | 332 | II - The DT block format |
320 | ======================== | 333 | ======================== |
321 | 334 | ||
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 89963d13f930..5e52d5362292 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig | |||
@@ -6,6 +6,21 @@ config SOLUTION_ENGINE | |||
6 | config SH_ALPHA_BOARD | 6 | config SH_ALPHA_BOARD |
7 | bool | 7 | bool |
8 | 8 | ||
9 | config SH_DEVICE_TREE | ||
10 | bool "Board Described by Device Tree" | ||
11 | select OF | ||
12 | select OF_EARLY_FLATTREE | ||
13 | select CLKSRC_OF | ||
14 | select GENERIC_CALIBRATE_DELAY | ||
15 | help | ||
16 | Select Board Described by Device Tree to build a kernel that | ||
17 | does not hard-code any board-specific knowledge but instead uses | ||
18 | a device tree blob provided by the boot-loader. You must enable | ||
19 | drivers for any hardware you want to use separately. At this | ||
20 | time, only boards based on the open-hardware J-Core processors | ||
21 | have sufficient driver coverage to use this option; do not | ||
22 | select it if you are using original SuperH hardware. | ||
23 | |||
9 | config SH_SOLUTION_ENGINE | 24 | config SH_SOLUTION_ENGINE |
10 | bool "SolutionEngine" | 25 | bool "SolutionEngine" |
11 | select SOLUTION_ENGINE | 26 | select SOLUTION_ENGINE |
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile index 975a0f64ff20..cea300362035 100644 --- a/arch/sh/boards/Makefile +++ b/arch/sh/boards/Makefile | |||
@@ -15,3 +15,5 @@ obj-$(CONFIG_SH_TITAN) += board-titan.o | |||
15 | obj-$(CONFIG_SH_SH7757LCR) += board-sh7757lcr.o | 15 | obj-$(CONFIG_SH_SH7757LCR) += board-sh7757lcr.o |
16 | obj-$(CONFIG_SH_APSH4A3A) += board-apsh4a3a.o | 16 | obj-$(CONFIG_SH_APSH4A3A) += board-apsh4a3a.o |
17 | obj-$(CONFIG_SH_APSH4AD0A) += board-apsh4ad0a.o | 17 | obj-$(CONFIG_SH_APSH4AD0A) += board-apsh4ad0a.o |
18 | |||
19 | obj-$(CONFIG_SH_DEVICE_TREE) += of-generic.o | ||
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c new file mode 100644 index 000000000000..71d890932151 --- /dev/null +++ b/arch/sh/boards/of-generic.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * SH generic board support, using device tree | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/of.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/of_fdt.h> | ||
14 | #include <linux/of_iommu.h> | ||
15 | #include <linux/clocksource.h> | ||
16 | #include <linux/irqchip.h> | ||
17 | #include <linux/clk-provider.h> | ||
18 | #include <asm/machvec.h> | ||
19 | #include <asm/rtc.h> | ||
20 | |||
21 | static void noop(void) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | static int noopi(void) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static void __init sh_of_mem_reserve(void) | ||
31 | { | ||
32 | early_init_fdt_reserve_self(); | ||
33 | early_init_fdt_scan_reserved_mem(); | ||
34 | } | ||
35 | |||
36 | static void __init sh_of_time_init(void) | ||
37 | { | ||
38 | pr_info("SH generic board support: scanning for clocksource devices\n"); | ||
39 | clocksource_probe(); | ||
40 | } | ||
41 | |||
42 | static void __init sh_of_setup(char **cmdline_p) | ||
43 | { | ||
44 | unflatten_device_tree(); | ||
45 | |||
46 | board_time_init = sh_of_time_init; | ||
47 | |||
48 | sh_mv.mv_name = of_flat_dt_get_machine_name(); | ||
49 | if (!sh_mv.mv_name) | ||
50 | sh_mv.mv_name = "Unknown SH model"; | ||
51 | |||
52 | /* FIXME: register smp ops to use dt to find cpus, use | ||
53 | * cpu enable-method, and use irq controller's ipi | ||
54 | * functions. */ | ||
55 | } | ||
56 | |||
57 | static int sh_of_irq_demux(int irq) | ||
58 | { | ||
59 | /* FIXME: eventually this should not be used at all; | ||
60 | * the interrupt controller should set_handle_irq(). */ | ||
61 | return irq; | ||
62 | } | ||
63 | |||
64 | static void __init sh_of_init_irq(void) | ||
65 | { | ||
66 | pr_info("SH generic board support: scanning for interrupt controllers\n"); | ||
67 | irqchip_init(); | ||
68 | } | ||
69 | |||
70 | static int __init sh_of_clk_init(void) | ||
71 | { | ||
72 | #ifdef CONFIG_COMMON_CLK | ||
73 | /* Disabled pending move to COMMON_CLK framework. */ | ||
74 | pr_info("SH generic board support: scanning for clk providers\n"); | ||
75 | of_clk_init(NULL); | ||
76 | #endif | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct sh_machine_vector __initmv sh_of_generic_mv = { | ||
81 | .mv_setup = sh_of_setup, | ||
82 | .mv_name = "devicetree", /* replaced by DT root's model */ | ||
83 | .mv_irq_demux = sh_of_irq_demux, | ||
84 | .mv_init_irq = sh_of_init_irq, | ||
85 | .mv_clk_init = sh_of_clk_init, | ||
86 | .mv_mode_pins = noopi, | ||
87 | .mv_mem_init = noop, | ||
88 | .mv_mem_reserve = sh_of_mem_reserve, | ||
89 | }; | ||
90 | |||
91 | struct sh_clk_ops; | ||
92 | |||
93 | void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx) | ||
94 | { | ||
95 | } | ||
96 | |||
97 | void __init plat_irq_setup(void) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | static int __init sh_of_device_init(void) | ||
102 | { | ||
103 | pr_info("SH generic board support: populating platform devices\n"); | ||
104 | if (of_have_populated_dt()) { | ||
105 | of_iommu_init(); | ||
106 | of_platform_populate(NULL, of_default_bus_match_table, | ||
107 | NULL, NULL); | ||
108 | } else { | ||
109 | pr_crit("Device tree not populated\n"); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | arch_initcall_sync(sh_of_device_init); | ||
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 7db248936b60..974bc152cc84 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S | |||
@@ -66,6 +66,10 @@ ENTRY(_stext) | |||
66 | mov #0, r0 | 66 | mov #0, r0 |
67 | ldc r0, r6_bank | 67 | ldc r0, r6_bank |
68 | #endif | 68 | #endif |
69 | |||
70 | #ifdef CONFIG_OF | ||
71 | mov r4, r12 ! Store device tree blob pointer in r12 | ||
72 | #endif | ||
69 | 73 | ||
70 | /* | 74 | /* |
71 | * Prefetch if possible to reduce cache miss penalty. | 75 | * Prefetch if possible to reduce cache miss penalty. |
@@ -314,6 +318,12 @@ ENTRY(_stext) | |||
314 | 10: | 318 | 10: |
315 | #endif | 319 | #endif |
316 | 320 | ||
321 | #ifdef CONFIG_OF | ||
322 | mov.l 8f, r0 ! Make flat device tree available early. | ||
323 | jsr @r0 | ||
324 | mov r12, r4 | ||
325 | #endif | ||
326 | |||
317 | ! Additional CPU initialization | 327 | ! Additional CPU initialization |
318 | mov.l 6f, r0 | 328 | mov.l 6f, r0 |
319 | jsr @r0 | 329 | jsr @r0 |
@@ -339,6 +349,9 @@ ENTRY(stack_start) | |||
339 | 5: .long start_kernel | 349 | 5: .long start_kernel |
340 | 6: .long cpu_init | 350 | 6: .long cpu_init |
341 | 7: .long init_thread_union | 351 | 7: .long init_thread_union |
352 | #if defined(CONFIG_OF) | ||
353 | 8: .long sh_fdt_init | ||
354 | #endif | ||
342 | 355 | ||
343 | #ifdef CONFIG_PMB | 356 | #ifdef CONFIG_PMB |
344 | .LPMB_ADDR: .long PMB_ADDR | 357 | .LPMB_ADDR: .long PMB_ADDR |
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index de19cfa768f2..efb60ce720a7 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/memblock.h> | 31 | #include <linux/memblock.h> |
32 | #include <linux/of.h> | ||
33 | #include <linux/of_fdt.h> | ||
32 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
33 | #include <asm/io.h> | 35 | #include <asm/io.h> |
34 | #include <asm/page.h> | 36 | #include <asm/page.h> |
@@ -172,6 +174,7 @@ disable: | |||
172 | #endif | 174 | #endif |
173 | } | 175 | } |
174 | 176 | ||
177 | #ifndef CONFIG_GENERIC_CALIBRATE_DELAY | ||
175 | void calibrate_delay(void) | 178 | void calibrate_delay(void) |
176 | { | 179 | { |
177 | struct clk *clk = clk_get(NULL, "cpu_clk"); | 180 | struct clk *clk = clk_get(NULL, "cpu_clk"); |
@@ -187,6 +190,7 @@ void calibrate_delay(void) | |||
187 | (loops_per_jiffy/(5000/HZ)) % 100, | 190 | (loops_per_jiffy/(5000/HZ)) % 100, |
188 | loops_per_jiffy); | 191 | loops_per_jiffy); |
189 | } | 192 | } |
193 | #endif | ||
190 | 194 | ||
191 | void __init __add_active_range(unsigned int nid, unsigned long start_pfn, | 195 | void __init __add_active_range(unsigned int nid, unsigned long start_pfn, |
192 | unsigned long end_pfn) | 196 | unsigned long end_pfn) |
@@ -238,6 +242,29 @@ void __init __weak plat_early_device_setup(void) | |||
238 | { | 242 | { |
239 | } | 243 | } |
240 | 244 | ||
245 | #ifdef CONFIG_OF | ||
246 | void __ref sh_fdt_init(phys_addr_t dt_phys) | ||
247 | { | ||
248 | static int done = 0; | ||
249 | void *dt_virt; | ||
250 | |||
251 | /* Avoid calling an __init function on secondary cpus. */ | ||
252 | if (done) return; | ||
253 | |||
254 | dt_virt = phys_to_virt(dt_phys); | ||
255 | |||
256 | if (!dt_virt || !early_init_dt_scan(dt_virt)) { | ||
257 | pr_crit("Error: invalid device tree blob" | ||
258 | " at physical address %p\n", (void *)dt_phys); | ||
259 | |||
260 | while (true) | ||
261 | cpu_relax(); | ||
262 | } | ||
263 | |||
264 | done = 1; | ||
265 | } | ||
266 | #endif | ||
267 | |||
241 | void __init setup_arch(char **cmdline_p) | 268 | void __init setup_arch(char **cmdline_p) |
242 | { | 269 | { |
243 | enable_mmu(); | 270 | enable_mmu(); |