linux/arch/mips/mti-malta/malta-dtshim.c
<<
>>
Prefs
   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
  25static unsigned char fdt_buf[16 << 10] __initdata;
  26
  27/* determined physical memory size, not overridden by command line args  */
  28extern unsigned long physical_memsize;
  29
  30enum mem_map {
  31        MEM_MAP_V1 = 0,
  32        MEM_MAP_V2,
  33};
  34
  35#define MAX_MEM_ARRAY_ENTRIES 2
  36
  37static __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
  70static 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
 126done:
 127        BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
 128        return entries;
 129}
 130
 131static 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
 227static 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_nocache(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
 301void __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}
 334