diff options
Diffstat (limited to 'arch/arm/mach-highbank')
| -rw-r--r-- | arch/arm/mach-highbank/Kconfig | 20 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/core.h | 9 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/highbank.c | 146 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/hotplug.c | 40 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/platsmp.c | 87 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/pm.c | 26 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/sysregs.h | 25 | ||||
| -rw-r--r-- | arch/arm/mach-highbank/system.c | 9 |
9 files changed, 116 insertions, 248 deletions
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig index 551c97e87a7..a5960e2ac09 100644 --- a/arch/arm/mach-highbank/Kconfig +++ b/arch/arm/mach-highbank/Kconfig @@ -1,15 +1,19 @@ config ARCH_HIGHBANK bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7 - select ARCH_WANT_OPTIONAL_GPIOLIB + select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE + select ARCH_HAS_HOLES_MEMORYMODEL + select ARCH_HAS_OPP + select ARCH_SUPPORTS_BIG_ENDIAN select ARM_AMBA + select ARM_ERRATA_764369 if SMP + select ARM_ERRATA_775420 + select ARM_ERRATA_798181 if SMP select ARM_GIC + select ARM_PSCI select ARM_TIMER_SP804 select CACHE_L2X0 - select CLKDEV_LOOKUP - select COMMON_CLK - select CPU_V7 - select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU - select HAVE_SMP - select SPARSE_IRQ - select USE_OF + select HAVE_ARM_TWD if SMP + select MAILBOX + select PL320_MBOX + select ZONE_DMA if ARM_LPAE diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index 8a1ef576d79..55840f414d3 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -3,6 +3,4 @@ obj-y := highbank.o system.o smc.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_smc.o :=-Wa,-march=armv7-a$(plus_sec) -obj-$(CONFIG_SMP) += platsmp.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_PM_SLEEP) += pm.o diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h index 80235b46cb5..7ec5edcd133 100644 --- a/arch/arm/mach-highbank/core.h +++ b/arch/arm/mach-highbank/core.h @@ -1,9 +1,9 @@ #ifndef __HIGHBANK_CORE_H #define __HIGHBANK_CORE_H -extern void highbank_set_cpu_jump(int cpu, void *jump_addr); -extern void highbank_clocks_init(void); -extern void highbank_restart(char, const char *); +#include <linux/reboot.h> + +extern void highbank_restart(enum reboot_mode, const char *); extern void __iomem *scu_base_addr; #ifdef CONFIG_PM_SLEEP @@ -13,8 +13,5 @@ static inline void highbank_pm_init(void) {} #endif extern void highbank_smc1(int fn, int arg); -extern void highbank_cpu_die(unsigned int cpu); - -extern struct smp_operations highbank_smp_ops; #endif diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index dc248167d20..8c35ae4ff17 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -15,28 +15,24 @@ */ #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/clocksource.h> #include <linux/dma-mapping.h> +#include <linux/input.h> #include <linux/io.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> +#include <linux/irqchip.h> +#include <linux/mailbox.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_address.h> -#include <linux/smp.h> +#include <linux/reboot.h> #include <linux/amba/bus.h> +#include <linux/platform_device.h> -#include <asm/arch_timer.h> -#include <asm/cacheflush.h> -#include <asm/smp_plat.h> -#include <asm/smp_twd.h> -#include <asm/hardware/arm_timer.h> -#include <asm/hardware/timer-sp.h> -#include <asm/hardware/gic.h> +#include <asm/psci.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <asm/mach/time.h> #include "core.h" #include "sysregs.h" @@ -54,88 +50,27 @@ static void __init highbank_scu_map_io(void) scu_base_addr = ioremap(base, SZ_4K); } -#define HB_JUMP_TABLE_PHYS(cpu) (0x40 + (0x10 * (cpu))) -#define HB_JUMP_TABLE_VIRT(cpu) phys_to_virt(HB_JUMP_TABLE_PHYS(cpu)) -void highbank_set_cpu_jump(int cpu, void *jump_addr) +static void highbank_l2c310_write_sec(unsigned long val, unsigned reg) { - cpu = cpu_logical_map(cpu); - writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu)); - __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16); - outer_clean_range(HB_JUMP_TABLE_PHYS(cpu), - HB_JUMP_TABLE_PHYS(cpu) + 15); + if (reg == L2X0_CTRL) + highbank_smc1(0x102, val); + else + WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n", + reg); } -const static struct of_device_id irq_match[] = { - { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, }, - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, - {} -}; - -#ifdef CONFIG_CACHE_L2X0 -static void highbank_l2x0_disable(void) -{ - /* Disable PL310 L2 Cache controller */ - highbank_smc1(0x102, 0x0); -} -#endif - static void __init highbank_init_irq(void) { - of_irq_init(irq_match); + irqchip_init(); if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9")) highbank_scu_map_io(); - -#ifdef CONFIG_CACHE_L2X0 - /* Enable PL310 L2 Cache controller */ - highbank_smc1(0x102, 0x1); - l2x0_of_init(0, ~0UL); - outer_cache.disable = highbank_l2x0_disable; -#endif -} - -static struct clk_lookup lookup = { - .dev_id = "sp804", - .con_id = NULL, -}; - -static void __init highbank_timer_init(void) -{ - int irq; - struct device_node *np; - void __iomem *timer_base; - - /* Map system registers */ - np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); - sregs_base = of_iomap(np, 0); - WARN_ON(!sregs_base); - - np = of_find_compatible_node(NULL, NULL, "arm,sp804"); - timer_base = of_iomap(np, 0); - WARN_ON(!timer_base); - irq = irq_of_parse_and_map(np, 0); - - highbank_clocks_init(); - lookup.clk = of_clk_get(np, 0); - clkdev_add(&lookup); - - sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); - sp804_clockevents_init(timer_base, irq, "timer0"); - - twd_local_timer_of_register(); - - arch_timer_of_register(); - arch_timer_sched_clock_init(); } -static struct sys_timer highbank_timer = { - .init = highbank_timer_init, -}; - static void highbank_power_off(void) { - hignbank_set_pwr_shutdown(); + highbank_set_pwr_shutdown(); while (1) cpu_do_idle(); @@ -146,6 +81,7 @@ static int highbank_platform_notifier(struct notifier_block *nb, { struct resource *res; int reg = -1; + u32 val; struct device *dev = __dev; if (event != BUS_NOTIFY_ADD_DEVICE) @@ -172,10 +108,10 @@ static int highbank_platform_notifier(struct notifier_block *nb, return NOTIFY_DONE; if (of_property_read_bool(dev->of_node, "dma-coherent")) { - writel(0xff31, sregs_base + reg); + val = readl(sregs_base + reg); + writel(val | 0xff01, sregs_base + reg); set_dma_ops(dev, &arm_coherent_dma_ops); - } else - writel(0, sregs_base + reg); + } return NOTIFY_OK; } @@ -188,15 +124,49 @@ static struct notifier_block highbank_platform_nb = { .notifier_call = highbank_platform_notifier, }; +static struct platform_device highbank_cpuidle_device = { + .name = "cpuidle-calxeda", +}; + +static int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data) +{ + u32 key = *(u32 *)data; + + if (event != 0x1000) + return 0; + + if (key == KEY_POWER) + orderly_poweroff(false); + else if (key == 0xffff) + ctrl_alt_del(); + + return 0; +} +static struct notifier_block hb_keys_nb = { + .notifier_call = hb_keys_notifier, +}; + static void __init highbank_init(void) { + struct device_node *np; + + /* Map system registers */ + np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); + sregs_base = of_iomap(np, 0); + WARN_ON(!sregs_base); + pm_power_off = highbank_power_off; highbank_pm_init(); bus_register_notifier(&platform_bus_type, &highbank_platform_nb); bus_register_notifier(&amba_bustype, &highbank_amba_nb); + pl320_ipc_register_notifier(&hb_keys_nb); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + if (psci_ops.cpu_suspend) + platform_device_register(&highbank_cpuidle_device); } static const char *highbank_match[] __initconst = { @@ -206,11 +176,13 @@ static const char *highbank_match[] __initconst = { }; DT_MACHINE_START(HIGHBANK, "Highbank") - .smp = smp_ops(highbank_smp_ops), - .map_io = debug_ll_io_init, +#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) + .dma_zone_size = (4ULL * SZ_1G), +#endif + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, + .l2c_write_sec = highbank_l2c310_write_sec, .init_irq = highbank_init_irq, - .timer = &highbank_timer, - .handle_irq = gic_handle_irq, .init_machine = highbank_init, .dt_compat = highbank_match, .restart = highbank_restart, diff --git a/arch/arm/mach-highbank/hotplug.c b/arch/arm/mach-highbank/hotplug.c deleted file mode 100644 index 7b60faccd55..00000000000 --- a/arch/arm/mach-highbank/hotplug.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2011 Calxeda, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include <linux/kernel.h> - -#include <asm/cacheflush.h> - -#include "core.h" -#include "sysregs.h" - -extern void secondary_startup(void); - -/* - * platform-specific code to shutdown a CPU - * - */ -void __ref highbank_cpu_die(unsigned int cpu) -{ - flush_cache_all(); - - highbank_set_cpu_jump(cpu, secondary_startup); - highbank_set_core_pwr(); - - cpu_do_idle(); - - /* We should never return from idle */ - panic("highbank: cpu %d unexpectedly exit from shutdown\n", cpu); -} diff --git a/arch/arm/mach-highbank/platsmp.c b/arch/arm/mach-highbank/platsmp.c deleted file mode 100644 index 1129957f6c1..00000000000 --- a/arch/arm/mach-highbank/platsmp.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010-2011 Calxeda, Inc. - * Based on platsmp.c, Copyright (C) 2002 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/io.h> - -#include <asm/smp_scu.h> -#include <asm/hardware/gic.h> - -#include "core.h" - -extern void secondary_startup(void); - -static void __cpuinit highbank_secondary_init(unsigned int cpu) -{ - gic_secondary_init(0); -} - -static int __cpuinit highbank_boot_secondary(unsigned int cpu, struct task_struct *idle) -{ - gic_raise_softirq(cpumask_of(cpu), 0); - return 0; -} - -/* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. - */ -static void __init highbank_smp_init_cpus(void) -{ - unsigned int i, ncores = 4; - - /* sanity check */ - if (ncores > NR_CPUS) { - printk(KERN_WARNING - "highbank: no. of cores (%d) greater than configured " - "maximum of %d - clipping\n", - ncores, NR_CPUS); - ncores = NR_CPUS; - } - - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); - - set_smp_cross_call(gic_raise_softirq); -} - -static void __init highbank_smp_prepare_cpus(unsigned int max_cpus) -{ - int i; - - if (scu_base_addr) - scu_enable(scu_base_addr); - - /* - * Write the address of secondary startup into the jump table - * The cores are in wfi and wait until they receive a soft interrupt - * and a non-zero value to jump to. Then the secondary CPU branches - * to this address. - */ - for (i = 1; i < max_cpus; i++) - highbank_set_cpu_jump(i, secondary_startup); -} - -struct smp_operations highbank_smp_ops __initdata = { - .smp_init_cpus = highbank_smp_init_cpus, - .smp_prepare_cpus = highbank_smp_prepare_cpus, - .smp_secondary_init = highbank_secondary_init, - .smp_boot_secondary = highbank_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = highbank_cpu_die, -#endif -}; diff --git a/arch/arm/mach-highbank/pm.c b/arch/arm/mach-highbank/pm.c index 74aa135966f..7f2bd85eb93 100644 --- a/arch/arm/mach-highbank/pm.c +++ b/arch/arm/mach-highbank/pm.c @@ -14,28 +14,33 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/cpu_pm.h> #include <linux/init.h> -#include <linux/io.h> #include <linux/suspend.h> -#include <asm/proc-fns.h> #include <asm/suspend.h> - -#include "core.h" -#include "sysregs.h" +#include <asm/psci.h> static int highbank_suspend_finish(unsigned long val) { - cpu_do_idle(); - return 0; + const struct psci_power_state ps = { + .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, + .affinity_level = 1, + }; + + return psci_ops.cpu_suspend(ps, __pa(cpu_resume)); } static int highbank_pm_enter(suspend_state_t state) { - hignbank_set_pwr_suspend(); - highbank_set_cpu_jump(0, cpu_resume); + cpu_pm_enter(); + cpu_cluster_pm_enter(); + cpu_suspend(0, highbank_suspend_finish); + cpu_cluster_pm_exit(); + cpu_pm_exit(); + return 0; } @@ -46,5 +51,8 @@ static const struct platform_suspend_ops highbank_pm_ops = { void __init highbank_pm_init(void) { + if (!psci_ops.cpu_suspend) + return; + suspend_set_ops(&highbank_pm_ops); } diff --git a/arch/arm/mach-highbank/sysregs.h b/arch/arm/mach-highbank/sysregs.h index e13e8ea7c6c..5995df7f262 100644 --- a/arch/arm/mach-highbank/sysregs.h +++ b/arch/arm/mach-highbank/sysregs.h @@ -37,35 +37,50 @@ extern void __iomem *sregs_base; static inline void highbank_set_core_pwr(void) { - int cpu = cpu_logical_map(smp_processor_id()); + int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0); if (scu_base_addr) scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); else writel_relaxed(1, sregs_base + SREG_CPU_PWR_CTRL(cpu)); } -static inline void hignbank_set_pwr_suspend(void) +static inline void highbank_clear_core_pwr(void) +{ + int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0); + if (scu_base_addr) + scu_power_mode(scu_base_addr, SCU_PM_NORMAL); + else + writel_relaxed(0, sregs_base + SREG_CPU_PWR_CTRL(cpu)); +} + +static inline void highbank_set_pwr_suspend(void) { writel(HB_PWR_SUSPEND, sregs_base + HB_SREG_A9_PWR_REQ); highbank_set_core_pwr(); } -static inline void hignbank_set_pwr_shutdown(void) +static inline void highbank_set_pwr_shutdown(void) { writel(HB_PWR_SHUTDOWN, sregs_base + HB_SREG_A9_PWR_REQ); highbank_set_core_pwr(); } -static inline void hignbank_set_pwr_soft_reset(void) +static inline void highbank_set_pwr_soft_reset(void) { writel(HB_PWR_SOFT_RESET, sregs_base + HB_SREG_A9_PWR_REQ); highbank_set_core_pwr(); } -static inline void hignbank_set_pwr_hard_reset(void) +static inline void highbank_set_pwr_hard_reset(void) { writel(HB_PWR_HARD_RESET, sregs_base + HB_SREG_A9_PWR_REQ); highbank_set_core_pwr(); } +static inline void highbank_clear_pwr_request(void) +{ + writel(~0UL, sregs_base + HB_SREG_A9_PWR_REQ); + highbank_clear_core_pwr(); +} + #endif diff --git a/arch/arm/mach-highbank/system.c b/arch/arm/mach-highbank/system.c index aed96ad9bd4..2df5870b758 100644 --- a/arch/arm/mach-highbank/system.c +++ b/arch/arm/mach-highbank/system.c @@ -15,16 +15,17 @@ */ #include <linux/io.h> #include <asm/proc-fns.h> +#include <linux/reboot.h> #include "core.h" #include "sysregs.h" -void highbank_restart(char mode, const char *cmd) +void highbank_restart(enum reboot_mode mode, const char *cmd) { - if (mode == 'h') - hignbank_set_pwr_hard_reset(); + if (mode == REBOOT_HARD) + highbank_set_pwr_hard_reset(); else - hignbank_set_pwr_soft_reset(); + highbank_set_pwr_soft_reset(); while (1) cpu_do_idle(); |
