linux/arch/arm/plat-omap/include/plat/dmtimer.h
<<
>>
Prefs
   1/*
   2 * arch/arm/plat-omap/include/plat/dmtimer.h
   3 *
   4 * OMAP Dual-Mode Timers
   5 *
   6 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
   7 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
   8 * Thara Gopinath <thara@ti.com>
   9 *
  10 * Platform device conversion and hwmod support.
  11 *
  12 * Copyright (C) 2005 Nokia Corporation
  13 * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
  14 * PWM and clock framwork support by Timo Teras.
  15 *
  16 * This program is free software; you can redistribute it and/or modify it
  17 * under the terms of the GNU General Public License as published by the
  18 * Free Software Foundation; either version 2 of the License, or (at your
  19 * option) any later version.
  20 *
  21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  24 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29 *
  30 * You should have received a copy of the  GNU General Public License along
  31 * with this program; if not, write  to the Free Software Foundation, Inc.,
  32 * 675 Mass Ave, Cambridge, MA 02139, USA.
  33 */
  34
  35#include <linux/clk.h>
  36#include <linux/delay.h>
  37#include <linux/io.h>
  38#include <linux/platform_device.h>
  39
  40#ifndef __ASM_ARCH_DMTIMER_H
  41#define __ASM_ARCH_DMTIMER_H
  42
  43/* clock sources */
  44#define OMAP_TIMER_SRC_SYS_CLK                  0x00
  45#define OMAP_TIMER_SRC_32_KHZ                   0x01
  46#define OMAP_TIMER_SRC_EXT_CLK                  0x02
  47
  48/* timer interrupt enable bits */
  49#define OMAP_TIMER_INT_CAPTURE                  (1 << 2)
  50#define OMAP_TIMER_INT_OVERFLOW                 (1 << 1)
  51#define OMAP_TIMER_INT_MATCH                    (1 << 0)
  52
  53/* trigger types */
  54#define OMAP_TIMER_TRIGGER_NONE                 0x00
  55#define OMAP_TIMER_TRIGGER_OVERFLOW             0x01
  56#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
  57
  58/* timer capabilities used in hwmod database */
  59#define OMAP_TIMER_SECURE                               0x80000000
  60#define OMAP_TIMER_ALWON                                0x40000000
  61#define OMAP_TIMER_HAS_PWM                              0x20000000
  62#define OMAP_TIMER_NEEDS_RESET                          0x10000000
  63#define OMAP_TIMER_HAS_DSP_IRQ                          0x08000000
  64
  65struct omap_timer_capability_dev_attr {
  66        u32 timer_capability;
  67};
  68
  69struct omap_dm_timer;
  70
  71struct timer_regs {
  72        u32 tidr;
  73        u32 tistat;
  74        u32 tisr;
  75        u32 tier;
  76        u32 twer;
  77        u32 tclr;
  78        u32 tcrr;
  79        u32 tldr;
  80        u32 ttrg;
  81        u32 twps;
  82        u32 tmar;
  83        u32 tcar1;
  84        u32 tsicr;
  85        u32 tcar2;
  86        u32 tpir;
  87        u32 tnir;
  88        u32 tcvr;
  89        u32 tocr;
  90        u32 towr;
  91};
  92
  93struct dmtimer_platform_data {
  94        /* set_timer_src - Only used for OMAP1 devices */
  95        int (*set_timer_src)(struct platform_device *pdev, int source);
  96        u32 timer_capability;
  97};
  98
  99int omap_dm_timer_reserve_systimer(int id);
 100struct omap_dm_timer *omap_dm_timer_request(void);
 101struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
 102int omap_dm_timer_free(struct omap_dm_timer *timer);
 103void omap_dm_timer_enable(struct omap_dm_timer *timer);
 104void omap_dm_timer_disable(struct omap_dm_timer *timer);
 105
 106int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
 107
 108u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 109struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
 110
 111int omap_dm_timer_trigger(struct omap_dm_timer *timer);
 112int omap_dm_timer_start(struct omap_dm_timer *timer);
 113int omap_dm_timer_stop(struct omap_dm_timer *timer);
 114
 115int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
 116int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
 117int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
 118int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
 119int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
 120int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
 121
 122int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
 123
 124unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
 125int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
 126unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
 127int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
 128
 129int omap_dm_timers_active(void);
 130
 131/*
 132 * Do not use the defines below, they are not needed. They should be only
 133 * used by dmtimer.c and sys_timer related code.
 134 */
 135
 136/*
 137 * The interrupt registers are different between v1 and v2 ip.
 138 * These registers are offsets from timer->iobase.
 139 */
 140#define OMAP_TIMER_ID_OFFSET            0x00
 141#define OMAP_TIMER_OCP_CFG_OFFSET       0x10
 142
 143#define OMAP_TIMER_V1_SYS_STAT_OFFSET   0x14
 144#define OMAP_TIMER_V1_STAT_OFFSET       0x18
 145#define OMAP_TIMER_V1_INT_EN_OFFSET     0x1c
 146
 147#define OMAP_TIMER_V2_IRQSTATUS_RAW     0x24
 148#define OMAP_TIMER_V2_IRQSTATUS         0x28
 149#define OMAP_TIMER_V2_IRQENABLE_SET     0x2c
 150#define OMAP_TIMER_V2_IRQENABLE_CLR     0x30
 151
 152/*
 153 * The functional registers have a different base on v1 and v2 ip.
 154 * These registers are offsets from timer->func_base. The func_base
 155 * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
 156 *
 157 */
 158#define OMAP_TIMER_V2_FUNC_OFFSET               0x14
 159
 160#define _OMAP_TIMER_WAKEUP_EN_OFFSET    0x20
 161#define _OMAP_TIMER_CTRL_OFFSET         0x24
 162#define         OMAP_TIMER_CTRL_GPOCFG          (1 << 14)
 163#define         OMAP_TIMER_CTRL_CAPTMODE        (1 << 13)
 164#define         OMAP_TIMER_CTRL_PT              (1 << 12)
 165#define         OMAP_TIMER_CTRL_TCM_LOWTOHIGH   (0x1 << 8)
 166#define         OMAP_TIMER_CTRL_TCM_HIGHTOLOW   (0x2 << 8)
 167#define         OMAP_TIMER_CTRL_TCM_BOTHEDGES   (0x3 << 8)
 168#define         OMAP_TIMER_CTRL_SCPWM           (1 << 7)
 169#define         OMAP_TIMER_CTRL_CE              (1 << 6) /* compare enable */
 170#define         OMAP_TIMER_CTRL_PRE             (1 << 5) /* prescaler enable */
 171#define         OMAP_TIMER_CTRL_PTV_SHIFT       2 /* prescaler value shift */
 172#define         OMAP_TIMER_CTRL_POSTED          (1 << 2)
 173#define         OMAP_TIMER_CTRL_AR              (1 << 1) /* auto-reload enable */
 174#define         OMAP_TIMER_CTRL_ST              (1 << 0) /* start timer */
 175#define _OMAP_TIMER_COUNTER_OFFSET      0x28
 176#define _OMAP_TIMER_LOAD_OFFSET         0x2c
 177#define _OMAP_TIMER_TRIGGER_OFFSET      0x30
 178#define _OMAP_TIMER_WRITE_PEND_OFFSET   0x34
 179#define         WP_NONE                 0       /* no write pending bit */
 180#define         WP_TCLR                 (1 << 0)
 181#define         WP_TCRR                 (1 << 1)
 182#define         WP_TLDR                 (1 << 2)
 183#define         WP_TTGR                 (1 << 3)
 184#define         WP_TMAR                 (1 << 4)
 185#define         WP_TPIR                 (1 << 5)
 186#define         WP_TNIR                 (1 << 6)
 187#define         WP_TCVR                 (1 << 7)
 188#define         WP_TOCR                 (1 << 8)
 189#define         WP_TOWR                 (1 << 9)
 190#define _OMAP_TIMER_MATCH_OFFSET        0x38
 191#define _OMAP_TIMER_CAPTURE_OFFSET      0x3c
 192#define _OMAP_TIMER_IF_CTRL_OFFSET      0x40
 193#define _OMAP_TIMER_CAPTURE2_OFFSET             0x44    /* TCAR2, 34xx only */
 194#define _OMAP_TIMER_TICK_POS_OFFSET             0x48    /* TPIR, 34xx only */
 195#define _OMAP_TIMER_TICK_NEG_OFFSET             0x4c    /* TNIR, 34xx only */
 196#define _OMAP_TIMER_TICK_COUNT_OFFSET           0x50    /* TCVR, 34xx only */
 197#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET    0x54    /* TOCR, 34xx only */
 198#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET  0x58    /* TOWR, 34xx only */
 199
 200/* register offsets with the write pending bit encoded */
 201#define WPSHIFT                                 16
 202
 203#define OMAP_TIMER_WAKEUP_EN_REG                (_OMAP_TIMER_WAKEUP_EN_OFFSET \
 204                                                        | (WP_NONE << WPSHIFT))
 205
 206#define OMAP_TIMER_CTRL_REG                     (_OMAP_TIMER_CTRL_OFFSET \
 207                                                        | (WP_TCLR << WPSHIFT))
 208
 209#define OMAP_TIMER_COUNTER_REG                  (_OMAP_TIMER_COUNTER_OFFSET \
 210                                                        | (WP_TCRR << WPSHIFT))
 211
 212#define OMAP_TIMER_LOAD_REG                     (_OMAP_TIMER_LOAD_OFFSET \
 213                                                        | (WP_TLDR << WPSHIFT))
 214
 215#define OMAP_TIMER_TRIGGER_REG                  (_OMAP_TIMER_TRIGGER_OFFSET \
 216                                                        | (WP_TTGR << WPSHIFT))
 217
 218#define OMAP_TIMER_WRITE_PEND_REG               (_OMAP_TIMER_WRITE_PEND_OFFSET \
 219                                                        | (WP_NONE << WPSHIFT))
 220
 221#define OMAP_TIMER_MATCH_REG                    (_OMAP_TIMER_MATCH_OFFSET \
 222                                                        | (WP_TMAR << WPSHIFT))
 223
 224#define OMAP_TIMER_CAPTURE_REG                  (_OMAP_TIMER_CAPTURE_OFFSET \
 225                                                        | (WP_NONE << WPSHIFT))
 226
 227#define OMAP_TIMER_IF_CTRL_REG                  (_OMAP_TIMER_IF_CTRL_OFFSET \
 228                                                        | (WP_NONE << WPSHIFT))
 229
 230#define OMAP_TIMER_CAPTURE2_REG                 (_OMAP_TIMER_CAPTURE2_OFFSET \
 231                                                        | (WP_NONE << WPSHIFT))
 232
 233#define OMAP_TIMER_TICK_POS_REG                 (_OMAP_TIMER_TICK_POS_OFFSET \
 234                                                        | (WP_TPIR << WPSHIFT))
 235
 236#define OMAP_TIMER_TICK_NEG_REG                 (_OMAP_TIMER_TICK_NEG_OFFSET \
 237                                                        | (WP_TNIR << WPSHIFT))
 238
 239#define OMAP_TIMER_TICK_COUNT_REG               (_OMAP_TIMER_TICK_COUNT_OFFSET \
 240                                                        | (WP_TCVR << WPSHIFT))
 241
 242#define OMAP_TIMER_TICK_INT_MASK_SET_REG                                \
 243                (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
 244
 245#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG                              \
 246                (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
 247
 248struct omap_dm_timer {
 249        unsigned long phys_base;
 250        int id;
 251        int irq;
 252        struct clk *fclk;
 253
 254        void __iomem    *io_base;
 255        void __iomem    *sys_stat;      /* TISTAT timer status */
 256        void __iomem    *irq_stat;      /* TISR/IRQSTATUS interrupt status */
 257        void __iomem    *irq_ena;       /* irq enable */
 258        void __iomem    *irq_dis;       /* irq disable, only on v2 ip */
 259        void __iomem    *pend;          /* write pending */
 260        void __iomem    *func_base;     /* function register base */
 261
 262        unsigned long rate;
 263        unsigned reserved:1;
 264        unsigned posted:1;
 265        struct timer_regs context;
 266        int ctx_loss_count;
 267        int revision;
 268        u32 capability;
 269        struct platform_device *pdev;
 270        struct list_head node;
 271};
 272
 273int omap_dm_timer_prepare(struct omap_dm_timer *timer);
 274
 275static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 276                                                int posted)
 277{
 278        if (posted)
 279                while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 280                        cpu_relax();
 281
 282        return __raw_readl(timer->func_base + (reg & 0xff));
 283}
 284
 285static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
 286                                        u32 reg, u32 val, int posted)
 287{
 288        if (posted)
 289                while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 290                        cpu_relax();
 291
 292        __raw_writel(val, timer->func_base + (reg & 0xff));
 293}
 294
 295static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 296{
 297        u32 tidr;
 298
 299        /* Assume v1 ip if bits [31:16] are zero */
 300        tidr = __raw_readl(timer->io_base);
 301        if (!(tidr >> 16)) {
 302                timer->revision = 1;
 303                timer->sys_stat = timer->io_base +
 304                                OMAP_TIMER_V1_SYS_STAT_OFFSET;
 305                timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
 306                timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
 307                timer->irq_dis = NULL;
 308                timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
 309                timer->func_base = timer->io_base;
 310        } else {
 311                timer->revision = 2;
 312                timer->sys_stat = NULL;
 313                timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
 314                timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
 315                timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
 316                timer->pend = timer->io_base +
 317                        _OMAP_TIMER_WRITE_PEND_OFFSET +
 318                                OMAP_TIMER_V2_FUNC_OFFSET;
 319                timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
 320        }
 321}
 322
 323/* Assumes the source clock has been set by caller */
 324static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
 325                                        int autoidle, int wakeup)
 326{
 327        u32 l;
 328
 329        l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
 330        l |= 0x02 << 3;  /* Set to smart-idle mode */
 331        l |= 0x2 << 8;   /* Set clock activity to perserve f-clock on idle */
 332
 333        if (autoidle)
 334                l |= 0x1 << 0;
 335
 336        if (wakeup)
 337                l |= 1 << 2;
 338
 339        __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
 340
 341        /* Match hardware reset default of posted mode */
 342        __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
 343                                        OMAP_TIMER_CTRL_POSTED, 0);
 344}
 345
 346static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
 347                                                struct clk *parent)
 348{
 349        int ret;
 350
 351        clk_disable(timer_fck);
 352        ret = clk_set_parent(timer_fck, parent);
 353        clk_enable(timer_fck);
 354
 355        /*
 356         * When the functional clock disappears, too quick writes seem
 357         * to cause an abort. XXX Is this still necessary?
 358         */
 359        __delay(300000);
 360
 361        return ret;
 362}
 363
 364static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
 365                                        int posted, unsigned long rate)
 366{
 367        u32 l;
 368
 369        l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
 370        if (l & OMAP_TIMER_CTRL_ST) {
 371                l &= ~0x1;
 372                __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
 373#ifdef CONFIG_ARCH_OMAP2PLUS
 374                /* Readback to make sure write has completed */
 375                __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
 376                /*
 377                 * Wait for functional clock period x 3.5 to make sure that
 378                 * timer is stopped
 379                 */
 380                udelay(3500000 / rate + 1);
 381#endif
 382        }
 383
 384        /* Ack possibly pending interrupt */
 385        __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
 386}
 387
 388static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
 389                                                u32 ctrl, unsigned int load,
 390                                                int posted)
 391{
 392        __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
 393        __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
 394}
 395
 396static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
 397                                                unsigned int value)
 398{
 399        __raw_writel(value, timer->irq_ena);
 400        __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
 401}
 402
 403static inline unsigned int
 404__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
 405{
 406        return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
 407}
 408
 409static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
 410                                                unsigned int value)
 411{
 412        __raw_writel(value, timer->irq_stat);
 413}
 414
 415#endif /* __ASM_ARCH_DMTIMER_H */
 416