diff options
Diffstat (limited to 'drivers/clocksource/timer-ti-dm.c')
| -rw-r--r-- | drivers/clocksource/timer-ti-dm.c | 123 | 
1 files changed, 123 insertions, 0 deletions
| diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index c194e8f74e1d..469f7c91564b 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -44,6 +44,121 @@ enum {  	REQUEST_BY_NODE,  }; +static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, +						int posted) +{ +	if (posted) +		while (readl_relaxed(timer->pend) & (reg >> WPSHIFT)) +			cpu_relax(); + +	return readl_relaxed(timer->func_base + (reg & 0xff)); +} + +static inline void __omap_dm_timer_write(struct omap_dm_timer *timer, +					u32 reg, u32 val, int posted) +{ +	if (posted) +		while (readl_relaxed(timer->pend) & (reg >> WPSHIFT)) +			cpu_relax(); + +	writel_relaxed(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 = readl_relaxed(timer->io_base); +	if (!(tidr >> 16)) { +		timer->revision = 1; +		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 = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; +		timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; +		timer->func_base = timer->io_base; +	} else { +		timer->revision = 2; +		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; +	} +} + +/* + * __omap_dm_timer_enable_posted - enables write posted mode + * @timer:      pointer to timer instance handle + * + * Enables the write posted mode for the timer. When posted mode is enabled + * writes to certain timer registers are immediately acknowledged by the + * internal bus and hence prevents stalling the CPU waiting for the write to + * complete. Enabling this feature can improve performance for writing to the + * timer registers. + */ +static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) +{ +	if (timer->posted) +		return; + +	if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) { +		timer->posted = OMAP_TIMER_NONPOSTED; +		__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0); +		return; +	} + +	__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, +			      OMAP_TIMER_CTRL_POSTED, 0); +	timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; +	timer->posted = OMAP_TIMER_POSTED; +} + +static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, +					int posted, unsigned long rate) +{ +	u32 l; + +	l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); +	if (l & OMAP_TIMER_CTRL_ST) { +		l &= ~0x1; +		__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(timer, OMAP_TIMER_CTRL_REG, posted); +		/* +		 * Wait for functional clock period x 3.5 to make sure that +		 * timer is stopped +		 */ +		udelay(3500000 / rate + 1); +#endif +	} + +	/* Ack possibly pending interrupt */ +	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat); +} + +static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer, +						unsigned int value) +{ +	writel_relaxed(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(struct omap_dm_timer *timer, int posted) +{ +	return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted); +} + +static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer, +						unsigned int value) +{ +	writel_relaxed(value, timer->irq_stat); +} +  /**   * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode   * @timer:      timer pointer over which read operation to perform @@ -921,6 +1036,10 @@ static const struct dmtimer_platform_data omap3plus_pdata = {  	.timer_ops = &dmtimer_ops,  }; +static const struct dmtimer_platform_data am6_pdata = { +	.timer_ops = &dmtimer_ops, +}; +  static const struct of_device_id omap_timer_match[] = {  	{  		.compatible = "ti,omap2420-timer", @@ -949,6 +1068,10 @@ static const struct of_device_id omap_timer_match[] = {  		.compatible = "ti,dm816-timer",  		.data = &omap3plus_pdata,  	}, +	{ +		.compatible = "ti,am654-timer", +		.data = &am6_pdata, +	},  	{},  };  MODULE_DEVICE_TABLE(of, omap_timer_match); |