Message ID | 20110917013531.GB2937@atomide.com |
---|---|
State | New |
Headers | show |
[...] > Well here's what I came up with to deal with the different timer > registers. We can't use the context registers as those are for > the value naturally.. > > But we can map the interrupt registers separately and then have > the rest start from func_base that is different based on the timer > version. Rebasing the rest of the dmtimer hwmod patches on this > should be fairly easy, mostly just need to pass timer instead of > timer->io_base and use __raw_read/write for the interrupt registers. I went through the patch. It definitely looks much more simplified now. I will rebase on top of this change. > > Also, I ended up checking the timer revision with if (!(tidr >> 16)) > as it seems that those bits are zero for v1 timers? If that works, > then we don't need patch 02/12 for the revision number. Right. -- Tarun > > Afzal, care to check if that works for AM335X/TI816X/TI814X? > It tried it briefly with omap4 gptimer3 as the clockevent and > CONFIG_LOCAL_TIMER disabled. > > The patch is against the current cleanup branch in linux-omap > tree. > > Regards, > > Tony > > > From: Tony Lindgren <tony@atomide.com> > Date: Fri, 16 Sep 2011 15:44:20 -0700 > Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip > > The registers are slightly different between v1 and v2 ip that > is available in omap4 and later for some timers. > > Add support for v2 ip by mapping the interrupt related registers > separately and adding func_base for the functional registers. > > Also disable dmtimer driver features on omap4 for now as > those need the hwmod conversion series to deal with enabling > the timers properly in omap_dm_timer_init. > > Signed-off-by: Tony Lindgren <tony@atomide.com> > > diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c > index cf1de7d..21d34fb 100644 > --- a/arch/arm/mach-omap2/timer.c > +++ b/arch/arm/mach-omap2/timer.c > @@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) > { > struct clock_event_device *evt = &clockevent_gpt; > > - __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); > + __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW); > > evt->event_handler(evt); > return IRQ_HANDLED; > @@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = { > static int omap2_gp_timer_set_next_event(unsigned long cycles, > struct clock_event_device *evt) > { > - __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST, > + __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, > 0xffffffff - cycles, 1); > > return 0; > @@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, > { > u32 period; > > - __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate); > + __omap_dm_timer_stop(&clkev, 1, clkev.rate); > > switch (mode) { > case CLOCK_EVT_MODE_PERIODIC: > period = clkev.rate / HZ; > period -= 1; > /* Looks like we need to first set the load value separately */ > - __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG, > + __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, > 0xffffffff - period, 1); > - __omap_dm_timer_load_start(clkev.io_base, > + __omap_dm_timer_load_start(&clkev, > OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, > 0xffffffff - period, 1); > break; > @@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, > } > > omap_hwmod_enable(oh); > + __omap_dm_timer_init_regs(timer); > > sys_timer_reserved |= (1 << (gptimer_id - 1)); > > @@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, > clk_put(src); > } > } > - __omap_dm_timer_reset(timer->io_base, 1, 1); > + __omap_dm_timer_reset(timer, 1, 1); > timer->posted = 1; > > timer->rate = clk_get_rate(timer->fclk); > @@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, > omap2_gp_timer_irq.dev_id = (void *)&clkev; > setup_irq(clkev.irq, &omap2_gp_timer_irq); > > - __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); > + __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); > > clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC, > clockevent_gpt.shift); > @@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc; > static DEFINE_CLOCK_DATA(cd); > static cycle_t clocksource_read_cycles(struct clocksource *cs) > { > - return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1); > + return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1); > } > > static struct clocksource clocksource_gpt = { > @@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void) > { > u32 cyc; > > - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1); > + cyc = __omap_dm_timer_read_counter(&clksrc, 1); > > update_sched_clock(&cd, cyc, (u32)~0); > } > @@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void) > u32 cyc = 0; > > if (clksrc.reserved) > - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1); > + cyc = __omap_dm_timer_read_counter(&clksrc, 1); > > return cyc_to_sched_clock(&cd, cyc, (u32)~0); > } > @@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, > pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", > gptimer_id, clksrc.rate); > > - __omap_dm_timer_load_start(clksrc.io_base, > + __omap_dm_timer_load_start(&clksrc, > OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); > init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate); > > diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c > index 75a847d..e23b7cf 100644 > --- a/arch/arm/plat-omap/dmtimer.c > +++ b/arch/arm/plat-omap/dmtimer.c > @@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock; > */ > static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) > { > - return __omap_dm_timer_read(timer->io_base, reg, timer->posted); > + WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); > + return __omap_dm_timer_read(timer, reg, timer->posted); > } > > /* > @@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) > static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, > u32 value) > { > - __omap_dm_timer_write(timer->io_base, reg, value, timer->posted); > + WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); > + __omap_dm_timer_write(timer, reg, value, timer->posted); > } > > static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) > { > int c; > > + if (!timer->sys_stat) > + return; > + > c = 0; > - while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { > + while (!(__raw_readl(timer->sys_stat) & 1)) { > c++; > if (c > 100000) { > printk(KERN_ERR "Timer failed to reset\n"); > @@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) > if (cpu_class_is_omap2()) > wakeup = 1; > > - __omap_dm_timer_reset(timer->io_base, autoidle, wakeup); > + __omap_dm_timer_reset(timer, autoidle, wakeup); > timer->posted = 1; > } > > @@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer) > rate = clk_get_rate(timer->fclk); > #endif > > - __omap_dm_timer_stop(timer->io_base, timer->posted, rate); > + __omap_dm_timer_stop(timer, timer->posted, rate); > } > EXPORT_SYMBOL_GPL(omap_dm_timer_stop); > > @@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, > } > l |= OMAP_TIMER_CTRL_ST; > > - __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted); > + __omap_dm_timer_load_start(timer, l, load, timer->posted); > } > EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); > > @@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); > void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, > unsigned int value) > { > - __omap_dm_timer_int_enable(timer->io_base, value); > + __omap_dm_timer_int_enable(timer, value); > } > EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); > > @@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) > { > unsigned int l; > > - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); > + l = __raw_readl(timer->irq_stat); > > return l; > } > @@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); > > void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) > { > - __omap_dm_timer_write_status(timer->io_base, value); > + __omap_dm_timer_write_status(timer, value); > } > EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); > > unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) > { > - return __omap_dm_timer_read_counter(timer->io_base, timer->posted); > + return __omap_dm_timer_read_counter(timer, timer->posted); > } > EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); > > @@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void) > dm_timer_count = omap4_dm_timer_count; > dm_source_names = omap4_dm_source_names; > dm_source_clocks = omap4_dm_source_clocks; > + > + pr_err("dmtimers disabled for omap4 until hwmod conversion\n"); > + return -ENODEV; > } > > if (cpu_class_is_omap2()) > @@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void) > if (sys_timer_reserved & (1 << i)) { > timer->reserved = 1; > timer->posted = 1; > + continue; > } > #endif > + omap_dm_timer_enable(timer); > + __omap_dm_timer_init_regs(timer); > + omap_dm_timer_disable(timer); > } > > return 0; > diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h > index eb5d16c..a11d0c0 100644 > --- a/arch/arm/plat-omap/include/plat/dmtimer.h > +++ b/arch/arm/plat-omap/include/plat/dmtimer.h > @@ -98,12 +98,30 @@ int omap_dm_timers_active(void); > * used by dmtimer.c and sys_timer related code. > */ > > -/* register offsets */ > -#define _OMAP_TIMER_ID_OFFSET 0x00 > -#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 > -#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 > -#define _OMAP_TIMER_STAT_OFFSET 0x18 > -#define _OMAP_TIMER_INT_EN_OFFSET 0x1c > +/* > + * The interrupt registers are different between v1 and v2 ip. > + * These registers are offsets from timer->iobase. > + */ > +#define OMAP_TIMER_ID_OFFSET 0x00 > +#define OMAP_TIMER_OCP_CFG_OFFSET 0x10 > + > +#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14 > +#define OMAP_TIMER_V1_STAT_OFFSET 0x18 > +#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c > + > +#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24 > +#define OMAP_TIMER_V2_IRQSTATUS 0x28 > +#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c > +#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30 > + > +/* > + * The functional registers have a different base on v1 and v2 ip. > + * These registers are offsets from timer->func_base. The func_base > + * is samae as io_base for v1 and io_base + 0x14 for v2 ip. > + * > + */ > +#define OMAP_TIMER_V2_FUNC_OFFSET 0x14 > + > #define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 > #define _OMAP_TIMER_CTRL_OFFSET 0x24 > #define OMAP_TIMER_CTRL_GPOCFG (1 << 14) > @@ -147,21 +165,6 @@ int omap_dm_timers_active(void); > /* register offsets with the write pending bit encoded */ > #define WPSHIFT 16 > > -#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \ > - | (WP_NONE << WPSHIFT)) > - > -#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ > - | (WP_NONE << WPSHIFT)) > - > -#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ > - | (WP_NONE << WPSHIFT)) > - > -#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ > - | (WP_NONE << WPSHIFT)) > - > -#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ > - | (WP_NONE << WPSHIFT)) > - > #define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ > | (WP_NONE << WPSHIFT)) > > @@ -213,7 +216,14 @@ struct omap_dm_timer { > #ifdef CONFIG_ARCH_OMAP2PLUS > struct clk *iclk, *fclk; > #endif > - void __iomem *io_base; > + void __iomem *io_base; > + void __iomem *sys_stat; /* TISTAT timer status */ > + void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ > + void __iomem *irq_ena; /* irq enable */ > + void __iomem *irq_dis; /* irq disable, only on v2 ip */ > + void __iomem *pend; /* write pending */ > + void __iomem *func_base; /* function register base */ > + > unsigned long rate; > unsigned reserved:1; > unsigned enabled:1; > @@ -223,35 +233,57 @@ struct omap_dm_timer { > extern u32 sys_timer_reserved; > void omap_dm_timer_prepare(struct omap_dm_timer *timer); > > -static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg, > +static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, > int posted) > { > if (posted) > - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) > - & (reg >> WPSHIFT)) > + while (__raw_readl(timer->pend) & (reg >> WPSHIFT)) > cpu_relax(); > > - return __raw_readl(base + (reg & 0xff)); > + return __raw_readl(timer->func_base + (reg & 0xff)); > } > > -static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val, > - int posted) > +static inline void __omap_dm_timer_write(struct omap_dm_timer *timer, > + u32 reg, u32 val, int posted) > { > if (posted) > - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) > - & (reg >> WPSHIFT)) > + while (__raw_readl(timer->pend) & (reg >> WPSHIFT)) > cpu_relax(); > > - __raw_writel(val, base + (reg & 0xff)); > + __raw_writel(val, timer->func_base + (reg & 0xff)); > +} > + > +static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) > +{ > + u32 tidr; > + > + /* Assume v1 ip if bits [31:16] are zero */ > + tidr = __raw_readl(timer->io_base); > + if (!(tidr >> 16)) { > + timer->sys_stat = timer->io_base + OMAP_TIMER_V1_SYS_STAT_OFFSET; > + timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; > + timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; > + timer->irq_dis = 0; > + timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; > + timer->func_base = timer->io_base; > + } else { > + timer->sys_stat = 0; > + timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; > + timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; > + timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; > + timer->pend = timer->io_base + > + _OMAP_TIMER_WRITE_PEND_OFFSET + OMAP_TIMER_V2_FUNC_OFFSET; > + timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET; > + } > } > > /* Assumes the source clock has been set by caller */ > -static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, > - int wakeup) > +static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, > + int autoidle, int wakeup) > { > u32 l; > > - l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0); > + l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); > l |= 0x02 << 3; /* Set to smart-idle mode */ > l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ > > @@ -261,10 +293,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, > if (wakeup) > l |= 1 << 2; > > - __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0); > + __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); > > /* Match hardware reset default of posted mode */ > - __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG, > + __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, > OMAP_TIMER_CTRL_POSTED, 0); > } > > @@ -286,18 +318,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck, > return ret; > } > > -static inline void __omap_dm_timer_stop(void __iomem *base, int posted, > - unsigned long rate) > +static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, > + int posted, unsigned long rate) > { > u32 l; > > - l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); > + l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); > if (l & OMAP_TIMER_CTRL_ST) { > l &= ~0x1; > - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted); > + __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted); > #ifdef CONFIG_ARCH_OMAP2PLUS > /* Readback to make sure write has completed */ > - __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); > + __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); > /* > * Wait for functional clock period x 3.5 to make sure that > * timer is stopped > @@ -307,34 +339,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted, > } > > /* Ack possibly pending interrupt */ > - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, > - OMAP_TIMER_INT_OVERFLOW, 0); > + __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat); > } > > -static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl, > - unsigned int load, int posted) > +static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer, > + u32 ctrl, unsigned int load, > + int posted) > { > - __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted); > - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted); > + __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted); > + __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted); > } > > -static inline void __omap_dm_timer_int_enable(void __iomem *base, > +static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer, > unsigned int value) > { > - __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0); > - __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0); > + __raw_writel(value, timer->irq_ena); > + __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0); > } > > -static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base, > - int posted) > +static inline unsigned int > +__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted) > { > - return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted); > + return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted); > } > > -static inline void __omap_dm_timer_write_status(void __iomem *base, > +static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer, > unsigned int value) > { > - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0); > + __raw_writel(value, timer->irq_stat); > } > > #endif /* __ASM_ARCH_DMTIMER_H */ >
Tony Lindgren wrote on Saturday, September 17, 2011 7:06 AM: > device driver) > > * DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110916 01:56]: >> [...] > > Afzal, care to check if that works for AM335X/TI816X/TI814X? > It tried it briefly with omap4 gptimer3 as the clockevent and > CONFIG_LOCAL_TIMER disabled. > > The patch is against the current cleanup branch in linux-omap > tree. > > Regards, > > Tony > > > From: Tony Lindgren <tony@atomide.com> > Date: Fri, 16 Sep 2011 15:44:20 -0700 > Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip > [...] Tony, Kernel boots fine on TI816X (should also boot on TI814X) with your patch and patches (including OSC clock fix) from series http://www.spinics.net/lists/linux-omap/msg57011.html Thanks. Hemant
* Pedanekar, Hemant <hemantp@ti.com> [110918 20:32]: > > Tony, > Kernel boots fine on TI816X (should also boot on TI814X) with your patch > and patches (including OSC clock fix) from series > http://www.spinics.net/lists/linux-omap/msg57011.html OK good to hear, I assume I can add your Tested-by then? Regards, Tony
* DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110918 04:53]: > > > > But we can map the interrupt registers separately and then have > > the rest start from func_base that is different based on the timer > > version. Rebasing the rest of the dmtimer hwmod patches on this > > should be fairly easy, mostly just need to pass timer instead of > > timer->io_base and use __raw_read/write for the interrupt registers. > I went through the patch. It definitely looks much more simplified now. > I will rebase on top of this change. OK thanks, can I add your Acked-by then? Tony
* Mohammed, Afzal <afzal@ti.com> [110918 21:48]: > Hi Tony, > > On Sat, Sep 17, 2011 at 07:05:31, Tony Lindgren wrote: > > > > Afzal, care to check if that works for AM335X/TI816X/TI814X? > > With following patch over yours, AM335X (the only board with me) boots up fine. Thanks for catching that, will fold it in with your Signed-off-by. Regards, Tony
Tony Lindgren wrote on Monday, September 19, 2011 11:11 PM: > device driver) > > * Pedanekar, Hemant <hemantp@ti.com> [110918 20:32]: >> >> Tony, >> Kernel boots fine on TI816X (should also boot on TI814X) with your patch >> and patches (including OSC clock fix) from series >> http://www.spinics.net/lists/linux-omap/msg57011.html > > OK good to hear, I assume I can add your Tested-by then? > > Regards, > > Tony Yes. Thanks. Hemant
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index cf1de7d..21d34fb 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_gpt; - __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); + __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW); evt->event_handler(evt); return IRQ_HANDLED; @@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = { static int omap2_gp_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST, + __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, 0xffffffff - cycles, 1); return 0; @@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, { u32 period; - __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate); + __omap_dm_timer_stop(&clkev, 1, clkev.rate); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: period = clkev.rate / HZ; period -= 1; /* Looks like we need to first set the load value separately */ - __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG, + __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, 0xffffffff - period, 1); - __omap_dm_timer_load_start(clkev.io_base, + __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, 0xffffffff - period, 1); break; @@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, } omap_hwmod_enable(oh); + __omap_dm_timer_init_regs(timer); sys_timer_reserved |= (1 << (gptimer_id - 1)); @@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, clk_put(src); } } - __omap_dm_timer_reset(timer->io_base, 1, 1); + __omap_dm_timer_reset(timer, 1, 1); timer->posted = 1; timer->rate = clk_get_rate(timer->fclk); @@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, omap2_gp_timer_irq.dev_id = (void *)&clkev; setup_irq(clkev.irq, &omap2_gp_timer_irq); - __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); + __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC, clockevent_gpt.shift); @@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc; static DEFINE_CLOCK_DATA(cd); static cycle_t clocksource_read_cycles(struct clocksource *cs) { - return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1); + return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1); } static struct clocksource clocksource_gpt = { @@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void) { u32 cyc; - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1); + cyc = __omap_dm_timer_read_counter(&clksrc, 1); update_sched_clock(&cd, cyc, (u32)~0); } @@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void) u32 cyc = 0; if (clksrc.reserved) - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1); + cyc = __omap_dm_timer_read_counter(&clksrc, 1); return cyc_to_sched_clock(&cd, cyc, (u32)~0); } @@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", gptimer_id, clksrc.rate); - __omap_dm_timer_load_start(clksrc.io_base, + __omap_dm_timer_load_start(&clksrc, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 75a847d..e23b7cf 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock; */ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) { - return __omap_dm_timer_read(timer->io_base, reg, timer->posted); + WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); + return __omap_dm_timer_read(timer, reg, timer->posted); } /* @@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, u32 value) { - __omap_dm_timer_write(timer->io_base, reg, value, timer->posted); + WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); + __omap_dm_timer_write(timer, reg, value, timer->posted); } static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) { int c; + if (!timer->sys_stat) + return; + c = 0; - while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { + while (!(__raw_readl(timer->sys_stat) & 1)) { c++; if (c > 100000) { printk(KERN_ERR "Timer failed to reset\n"); @@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) if (cpu_class_is_omap2()) wakeup = 1; - __omap_dm_timer_reset(timer->io_base, autoidle, wakeup); + __omap_dm_timer_reset(timer, autoidle, wakeup); timer->posted = 1; } @@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer) rate = clk_get_rate(timer->fclk); #endif - __omap_dm_timer_stop(timer->io_base, timer->posted, rate); + __omap_dm_timer_stop(timer, timer->posted, rate); } EXPORT_SYMBOL_GPL(omap_dm_timer_stop); @@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, } l |= OMAP_TIMER_CTRL_ST; - __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted); + __omap_dm_timer_load_start(timer, l, load, timer->posted); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); @@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_int_enable(timer->io_base, value); + __omap_dm_timer_int_enable(timer, value); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); @@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { unsigned int l; - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); + l = __raw_readl(timer->irq_stat); return l; } @@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_write_status(timer->io_base, value); + __omap_dm_timer_write_status(timer, value); } EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - return __omap_dm_timer_read_counter(timer->io_base, timer->posted); + return __omap_dm_timer_read_counter(timer, timer->posted); } EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); @@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void) dm_timer_count = omap4_dm_timer_count; dm_source_names = omap4_dm_source_names; dm_source_clocks = omap4_dm_source_clocks; + + pr_err("dmtimers disabled for omap4 until hwmod conversion\n"); + return -ENODEV; } if (cpu_class_is_omap2()) @@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void) if (sys_timer_reserved & (1 << i)) { timer->reserved = 1; timer->posted = 1; + continue; } #endif + omap_dm_timer_enable(timer); + __omap_dm_timer_init_regs(timer); + omap_dm_timer_disable(timer); } return 0; diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index eb5d16c..a11d0c0 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -98,12 +98,30 @@ int omap_dm_timers_active(void); * used by dmtimer.c and sys_timer related code. */ -/* register offsets */ -#define _OMAP_TIMER_ID_OFFSET 0x00 -#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 -#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 -#define _OMAP_TIMER_STAT_OFFSET 0x18 -#define _OMAP_TIMER_INT_EN_OFFSET 0x1c +/* + * The interrupt registers are different between v1 and v2 ip. + * These registers are offsets from timer->iobase. + */ +#define OMAP_TIMER_ID_OFFSET 0x00 +#define OMAP_TIMER_OCP_CFG_OFFSET 0x10 + +#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14 +#define OMAP_TIMER_V1_STAT_OFFSET 0x18 +#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c + +#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24 +#define OMAP_TIMER_V2_IRQSTATUS 0x28 +#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c +#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30 + +/* + * The functional registers have a different base on v1 and v2 ip. + * These registers are offsets from timer->func_base. The func_base + * is samae as io_base for v1 and io_base + 0x14 for v2 ip. + * + */ +#define OMAP_TIMER_V2_FUNC_OFFSET 0x14 + #define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 #define _OMAP_TIMER_CTRL_OFFSET 0x24 #define OMAP_TIMER_CTRL_GPOCFG (1 << 14) @@ -147,21 +165,6 @@ int omap_dm_timers_active(void); /* register offsets with the write pending bit encoded */ #define WPSHIFT 16 -#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ - | (WP_NONE << WPSHIFT)) - #define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ | (WP_NONE << WPSHIFT)) @@ -213,7 +216,14 @@ struct omap_dm_timer { #ifdef CONFIG_ARCH_OMAP2PLUS struct clk *iclk, *fclk; #endif - void __iomem *io_base; + void __iomem *io_base; + void __iomem *sys_stat; /* TISTAT timer status */ + void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ + void __iomem *irq_ena; /* irq enable */ + void __iomem *irq_dis; /* irq disable, only on v2 ip */ + void __iomem *pend; /* write pending */ + void __iomem *func_base; /* function register base */ + unsigned long rate; unsigned reserved:1; unsigned enabled:1; @@ -223,35 +233,57 @@ struct omap_dm_timer { extern u32 sys_timer_reserved; void omap_dm_timer_prepare(struct omap_dm_timer *timer); -static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg, +static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, int posted) { if (posted) - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) - & (reg >> WPSHIFT)) + while (__raw_readl(timer->pend) & (reg >> WPSHIFT)) cpu_relax(); - return __raw_readl(base + (reg & 0xff)); + return __raw_readl(timer->func_base + (reg & 0xff)); } -static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val, - int posted) +static inline void __omap_dm_timer_write(struct omap_dm_timer *timer, + u32 reg, u32 val, int posted) { if (posted) - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) - & (reg >> WPSHIFT)) + while (__raw_readl(timer->pend) & (reg >> WPSHIFT)) cpu_relax(); - __raw_writel(val, base + (reg & 0xff)); + __raw_writel(val, timer->func_base + (reg & 0xff)); +} + +static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) +{ + u32 tidr; + + /* Assume v1 ip if bits [31:16] are zero */ + tidr = __raw_readl(timer->io_base); + if (!(tidr >> 16)) { + timer->sys_stat = timer->io_base + OMAP_TIMER_V1_SYS_STAT_OFFSET; + timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; + timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; + timer->irq_dis = 0; + timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; + timer->func_base = timer->io_base; + } else { + timer->sys_stat = 0; + timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; + timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; + timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; + timer->pend = timer->io_base + + _OMAP_TIMER_WRITE_PEND_OFFSET + OMAP_TIMER_V2_FUNC_OFFSET; + timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET; + } } /* Assumes the source clock has been set by caller */ -static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, - int wakeup) +static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, + int autoidle, int wakeup) { u32 l; - l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0); + l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); l |= 0x02 << 3; /* Set to smart-idle mode */ l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ @@ -261,10 +293,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, if (wakeup) l |= 1 << 2; - __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0); + __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); /* Match hardware reset default of posted mode */ - __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG, + __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, OMAP_TIMER_CTRL_POSTED, 0); } @@ -286,18 +318,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck, return ret; } -static inline void __omap_dm_timer_stop(void __iomem *base, int posted, - unsigned long rate) +static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, + int posted, unsigned long rate) { u32 l; - l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); + l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); if (l & OMAP_TIMER_CTRL_ST) { l &= ~0x1; - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted); + __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted); #ifdef CONFIG_ARCH_OMAP2PLUS /* Readback to make sure write has completed */ - __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); + __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); /* * Wait for functional clock period x 3.5 to make sure that * timer is stopped @@ -307,34 +339,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted, } /* Ack possibly pending interrupt */ - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, - OMAP_TIMER_INT_OVERFLOW, 0); + __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat); } -static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl, - unsigned int load, int posted) +static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer, + u32 ctrl, unsigned int load, + int posted) { - __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted); - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted); + __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted); + __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted); } -static inline void __omap_dm_timer_int_enable(void __iomem *base, +static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0); - __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0); + __raw_writel(value, timer->irq_ena); + __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0); } -static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base, - int posted) +static inline unsigned int +__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted) { - return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted); + return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted); } -static inline void __omap_dm_timer_write_status(void __iomem *base, +static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0); + __raw_writel(value, timer->irq_stat); } #endif /* __ASM_ARCH_DMTIMER_H */