18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2010-2011 Calxeda, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <linux/clk.h>
68c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
78c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
88c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
98c2ecf20Sopenharmony_ci#include <linux/input.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/irqchip.h>
128c2ecf20Sopenharmony_ci#include <linux/pl320-ipc.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
158c2ecf20Sopenharmony_ci#include <linux/of_address.h>
168c2ecf20Sopenharmony_ci#include <linux/reboot.h>
178c2ecf20Sopenharmony_ci#include <linux/amba/bus.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/psci.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/hardware/cache-l2x0.h>
228c2ecf20Sopenharmony_ci#include <asm/mach/arch.h>
238c2ecf20Sopenharmony_ci#include <asm/mach/map.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "core.h"
268c2ecf20Sopenharmony_ci#include "sysregs.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_civoid __iomem *sregs_base;
298c2ecf20Sopenharmony_civoid __iomem *scu_base_addr;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void __init highbank_scu_map_io(void)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	unsigned long base;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* Get SCU base */
368c2ecf20Sopenharmony_ci	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	scu_base_addr = ioremap(base, SZ_4K);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void highbank_l2c310_write_sec(unsigned long val, unsigned reg)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	if (reg == L2X0_CTRL)
458c2ecf20Sopenharmony_ci		highbank_smc1(0x102, val);
468c2ecf20Sopenharmony_ci	else
478c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n",
488c2ecf20Sopenharmony_ci			  reg);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void __init highbank_init_irq(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	irqchip_init();
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
568c2ecf20Sopenharmony_ci		highbank_scu_map_io();
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void highbank_power_off(void)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	highbank_set_pwr_shutdown();
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	while (1)
648c2ecf20Sopenharmony_ci		cpu_do_idle();
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int highbank_platform_notifier(struct notifier_block *nb,
688c2ecf20Sopenharmony_ci				  unsigned long event, void *__dev)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct resource *res;
718c2ecf20Sopenharmony_ci	int reg = -1;
728c2ecf20Sopenharmony_ci	u32 val;
738c2ecf20Sopenharmony_ci	struct device *dev = __dev;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (event != BUS_NOTIFY_ADD_DEVICE)
768c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci"))
798c2ecf20Sopenharmony_ci		reg = 0xc;
808c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci"))
818c2ecf20Sopenharmony_ci		reg = 0x18;
828c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "arm,pl330"))
838c2ecf20Sopenharmony_ci		reg = 0x20;
848c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) {
858c2ecf20Sopenharmony_ci		res = platform_get_resource(to_platform_device(dev),
868c2ecf20Sopenharmony_ci					    IORESOURCE_MEM, 0);
878c2ecf20Sopenharmony_ci		if (res) {
888c2ecf20Sopenharmony_ci			if (res->start == 0xfff50000)
898c2ecf20Sopenharmony_ci				reg = 0;
908c2ecf20Sopenharmony_ci			else if (res->start == 0xfff51000)
918c2ecf20Sopenharmony_ci				reg = 4;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (reg < 0)
968c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (of_property_read_bool(dev->of_node, "dma-coherent")) {
998c2ecf20Sopenharmony_ci		val = readl(sregs_base + reg);
1008c2ecf20Sopenharmony_ci		writel(val | 0xff01, sregs_base + reg);
1018c2ecf20Sopenharmony_ci		set_dma_ops(dev, &arm_coherent_dma_ops);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return NOTIFY_OK;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic struct notifier_block highbank_amba_nb = {
1088c2ecf20Sopenharmony_ci	.notifier_call = highbank_platform_notifier,
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic struct notifier_block highbank_platform_nb = {
1128c2ecf20Sopenharmony_ci	.notifier_call = highbank_platform_notifier,
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic struct platform_device highbank_cpuidle_device = {
1168c2ecf20Sopenharmony_ci	.name = "cpuidle-calxeda",
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	u32 key = *(u32 *)data;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (event != 0x1000)
1248c2ecf20Sopenharmony_ci		return 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (key == KEY_POWER)
1278c2ecf20Sopenharmony_ci		orderly_poweroff(false);
1288c2ecf20Sopenharmony_ci	else if (key == 0xffff)
1298c2ecf20Sopenharmony_ci		ctrl_alt_del();
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_cistatic struct notifier_block hb_keys_nb = {
1348c2ecf20Sopenharmony_ci	.notifier_call = hb_keys_notifier,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void __init highbank_init(void)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct device_node *np;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Map system registers */
1428c2ecf20Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
1438c2ecf20Sopenharmony_ci	sregs_base = of_iomap(np, 0);
1448c2ecf20Sopenharmony_ci	WARN_ON(!sregs_base);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	pm_power_off = highbank_power_off;
1478c2ecf20Sopenharmony_ci	highbank_pm_init();
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	bus_register_notifier(&platform_bus_type, &highbank_platform_nb);
1508c2ecf20Sopenharmony_ci	bus_register_notifier(&amba_bustype, &highbank_amba_nb);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	pl320_ipc_register_notifier(&hb_keys_nb);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (psci_ops.cpu_suspend)
1558c2ecf20Sopenharmony_ci		platform_device_register(&highbank_cpuidle_device);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic const char *const highbank_match[] __initconst = {
1598c2ecf20Sopenharmony_ci	"calxeda,highbank",
1608c2ecf20Sopenharmony_ci	"calxeda,ecx-2000",
1618c2ecf20Sopenharmony_ci	NULL,
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ciDT_MACHINE_START(HIGHBANK, "Highbank")
1658c2ecf20Sopenharmony_ci#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
1668c2ecf20Sopenharmony_ci	.dma_zone_size	= (4ULL * SZ_1G),
1678c2ecf20Sopenharmony_ci#endif
1688c2ecf20Sopenharmony_ci	.l2c_aux_val	= 0,
1698c2ecf20Sopenharmony_ci	.l2c_aux_mask	= ~0,
1708c2ecf20Sopenharmony_ci	.l2c_write_sec	= highbank_l2c310_write_sec,
1718c2ecf20Sopenharmony_ci	.init_irq	= highbank_init_irq,
1728c2ecf20Sopenharmony_ci	.init_machine	= highbank_init,
1738c2ecf20Sopenharmony_ci	.dt_compat	= highbank_match,
1748c2ecf20Sopenharmony_ci	.restart	= highbank_restart,
1758c2ecf20Sopenharmony_ciMACHINE_END
176