aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/generic/init.c
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2016-10-05 13:18:20 -0400
committerRalf Baechle <ralf@linux-mips.org>2016-10-06 12:04:04 -0400
commiteed0eabd12ef061821cbfa20d903476e07645320 (patch)
treedabf064a54995ba234fba3bd03d19f5dd07058c4 /arch/mips/generic/init.c
parentcf2a5e0bb4c66e8c43caf9f1be93a1bd7fd07b17 (diff)
MIPS: generic: Introduce generic DT-based board support
Introduce a "generic" platform, which aims to be board-agnostic by making use of device trees passed by the boot protocol defined in the MIPS UHI (Universal Hosting Interface) specification. Provision is made for supporting boards which use a legacy boot protocol that can't be changed, but adding support for such boards or any others is left to followon patches. Right now the built kernels expect to be loaded to 0x80100000, ie. in kseg0. This is fine for the vast majority of MIPS platforms, but nevertheless it would be good to remove this limitation in the future by mapping the kernel via the TLB such that it can be loaded anywhere & map itself appropriately. Configuration is handled by dynamically generating configs using scripts/kconfig/merge_config.sh, somewhat similar to the way powerpc makes use of it. This allows for variations upon the configuration, eg. differing architecture revisions or subsets of driver support for differing boards, to be handled without having a large number of defconfig files. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14353/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/generic/init.c')
-rw-r--r--arch/mips/generic/init.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
new file mode 100644
index 000000000000..0ea73e845440
--- /dev/null
+++ b/arch/mips/generic/init.c
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2016 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#include <linux/clk.h>
12#include <linux/clk-provider.h>
13#include <linux/clocksource.h>
14#include <linux/init.h>
15#include <linux/irqchip.h>
16#include <linux/of_fdt.h>
17#include <linux/of_platform.h>
18
19#include <asm/fw/fw.h>
20#include <asm/irq_cpu.h>
21#include <asm/machine.h>
22#include <asm/mips-cpc.h>
23#include <asm/prom.h>
24#include <asm/smp-ops.h>
25#include <asm/time.h>
26
27static __initdata const void *fdt;
28static __initdata const struct mips_machine *mach;
29static __initdata const void *mach_match_data;
30
31void __init prom_init(void)
32{
33 const struct mips_machine *check_mach;
34 const struct of_device_id *match;
35
36 if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
37 /*
38 * We booted using the UHI boot protocol, so we have been
39 * provided with the appropriate device tree for the board.
40 * Make use of it & search for any machine struct based upon
41 * the root compatible string.
42 */
43 fdt = (void *)fw_arg1;
44
45 for_each_mips_machine(check_mach) {
46 match = mips_machine_is_compatible(check_mach, fdt);
47 if (match) {
48 mach = check_mach;
49 mach_match_data = match->data;
50 break;
51 }
52 }
53 } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) {
54 /*
55 * We weren't booted using the UHI boot protocol, but do
56 * support some number of boards with legacy boot protocols.
57 * Attempt to find the right one.
58 */
59 for_each_mips_machine(check_mach) {
60 if (!check_mach->detect)
61 continue;
62
63 if (!check_mach->detect())
64 continue;
65
66 mach = check_mach;
67 }
68
69 /*
70 * If we don't recognise the machine then we can't continue, so
71 * die here.
72 */
73 BUG_ON(!mach);
74
75 /* Retrieve the machine's FDT */
76 fdt = mach->fdt;
77 }
78
79 BUG_ON(!fdt);
80}
81
82void __init *plat_get_fdt(void)
83{
84 return (void *)fdt;
85}
86
87void __init plat_mem_setup(void)
88{
89 if (mach && mach->fixup_fdt)
90 fdt = mach->fixup_fdt(fdt, mach_match_data);
91
92 strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
93 __dt_setup_arch((void *)fdt);
94}
95
96void __init device_tree_init(void)
97{
98 int err;
99
100 unflatten_and_copy_device_tree();
101 mips_cpc_probe();
102
103 err = register_cps_smp_ops();
104 if (err)
105 err = register_up_smp_ops();
106}
107
108void __init plat_time_init(void)
109{
110 struct device_node *np;
111 struct clk *clk;
112
113 of_clk_init(NULL);
114
115 if (!cpu_has_counter) {
116 mips_hpt_frequency = 0;
117 } else if (mach && mach->measure_hpt_freq) {
118 mips_hpt_frequency = mach->measure_hpt_freq();
119 } else {
120 np = of_get_cpu_node(0, NULL);
121 if (!np) {
122 pr_err("Failed to get CPU node\n");
123 return;
124 }
125
126 clk = of_clk_get(np, 0);
127 if (IS_ERR(clk)) {
128 pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
129 return;
130 }
131
132 mips_hpt_frequency = clk_get_rate(clk);
133 clk_put(clk);
134
135 switch (boot_cpu_type()) {
136 case CPU_20KC:
137 case CPU_25KF:
138 /* The counter runs at the CPU clock rate */
139 break;
140 default:
141 /* The counter runs at half the CPU clock rate */
142 mips_hpt_frequency /= 2;
143 break;
144 }
145 }
146
147 clocksource_probe();
148}
149
150void __init arch_init_irq(void)
151{
152 struct device_node *intc_node;
153
154 intc_node = of_find_compatible_node(NULL, NULL,
155 "mti,cpu-interrupt-controller");
156 if (!cpu_has_veic && !intc_node)
157 mips_cpu_irq_init();
158
159 irqchip_init();
160}
161
162static int __init publish_devices(void)
163{
164 if (!of_have_populated_dt())
165 panic("Device-tree not present");
166
167 if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL))
168 panic("Failed to populate DT");
169
170 return 0;
171}
172arch_initcall(publish_devices);
173
174void __init prom_free_prom_memory(void)
175{
176}