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