From f64691b3ab795268072e76ddb89290b6277cdf33 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Wed, 15 Apr 2009 12:40:11 -0700 Subject: [PATCH] davinci: Add base address and timer flexibility The davinci timer code currently hardcodes the timer register base addresses, the timer irq numbers, and the timers to use for clock events and clocksource. This won't work for some a new SoC so put those values into the soc_info structure and set them up in the SoC-specific files. Signed-off-by: Mark A. Greer Signed-off-by: Kevin Hilman --- arch/arm/mach-davinci/devices.c | 47 ++++++++++ arch/arm/mach-davinci/dm355.c | 14 +++ arch/arm/mach-davinci/dm644x.c | 14 +++ arch/arm/mach-davinci/dm646x.c | 14 +++ arch/arm/mach-davinci/include/mach/common.h | 13 +++ arch/arm/mach-davinci/include/mach/time.h | 34 ++++++++ arch/arm/mach-davinci/time.c | 96 +++++++++------------ 7 files changed, 179 insertions(+), 53 deletions(-) create mode 100644 arch/arm/mach-davinci/include/mach/time.h diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 56c19319a7d2..36c528ff30f9 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -25,6 +25,7 @@ #include #include #include +#include #define DAVINCI_I2C_BASE 0x01C21000 #define DAVINCI_MMCSD0_BASE 0x01E10000 @@ -235,6 +236,52 @@ static void davinci_init_wdt(void) /*-------------------------------------------------------------------------*/ +struct davinci_timer_instance davinci_timer_instance[2] = { + { + .base = IO_ADDRESS(DAVINCI_TIMER0_BASE), + .bottom_irq = IRQ_TINT0_TINT12, + .top_irq = IRQ_TINT0_TINT34, + }, + { + .base = IO_ADDRESS(DAVINCI_TIMER1_BASE), + .bottom_irq = IRQ_TINT1_TINT12, + .top_irq = IRQ_TINT1_TINT34, + }, +}; + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE) + +void davinci_init_emac(struct emac_platform_data *pdata) +{ + DECLARE_MAC_BUF(buf); + + if (cpu_is_davinci_dm644x()) + dm644x_init_emac(pdata); + else if (cpu_is_davinci_dm646x()) + dm646x_init_emac(pdata); + + /* if valid MAC exists, don't re-register */ + if (is_valid_ether_addr(pdata->mac_addr)) + return; + else { + /* Use random MAC if none passed */ + random_ether_addr(pdata->mac_addr); + + printk(KERN_WARNING "%s: using random MAC addr: %s\n", + __func__, print_mac(buf, pdata->mac_addr)); + } +} + +#else + +void davinci_init_emac(struct emac_platform_data *unused) {} + +#endif + +/*-------------------------------------------------------------------------*/ + static int __init davinci_init_devices(void) { /* please keep these calls, and their implementations above, diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index e8c01ffe818a..293a419a4a8e 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "clock.h" @@ -616,6 +617,18 @@ static void __iomem *dm355_psc_bases[] = { IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), }; +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm355_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + static struct davinci_soc_info davinci_soc_info_dm355 = { .io_desc = dm355_io_desc, .io_desc_num = ARRAY_SIZE(dm355_io_desc), @@ -632,6 +645,7 @@ static struct davinci_soc_info davinci_soc_info_dm355 = { .intc_type = DAVINCI_INTC_TYPE_AINTC, .intc_irq_prios = dm355_default_priorities, .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm355_timer_info, }; void __init dm355_init(void) diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 5c6a7b175786..8e9385c34853 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "clock.h" @@ -559,6 +560,18 @@ static void __iomem *dm644x_psc_bases[] = { IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), }; +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm644x_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + static struct davinci_soc_info davinci_soc_info_dm644x = { .io_desc = dm644x_io_desc, .io_desc_num = ARRAY_SIZE(dm644x_io_desc), @@ -575,6 +588,7 @@ static struct davinci_soc_info davinci_soc_info_dm644x = { .intc_type = DAVINCI_INTC_TYPE_AINTC, .intc_irq_prios = dm644x_default_priorities, .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm644x_timer_info, }; void __init dm644x_init(void) diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index beb522e8a1a5..219063f4d000 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "clock.h" @@ -538,6 +539,18 @@ static void __iomem *dm646x_psc_bases[] = { IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), }; +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm646x_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + static struct davinci_soc_info davinci_soc_info_dm646x = { .io_desc = dm646x_io_desc, .io_desc_num = ARRAY_SIZE(dm646x_io_desc), @@ -554,6 +567,7 @@ static struct davinci_soc_info davinci_soc_info_dm646x = { .intc_type = DAVINCI_INTC_TYPE_AINTC, .intc_irq_prios = dm646x_default_priorities, .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm646x_timer_info, }; void __init dm646x_init(void) diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h index 838ae13595a4..90b43be1174e 100644 --- a/arch/arm/mach-davinci/include/mach/common.h +++ b/arch/arm/mach-davinci/include/mach/common.h @@ -25,6 +25,18 @@ extern void setup_usb(unsigned mA, unsigned potpgt_msec); /* parameters describe VBUS sourcing for host mode */ extern void setup_usb(unsigned mA, unsigned potpgt_msec); +struct davinci_timer_instance { + void __iomem *base; + u32 bottom_irq; + u32 top_irq; +}; + +struct davinci_timer_info { + struct davinci_timer_instance *timers; + unsigned int clockevent_id; + unsigned int clocksource_id; +}; + /* SoC specific init support */ struct davinci_soc_info { struct map_desc *io_desc; @@ -44,6 +56,7 @@ struct davinci_soc_info { int intc_type; u8 *intc_irq_prios; unsigned long intc_irq_num; + struct davinci_timer_info *timer_info; }; extern struct davinci_soc_info davinci_soc_info; diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h new file mode 100644 index 000000000000..1428d77c989e --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/time.h @@ -0,0 +1,34 @@ +/* + * Local header file for DaVinci time code. + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H +#define __ARCH_ARM_MACH_DAVINCI_TIME_H + +#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) +#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) + +enum { + T0_BOT, + T0_TOP, + T1_BOT, + T1_TOP, + NUM_TIMERS +}; + +#define IS_TIMER1(id) (id & 0x2) +#define IS_TIMER0(id) (!IS_TIMER1(id)) +#define IS_TIMER_TOP(id) ((id & 0x1)) +#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id)) + +#define ID_TO_TIMER(id) (IS_TIMER1(id) != 0) + +extern struct davinci_timer_instance davinci_timer_instance[]; + +#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */ diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index efbbc2ac63b4..faafb897f4bd 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -29,42 +29,23 @@ #include #include #include +#include #include "clock.h" static struct clock_event_device clockevent_davinci; static unsigned int davinci_clock_tick_rate; -#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) -#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) #define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) -enum { - T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS, -}; - -#define IS_TIMER1(id) (id & 0x2) -#define IS_TIMER0(id) (!IS_TIMER1(id)) -#define IS_TIMER_TOP(id) ((id & 0x1)) -#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id)) - -static int timer_irqs[NUM_TIMERS] = { - IRQ_TINT0_TINT12, - IRQ_TINT0_TINT34, - IRQ_TINT1_TINT12, - IRQ_TINT1_TINT34, -}; - /* * This driver configures the 2 64-bit count-up timers as 4 independent * 32-bit count-up timers used as follows: - * - * T0_BOT: Timer 0, bottom: clockevent source for hrtimers - * T0_TOP: Timer 0, top : clocksource for generic timekeeping - * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) - * T1_TOP: Timer 1, top : */ -#define TID_CLOCKEVENT T0_BOT -#define TID_CLOCKSOURCE T0_TOP + +enum { + TID_CLOCKEVENT, + TID_CLOCKSOURCE, +}; /* Timer register offsets */ #define PID12 0x0 @@ -119,6 +100,13 @@ static struct timer_s timers[]; #define TIMER_OPTS_ONESHOT 0x01 #define TIMER_OPTS_PERIODIC 0x02 +static char *id_to_name[] = { + [T0_BOT] = "timer0_0", + [T0_TOP] = "timer0_1", + [T1_BOT] = "timer1_0", + [T1_TOP] = "timer1_1", +}; + static int timer32_config(struct timer_s *t) { u32 tcr = __raw_readl(t->base + TCR); @@ -183,13 +171,14 @@ static struct timer_s timers[] = { static void __init timer_init(void) { - u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE}; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct davinci_timer_instance *dtip = soc_info->timer_info->timers; int i; /* Global init of each 64-bit timer as a whole */ for(i=0; i<2; i++) { u32 tgcr; - void __iomem *base = IO_ADDRESS(phys_bases[i]); + void __iomem *base = dtip[i].base; /* Disabled, Internal clock source */ __raw_writel(0, base + TCR); @@ -215,33 +204,30 @@ static void __init timer_init(void) /* Init of each timer as a 32-bit timer */ for (i=0; i< ARRAY_SIZE(timers); i++) { struct timer_s *t = &timers[i]; - u32 phys_base; + int timer = ID_TO_TIMER(t->id); + u32 irq; - if (t->name) { - t->id = i; - phys_base = (IS_TIMER1(t->id) ? - DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE); - t->base = IO_ADDRESS(phys_base); + t->base = dtip[timer].base; - if (IS_TIMER_BOT(t->id)) { - t->enamode_shift = 6; - t->tim_off = TIM12; - t->prd_off = PRD12; - } else { - t->enamode_shift = 22; - t->tim_off = TIM34; - t->prd_off = PRD34; - } - - /* Register interrupt */ - t->irqaction.name = t->name; - t->irqaction.dev_id = (void *)t; - if (t->irqaction.handler != NULL) { - setup_irq(timer_irqs[t->id], &t->irqaction); - } - - timer32_config(&timers[i]); + if (IS_TIMER_BOT(t->id)) { + t->enamode_shift = 6; + t->tim_off = TIM12; + t->prd_off = PRD12; + irq = dtip[timer].bottom_irq; + } else { + t->enamode_shift = 22; + t->tim_off = TIM34; + t->prd_off = PRD34; + irq = dtip[timer].top_irq; } + + /* Register interrupt */ + t->irqaction.name = t->name; + t->irqaction.dev_id = (void *)t; + if (t->irqaction.handler != NULL) + setup_irq(irq, &t->irqaction); + + timer32_config(&timers[i]); } } @@ -256,7 +242,6 @@ static cycle_t read_cycles(struct clocksource *cs) } static struct clocksource clocksource_davinci = { - .name = "timer0_1", .rating = 300, .read = read_cycles, .mask = CLOCKSOURCE_MASK(32), @@ -301,7 +286,6 @@ static void davinci_set_mode(enum clock_event_mode mode, } static struct clock_event_device clockevent_davinci = { - .name = "timer0_0", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .shift = 32, .set_next_event = davinci_set_next_event, @@ -312,10 +296,14 @@ static struct clock_event_device clockevent_davinci = { static void __init davinci_timer_init(void) { struct clk *timer_clk; + struct davinci_soc_info *soc_info = &davinci_soc_info; static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n"; + timers[TID_CLOCKEVENT].id = soc_info->timer_info->clockevent_id; + timers[TID_CLOCKSOURCE].id = soc_info->timer_info->clocksource_id; + /* init timer hw */ timer_init(); @@ -326,6 +314,7 @@ static void __init davinci_timer_init(void) davinci_clock_tick_rate = clk_get_rate(timer_clk); /* setup clocksource */ + clocksource_davinci.name = id_to_name[timers[TID_CLOCKSOURCE].id]; clocksource_davinci.mult = clocksource_khz2mult(davinci_clock_tick_rate/1000, clocksource_davinci.shift); @@ -333,6 +322,7 @@ static void __init davinci_timer_init(void) printk(err, clocksource_davinci.name); /* setup clockevent */ + clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id]; clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, clockevent_davinci.shift); clockevent_davinci.max_delta_ns =