1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * SH generic board support, using device tree |
4 | * |
5 | * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. |
6 | */ |
7 | |
8 | #include <linux/of.h> |
9 | #include <linux/of_clk.h> |
10 | #include <linux/of_fdt.h> |
11 | #include <linux/clocksource.h> |
12 | #include <linux/irqchip.h> |
13 | #include <asm/machvec.h> |
14 | #include <asm/rtc.h> |
15 | |
16 | #ifdef CONFIG_SMP |
17 | |
18 | static void dummy_smp_setup(void) |
19 | { |
20 | } |
21 | |
22 | static void dummy_prepare_cpus(unsigned int max_cpus) |
23 | { |
24 | } |
25 | |
26 | static void dummy_start_cpu(unsigned int cpu, unsigned long entry_point) |
27 | { |
28 | } |
29 | |
30 | static unsigned int dummy_smp_processor_id(void) |
31 | { |
32 | return 0; |
33 | } |
34 | |
35 | static void dummy_send_ipi(unsigned int cpu, unsigned int message) |
36 | { |
37 | } |
38 | |
39 | static struct plat_smp_ops dummy_smp_ops = { |
40 | .smp_setup = dummy_smp_setup, |
41 | .prepare_cpus = dummy_prepare_cpus, |
42 | .start_cpu = dummy_start_cpu, |
43 | .smp_processor_id = dummy_smp_processor_id, |
44 | .send_ipi = dummy_send_ipi, |
45 | .cpu_die = native_cpu_die, |
46 | .cpu_disable = native_cpu_disable, |
47 | .play_dead = native_play_dead, |
48 | }; |
49 | |
50 | extern const struct of_cpu_method __cpu_method_of_table[]; |
51 | const struct of_cpu_method __cpu_method_of_table_sentinel |
52 | __section("__cpu_method_of_table_end" ); |
53 | |
54 | static void sh_of_smp_probe(void) |
55 | { |
56 | struct device_node *np; |
57 | const char *method = NULL; |
58 | const struct of_cpu_method *m = __cpu_method_of_table; |
59 | |
60 | pr_info("SH generic board support: scanning for cpus\n" ); |
61 | |
62 | init_cpu_possible(cpumask_of(0)); |
63 | |
64 | for_each_of_cpu_node(np) { |
65 | u64 id = of_get_cpu_hwid(cpun: np, thread: 0); |
66 | |
67 | if (id < NR_CPUS) { |
68 | if (!method) |
69 | of_property_read_string(np, propname: "enable-method" , out_string: &method); |
70 | set_cpu_possible(cpu: id, possible: true); |
71 | set_cpu_present(cpu: id, present: true); |
72 | __cpu_number_map[id] = id; |
73 | __cpu_logical_map[id] = id; |
74 | } |
75 | } |
76 | if (!method) { |
77 | np = of_find_node_by_name(NULL, name: "cpus" ); |
78 | of_property_read_string(np, propname: "enable-method" , out_string: &method); |
79 | of_node_put(node: np); |
80 | } |
81 | |
82 | pr_info("CPU enable method: %s\n" , method); |
83 | if (method) |
84 | for (; m->method; m++) |
85 | if (!strcmp(m->method, method)) { |
86 | register_smp_ops(m->ops); |
87 | return; |
88 | } |
89 | |
90 | register_smp_ops(&dummy_smp_ops); |
91 | } |
92 | |
93 | #else |
94 | |
95 | static void sh_of_smp_probe(void) |
96 | { |
97 | } |
98 | |
99 | #endif |
100 | |
101 | static void noop(void) |
102 | { |
103 | } |
104 | |
105 | static int noopi(void) |
106 | { |
107 | return 0; |
108 | } |
109 | |
110 | static void __init sh_of_mem_reserve(void) |
111 | { |
112 | early_init_fdt_reserve_self(); |
113 | early_init_fdt_scan_reserved_mem(); |
114 | } |
115 | |
116 | static void __init sh_of_setup(char **cmdline_p) |
117 | { |
118 | struct device_node *root; |
119 | |
120 | sh_mv.mv_name = "Unknown SH model" ; |
121 | root = of_find_node_by_path(path: "/" ); |
122 | if (root) { |
123 | of_property_read_string(np: root, propname: "model" , out_string: &sh_mv.mv_name); |
124 | of_node_put(node: root); |
125 | } |
126 | |
127 | sh_of_smp_probe(); |
128 | } |
129 | |
130 | static int sh_of_irq_demux(int irq) |
131 | { |
132 | /* FIXME: eventually this should not be used at all; |
133 | * the interrupt controller should set_handle_irq(). */ |
134 | return irq; |
135 | } |
136 | |
137 | static void __init sh_of_init_irq(void) |
138 | { |
139 | pr_info("SH generic board support: scanning for interrupt controllers\n" ); |
140 | irqchip_init(); |
141 | } |
142 | |
143 | static int __init sh_of_clk_init(void) |
144 | { |
145 | #ifdef CONFIG_COMMON_CLK |
146 | /* Disabled pending move to COMMON_CLK framework. */ |
147 | pr_info("SH generic board support: scanning for clk providers\n" ); |
148 | of_clk_init(NULL); |
149 | #endif |
150 | return 0; |
151 | } |
152 | |
153 | static struct sh_machine_vector __initmv sh_of_generic_mv = { |
154 | .mv_setup = sh_of_setup, |
155 | .mv_name = "devicetree" , /* replaced by DT root's model */ |
156 | .mv_irq_demux = sh_of_irq_demux, |
157 | .mv_init_irq = sh_of_init_irq, |
158 | .mv_clk_init = sh_of_clk_init, |
159 | .mv_mode_pins = noopi, |
160 | .mv_mem_init = noop, |
161 | .mv_mem_reserve = sh_of_mem_reserve, |
162 | }; |
163 | |
164 | struct sh_clk_ops; |
165 | |
166 | void __init __weak arch_init_clk_ops(struct sh_clk_ops **ops, int idx) |
167 | { |
168 | } |
169 | |
170 | void __init __weak plat_irq_setup(void) |
171 | { |
172 | } |
173 | |