162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2008-2009 ST-Ericsson SA
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/amba/bus.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/irq.h>
1362306a36Sopenharmony_ci#include <linux/irqchip.h>
1462306a36Sopenharmony_ci#include <linux/irqchip/arm-gic.h>
1562306a36Sopenharmony_ci#include <linux/mfd/dbx500-prcmu.h>
1662306a36Sopenharmony_ci#include <linux/platform_data/arm-ux500-pm.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/of_address.h>
2162306a36Sopenharmony_ci#include <linux/of_platform.h>
2262306a36Sopenharmony_ci#include <linux/regulator/machine.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/outercache.h>
2562306a36Sopenharmony_ci#include <asm/hardware/cache-l2x0.h>
2662306a36Sopenharmony_ci#include <asm/mach/map.h>
2762306a36Sopenharmony_ci#include <asm/mach/arch.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int __init ux500_l2x0_unlock(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int i;
3262306a36Sopenharmony_ci	struct device_node *np;
3362306a36Sopenharmony_ci	void __iomem *l2x0_base;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
3662306a36Sopenharmony_ci	l2x0_base = of_iomap(np, 0);
3762306a36Sopenharmony_ci	of_node_put(np);
3862306a36Sopenharmony_ci	if (!l2x0_base)
3962306a36Sopenharmony_ci		return -ENODEV;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/*
4262306a36Sopenharmony_ci	 * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
4362306a36Sopenharmony_ci	 * apparently locks both caches before jumping to the kernel. The
4462306a36Sopenharmony_ci	 * l2x0 core will not touch the unlock registers if the l2x0 is
4562306a36Sopenharmony_ci	 * already enabled, so we do it right here instead. The PL310 has
4662306a36Sopenharmony_ci	 * 8 sets of registers, one per possible CPU.
4762306a36Sopenharmony_ci	 */
4862306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
4962306a36Sopenharmony_ci		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
5062306a36Sopenharmony_ci			       i * L2X0_LOCKDOWN_STRIDE);
5162306a36Sopenharmony_ci		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
5262306a36Sopenharmony_ci			       i * L2X0_LOCKDOWN_STRIDE);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	iounmap(l2x0_base);
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void ux500_l2c310_write_sec(unsigned long val, unsigned reg)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	/*
6162306a36Sopenharmony_ci	 * We can't write to secure registers as we are in non-secure
6262306a36Sopenharmony_ci	 * mode, until we have some SMI service available.
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*
6762306a36Sopenharmony_ci * FIXME: Should we set up the GPIO domain here?
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * The problem is that we cannot put the interrupt resources into the platform
7062306a36Sopenharmony_ci * device until the irqdomain has been added. Right now, we set the GIC interrupt
7162306a36Sopenharmony_ci * domain from init_irq(), then load the gpio driver from
7262306a36Sopenharmony_ci * core_initcall(nmk_gpio_init) and add the platform devices from
7362306a36Sopenharmony_ci * arch_initcall(customize_machine).
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * This feels fragile because it depends on the gpio device getting probed
7662306a36Sopenharmony_ci * _before_ any device uses the gpio interrupts.
7762306a36Sopenharmony_ci*/
7862306a36Sopenharmony_cistatic void __init ux500_init_irq(void)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct device_node *np;
8162306a36Sopenharmony_ci	struct resource r;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	irqchip_init();
8462306a36Sopenharmony_ci	prcmu_early_init();
8562306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
8662306a36Sopenharmony_ci	of_address_to_resource(np, 0, &r);
8762306a36Sopenharmony_ci	of_node_put(np);
8862306a36Sopenharmony_ci	if (!r.start) {
8962306a36Sopenharmony_ci		pr_err("could not find PRCMU base resource\n");
9062306a36Sopenharmony_ci		return;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci	ux500_pm_init(r.start, r.end-r.start);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Unlock before init */
9562306a36Sopenharmony_ci	ux500_l2x0_unlock();
9662306a36Sopenharmony_ci	outer_cache.write_sec = ux500_l2c310_write_sec;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic void ux500_restart(enum reboot_mode mode, const char *cmd)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	local_irq_disable();
10262306a36Sopenharmony_ci	local_fiq_disable();
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	prcmu_system_reset(0);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const struct of_device_id u8500_local_bus_nodes[] = {
10862306a36Sopenharmony_ci	/* only create devices below soc node */
10962306a36Sopenharmony_ci	{ .compatible = "stericsson,db8500", },
11062306a36Sopenharmony_ci	{ .compatible = "simple-bus"},
11162306a36Sopenharmony_ci	{ },
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void __init u8500_init_machine(void)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	of_platform_populate(NULL, u8500_local_bus_nodes,
11762306a36Sopenharmony_ci			     NULL, NULL);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic const char * stericsson_dt_platform_compat[] = {
12162306a36Sopenharmony_ci	"st-ericsson,u8500",
12262306a36Sopenharmony_ci	"st-ericsson,u9500",
12362306a36Sopenharmony_ci	NULL,
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciDT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)")
12762306a36Sopenharmony_ci	.l2c_aux_val    = 0,
12862306a36Sopenharmony_ci	.l2c_aux_mask	= ~0,
12962306a36Sopenharmony_ci	.init_irq	= ux500_init_irq,
13062306a36Sopenharmony_ci	.init_machine	= u8500_init_machine,
13162306a36Sopenharmony_ci	.dt_compat      = stericsson_dt_platform_compat,
13262306a36Sopenharmony_ci	.restart        = ux500_restart,
13362306a36Sopenharmony_ciMACHINE_END
134