162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2010-2011 Calxeda, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/clk.h>
662306a36Sopenharmony_ci#include <linux/clkdev.h>
762306a36Sopenharmony_ci#include <linux/clocksource.h>
862306a36Sopenharmony_ci#include <linux/dma-map-ops.h>
962306a36Sopenharmony_ci#include <linux/input.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/irqchip.h>
1262306a36Sopenharmony_ci#include <linux/pl320-ipc.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_irq.h>
1562306a36Sopenharmony_ci#include <linux/of_address.h>
1662306a36Sopenharmony_ci#include <linux/reboot.h>
1762306a36Sopenharmony_ci#include <linux/amba/bus.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/psci.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <asm/hardware/cache-l2x0.h>
2262306a36Sopenharmony_ci#include <asm/mach/arch.h>
2362306a36Sopenharmony_ci#include <asm/mach/map.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "core.h"
2662306a36Sopenharmony_ci#include "sysregs.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_civoid __iomem *sregs_base;
2962306a36Sopenharmony_civoid __iomem *scu_base_addr;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void __init highbank_scu_map_io(void)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	unsigned long base;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* Get SCU base */
3662306a36Sopenharmony_ci	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	scu_base_addr = ioremap(base, SZ_4K);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void highbank_l2c310_write_sec(unsigned long val, unsigned reg)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	if (reg == L2X0_CTRL)
4562306a36Sopenharmony_ci		highbank_smc1(0x102, val);
4662306a36Sopenharmony_ci	else
4762306a36Sopenharmony_ci		WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n",
4862306a36Sopenharmony_ci			  reg);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void __init highbank_init_irq(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	irqchip_init();
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
5662306a36Sopenharmony_ci		highbank_scu_map_io();
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void highbank_power_off(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	highbank_set_pwr_shutdown();
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	while (1)
6462306a36Sopenharmony_ci		cpu_do_idle();
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int highbank_platform_notifier(struct notifier_block *nb,
6862306a36Sopenharmony_ci				  unsigned long event, void *__dev)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct resource *res;
7162306a36Sopenharmony_ci	int reg = -1;
7262306a36Sopenharmony_ci	u32 val;
7362306a36Sopenharmony_ci	struct device *dev = __dev;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (event != BUS_NOTIFY_ADD_DEVICE)
7662306a36Sopenharmony_ci		return NOTIFY_DONE;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci"))
7962306a36Sopenharmony_ci		reg = 0xc;
8062306a36Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci"))
8162306a36Sopenharmony_ci		reg = 0x18;
8262306a36Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "arm,pl330"))
8362306a36Sopenharmony_ci		reg = 0x20;
8462306a36Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) {
8562306a36Sopenharmony_ci		res = platform_get_resource(to_platform_device(dev),
8662306a36Sopenharmony_ci					    IORESOURCE_MEM, 0);
8762306a36Sopenharmony_ci		if (res) {
8862306a36Sopenharmony_ci			if (res->start == 0xfff50000)
8962306a36Sopenharmony_ci				reg = 0;
9062306a36Sopenharmony_ci			else if (res->start == 0xfff51000)
9162306a36Sopenharmony_ci				reg = 4;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (reg < 0)
9662306a36Sopenharmony_ci		return NOTIFY_DONE;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (of_property_read_bool(dev->of_node, "dma-coherent")) {
9962306a36Sopenharmony_ci		val = readl(sregs_base + reg);
10062306a36Sopenharmony_ci		writel(val | 0xff01, sregs_base + reg);
10162306a36Sopenharmony_ci		dev->dma_coherent = true;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return NOTIFY_OK;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic struct notifier_block highbank_amba_nb = {
10862306a36Sopenharmony_ci	.notifier_call = highbank_platform_notifier,
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct notifier_block highbank_platform_nb = {
11262306a36Sopenharmony_ci	.notifier_call = highbank_platform_notifier,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic struct platform_device highbank_cpuidle_device = {
11662306a36Sopenharmony_ci	.name = "cpuidle-calxeda",
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	u32 key = *(u32 *)data;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (event != 0x1000)
12462306a36Sopenharmony_ci		return 0;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (key == KEY_POWER)
12762306a36Sopenharmony_ci		orderly_poweroff(false);
12862306a36Sopenharmony_ci	else if (key == 0xffff)
12962306a36Sopenharmony_ci		ctrl_alt_del();
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return 0;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_cistatic struct notifier_block hb_keys_nb = {
13462306a36Sopenharmony_ci	.notifier_call = hb_keys_notifier,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void __init highbank_init(void)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct device_node *np;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Map system registers */
14262306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
14362306a36Sopenharmony_ci	sregs_base = of_iomap(np, 0);
14462306a36Sopenharmony_ci	WARN_ON(!sregs_base);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	pm_power_off = highbank_power_off;
14762306a36Sopenharmony_ci	highbank_pm_init();
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	bus_register_notifier(&platform_bus_type, &highbank_platform_nb);
15062306a36Sopenharmony_ci	bus_register_notifier(&amba_bustype, &highbank_amba_nb);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	pl320_ipc_register_notifier(&hb_keys_nb);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (psci_ops.cpu_suspend)
15562306a36Sopenharmony_ci		platform_device_register(&highbank_cpuidle_device);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const char *const highbank_match[] __initconst = {
15962306a36Sopenharmony_ci	"calxeda,highbank",
16062306a36Sopenharmony_ci	"calxeda,ecx-2000",
16162306a36Sopenharmony_ci	NULL,
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciDT_MACHINE_START(HIGHBANK, "Highbank")
16562306a36Sopenharmony_ci#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
16662306a36Sopenharmony_ci	.dma_zone_size	= (4ULL * SZ_1G),
16762306a36Sopenharmony_ci#endif
16862306a36Sopenharmony_ci	.l2c_aux_val	= 0,
16962306a36Sopenharmony_ci	.l2c_aux_mask	= ~0,
17062306a36Sopenharmony_ci	.l2c_write_sec	= highbank_l2c310_write_sec,
17162306a36Sopenharmony_ci	.init_irq	= highbank_init_irq,
17262306a36Sopenharmony_ci	.init_machine	= highbank_init,
17362306a36Sopenharmony_ci	.dt_compat	= highbank_match,
17462306a36Sopenharmony_ci	.restart	= highbank_restart,
17562306a36Sopenharmony_ciMACHINE_END
176