diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/mti-malta | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/mti-malta')
-rw-r--r-- | arch/mips/mti-malta/Makefile | 20 | ||||
-rw-r--r-- | arch/mips/mti-malta/Platform | 10 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-amon.c | 88 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-dt.c | 15 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-dtshim.c | 333 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-init.c | 298 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-int.c | 223 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-memory.c | 48 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-platform.c | 76 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-setup.c | 249 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-time.c | 256 |
11 files changed, 1616 insertions, 0 deletions
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile new file mode 100644 index 000000000..94c11f5ea --- /dev/null +++ b/arch/mips/mti-malta/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | # | ||
3 | # Carsten Langgaard, carstenl@mips.com | ||
4 | # Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | # | ||
6 | # Copyright (C) 2008 Wind River Systems, Inc. | ||
7 | # written by Ralf Baechle <ralf@linux-mips.org> | ||
8 | # | ||
9 | obj-y += malta-dt.o | ||
10 | obj-y += malta-dtshim.o | ||
11 | obj-y += malta-init.o | ||
12 | obj-y += malta-int.o | ||
13 | obj-y += malta-memory.o | ||
14 | obj-y += malta-platform.o | ||
15 | obj-y += malta-setup.o | ||
16 | obj-y += malta-time.o | ||
17 | |||
18 | obj-$(CONFIG_MIPS_CMP) += malta-amon.o | ||
19 | |||
20 | CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt | ||
diff --git a/arch/mips/mti-malta/Platform b/arch/mips/mti-malta/Platform new file mode 100644 index 000000000..41e0d2a2d --- /dev/null +++ b/arch/mips/mti-malta/Platform | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # MIPS Malta board | ||
3 | # | ||
4 | cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta | ||
5 | ifdef CONFIG_KVM_GUEST | ||
6 | load-$(CONFIG_MIPS_MALTA) += 0x0000000040100000 | ||
7 | else | ||
8 | load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000 | ||
9 | endif | ||
10 | all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin | ||
diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c new file mode 100644 index 000000000..84ac523b0 --- /dev/null +++ b/arch/mips/mti-malta/malta-amon.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2007 MIPS Technologies, Inc. All rights reserved. | ||
7 | * Copyright (C) 2013 Imagination Technologies Ltd. | ||
8 | * | ||
9 | * Arbitrary Monitor Interface | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/smp.h> | ||
13 | |||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/mipsmtregs.h> | ||
16 | #include <asm/mips-boards/launch.h> | ||
17 | #include <asm/vpe.h> | ||
18 | |||
19 | int amon_cpu_avail(int cpu) | ||
20 | { | ||
21 | struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); | ||
22 | |||
23 | if (cpu < 0 || cpu >= NCPULAUNCH) { | ||
24 | pr_debug("avail: cpu%d is out of range\n", cpu); | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | launch += cpu; | ||
29 | if (!(launch->flags & LAUNCH_FREADY)) { | ||
30 | pr_debug("avail: cpu%d is not ready\n", cpu); | ||
31 | return 0; | ||
32 | } | ||
33 | if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { | ||
34 | pr_debug("avail: too late.. cpu%d is already gone\n", cpu); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | return 1; | ||
39 | } | ||
40 | |||
41 | int amon_cpu_start(int cpu, | ||
42 | unsigned long pc, unsigned long sp, | ||
43 | unsigned long gp, unsigned long a0) | ||
44 | { | ||
45 | volatile struct cpulaunch *launch = | ||
46 | (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); | ||
47 | |||
48 | if (!amon_cpu_avail(cpu)) | ||
49 | return -1; | ||
50 | if (cpu == smp_processor_id()) { | ||
51 | pr_debug("launch: I am cpu%d!\n", cpu); | ||
52 | return -1; | ||
53 | } | ||
54 | launch += cpu; | ||
55 | |||
56 | pr_debug("launch: starting cpu%d\n", cpu); | ||
57 | |||
58 | launch->pc = pc; | ||
59 | launch->gp = gp; | ||
60 | launch->sp = sp; | ||
61 | launch->a0 = a0; | ||
62 | |||
63 | smp_wmb(); /* Target must see parameters before go */ | ||
64 | launch->flags |= LAUNCH_FGO; | ||
65 | smp_wmb(); /* Target must see go before we poll */ | ||
66 | |||
67 | while ((launch->flags & LAUNCH_FGONE) == 0) | ||
68 | ; | ||
69 | smp_rmb(); /* Target will be updating flags soon */ | ||
70 | pr_debug("launch: cpu%d gone!\n", cpu); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | #ifdef CONFIG_MIPS_VPE_LOADER_CMP | ||
76 | int vpe_run(struct vpe *v) | ||
77 | { | ||
78 | struct vpe_notifications *n; | ||
79 | |||
80 | if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0) | ||
81 | return -1; | ||
82 | |||
83 | list_for_each_entry(n, &v->notify, list) | ||
84 | n->start(VPE_MODULE_MINOR); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | #endif | ||
diff --git a/arch/mips/mti-malta/malta-dt.c b/arch/mips/mti-malta/malta-dt.c new file mode 100644 index 000000000..d045c9149 --- /dev/null +++ b/arch/mips/mti-malta/malta-dt.c | |||
@@ -0,0 +1,15 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2015 Imagination Technologies | ||
4 | * Author: Paul Burton <paul.burton@mips.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/clk-provider.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/of_fdt.h> | ||
10 | #include <linux/of_platform.h> | ||
11 | |||
12 | void __init device_tree_init(void) | ||
13 | { | ||
14 | unflatten_and_copy_device_tree(); | ||
15 | } | ||
diff --git a/arch/mips/mti-malta/malta-dtshim.c b/arch/mips/mti-malta/malta-dtshim.c new file mode 100644 index 000000000..f451268f6 --- /dev/null +++ b/arch/mips/mti-malta/malta-dtshim.c | |||
@@ -0,0 +1,333 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2015 Imagination Technologies | ||
4 | * Author: Paul Burton <paul.burton@mips.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/bug.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/libfdt.h> | ||
10 | #include <linux/of_fdt.h> | ||
11 | #include <linux/sizes.h> | ||
12 | #include <asm/addrspace.h> | ||
13 | #include <asm/bootinfo.h> | ||
14 | #include <asm/fw/fw.h> | ||
15 | #include <asm/mips-boards/generic.h> | ||
16 | #include <asm/mips-boards/malta.h> | ||
17 | #include <asm/mips-cps.h> | ||
18 | #include <asm/page.h> | ||
19 | |||
20 | #define ROCIT_REG_BASE 0x1f403000 | ||
21 | #define ROCIT_CONFIG_GEN1 (ROCIT_REG_BASE + 0x04) | ||
22 | #define ROCIT_CONFIG_GEN1_MEMMAP_SHIFT 8 | ||
23 | #define ROCIT_CONFIG_GEN1_MEMMAP_MASK (0xf << 8) | ||
24 | |||
25 | static unsigned char fdt_buf[16 << 10] __initdata __aligned(8); | ||
26 | |||
27 | /* determined physical memory size, not overridden by command line args */ | ||
28 | extern unsigned long physical_memsize; | ||
29 | |||
30 | enum mem_map { | ||
31 | MEM_MAP_V1 = 0, | ||
32 | MEM_MAP_V2, | ||
33 | }; | ||
34 | |||
35 | #define MAX_MEM_ARRAY_ENTRIES 2 | ||
36 | |||
37 | static __init int malta_scon(void) | ||
38 | { | ||
39 | int scon = MIPS_REVISION_SCONID; | ||
40 | |||
41 | if (scon != MIPS_REVISION_SCON_OTHER) | ||
42 | return scon; | ||
43 | |||
44 | switch (MIPS_REVISION_CORID) { | ||
45 | case MIPS_REVISION_CORID_QED_RM5261: | ||
46 | case MIPS_REVISION_CORID_CORE_LV: | ||
47 | case MIPS_REVISION_CORID_CORE_FPGA: | ||
48 | case MIPS_REVISION_CORID_CORE_FPGAR2: | ||
49 | return MIPS_REVISION_SCON_GT64120; | ||
50 | |||
51 | case MIPS_REVISION_CORID_CORE_EMUL_BON: | ||
52 | case MIPS_REVISION_CORID_BONITO64: | ||
53 | case MIPS_REVISION_CORID_CORE_20K: | ||
54 | return MIPS_REVISION_SCON_BONITO; | ||
55 | |||
56 | case MIPS_REVISION_CORID_CORE_MSC: | ||
57 | case MIPS_REVISION_CORID_CORE_FPGA2: | ||
58 | case MIPS_REVISION_CORID_CORE_24K: | ||
59 | return MIPS_REVISION_SCON_SOCIT; | ||
60 | |||
61 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
62 | case MIPS_REVISION_CORID_CORE_FPGA4: | ||
63 | case MIPS_REVISION_CORID_CORE_FPGA5: | ||
64 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
65 | default: | ||
66 | return MIPS_REVISION_SCON_ROCIT; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size, | ||
71 | enum mem_map map) | ||
72 | { | ||
73 | unsigned long size_preio; | ||
74 | unsigned entries; | ||
75 | |||
76 | entries = 1; | ||
77 | mem_array[0] = cpu_to_be32(PHYS_OFFSET); | ||
78 | if (IS_ENABLED(CONFIG_EVA)) { | ||
79 | /* | ||
80 | * The current Malta EVA configuration is "special" in that it | ||
81 | * always makes use of addresses in the upper half of the 32 bit | ||
82 | * physical address map, which gives it a contiguous region of | ||
83 | * DDR but limits it to 2GB. | ||
84 | */ | ||
85 | mem_array[1] = cpu_to_be32(size); | ||
86 | goto done; | ||
87 | } | ||
88 | |||
89 | size_preio = min_t(unsigned long, size, SZ_256M); | ||
90 | mem_array[1] = cpu_to_be32(size_preio); | ||
91 | size -= size_preio; | ||
92 | if (!size) | ||
93 | goto done; | ||
94 | |||
95 | if (map == MEM_MAP_V2) { | ||
96 | /* | ||
97 | * We have a flat 32 bit physical memory map with DDR filling | ||
98 | * all 4GB of the memory map, apart from the I/O region which | ||
99 | * obscures 256MB from 0x10000000-0x1fffffff. | ||
100 | * | ||
101 | * Therefore we discard the 256MB behind the I/O region. | ||
102 | */ | ||
103 | if (size <= SZ_256M) | ||
104 | goto done; | ||
105 | size -= SZ_256M; | ||
106 | |||
107 | /* Make use of the memory following the I/O region */ | ||
108 | entries++; | ||
109 | mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_512M); | ||
110 | mem_array[3] = cpu_to_be32(size); | ||
111 | } else { | ||
112 | /* | ||
113 | * We have a 32 bit physical memory map with a 2GB DDR region | ||
114 | * aliased in the upper & lower halves of it. The I/O region | ||
115 | * obscures 256MB from 0x10000000-0x1fffffff in the low alias | ||
116 | * but the DDR it obscures is accessible via the high alias. | ||
117 | * | ||
118 | * Simply access everything beyond the lowest 256MB of DDR using | ||
119 | * the high alias. | ||
120 | */ | ||
121 | entries++; | ||
122 | mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_2G + SZ_256M); | ||
123 | mem_array[3] = cpu_to_be32(size); | ||
124 | } | ||
125 | |||
126 | done: | ||
127 | BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES); | ||
128 | return entries; | ||
129 | } | ||
130 | |||
131 | static void __init append_memory(void *fdt, int root_off) | ||
132 | { | ||
133 | __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES]; | ||
134 | unsigned long memsize; | ||
135 | unsigned mem_entries; | ||
136 | int i, err, mem_off; | ||
137 | enum mem_map mem_map; | ||
138 | u32 config; | ||
139 | char *var, param_name[10], *var_names[] = { | ||
140 | "ememsize", "memsize", | ||
141 | }; | ||
142 | |||
143 | /* if a memory node already exists, leave it alone */ | ||
144 | mem_off = fdt_path_offset(fdt, "/memory"); | ||
145 | if (mem_off >= 0) | ||
146 | return; | ||
147 | |||
148 | /* find memory size from the bootloader environment */ | ||
149 | for (i = 0; i < ARRAY_SIZE(var_names); i++) { | ||
150 | var = fw_getenv(var_names[i]); | ||
151 | if (!var) | ||
152 | continue; | ||
153 | |||
154 | err = kstrtoul(var, 0, &physical_memsize); | ||
155 | if (!err) | ||
156 | break; | ||
157 | |||
158 | pr_warn("Failed to read the '%s' env variable '%s'\n", | ||
159 | var_names[i], var); | ||
160 | } | ||
161 | |||
162 | if (!physical_memsize) { | ||
163 | pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); | ||
164 | physical_memsize = 32 << 20; | ||
165 | } | ||
166 | |||
167 | if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { | ||
168 | /* | ||
169 | * SOC-it swaps, or perhaps doesn't swap, when DMA'ing | ||
170 | * the last word of physical memory. | ||
171 | */ | ||
172 | physical_memsize -= PAGE_SIZE; | ||
173 | } | ||
174 | |||
175 | /* default to using all available RAM */ | ||
176 | memsize = physical_memsize; | ||
177 | |||
178 | /* allow the user to override the usable memory */ | ||
179 | for (i = 0; i < ARRAY_SIZE(var_names); i++) { | ||
180 | snprintf(param_name, sizeof(param_name), "%s=", var_names[i]); | ||
181 | var = strstr(arcs_cmdline, param_name); | ||
182 | if (!var) | ||
183 | continue; | ||
184 | |||
185 | memsize = memparse(var + strlen(param_name), NULL); | ||
186 | } | ||
187 | |||
188 | /* if the user says there's more RAM than we thought, believe them */ | ||
189 | physical_memsize = max_t(unsigned long, physical_memsize, memsize); | ||
190 | |||
191 | /* detect the memory map in use */ | ||
192 | if (malta_scon() == MIPS_REVISION_SCON_ROCIT) { | ||
193 | /* ROCit has a register indicating the memory map in use */ | ||
194 | config = readl((void __iomem *)CKSEG1ADDR(ROCIT_CONFIG_GEN1)); | ||
195 | mem_map = config & ROCIT_CONFIG_GEN1_MEMMAP_MASK; | ||
196 | mem_map >>= ROCIT_CONFIG_GEN1_MEMMAP_SHIFT; | ||
197 | } else { | ||
198 | /* if not using ROCit, presume the v1 memory map */ | ||
199 | mem_map = MEM_MAP_V1; | ||
200 | } | ||
201 | if (mem_map > MEM_MAP_V2) | ||
202 | panic("Unsupported physical memory map v%u detected", | ||
203 | (unsigned int)mem_map); | ||
204 | |||
205 | /* append memory to the DT */ | ||
206 | mem_off = fdt_add_subnode(fdt, root_off, "memory"); | ||
207 | if (mem_off < 0) | ||
208 | panic("Unable to add memory node to DT: %d", mem_off); | ||
209 | |||
210 | err = fdt_setprop_string(fdt, mem_off, "device_type", "memory"); | ||
211 | if (err) | ||
212 | panic("Unable to set memory node device_type: %d", err); | ||
213 | |||
214 | mem_entries = gen_fdt_mem_array(mem_array, physical_memsize, mem_map); | ||
215 | err = fdt_setprop(fdt, mem_off, "reg", mem_array, | ||
216 | mem_entries * 2 * sizeof(mem_array[0])); | ||
217 | if (err) | ||
218 | panic("Unable to set memory regs property: %d", err); | ||
219 | |||
220 | mem_entries = gen_fdt_mem_array(mem_array, memsize, mem_map); | ||
221 | err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array, | ||
222 | mem_entries * 2 * sizeof(mem_array[0])); | ||
223 | if (err) | ||
224 | panic("Unable to set linux,usable-memory property: %d", err); | ||
225 | } | ||
226 | |||
227 | static void __init remove_gic(void *fdt) | ||
228 | { | ||
229 | int err, gic_off, i8259_off, cpu_off; | ||
230 | void __iomem *biu_base; | ||
231 | uint32_t cpu_phandle, sc_cfg; | ||
232 | |||
233 | /* if we have a CM which reports a GIC is present, leave the DT alone */ | ||
234 | err = mips_cm_probe(); | ||
235 | if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX)) | ||
236 | return; | ||
237 | |||
238 | if (malta_scon() == MIPS_REVISION_SCON_ROCIT) { | ||
239 | /* | ||
240 | * On systems using the RocIT system controller a GIC may be | ||
241 | * present without a CM. Detect whether that is the case. | ||
242 | */ | ||
243 | biu_base = ioremap(MSC01_BIU_REG_BASE, | ||
244 | MSC01_BIU_ADDRSPACE_SZ); | ||
245 | sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS); | ||
246 | if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) { | ||
247 | /* enable the GIC at the system controller level */ | ||
248 | sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF); | ||
249 | __raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS); | ||
250 | return; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic"); | ||
255 | if (gic_off < 0) { | ||
256 | pr_warn("malta-dtshim: unable to find DT GIC node: %d\n", | ||
257 | gic_off); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | err = fdt_nop_node(fdt, gic_off); | ||
262 | if (err) | ||
263 | pr_warn("malta-dtshim: unable to nop GIC node\n"); | ||
264 | |||
265 | i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259"); | ||
266 | if (i8259_off < 0) { | ||
267 | pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n", | ||
268 | i8259_off); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | cpu_off = fdt_node_offset_by_compatible(fdt, -1, | ||
273 | "mti,cpu-interrupt-controller"); | ||
274 | if (cpu_off < 0) { | ||
275 | pr_warn("malta-dtshim: unable to find CPU intc node: %d\n", | ||
276 | cpu_off); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | cpu_phandle = fdt_get_phandle(fdt, cpu_off); | ||
281 | if (!cpu_phandle) { | ||
282 | pr_warn("malta-dtshim: unable to get CPU intc phandle\n"); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle); | ||
287 | if (err) { | ||
288 | pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n", | ||
289 | err); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2); | ||
294 | if (err) { | ||
295 | pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n", | ||
296 | err); | ||
297 | return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void __init *malta_dt_shim(void *fdt) | ||
302 | { | ||
303 | int root_off, len, err; | ||
304 | const char *compat; | ||
305 | |||
306 | if (fdt_check_header(fdt)) | ||
307 | panic("Corrupt DT"); | ||
308 | |||
309 | err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf)); | ||
310 | if (err) | ||
311 | panic("Unable to open FDT: %d", err); | ||
312 | |||
313 | root_off = fdt_path_offset(fdt_buf, "/"); | ||
314 | if (root_off < 0) | ||
315 | panic("No / node in DT"); | ||
316 | |||
317 | compat = fdt_getprop(fdt_buf, root_off, "compatible", &len); | ||
318 | if (!compat) | ||
319 | panic("No root compatible property in DT: %d", len); | ||
320 | |||
321 | /* if this isn't Malta, leave the DT alone */ | ||
322 | if (strncmp(compat, "mti,malta", len)) | ||
323 | return fdt; | ||
324 | |||
325 | append_memory(fdt_buf, root_off); | ||
326 | remove_gic(fdt_buf); | ||
327 | |||
328 | err = fdt_pack(fdt_buf); | ||
329 | if (err) | ||
330 | panic("Unable to pack FDT: %d\n", err); | ||
331 | |||
332 | return fdt_buf; | ||
333 | } | ||
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c new file mode 100644 index 000000000..893af377a --- /dev/null +++ b/arch/mips/mti-malta/malta-init.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * PROM library initialisation code. | ||
7 | * | ||
8 | * Copyright (C) 1999,2000,2004,2005,2012 MIPS Technologies, Inc. | ||
9 | * All rights reserved. | ||
10 | * Authors: Carsten Langgaard <carstenl@mips.com> | ||
11 | * Maciej W. Rozycki <macro@mips.com> | ||
12 | * Steven J. Hill <sjhill@mips.com> | ||
13 | */ | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/pci_regs.h> | ||
18 | #include <linux/serial_core.h> | ||
19 | |||
20 | #include <asm/cacheflush.h> | ||
21 | #include <asm/smp-ops.h> | ||
22 | #include <asm/traps.h> | ||
23 | #include <asm/fw/fw.h> | ||
24 | #include <asm/mips-cps.h> | ||
25 | #include <asm/mips-boards/generic.h> | ||
26 | #include <asm/mips-boards/malta.h> | ||
27 | |||
28 | static int mips_revision_corid; | ||
29 | int mips_revision_sconid; | ||
30 | |||
31 | /* Bonito64 system controller register base. */ | ||
32 | unsigned long _pcictrl_bonito; | ||
33 | unsigned long _pcictrl_bonito_pcicfg; | ||
34 | |||
35 | /* GT64120 system controller register base */ | ||
36 | unsigned long _pcictrl_gt64120; | ||
37 | |||
38 | /* MIPS System controller register base */ | ||
39 | unsigned long _pcictrl_msc; | ||
40 | |||
41 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
42 | static void __init console_config(void) | ||
43 | { | ||
44 | char console_string[40]; | ||
45 | int baud = 0; | ||
46 | char parity = '\0', bits = '\0', flow = '\0'; | ||
47 | char *s; | ||
48 | |||
49 | s = fw_getenv("modetty0"); | ||
50 | if (s) { | ||
51 | while (*s >= '0' && *s <= '9') | ||
52 | baud = baud*10 + *s++ - '0'; | ||
53 | if (*s == ',') | ||
54 | s++; | ||
55 | if (*s) | ||
56 | parity = *s++; | ||
57 | if (*s == ',') | ||
58 | s++; | ||
59 | if (*s) | ||
60 | bits = *s++; | ||
61 | if (*s == ',') | ||
62 | s++; | ||
63 | if (*s == 'h') | ||
64 | flow = 'r'; | ||
65 | } | ||
66 | if (baud == 0) | ||
67 | baud = 38400; | ||
68 | if (parity != 'n' && parity != 'o' && parity != 'e') | ||
69 | parity = 'n'; | ||
70 | if (bits != '7' && bits != '8') | ||
71 | bits = '8'; | ||
72 | if (flow == '\0') | ||
73 | flow = 'r'; | ||
74 | |||
75 | if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) { | ||
76 | sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud, | ||
77 | parity, bits); | ||
78 | setup_earlycon(console_string); | ||
79 | } | ||
80 | |||
81 | if ((strstr(fw_getcmdline(), "console=")) == NULL) { | ||
82 | sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, | ||
83 | parity, bits, flow); | ||
84 | strcat(fw_getcmdline(), console_string); | ||
85 | pr_info("Config serial console:%s\n", console_string); | ||
86 | } | ||
87 | } | ||
88 | #endif | ||
89 | |||
90 | static void __init mips_nmi_setup(void) | ||
91 | { | ||
92 | void *base; | ||
93 | extern char except_vec_nmi[]; | ||
94 | |||
95 | base = cpu_has_veic ? | ||
96 | (void *)(CAC_BASE + 0xa80) : | ||
97 | (void *)(CAC_BASE + 0x380); | ||
98 | memcpy(base, except_vec_nmi, 0x80); | ||
99 | flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); | ||
100 | } | ||
101 | |||
102 | static void __init mips_ejtag_setup(void) | ||
103 | { | ||
104 | void *base; | ||
105 | extern char except_vec_ejtag_debug[]; | ||
106 | |||
107 | base = cpu_has_veic ? | ||
108 | (void *)(CAC_BASE + 0xa00) : | ||
109 | (void *)(CAC_BASE + 0x300); | ||
110 | memcpy(base, except_vec_ejtag_debug, 0x80); | ||
111 | flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); | ||
112 | } | ||
113 | |||
114 | phys_addr_t mips_cpc_default_phys_base(void) | ||
115 | { | ||
116 | return CPC_BASE_ADDR; | ||
117 | } | ||
118 | |||
119 | void __init prom_init(void) | ||
120 | { | ||
121 | /* | ||
122 | * early setup of _pcictrl_bonito so that we can determine | ||
123 | * the system controller on a CORE_EMUL board | ||
124 | */ | ||
125 | _pcictrl_bonito = (unsigned long)ioremap(BONITO_REG_BASE, BONITO_REG_SIZE); | ||
126 | |||
127 | mips_revision_corid = MIPS_REVISION_CORID; | ||
128 | |||
129 | if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) { | ||
130 | if (BONITO_PCIDID == 0x0001df53 || | ||
131 | BONITO_PCIDID == 0x0003df53) | ||
132 | mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON; | ||
133 | else | ||
134 | mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_MSC; | ||
135 | } | ||
136 | |||
137 | mips_revision_sconid = MIPS_REVISION_SCONID; | ||
138 | if (mips_revision_sconid == MIPS_REVISION_SCON_OTHER) { | ||
139 | switch (mips_revision_corid) { | ||
140 | case MIPS_REVISION_CORID_QED_RM5261: | ||
141 | case MIPS_REVISION_CORID_CORE_LV: | ||
142 | case MIPS_REVISION_CORID_CORE_FPGA: | ||
143 | case MIPS_REVISION_CORID_CORE_FPGAR2: | ||
144 | mips_revision_sconid = MIPS_REVISION_SCON_GT64120; | ||
145 | break; | ||
146 | case MIPS_REVISION_CORID_CORE_EMUL_BON: | ||
147 | case MIPS_REVISION_CORID_BONITO64: | ||
148 | case MIPS_REVISION_CORID_CORE_20K: | ||
149 | mips_revision_sconid = MIPS_REVISION_SCON_BONITO; | ||
150 | break; | ||
151 | case MIPS_REVISION_CORID_CORE_MSC: | ||
152 | case MIPS_REVISION_CORID_CORE_FPGA2: | ||
153 | case MIPS_REVISION_CORID_CORE_24K: | ||
154 | /* | ||
155 | * SOCit/ROCit support is essentially identical | ||
156 | * but make an attempt to distinguish them | ||
157 | */ | ||
158 | mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; | ||
159 | break; | ||
160 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
161 | case MIPS_REVISION_CORID_CORE_FPGA4: | ||
162 | case MIPS_REVISION_CORID_CORE_FPGA5: | ||
163 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
164 | default: | ||
165 | /* See above */ | ||
166 | mips_revision_sconid = MIPS_REVISION_SCON_ROCIT; | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | switch (mips_revision_sconid) { | ||
172 | u32 start, map, mask, data; | ||
173 | |||
174 | case MIPS_REVISION_SCON_GT64120: | ||
175 | /* | ||
176 | * Setup the North bridge to do Master byte-lane swapping | ||
177 | * when running in bigendian. | ||
178 | */ | ||
179 | _pcictrl_gt64120 = (unsigned long)ioremap(MIPS_GT_BASE, 0x2000); | ||
180 | |||
181 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
182 | GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT | | ||
183 | GT_PCI0_CMD_SBYTESWAP_BIT); | ||
184 | #else | ||
185 | GT_WRITE(GT_PCI0_CMD_OFS, 0); | ||
186 | #endif | ||
187 | /* Fix up PCI I/O mapping if necessary (for Atlas). */ | ||
188 | start = GT_READ(GT_PCI0IOLD_OFS); | ||
189 | map = GT_READ(GT_PCI0IOREMAP_OFS); | ||
190 | if ((start & map) != 0) { | ||
191 | map &= ~start; | ||
192 | GT_WRITE(GT_PCI0IOREMAP_OFS, map); | ||
193 | } | ||
194 | |||
195 | set_io_port_base(MALTA_GT_PORT_BASE); | ||
196 | break; | ||
197 | |||
198 | case MIPS_REVISION_SCON_BONITO: | ||
199 | _pcictrl_bonito_pcicfg = (unsigned long)ioremap(BONITO_PCICFG_BASE, BONITO_PCICFG_SIZE); | ||
200 | |||
201 | /* | ||
202 | * Disable Bonito IOBC. | ||
203 | */ | ||
204 | BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & | ||
205 | ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | | ||
206 | BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); | ||
207 | |||
208 | /* | ||
209 | * Setup the North bridge to do Master byte-lane swapping | ||
210 | * when running in bigendian. | ||
211 | */ | ||
212 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
213 | BONITO_BONGENCFG = BONITO_BONGENCFG & | ||
214 | ~(BONITO_BONGENCFG_MSTRBYTESWAP | | ||
215 | BONITO_BONGENCFG_BYTESWAP); | ||
216 | #else | ||
217 | BONITO_BONGENCFG = BONITO_BONGENCFG | | ||
218 | BONITO_BONGENCFG_MSTRBYTESWAP | | ||
219 | BONITO_BONGENCFG_BYTESWAP; | ||
220 | #endif | ||
221 | |||
222 | set_io_port_base(MALTA_BONITO_PORT_BASE); | ||
223 | break; | ||
224 | |||
225 | case MIPS_REVISION_SCON_SOCIT: | ||
226 | case MIPS_REVISION_SCON_ROCIT: | ||
227 | _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); | ||
228 | mips_pci_controller: | ||
229 | mb(); | ||
230 | MSC_READ(MSC01_PCI_CFG, data); | ||
231 | MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT); | ||
232 | wmb(); | ||
233 | |||
234 | /* Fix up lane swapping. */ | ||
235 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
236 | MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP); | ||
237 | #else | ||
238 | MSC_WRITE(MSC01_PCI_SWAP, | ||
239 | MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_IO_SHF | | ||
240 | MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF | | ||
241 | MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF); | ||
242 | #endif | ||
243 | |||
244 | /* | ||
245 | * Setup the Malta max (2GB) memory for PCI DMA in host bridge | ||
246 | * in transparent addressing mode. | ||
247 | */ | ||
248 | mask = PHYS_OFFSET | PCI_BASE_ADDRESS_MEM_PREFETCH; | ||
249 | MSC_WRITE(MSC01_PCI_BAR0, mask); | ||
250 | MSC_WRITE(MSC01_PCI_HEAD4, mask); | ||
251 | |||
252 | mask &= MSC01_PCI_BAR0_SIZE_MSK; | ||
253 | MSC_WRITE(MSC01_PCI_P2SCMSKL, mask); | ||
254 | MSC_WRITE(MSC01_PCI_P2SCMAPL, mask); | ||
255 | |||
256 | /* Don't handle target retries indefinitely. */ | ||
257 | if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) == | ||
258 | MSC01_PCI_CFG_MAXRTRY_MSK) | ||
259 | data = (data & ~(MSC01_PCI_CFG_MAXRTRY_MSK << | ||
260 | MSC01_PCI_CFG_MAXRTRY_SHF)) | | ||
261 | ((MSC01_PCI_CFG_MAXRTRY_MSK - 1) << | ||
262 | MSC01_PCI_CFG_MAXRTRY_SHF); | ||
263 | |||
264 | wmb(); | ||
265 | MSC_WRITE(MSC01_PCI_CFG, data); | ||
266 | mb(); | ||
267 | |||
268 | set_io_port_base(MALTA_MSC_PORT_BASE); | ||
269 | break; | ||
270 | |||
271 | case MIPS_REVISION_SCON_SOCITSC: | ||
272 | case MIPS_REVISION_SCON_SOCITSCP: | ||
273 | _pcictrl_msc = (unsigned long)ioremap(MIPS_SOCITSC_PCI_REG_BASE, 0x2000); | ||
274 | goto mips_pci_controller; | ||
275 | |||
276 | default: | ||
277 | /* Unknown system controller */ | ||
278 | while (1); /* We die here... */ | ||
279 | } | ||
280 | board_nmi_handler_setup = mips_nmi_setup; | ||
281 | board_ejtag_handler_setup = mips_ejtag_setup; | ||
282 | |||
283 | fw_init_cmdline(); | ||
284 | fw_meminit(); | ||
285 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
286 | console_config(); | ||
287 | #endif | ||
288 | /* Early detection of CMP support */ | ||
289 | mips_cpc_probe(); | ||
290 | |||
291 | if (!register_cps_smp_ops()) | ||
292 | return; | ||
293 | if (!register_cmp_smp_ops()) | ||
294 | return; | ||
295 | if (!register_vsmp_smp_ops()) | ||
296 | return; | ||
297 | register_up_smp_ops(); | ||
298 | } | ||
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c new file mode 100644 index 000000000..03d85b2b3 --- /dev/null +++ b/arch/mips/mti-malta/malta-int.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Carsten Langgaard, carstenl@mips.com | ||
7 | * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. | ||
8 | * Copyright (C) 2001 Ralf Baechle | ||
9 | * Copyright (C) 2013 Imagination Technologies Ltd. | ||
10 | * | ||
11 | * Routines for generic manipulation of the interrupts found on the MIPS | ||
12 | * Malta board. The interrupt controller is located in the South Bridge | ||
13 | * a PIIX4 device with two internal 82C95 interrupt controllers. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/irqchip.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/smp.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/kernel_stat.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/random.h> | ||
26 | |||
27 | #include <asm/traps.h> | ||
28 | #include <asm/i8259.h> | ||
29 | #include <asm/irq_cpu.h> | ||
30 | #include <asm/irq_regs.h> | ||
31 | #include <asm/mips-boards/malta.h> | ||
32 | #include <asm/mips-boards/maltaint.h> | ||
33 | #include <asm/mips-cps.h> | ||
34 | #include <asm/gt64120.h> | ||
35 | #include <asm/mips-boards/generic.h> | ||
36 | #include <asm/mips-boards/msc01_pci.h> | ||
37 | #include <asm/msc01_ic.h> | ||
38 | #include <asm/setup.h> | ||
39 | #include <asm/rtlx.h> | ||
40 | |||
41 | static inline int mips_pcibios_iack(void) | ||
42 | { | ||
43 | int irq; | ||
44 | |||
45 | /* | ||
46 | * Determine highest priority pending interrupt by performing | ||
47 | * a PCI Interrupt Acknowledge cycle. | ||
48 | */ | ||
49 | switch (mips_revision_sconid) { | ||
50 | case MIPS_REVISION_SCON_SOCIT: | ||
51 | case MIPS_REVISION_SCON_ROCIT: | ||
52 | case MIPS_REVISION_SCON_SOCITSC: | ||
53 | case MIPS_REVISION_SCON_SOCITSCP: | ||
54 | MSC_READ(MSC01_PCI_IACK, irq); | ||
55 | irq &= 0xff; | ||
56 | break; | ||
57 | case MIPS_REVISION_SCON_GT64120: | ||
58 | irq = GT_READ(GT_PCI0_IACK_OFS); | ||
59 | irq &= 0xff; | ||
60 | break; | ||
61 | case MIPS_REVISION_SCON_BONITO: | ||
62 | /* The following will generate a PCI IACK cycle on the | ||
63 | * Bonito controller. It's a little bit kludgy, but it | ||
64 | * was the easiest way to implement it in hardware at | ||
65 | * the given time. | ||
66 | */ | ||
67 | BONITO_PCIMAP_CFG = 0x20000; | ||
68 | |||
69 | /* Flush Bonito register block */ | ||
70 | (void) BONITO_PCIMAP_CFG; | ||
71 | iob(); /* sync */ | ||
72 | |||
73 | irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg); | ||
74 | iob(); /* sync */ | ||
75 | irq &= 0xff; | ||
76 | BONITO_PCIMAP_CFG = 0; | ||
77 | break; | ||
78 | default: | ||
79 | pr_emerg("Unknown system controller.\n"); | ||
80 | return -1; | ||
81 | } | ||
82 | return irq; | ||
83 | } | ||
84 | |||
85 | static void corehi_irqdispatch(void) | ||
86 | { | ||
87 | unsigned int intedge, intsteer, pcicmd, pcibadaddr; | ||
88 | unsigned int pcimstat, intisr, inten, intpol; | ||
89 | unsigned int intrcause, datalo, datahi; | ||
90 | struct pt_regs *regs = get_irq_regs(); | ||
91 | |||
92 | pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n"); | ||
93 | pr_emerg("epc : %08lx\nStatus: %08lx\n" | ||
94 | "Cause : %08lx\nbadVaddr : %08lx\n", | ||
95 | regs->cp0_epc, regs->cp0_status, | ||
96 | regs->cp0_cause, regs->cp0_badvaddr); | ||
97 | |||
98 | /* Read all the registers and then print them as there is a | ||
99 | problem with interspersed printk's upsetting the Bonito controller. | ||
100 | Do it for the others too. | ||
101 | */ | ||
102 | |||
103 | switch (mips_revision_sconid) { | ||
104 | case MIPS_REVISION_SCON_SOCIT: | ||
105 | case MIPS_REVISION_SCON_ROCIT: | ||
106 | case MIPS_REVISION_SCON_SOCITSC: | ||
107 | case MIPS_REVISION_SCON_SOCITSCP: | ||
108 | ll_msc_irq(); | ||
109 | break; | ||
110 | case MIPS_REVISION_SCON_GT64120: | ||
111 | intrcause = GT_READ(GT_INTRCAUSE_OFS); | ||
112 | datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); | ||
113 | datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); | ||
114 | pr_emerg("GT_INTRCAUSE = %08x\n", intrcause); | ||
115 | pr_emerg("GT_CPUERR_ADDR = %02x%08x\n", | ||
116 | datahi, datalo); | ||
117 | break; | ||
118 | case MIPS_REVISION_SCON_BONITO: | ||
119 | pcibadaddr = BONITO_PCIBADADDR; | ||
120 | pcimstat = BONITO_PCIMSTAT; | ||
121 | intisr = BONITO_INTISR; | ||
122 | inten = BONITO_INTEN; | ||
123 | intpol = BONITO_INTPOL; | ||
124 | intedge = BONITO_INTEDGE; | ||
125 | intsteer = BONITO_INTSTEER; | ||
126 | pcicmd = BONITO_PCICMD; | ||
127 | pr_emerg("BONITO_INTISR = %08x\n", intisr); | ||
128 | pr_emerg("BONITO_INTEN = %08x\n", inten); | ||
129 | pr_emerg("BONITO_INTPOL = %08x\n", intpol); | ||
130 | pr_emerg("BONITO_INTEDGE = %08x\n", intedge); | ||
131 | pr_emerg("BONITO_INTSTEER = %08x\n", intsteer); | ||
132 | pr_emerg("BONITO_PCICMD = %08x\n", pcicmd); | ||
133 | pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr); | ||
134 | pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat); | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | die("CoreHi interrupt", regs); | ||
139 | } | ||
140 | |||
141 | static irqreturn_t corehi_handler(int irq, void *dev_id) | ||
142 | { | ||
143 | corehi_irqdispatch(); | ||
144 | return IRQ_HANDLED; | ||
145 | } | ||
146 | |||
147 | static msc_irqmap_t msc_irqmap[] __initdata = { | ||
148 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
149 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
150 | }; | ||
151 | static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap); | ||
152 | |||
153 | static msc_irqmap_t msc_eicirqmap[] __initdata = { | ||
154 | {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, | ||
155 | {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, | ||
156 | {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, | ||
157 | {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0}, | ||
158 | {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0}, | ||
159 | {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0}, | ||
160 | {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
161 | {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
162 | {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, | ||
163 | {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} | ||
164 | }; | ||
165 | |||
166 | static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap); | ||
167 | |||
168 | void __init arch_init_irq(void) | ||
169 | { | ||
170 | int corehi_irq; | ||
171 | |||
172 | /* | ||
173 | * Preallocate the i8259's expected virq's here. Since irqchip_init() | ||
174 | * will probe the irqchips in hierarchial order, i8259 is probed last. | ||
175 | * If anything allocates a virq before the i8259 is probed, it will | ||
176 | * be given one of the i8259's expected range and consequently setup | ||
177 | * of the i8259 will fail. | ||
178 | */ | ||
179 | WARN(irq_alloc_descs(I8259A_IRQ_BASE, I8259A_IRQ_BASE, | ||
180 | 16, numa_node_id()) < 0, | ||
181 | "Cannot reserve i8259 virqs at IRQ%d\n", I8259A_IRQ_BASE); | ||
182 | |||
183 | i8259_set_poll(mips_pcibios_iack); | ||
184 | irqchip_init(); | ||
185 | |||
186 | switch (mips_revision_sconid) { | ||
187 | case MIPS_REVISION_SCON_SOCIT: | ||
188 | case MIPS_REVISION_SCON_ROCIT: | ||
189 | if (cpu_has_veic) | ||
190 | init_msc_irqs(MIPS_MSC01_IC_REG_BASE, | ||
191 | MSC01E_INT_BASE, msc_eicirqmap, | ||
192 | msc_nr_eicirqs); | ||
193 | else | ||
194 | init_msc_irqs(MIPS_MSC01_IC_REG_BASE, | ||
195 | MSC01C_INT_BASE, msc_irqmap, | ||
196 | msc_nr_irqs); | ||
197 | break; | ||
198 | |||
199 | case MIPS_REVISION_SCON_SOCITSC: | ||
200 | case MIPS_REVISION_SCON_SOCITSCP: | ||
201 | if (cpu_has_veic) | ||
202 | init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, | ||
203 | MSC01E_INT_BASE, msc_eicirqmap, | ||
204 | msc_nr_eicirqs); | ||
205 | else | ||
206 | init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, | ||
207 | MSC01C_INT_BASE, msc_irqmap, | ||
208 | msc_nr_irqs); | ||
209 | } | ||
210 | |||
211 | if (mips_gic_present()) { | ||
212 | corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; | ||
213 | } else if (cpu_has_veic) { | ||
214 | set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch); | ||
215 | corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI; | ||
216 | } else { | ||
217 | corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; | ||
218 | } | ||
219 | |||
220 | if (request_irq(corehi_irq, corehi_handler, IRQF_NO_THREAD, "CoreHi", | ||
221 | NULL)) | ||
222 | pr_err("Failed to request irq %d (CoreHi)\n", corehi_irq); | ||
223 | } | ||
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c new file mode 100644 index 000000000..7c25a0a23 --- /dev/null +++ b/arch/mips/mti-malta/malta-memory.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * PROM library functions for acquiring/using memory descriptors given to | ||
7 | * us from the YAMON. | ||
8 | * | ||
9 | * Copyright (C) 1999,2000,2012 MIPS Technologies, Inc. | ||
10 | * All rights reserved. | ||
11 | * Authors: Carsten Langgaard <carstenl@mips.com> | ||
12 | * Steven J. Hill <sjhill@mips.com> | ||
13 | */ | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/memblock.h> | ||
16 | #include <linux/string.h> | ||
17 | |||
18 | #include <asm/bootinfo.h> | ||
19 | #include <asm/cdmm.h> | ||
20 | #include <asm/maar.h> | ||
21 | #include <asm/sections.h> | ||
22 | #include <asm/fw/fw.h> | ||
23 | |||
24 | /* determined physical memory size, not overridden by command line args */ | ||
25 | unsigned long physical_memsize = 0L; | ||
26 | |||
27 | static void free_init_pages_eva_malta(void *begin, void *end) | ||
28 | { | ||
29 | free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin), | ||
30 | __pa_symbol((unsigned long *)end)); | ||
31 | } | ||
32 | |||
33 | void __init fw_meminit(void) | ||
34 | { | ||
35 | bool eva = IS_ENABLED(CONFIG_EVA); | ||
36 | |||
37 | free_init_pages_eva = eva ? free_init_pages_eva_malta : NULL; | ||
38 | } | ||
39 | |||
40 | void __init prom_free_prom_memory(void) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | phys_addr_t mips_cdmm_phys_base(void) | ||
45 | { | ||
46 | /* This address is "typically unused" */ | ||
47 | return 0x1fc10000; | ||
48 | } | ||
diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c new file mode 100644 index 000000000..62ffac500 --- /dev/null +++ b/arch/mips/mti-malta/malta-platform.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2006, 07 MIPS Technologies, Inc. | ||
7 | * written by Ralf Baechle (ralf@linux-mips.org) | ||
8 | * written by Ralf Baechle <ralf@linux-mips.org> | ||
9 | * | ||
10 | * Copyright (C) 2008 Wind River Systems, Inc. | ||
11 | * updated by Tiejun Chen <tiejun.chen@windriver.com> | ||
12 | * | ||
13 | * 1. Probe driver for the Malta's UART ports: | ||
14 | * | ||
15 | * o 2 ports in the SMC SuperIO | ||
16 | * o 1 port in the CBUS UART, a discrete 16550 which normally is only used | ||
17 | * for bringups. | ||
18 | * | ||
19 | * We don't use 8250_platform.c on Malta as it would result in the CBUS | ||
20 | * UART becoming ttyS0. | ||
21 | * | ||
22 | * 2. Register RTC-CMOS platform device on Malta. | ||
23 | */ | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/serial_8250.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <asm/mips-boards/maltaint.h> | ||
29 | |||
30 | #define SMC_PORT(base, int) \ | ||
31 | { \ | ||
32 | .iobase = base, \ | ||
33 | .irq = int, \ | ||
34 | .uartclk = 1843200, \ | ||
35 | .iotype = UPIO_PORT, \ | ||
36 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ | ||
37 | .regshift = 0, \ | ||
38 | } | ||
39 | |||
40 | #define CBUS_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP) | ||
41 | |||
42 | static struct plat_serial8250_port uart8250_data[] = { | ||
43 | SMC_PORT(0x3F8, 4), | ||
44 | SMC_PORT(0x2F8, 3), | ||
45 | #ifndef CONFIG_MIPS_CMP | ||
46 | { | ||
47 | .mapbase = 0x1f000900, /* The CBUS UART */ | ||
48 | .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, | ||
49 | .uartclk = 3686400, /* Twice the usual clk! */ | ||
50 | .iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? | ||
51 | UPIO_MEM32BE : UPIO_MEM32, | ||
52 | .flags = CBUS_UART_FLAGS, | ||
53 | .regshift = 3, | ||
54 | }, | ||
55 | #endif | ||
56 | { }, | ||
57 | }; | ||
58 | |||
59 | static struct platform_device malta_uart8250_device = { | ||
60 | .name = "serial8250", | ||
61 | .id = PLAT8250_DEV_PLATFORM, | ||
62 | .dev = { | ||
63 | .platform_data = uart8250_data, | ||
64 | }, | ||
65 | }; | ||
66 | |||
67 | static struct platform_device *malta_devices[] __initdata = { | ||
68 | &malta_uart8250_device, | ||
69 | }; | ||
70 | |||
71 | static int __init malta_add_devices(void) | ||
72 | { | ||
73 | return platform_add_devices(malta_devices, ARRAY_SIZE(malta_devices)); | ||
74 | } | ||
75 | |||
76 | device_initcall(malta_add_devices); | ||
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c new file mode 100644 index 000000000..e1fb8b534 --- /dev/null +++ b/arch/mips/mti-malta/malta-setup.c | |||
@@ -0,0 +1,249 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | * Copyright (C) 2008 Dmitri Vorobiev | ||
6 | */ | ||
7 | #include <linux/cpu.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/ioport.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/of_fdt.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/screen_info.h> | ||
15 | #include <linux/time.h> | ||
16 | |||
17 | #include <asm/dma-coherence.h> | ||
18 | #include <asm/fw/fw.h> | ||
19 | #include <asm/mips-cps.h> | ||
20 | #include <asm/mips-boards/generic.h> | ||
21 | #include <asm/mips-boards/malta.h> | ||
22 | #include <asm/mips-boards/maltaint.h> | ||
23 | #include <asm/dma.h> | ||
24 | #include <asm/prom.h> | ||
25 | #include <asm/traps.h> | ||
26 | #ifdef CONFIG_VT | ||
27 | #include <linux/console.h> | ||
28 | #endif | ||
29 | |||
30 | #define ROCIT_CONFIG_GEN0 0x1f403000 | ||
31 | #define ROCIT_CONFIG_GEN0_PCI_IOCU BIT(7) | ||
32 | |||
33 | static struct resource standard_io_resources[] = { | ||
34 | { | ||
35 | .name = "dma1", | ||
36 | .start = 0x00, | ||
37 | .end = 0x1f, | ||
38 | .flags = IORESOURCE_IO | IORESOURCE_BUSY | ||
39 | }, | ||
40 | { | ||
41 | .name = "timer", | ||
42 | .start = 0x40, | ||
43 | .end = 0x5f, | ||
44 | .flags = IORESOURCE_IO | IORESOURCE_BUSY | ||
45 | }, | ||
46 | { | ||
47 | .name = "keyboard", | ||
48 | .start = 0x60, | ||
49 | .end = 0x6f, | ||
50 | .flags = IORESOURCE_IO | IORESOURCE_BUSY | ||
51 | }, | ||
52 | { | ||
53 | .name = "dma page reg", | ||
54 | .start = 0x80, | ||
55 | .end = 0x8f, | ||
56 | .flags = IORESOURCE_IO | IORESOURCE_BUSY | ||
57 | }, | ||
58 | { | ||
59 | .name = "dma2", | ||
60 | .start = 0xc0, | ||
61 | .end = 0xdf, | ||
62 | .flags = IORESOURCE_IO | IORESOURCE_BUSY | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | const char *get_system_type(void) | ||
67 | { | ||
68 | return "MIPS Malta"; | ||
69 | } | ||
70 | |||
71 | #ifdef CONFIG_BLK_DEV_FD | ||
72 | static void __init fd_activate(void) | ||
73 | { | ||
74 | /* | ||
75 | * Activate Floppy Controller in the SMSC FDC37M817 Super I/O | ||
76 | * Controller. | ||
77 | * Done by YAMON 2.00 onwards | ||
78 | */ | ||
79 | /* Entering config state. */ | ||
80 | SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); | ||
81 | |||
82 | /* Activate floppy controller. */ | ||
83 | SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG); | ||
84 | SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG); | ||
85 | SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG); | ||
86 | SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG); | ||
87 | |||
88 | /* Exit config state. */ | ||
89 | SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG); | ||
90 | } | ||
91 | #endif | ||
92 | |||
93 | static int __init plat_enable_iocoherency(void) | ||
94 | { | ||
95 | int supported = 0; | ||
96 | u32 cfg; | ||
97 | |||
98 | if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) { | ||
99 | if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) { | ||
100 | BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN; | ||
101 | pr_info("Enabled Bonito CPU coherency\n"); | ||
102 | supported = 1; | ||
103 | } | ||
104 | if (strstr(fw_getcmdline(), "iobcuncached")) { | ||
105 | BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN; | ||
106 | BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & | ||
107 | ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | | ||
108 | BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); | ||
109 | pr_info("Disabled Bonito IOBC coherency\n"); | ||
110 | } else { | ||
111 | BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN; | ||
112 | BONITO_PCIMEMBASECFG |= | ||
113 | (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | | ||
114 | BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); | ||
115 | pr_info("Enabled Bonito IOBC coherency\n"); | ||
116 | } | ||
117 | } else if (mips_cps_numiocu(0) != 0) { | ||
118 | /* Nothing special needs to be done to enable coherency */ | ||
119 | pr_info("CMP IOCU detected\n"); | ||
120 | cfg = __raw_readl((u32 *)CKSEG1ADDR(ROCIT_CONFIG_GEN0)); | ||
121 | if (!(cfg & ROCIT_CONFIG_GEN0_PCI_IOCU)) { | ||
122 | pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n"); | ||
123 | return 0; | ||
124 | } | ||
125 | supported = 1; | ||
126 | } | ||
127 | hw_coherentio = supported; | ||
128 | return supported; | ||
129 | } | ||
130 | |||
131 | static void __init plat_setup_iocoherency(void) | ||
132 | { | ||
133 | if (plat_enable_iocoherency()) { | ||
134 | if (coherentio == IO_COHERENCE_DISABLED) | ||
135 | pr_info("Hardware DMA cache coherency disabled\n"); | ||
136 | else | ||
137 | pr_info("Hardware DMA cache coherency enabled\n"); | ||
138 | } else { | ||
139 | if (coherentio == IO_COHERENCE_ENABLED) | ||
140 | pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n"); | ||
141 | else | ||
142 | pr_info("Software DMA cache coherency enabled\n"); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static void __init pci_clock_check(void) | ||
147 | { | ||
148 | unsigned int __iomem *jmpr_p = | ||
149 | (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int)); | ||
150 | int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07; | ||
151 | static const int pciclocks[] __initconst = { | ||
152 | 33, 20, 25, 30, 12, 16, 37, 10 | ||
153 | }; | ||
154 | int pciclock = pciclocks[jmpr]; | ||
155 | char *optptr, *argptr = fw_getcmdline(); | ||
156 | |||
157 | /* | ||
158 | * If user passed a pci_clock= option, don't tack on another one | ||
159 | */ | ||
160 | optptr = strstr(argptr, "pci_clock="); | ||
161 | if (optptr && (optptr == argptr || optptr[-1] == ' ')) | ||
162 | return; | ||
163 | |||
164 | if (pciclock != 33) { | ||
165 | pr_warn("WARNING: PCI clock is %dMHz, setting pci_clock\n", | ||
166 | pciclock); | ||
167 | argptr += strlen(argptr); | ||
168 | sprintf(argptr, " pci_clock=%d", pciclock); | ||
169 | if (pciclock < 20 || pciclock > 66) | ||
170 | pr_warn("WARNING: IDE timing calculations will be " | ||
171 | "incorrect\n"); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) | ||
176 | static void __init screen_info_setup(void) | ||
177 | { | ||
178 | screen_info = (struct screen_info) { | ||
179 | .orig_x = 0, | ||
180 | .orig_y = 25, | ||
181 | .ext_mem_k = 0, | ||
182 | .orig_video_page = 0, | ||
183 | .orig_video_mode = 0, | ||
184 | .orig_video_cols = 80, | ||
185 | .unused2 = 0, | ||
186 | .orig_video_ega_bx = 0, | ||
187 | .unused3 = 0, | ||
188 | .orig_video_lines = 25, | ||
189 | .orig_video_isVGA = VIDEO_TYPE_VGAC, | ||
190 | .orig_video_points = 16 | ||
191 | }; | ||
192 | } | ||
193 | #endif | ||
194 | |||
195 | static void __init bonito_quirks_setup(void) | ||
196 | { | ||
197 | char *argptr; | ||
198 | |||
199 | argptr = fw_getcmdline(); | ||
200 | if (strstr(argptr, "debug")) { | ||
201 | BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE; | ||
202 | pr_info("Enabled Bonito debug mode\n"); | ||
203 | } else | ||
204 | BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE; | ||
205 | } | ||
206 | |||
207 | void __init *plat_get_fdt(void) | ||
208 | { | ||
209 | return (void *)__dtb_start; | ||
210 | } | ||
211 | |||
212 | void __init plat_mem_setup(void) | ||
213 | { | ||
214 | unsigned int i; | ||
215 | void *fdt = plat_get_fdt(); | ||
216 | |||
217 | fdt = malta_dt_shim(fdt); | ||
218 | __dt_setup_arch(fdt); | ||
219 | |||
220 | if (IS_ENABLED(CONFIG_EVA)) | ||
221 | /* EVA has already been configured in mach-malta/kernel-init.h */ | ||
222 | pr_info("Enhanced Virtual Addressing (EVA) activated\n"); | ||
223 | |||
224 | mips_pcibios_init(); | ||
225 | |||
226 | /* Request I/O space for devices used on the Malta board. */ | ||
227 | for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) | ||
228 | request_resource(&ioport_resource, standard_io_resources+i); | ||
229 | |||
230 | /* | ||
231 | * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge. | ||
232 | */ | ||
233 | enable_dma(4); | ||
234 | |||
235 | if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) | ||
236 | bonito_quirks_setup(); | ||
237 | |||
238 | plat_setup_iocoherency(); | ||
239 | |||
240 | pci_clock_check(); | ||
241 | |||
242 | #ifdef CONFIG_BLK_DEV_FD | ||
243 | fd_activate(); | ||
244 | #endif | ||
245 | |||
246 | #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) | ||
247 | screen_info_setup(); | ||
248 | #endif | ||
249 | } | ||
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c new file mode 100644 index 000000000..7efcfe0c9 --- /dev/null +++ b/arch/mips/mti-malta/malta-time.c | |||
@@ -0,0 +1,256 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Setting up the clock on the MIPS boards. | ||
7 | */ | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/i8253.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel_stat.h> | ||
12 | #include <linux/libfdt.h> | ||
13 | #include <linux/math64.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/timex.h> | ||
18 | #include <linux/mc146818rtc.h> | ||
19 | |||
20 | #include <asm/cpu.h> | ||
21 | #include <asm/mipsregs.h> | ||
22 | #include <asm/mipsmtregs.h> | ||
23 | #include <asm/hardirq.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/div64.h> | ||
26 | #include <asm/setup.h> | ||
27 | #include <asm/time.h> | ||
28 | #include <asm/mc146818-time.h> | ||
29 | #include <asm/msc01_ic.h> | ||
30 | #include <asm/mips-cps.h> | ||
31 | |||
32 | #include <asm/mips-boards/generic.h> | ||
33 | #include <asm/mips-boards/maltaint.h> | ||
34 | |||
35 | static int mips_cpu_timer_irq; | ||
36 | static int mips_cpu_perf_irq; | ||
37 | extern int cp0_perfcount_irq; | ||
38 | |||
39 | static unsigned int gic_frequency; | ||
40 | |||
41 | static void mips_timer_dispatch(void) | ||
42 | { | ||
43 | do_IRQ(mips_cpu_timer_irq); | ||
44 | } | ||
45 | |||
46 | static void mips_perf_dispatch(void) | ||
47 | { | ||
48 | do_IRQ(mips_cpu_perf_irq); | ||
49 | } | ||
50 | |||
51 | static unsigned int freqround(unsigned int freq, unsigned int amount) | ||
52 | { | ||
53 | freq += amount; | ||
54 | freq -= freq % (amount*2); | ||
55 | return freq; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Estimate CPU and GIC frequencies. | ||
60 | */ | ||
61 | static void __init estimate_frequencies(void) | ||
62 | { | ||
63 | unsigned long flags; | ||
64 | unsigned int count, start; | ||
65 | unsigned char secs1, secs2, ctrl; | ||
66 | int secs; | ||
67 | u64 giccount = 0, gicstart = 0; | ||
68 | |||
69 | #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ | ||
70 | mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; | ||
71 | return; | ||
72 | #endif | ||
73 | |||
74 | local_irq_save(flags); | ||
75 | |||
76 | if (mips_gic_present()) | ||
77 | clear_gic_config(GIC_CONFIG_COUNTSTOP); | ||
78 | |||
79 | /* | ||
80 | * Read counters exactly on rising edge of update flag. | ||
81 | * This helps get an accurate reading under virtualisation. | ||
82 | */ | ||
83 | while (CMOS_READ(RTC_REG_A) & RTC_UIP); | ||
84 | while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); | ||
85 | start = read_c0_count(); | ||
86 | if (mips_gic_present()) | ||
87 | gicstart = read_gic_counter(); | ||
88 | |||
89 | /* Wait for falling edge before reading RTC. */ | ||
90 | while (CMOS_READ(RTC_REG_A) & RTC_UIP); | ||
91 | secs1 = CMOS_READ(RTC_SECONDS); | ||
92 | |||
93 | /* Read counters again exactly on rising edge of update flag. */ | ||
94 | while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); | ||
95 | count = read_c0_count(); | ||
96 | if (mips_gic_present()) | ||
97 | giccount = read_gic_counter(); | ||
98 | |||
99 | /* Wait for falling edge before reading RTC again. */ | ||
100 | while (CMOS_READ(RTC_REG_A) & RTC_UIP); | ||
101 | secs2 = CMOS_READ(RTC_SECONDS); | ||
102 | |||
103 | ctrl = CMOS_READ(RTC_CONTROL); | ||
104 | |||
105 | local_irq_restore(flags); | ||
106 | |||
107 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
108 | secs1 = bcd2bin(secs1); | ||
109 | secs2 = bcd2bin(secs2); | ||
110 | } | ||
111 | secs = secs2 - secs1; | ||
112 | if (secs < 1) | ||
113 | secs += 60; | ||
114 | |||
115 | count -= start; | ||
116 | count /= secs; | ||
117 | mips_hpt_frequency = count; | ||
118 | |||
119 | if (mips_gic_present()) { | ||
120 | giccount = div_u64(giccount - gicstart, secs); | ||
121 | gic_frequency = giccount; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | void read_persistent_clock64(struct timespec64 *ts) | ||
126 | { | ||
127 | ts->tv_sec = mc146818_get_cmos_time(); | ||
128 | ts->tv_nsec = 0; | ||
129 | } | ||
130 | |||
131 | int get_c0_fdc_int(void) | ||
132 | { | ||
133 | /* | ||
134 | * Some cores claim the FDC is routable through the GIC, but it doesn't | ||
135 | * actually seem to be connected for those Malta bitstreams. | ||
136 | */ | ||
137 | switch (current_cpu_type()) { | ||
138 | case CPU_INTERAPTIV: | ||
139 | case CPU_PROAPTIV: | ||
140 | return -1; | ||
141 | }; | ||
142 | |||
143 | if (cpu_has_veic) | ||
144 | return -1; | ||
145 | else if (mips_gic_present()) | ||
146 | return gic_get_c0_fdc_int(); | ||
147 | else if (cp0_fdc_irq >= 0) | ||
148 | return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; | ||
149 | else | ||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | int get_c0_perfcount_int(void) | ||
154 | { | ||
155 | if (cpu_has_veic) { | ||
156 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); | ||
157 | mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | ||
158 | } else if (mips_gic_present()) { | ||
159 | mips_cpu_perf_irq = gic_get_c0_perfcount_int(); | ||
160 | } else if (cp0_perfcount_irq >= 0) { | ||
161 | mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | ||
162 | } else { | ||
163 | mips_cpu_perf_irq = -1; | ||
164 | } | ||
165 | |||
166 | return mips_cpu_perf_irq; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(get_c0_perfcount_int); | ||
169 | |||
170 | unsigned int get_c0_compare_int(void) | ||
171 | { | ||
172 | if (cpu_has_veic) { | ||
173 | set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); | ||
174 | mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; | ||
175 | } else if (mips_gic_present()) { | ||
176 | mips_cpu_timer_irq = gic_get_c0_compare_int(); | ||
177 | } else { | ||
178 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | ||
179 | } | ||
180 | |||
181 | return mips_cpu_timer_irq; | ||
182 | } | ||
183 | |||
184 | static void __init init_rtc(void) | ||
185 | { | ||
186 | unsigned char freq, ctrl; | ||
187 | |||
188 | /* Set 32KHz time base if not already set */ | ||
189 | freq = CMOS_READ(RTC_FREQ_SELECT); | ||
190 | if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ) | ||
191 | CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); | ||
192 | |||
193 | /* Ensure SET bit is clear so RTC can run */ | ||
194 | ctrl = CMOS_READ(RTC_CONTROL); | ||
195 | if (ctrl & RTC_SET) | ||
196 | CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL); | ||
197 | } | ||
198 | |||
199 | #ifdef CONFIG_CLKSRC_MIPS_GIC | ||
200 | static u32 gic_frequency_dt; | ||
201 | |||
202 | static struct property gic_frequency_prop = { | ||
203 | .name = "clock-frequency", | ||
204 | .length = sizeof(u32), | ||
205 | .value = &gic_frequency_dt, | ||
206 | }; | ||
207 | |||
208 | static void update_gic_frequency_dt(void) | ||
209 | { | ||
210 | struct device_node *node; | ||
211 | |||
212 | gic_frequency_dt = cpu_to_be32(gic_frequency); | ||
213 | |||
214 | node = of_find_compatible_node(NULL, NULL, "mti,gic-timer"); | ||
215 | if (!node) { | ||
216 | pr_err("mti,gic-timer device node not found\n"); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | if (of_update_property(node, &gic_frequency_prop) < 0) | ||
221 | pr_err("error updating gic frequency property\n"); | ||
222 | } | ||
223 | |||
224 | #endif | ||
225 | |||
226 | void __init plat_time_init(void) | ||
227 | { | ||
228 | unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); | ||
229 | unsigned int freq; | ||
230 | |||
231 | init_rtc(); | ||
232 | estimate_frequencies(); | ||
233 | |||
234 | freq = mips_hpt_frequency; | ||
235 | if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && | ||
236 | (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) | ||
237 | freq *= 2; | ||
238 | freq = freqround(freq, 5000); | ||
239 | printk("CPU frequency %d.%02d MHz\n", freq/1000000, | ||
240 | (freq%1000000)*100/1000000); | ||
241 | |||
242 | #ifdef CONFIG_I8253 | ||
243 | /* Only Malta has a PIT. */ | ||
244 | setup_pit_timer(); | ||
245 | #endif | ||
246 | |||
247 | if (mips_gic_present()) { | ||
248 | freq = freqround(gic_frequency, 5000); | ||
249 | printk("GIC frequency %d.%02d MHz\n", freq/1000000, | ||
250 | (freq%1000000)*100/1000000); | ||
251 | #ifdef CONFIG_CLKSRC_MIPS_GIC | ||
252 | update_gic_frequency_dt(); | ||
253 | timer_probe(); | ||
254 | #endif | ||
255 | } | ||
256 | } | ||