diff options
Diffstat (limited to 'arch/arm/plat-omap/include/plat/dmtimer.h')
| -rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 143 | 
1 files changed, 71 insertions, 72 deletions
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 85868e98c11..a3fbc48c332 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -32,7 +32,6 @@   * 675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include <linux/clk.h>  #include <linux/delay.h>  #include <linux/io.h>  #include <linux/platform_device.h> @@ -55,6 +54,10 @@  #define OMAP_TIMER_TRIGGER_OVERFLOW		0x01  #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE	0x02 +/* posted mode types */ +#define OMAP_TIMER_NONPOSTED			0x00 +#define OMAP_TIMER_POSTED			0x01 +  /* timer capabilities used in hwmod database */  #define OMAP_TIMER_SECURE				0x80000000  #define OMAP_TIMER_ALWON				0x40000000 @@ -62,16 +65,22 @@  #define OMAP_TIMER_NEEDS_RESET				0x10000000  #define OMAP_TIMER_HAS_DSP_IRQ				0x08000000 +/* + * timer errata flags + * + * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This + * errata prevents us from using posted mode on these devices, unless the + * timer counter register is never read. For more details please refer to + * the OMAP3/4/5 errata documents. + */ +#define OMAP_TIMER_ERRATA_I103_I767			0x80000000 +  struct omap_timer_capability_dev_attr {  	u32 timer_capability;  }; -struct omap_dm_timer; -  struct timer_regs {  	u32 tidr; -	u32 tistat; -	u32 tisr;  	u32 tier;  	u32 twer;  	u32 tclr; @@ -90,15 +99,35 @@ struct timer_regs {  	u32 towr;  }; -struct dmtimer_platform_data { -	/* set_timer_src - Only used for OMAP1 devices */ -	int (*set_timer_src)(struct platform_device *pdev, int source); -	u32 timer_capability; +struct omap_dm_timer { +	int id; +	int irq; +	struct clk *fclk; + +	void __iomem	*io_base; +	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 posted:1; +	struct timer_regs context; +	int (*get_context_loss_count)(struct device *); +	int ctx_loss_count; +	int revision; +	u32 capability; +	u32 errata; +	struct platform_device *pdev; +	struct list_head node;  };  int omap_dm_timer_reserve_systimer(int id);  struct omap_dm_timer *omap_dm_timer_request(void);  struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); +struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);  int omap_dm_timer_free(struct omap_dm_timer *timer);  void omap_dm_timer_enable(struct omap_dm_timer *timer);  void omap_dm_timer_disable(struct omap_dm_timer *timer); @@ -120,6 +149,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, i  int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);  int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); +int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);  unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);  int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); @@ -245,33 +275,6 @@ int omap_dm_timers_active(void);  #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG				\  		(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) -struct omap_dm_timer { -	unsigned long phys_base; -	int id; -	int irq; -	struct clk *fclk; - -	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 posted:1; -	struct timer_regs context; -	int ctx_loss_count; -	int revision; -	u32 capability; -	struct platform_device *pdev; -	struct list_head node; -}; - -int omap_dm_timer_prepare(struct omap_dm_timer *timer); -  static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,  						int posted)  { @@ -300,16 +303,13 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)  	tidr = __raw_readl(timer->io_base);  	if (!(tidr >> 16)) {  		timer->revision = 1; -		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 = NULL; +		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->sys_stat = NULL;  		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; @@ -320,45 +320,44 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)  	}  } -/* Assumes the source clock has been set by caller */ -static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, -					int autoidle, int wakeup) +/* + * __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)  { -	u32 l; +	if (timer->posted) +		return; -	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 */ +	if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) +		return; -	if (autoidle) -		l |= 0x1 << 0; - -	if (wakeup) -		l |= 1 << 2; - -	__raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); - -	/* Match hardware reset default of posted mode */  	__omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, -					OMAP_TIMER_CTRL_POSTED, 0); +			      OMAP_TIMER_CTRL_POSTED, 0); +	timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; +	timer->posted = OMAP_TIMER_POSTED;  } -static inline int __omap_dm_timer_set_source(struct clk *timer_fck, -						struct clk *parent) +/** + * __omap_dm_timer_override_errata - override errata flags for a timer + * @timer:      pointer to timer handle + * @errata:	errata flags to be ignored + * + * For a given timer, override a timer errata by clearing the flags + * specified by the errata argument. A specific erratum should only be + * overridden for a timer if the timer is used in such a way the erratum + * has no impact. + */ +static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, +						   u32 errata)  { -	int ret; - -	clk_disable(timer_fck); -	ret = clk_set_parent(timer_fck, parent); -	clk_enable(timer_fck); - -	/* -	 * When the functional clock disappears, too quick writes seem -	 * to cause an abort. XXX Is this still necessary? -	 */ -	__delay(300000); - -	return ret; +	timer->errata &= ~errata;  }  static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,  |