1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2015 Imagination Technologies
4*4882a593Smuzhiyun * Author: Paul Burton <paul.burton@mips.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/bug.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/libfdt.h>
10*4882a593Smuzhiyun #include <linux/of_fdt.h>
11*4882a593Smuzhiyun #include <linux/sizes.h>
12*4882a593Smuzhiyun #include <asm/addrspace.h>
13*4882a593Smuzhiyun #include <asm/bootinfo.h>
14*4882a593Smuzhiyun #include <asm/fw/fw.h>
15*4882a593Smuzhiyun #include <asm/mips-boards/generic.h>
16*4882a593Smuzhiyun #include <asm/mips-boards/malta.h>
17*4882a593Smuzhiyun #include <asm/mips-cps.h>
18*4882a593Smuzhiyun #include <asm/page.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define ROCIT_REG_BASE 0x1f403000
21*4882a593Smuzhiyun #define ROCIT_CONFIG_GEN1 (ROCIT_REG_BASE + 0x04)
22*4882a593Smuzhiyun #define ROCIT_CONFIG_GEN1_MEMMAP_SHIFT 8
23*4882a593Smuzhiyun #define ROCIT_CONFIG_GEN1_MEMMAP_MASK (0xf << 8)
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static unsigned char fdt_buf[16 << 10] __initdata __aligned(8);
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* determined physical memory size, not overridden by command line args */
28*4882a593Smuzhiyun extern unsigned long physical_memsize;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun enum mem_map {
31*4882a593Smuzhiyun MEM_MAP_V1 = 0,
32*4882a593Smuzhiyun MEM_MAP_V2,
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define MAX_MEM_ARRAY_ENTRIES 2
36*4882a593Smuzhiyun
malta_scon(void)37*4882a593Smuzhiyun static __init int malta_scon(void)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun int scon = MIPS_REVISION_SCONID;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun if (scon != MIPS_REVISION_SCON_OTHER)
42*4882a593Smuzhiyun return scon;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun switch (MIPS_REVISION_CORID) {
45*4882a593Smuzhiyun case MIPS_REVISION_CORID_QED_RM5261:
46*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_LV:
47*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGA:
48*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGAR2:
49*4882a593Smuzhiyun return MIPS_REVISION_SCON_GT64120;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_EMUL_BON:
52*4882a593Smuzhiyun case MIPS_REVISION_CORID_BONITO64:
53*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_20K:
54*4882a593Smuzhiyun return MIPS_REVISION_SCON_BONITO;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_MSC:
57*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGA2:
58*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_24K:
59*4882a593Smuzhiyun return MIPS_REVISION_SCON_SOCIT;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGA3:
62*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGA4:
63*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_FPGA5:
64*4882a593Smuzhiyun case MIPS_REVISION_CORID_CORE_EMUL_MSC:
65*4882a593Smuzhiyun default:
66*4882a593Smuzhiyun return MIPS_REVISION_SCON_ROCIT;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
gen_fdt_mem_array(__be32 * mem_array,unsigned long size,enum mem_map map)70*4882a593Smuzhiyun static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size,
71*4882a593Smuzhiyun enum mem_map map)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun unsigned long size_preio;
74*4882a593Smuzhiyun unsigned entries;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun entries = 1;
77*4882a593Smuzhiyun mem_array[0] = cpu_to_be32(PHYS_OFFSET);
78*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_EVA)) {
79*4882a593Smuzhiyun /*
80*4882a593Smuzhiyun * The current Malta EVA configuration is "special" in that it
81*4882a593Smuzhiyun * always makes use of addresses in the upper half of the 32 bit
82*4882a593Smuzhiyun * physical address map, which gives it a contiguous region of
83*4882a593Smuzhiyun * DDR but limits it to 2GB.
84*4882a593Smuzhiyun */
85*4882a593Smuzhiyun mem_array[1] = cpu_to_be32(size);
86*4882a593Smuzhiyun goto done;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun size_preio = min_t(unsigned long, size, SZ_256M);
90*4882a593Smuzhiyun mem_array[1] = cpu_to_be32(size_preio);
91*4882a593Smuzhiyun size -= size_preio;
92*4882a593Smuzhiyun if (!size)
93*4882a593Smuzhiyun goto done;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (map == MEM_MAP_V2) {
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun * We have a flat 32 bit physical memory map with DDR filling
98*4882a593Smuzhiyun * all 4GB of the memory map, apart from the I/O region which
99*4882a593Smuzhiyun * obscures 256MB from 0x10000000-0x1fffffff.
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * Therefore we discard the 256MB behind the I/O region.
102*4882a593Smuzhiyun */
103*4882a593Smuzhiyun if (size <= SZ_256M)
104*4882a593Smuzhiyun goto done;
105*4882a593Smuzhiyun size -= SZ_256M;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* Make use of the memory following the I/O region */
108*4882a593Smuzhiyun entries++;
109*4882a593Smuzhiyun mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_512M);
110*4882a593Smuzhiyun mem_array[3] = cpu_to_be32(size);
111*4882a593Smuzhiyun } else {
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * We have a 32 bit physical memory map with a 2GB DDR region
114*4882a593Smuzhiyun * aliased in the upper & lower halves of it. The I/O region
115*4882a593Smuzhiyun * obscures 256MB from 0x10000000-0x1fffffff in the low alias
116*4882a593Smuzhiyun * but the DDR it obscures is accessible via the high alias.
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun * Simply access everything beyond the lowest 256MB of DDR using
119*4882a593Smuzhiyun * the high alias.
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun entries++;
122*4882a593Smuzhiyun mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_2G + SZ_256M);
123*4882a593Smuzhiyun mem_array[3] = cpu_to_be32(size);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun done:
127*4882a593Smuzhiyun BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
128*4882a593Smuzhiyun return entries;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
append_memory(void * fdt,int root_off)131*4882a593Smuzhiyun static void __init append_memory(void *fdt, int root_off)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
134*4882a593Smuzhiyun unsigned long memsize;
135*4882a593Smuzhiyun unsigned mem_entries;
136*4882a593Smuzhiyun int i, err, mem_off;
137*4882a593Smuzhiyun enum mem_map mem_map;
138*4882a593Smuzhiyun u32 config;
139*4882a593Smuzhiyun char *var, param_name[10], *var_names[] = {
140*4882a593Smuzhiyun "ememsize", "memsize",
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* if a memory node already exists, leave it alone */
144*4882a593Smuzhiyun mem_off = fdt_path_offset(fdt, "/memory");
145*4882a593Smuzhiyun if (mem_off >= 0)
146*4882a593Smuzhiyun return;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /* find memory size from the bootloader environment */
149*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(var_names); i++) {
150*4882a593Smuzhiyun var = fw_getenv(var_names[i]);
151*4882a593Smuzhiyun if (!var)
152*4882a593Smuzhiyun continue;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun err = kstrtoul(var, 0, &physical_memsize);
155*4882a593Smuzhiyun if (!err)
156*4882a593Smuzhiyun break;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun pr_warn("Failed to read the '%s' env variable '%s'\n",
159*4882a593Smuzhiyun var_names[i], var);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (!physical_memsize) {
163*4882a593Smuzhiyun pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
164*4882a593Smuzhiyun physical_memsize = 32 << 20;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
168*4882a593Smuzhiyun /*
169*4882a593Smuzhiyun * SOC-it swaps, or perhaps doesn't swap, when DMA'ing
170*4882a593Smuzhiyun * the last word of physical memory.
171*4882a593Smuzhiyun */
172*4882a593Smuzhiyun physical_memsize -= PAGE_SIZE;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* default to using all available RAM */
176*4882a593Smuzhiyun memsize = physical_memsize;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* allow the user to override the usable memory */
179*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(var_names); i++) {
180*4882a593Smuzhiyun snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
181*4882a593Smuzhiyun var = strstr(arcs_cmdline, param_name);
182*4882a593Smuzhiyun if (!var)
183*4882a593Smuzhiyun continue;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun memsize = memparse(var + strlen(param_name), NULL);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* if the user says there's more RAM than we thought, believe them */
189*4882a593Smuzhiyun physical_memsize = max_t(unsigned long, physical_memsize, memsize);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* detect the memory map in use */
192*4882a593Smuzhiyun if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
193*4882a593Smuzhiyun /* ROCit has a register indicating the memory map in use */
194*4882a593Smuzhiyun config = readl((void __iomem *)CKSEG1ADDR(ROCIT_CONFIG_GEN1));
195*4882a593Smuzhiyun mem_map = config & ROCIT_CONFIG_GEN1_MEMMAP_MASK;
196*4882a593Smuzhiyun mem_map >>= ROCIT_CONFIG_GEN1_MEMMAP_SHIFT;
197*4882a593Smuzhiyun } else {
198*4882a593Smuzhiyun /* if not using ROCit, presume the v1 memory map */
199*4882a593Smuzhiyun mem_map = MEM_MAP_V1;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun if (mem_map > MEM_MAP_V2)
202*4882a593Smuzhiyun panic("Unsupported physical memory map v%u detected",
203*4882a593Smuzhiyun (unsigned int)mem_map);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* append memory to the DT */
206*4882a593Smuzhiyun mem_off = fdt_add_subnode(fdt, root_off, "memory");
207*4882a593Smuzhiyun if (mem_off < 0)
208*4882a593Smuzhiyun panic("Unable to add memory node to DT: %d", mem_off);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
211*4882a593Smuzhiyun if (err)
212*4882a593Smuzhiyun panic("Unable to set memory node device_type: %d", err);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun mem_entries = gen_fdt_mem_array(mem_array, physical_memsize, mem_map);
215*4882a593Smuzhiyun err = fdt_setprop(fdt, mem_off, "reg", mem_array,
216*4882a593Smuzhiyun mem_entries * 2 * sizeof(mem_array[0]));
217*4882a593Smuzhiyun if (err)
218*4882a593Smuzhiyun panic("Unable to set memory regs property: %d", err);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun mem_entries = gen_fdt_mem_array(mem_array, memsize, mem_map);
221*4882a593Smuzhiyun err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array,
222*4882a593Smuzhiyun mem_entries * 2 * sizeof(mem_array[0]));
223*4882a593Smuzhiyun if (err)
224*4882a593Smuzhiyun panic("Unable to set linux,usable-memory property: %d", err);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
remove_gic(void * fdt)227*4882a593Smuzhiyun static void __init remove_gic(void *fdt)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun int err, gic_off, i8259_off, cpu_off;
230*4882a593Smuzhiyun void __iomem *biu_base;
231*4882a593Smuzhiyun uint32_t cpu_phandle, sc_cfg;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* if we have a CM which reports a GIC is present, leave the DT alone */
234*4882a593Smuzhiyun err = mips_cm_probe();
235*4882a593Smuzhiyun if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX))
236*4882a593Smuzhiyun return;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
239*4882a593Smuzhiyun /*
240*4882a593Smuzhiyun * On systems using the RocIT system controller a GIC may be
241*4882a593Smuzhiyun * present without a CM. Detect whether that is the case.
242*4882a593Smuzhiyun */
243*4882a593Smuzhiyun biu_base = ioremap(MSC01_BIU_REG_BASE,
244*4882a593Smuzhiyun MSC01_BIU_ADDRSPACE_SZ);
245*4882a593Smuzhiyun sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS);
246*4882a593Smuzhiyun if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) {
247*4882a593Smuzhiyun /* enable the GIC at the system controller level */
248*4882a593Smuzhiyun sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF);
249*4882a593Smuzhiyun __raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS);
250*4882a593Smuzhiyun return;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
255*4882a593Smuzhiyun if (gic_off < 0) {
256*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to find DT GIC node: %d\n",
257*4882a593Smuzhiyun gic_off);
258*4882a593Smuzhiyun return;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun err = fdt_nop_node(fdt, gic_off);
262*4882a593Smuzhiyun if (err)
263*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to nop GIC node\n");
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259");
266*4882a593Smuzhiyun if (i8259_off < 0) {
267*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n",
268*4882a593Smuzhiyun i8259_off);
269*4882a593Smuzhiyun return;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun cpu_off = fdt_node_offset_by_compatible(fdt, -1,
273*4882a593Smuzhiyun "mti,cpu-interrupt-controller");
274*4882a593Smuzhiyun if (cpu_off < 0) {
275*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to find CPU intc node: %d\n",
276*4882a593Smuzhiyun cpu_off);
277*4882a593Smuzhiyun return;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun cpu_phandle = fdt_get_phandle(fdt, cpu_off);
281*4882a593Smuzhiyun if (!cpu_phandle) {
282*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to get CPU intc phandle\n");
283*4882a593Smuzhiyun return;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle);
287*4882a593Smuzhiyun if (err) {
288*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n",
289*4882a593Smuzhiyun err);
290*4882a593Smuzhiyun return;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2);
294*4882a593Smuzhiyun if (err) {
295*4882a593Smuzhiyun pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n",
296*4882a593Smuzhiyun err);
297*4882a593Smuzhiyun return;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
malta_dt_shim(void * fdt)301*4882a593Smuzhiyun void __init *malta_dt_shim(void *fdt)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun int root_off, len, err;
304*4882a593Smuzhiyun const char *compat;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (fdt_check_header(fdt))
307*4882a593Smuzhiyun panic("Corrupt DT");
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
310*4882a593Smuzhiyun if (err)
311*4882a593Smuzhiyun panic("Unable to open FDT: %d", err);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun root_off = fdt_path_offset(fdt_buf, "/");
314*4882a593Smuzhiyun if (root_off < 0)
315*4882a593Smuzhiyun panic("No / node in DT");
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun compat = fdt_getprop(fdt_buf, root_off, "compatible", &len);
318*4882a593Smuzhiyun if (!compat)
319*4882a593Smuzhiyun panic("No root compatible property in DT: %d", len);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /* if this isn't Malta, leave the DT alone */
322*4882a593Smuzhiyun if (strncmp(compat, "mti,malta", len))
323*4882a593Smuzhiyun return fdt;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun append_memory(fdt_buf, root_off);
326*4882a593Smuzhiyun remove_gic(fdt_buf);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun err = fdt_pack(fdt_buf);
329*4882a593Smuzhiyun if (err)
330*4882a593Smuzhiyun panic("Unable to pack FDT: %d\n", err);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun return fdt_buf;
333*4882a593Smuzhiyun }
334