^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2010-2011 Calxeda, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/clocksource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/dma-map-ops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/pl320-ipc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/amba/bus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/psci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/hardware/cache-l2x0.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/mach/arch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "sysregs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void __iomem *sregs_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) void __iomem *scu_base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static void __init highbank_scu_map_io(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Get SCU base */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) scu_base_addr = ioremap(base, SZ_4K);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static void highbank_l2c310_write_sec(unsigned long val, unsigned reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (reg == L2X0_CTRL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) highbank_smc1(0x102, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static void __init highbank_init_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) irqchip_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) highbank_scu_map_io();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void highbank_power_off(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) highbank_set_pwr_shutdown();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) while (1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) cpu_do_idle();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int highbank_platform_notifier(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) unsigned long event, void *__dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int reg = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct device *dev = __dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (event != BUS_NOTIFY_ADD_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) reg = 0xc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) reg = 0x18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) else if (of_device_is_compatible(dev->of_node, "arm,pl330"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) reg = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) res = platform_get_resource(to_platform_device(dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (res->start == 0xfff50000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) reg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) else if (res->start == 0xfff51000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) reg = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (reg < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (of_property_read_bool(dev->of_node, "dma-coherent")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) val = readl(sregs_base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) writel(val | 0xff01, sregs_base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) set_dma_ops(dev, &arm_coherent_dma_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static struct notifier_block highbank_amba_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .notifier_call = highbank_platform_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static struct notifier_block highbank_platform_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .notifier_call = highbank_platform_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static struct platform_device highbank_cpuidle_device = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .name = "cpuidle-calxeda",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) u32 key = *(u32 *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (event != 0x1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (key == KEY_POWER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) orderly_poweroff(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) else if (key == 0xffff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ctrl_alt_del();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static struct notifier_block hb_keys_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .notifier_call = hb_keys_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static void __init highbank_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* Map system registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) sregs_base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) WARN_ON(!sregs_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) pm_power_off = highbank_power_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) highbank_pm_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) bus_register_notifier(&platform_bus_type, &highbank_platform_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) bus_register_notifier(&amba_bustype, &highbank_amba_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) pl320_ipc_register_notifier(&hb_keys_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (psci_ops.cpu_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) platform_device_register(&highbank_cpuidle_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static const char *const highbank_match[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) "calxeda,highbank",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) "calxeda,ecx-2000",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) DT_MACHINE_START(HIGHBANK, "Highbank")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .dma_zone_size = (4ULL * SZ_1G),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .l2c_aux_val = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .l2c_aux_mask = ~0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .l2c_write_sec = highbank_l2c310_write_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .init_irq = highbank_init_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .init_machine = highbank_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .dt_compat = highbank_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .restart = highbank_restart,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) MACHINE_END