From: Barry Song Date: Thu, 20 Dec 2012 09:33:49 +0000 (+0800) Subject: ARM: PRIMA2: mv timer to timer-prima2 as we will add timer-marco X-Git-Tag: firefly_0821_release~3680^2~1071^2~26^2~5 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0d5983a62ad5749068a507e0c579af88f4753261;p=firefly-linux-kernel-4.4.55.git ARM: PRIMA2: mv timer to timer-prima2 as we will add timer-marco Marco timer has different timer IP with prima2, so rename the current timer to timer-prima2 so that we can add timer-marco. at the same time, if we don't find prima2 timer node in dt, don't panic the system as we will make prima2 and marco use same kernel image. Signed-off-by: Barry Song --- diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index fc9ce22e2b5a..0007a6ec78f2 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -1,4 +1,3 @@ -obj-y := timer.o obj-y += rstc.o obj-y += common.o obj-y += rtciobrg.o @@ -6,3 +5,4 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o obj-$(CONFIG_SUSPEND) += pm.o sleep.o obj-$(CONFIG_SIRF_IRQ) += irq.o +obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index ed3570e5eb8f..8e6f6681b546 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -40,7 +40,7 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") /* Maintainer: Barry Song */ .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, - .init_time = sirfsoc_timer_init, + .init_time = sirfsoc_prima2_timer_init, .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, .init_late = sirfsoc_init_late, diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index 9c75f124e3cf..d6890b6833c9 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -12,7 +12,7 @@ #include #include -extern void sirfsoc_timer_init(void); +extern void sirfsoc_prima2_timer_init(void); extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); diff --git a/arch/arm/mach-prima2/timer-prima2.c b/arch/arm/mach-prima2/timer-prima2.c new file mode 100644 index 000000000000..309e724735b7 --- /dev/null +++ b/arch/arm/mach-prima2/timer-prima2.c @@ -0,0 +1,247 @@ +/* + * System timer for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define SIRFSOC_TIMER_COUNTER_LO 0x0000 +#define SIRFSOC_TIMER_COUNTER_HI 0x0004 +#define SIRFSOC_TIMER_MATCH_0 0x0008 +#define SIRFSOC_TIMER_MATCH_1 0x000C +#define SIRFSOC_TIMER_MATCH_2 0x0010 +#define SIRFSOC_TIMER_MATCH_3 0x0014 +#define SIRFSOC_TIMER_MATCH_4 0x0018 +#define SIRFSOC_TIMER_MATCH_5 0x001C +#define SIRFSOC_TIMER_STATUS 0x0020 +#define SIRFSOC_TIMER_INT_EN 0x0024 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028 +#define SIRFSOC_TIMER_DIV 0x002C +#define SIRFSOC_TIMER_LATCH 0x0030 +#define SIRFSOC_TIMER_LATCHED_LO 0x0034 +#define SIRFSOC_TIMER_LATCHED_HI 0x0038 + +#define SIRFSOC_TIMER_WDT_INDEX 5 + +#define SIRFSOC_TIMER_LATCH_BIT BIT(0) + +#define SIRFSOC_TIMER_REG_CNT 11 + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { + SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2, + SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5, + SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV, + SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI, +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; + +static void __iomem *sirfsoc_timer_base; +static void __init sirfsoc_of_timer_map(void); + +/* timer0 interrupt handler */ +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + + WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0))); + + /* clear timer0 interrupt */ + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + /* latch the 64-bit timer counter */ + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + unsigned long now, next; + + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + next = now + delta; + writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + + return next - now > delta ? -ETIME : 0; +} + +static void sirfsoc_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + WARN_ON(1); + break; + case CLOCK_EVT_MODE_ONESHOT: + writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static void sirfsoc_clocksource_suspend(struct clocksource *cs) +{ + int i; + + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) + writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); +} + +static struct clock_event_device sirfsoc_clockevent = { + .name = "sirfsoc_clockevent", + .rating = 200, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sirfsoc_timer_set_mode, + .set_next_event = sirfsoc_timer_set_next_event, +}; + +static struct clocksource sirfsoc_clocksource = { + .name = "sirfsoc_clocksource", + .rating = 200, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = sirfsoc_timer_read, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER, + .irq = 0, + .handler = sirfsoc_timer_interrupt, + .dev_id = &sirfsoc_clockevent, +}; + +/* Overwrite weak default sched_clock with more precise one */ +static u32 notrace sirfsoc_read_sched_clock(void) +{ + return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff); +} + +static void __init sirfsoc_clockevent_init(void) +{ + clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); + + sirfsoc_clockevent.max_delta_ns = + clockevent_delta2ns(-2, &sirfsoc_clockevent); + sirfsoc_clockevent.min_delta_ns = + clockevent_delta2ns(2, &sirfsoc_clockevent); + + sirfsoc_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&sirfsoc_clockevent); +} + +/* initialize the kernel jiffy timer source */ +void __init sirfsoc_prima2_timer_init(void) +{ + unsigned long rate; + struct clk *clk; + + /* initialize clocking early, we want to set the OS timer */ + sirfsoc_of_clk_init(); + + /* timer's input clock is io clock */ + clk = clk_get_sys("io", NULL); + + BUG_ON(IS_ERR(clk)); + + rate = clk_get_rate(clk); + + BUG_ON(rate < CLOCK_TICK_RATE); + BUG_ON(rate % CLOCK_TICK_RATE); + + sirfsoc_of_timer_map(); + + writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + + setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE); + + BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); + + sirfsoc_clockevent_init(); +} + +static struct of_device_id timer_ids[] = { + { .compatible = "sirf,prima2-tick" }, + {}, +}; + +static void __init sirfsoc_of_timer_map(void) +{ + struct device_node *np; + const unsigned int *intspec; + + np = of_find_matching_node(NULL, timer_ids); + if (!np) + return; + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + /* Get the interrupts property */ + intspec = of_get_property(np, "interrupts", NULL); + BUG_ON(!intspec); + sirfsoc_timer_irq.irq = be32_to_cpup(intspec); + + of_node_put(np); +} diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c deleted file mode 100644 index 8c732a5beb7f..000000000000 --- a/arch/arm/mach-prima2/timer.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * System timer for CSR SiRFprimaII - * - * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - * - * Licensed under GPLv2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" - -#define SIRFSOC_TIMER_COUNTER_LO 0x0000 -#define SIRFSOC_TIMER_COUNTER_HI 0x0004 -#define SIRFSOC_TIMER_MATCH_0 0x0008 -#define SIRFSOC_TIMER_MATCH_1 0x000C -#define SIRFSOC_TIMER_MATCH_2 0x0010 -#define SIRFSOC_TIMER_MATCH_3 0x0014 -#define SIRFSOC_TIMER_MATCH_4 0x0018 -#define SIRFSOC_TIMER_MATCH_5 0x001C -#define SIRFSOC_TIMER_STATUS 0x0020 -#define SIRFSOC_TIMER_INT_EN 0x0024 -#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028 -#define SIRFSOC_TIMER_DIV 0x002C -#define SIRFSOC_TIMER_LATCH 0x0030 -#define SIRFSOC_TIMER_LATCHED_LO 0x0034 -#define SIRFSOC_TIMER_LATCHED_HI 0x0038 - -#define SIRFSOC_TIMER_WDT_INDEX 5 - -#define SIRFSOC_TIMER_LATCH_BIT BIT(0) - -#define SIRFSOC_TIMER_REG_CNT 11 - -static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { - SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2, - SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5, - SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV, - SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI, -}; - -static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; - -static void __iomem *sirfsoc_timer_base; -static void __init sirfsoc_of_timer_map(void); - -/* timer0 interrupt handler */ -static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *ce = dev_id; - - WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0))); - - /* clear timer0 interrupt */ - writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); - - ce->event_handler(ce); - - return IRQ_HANDLED; -} - -/* read 64-bit timer counter */ -static cycle_t sirfsoc_timer_read(struct clocksource *cs) -{ - u64 cycles; - - /* latch the 64-bit timer counter */ - writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); - cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI); - cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); - - return cycles; -} - -static int sirfsoc_timer_set_next_event(unsigned long delta, - struct clock_event_device *ce) -{ - unsigned long now, next; - - writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); - now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); - next = now + delta; - writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); - writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); - now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); - - return next - now > delta ? -ETIME : 0; -} - -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) -{ - u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - WARN_ON(1); - break; - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - break; - } -} - -static void sirfsoc_clocksource_suspend(struct clocksource *cs) -{ - int i; - - writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); - - for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) - sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); -} - -static void sirfsoc_clocksource_resume(struct clocksource *cs) -{ - int i; - - for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) - writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); - - writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); - writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); -} - -static struct clock_event_device sirfsoc_clockevent = { - .name = "sirfsoc_clockevent", - .rating = 200, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sirfsoc_timer_set_mode, - .set_next_event = sirfsoc_timer_set_next_event, -}; - -static struct clocksource sirfsoc_clocksource = { - .name = "sirfsoc_clocksource", - .rating = 200, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .read = sirfsoc_timer_read, - .suspend = sirfsoc_clocksource_suspend, - .resume = sirfsoc_clocksource_resume, -}; - -static struct irqaction sirfsoc_timer_irq = { - .name = "sirfsoc_timer0", - .flags = IRQF_TIMER, - .irq = 0, - .handler = sirfsoc_timer_interrupt, - .dev_id = &sirfsoc_clockevent, -}; - -/* Overwrite weak default sched_clock with more precise one */ -static u32 notrace sirfsoc_read_sched_clock(void) -{ - return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff); -} - -static void __init sirfsoc_clockevent_init(void) -{ - clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); - - sirfsoc_clockevent.max_delta_ns = - clockevent_delta2ns(-2, &sirfsoc_clockevent); - sirfsoc_clockevent.min_delta_ns = - clockevent_delta2ns(2, &sirfsoc_clockevent); - - sirfsoc_clockevent.cpumask = cpumask_of(0); - clockevents_register_device(&sirfsoc_clockevent); -} - -/* initialize the kernel jiffy timer source */ -void __init sirfsoc_timer_init(void) -{ - unsigned long rate; - struct clk *clk; - - /* initialize clocking early, we want to set the OS timer */ - sirfsoc_of_clk_init(); - - /* timer's input clock is io clock */ - clk = clk_get_sys("io", NULL); - - BUG_ON(IS_ERR(clk)); - - rate = clk_get_rate(clk); - - BUG_ON(rate < CLOCK_TICK_RATE); - BUG_ON(rate % CLOCK_TICK_RATE); - - sirfsoc_of_timer_map(); - - writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); - writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); - writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); - - BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); - - setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE); - - BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); - - sirfsoc_clockevent_init(); -} - -static struct of_device_id timer_ids[] = { - { .compatible = "sirf,prima2-tick" }, - {}, -}; - -void __init sirfsoc_of_timer_map(void) -{ - struct device_node *np; - const unsigned int *intspec; - - np = of_find_matching_node(NULL, timer_ids); - if (!np) - panic("unable to find compatible timer node in dtb\n"); - sirfsoc_timer_base = of_iomap(np, 0); - if (!sirfsoc_timer_base) - panic("unable to map timer cpu registers\n"); - - /* Get the interrupts property */ - intspec = of_get_property(np, "interrupts", NULL); - BUG_ON(!intspec); - sirfsoc_timer_irq.irq = be32_to_cpup(intspec); - - of_node_put(np); -}