1220e6cf7SRob Herring /* 2220e6cf7SRob Herring * Copyright 2010-2011 Calxeda, Inc. 3220e6cf7SRob Herring * 4220e6cf7SRob Herring * This program is free software; you can redistribute it and/or modify it 5220e6cf7SRob Herring * under the terms and conditions of the GNU General Public License, 6220e6cf7SRob Herring * version 2, as published by the Free Software Foundation. 7220e6cf7SRob Herring * 8220e6cf7SRob Herring * This program is distributed in the hope it will be useful, but WITHOUT 9220e6cf7SRob Herring * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10220e6cf7SRob Herring * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11220e6cf7SRob Herring * more details. 12220e6cf7SRob Herring * 13220e6cf7SRob Herring * You should have received a copy of the GNU General Public License along with 14220e6cf7SRob Herring * this program. If not, see <http://www.gnu.org/licenses/>. 15220e6cf7SRob Herring */ 16220e6cf7SRob Herring #include <linux/clk.h> 17220e6cf7SRob Herring #include <linux/clkdev.h> 180583fe47SRob Herring #include <linux/clocksource.h> 191dc737c4SRob Herring #include <linux/dma-mapping.h> 2038431148SRob Herring #include <linux/input.h> 21220e6cf7SRob Herring #include <linux/io.h> 220529e315SRob Herring #include <linux/irqchip.h> 2338431148SRob Herring #include <linux/mailbox.h> 24220e6cf7SRob Herring #include <linux/of.h> 25220e6cf7SRob Herring #include <linux/of_irq.h> 26220e6cf7SRob Herring #include <linux/of_platform.h> 27220e6cf7SRob Herring #include <linux/of_address.h> 2838431148SRob Herring #include <linux/reboot.h> 291dc737c4SRob Herring #include <linux/amba/bus.h> 3060a66e37SDaniel Lezcano #include <linux/platform_device.h> 31220e6cf7SRob Herring 32dd68eb02SRob Herring #include <asm/psci.h> 33220e6cf7SRob Herring #include <asm/hardware/cache-l2x0.h> 34220e6cf7SRob Herring #include <asm/mach/arch.h> 3552530343SRob Herring #include <asm/mach/map.h> 36220e6cf7SRob Herring 37220e6cf7SRob Herring #include "core.h" 38220e6cf7SRob Herring #include "sysregs.h" 39220e6cf7SRob Herring 40220e6cf7SRob Herring void __iomem *sregs_base; 417a2848d3SRob Herring void __iomem *scu_base_addr; 42220e6cf7SRob Herring 43220e6cf7SRob Herring static void __init highbank_scu_map_io(void) 44220e6cf7SRob Herring { 45220e6cf7SRob Herring unsigned long base; 46220e6cf7SRob Herring 47220e6cf7SRob Herring /* Get SCU base */ 48220e6cf7SRob Herring asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); 49220e6cf7SRob Herring 507a2848d3SRob Herring scu_base_addr = ioremap(base, SZ_4K); 51220e6cf7SRob Herring } 52220e6cf7SRob Herring 53220e6cf7SRob Herring 540074fb2cSRussell King static void highbank_l2c310_write_sec(unsigned long val, unsigned reg) 558e56130dSRob Herring { 560074fb2cSRussell King if (reg == L2X0_CTRL) 570074fb2cSRussell King highbank_smc1(0x102, val); 580074fb2cSRussell King else 590074fb2cSRussell King WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n", 600074fb2cSRussell King reg); 618e56130dSRob Herring } 628e56130dSRob Herring 63220e6cf7SRob Herring static void __init highbank_init_irq(void) 64220e6cf7SRob Herring { 650529e315SRob Herring irqchip_init(); 668e56130dSRob Herring 677a2848d3SRob Herring if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9")) 687a2848d3SRob Herring highbank_scu_map_io(); 69220e6cf7SRob Herring } 70220e6cf7SRob Herring 71220e6cf7SRob Herring static void highbank_power_off(void) 72220e6cf7SRob Herring { 73c05ee88fSRob Herring highbank_set_pwr_shutdown(); 74220e6cf7SRob Herring 75220e6cf7SRob Herring while (1) 76220e6cf7SRob Herring cpu_do_idle(); 77220e6cf7SRob Herring } 78220e6cf7SRob Herring 791dc737c4SRob Herring static int highbank_platform_notifier(struct notifier_block *nb, 801dc737c4SRob Herring unsigned long event, void *__dev) 811dc737c4SRob Herring { 821dc737c4SRob Herring struct resource *res; 831dc737c4SRob Herring int reg = -1; 84e64bf95eSRob Herring u32 val; 851dc737c4SRob Herring struct device *dev = __dev; 861dc737c4SRob Herring 871dc737c4SRob Herring if (event != BUS_NOTIFY_ADD_DEVICE) 881dc737c4SRob Herring return NOTIFY_DONE; 891dc737c4SRob Herring 901dc737c4SRob Herring if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci")) 911dc737c4SRob Herring reg = 0xc; 921dc737c4SRob Herring else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci")) 931dc737c4SRob Herring reg = 0x18; 941dc737c4SRob Herring else if (of_device_is_compatible(dev->of_node, "arm,pl330")) 951dc737c4SRob Herring reg = 0x20; 961dc737c4SRob Herring else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) { 971dc737c4SRob Herring res = platform_get_resource(to_platform_device(dev), 981dc737c4SRob Herring IORESOURCE_MEM, 0); 991dc737c4SRob Herring if (res) { 1001dc737c4SRob Herring if (res->start == 0xfff50000) 1011dc737c4SRob Herring reg = 0; 1021dc737c4SRob Herring else if (res->start == 0xfff51000) 1031dc737c4SRob Herring reg = 4; 1041dc737c4SRob Herring } 1051dc737c4SRob Herring } 1061dc737c4SRob Herring 1071dc737c4SRob Herring if (reg < 0) 1081dc737c4SRob Herring return NOTIFY_DONE; 1091dc737c4SRob Herring 1101dc737c4SRob Herring if (of_property_read_bool(dev->of_node, "dma-coherent")) { 111e64bf95eSRob Herring val = readl(sregs_base + reg); 112e64bf95eSRob Herring writel(val | 0xff01, sregs_base + reg); 1131dc737c4SRob Herring set_dma_ops(dev, &arm_coherent_dma_ops); 114e64bf95eSRob Herring } 1151dc737c4SRob Herring 1161dc737c4SRob Herring return NOTIFY_OK; 1171dc737c4SRob Herring } 1181dc737c4SRob Herring 1191dc737c4SRob Herring static struct notifier_block highbank_amba_nb = { 1201dc737c4SRob Herring .notifier_call = highbank_platform_notifier, 1211dc737c4SRob Herring }; 1221dc737c4SRob Herring 1231dc737c4SRob Herring static struct notifier_block highbank_platform_nb = { 1241dc737c4SRob Herring .notifier_call = highbank_platform_notifier, 1251dc737c4SRob Herring }; 1261dc737c4SRob Herring 12760a66e37SDaniel Lezcano static struct platform_device highbank_cpuidle_device = { 12860a66e37SDaniel Lezcano .name = "cpuidle-calxeda", 12960a66e37SDaniel Lezcano }; 13060a66e37SDaniel Lezcano 13138431148SRob Herring static int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data) 13238431148SRob Herring { 13338431148SRob Herring u32 key = *(u32 *)data; 13438431148SRob Herring 13538431148SRob Herring if (event != 0x1000) 13638431148SRob Herring return 0; 13738431148SRob Herring 13838431148SRob Herring if (key == KEY_POWER) 13938431148SRob Herring orderly_poweroff(false); 14038431148SRob Herring else if (key == 0xffff) 14138431148SRob Herring ctrl_alt_del(); 14238431148SRob Herring 14338431148SRob Herring return 0; 14438431148SRob Herring } 14538431148SRob Herring static struct notifier_block hb_keys_nb = { 14638431148SRob Herring .notifier_call = hb_keys_notifier, 14738431148SRob Herring }; 14838431148SRob Herring 149220e6cf7SRob Herring static void __init highbank_init(void) 150220e6cf7SRob Herring { 15126cae166SSebastian Hesselbarth struct device_node *np; 15226cae166SSebastian Hesselbarth 15326cae166SSebastian Hesselbarth /* Map system registers */ 15426cae166SSebastian Hesselbarth np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); 15526cae166SSebastian Hesselbarth sregs_base = of_iomap(np, 0); 15626cae166SSebastian Hesselbarth WARN_ON(!sregs_base); 15726cae166SSebastian Hesselbarth 158220e6cf7SRob Herring pm_power_off = highbank_power_off; 159a283580cSRob Herring highbank_pm_init(); 160220e6cf7SRob Herring 1611dc737c4SRob Herring bus_register_notifier(&platform_bus_type, &highbank_platform_nb); 1621dc737c4SRob Herring bus_register_notifier(&amba_bustype, &highbank_amba_nb); 1631dc737c4SRob Herring 16438431148SRob Herring pl320_ipc_register_notifier(&hb_keys_nb); 16538431148SRob Herring 166220e6cf7SRob Herring of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 16760a66e37SDaniel Lezcano 168a410146cSRob Herring if (psci_ops.cpu_suspend) 16960a66e37SDaniel Lezcano platform_device_register(&highbank_cpuidle_device); 170220e6cf7SRob Herring } 171220e6cf7SRob Herring 172220e6cf7SRob Herring static const char *highbank_match[] __initconst = { 173220e6cf7SRob Herring "calxeda,highbank", 174e095c0d1SRob Herring "calxeda,ecx-2000", 175220e6cf7SRob Herring NULL, 176220e6cf7SRob Herring }; 177220e6cf7SRob Herring 178220e6cf7SRob Herring DT_MACHINE_START(HIGHBANK, "Highbank") 179a6a39834SRob Herring #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) 180a6a39834SRob Herring .dma_zone_size = (4ULL * SZ_1G), 181a6a39834SRob Herring #endif 182513b9a08SRussell King .l2c_aux_val = 0, 183513b9a08SRussell King .l2c_aux_mask = ~0, 184513b9a08SRussell King .l2c_write_sec = highbank_l2c310_write_sec, 185220e6cf7SRob Herring .init_irq = highbank_init_irq, 186220e6cf7SRob Herring .init_machine = highbank_init, 187220e6cf7SRob Herring .dt_compat = highbank_match, 18800e9967eSRussell King .restart = highbank_restart, 189220e6cf7SRob Herring MACHINE_END 190