0001
0002
0003
0004
0005
0006
0007 #include <linux/bug.h>
0008 #include <linux/kernel.h>
0009 #include <linux/libfdt.h>
0010 #include <linux/of_fdt.h>
0011 #include <linux/sizes.h>
0012 #include <asm/addrspace.h>
0013 #include <asm/bootinfo.h>
0014 #include <asm/fw/fw.h>
0015 #include <asm/mips-boards/generic.h>
0016 #include <asm/mips-boards/malta.h>
0017 #include <asm/mips-cps.h>
0018 #include <asm/page.h>
0019
0020 #define ROCIT_REG_BASE 0x1f403000
0021 #define ROCIT_CONFIG_GEN1 (ROCIT_REG_BASE + 0x04)
0022 #define ROCIT_CONFIG_GEN1_MEMMAP_SHIFT 8
0023 #define ROCIT_CONFIG_GEN1_MEMMAP_MASK (0xf << 8)
0024
0025 static unsigned char fdt_buf[16 << 10] __initdata __aligned(8);
0026
0027
0028 extern unsigned long physical_memsize;
0029
0030 enum mem_map {
0031 MEM_MAP_V1 = 0,
0032 MEM_MAP_V2,
0033 };
0034
0035 #define MAX_MEM_ARRAY_ENTRIES 2
0036
0037 static __init int malta_scon(void)
0038 {
0039 int scon = MIPS_REVISION_SCONID;
0040
0041 if (scon != MIPS_REVISION_SCON_OTHER)
0042 return scon;
0043
0044 switch (MIPS_REVISION_CORID) {
0045 case MIPS_REVISION_CORID_QED_RM5261:
0046 case MIPS_REVISION_CORID_CORE_LV:
0047 case MIPS_REVISION_CORID_CORE_FPGA:
0048 case MIPS_REVISION_CORID_CORE_FPGAR2:
0049 return MIPS_REVISION_SCON_GT64120;
0050
0051 case MIPS_REVISION_CORID_CORE_EMUL_BON:
0052 case MIPS_REVISION_CORID_BONITO64:
0053 case MIPS_REVISION_CORID_CORE_20K:
0054 return MIPS_REVISION_SCON_BONITO;
0055
0056 case MIPS_REVISION_CORID_CORE_MSC:
0057 case MIPS_REVISION_CORID_CORE_FPGA2:
0058 case MIPS_REVISION_CORID_CORE_24K:
0059 return MIPS_REVISION_SCON_SOCIT;
0060
0061 case MIPS_REVISION_CORID_CORE_FPGA3:
0062 case MIPS_REVISION_CORID_CORE_FPGA4:
0063 case MIPS_REVISION_CORID_CORE_FPGA5:
0064 case MIPS_REVISION_CORID_CORE_EMUL_MSC:
0065 default:
0066 return MIPS_REVISION_SCON_ROCIT;
0067 }
0068 }
0069
0070 static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size,
0071 enum mem_map map)
0072 {
0073 unsigned long size_preio;
0074 unsigned entries;
0075
0076 entries = 1;
0077 mem_array[0] = cpu_to_be32(PHYS_OFFSET);
0078 if (IS_ENABLED(CONFIG_EVA)) {
0079
0080
0081
0082
0083
0084
0085 mem_array[1] = cpu_to_be32(size);
0086 goto done;
0087 }
0088
0089 size_preio = min_t(unsigned long, size, SZ_256M);
0090 mem_array[1] = cpu_to_be32(size_preio);
0091 size -= size_preio;
0092 if (!size)
0093 goto done;
0094
0095 if (map == MEM_MAP_V2) {
0096
0097
0098
0099
0100
0101
0102
0103 if (size <= SZ_256M)
0104 goto done;
0105 size -= SZ_256M;
0106
0107
0108 entries++;
0109 mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_512M);
0110 mem_array[3] = cpu_to_be32(size);
0111 } else {
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 entries++;
0122 mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_2G + SZ_256M);
0123 mem_array[3] = cpu_to_be32(size);
0124 }
0125
0126 done:
0127 BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
0128 return entries;
0129 }
0130
0131 static void __init append_memory(void *fdt, int root_off)
0132 {
0133 __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
0134 unsigned long memsize;
0135 unsigned mem_entries;
0136 int i, err, mem_off;
0137 enum mem_map mem_map;
0138 u32 config;
0139 char *var, param_name[10], *var_names[] = {
0140 "ememsize", "memsize",
0141 };
0142
0143
0144 mem_off = fdt_path_offset(fdt, "/memory");
0145 if (mem_off >= 0)
0146 return;
0147
0148
0149 for (i = 0; i < ARRAY_SIZE(var_names); i++) {
0150 var = fw_getenv(var_names[i]);
0151 if (!var)
0152 continue;
0153
0154 err = kstrtoul(var, 0, &physical_memsize);
0155 if (!err)
0156 break;
0157
0158 pr_warn("Failed to read the '%s' env variable '%s'\n",
0159 var_names[i], var);
0160 }
0161
0162 if (!physical_memsize) {
0163 pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
0164 physical_memsize = 32 << 20;
0165 }
0166
0167 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
0168
0169
0170
0171
0172 physical_memsize -= PAGE_SIZE;
0173 }
0174
0175
0176 memsize = physical_memsize;
0177
0178
0179 for (i = 0; i < ARRAY_SIZE(var_names); i++) {
0180 snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
0181 var = strstr(arcs_cmdline, param_name);
0182 if (!var)
0183 continue;
0184
0185 memsize = memparse(var + strlen(param_name), NULL);
0186 }
0187
0188
0189 physical_memsize = max_t(unsigned long, physical_memsize, memsize);
0190
0191
0192 if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
0193
0194 config = readl((void __iomem *)CKSEG1ADDR(ROCIT_CONFIG_GEN1));
0195 mem_map = config & ROCIT_CONFIG_GEN1_MEMMAP_MASK;
0196 mem_map >>= ROCIT_CONFIG_GEN1_MEMMAP_SHIFT;
0197 } else {
0198
0199 mem_map = MEM_MAP_V1;
0200 }
0201 if (mem_map > MEM_MAP_V2)
0202 panic("Unsupported physical memory map v%u detected",
0203 (unsigned int)mem_map);
0204
0205
0206 mem_off = fdt_add_subnode(fdt, root_off, "memory");
0207 if (mem_off < 0)
0208 panic("Unable to add memory node to DT: %d", mem_off);
0209
0210 err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
0211 if (err)
0212 panic("Unable to set memory node device_type: %d", err);
0213
0214 mem_entries = gen_fdt_mem_array(mem_array, physical_memsize, mem_map);
0215 err = fdt_setprop(fdt, mem_off, "reg", mem_array,
0216 mem_entries * 2 * sizeof(mem_array[0]));
0217 if (err)
0218 panic("Unable to set memory regs property: %d", err);
0219
0220 mem_entries = gen_fdt_mem_array(mem_array, memsize, mem_map);
0221 err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array,
0222 mem_entries * 2 * sizeof(mem_array[0]));
0223 if (err)
0224 panic("Unable to set linux,usable-memory property: %d", err);
0225 }
0226
0227 static void __init remove_gic(void *fdt)
0228 {
0229 int err, gic_off, i8259_off, cpu_off;
0230 void __iomem *biu_base;
0231 uint32_t cpu_phandle, sc_cfg;
0232
0233
0234 err = mips_cm_probe();
0235 if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX))
0236 return;
0237
0238 if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
0239
0240
0241
0242
0243 biu_base = ioremap(MSC01_BIU_REG_BASE,
0244 MSC01_BIU_ADDRSPACE_SZ);
0245 sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS);
0246 if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) {
0247
0248 sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF);
0249 __raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS);
0250 return;
0251 }
0252 }
0253
0254 gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
0255 if (gic_off < 0) {
0256 pr_warn("malta-dtshim: unable to find DT GIC node: %d\n",
0257 gic_off);
0258 return;
0259 }
0260
0261 err = fdt_nop_node(fdt, gic_off);
0262 if (err)
0263 pr_warn("malta-dtshim: unable to nop GIC node\n");
0264
0265 i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259");
0266 if (i8259_off < 0) {
0267 pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n",
0268 i8259_off);
0269 return;
0270 }
0271
0272 cpu_off = fdt_node_offset_by_compatible(fdt, -1,
0273 "mti,cpu-interrupt-controller");
0274 if (cpu_off < 0) {
0275 pr_warn("malta-dtshim: unable to find CPU intc node: %d\n",
0276 cpu_off);
0277 return;
0278 }
0279
0280 cpu_phandle = fdt_get_phandle(fdt, cpu_off);
0281 if (!cpu_phandle) {
0282 pr_warn("malta-dtshim: unable to get CPU intc phandle\n");
0283 return;
0284 }
0285
0286 err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle);
0287 if (err) {
0288 pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n",
0289 err);
0290 return;
0291 }
0292
0293 err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2);
0294 if (err) {
0295 pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n",
0296 err);
0297 return;
0298 }
0299 }
0300
0301 void __init *malta_dt_shim(void *fdt)
0302 {
0303 int root_off, len, err;
0304 const char *compat;
0305
0306 if (fdt_check_header(fdt))
0307 panic("Corrupt DT");
0308
0309 err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
0310 if (err)
0311 panic("Unable to open FDT: %d", err);
0312
0313 root_off = fdt_path_offset(fdt_buf, "/");
0314 if (root_off < 0)
0315 panic("No / node in DT");
0316
0317 compat = fdt_getprop(fdt_buf, root_off, "compatible", &len);
0318 if (!compat)
0319 panic("No root compatible property in DT: %d", len);
0320
0321
0322 if (strncmp(compat, "mti,malta", len))
0323 return fdt;
0324
0325 append_memory(fdt_buf, root_off);
0326 remove_gic(fdt_buf);
0327
0328 err = fdt_pack(fdt_buf);
0329 if (err)
0330 panic("Unable to pack FDT: %d\n", err);
0331
0332 return fdt_buf;
0333 }