xref: /openbmc/linux/arch/arm/mach-mvebu/board-v7.c (revision 3972863aad8919fd8ec5527ea560abed285edd40)
199b3d294SThomas Petazzoni /*
299b3d294SThomas Petazzoni  * Device Tree support for Armada 370 and XP platforms.
399b3d294SThomas Petazzoni  *
499b3d294SThomas Petazzoni  * Copyright (C) 2012 Marvell
599b3d294SThomas Petazzoni  *
699b3d294SThomas Petazzoni  * Lior Amsalem <alior@marvell.com>
799b3d294SThomas Petazzoni  * Gregory CLEMENT <gregory.clement@free-electrons.com>
899b3d294SThomas Petazzoni  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
999b3d294SThomas Petazzoni  *
1099b3d294SThomas Petazzoni  * This file is licensed under the terms of the GNU General Public
1199b3d294SThomas Petazzoni  * License version 2.  This program is licensed "as is" without any
1299b3d294SThomas Petazzoni  * warranty of any kind, whether express or implied.
1399b3d294SThomas Petazzoni  */
1499b3d294SThomas Petazzoni 
1599b3d294SThomas Petazzoni #include <linux/kernel.h>
1699b3d294SThomas Petazzoni #include <linux/init.h>
1799b3d294SThomas Petazzoni #include <linux/of_address.h>
188da2b2f7SThomas Petazzoni #include <linux/of_fdt.h>
1999b3d294SThomas Petazzoni #include <linux/io.h>
2099b3d294SThomas Petazzoni #include <linux/clocksource.h>
2199b3d294SThomas Petazzoni #include <linux/dma-mapping.h>
228da2b2f7SThomas Petazzoni #include <linux/memblock.h>
2399b3d294SThomas Petazzoni #include <linux/mbus.h>
2499b3d294SThomas Petazzoni #include <linux/slab.h>
2501178890SThomas Petazzoni #include <linux/irqchip.h>
2699b3d294SThomas Petazzoni #include <asm/hardware/cache-l2x0.h>
2799b3d294SThomas Petazzoni #include <asm/mach/arch.h>
2899b3d294SThomas Petazzoni #include <asm/mach/map.h>
2999b3d294SThomas Petazzoni #include <asm/mach/time.h>
308e6ac203SThomas Petazzoni #include <asm/smp_scu.h>
3199b3d294SThomas Petazzoni #include "armada-370-xp.h"
3299b3d294SThomas Petazzoni #include "common.h"
3399b3d294SThomas Petazzoni #include "coherency.h"
3499b3d294SThomas Petazzoni #include "mvebu-soc-id.h"
3599b3d294SThomas Petazzoni 
366a2b5343SGregory CLEMENT static void __iomem *scu_base;
376a2b5343SGregory CLEMENT 
38ca4a6f87SThomas Petazzoni /*
398e6ac203SThomas Petazzoni  * Enables the SCU when available. Obviously, this is only useful on
408e6ac203SThomas Petazzoni  * Cortex-A based SOCs, not on PJ4B based ones.
418e6ac203SThomas Petazzoni  */
428e6ac203SThomas Petazzoni static void __init mvebu_scu_enable(void)
438e6ac203SThomas Petazzoni {
448e6ac203SThomas Petazzoni 	struct device_node *np =
458e6ac203SThomas Petazzoni 		of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
468e6ac203SThomas Petazzoni 	if (np) {
478e6ac203SThomas Petazzoni 		scu_base = of_iomap(np, 0);
488e6ac203SThomas Petazzoni 		scu_enable(scu_base);
498e6ac203SThomas Petazzoni 		of_node_put(np);
508e6ac203SThomas Petazzoni 	}
518e6ac203SThomas Petazzoni }
528e6ac203SThomas Petazzoni 
536a2b5343SGregory CLEMENT void __iomem *mvebu_get_scu_base(void)
546a2b5343SGregory CLEMENT {
556a2b5343SGregory CLEMENT 	return scu_base;
566a2b5343SGregory CLEMENT }
576a2b5343SGregory CLEMENT 
588e6ac203SThomas Petazzoni /*
598da2b2f7SThomas Petazzoni  * When returning from suspend, the platform goes through the
608da2b2f7SThomas Petazzoni  * bootloader, which executes its DDR3 training code. This code has
618da2b2f7SThomas Petazzoni  * the unfortunate idea of using the first 10 KB of each DRAM bank to
628da2b2f7SThomas Petazzoni  * exercise the RAM and calculate the optimal timings. Therefore, this
638da2b2f7SThomas Petazzoni  * area of RAM is overwritten, and shouldn't be used by the kernel if
648da2b2f7SThomas Petazzoni  * suspend/resume is supported.
658da2b2f7SThomas Petazzoni  */
668da2b2f7SThomas Petazzoni 
678da2b2f7SThomas Petazzoni #ifdef CONFIG_SUSPEND
688da2b2f7SThomas Petazzoni #define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
698da2b2f7SThomas Petazzoni static int __init mvebu_scan_mem(unsigned long node, const char *uname,
708da2b2f7SThomas Petazzoni 				 int depth, void *data)
718da2b2f7SThomas Petazzoni {
728da2b2f7SThomas Petazzoni 	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
738da2b2f7SThomas Petazzoni 	const __be32 *reg, *endp;
748da2b2f7SThomas Petazzoni 	int l;
758da2b2f7SThomas Petazzoni 
768da2b2f7SThomas Petazzoni 	if (type == NULL || strcmp(type, "memory"))
778da2b2f7SThomas Petazzoni 		return 0;
788da2b2f7SThomas Petazzoni 
798da2b2f7SThomas Petazzoni 	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
808da2b2f7SThomas Petazzoni 	if (reg == NULL)
818da2b2f7SThomas Petazzoni 		reg = of_get_flat_dt_prop(node, "reg", &l);
828da2b2f7SThomas Petazzoni 	if (reg == NULL)
838da2b2f7SThomas Petazzoni 		return 0;
848da2b2f7SThomas Petazzoni 
858da2b2f7SThomas Petazzoni 	endp = reg + (l / sizeof(__be32));
868da2b2f7SThomas Petazzoni 	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
878da2b2f7SThomas Petazzoni 		u64 base, size;
888da2b2f7SThomas Petazzoni 
898da2b2f7SThomas Petazzoni 		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
908da2b2f7SThomas Petazzoni 		size = dt_mem_next_cell(dt_root_size_cells, &reg);
918da2b2f7SThomas Petazzoni 
928da2b2f7SThomas Petazzoni 		memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
938da2b2f7SThomas Petazzoni 	}
948da2b2f7SThomas Petazzoni 
958da2b2f7SThomas Petazzoni 	return 0;
968da2b2f7SThomas Petazzoni }
978da2b2f7SThomas Petazzoni 
988da2b2f7SThomas Petazzoni static void __init mvebu_memblock_reserve(void)
998da2b2f7SThomas Petazzoni {
1008da2b2f7SThomas Petazzoni 	of_scan_flat_dt(mvebu_scan_mem, NULL);
1018da2b2f7SThomas Petazzoni }
1028da2b2f7SThomas Petazzoni #else
1038da2b2f7SThomas Petazzoni static void __init mvebu_memblock_reserve(void) {}
1048da2b2f7SThomas Petazzoni #endif
1058da2b2f7SThomas Petazzoni 
10601178890SThomas Petazzoni static void __init mvebu_init_irq(void)
10799b3d294SThomas Petazzoni {
10801178890SThomas Petazzoni 	irqchip_init();
1098e6ac203SThomas Petazzoni 	mvebu_scu_enable();
11099b3d294SThomas Petazzoni 	coherency_init();
1115686a1e5SThomas Petazzoni 	BUG_ON(mvebu_mbus_dt_init(coherency_available()));
112752ef800SThomas Petazzoni }
113ca4a6f87SThomas Petazzoni 
11499b3d294SThomas Petazzoni static void __init i2c_quirk(void)
11599b3d294SThomas Petazzoni {
11699b3d294SThomas Petazzoni 	struct device_node *np;
11799b3d294SThomas Petazzoni 	u32 dev, rev;
11899b3d294SThomas Petazzoni 
11999b3d294SThomas Petazzoni 	/*
12099b3d294SThomas Petazzoni 	 * Only revisons more recent than A0 support the offload
12199b3d294SThomas Petazzoni 	 * mechanism. We can exit only if we are sure that we can
12299b3d294SThomas Petazzoni 	 * get the SoC revision and it is more recent than A0.
12399b3d294SThomas Petazzoni 	 */
1248eee0f81SGregory CLEMENT 	if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
12599b3d294SThomas Petazzoni 		return;
12699b3d294SThomas Petazzoni 
12799b3d294SThomas Petazzoni 	for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
12899b3d294SThomas Petazzoni 		struct property *new_compat;
12999b3d294SThomas Petazzoni 
13099b3d294SThomas Petazzoni 		new_compat = kzalloc(sizeof(*new_compat), GFP_KERNEL);
13199b3d294SThomas Petazzoni 
13299b3d294SThomas Petazzoni 		new_compat->name = kstrdup("compatible", GFP_KERNEL);
13399b3d294SThomas Petazzoni 		new_compat->length = sizeof("marvell,mv78230-a0-i2c");
13499b3d294SThomas Petazzoni 		new_compat->value = kstrdup("marvell,mv78230-a0-i2c",
13599b3d294SThomas Petazzoni 						GFP_KERNEL);
13699b3d294SThomas Petazzoni 
13799b3d294SThomas Petazzoni 		of_update_property(np, new_compat);
13899b3d294SThomas Petazzoni 	}
13999b3d294SThomas Petazzoni 	return;
14099b3d294SThomas Petazzoni }
14199b3d294SThomas Petazzoni 
14299b3d294SThomas Petazzoni static void __init mvebu_dt_init(void)
14399b3d294SThomas Petazzoni {
1445129ee22SAndrew Lunn 	if (of_machine_is_compatible("marvell,armadaxp"))
14599b3d294SThomas Petazzoni 		i2c_quirk();
14699b3d294SThomas Petazzoni }
14799b3d294SThomas Petazzoni 
148*3972863aSChris Packham static void __init armada_370_xp_dt_fixup(void)
149*3972863aSChris Packham {
150*3972863aSChris Packham #ifdef CONFIG_SMP
151*3972863aSChris Packham 	smp_set_ops(smp_ops(armada_xp_smp_ops));
152*3972863aSChris Packham #endif
153*3972863aSChris Packham }
154*3972863aSChris Packham 
155bc2d7a58SThomas Petazzoni static const char * const armada_370_xp_dt_compat[] __initconst = {
15699b3d294SThomas Petazzoni 	"marvell,armada-370-xp",
15799b3d294SThomas Petazzoni 	NULL,
15899b3d294SThomas Petazzoni };
15999b3d294SThomas Petazzoni 
160a017dbb6SThomas Petazzoni DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
1619847cf04SRussell King 	.l2c_aux_val	= 0,
1629847cf04SRussell King 	.l2c_aux_mask	= ~0,
16399b3d294SThomas Petazzoni 	.init_machine	= mvebu_dt_init,
16401178890SThomas Petazzoni 	.init_irq       = mvebu_init_irq,
16599b3d294SThomas Petazzoni 	.restart	= mvebu_restart,
1668da2b2f7SThomas Petazzoni 	.reserve        = mvebu_memblock_reserve,
16799b3d294SThomas Petazzoni 	.dt_compat	= armada_370_xp_dt_compat,
168*3972863aSChris Packham 	.dt_fixup	= armada_370_xp_dt_fixup,
16999b3d294SThomas Petazzoni MACHINE_END
170d3ce7f25SGregory CLEMENT 
171bc2d7a58SThomas Petazzoni static const char * const armada_375_dt_compat[] __initconst = {
172d3ce7f25SGregory CLEMENT 	"marvell,armada375",
173d3ce7f25SGregory CLEMENT 	NULL,
174d3ce7f25SGregory CLEMENT };
175d3ce7f25SGregory CLEMENT 
176d3ce7f25SGregory CLEMENT DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
1779847cf04SRussell King 	.l2c_aux_val	= 0,
1789847cf04SRussell King 	.l2c_aux_mask	= ~0,
17901178890SThomas Petazzoni 	.init_irq       = mvebu_init_irq,
1805fd62066SEzequiel Garcia 	.init_machine	= mvebu_dt_init,
181d3ce7f25SGregory CLEMENT 	.restart	= mvebu_restart,
182d3ce7f25SGregory CLEMENT 	.dt_compat	= armada_375_dt_compat,
183d3ce7f25SGregory CLEMENT MACHINE_END
1849aa30f1cSThomas Petazzoni 
185bc2d7a58SThomas Petazzoni static const char * const armada_38x_dt_compat[] __initconst = {
1869aa30f1cSThomas Petazzoni 	"marvell,armada380",
1879aa30f1cSThomas Petazzoni 	"marvell,armada385",
1889aa30f1cSThomas Petazzoni 	NULL,
1899aa30f1cSThomas Petazzoni };
1909aa30f1cSThomas Petazzoni 
1919aa30f1cSThomas Petazzoni DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)")
1929847cf04SRussell King 	.l2c_aux_val	= 0,
1939847cf04SRussell King 	.l2c_aux_mask	= ~0,
19401178890SThomas Petazzoni 	.init_irq       = mvebu_init_irq,
1959aa30f1cSThomas Petazzoni 	.restart	= mvebu_restart,
1969aa30f1cSThomas Petazzoni 	.dt_compat	= armada_38x_dt_compat,
1979aa30f1cSThomas Petazzoni MACHINE_END
198242ede0bSThomas Petazzoni 
199242ede0bSThomas Petazzoni static const char * const armada_39x_dt_compat[] __initconst = {
200242ede0bSThomas Petazzoni 	"marvell,armada390",
201242ede0bSThomas Petazzoni 	"marvell,armada398",
202242ede0bSThomas Petazzoni 	NULL,
203242ede0bSThomas Petazzoni };
204242ede0bSThomas Petazzoni 
205242ede0bSThomas Petazzoni DT_MACHINE_START(ARMADA_39X_DT, "Marvell Armada 39x (Device Tree)")
206242ede0bSThomas Petazzoni 	.l2c_aux_val	= 0,
207242ede0bSThomas Petazzoni 	.l2c_aux_mask	= ~0,
208242ede0bSThomas Petazzoni 	.init_irq       = mvebu_init_irq,
209242ede0bSThomas Petazzoni 	.restart	= mvebu_restart,
210242ede0bSThomas Petazzoni 	.dt_compat	= armada_39x_dt_compat,
211242ede0bSThomas Petazzoni MACHINE_END
212