Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Device Tree support for Armada 370 and XP platforms.
0004  *
0005  * Copyright (C) 2012 Marvell
0006  *
0007  * Lior Amsalem <alior@marvell.com>
0008  * Gregory CLEMENT <gregory.clement@free-electrons.com>
0009  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/init.h>
0014 #include <linux/of_address.h>
0015 #include <linux/of_fdt.h>
0016 #include <linux/io.h>
0017 #include <linux/clocksource.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/memblock.h>
0020 #include <linux/mbus.h>
0021 #include <linux/slab.h>
0022 #include <linux/irqchip.h>
0023 #include <asm/hardware/cache-l2x0.h>
0024 #include <asm/mach/arch.h>
0025 #include <asm/mach/map.h>
0026 #include <asm/mach/time.h>
0027 #include <asm/smp_scu.h>
0028 #include "armada-370-xp.h"
0029 #include "common.h"
0030 #include "coherency.h"
0031 #include "mvebu-soc-id.h"
0032 
0033 static void __iomem *scu_base;
0034 
0035 /*
0036  * Enables the SCU when available. Obviously, this is only useful on
0037  * Cortex-A based SOCs, not on PJ4B based ones.
0038  */
0039 static void __init mvebu_scu_enable(void)
0040 {
0041     struct device_node *np =
0042         of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
0043     if (np) {
0044         scu_base = of_iomap(np, 0);
0045         scu_enable(scu_base);
0046         of_node_put(np);
0047     }
0048 }
0049 
0050 void __iomem *mvebu_get_scu_base(void)
0051 {
0052     return scu_base;
0053 }
0054 
0055 /*
0056  * When returning from suspend, the platform goes through the
0057  * bootloader, which executes its DDR3 training code. This code has
0058  * the unfortunate idea of using the first 10 KB of each DRAM bank to
0059  * exercise the RAM and calculate the optimal timings. Therefore, this
0060  * area of RAM is overwritten, and shouldn't be used by the kernel if
0061  * suspend/resume is supported.
0062  */
0063 
0064 #ifdef CONFIG_SUSPEND
0065 #define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
0066 static int __init mvebu_scan_mem(unsigned long node, const char *uname,
0067                  int depth, void *data)
0068 {
0069     const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
0070     const __be32 *reg, *endp;
0071     int l;
0072 
0073     if (type == NULL || strcmp(type, "memory"))
0074         return 0;
0075 
0076     reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
0077     if (reg == NULL)
0078         reg = of_get_flat_dt_prop(node, "reg", &l);
0079     if (reg == NULL)
0080         return 0;
0081 
0082     endp = reg + (l / sizeof(__be32));
0083     while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
0084         u64 base, size;
0085 
0086         base = dt_mem_next_cell(dt_root_addr_cells, &reg);
0087         size = dt_mem_next_cell(dt_root_size_cells, &reg);
0088 
0089         memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
0090     }
0091 
0092     return 0;
0093 }
0094 
0095 static void __init mvebu_memblock_reserve(void)
0096 {
0097     of_scan_flat_dt(mvebu_scan_mem, NULL);
0098 }
0099 #else
0100 static void __init mvebu_memblock_reserve(void) {}
0101 #endif
0102 
0103 static void __init mvebu_init_irq(void)
0104 {
0105     irqchip_init();
0106     mvebu_scu_enable();
0107     coherency_init();
0108     BUG_ON(mvebu_mbus_dt_init(coherency_available()));
0109 }
0110 
0111 static void __init i2c_quirk(void)
0112 {
0113     struct device_node *np;
0114     u32 dev, rev;
0115 
0116     /*
0117      * Only revisons more recent than A0 support the offload
0118      * mechanism. We can exit only if we are sure that we can
0119      * get the SoC revision and it is more recent than A0.
0120      */
0121     if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
0122         return;
0123 
0124     for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
0125         struct property *new_compat;
0126 
0127         new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);
0128 
0129         new_compat->name = kstrdup("compatible", GFP_KERNEL);
0130         new_compat->length = sizeof("marvell,mv78230-a0-i2c");
0131         new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
0132                         GFP_KERNEL);
0133 
0134         of_update_property(np, new_compat);
0135     }
0136 }
0137 
0138 static void __init mvebu_dt_init(void)
0139 {
0140     if (of_machine_is_compatible("marvell,armadaxp"))
0141         i2c_quirk();
0142 }
0143 
0144 static void __init armada_370_xp_dt_fixup(void)
0145 {
0146 #ifdef CONFIG_SMP
0147     smp_set_ops(smp_ops(armada_xp_smp_ops));
0148 #endif
0149 }
0150 
0151 static const char * const armada_370_xp_dt_compat[] __initconst = {
0152     "marvell,armada-370-xp",
0153     NULL,
0154 };
0155 
0156 DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
0157     .l2c_aux_val    = 0,
0158     .l2c_aux_mask   = ~0,
0159     .init_machine   = mvebu_dt_init,
0160     .init_irq       = mvebu_init_irq,
0161     .restart    = mvebu_restart,
0162     .reserve        = mvebu_memblock_reserve,
0163     .dt_compat  = armada_370_xp_dt_compat,
0164     .dt_fixup   = armada_370_xp_dt_fixup,
0165 MACHINE_END
0166 
0167 static const char * const armada_375_dt_compat[] __initconst = {
0168     "marvell,armada375",
0169     NULL,
0170 };
0171 
0172 DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
0173     .l2c_aux_val    = 0,
0174     .l2c_aux_mask   = ~0,
0175     .init_irq       = mvebu_init_irq,
0176     .init_machine   = mvebu_dt_init,
0177     .restart    = mvebu_restart,
0178     .dt_compat  = armada_375_dt_compat,
0179 MACHINE_END
0180 
0181 static const char * const armada_38x_dt_compat[] __initconst = {
0182     "marvell,armada380",
0183     "marvell,armada385",
0184     NULL,
0185 };
0186 
0187 DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)")
0188     .l2c_aux_val    = 0,
0189     .l2c_aux_mask   = ~0,
0190     .init_irq       = mvebu_init_irq,
0191     .restart    = mvebu_restart,
0192     .dt_compat  = armada_38x_dt_compat,
0193 MACHINE_END
0194 
0195 static const char * const armada_39x_dt_compat[] __initconst = {
0196     "marvell,armada390",
0197     "marvell,armada398",
0198     NULL,
0199 };
0200 
0201 DT_MACHINE_START(ARMADA_39X_DT, "Marvell Armada 39x (Device Tree)")
0202     .l2c_aux_val    = 0,
0203     .l2c_aux_mask   = ~0,
0204     .init_irq       = mvebu_init_irq,
0205     .restart    = mvebu_restart,
0206     .dt_compat  = armada_39x_dt_compat,
0207 MACHINE_END