From 79f08d9ed217318b4f325b7fcf8f26dcd0e41689 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 21 Oct 2013 11:07:04 +0200 Subject: ARM: drop for !ARCH_MULTIPLATFORM, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While isn't used for multi-platform builds since long it still is for "normal" builds. As the previous patches fix all sites to not make use of this per-platform file, it can go now for good also for platforms that are not (yet) converted to multi-platform. While at it there are no users of CLOCK_TICK_RATE any more, so also drop the dummy #define. Signed-off-by: Uwe Kleine-König --- arch/arm/mach-msm/include/mach/timex.h | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 arch/arm/mach-msm/include/mach/timex.h (limited to 'arch/arm/mach-msm') diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h deleted file mode 100644 index a62e6b215aec..000000000000 --- a/arch/arm/mach-msm/include/mach/timex.h +++ /dev/null @@ -1,21 +0,0 @@ -/* arch/arm/mach-msm/include/mach/timex.h - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#ifndef __ASM_ARCH_MSM_TIMEX_H -#define __ASM_ARCH_MSM_TIMEX_H - -#define CLOCK_TICK_RATE 1000000 - -#endif -- cgit v1.2.3 From 52b52b4681df8bad450692cf3fa8a61ca1e1599a Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Fri, 21 Jun 2013 12:17:37 -0700 Subject: ARM: msm: Remove pen_release usage pen_release is no longer required as the synchronization is now managed by generic arm code. This is done as suggested in https://lkml.org/lkml/2013/6/4/184 Cc: Russell King Signed-off-by: Rohit Vaswani Signed-off-by: Stephen Boyd Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/headsmp.S | 39 --------------------------------------- arch/arm/mach-msm/hotplug.c | 31 ++++--------------------------- arch/arm/mach-msm/platsmp.c | 37 +++---------------------------------- 4 files changed, 8 insertions(+), 101 deletions(-) delete mode 100644 arch/arm/mach-msm/headsmp.S (limited to 'arch/arm/mach-msm') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8e307a10d3c3..721f27f50d96 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S deleted file mode 100644 index 6c62c3f82fe6..000000000000 --- a/arch/arm/mach-msm/headsmp.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * linux/arch/arm/mach-realview/headsmp.S - * - * Copyright (c) 2003 ARM Limited - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include - -/* - * MSM specific entry point for secondary CPUs. This provides - * a "holding pen" into which all secondary cores are held until we're - * ready for them to initialise. - */ -ENTRY(msm_secondary_startup) - mrc p15, 0, r0, c0, c0, 5 - and r0, r0, #15 - adr r4, 1f - ldmia r4, {r5, r6} - sub r4, r4, r5 - add r6, r6, r4 -pen: ldr r7, [r6] - cmp r7, r0 - bne pen - - /* - * we've been released from the holding pen: secondary_stack - * should now contain the SVC stack for this core - */ - b secondary_startup -ENDPROC(msm_secondary_startup) - - .align -1: .long . - .long pen_release diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c index 326a87261f9a..cea80fc6e48e 100644 --- a/arch/arm/mach-msm/hotplug.c +++ b/arch/arm/mach-msm/hotplug.c @@ -24,33 +24,10 @@ static inline void cpu_leave_lowpower(void) static inline void platform_do_lowpower(unsigned int cpu) { - /* Just enter wfi for now. TODO: Properly shut off the cpu. */ - for (;;) { - /* - * here's the WFI - */ - asm("wfi" - : - : - : "memory", "cc"); - - if (pen_release == cpu_logical_map(cpu)) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else - */ - pr_debug("CPU%u: spurious wakeup call\n", cpu); - } + asm("wfi" + : + : + : "memory", "cc"); } /* diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index f10a1f58fde9..3721b31ef6ae 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -12,13 +12,10 @@ #include #include #include -#include #include #include -#include #include -#include #include #include "scm-boot.h" @@ -28,7 +25,7 @@ #define SCSS_CPU1CORE_RESET 0xD80 #define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 -extern void msm_secondary_startup(void); +extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); @@ -40,13 +37,6 @@ static inline int get_core_count(void) static void msm_secondary_init(unsigned int cpu) { - /* - * let the primary processor know we're out of the - * pen, then head off into the C entry point - */ - pen_release = -1; - smp_wmb(); - /* * Synchronise with the boot thread. */ @@ -57,7 +47,7 @@ static void msm_secondary_init(unsigned int cpu) static void prepare_cold_cpu(unsigned int cpu) { int ret; - ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup), + ret = scm_set_boot_addr(virt_to_phys(secondary_startup), SCM_FLAG_COLDBOOT_CPU1); if (ret == 0) { void __iomem *sc1_base_ptr; @@ -75,7 +65,6 @@ static void prepare_cold_cpu(unsigned int cpu) static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) { - unsigned long timeout; static int cold_boot_done; /* Only need to bring cpu out of reset this way once */ @@ -90,17 +79,6 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) */ spin_lock(&boot_lock); - /* - * The secondary processor is waiting to be released from - * the holding pen - release it, then wait for it to flag - * that it has been released by resetting pen_release. - * - * Note that "pen_release" is the hardware CPU ID, whereas - * "cpu" is Linux's internal ID. - */ - pen_release = cpu_logical_map(cpu); - sync_cache_w(&pen_release); - /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, @@ -108,22 +86,13 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) */ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - timeout = jiffies + (1 * HZ); - while (time_before(jiffies, timeout)) { - smp_rmb(); - if (pen_release == -1) - break; - - udelay(10); - } - /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); - return pen_release != -1 ? -ENOSYS : 0; + return 0; } /* -- cgit v1.2.3 From 6a032dba7d2329084dca41cc8d82c0cda13103ef Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 31 Jan 2014 13:48:29 -0600 Subject: ARM: msm: kill off hotplug.c Right now hotplug.c only really implements msm_cpu_die as a wfi. Just move that implementation into platsmp.c. At the same time we use the existing wfi() instead of inline asm. Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Makefile | 1 - arch/arm/mach-msm/common.h | 1 - arch/arm/mach-msm/hotplug.c | 51 --------------------------------------------- arch/arm/mach-msm/platsmp.c | 7 +++++++ 4 files changed, 7 insertions(+), 53 deletions(-) delete mode 100644 arch/arm/mach-msm/hotplug.c (limited to 'arch/arm/mach-msm') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 721f27f50d96..8327f603df4c 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h index 33c7725adae2..0a4899b7d85c 100644 --- a/arch/arm/mach-msm/common.h +++ b/arch/arm/mach-msm/common.h @@ -24,7 +24,6 @@ extern void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size, unsigned int mtype, void *caller); extern struct smp_operations msm_smp_ops; -extern void msm_cpu_die(unsigned int cpu); struct msm_mmc_platform_data; diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c deleted file mode 100644 index cea80fc6e48e..000000000000 --- a/arch/arm/mach-msm/hotplug.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include - -#include - -#include "common.h" - -static inline void cpu_enter_lowpower(void) -{ -} - -static inline void cpu_leave_lowpower(void) -{ -} - -static inline void platform_do_lowpower(unsigned int cpu) -{ - asm("wfi" - : - : - : "memory", "cc"); -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void __ref msm_cpu_die(unsigned int cpu) -{ - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); -} diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c index 3721b31ef6ae..251a91eb102a 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-msm/platsmp.c @@ -29,6 +29,13 @@ extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); +#ifdef CONFIG_HOTPLUG_CPU +static void __ref msm_cpu_die(unsigned int cpu) +{ + wfi(); +} +#endif + static inline int get_core_count(void) { /* 1 + the PART[1:0] field of MIDR */ -- cgit v1.2.3 From 3f8e8cee2f4bd02367583cc2d143887d1f49fd6c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 29 Jan 2014 16:17:30 -0600 Subject: clocksource: qcom: Move clocksource code out of mach-msm We intend to share the clocksource code for MSM platforms between legacy and multiplatform supported qcom SoCs. Acked-by: Olof Johansson Signed-off-by: Kumar Gala --- arch/arm/mach-msm/Kconfig | 13 +- arch/arm/mach-msm/Makefile | 1 - arch/arm/mach-msm/timer.c | 333 --------------------------------------- drivers/clocksource/Kconfig | 3 + drivers/clocksource/Makefile | 1 + drivers/clocksource/qcom-timer.c | 329 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 338 insertions(+), 342 deletions(-) delete mode 100644 arch/arm/mach-msm/timer.c create mode 100644 drivers/clocksource/qcom-timer.c (limited to 'arch/arm/mach-msm') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9625cf378931..3c4eca71f976 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -21,7 +21,7 @@ config ARCH_MSM8X60 select CPU_V7 select HAVE_SMP select MSM_SCM if SMP - select MSM_TIMER + select CLKSRC_QCOM config ARCH_MSM8960 bool "Enable support for MSM8960" @@ -29,7 +29,7 @@ config ARCH_MSM8960 select CPU_V7 select HAVE_SMP select MSM_SCM if SMP - select MSM_TIMER + select CLKSRC_QCOM config ARCH_MSM8974 bool "Enable support for MSM8974" @@ -54,7 +54,7 @@ config ARCH_MSM7X00A select MACH_TROUT if !MACH_HALIBUT select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_SMD_PKG3 config ARCH_MSM7X30 @@ -66,7 +66,7 @@ config ARCH_MSM7X30 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC config ARCH_QSD8X50 @@ -78,7 +78,7 @@ config ARCH_QSD8X50 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC endchoice @@ -153,7 +153,4 @@ config MSM_GPIOMUX config MSM_SCM bool -config MSM_TIMER - bool - endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8327f603df4c..04b1bee941f5 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_MSM_TIMER) += timer.o obj-$(CONFIG_MSM_PROC_COMM) += clock.o obj-$(CONFIG_MSM_VIC) += irq-vic.o diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c deleted file mode 100644 index fd1644987534..000000000000 --- a/arch/arm/mach-msm/timer.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "common.h" - -#define TIMER_MATCH_VAL 0x0000 -#define TIMER_COUNT_VAL 0x0004 -#define TIMER_ENABLE 0x0008 -#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) -#define TIMER_ENABLE_EN BIT(0) -#define TIMER_CLEAR 0x000C -#define DGT_CLK_CTL 0x10 -#define DGT_CLK_CTL_DIV_4 0x3 -#define TIMER_STS_GPT0_CLR_PEND BIT(10) - -#define GPT_HZ 32768 - -#define MSM_DGT_SHIFT 5 - -static void __iomem *event_base; -static void __iomem *sts_base; - -static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - /* Stop the timer tick */ - if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { - u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); - ctrl &= ~TIMER_ENABLE_EN; - writel_relaxed(ctrl, event_base + TIMER_ENABLE); - } - evt->event_handler(evt); - return IRQ_HANDLED; -} - -static int msm_timer_set_next_event(unsigned long cycles, - struct clock_event_device *evt) -{ - u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); - - ctrl &= ~TIMER_ENABLE_EN; - writel_relaxed(ctrl, event_base + TIMER_ENABLE); - - writel_relaxed(ctrl, event_base + TIMER_CLEAR); - writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); - - if (sts_base) - while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND) - cpu_relax(); - - writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); - return 0; -} - -static void msm_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - u32 ctrl; - - ctrl = readl_relaxed(event_base + TIMER_ENABLE); - ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); - - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - break; - } - writel_relaxed(ctrl, event_base + TIMER_ENABLE); -} - -static struct clock_event_device __percpu *msm_evt; - -static void __iomem *source_base; - -static notrace cycle_t msm_read_timer_count(struct clocksource *cs) -{ - return readl_relaxed(source_base + TIMER_COUNT_VAL); -} - -static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) -{ - /* - * Shift timer count down by a constant due to unreliable lower bits - * on some targets. - */ - return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; -} - -static struct clocksource msm_clocksource = { - .name = "dg_timer", - .rating = 300, - .read = msm_read_timer_count, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int msm_timer_irq; -static int msm_timer_has_ppi; - -static int msm_local_timer_setup(struct clock_event_device *evt) -{ - int cpu = smp_processor_id(); - int err; - - evt->irq = msm_timer_irq; - evt->name = "msm_timer"; - evt->features = CLOCK_EVT_FEAT_ONESHOT; - evt->rating = 200; - evt->set_mode = msm_timer_set_mode; - evt->set_next_event = msm_timer_set_next_event; - evt->cpumask = cpumask_of(cpu); - - clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff); - - if (msm_timer_has_ppi) { - enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); - } else { - err = request_irq(evt->irq, msm_timer_interrupt, - IRQF_TIMER | IRQF_NOBALANCING | - IRQF_TRIGGER_RISING, "gp_timer", evt); - if (err) - pr_err("request_irq failed\n"); - } - - return 0; -} - -static void msm_local_timer_stop(struct clock_event_device *evt) -{ - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); - disable_percpu_irq(evt->irq); -} - -static int msm_timer_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - /* - * Grab cpu pointer in each case to avoid spurious - * preemptible warnings - */ - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_STARTING: - msm_local_timer_setup(this_cpu_ptr(msm_evt)); - break; - case CPU_DYING: - msm_local_timer_stop(this_cpu_ptr(msm_evt)); - break; - } - - return NOTIFY_OK; -} - -static struct notifier_block msm_timer_cpu_nb = { - .notifier_call = msm_timer_cpu_notify, -}; - -static u64 notrace msm_sched_clock_read(void) -{ - return msm_clocksource.read(&msm_clocksource); -} - -static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, - bool percpu) -{ - struct clocksource *cs = &msm_clocksource; - int res = 0; - - msm_timer_irq = irq; - msm_timer_has_ppi = percpu; - - msm_evt = alloc_percpu(struct clock_event_device); - if (!msm_evt) { - pr_err("memory allocation failed for clockevents\n"); - goto err; - } - - if (percpu) - res = request_percpu_irq(irq, msm_timer_interrupt, - "gp_timer", msm_evt); - - if (res) { - pr_err("request_percpu_irq failed\n"); - } else { - res = register_cpu_notifier(&msm_timer_cpu_nb); - if (res) { - free_percpu_irq(irq, msm_evt); - goto err; - } - - /* Immediately configure the timer on the boot CPU */ - msm_local_timer_setup(__this_cpu_ptr(msm_evt)); - } - -err: - writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); - res = clocksource_register_hz(cs, dgt_hz); - if (res) - pr_err("clocksource_register failed\n"); - sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); -} - -#ifdef CONFIG_OF -static void __init msm_dt_timer_init(struct device_node *np) -{ - u32 freq; - int irq; - struct resource res; - u32 percpu_offset; - void __iomem *base; - void __iomem *cpu0_base; - - base = of_iomap(np, 0); - if (!base) { - pr_err("Failed to map event base\n"); - return; - } - - /* We use GPT0 for the clockevent */ - irq = irq_of_parse_and_map(np, 1); - if (irq <= 0) { - pr_err("Can't get irq\n"); - return; - } - - /* We use CPU0's DGT for the clocksource */ - if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) - percpu_offset = 0; - - if (of_address_to_resource(np, 0, &res)) { - pr_err("Failed to parse DGT resource\n"); - return; - } - - cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res)); - if (!cpu0_base) { - pr_err("Failed to map source base\n"); - return; - } - - if (of_property_read_u32(np, "clock-frequency", &freq)) { - pr_err("Unknown frequency\n"); - return; - } - - event_base = base + 0x4; - sts_base = base + 0x88; - source_base = cpu0_base + 0x24; - freq /= 4; - writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); - - msm_timer_init(freq, 32, irq, !!percpu_offset); -} -CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); -CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); -#endif - -static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, - u32 sts) -{ - void __iomem *base; - - base = ioremap(addr, SZ_256); - if (!base) { - pr_err("Failed to map timer base\n"); - return -ENOMEM; - } - event_base = base + event; - source_base = base + source; - if (sts) - sts_base = base + sts; - - return 0; -} - -void __init msm7x01_timer_init(void) -{ - struct clocksource *cs = &msm_clocksource; - - if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0)) - return; - cs->read = msm_read_timer_count_shift; - cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); - /* 600 KHz */ - msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7, - false); -} - -void __init msm7x30_timer_init(void) -{ - if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80)) - return; - msm_timer_init(24576000 / 4, 32, 1, false); -} - -void __init qsd8x50_timer_init(void) -{ - if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34)) - return; - msm_timer_init(19200000 / 4, 32, 7, false); -} diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cd6950fd8caf..6510ec4f45ff 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -140,3 +140,6 @@ config VF_PIT_TIMER bool help Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. + +config CLKSRC_QCOM + bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index c7ca50a9c232..2e0c0cc0a014 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o +obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c new file mode 100644 index 000000000000..dca829ec859b --- /dev/null +++ b/drivers/clocksource/qcom-timer.c @@ -0,0 +1,329 @@ +/* + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2012,2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMER_MATCH_VAL 0x0000 +#define TIMER_COUNT_VAL 0x0004 +#define TIMER_ENABLE 0x0008 +#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) +#define TIMER_ENABLE_EN BIT(0) +#define TIMER_CLEAR 0x000C +#define DGT_CLK_CTL 0x10 +#define DGT_CLK_CTL_DIV_4 0x3 +#define TIMER_STS_GPT0_CLR_PEND BIT(10) + +#define GPT_HZ 32768 + +#define MSM_DGT_SHIFT 5 + +static void __iomem *event_base; +static void __iomem *sts_base; + +static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + /* Stop the timer tick */ + if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { + u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); + ctrl &= ~TIMER_ENABLE_EN; + writel_relaxed(ctrl, event_base + TIMER_ENABLE); + } + evt->event_handler(evt); + return IRQ_HANDLED; +} + +static int msm_timer_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); + + ctrl &= ~TIMER_ENABLE_EN; + writel_relaxed(ctrl, event_base + TIMER_ENABLE); + + writel_relaxed(ctrl, event_base + TIMER_CLEAR); + writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); + + if (sts_base) + while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND) + cpu_relax(); + + writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); + return 0; +} + +static void msm_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + u32 ctrl; + + ctrl = readl_relaxed(event_base + TIMER_ENABLE); + ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); + + switch (mode) { + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Timer is enabled in set_next_event */ + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + break; + } + writel_relaxed(ctrl, event_base + TIMER_ENABLE); +} + +static struct clock_event_device __percpu *msm_evt; + +static void __iomem *source_base; + +static notrace cycle_t msm_read_timer_count(struct clocksource *cs) +{ + return readl_relaxed(source_base + TIMER_COUNT_VAL); +} + +static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) +{ + /* + * Shift timer count down by a constant due to unreliable lower bits + * on some targets. + */ + return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; +} + +static struct clocksource msm_clocksource = { + .name = "dg_timer", + .rating = 300, + .read = msm_read_timer_count, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int msm_timer_irq; +static int msm_timer_has_ppi; + +static int msm_local_timer_setup(struct clock_event_device *evt) +{ + int cpu = smp_processor_id(); + int err; + + evt->irq = msm_timer_irq; + evt->name = "msm_timer"; + evt->features = CLOCK_EVT_FEAT_ONESHOT; + evt->rating = 200; + evt->set_mode = msm_timer_set_mode; + evt->set_next_event = msm_timer_set_next_event; + evt->cpumask = cpumask_of(cpu); + + clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff); + + if (msm_timer_has_ppi) { + enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); + } else { + err = request_irq(evt->irq, msm_timer_interrupt, + IRQF_TIMER | IRQF_NOBALANCING | + IRQF_TRIGGER_RISING, "gp_timer", evt); + if (err) + pr_err("request_irq failed\n"); + } + + return 0; +} + +static void msm_local_timer_stop(struct clock_event_device *evt) +{ + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + disable_percpu_irq(evt->irq); +} + +static int msm_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + msm_local_timer_setup(this_cpu_ptr(msm_evt)); + break; + case CPU_DYING: + msm_local_timer_stop(this_cpu_ptr(msm_evt)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block msm_timer_cpu_nb = { + .notifier_call = msm_timer_cpu_notify, +}; + +static u64 notrace msm_sched_clock_read(void) +{ + return msm_clocksource.read(&msm_clocksource); +} + +static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, + bool percpu) +{ + struct clocksource *cs = &msm_clocksource; + int res = 0; + + msm_timer_irq = irq; + msm_timer_has_ppi = percpu; + + msm_evt = alloc_percpu(struct clock_event_device); + if (!msm_evt) { + pr_err("memory allocation failed for clockevents\n"); + goto err; + } + + if (percpu) + res = request_percpu_irq(irq, msm_timer_interrupt, + "gp_timer", msm_evt); + + if (res) { + pr_err("request_percpu_irq failed\n"); + } else { + res = register_cpu_notifier(&msm_timer_cpu_nb); + if (res) { + free_percpu_irq(irq, msm_evt); + goto err; + } + + /* Immediately configure the timer on the boot CPU */ + msm_local_timer_setup(__this_cpu_ptr(msm_evt)); + } + +err: + writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); + res = clocksource_register_hz(cs, dgt_hz); + if (res) + pr_err("clocksource_register failed\n"); + sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); +} + +#ifdef CONFIG_OF +static void __init msm_dt_timer_init(struct device_node *np) +{ + u32 freq; + int irq; + struct resource res; + u32 percpu_offset; + void __iomem *base; + void __iomem *cpu0_base; + + base = of_iomap(np, 0); + if (!base) { + pr_err("Failed to map event base\n"); + return; + } + + /* We use GPT0 for the clockevent */ + irq = irq_of_parse_and_map(np, 1); + if (irq <= 0) { + pr_err("Can't get irq\n"); + return; + } + + /* We use CPU0's DGT for the clocksource */ + if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) + percpu_offset = 0; + + if (of_address_to_resource(np, 0, &res)) { + pr_err("Failed to parse DGT resource\n"); + return; + } + + cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res)); + if (!cpu0_base) { + pr_err("Failed to map source base\n"); + return; + } + + if (of_property_read_u32(np, "clock-frequency", &freq)) { + pr_err("Unknown frequency\n"); + return; + } + + event_base = base + 0x4; + sts_base = base + 0x88; + source_base = cpu0_base + 0x24; + freq /= 4; + writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); + + msm_timer_init(freq, 32, irq, !!percpu_offset); +} +CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +#endif + +static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, + u32 sts) +{ + void __iomem *base; + + base = ioremap(addr, SZ_256); + if (!base) { + pr_err("Failed to map timer base\n"); + return -ENOMEM; + } + event_base = base + event; + source_base = base + source; + if (sts) + sts_base = base + sts; + + return 0; +} + +void __init msm7x01_timer_init(void) +{ + struct clocksource *cs = &msm_clocksource; + + if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0)) + return; + cs->read = msm_read_timer_count_shift; + cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); + /* 600 KHz */ + msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7, + false); +} + +void __init msm7x30_timer_init(void) +{ + if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80)) + return; + msm_timer_init(24576000 / 4, 32, 1, false); +} + +void __init qsd8x50_timer_init(void) +{ + if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34)) + return; + msm_timer_init(19200000 / 4, 32, 7, false); +} -- cgit v1.2.3 From 8fc1b0f87d9fcc7f05873c70b3003328c3d7defa Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 21 Jan 2014 17:14:10 -0600 Subject: ARM: qcom: Split Qualcomm support into legacy and multiplatform Introduce a new mach-qcom that will support SoCs that intend to be multiplatform compatible while keeping mach-msm to legacy SoC/board support that will not transition over to multiplatform. As part of this, we move support for MSM8X60, MSM8960 and MSM8974 over to mach-qcom. Signed-off-by: Kumar Gala --- MAINTAINERS | 8 ++ arch/arm/Kconfig | 7 +- arch/arm/Kconfig.debug | 2 +- arch/arm/Makefile | 1 + arch/arm/boot/dts/Makefile | 6 +- arch/arm/mach-msm/Kconfig | 45 +------ arch/arm/mach-msm/Makefile | 6 - arch/arm/mach-msm/board-dt.c | 41 ------ arch/arm/mach-msm/platsmp.c | 137 ------------------- arch/arm/mach-msm/scm-boot.c | 39 ------ arch/arm/mach-msm/scm-boot.h | 22 ---- arch/arm/mach-msm/scm.c | 299 ------------------------------------------ arch/arm/mach-msm/scm.h | 25 ---- arch/arm/mach-qcom/Kconfig | 33 +++++ arch/arm/mach-qcom/Makefile | 5 + arch/arm/mach-qcom/board.c | 40 ++++++ arch/arm/mach-qcom/platsmp.c | 137 +++++++++++++++++++ arch/arm/mach-qcom/scm-boot.c | 39 ++++++ arch/arm/mach-qcom/scm-boot.h | 22 ++++ arch/arm/mach-qcom/scm.c | 299 ++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-qcom/scm.h | 25 ++++ 21 files changed, 619 insertions(+), 619 deletions(-) delete mode 100644 arch/arm/mach-msm/board-dt.c delete mode 100644 arch/arm/mach-msm/platsmp.c delete mode 100644 arch/arm/mach-msm/scm-boot.c delete mode 100644 arch/arm/mach-msm/scm-boot.h delete mode 100644 arch/arm/mach-msm/scm.c delete mode 100644 arch/arm/mach-msm/scm.h create mode 100644 arch/arm/mach-qcom/Kconfig create mode 100644 arch/arm/mach-qcom/Makefile create mode 100644 arch/arm/mach-qcom/board.c create mode 100644 arch/arm/mach-qcom/platsmp.c create mode 100644 arch/arm/mach-qcom/scm-boot.c create mode 100644 arch/arm/mach-qcom/scm-boot.h create mode 100644 arch/arm/mach-qcom/scm.c create mode 100644 arch/arm/mach-qcom/scm.h (limited to 'arch/arm/mach-msm') diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..402be6009e26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1167,6 +1167,14 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.arm.linux.org.uk/ S: Maintained +ARM/QUALCOMM SUPPORT +M: Kumar Gala +M: David Brown +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: arch/arm/mach-qcom/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git + ARM/RADISYS ENP2611 MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..f093f2030c1c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -657,9 +657,8 @@ config ARCH_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. -config ARCH_MSM_NODT - bool "Qualcomm MSM" - select ARCH_MSM +config ARCH_MSM + bool "Qualcomm MSM (non-multiplatform)" select ARCH_REQUIRE_GPIOLIB select COMMON_CLK select GENERIC_CLOCKEVENTS @@ -1005,6 +1004,8 @@ source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-mmp/Kconfig" +source "arch/arm/mach-qcom/Kconfig" + source "arch/arm/mach-realview/Kconfig" source "arch/arm/mach-rockchip/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0531da8e5216..4491c7b05275 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -956,7 +956,7 @@ config DEBUG_STI_UART config DEBUG_MSM_UART bool - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM config DEBUG_LL_INCLUDE string diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 08a9ef58d9c3..51e5bede657f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -180,6 +180,7 @@ machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2 machine-$(CONFIG_ARCH_ORION5X) += orion5x machine-$(CONFIG_ARCH_PICOXCELL) += picoxcell machine-$(CONFIG_ARCH_PXA) += pxa +machine-$(CONFIG_ARCH_QCOM) += qcom machine-$(CONFIG_ARCH_REALVIEW) += realview machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip machine-$(CONFIG_ARCH_RPC) += rpc diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..c9eaf1f87041 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -118,9 +118,6 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \ kirkwood-ts219-6282.dtb dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb -dtb-$(CONFIG_ARCH_MSM) += qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ armada-370-mirabox.dtb \ armada-370-netgear-rn102.dtb \ @@ -232,6 +229,9 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ dra7-evm.dtb dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \ ste-hrefprev60-stuib.dtb \ ste-hrefprev60-tvk.dtb \ diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 3c4eca71f976..a7f959e58c3d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,50 +1,9 @@ -config ARCH_MSM - bool - -config ARCH_MSM_DT - bool "Qualcomm MSM DT Support" if ARCH_MULTI_V7 - select ARCH_MSM - select ARCH_REQUIRE_GPIOLIB - select CLKSRC_OF - select GENERIC_CLOCKEVENTS - help - Support for Qualcomm's devicetree based MSM systems. - if ARCH_MSM -menu "Qualcomm MSM SoC Selection" - depends on ARCH_MSM_DT - -config ARCH_MSM8X60 - bool "Enable support for MSM8X60" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select CLKSRC_QCOM - -config ARCH_MSM8960 - bool "Enable support for MSM8960" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select CLKSRC_QCOM - -config ARCH_MSM8974 - bool "Enable support for MSM8974" - select ARM_GIC - select CPU_V7 - select HAVE_ARM_ARCH_TIMER - select HAVE_SMP - select MSM_SCM if SMP - -endmenu - choice prompt "Qualcomm MSM SoC Type" default ARCH_MSM7X00A - depends on ARCH_MSM_NODT + depends on ARCH_MSM config ARCH_MSM7X00A bool "MSM7x00A / MSM7x01A" @@ -99,7 +58,7 @@ config MSM_VIC bool menu "Qualcomm MSM Board Type" - depends on ARCH_MSM_NODT + depends on ARCH_MSM config MACH_HALIBUT depends on ARCH_MSM diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 04b1bee941f5..27c078a568df 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -13,17 +13,11 @@ obj-$(CONFIG_ARCH_QSD8X50) += dma.o io.o obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o obj-$(CONFIG_MSM_SMD) += last_radio_log.o -obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o - -CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) - -obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o -obj-$(CONFIG_ARCH_MSM_DT) += board-dt.o obj-$(CONFIG_MSM_GPIOMUX) += gpiomux.o obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c deleted file mode 100644 index 1f11d93e700e..000000000000 --- a/arch/arm/mach-msm/board-dt.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2010-2012,2013 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ - -#include -#include -#include - -#include -#include - -#include "common.h" - -static const char * const msm_dt_match[] __initconst = { - "qcom,msm8660-fluid", - "qcom,msm8660-surf", - "qcom,msm8960-cdp", - NULL -}; - -static const char * const apq8074_dt_match[] __initconst = { - "qcom,apq8074-dragonboard", - NULL -}; - -DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") - .smp = smp_ops(msm_smp_ops), - .dt_compat = msm_dt_match, -MACHINE_END - -DT_MACHINE_START(APQ_DT, "Qualcomm MSM (Flattened Device Tree)") - .dt_compat = apq8074_dt_match, -MACHINE_END diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c deleted file mode 100644 index 251a91eb102a..000000000000 --- a/arch/arm/mach-msm/platsmp.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scm-boot.h" -#include "common.h" - -#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 -#define SCSS_CPU1CORE_RESET 0xD80 -#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 - -extern void secondary_startup(void); - -static DEFINE_SPINLOCK(boot_lock); - -#ifdef CONFIG_HOTPLUG_CPU -static void __ref msm_cpu_die(unsigned int cpu) -{ - wfi(); -} -#endif - -static inline int get_core_count(void) -{ - /* 1 + the PART[1:0] field of MIDR */ - return ((read_cpuid_id() >> 4) & 3) + 1; -} - -static void msm_secondary_init(unsigned int cpu) -{ - /* - * Synchronise with the boot thread. - */ - spin_lock(&boot_lock); - spin_unlock(&boot_lock); -} - -static void prepare_cold_cpu(unsigned int cpu) -{ - int ret; - ret = scm_set_boot_addr(virt_to_phys(secondary_startup), - SCM_FLAG_COLDBOOT_CPU1); - if (ret == 0) { - void __iomem *sc1_base_ptr; - sc1_base_ptr = ioremap_nocache(0x00902000, SZ_4K*2); - if (sc1_base_ptr) { - writel(0, sc1_base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL); - writel(0, sc1_base_ptr + SCSS_CPU1CORE_RESET); - writel(3, sc1_base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP); - iounmap(sc1_base_ptr); - } - } else - printk(KERN_DEBUG "Failed to set secondary core boot " - "address\n"); -} - -static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) -{ - static int cold_boot_done; - - /* Only need to bring cpu out of reset this way once */ - if (cold_boot_done == false) { - prepare_cold_cpu(cpu); - cold_boot_done = true; - } - - /* - * set synchronisation state between this boot processor - * and the secondary one - */ - spin_lock(&boot_lock); - - /* - * Send the secondary CPU a soft interrupt, thereby causing - * the boot monitor to read the system wide flags register, - * and branch to the address found there. - */ - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - - /* - * now the secondary core is starting up let it run its - * calibrations, then wait for it to finish - */ - spin_unlock(&boot_lock); - - return 0; -} - -/* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. The msm8x60 - * does not support the ARM SCU, so just set the possible cpu mask to - * NR_CPUS. - */ -static void __init msm_smp_init_cpus(void) -{ - unsigned int i, ncores = get_core_count(); - - if (ncores > nr_cpu_ids) { - pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", - ncores, nr_cpu_ids); - ncores = nr_cpu_ids; - } - - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); -} - -static void __init msm_smp_prepare_cpus(unsigned int max_cpus) -{ -} - -struct smp_operations msm_smp_ops __initdata = { - .smp_init_cpus = msm_smp_init_cpus, - .smp_prepare_cpus = msm_smp_prepare_cpus, - .smp_secondary_init = msm_secondary_init, - .smp_boot_secondary = msm_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = msm_cpu_die, -#endif -}; diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-msm/scm-boot.c deleted file mode 100644 index 45cee3e469a5..000000000000 --- a/arch/arm/mach-msm/scm-boot.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include - -#include "scm.h" -#include "scm-boot.h" - -/* - * Set the cold/warm boot address for one of the CPU cores. - */ -int scm_set_boot_addr(phys_addr_t addr, int flags) -{ - struct { - unsigned int flags; - phys_addr_t addr; - } cmd; - - cmd.addr = addr; - cmd.flags = flags; - return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR, - &cmd, sizeof(cmd), NULL, 0); -} -EXPORT_SYMBOL(scm_set_boot_addr); diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h deleted file mode 100644 index 7be32ff5d687..000000000000 --- a/arch/arm/mach-msm/scm-boot.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ -#ifndef __MACH_SCM_BOOT_H -#define __MACH_SCM_BOOT_H - -#define SCM_BOOT_ADDR 0x1 -#define SCM_FLAG_COLDBOOT_CPU1 0x1 -#define SCM_FLAG_WARMBOOT_CPU1 0x2 -#define SCM_FLAG_WARMBOOT_CPU0 0x4 - -int scm_set_boot_addr(phys_addr_t addr, int flags); - -#endif diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c deleted file mode 100644 index c536fd6bf827..000000000000 --- a/arch/arm/mach-msm/scm.c +++ /dev/null @@ -1,299 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "scm.h" - -/* Cache line size for msm8x60 */ -#define CACHELINESIZE 32 - -#define SCM_ENOMEM -5 -#define SCM_EOPNOTSUPP -4 -#define SCM_EINVAL_ADDR -3 -#define SCM_EINVAL_ARG -2 -#define SCM_ERROR -1 -#define SCM_INTERRUPTED 1 - -static DEFINE_MUTEX(scm_lock); - -/** - * struct scm_command - one SCM command buffer - * @len: total available memory for command and response - * @buf_offset: start of command buffer - * @resp_hdr_offset: start of response buffer - * @id: command to be executed - * @buf: buffer returned from scm_get_command_buffer() - * - * An SCM command is laid out in memory as follows: - * - * ------------------- <--- struct scm_command - * | command header | - * ------------------- <--- scm_get_command_buffer() - * | command buffer | - * ------------------- <--- struct scm_response and - * | response header | scm_command_to_response() - * ------------------- <--- scm_get_response_buffer() - * | response buffer | - * ------------------- - * - * There can be arbitrary padding between the headers and buffers so - * you should always use the appropriate scm_get_*_buffer() routines - * to access the buffers in a safe manner. - */ -struct scm_command { - u32 len; - u32 buf_offset; - u32 resp_hdr_offset; - u32 id; - u32 buf[0]; -}; - -/** - * struct scm_response - one SCM response buffer - * @len: total available memory for response - * @buf_offset: start of response data relative to start of scm_response - * @is_complete: indicates if the command has finished processing - */ -struct scm_response { - u32 len; - u32 buf_offset; - u32 is_complete; -}; - -/** - * alloc_scm_command() - Allocate an SCM command - * @cmd_size: size of the command buffer - * @resp_size: size of the response buffer - * - * Allocate an SCM command, including enough room for the command - * and response headers as well as the command and response buffers. - * - * Returns a valid &scm_command on success or %NULL if the allocation fails. - */ -static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size) -{ - struct scm_command *cmd; - size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size + - resp_size; - - cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); - if (cmd) { - cmd->len = len; - cmd->buf_offset = offsetof(struct scm_command, buf); - cmd->resp_hdr_offset = cmd->buf_offset + cmd_size; - } - return cmd; -} - -/** - * free_scm_command() - Free an SCM command - * @cmd: command to free - * - * Free an SCM command. - */ -static inline void free_scm_command(struct scm_command *cmd) -{ - kfree(cmd); -} - -/** - * scm_command_to_response() - Get a pointer to a scm_response - * @cmd: command - * - * Returns a pointer to a response for a command. - */ -static inline struct scm_response *scm_command_to_response( - const struct scm_command *cmd) -{ - return (void *)cmd + cmd->resp_hdr_offset; -} - -/** - * scm_get_command_buffer() - Get a pointer to a command buffer - * @cmd: command - * - * Returns a pointer to the command buffer of a command. - */ -static inline void *scm_get_command_buffer(const struct scm_command *cmd) -{ - return (void *)cmd->buf; -} - -/** - * scm_get_response_buffer() - Get a pointer to a response buffer - * @rsp: response - * - * Returns a pointer to a response buffer of a response. - */ -static inline void *scm_get_response_buffer(const struct scm_response *rsp) -{ - return (void *)rsp + rsp->buf_offset; -} - -static int scm_remap_error(int err) -{ - switch (err) { - case SCM_ERROR: - return -EIO; - case SCM_EINVAL_ADDR: - case SCM_EINVAL_ARG: - return -EINVAL; - case SCM_EOPNOTSUPP: - return -EOPNOTSUPP; - case SCM_ENOMEM: - return -ENOMEM; - } - return -EINVAL; -} - -static u32 smc(u32 cmd_addr) -{ - int context_id; - register u32 r0 asm("r0") = 1; - register u32 r1 asm("r1") = (u32)&context_id; - register u32 r2 asm("r2") = cmd_addr; - do { - asm volatile( - __asmeq("%0", "r0") - __asmeq("%1", "r0") - __asmeq("%2", "r1") - __asmeq("%3", "r2") -#ifdef REQUIRES_SEC - ".arch_extension sec\n" -#endif - "smc #0 @ switch to secure world\n" - : "=r" (r0) - : "r" (r0), "r" (r1), "r" (r2) - : "r3"); - } while (r0 == SCM_INTERRUPTED); - - return r0; -} - -static int __scm_call(const struct scm_command *cmd) -{ - int ret; - u32 cmd_addr = virt_to_phys(cmd); - - /* - * Flush the entire cache here so callers don't have to remember - * to flush the cache when passing physical addresses to the secure - * side in the buffer. - */ - flush_cache_all(); - ret = smc(cmd_addr); - if (ret < 0) - ret = scm_remap_error(ret); - - return ret; -} - -/** - * scm_call() - Send an SCM command - * @svc_id: service identifier - * @cmd_id: command identifier - * @cmd_buf: command buffer - * @cmd_len: length of the command buffer - * @resp_buf: response buffer - * @resp_len: length of the response buffer - * - * Sends a command to the SCM and waits for the command to finish processing. - */ -int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, - void *resp_buf, size_t resp_len) -{ - int ret; - struct scm_command *cmd; - struct scm_response *rsp; - - cmd = alloc_scm_command(cmd_len, resp_len); - if (!cmd) - return -ENOMEM; - - cmd->id = (svc_id << 10) | cmd_id; - if (cmd_buf) - memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len); - - mutex_lock(&scm_lock); - ret = __scm_call(cmd); - mutex_unlock(&scm_lock); - if (ret) - goto out; - - rsp = scm_command_to_response(cmd); - do { - u32 start = (u32)rsp; - u32 end = (u32)scm_get_response_buffer(rsp) + resp_len; - start &= ~(CACHELINESIZE - 1); - while (start < end) { - asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) - : "memory"); - start += CACHELINESIZE; - } - } while (!rsp->is_complete); - - if (resp_buf) - memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len); -out: - free_scm_command(cmd); - return ret; -} -EXPORT_SYMBOL(scm_call); - -u32 scm_get_version(void) -{ - int context_id; - static u32 version = -1; - register u32 r0 asm("r0"); - register u32 r1 asm("r1"); - - if (version != -1) - return version; - - mutex_lock(&scm_lock); - - r0 = 0x1 << 8; - r1 = (u32)&context_id; - do { - asm volatile( - __asmeq("%0", "r0") - __asmeq("%1", "r1") - __asmeq("%2", "r0") - __asmeq("%3", "r1") -#ifdef REQUIRES_SEC - ".arch_extension sec\n" -#endif - "smc #0 @ switch to secure world\n" - : "=r" (r0), "=r" (r1) - : "r" (r0), "r" (r1) - : "r2", "r3"); - } while (r0 == SCM_INTERRUPTED); - - version = r1; - mutex_unlock(&scm_lock); - - return version; -} -EXPORT_SYMBOL(scm_get_version); diff --git a/arch/arm/mach-msm/scm.h b/arch/arm/mach-msm/scm.h deleted file mode 100644 index 00b31ea58f29..000000000000 --- a/arch/arm/mach-msm/scm.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ -#ifndef __MACH_SCM_H -#define __MACH_SCM_H - -#define SCM_SVC_BOOT 0x1 -#define SCM_SVC_PIL 0x2 - -extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, - void *resp_buf, size_t resp_len); - -#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) - -extern u32 scm_get_version(void); - -#endif diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig new file mode 100644 index 000000000000..a028be234334 --- /dev/null +++ b/arch/arm/mach-qcom/Kconfig @@ -0,0 +1,33 @@ +config ARCH_QCOM + bool "Qualcomm Support" if ARCH_MULTI_V7 + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC + select CLKSRC_OF + select GENERIC_CLOCKEVENTS + select HAVE_SMP + select QCOM_SCM if SMP + help + Support for Qualcomm's devicetree based systems. + +if ARCH_QCOM + +menu "Qualcomm SoC Selection" + +config ARCH_MSM8X60 + bool "Enable support for MSM8X60" + select CLKSRC_QCOM + +config ARCH_MSM8960 + bool "Enable support for MSM8960" + select CLKSRC_QCOM + +config ARCH_MSM8974 + bool "Enable support for MSM8974" + select HAVE_ARM_ARCH_TIMER + +endmenu + +config QCOM_SCM + bool + +endif diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile new file mode 100644 index 000000000000..8f756ae1ae31 --- /dev/null +++ b/arch/arm/mach-qcom/Makefile @@ -0,0 +1,5 @@ +obj-y := board.o +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o + +CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) diff --git a/arch/arm/mach-qcom/board.c b/arch/arm/mach-qcom/board.c new file mode 100644 index 000000000000..4529f6b222d3 --- /dev/null +++ b/arch/arm/mach-qcom/board.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2010-2014 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#include +#include +#include + +#include +#include + +extern struct smp_operations msm_smp_ops; + +static const char * const qcom_dt_match[] __initconst = { + "qcom,msm8660-surf", + "qcom,msm8960-cdp", + NULL +}; + +static const char * const apq8074_dt_match[] __initconst = { + "qcom,apq8074-dragonboard", + NULL +}; + +DT_MACHINE_START(QCOM_DT, "Qualcomm (Flattened Device Tree)") + .smp = smp_ops(msm_smp_ops), + .dt_compat = qcom_dt_match, +MACHINE_END + +DT_MACHINE_START(APQ_DT, "Qualcomm (Flattened Device Tree)") + .dt_compat = apq8074_dt_match, +MACHINE_END diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c new file mode 100644 index 000000000000..67823a7bec0d --- /dev/null +++ b/arch/arm/mach-qcom/platsmp.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "scm-boot.h" + +#define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 +#define SCSS_CPU1CORE_RESET 0xD80 +#define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 + +extern void secondary_startup(void); + +static DEFINE_SPINLOCK(boot_lock); + +#ifdef CONFIG_HOTPLUG_CPU +static void __ref msm_cpu_die(unsigned int cpu) +{ + wfi(); +} +#endif + +static inline int get_core_count(void) +{ + /* 1 + the PART[1:0] field of MIDR */ + return ((read_cpuid_id() >> 4) & 3) + 1; +} + +static void msm_secondary_init(unsigned int cpu) +{ + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static void prepare_cold_cpu(unsigned int cpu) +{ + int ret; + ret = scm_set_boot_addr(virt_to_phys(secondary_startup), + SCM_FLAG_COLDBOOT_CPU1); + if (ret == 0) { + void __iomem *sc1_base_ptr; + sc1_base_ptr = ioremap_nocache(0x00902000, SZ_4K*2); + if (sc1_base_ptr) { + writel(0, sc1_base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL); + writel(0, sc1_base_ptr + SCSS_CPU1CORE_RESET); + writel(3, sc1_base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP); + iounmap(sc1_base_ptr); + } + } else + printk(KERN_DEBUG "Failed to set secondary core boot " + "address\n"); +} + +static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + static int cold_boot_done; + + /* Only need to bring cpu out of reset this way once */ + if (cold_boot_done == false) { + prepare_cold_cpu(cpu); + cold_boot_done = true; + } + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. The msm8x60 + * does not support the ARM SCU, so just set the possible cpu mask to + * NR_CPUS. + */ +static void __init msm_smp_init_cpus(void) +{ + unsigned int i, ncores = get_core_count(); + + if (ncores > nr_cpu_ids) { + pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", + ncores, nr_cpu_ids); + ncores = nr_cpu_ids; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +static void __init msm_smp_prepare_cpus(unsigned int max_cpus) +{ +} + +struct smp_operations msm_smp_ops __initdata = { + .smp_init_cpus = msm_smp_init_cpus, + .smp_prepare_cpus = msm_smp_prepare_cpus, + .smp_secondary_init = msm_secondary_init, + .smp_boot_secondary = msm_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = msm_cpu_die, +#endif +}; diff --git a/arch/arm/mach-qcom/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c new file mode 100644 index 000000000000..45cee3e469a5 --- /dev/null +++ b/arch/arm/mach-qcom/scm-boot.c @@ -0,0 +1,39 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +#include "scm.h" +#include "scm-boot.h" + +/* + * Set the cold/warm boot address for one of the CPU cores. + */ +int scm_set_boot_addr(phys_addr_t addr, int flags) +{ + struct { + unsigned int flags; + phys_addr_t addr; + } cmd; + + cmd.addr = addr; + cmd.flags = flags; + return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR, + &cmd, sizeof(cmd), NULL, 0); +} +EXPORT_SYMBOL(scm_set_boot_addr); diff --git a/arch/arm/mach-qcom/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h new file mode 100644 index 000000000000..7be32ff5d687 --- /dev/null +++ b/arch/arm/mach-qcom/scm-boot.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ +#ifndef __MACH_SCM_BOOT_H +#define __MACH_SCM_BOOT_H + +#define SCM_BOOT_ADDR 0x1 +#define SCM_FLAG_COLDBOOT_CPU1 0x1 +#define SCM_FLAG_WARMBOOT_CPU1 0x2 +#define SCM_FLAG_WARMBOOT_CPU0 0x4 + +int scm_set_boot_addr(phys_addr_t addr, int flags); + +#endif diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c new file mode 100644 index 000000000000..c536fd6bf827 --- /dev/null +++ b/arch/arm/mach-qcom/scm.c @@ -0,0 +1,299 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "scm.h" + +/* Cache line size for msm8x60 */ +#define CACHELINESIZE 32 + +#define SCM_ENOMEM -5 +#define SCM_EOPNOTSUPP -4 +#define SCM_EINVAL_ADDR -3 +#define SCM_EINVAL_ARG -2 +#define SCM_ERROR -1 +#define SCM_INTERRUPTED 1 + +static DEFINE_MUTEX(scm_lock); + +/** + * struct scm_command - one SCM command buffer + * @len: total available memory for command and response + * @buf_offset: start of command buffer + * @resp_hdr_offset: start of response buffer + * @id: command to be executed + * @buf: buffer returned from scm_get_command_buffer() + * + * An SCM command is laid out in memory as follows: + * + * ------------------- <--- struct scm_command + * | command header | + * ------------------- <--- scm_get_command_buffer() + * | command buffer | + * ------------------- <--- struct scm_response and + * | response header | scm_command_to_response() + * ------------------- <--- scm_get_response_buffer() + * | response buffer | + * ------------------- + * + * There can be arbitrary padding between the headers and buffers so + * you should always use the appropriate scm_get_*_buffer() routines + * to access the buffers in a safe manner. + */ +struct scm_command { + u32 len; + u32 buf_offset; + u32 resp_hdr_offset; + u32 id; + u32 buf[0]; +}; + +/** + * struct scm_response - one SCM response buffer + * @len: total available memory for response + * @buf_offset: start of response data relative to start of scm_response + * @is_complete: indicates if the command has finished processing + */ +struct scm_response { + u32 len; + u32 buf_offset; + u32 is_complete; +}; + +/** + * alloc_scm_command() - Allocate an SCM command + * @cmd_size: size of the command buffer + * @resp_size: size of the response buffer + * + * Allocate an SCM command, including enough room for the command + * and response headers as well as the command and response buffers. + * + * Returns a valid &scm_command on success or %NULL if the allocation fails. + */ +static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size) +{ + struct scm_command *cmd; + size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size + + resp_size; + + cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); + if (cmd) { + cmd->len = len; + cmd->buf_offset = offsetof(struct scm_command, buf); + cmd->resp_hdr_offset = cmd->buf_offset + cmd_size; + } + return cmd; +} + +/** + * free_scm_command() - Free an SCM command + * @cmd: command to free + * + * Free an SCM command. + */ +static inline void free_scm_command(struct scm_command *cmd) +{ + kfree(cmd); +} + +/** + * scm_command_to_response() - Get a pointer to a scm_response + * @cmd: command + * + * Returns a pointer to a response for a command. + */ +static inline struct scm_response *scm_command_to_response( + const struct scm_command *cmd) +{ + return (void *)cmd + cmd->resp_hdr_offset; +} + +/** + * scm_get_command_buffer() - Get a pointer to a command buffer + * @cmd: command + * + * Returns a pointer to the command buffer of a command. + */ +static inline void *scm_get_command_buffer(const struct scm_command *cmd) +{ + return (void *)cmd->buf; +} + +/** + * scm_get_response_buffer() - Get a pointer to a response buffer + * @rsp: response + * + * Returns a pointer to a response buffer of a response. + */ +static inline void *scm_get_response_buffer(const struct scm_response *rsp) +{ + return (void *)rsp + rsp->buf_offset; +} + +static int scm_remap_error(int err) +{ + switch (err) { + case SCM_ERROR: + return -EIO; + case SCM_EINVAL_ADDR: + case SCM_EINVAL_ARG: + return -EINVAL; + case SCM_EOPNOTSUPP: + return -EOPNOTSUPP; + case SCM_ENOMEM: + return -ENOMEM; + } + return -EINVAL; +} + +static u32 smc(u32 cmd_addr) +{ + int context_id; + register u32 r0 asm("r0") = 1; + register u32 r1 asm("r1") = (u32)&context_id; + register u32 r2 asm("r2") = cmd_addr; + do { + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r0") + __asmeq("%2", "r1") + __asmeq("%3", "r2") +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + : "=r" (r0) + : "r" (r0), "r" (r1), "r" (r2) + : "r3"); + } while (r0 == SCM_INTERRUPTED); + + return r0; +} + +static int __scm_call(const struct scm_command *cmd) +{ + int ret; + u32 cmd_addr = virt_to_phys(cmd); + + /* + * Flush the entire cache here so callers don't have to remember + * to flush the cache when passing physical addresses to the secure + * side in the buffer. + */ + flush_cache_all(); + ret = smc(cmd_addr); + if (ret < 0) + ret = scm_remap_error(ret); + + return ret; +} + +/** + * scm_call() - Send an SCM command + * @svc_id: service identifier + * @cmd_id: command identifier + * @cmd_buf: command buffer + * @cmd_len: length of the command buffer + * @resp_buf: response buffer + * @resp_len: length of the response buffer + * + * Sends a command to the SCM and waits for the command to finish processing. + */ +int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, + void *resp_buf, size_t resp_len) +{ + int ret; + struct scm_command *cmd; + struct scm_response *rsp; + + cmd = alloc_scm_command(cmd_len, resp_len); + if (!cmd) + return -ENOMEM; + + cmd->id = (svc_id << 10) | cmd_id; + if (cmd_buf) + memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len); + + mutex_lock(&scm_lock); + ret = __scm_call(cmd); + mutex_unlock(&scm_lock); + if (ret) + goto out; + + rsp = scm_command_to_response(cmd); + do { + u32 start = (u32)rsp; + u32 end = (u32)scm_get_response_buffer(rsp) + resp_len; + start &= ~(CACHELINESIZE - 1); + while (start < end) { + asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) + : "memory"); + start += CACHELINESIZE; + } + } while (!rsp->is_complete); + + if (resp_buf) + memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len); +out: + free_scm_command(cmd); + return ret; +} +EXPORT_SYMBOL(scm_call); + +u32 scm_get_version(void) +{ + int context_id; + static u32 version = -1; + register u32 r0 asm("r0"); + register u32 r1 asm("r1"); + + if (version != -1) + return version; + + mutex_lock(&scm_lock); + + r0 = 0x1 << 8; + r1 = (u32)&context_id; + do { + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r1") + __asmeq("%2", "r0") + __asmeq("%3", "r1") +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + : "=r" (r0), "=r" (r1) + : "r" (r0), "r" (r1) + : "r2", "r3"); + } while (r0 == SCM_INTERRUPTED); + + version = r1; + mutex_unlock(&scm_lock); + + return version; +} +EXPORT_SYMBOL(scm_get_version); diff --git a/arch/arm/mach-qcom/scm.h b/arch/arm/mach-qcom/scm.h new file mode 100644 index 000000000000..00b31ea58f29 --- /dev/null +++ b/arch/arm/mach-qcom/scm.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ +#ifndef __MACH_SCM_H +#define __MACH_SCM_H + +#define SCM_SVC_BOOT 0x1 +#define SCM_SVC_PIL 0x2 + +extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, + void *resp_buf, size_t resp_len); + +#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) + +extern u32 scm_get_version(void); + +#endif -- cgit v1.2.3