From 7895f73169ade9a74940ae6b0b4ee82faf286861 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 28 Apr 2015 15:51:19 -0400 Subject: ARM: MCPM: remove residency argument from mcpm_cpu_suspend() This is currently unused. If a suspend must be limited to CPU level only by preventing the last man from triggering a cluster level suspend then this should be determined according to many other criteria the MCPM layer is currently not aware of. It is unlikely that mcpm_cpu_suspend() would be the proper conduit for that information anyway. Signed-off-by: Nicolas Pitre Acked-by: Dave Martin --- drivers/cpuidle/cpuidle-big_little.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index 40c34faffe59..db2ede565f1a 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -108,13 +108,7 @@ static int notrace bl_powerdown_finisher(unsigned long arg) unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); mcpm_set_entry_vector(cpu, cluster, cpu_resume); - - /* - * Residency value passed to mcpm_cpu_suspend back-end - * has to be given clear semantics. Set to 0 as a - * temporary value. - */ - mcpm_cpu_suspend(0); + mcpm_cpu_suspend(); /* return value != 0 means failure */ return 1; -- cgit v1.2.3 From 22b67acd99c00e3fdc66869cd43fd539bab0ef8c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 19 May 2015 16:17:09 +0100 Subject: ARM: 8368/1: sa1100: move irq driver to drivers/irqchip/ Move current sa11x0 IRQ driver to the irqchip subsystem. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Thomas Gleixner Signed-off-by: Russell King --- arch/arm/mach-sa1100/Makefile | 2 +- arch/arm/mach-sa1100/irq.c | 177 ------------------------------------------ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sa11x0.c | 175 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 178 deletions(-) delete mode 100644 arch/arm/mach-sa1100/irq.c create mode 100644 drivers/irqchip/irq-sa11x0.c (limited to 'drivers') diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 61ff91e76e0a..ebc4d58e1a32 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := clock.o generic.o irq.o #nmi-oopser.o +obj-y := clock.o generic.o #nmi-oopser.o # Specific board support obj-$(CONFIG_SA1100_ASSABET) += assabet.o diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c deleted file mode 100644 index fdec5edbbfd5..000000000000 --- a/arch/arm/mach-sa1100/irq.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/irq.c - * - * Copyright (C) 2015 Dmitry Eremin-Solenikov - * Copyright (C) 1999-2001 Nicolas Pitre - * - * Generic IRQ handling for the SA11x0. - * - * 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 - -#include - -#define ICIP 0x00 /* IC IRQ Pending reg. */ -#define ICMR 0x04 /* IC Mask Reg. */ -#define ICLR 0x08 /* IC Level Reg. */ -#define ICCR 0x0C /* IC Control Reg. */ -#define ICFP 0x10 /* IC FIQ Pending reg. */ -#define ICPR 0x20 /* IC Pending Reg. */ - -static void __iomem *iobase; - -/* - * We don't need to ACK IRQs on the SA1100 unless they're GPIOs - * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. - */ -static void sa1100_mask_irq(struct irq_data *d) -{ - u32 reg; - - reg = readl_relaxed(iobase + ICMR); - reg &= ~BIT(d->hwirq); - writel_relaxed(reg, iobase + ICMR); -} - -static void sa1100_unmask_irq(struct irq_data *d) -{ - u32 reg; - - reg = readl_relaxed(iobase + ICMR); - reg |= BIT(d->hwirq); - writel_relaxed(reg, iobase + ICMR); -} - -static int sa1100_set_wake(struct irq_data *d, unsigned int on) -{ - return sa11x0_sc_set_wake(d->hwirq, on); -} - -static struct irq_chip sa1100_normal_chip = { - .name = "SC", - .irq_ack = sa1100_mask_irq, - .irq_mask = sa1100_mask_irq, - .irq_unmask = sa1100_unmask_irq, - .irq_set_wake = sa1100_set_wake, -}; - -static int sa1100_normal_irqdomain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - irq_set_chip_and_handler(irq, &sa1100_normal_chip, - handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - - return 0; -} - -static struct irq_domain_ops sa1100_normal_irqdomain_ops = { - .map = sa1100_normal_irqdomain_map, - .xlate = irq_domain_xlate_onetwocell, -}; - -static struct irq_domain *sa1100_normal_irqdomain; - -static struct sa1100irq_state { - unsigned int saved; - unsigned int icmr; - unsigned int iclr; - unsigned int iccr; -} sa1100irq_state; - -static int sa1100irq_suspend(void) -{ - struct sa1100irq_state *st = &sa1100irq_state; - - st->saved = 1; - st->icmr = readl_relaxed(iobase + ICMR); - st->iclr = readl_relaxed(iobase + ICLR); - st->iccr = readl_relaxed(iobase + ICCR); - - /* - * Disable all GPIO-based interrupts. - */ - writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR); - - return 0; -} - -static void sa1100irq_resume(void) -{ - struct sa1100irq_state *st = &sa1100irq_state; - - if (st->saved) { - writel_relaxed(st->iccr, iobase + ICCR); - writel_relaxed(st->iclr, iobase + ICLR); - - writel_relaxed(st->icmr, iobase + ICMR); - } -} - -static struct syscore_ops sa1100irq_syscore_ops = { - .suspend = sa1100irq_suspend, - .resume = sa1100irq_resume, -}; - -static int __init sa1100irq_init_devicefs(void) -{ - register_syscore_ops(&sa1100irq_syscore_ops); - return 0; -} - -device_initcall(sa1100irq_init_devicefs); - -static asmlinkage void __exception_irq_entry -sa1100_handle_irq(struct pt_regs *regs) -{ - uint32_t icip, icmr, mask; - - do { - icip = readl_relaxed(iobase + ICIP); - icmr = readl_relaxed(iobase + ICMR); - mask = icip & icmr; - - if (mask == 0) - break; - - handle_domain_irq(sa1100_normal_irqdomain, - ffs(mask) - 1, regs); - } while (1); -} - -void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start) -{ - iobase = ioremap(io_start, SZ_64K); - if (WARN_ON(!iobase)) - return; - - /* disable all IRQs */ - writel_relaxed(0, iobase + ICMR); - - /* all IRQs are IRQ, not FIQ */ - writel_relaxed(0, iobase + ICLR); - - /* - * Whatever the doc says, this has to be set for the wait-on-irq - * instruction to work... on a SA1100 rev 9 at least. - */ - writel_relaxed(1, iobase + ICCR); - - sa1100_normal_irqdomain = irq_domain_add_simple(NULL, - 32, irq_start, - &sa1100_normal_irqdomain_ops, NULL); - - set_handle_irq(sa1100_handle_irq); -} diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index dda4927e47a6..49f372a168f9 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -47,3 +47,4 @@ obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o +obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c new file mode 100644 index 000000000000..97d257bd8b12 --- /dev/null +++ b/drivers/irqchip/irq-sa11x0.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2015 Dmitry Eremin-Solenikov + * Copyright (C) 1999-2001 Nicolas Pitre + * + * Generic IRQ handling for the SA11x0. + * + * 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 + +#include + +#define ICIP 0x00 /* IC IRQ Pending reg. */ +#define ICMR 0x04 /* IC Mask Reg. */ +#define ICLR 0x08 /* IC Level Reg. */ +#define ICCR 0x0C /* IC Control Reg. */ +#define ICFP 0x10 /* IC FIQ Pending reg. */ +#define ICPR 0x20 /* IC Pending Reg. */ + +static void __iomem *iobase; + +/* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. + */ +static void sa1100_mask_irq(struct irq_data *d) +{ + u32 reg; + + reg = readl_relaxed(iobase + ICMR); + reg &= ~BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); +} + +static void sa1100_unmask_irq(struct irq_data *d) +{ + u32 reg; + + reg = readl_relaxed(iobase + ICMR); + reg |= BIT(d->hwirq); + writel_relaxed(reg, iobase + ICMR); +} + +static int sa1100_set_wake(struct irq_data *d, unsigned int on) +{ + return sa11x0_sc_set_wake(d->hwirq, on); +} + +static struct irq_chip sa1100_normal_chip = { + .name = "SC", + .irq_ack = sa1100_mask_irq, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, + .irq_set_wake = sa1100_set_wake, +}; + +static int sa1100_normal_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &sa1100_normal_chip, + handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops sa1100_normal_irqdomain_ops = { + .map = sa1100_normal_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_normal_irqdomain; + +static struct sa1100irq_state { + unsigned int saved; + unsigned int icmr; + unsigned int iclr; + unsigned int iccr; +} sa1100irq_state; + +static int sa1100irq_suspend(void) +{ + struct sa1100irq_state *st = &sa1100irq_state; + + st->saved = 1; + st->icmr = readl_relaxed(iobase + ICMR); + st->iclr = readl_relaxed(iobase + ICLR); + st->iccr = readl_relaxed(iobase + ICCR); + + /* + * Disable all GPIO-based interrupts. + */ + writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR); + + return 0; +} + +static void sa1100irq_resume(void) +{ + struct sa1100irq_state *st = &sa1100irq_state; + + if (st->saved) { + writel_relaxed(st->iccr, iobase + ICCR); + writel_relaxed(st->iclr, iobase + ICLR); + + writel_relaxed(st->icmr, iobase + ICMR); + } +} + +static struct syscore_ops sa1100irq_syscore_ops = { + .suspend = sa1100irq_suspend, + .resume = sa1100irq_resume, +}; + +static int __init sa1100irq_init_devicefs(void) +{ + register_syscore_ops(&sa1100irq_syscore_ops); + return 0; +} + +device_initcall(sa1100irq_init_devicefs); + +static asmlinkage void __exception_irq_entry +sa1100_handle_irq(struct pt_regs *regs) +{ + uint32_t icip, icmr, mask; + + do { + icip = readl_relaxed(iobase + ICIP); + icmr = readl_relaxed(iobase + ICMR); + mask = icip & icmr; + + if (mask == 0) + break; + + handle_domain_irq(sa1100_normal_irqdomain, + ffs(mask) - 1, regs); + } while (1); +} + +void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start) +{ + iobase = ioremap(io_start, SZ_64K); + if (WARN_ON(!iobase)) + return; + + /* disable all IRQs */ + writel_relaxed(0, iobase + ICMR); + + /* all IRQs are IRQ, not FIQ */ + writel_relaxed(0, iobase + ICLR); + + /* + * Whatever the doc says, this has to be set for the wait-on-irq + * instruction to work... on a SA1100 rev 9 at least. + */ + writel_relaxed(1, iobase + ICCR); + + sa1100_normal_irqdomain = irq_domain_add_simple(NULL, + 32, irq_start, + &sa1100_normal_irqdomain_ops, NULL); + + set_handle_irq(sa1100_handle_irq); +} -- cgit v1.2.3 From 0b7402dce445ba0d11401c2cb806e8fc260c9e49 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 18 May 2015 16:29:40 +0100 Subject: ARM: 8366/1: move Dual-Timer SP804 driver to drivers/clocksource The ARM Dual-Timer SP804 module is peripheral found not only on ARM32 platforms but also on ARM64 platforms. This patch moves the driver out of arch/arm to driver/clocksource so that it can be used on ARM64 platforms also. Cc: Daniel Lezcano Cc: Rob Herring Cc: Arnd Bergmann Cc: Catalin Marinas Cc: Olof Johansson Acked-by: Thomas Gleixner Signed-off-by: Sudeep Holla Signed-off-by: Russell King --- arch/arm/Kconfig | 5 - arch/arm/common/Makefile | 1 - arch/arm/common/timer-sp.c | 309 ----------------------------- arch/arm/include/asm/hardware/arm_timer.h | 35 ---- arch/arm/include/asm/hardware/timer-sp.h | 24 --- arch/arm/mach-nspire/nspire.c | 2 - arch/arm/mach-realview/core.c | 4 +- arch/arm/mach-versatile/core.c | 3 +- drivers/clocksource/Kconfig | 5 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-integrator-ap.c | 3 +- drivers/clocksource/timer-sp.h | 30 +++ drivers/clocksource/timer-sp804.c | 310 ++++++++++++++++++++++++++++++ include/clocksource/timer-sp804.h | 28 +++ 14 files changed, 380 insertions(+), 380 deletions(-) delete mode 100644 arch/arm/common/timer-sp.c delete mode 100644 arch/arm/include/asm/hardware/arm_timer.h delete mode 100644 arch/arm/include/asm/hardware/timer-sp.h create mode 100644 drivers/clocksource/timer-sp.h create mode 100644 drivers/clocksource/timer-sp804.c create mode 100644 include/clocksource/timer-sp804.h (limited to 'drivers') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d0950ce75f3e..34b728583dae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -975,11 +975,6 @@ config PLAT_PXA config PLAT_VERSATILE bool -config ARM_TIMER_SP804 - bool - select CLKSRC_MMIO - select CLKSRC_OF if OF - source "arch/arm/firmware/Kconfig" source arch/arm/mm/Kconfig diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 70b1eff477b3..6ee5959a813b 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o -obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o CFLAGS_REMOVE_mcpm_entry.o = -pg AFLAGS_mcpm_head.o := -march=armv7-a diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c deleted file mode 100644 index 000aea3722bc..000000000000 --- a/arch/arm/common/timer-sp.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * linux/arch/arm/common/timer-sp.c - * - * Copyright (C) 1999 - 2003 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static long __init sp804_get_clock_rate(struct clk *clk) -{ - long rate; - int err; - - err = clk_prepare(clk); - if (err) { - pr_err("sp804: clock failed to prepare: %d\n", err); - clk_put(clk); - return err; - } - - err = clk_enable(clk); - if (err) { - pr_err("sp804: clock failed to enable: %d\n", err); - clk_unprepare(clk); - clk_put(clk); - return err; - } - - rate = clk_get_rate(clk); - if (rate < 0) { - pr_err("sp804: clock failed to get rate: %ld\n", rate); - clk_disable(clk); - clk_unprepare(clk); - clk_put(clk); - } - - return rate; -} - -static void __iomem *sched_clock_base; - -static u64 notrace sp804_read(void) -{ - return ~readl_relaxed(sched_clock_base + TIMER_VALUE); -} - -void __init sp804_timer_disable(void __iomem *base) -{ - writel(0, base + TIMER_CTRL); -} - -void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, - const char *name, - struct clk *clk, - int use_sched_clock) -{ - long rate; - - if (!clk) { - clk = clk_get_sys("sp804", name); - if (IS_ERR(clk)) { - pr_err("sp804: clock not found: %d\n", - (int)PTR_ERR(clk)); - return; - } - } - - rate = sp804_get_clock_rate(clk); - - if (rate < 0) - return; - - /* setup timer 0 as free-running clocksource */ - writel(0, base + TIMER_CTRL); - writel(0xffffffff, base + TIMER_LOAD); - writel(0xffffffff, base + TIMER_VALUE); - writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, - base + TIMER_CTRL); - - clocksource_mmio_init(base + TIMER_VALUE, name, - rate, 200, 32, clocksource_mmio_readl_down); - - if (use_sched_clock) { - sched_clock_base = base; - sched_clock_register(sp804_read, 32, rate); - } -} - - -static void __iomem *clkevt_base; -static unsigned long clkevt_reload; - -/* - * IRQ handler for the timer - */ -static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - /* clear the interrupt */ - writel(1, clkevt_base + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static void sp804_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; - - writel(ctrl, clkevt_base + TIMER_CTRL); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel(clkevt_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* period set, and timer enabled in 'next_event' hook */ - ctrl |= TIMER_CTRL_ONESHOT; - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } - - writel(ctrl, clkevt_base + TIMER_CTRL); -} - -static int sp804_set_next_event(unsigned long next, - struct clock_event_device *evt) -{ - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); - - writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device sp804_clockevent = { - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_DYNIRQ, - .set_mode = sp804_set_mode, - .set_next_event = sp804_set_next_event, - .rating = 300, -}; - -static struct irqaction sp804_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = sp804_timer_interrupt, - .dev_id = &sp804_clockevent, -}; - -void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) -{ - struct clock_event_device *evt = &sp804_clockevent; - long rate; - - if (!clk) - clk = clk_get_sys("sp804", name); - if (IS_ERR(clk)) { - pr_err("sp804: %s clock not found: %d\n", name, - (int)PTR_ERR(clk)); - return; - } - - rate = sp804_get_clock_rate(clk); - if (rate < 0) - return; - - clkevt_base = base; - clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ); - evt->name = name; - evt->irq = irq; - evt->cpumask = cpu_possible_mask; - - writel(0, base + TIMER_CTRL); - - setup_irq(irq, &sp804_timer_irq); - clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); -} - -static void __init sp804_of_init(struct device_node *np) -{ - static bool initialized = false; - void __iomem *base; - int irq; - u32 irq_num = 0; - struct clk *clk1, *clk2; - const char *name = of_get_property(np, "compatible", NULL); - - base = of_iomap(np, 0); - if (WARN_ON(!base)) - return; - - /* Ensure timers are disabled */ - writel(0, base + TIMER_CTRL); - writel(0, base + TIMER_2_BASE + TIMER_CTRL); - - if (initialized || !of_device_is_available(np)) - goto err; - - clk1 = of_clk_get(np, 0); - if (IS_ERR(clk1)) - clk1 = NULL; - - /* Get the 2nd clock if the timer has 3 timer clocks */ - if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) { - clk2 = of_clk_get(np, 1); - if (IS_ERR(clk2)) { - pr_err("sp804: %s clock not found: %d\n", np->name, - (int)PTR_ERR(clk2)); - clk2 = NULL; - } - } else - clk2 = clk1; - - irq = irq_of_parse_and_map(np, 0); - if (irq <= 0) - goto err; - - of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); - if (irq_num == 2) { - __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); - __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); - } else { - __sp804_clockevents_init(base, irq, clk1 , name); - __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, - name, clk2, 1); - } - initialized = true; - - return; -err: - iounmap(base); -} -CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); - -static void __init integrator_cp_of_init(struct device_node *np) -{ - static int init_count = 0; - void __iomem *base; - int irq; - const char *name = of_get_property(np, "compatible", NULL); - struct clk *clk; - - base = of_iomap(np, 0); - if (WARN_ON(!base)) - return; - clk = of_clk_get(np, 0); - if (WARN_ON(IS_ERR(clk))) - return; - - /* Ensure timer is disabled */ - writel(0, base + TIMER_CTRL); - - if (init_count == 2 || !of_device_is_available(np)) - goto err; - - if (!init_count) - __sp804_clocksource_and_sched_clock_init(base, name, clk, 0); - else { - irq = irq_of_parse_and_map(np, 0); - if (irq <= 0) - goto err; - - __sp804_clockevents_init(base, irq, clk, name); - } - - init_count++; - return; -err: - iounmap(base); -} -CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h deleted file mode 100644 index d6030ff599db..000000000000 --- a/arch/arm/include/asm/hardware/arm_timer.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H -#define __ASM_ARM_HARDWARE_ARM_TIMER_H - -/* - * ARM timer implementation, found in Integrator, Versatile and Realview - * platforms. Not all platforms support all registers and bits in these - * registers, so we mark them with A for Integrator AP, C for Integrator - * CP, V for Versatile and R for Realview. - * - * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview - * can have 16-bit or 32-bit selectable via a bit in the control register. - * - * Every SP804 contains two identical timers. - */ -#define TIMER_1_BASE 0x00 -#define TIMER_2_BASE 0x20 - -#define TIMER_LOAD 0x00 /* ACVR rw */ -#define TIMER_VALUE 0x04 /* ACVR ro */ -#define TIMER_CTRL 0x08 /* ACVR rw */ -#define TIMER_CTRL_ONESHOT (1 << 0) /* CVR */ -#define TIMER_CTRL_32BIT (1 << 1) /* CVR */ -#define TIMER_CTRL_DIV1 (0 << 2) /* ACVR */ -#define TIMER_CTRL_DIV16 (1 << 2) /* ACVR */ -#define TIMER_CTRL_DIV256 (2 << 2) /* ACVR */ -#define TIMER_CTRL_IE (1 << 5) /* VR */ -#define TIMER_CTRL_PERIODIC (1 << 6) /* ACVR */ -#define TIMER_CTRL_ENABLE (1 << 7) /* ACVR */ - -#define TIMER_INTCLR 0x0c /* ACVR wo */ -#define TIMER_RIS 0x10 /* CVR ro */ -#define TIMER_MIS 0x14 /* CVR ro */ -#define TIMER_BGLOAD 0x18 /* CVR rw */ - -#endif diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h deleted file mode 100644 index 05eaefa46742..000000000000 --- a/arch/arm/include/asm/hardware/timer-sp.h +++ /dev/null @@ -1,24 +0,0 @@ -struct clk; - -void __sp804_clocksource_and_sched_clock_init(void __iomem *, - const char *, struct clk *, int); -void __sp804_clockevents_init(void __iomem *, unsigned int, - struct clk *, const char *); -void sp804_timer_disable(void __iomem *); - -static inline void sp804_clocksource_init(void __iomem *base, const char *name) -{ - __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0); -} - -static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, - const char *name) -{ - __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1); -} - -static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name) -{ - __sp804_clockevents_init(base, irq, NULL, name); - -} diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c index 3445a5686805..34c2a1b32e7d 100644 --- a/arch/arm/mach-nspire/nspire.c +++ b/arch/arm/mach-nspire/nspire.c @@ -22,8 +22,6 @@ #include #include -#include - #include "mmio.h" #include "clcd.h" diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index c611f489bdd2..44575edc44b1 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -35,6 +35,8 @@ #include #include +#include + #include #include #include @@ -44,10 +46,8 @@ #include #include - #include #include -#include #include diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index f98c1961be6a..23a04fe5d2ad 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -41,6 +41,8 @@ #include #include +#include + #include #include #include @@ -51,7 +53,6 @@ #include #include #include -#include #include diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 51d7865fdddb..0f1c0e7f86da 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -132,6 +132,11 @@ config ARM_GLOBAL_TIMER help This options enables support for the ARM global timer unit +config ARM_TIMER_SP804 + bool "Support for Dual Timer SP804 module" + select CLKSRC_MMIO + select CLKSRC_OF if OF + config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK bool depends on ARM_GLOBAL_TIMER diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 5b85f6adb258..5ca59f9b377f 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o +obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index b9efd30513d5..d7d21e4dcef0 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -26,7 +26,8 @@ #include #include #include -#include + +#include "timer-sp.h" static void __iomem * sched_clk_base; diff --git a/drivers/clocksource/timer-sp.h b/drivers/clocksource/timer-sp.h new file mode 100644 index 000000000000..050d88561e9c --- /dev/null +++ b/drivers/clocksource/timer-sp.h @@ -0,0 +1,30 @@ +/* + * ARM timer implementation, found in Integrator, Versatile and Realview + * platforms. Not all platforms support all registers and bits in these + * registers, so we mark them with A for Integrator AP, C for Integrator + * CP, V for Versatile and R for Realview. + * + * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview + * can have 16-bit or 32-bit selectable via a bit in the control register. + * + * Every SP804 contains two identical timers. + */ +#define TIMER_1_BASE 0x00 +#define TIMER_2_BASE 0x20 + +#define TIMER_LOAD 0x00 /* ACVR rw */ +#define TIMER_VALUE 0x04 /* ACVR ro */ +#define TIMER_CTRL 0x08 /* ACVR rw */ +#define TIMER_CTRL_ONESHOT (1 << 0) /* CVR */ +#define TIMER_CTRL_32BIT (1 << 1) /* CVR */ +#define TIMER_CTRL_DIV1 (0 << 2) /* ACVR */ +#define TIMER_CTRL_DIV16 (1 << 2) /* ACVR */ +#define TIMER_CTRL_DIV256 (2 << 2) /* ACVR */ +#define TIMER_CTRL_IE (1 << 5) /* VR */ +#define TIMER_CTRL_PERIODIC (1 << 6) /* ACVR */ +#define TIMER_CTRL_ENABLE (1 << 7) /* ACVR */ + +#define TIMER_INTCLR 0x0c /* ACVR wo */ +#define TIMER_RIS 0x10 /* CVR ro */ +#define TIMER_MIS 0x14 /* CVR ro */ +#define TIMER_BGLOAD 0x18 /* CVR rw */ diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c new file mode 100644 index 000000000000..ca02503f17d1 --- /dev/null +++ b/drivers/clocksource/timer-sp804.c @@ -0,0 +1,310 @@ +/* + * linux/drivers/clocksource/timer-sp.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "timer-sp.h" + +static long __init sp804_get_clock_rate(struct clk *clk) +{ + long rate; + int err; + + err = clk_prepare(clk); + if (err) { + pr_err("sp804: clock failed to prepare: %d\n", err); + clk_put(clk); + return err; + } + + err = clk_enable(clk); + if (err) { + pr_err("sp804: clock failed to enable: %d\n", err); + clk_unprepare(clk); + clk_put(clk); + return err; + } + + rate = clk_get_rate(clk); + if (rate < 0) { + pr_err("sp804: clock failed to get rate: %ld\n", rate); + clk_disable(clk); + clk_unprepare(clk); + clk_put(clk); + } + + return rate; +} + +static void __iomem *sched_clock_base; + +static u64 notrace sp804_read(void) +{ + return ~readl_relaxed(sched_clock_base + TIMER_VALUE); +} + +void __init sp804_timer_disable(void __iomem *base) +{ + writel(0, base + TIMER_CTRL); +} + +void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, + const char *name, + struct clk *clk, + int use_sched_clock) +{ + long rate; + + if (!clk) { + clk = clk_get_sys("sp804", name); + if (IS_ERR(clk)) { + pr_err("sp804: clock not found: %d\n", + (int)PTR_ERR(clk)); + return; + } + } + + rate = sp804_get_clock_rate(clk); + + if (rate < 0) + return; + + /* setup timer 0 as free-running clocksource */ + writel(0, base + TIMER_CTRL); + writel(0xffffffff, base + TIMER_LOAD); + writel(0xffffffff, base + TIMER_VALUE); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + base + TIMER_CTRL); + + clocksource_mmio_init(base + TIMER_VALUE, name, + rate, 200, 32, clocksource_mmio_readl_down); + + if (use_sched_clock) { + sched_clock_base = base; + sched_clock_register(sp804_read, 32, rate); + } +} + + +static void __iomem *clkevt_base; +static unsigned long clkevt_reload; + +/* + * IRQ handler for the timer + */ +static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void sp804_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(clkevt_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl |= TIMER_CTRL_ONESHOT; + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } + + writel(ctrl, clkevt_base + TIMER_CTRL); +} + +static int sp804_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device sp804_clockevent = { + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ, + .set_mode = sp804_set_mode, + .set_next_event = sp804_set_next_event, + .rating = 300, +}; + +static struct irqaction sp804_timer_irq = { + .name = "timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = sp804_timer_interrupt, + .dev_id = &sp804_clockevent, +}; + +void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) +{ + struct clock_event_device *evt = &sp804_clockevent; + long rate; + + if (!clk) + clk = clk_get_sys("sp804", name); + if (IS_ERR(clk)) { + pr_err("sp804: %s clock not found: %d\n", name, + (int)PTR_ERR(clk)); + return; + } + + rate = sp804_get_clock_rate(clk); + if (rate < 0) + return; + + clkevt_base = base; + clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ); + evt->name = name; + evt->irq = irq; + evt->cpumask = cpu_possible_mask; + + writel(0, base + TIMER_CTRL); + + setup_irq(irq, &sp804_timer_irq); + clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); +} + +static void __init sp804_of_init(struct device_node *np) +{ + static bool initialized = false; + void __iomem *base; + int irq; + u32 irq_num = 0; + struct clk *clk1, *clk2; + const char *name = of_get_property(np, "compatible", NULL); + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return; + + /* Ensure timers are disabled */ + writel(0, base + TIMER_CTRL); + writel(0, base + TIMER_2_BASE + TIMER_CTRL); + + if (initialized || !of_device_is_available(np)) + goto err; + + clk1 = of_clk_get(np, 0); + if (IS_ERR(clk1)) + clk1 = NULL; + + /* Get the 2nd clock if the timer has 3 timer clocks */ + if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) { + clk2 = of_clk_get(np, 1); + if (IS_ERR(clk2)) { + pr_err("sp804: %s clock not found: %d\n", np->name, + (int)PTR_ERR(clk2)); + clk2 = NULL; + } + } else + clk2 = clk1; + + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) + goto err; + + of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); + if (irq_num == 2) { + __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); + __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); + } else { + __sp804_clockevents_init(base, irq, clk1 , name); + __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, + name, clk2, 1); + } + initialized = true; + + return; +err: + iounmap(base); +} +CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); + +static void __init integrator_cp_of_init(struct device_node *np) +{ + static int init_count = 0; + void __iomem *base; + int irq; + const char *name = of_get_property(np, "compatible", NULL); + struct clk *clk; + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return; + clk = of_clk_get(np, 0); + if (WARN_ON(IS_ERR(clk))) + return; + + /* Ensure timer is disabled */ + writel(0, base + TIMER_CTRL); + + if (init_count == 2 || !of_device_is_available(np)) + goto err; + + if (!init_count) + __sp804_clocksource_and_sched_clock_init(base, name, clk, 0); + else { + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) + goto err; + + __sp804_clockevents_init(base, irq, clk, name); + } + + init_count++; + return; +err: + iounmap(base); +} +CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/include/clocksource/timer-sp804.h b/include/clocksource/timer-sp804.h new file mode 100644 index 000000000000..1f8a1caa7cb4 --- /dev/null +++ b/include/clocksource/timer-sp804.h @@ -0,0 +1,28 @@ +#ifndef __CLKSOURCE_TIMER_SP804_H +#define __CLKSOURCE_TIMER_SP804_H + +struct clk; + +void __sp804_clocksource_and_sched_clock_init(void __iomem *, + const char *, struct clk *, int); +void __sp804_clockevents_init(void __iomem *, unsigned int, + struct clk *, const char *); +void sp804_timer_disable(void __iomem *); + +static inline void sp804_clocksource_init(void __iomem *base, const char *name) +{ + __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0); +} + +static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, + const char *name) +{ + __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1); +} + +static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name) +{ + __sp804_clockevents_init(base, irq, NULL, name); + +} +#endif -- cgit v1.2.3 From e44d89f14227ffa5e96cd158fb2d35fbb40fa97a Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 29 May 2015 12:27:46 +0100 Subject: ARM: 8382/1: clocksource: make ARM_TIMER_SP804 depend on GENERIC_SCHED_CLOCK Commit 5261ef2ea836 ("ARM: 8366/1: move Dual-Timer SP804 driver to drivers/clocksource") moved SP804 to drivers/clocksource resulting in it being selectable on platforms/architectures without the config GENERIC_SCHED_CLOCK enabled. Due to that, it results in the following build failure(e.g. x86_64 allmodconfig) drivers/built-in.o: In function `__sp804_clocksource_and_sched_clock_init': (.init.text+0x1a0e7): undefined reference to `sched_clock_register' This patch fixes the build by making ARM_TIMER_SP804 depend on GENERIC_SCHED_CLOCK Cc: Daniel Lezcano Cc: Thomas Gleixner Reported-by: Stephen Rothwell Signed-off-by: Sudeep Holla Signed-off-by: Russell King --- drivers/clocksource/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 0f1c0e7f86da..50534704486a 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -134,6 +134,7 @@ config ARM_GLOBAL_TIMER config ARM_TIMER_SP804 bool "Support for Dual Timer SP804 module" + depends on GENERIC_SCHED_CLOCK select CLKSRC_MMIO select CLKSRC_OF if OF -- cgit v1.2.3 From 002af195a8c720ca47c7884fd0390f3b327423b9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 23 Jun 2015 20:49:05 -0700 Subject: ARM: Fix build if CLKDEV_LOOKUP is not configured mips:allmodconfig fails to build with drivers/clocksource/timer-sp804.c: In function '__sp804_clocksource_and_sched_clock_init': drivers/clocksource/timer-sp804.c:88:3: error: implicit declaration of function 'clk_get_sys' because CLKDEV_LOOKUP is not configured and the driver depends on it. Fixes: 0b7402dce445 ("ARM: 8366/1: move Dual-Timer SP804 driver to drivers/clocksource") Acked-by: Sudeep Holla Signed-off-by: Guenter Roeck Signed-off-by: Russell King --- drivers/clocksource/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 50534704486a..b2590d6c721a 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -134,7 +134,7 @@ config ARM_GLOBAL_TIMER config ARM_TIMER_SP804 bool "Support for Dual Timer SP804 module" - depends on GENERIC_SCHED_CLOCK + depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP select CLKSRC_MMIO select CLKSRC_OF if OF -- cgit v1.2.3