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, 70 insertions, 73 deletions
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 3f5b9cfd9c0b..a3fbc48c332e 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |||
| @@ -32,7 +32,6 @@ | |||
| 32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 32 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | #include <linux/clk.h> | ||
| 36 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
| 37 | #include <linux/io.h> | 36 | #include <linux/io.h> |
| 38 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
| @@ -55,6 +54,10 @@ | |||
| 55 | #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 | 54 | #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 |
| 56 | #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 | 55 | #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 |
| 57 | 56 | ||
| 57 | /* posted mode types */ | ||
| 58 | #define OMAP_TIMER_NONPOSTED 0x00 | ||
| 59 | #define OMAP_TIMER_POSTED 0x01 | ||
| 60 | |||
| 58 | /* timer capabilities used in hwmod database */ | 61 | /* timer capabilities used in hwmod database */ |
| 59 | #define OMAP_TIMER_SECURE 0x80000000 | 62 | #define OMAP_TIMER_SECURE 0x80000000 |
| 60 | #define OMAP_TIMER_ALWON 0x40000000 | 63 | #define OMAP_TIMER_ALWON 0x40000000 |
| @@ -62,16 +65,22 @@ | |||
| 62 | #define OMAP_TIMER_NEEDS_RESET 0x10000000 | 65 | #define OMAP_TIMER_NEEDS_RESET 0x10000000 |
| 63 | #define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 | 66 | #define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 |
| 64 | 67 | ||
| 68 | /* | ||
| 69 | * timer errata flags | ||
| 70 | * | ||
| 71 | * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This | ||
| 72 | * errata prevents us from using posted mode on these devices, unless the | ||
| 73 | * timer counter register is never read. For more details please refer to | ||
| 74 | * the OMAP3/4/5 errata documents. | ||
| 75 | */ | ||
| 76 | #define OMAP_TIMER_ERRATA_I103_I767 0x80000000 | ||
| 77 | |||
| 65 | struct omap_timer_capability_dev_attr { | 78 | struct omap_timer_capability_dev_attr { |
| 66 | u32 timer_capability; | 79 | u32 timer_capability; |
| 67 | }; | 80 | }; |
| 68 | 81 | ||
| 69 | struct omap_dm_timer; | ||
| 70 | |||
| 71 | struct timer_regs { | 82 | struct timer_regs { |
| 72 | u32 tidr; | 83 | u32 tidr; |
| 73 | u32 tistat; | ||
| 74 | u32 tisr; | ||
| 75 | u32 tier; | 84 | u32 tier; |
| 76 | u32 twer; | 85 | u32 twer; |
| 77 | u32 tclr; | 86 | u32 tclr; |
| @@ -90,16 +99,35 @@ struct timer_regs { | |||
| 90 | u32 towr; | 99 | u32 towr; |
| 91 | }; | 100 | }; |
| 92 | 101 | ||
| 93 | struct dmtimer_platform_data { | 102 | struct omap_dm_timer { |
| 94 | /* set_timer_src - Only used for OMAP1 devices */ | 103 | int id; |
| 95 | int (*set_timer_src)(struct platform_device *pdev, int source); | 104 | int irq; |
| 96 | u32 timer_capability; | 105 | struct clk *fclk; |
| 106 | |||
| 107 | void __iomem *io_base; | ||
| 108 | void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ | ||
| 109 | void __iomem *irq_ena; /* irq enable */ | ||
| 110 | void __iomem *irq_dis; /* irq disable, only on v2 ip */ | ||
| 111 | void __iomem *pend; /* write pending */ | ||
| 112 | void __iomem *func_base; /* function register base */ | ||
| 113 | |||
| 114 | unsigned long rate; | ||
| 115 | unsigned reserved:1; | ||
| 116 | unsigned posted:1; | ||
| 117 | struct timer_regs context; | ||
| 97 | int (*get_context_loss_count)(struct device *); | 118 | int (*get_context_loss_count)(struct device *); |
| 119 | int ctx_loss_count; | ||
| 120 | int revision; | ||
| 121 | u32 capability; | ||
| 122 | u32 errata; | ||
| 123 | struct platform_device *pdev; | ||
| 124 | struct list_head node; | ||
| 98 | }; | 125 | }; |
| 99 | 126 | ||
| 100 | int omap_dm_timer_reserve_systimer(int id); | 127 | int omap_dm_timer_reserve_systimer(int id); |
| 101 | struct omap_dm_timer *omap_dm_timer_request(void); | 128 | struct omap_dm_timer *omap_dm_timer_request(void); |
| 102 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); | 129 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); |
| 130 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); | ||
| 103 | int omap_dm_timer_free(struct omap_dm_timer *timer); | 131 | int omap_dm_timer_free(struct omap_dm_timer *timer); |
| 104 | void omap_dm_timer_enable(struct omap_dm_timer *timer); | 132 | void omap_dm_timer_enable(struct omap_dm_timer *timer); |
| 105 | void omap_dm_timer_disable(struct omap_dm_timer *timer); | 133 | void omap_dm_timer_disable(struct omap_dm_timer *timer); |
| @@ -121,6 +149,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, i | |||
| 121 | int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); | 149 | int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); |
| 122 | 150 | ||
| 123 | int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); | 151 | int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); |
| 152 | int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask); | ||
| 124 | 153 | ||
| 125 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); | 154 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); |
| 126 | int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); | 155 | int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); |
| @@ -246,34 +275,6 @@ int omap_dm_timers_active(void); | |||
| 246 | #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ | 275 | #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ |
| 247 | (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) | 276 | (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) |
| 248 | 277 | ||
| 249 | struct omap_dm_timer { | ||
| 250 | unsigned long phys_base; | ||
| 251 | int id; | ||
| 252 | int irq; | ||
| 253 | struct clk *fclk; | ||
| 254 | |||
| 255 | void __iomem *io_base; | ||
| 256 | void __iomem *sys_stat; /* TISTAT timer status */ | ||
| 257 | void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ | ||
| 258 | void __iomem *irq_ena; /* irq enable */ | ||
| 259 | void __iomem *irq_dis; /* irq disable, only on v2 ip */ | ||
| 260 | void __iomem *pend; /* write pending */ | ||
| 261 | void __iomem *func_base; /* function register base */ | ||
| 262 | |||
| 263 | unsigned long rate; | ||
| 264 | unsigned reserved:1; | ||
| 265 | unsigned posted:1; | ||
| 266 | struct timer_regs context; | ||
| 267 | int (*get_context_loss_count)(struct device *); | ||
| 268 | int ctx_loss_count; | ||
| 269 | int revision; | ||
| 270 | u32 capability; | ||
| 271 | struct platform_device *pdev; | ||
| 272 | struct list_head node; | ||
| 273 | }; | ||
| 274 | |||
| 275 | int omap_dm_timer_prepare(struct omap_dm_timer *timer); | ||
| 276 | |||
| 277 | static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, | 278 | static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, |
| 278 | int posted) | 279 | int posted) |
| 279 | { | 280 | { |
| @@ -302,16 +303,13 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) | |||
| 302 | tidr = __raw_readl(timer->io_base); | 303 | tidr = __raw_readl(timer->io_base); |
| 303 | if (!(tidr >> 16)) { | 304 | if (!(tidr >> 16)) { |
| 304 | timer->revision = 1; | 305 | timer->revision = 1; |
| 305 | timer->sys_stat = timer->io_base + | ||
| 306 | OMAP_TIMER_V1_SYS_STAT_OFFSET; | ||
| 307 | timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; | 306 | timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; |
| 308 | timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; | 307 | timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; |
| 309 | timer->irq_dis = NULL; | 308 | timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; |
| 310 | timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; | 309 | timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; |
| 311 | timer->func_base = timer->io_base; | 310 | timer->func_base = timer->io_base; |
| 312 | } else { | 311 | } else { |
| 313 | timer->revision = 2; | 312 | timer->revision = 2; |
| 314 | timer->sys_stat = NULL; | ||
| 315 | timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; | 313 | timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; |
| 316 | timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; | 314 | timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; |
| 317 | timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; | 315 | timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; |
| @@ -322,45 +320,44 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) | |||
| 322 | } | 320 | } |
| 323 | } | 321 | } |
| 324 | 322 | ||
| 325 | /* Assumes the source clock has been set by caller */ | 323 | /* |
| 326 | static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, | 324 | * __omap_dm_timer_enable_posted - enables write posted mode |
| 327 | int autoidle, int wakeup) | 325 | * @timer: pointer to timer instance handle |
| 326 | * | ||
| 327 | * Enables the write posted mode for the timer. When posted mode is enabled | ||
| 328 | * writes to certain timer registers are immediately acknowledged by the | ||
| 329 | * internal bus and hence prevents stalling the CPU waiting for the write to | ||
| 330 | * complete. Enabling this feature can improve performance for writing to the | ||
| 331 | * timer registers. | ||
| 332 | */ | ||
| 333 | static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) | ||
| 328 | { | 334 | { |
| 329 | u32 l; | 335 | if (timer->posted) |
| 336 | return; | ||
| 330 | 337 | ||
| 331 | l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); | 338 | if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) |
| 332 | l |= 0x02 << 3; /* Set to smart-idle mode */ | 339 | return; |
| 333 | l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ | ||
| 334 | 340 | ||
| 335 | if (autoidle) | ||
| 336 | l |= 0x1 << 0; | ||
| 337 | |||
| 338 | if (wakeup) | ||
| 339 | l |= 1 << 2; | ||
| 340 | |||
| 341 | __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); | ||
| 342 | |||
| 343 | /* Match hardware reset default of posted mode */ | ||
| 344 | __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, | 341 | __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, |
| 345 | OMAP_TIMER_CTRL_POSTED, 0); | 342 | OMAP_TIMER_CTRL_POSTED, 0); |
| 343 | timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; | ||
| 344 | timer->posted = OMAP_TIMER_POSTED; | ||
| 346 | } | 345 | } |
| 347 | 346 | ||
| 348 | static inline int __omap_dm_timer_set_source(struct clk *timer_fck, | 347 | /** |
| 349 | struct clk *parent) | 348 | * __omap_dm_timer_override_errata - override errata flags for a timer |
| 349 | * @timer: pointer to timer handle | ||
| 350 | * @errata: errata flags to be ignored | ||
| 351 | * | ||
| 352 | * For a given timer, override a timer errata by clearing the flags | ||
| 353 | * specified by the errata argument. A specific erratum should only be | ||
| 354 | * overridden for a timer if the timer is used in such a way the erratum | ||
| 355 | * has no impact. | ||
| 356 | */ | ||
| 357 | static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, | ||
| 358 | u32 errata) | ||
| 350 | { | 359 | { |
| 351 | int ret; | 360 | timer->errata &= ~errata; |
| 352 | |||
| 353 | clk_disable(timer_fck); | ||
| 354 | ret = clk_set_parent(timer_fck, parent); | ||
| 355 | clk_enable(timer_fck); | ||
| 356 | |||
| 357 | /* | ||
| 358 | * When the functional clock disappears, too quick writes seem | ||
| 359 | * to cause an abort. XXX Is this still necessary? | ||
| 360 | */ | ||
| 361 | __delay(300000); | ||
| 362 | |||
| 363 | return ret; | ||
| 364 | } | 361 | } |
| 365 | 362 | ||
| 366 | static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, | 363 | static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, |
