linux/arch/arm/mach-mvebu/board-v7.c
<<
>>
Prefs
   1/*
   2 * Device Tree support for Armada 370 and XP platforms.
   3 *
   4 * Copyright (C) 2012 Marvell
   5 *
   6 * Lior Amsalem <alior@marvell.com>
   7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
   8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
   9 *
  10 * This file is licensed under the terms of the GNU General Public
  11 * License version 2.  This program is licensed "as is" without any
  12 * warranty of any kind, whether express or implied.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/init.h>
  17#include <linux/of_address.h>
  18#include <linux/of_fdt.h>
  19#include <linux/io.h>
  20#include <linux/clocksource.h>
  21#include <linux/dma-mapping.h>
  22#include <linux/memblock.h>
  23#include <linux/mbus.h>
  24#include <linux/slab.h>
  25#include <linux/irqchip.h>
  26#include <asm/hardware/cache-l2x0.h>
  27#include <asm/mach/arch.h>
  28#include <asm/mach/map.h>
  29#include <asm/mach/time.h>
  30#include <asm/smp_scu.h>
  31#include "armada-370-xp.h"
  32#include "common.h"
  33#include "coherency.h"
  34#include "mvebu-soc-id.h"
  35
  36static void __iomem *scu_base;
  37
  38/*
  39 * Enables the SCU when available. Obviously, this is only useful on
  40 * Cortex-A based SOCs, not on PJ4B based ones.
  41 */
  42static void __init mvebu_scu_enable(void)
  43{
  44        struct device_node *np =
  45                of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  46        if (np) {
  47                scu_base = of_iomap(np, 0);
  48                scu_enable(scu_base);
  49                of_node_put(np);
  50        }
  51}
  52
  53void __iomem *mvebu_get_scu_base(void)
  54{
  55        return scu_base;
  56}
  57
  58/*
  59 * When returning from suspend, the platform goes through the
  60 * bootloader, which executes its DDR3 training code. This code has
  61 * the unfortunate idea of using the first 10 KB of each DRAM bank to
  62 * exercise the RAM and calculate the optimal timings. Therefore, this
  63 * area of RAM is overwritten, and shouldn't be used by the kernel if
  64 * suspend/resume is supported.
  65 */
  66
  67#ifdef CONFIG_SUSPEND
  68#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
  69static int __init mvebu_scan_mem(unsigned long node, const char *uname,
  70                                 int depth, void *data)
  71{
  72        const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
  73        const __be32 *reg, *endp;
  74        int l;
  75
  76        if (type == NULL || strcmp(type, "memory"))
  77                return 0;
  78
  79        reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
  80        if (reg == NULL)
  81                reg = of_get_flat_dt_prop(node, "reg", &l);
  82        if (reg == NULL)
  83                return 0;
  84
  85        endp = reg + (l / sizeof(__be32));
  86        while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
  87                u64 base, size;
  88
  89                base = dt_mem_next_cell(dt_root_addr_cells, &reg);
  90                size = dt_mem_next_cell(dt_root_size_cells, &reg);
  91
  92                memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
  93        }
  94
  95        return 0;
  96}
  97
  98static void __init mvebu_memblock_reserve(void)
  99{
 100        of_scan_flat_dt(mvebu_scan_mem, NULL);
 101}
 102#else
 103static void __init mvebu_memblock_reserve(void) {}
 104#endif
 105
 106static void __init mvebu_init_irq(void)
 107{
 108        irqchip_init();
 109        mvebu_scu_enable();
 110        coherency_init();
 111        BUG_ON(mvebu_mbus_dt_init(coherency_available()));
 112}
 113
 114static void __init i2c_quirk(void)
 115{
 116        struct device_node *np;
 117        u32 dev, rev;
 118
 119        /*
 120         * Only revisons more recent than A0 support the offload
 121         * mechanism. We can exit only if we are sure that we can
 122         * get the SoC revision and it is more recent than A0.
 123         */
 124        if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
 125                return;
 126
 127        for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
 128                struct property *new_compat;
 129
 130                new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);
 131
 132                new_compat->name = kstrdup("compatible", GFP_KERNEL);
 133                new_compat->length = sizeof("marvell,mv78230-a0-i2c");
 134                new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
 135                                                GFP_KERNEL);
 136
 137                of_update_property(np, new_compat);
 138        }
 139}
 140
 141static void __init mvebu_dt_init(void)
 142{
 143        if (of_machine_is_compatible("marvell,armadaxp"))
 144                i2c_quirk();
 145}
 146
 147static void __init armada_370_xp_dt_fixup(void)
 148{
 149#ifdef CONFIG_SMP
 150        smp_set_ops(smp_ops(armada_xp_smp_ops));
 151#endif
 152}
 153
 154static const char * const armada_370_xp_dt_compat[] __initconst = {
 155        "marvell,armada-370-xp",
 156        NULL,
 157};
 158
 159DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
 160        .l2c_aux_val    = 0,
 161        .l2c_aux_mask   = ~0,
 162        .init_machine   = mvebu_dt_init,
 163        .init_irq       = mvebu_init_irq,
 164        .restart        = mvebu_restart,
 165        .reserve        = mvebu_memblock_reserve,
 166        .dt_compat      = armada_370_xp_dt_compat,
 167        .dt_fixup       = armada_370_xp_dt_fixup,
 168MACHINE_END
 169
 170static const char * const armada_375_dt_compat[] __initconst = {
 171        "marvell,armada375",
 172        NULL,
 173};
 174
 175DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
 176        .l2c_aux_val    = 0,
 177        .l2c_aux_mask   = ~0,
 178        .init_irq       = mvebu_init_irq,
 179        .init_machine   = mvebu_dt_init,
 180        .restart        = mvebu_restart,
 181        .dt_compat      = armada_375_dt_compat,
 182MACHINE_END
 183
 184static const char * const armada_38x_dt_compat[] __initconst = {
 185        "marvell,armada380",
 186        "marvell,armada385",
 187        NULL,
 188};
 189
 190DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)")
 191        .l2c_aux_val    = 0,
 192        .l2c_aux_mask   = ~0,
 193        .init_irq       = mvebu_init_irq,
 194        .restart        = mvebu_restart,
 195        .dt_compat      = armada_38x_dt_compat,
 196MACHINE_END
 197
 198static const char * const armada_39x_dt_compat[] __initconst = {
 199        "marvell,armada390",
 200        "marvell,armada398",
 201        NULL,
 202};
 203
 204DT_MACHINE_START(ARMADA_39X_DT, "Marvell Armada 39x (Device Tree)")
 205        .l2c_aux_val    = 0,
 206        .l2c_aux_mask   = ~0,
 207        .init_irq       = mvebu_init_irq,
 208        .restart        = mvebu_restart,
 209        .dt_compat      = armada_39x_dt_compat,
 210MACHINE_END
 211