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/delay.h>
  36#include <linux/io.h>
  37#include <linux/platform_device.h>
  38
  39#ifndef __ASM_ARCH_DMTIMER_H
  40#define __ASM_ARCH_DMTIMER_H
  41
  42/* clock sources */
  43#define OMAP_TIMER_SRC_SYS_CLK                  0x00
  44#define OMAP_TIMER_SRC_32_KHZ                   0x01
  45#define OMAP_TIMER_SRC_EXT_CLK                  0x02
  46
  47/* timer interrupt enable bits */
  48#define OMAP_TIMER_INT_CAPTURE                  (1 << 2)
  49#define OMAP_TIMER_INT_OVERFLOW                 (1 << 1)
  50#define OMAP_TIMER_INT_MATCH                    (1 << 0)
  51
  52/* trigger types */
  53#define OMAP_TIMER_TRIGGER_NONE                 0x00
  54#define OMAP_TIMER_TRIGGER_OVERFLOW             0x01
  55#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
  56
  57/* posted mode types */
  58#define OMAP_TIMER_NONPOSTED                    0x00
  59#define OMAP_TIMER_POSTED                       0x01
  60
  61/* timer capabilities used in hwmod database */
  62#define OMAP_TIMER_SECURE                               0x80000000
  63#define OMAP_TIMER_ALWON                                0x40000000
  64#define OMAP_TIMER_HAS_PWM                              0x20000000
  65#define OMAP_TIMER_NEEDS_RESET                          0x10000000
  66#define OMAP_TIMER_HAS_DSP_IRQ                          0x08000000
  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
  78struct omap_timer_capability_dev_attr {
  79        u32 timer_capability;
  80};
  81
  82struct timer_regs {
  83        u32 tidr;
  84        u32 tier;
  85        u32 twer;
  86        u32 tclr;
  87        u32 tcrr;
  88        u32 tldr;
  89        u32 ttrg;
  90        u32 twps;
  91        u32 tmar;
  92        u32 tcar1;
  93        u32 tsicr;
  94        u32 tcar2;
  95        u32 tpir;
  96        u32 tnir;
  97        u32 tcvr;
  98        u32 tocr;
  99        u32 towr;
 100};
 101
 102struct omap_dm_timer {
 103        int id;
 104        int irq;
 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;
 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;
 125};
 126
 127int omap_dm_timer_reserve_systimer(int id);
 128struct omap_dm_timer *omap_dm_timer_request(void);
 129struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
 130struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
 131struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np);
 132int omap_dm_timer_free(struct omap_dm_timer *timer);
 133void omap_dm_timer_enable(struct omap_dm_timer *timer);
 134void omap_dm_timer_disable(struct omap_dm_timer *timer);
 135
 136int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
 137
 138u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 139struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
 140
 141int omap_dm_timer_trigger(struct omap_dm_timer *timer);
 142int omap_dm_timer_start(struct omap_dm_timer *timer);
 143int omap_dm_timer_stop(struct omap_dm_timer *timer);
 144
 145int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
 146int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
 147int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
 148int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
 149int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
 150int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
 151
 152int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
 153int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);
 154
 155unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
 156int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
 157unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
 158int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
 159
 160int omap_dm_timers_active(void);
 161
 162/*
 163 * Do not use the defines below, they are not needed. They should be only
 164 * used by dmtimer.c and sys_timer related code.
 165 */
 166
 167/*
 168 * The interrupt registers are different between v1 and v2 ip.
 169 * These registers are offsets from timer->iobase.
 170 */
 171#define OMAP_TIMER_ID_OFFSET            0x00
 172#define OMAP_TIMER_OCP_CFG_OFFSET       0x10
 173
 174#define OMAP_TIMER_V1_SYS_STAT_OFFSET   0x14
 175#define OMAP_TIMER_V1_STAT_OFFSET       0x18
 176#define OMAP_TIMER_V1_INT_EN_OFFSET     0x1c
 177
 178#define OMAP_TIMER_V2_IRQSTATUS_RAW     0x24
 179#define OMAP_TIMER_V2_IRQSTATUS         0x28
 180#define OMAP_TIMER_V2_IRQENABLE_SET     0x2c
 181#define OMAP_TIMER_V2_IRQENABLE_CLR     0x30
 182
 183/*
 184 * The functional registers have a different base on v1 and v2 ip.
 185 * These registers are offsets from timer->func_base. The func_base
 186 * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
 187 *
 188 */
 189#define OMAP_TIMER_V2_FUNC_OFFSET               0x14
 190
 191#define _OMAP_TIMER_WAKEUP_EN_OFFSET    0x20
 192#define _OMAP_TIMER_CTRL_OFFSET         0x24
 193#define         OMAP_TIMER_CTRL_GPOCFG          (1 << 14)
 194#define         OMAP_TIMER_CTRL_CAPTMODE        (1 << 13)
 195#define         OMAP_TIMER_CTRL_PT              (1 << 12)
 196#define         OMAP_TIMER_CTRL_TCM_LOWTOHIGH   (0x1 << 8)
 197#define         OMAP_TIMER_CTRL_TCM_HIGHTOLOW   (0x2 << 8)
 198#define         OMAP_TIMER_CTRL_TCM_BOTHEDGES   (0x3 << 8)
 199#define         OMAP_TIMER_CTRL_SCPWM           (1 << 7)
 200#define         OMAP_TIMER_CTRL_CE              (1 << 6) /* compare enable */
 201#define         OMAP_TIMER_CTRL_PRE             (1 << 5) /* prescaler enable */
 202#define         OMAP_TIMER_CTRL_PTV_SHIFT       2 /* prescaler value shift */
 203#define         OMAP_TIMER_CTRL_POSTED          (1 << 2)
 204#define         OMAP_TIMER_CTRL_AR              (1 << 1) /* auto-reload enable */
 205#define         OMAP_TIMER_CTRL_ST              (1 << 0) /* start timer */
 206#define _OMAP_TIMER_COUNTER_OFFSET      0x28
 207#define _OMAP_TIMER_LOAD_OFFSET         0x2c
 208#define _OMAP_TIMER_TRIGGER_OFFSET      0x30
 209#define _OMAP_TIMER_WRITE_PEND_OFFSET   0x34
 210#define         WP_NONE                 0       /* no write pending bit */
 211#define         WP_TCLR                 (1 << 0)
 212#define         WP_TCRR                 (1 << 1)
 213#define         WP_TLDR                 (1 << 2)
 214#define         WP_TTGR                 (1 << 3)
 215#define         WP_TMAR                 (1 << 4)
 216#define         WP_TPIR                 (1 << 5)
 217#define         WP_TNIR                 (1 << 6)
 218#define         WP_TCVR                 (1 << 7)
 219#define         WP_TOCR                 (1 << 8)
 220#define         WP_TOWR                 (1 << 9)
 221#define _OMAP_TIMER_MATCH_OFFSET        0x38
 222#define _OMAP_TIMER_CAPTURE_OFFSET      0x3c
 223#define _OMAP_TIMER_IF_CTRL_OFFSET      0x40
 224#define _OMAP_TIMER_CAPTURE2_OFFSET             0x44    /* TCAR2, 34xx only */
 225#define _OMAP_TIMER_TICK_POS_OFFSET             0x48    /* TPIR, 34xx only */
 226#define _OMAP_TIMER_TICK_NEG_OFFSET             0x4c    /* TNIR, 34xx only */
 227#define _OMAP_TIMER_TICK_COUNT_OFFSET           0x50    /* TCVR, 34xx only */
 228#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET    0x54    /* TOCR, 34xx only */
 229#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET  0x58    /* TOWR, 34xx only */
 230
 231/* register offsets with the write pending bit encoded */
 232#define WPSHIFT                                 16
 233
 234#define OMAP_TIMER_WAKEUP_EN_REG                (_OMAP_TIMER_WAKEUP_EN_OFFSET \
 235                                                        | (WP_NONE << WPSHIFT))
 236
 237#define OMAP_TIMER_CTRL_REG                     (_OMAP_TIMER_CTRL_OFFSET \
 238                                                        | (WP_TCLR << WPSHIFT))
 239
 240#define OMAP_TIMER_COUNTER_REG                  (_OMAP_TIMER_COUNTER_OFFSET \
 241                                                        | (WP_TCRR << WPSHIFT))
 242
 243#define OMAP_TIMER_LOAD_REG                     (_OMAP_TIMER_LOAD_OFFSET \
 244                                                        | (WP_TLDR << WPSHIFT))
 245
 246#define OMAP_TIMER_TRIGGER_REG                  (_OMAP_TIMER_TRIGGER_OFFSET \
 247                                                        | (WP_TTGR << WPSHIFT))
 248
 249#define OMAP_TIMER_WRITE_PEND_REG               (_OMAP_TIMER_WRITE_PEND_OFFSET \
 250                                                        | (WP_NONE << WPSHIFT))
 251
 252#define OMAP_TIMER_MATCH_REG                    (_OMAP_TIMER_MATCH_OFFSET \
 253                                                        | (WP_TMAR << WPSHIFT))
 254
 255#define OMAP_TIMER_CAPTURE_REG                  (_OMAP_TIMER_CAPTURE_OFFSET \
 256                                                        | (WP_NONE << WPSHIFT))
 257
 258#define OMAP_TIMER_IF_CTRL_REG                  (_OMAP_TIMER_IF_CTRL_OFFSET \
 259                                                        | (WP_NONE << WPSHIFT))
 260
 261#define OMAP_TIMER_CAPTURE2_REG                 (_OMAP_TIMER_CAPTURE2_OFFSET \
 262                                                        | (WP_NONE << WPSHIFT))
 263
 264#define OMAP_TIMER_TICK_POS_REG                 (_OMAP_TIMER_TICK_POS_OFFSET \
 265                                                        | (WP_TPIR << WPSHIFT))
 266
 267#define OMAP_TIMER_TICK_NEG_REG                 (_OMAP_TIMER_TICK_NEG_OFFSET \
 268                                                        | (WP_TNIR << WPSHIFT))
 269
 270#define OMAP_TIMER_TICK_COUNT_REG               (_OMAP_TIMER_TICK_COUNT_OFFSET \
 271                                                        | (WP_TCVR << WPSHIFT))
 272
 273#define OMAP_TIMER_TICK_INT_MASK_SET_REG                                \
 274                (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))
 275
 276#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG                              \
 277                (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
 278
 279static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
 280                                                int posted)
 281{
 282        if (posted)
 283                while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 284                        cpu_relax();
 285
 286        return __raw_readl(timer->func_base + (reg & 0xff));
 287}
 288
 289static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
 290                                        u32 reg, u32 val, int posted)
 291{
 292        if (posted)
 293                while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
 294                        cpu_relax();
 295
 296        __raw_writel(val, timer->func_base + (reg & 0xff));
 297}
 298
 299static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
 300{
 301        u32 tidr;
 302
 303        /* Assume v1 ip if bits [31:16] are zero */
 304        tidr = __raw_readl(timer->io_base);
 305        if (!(tidr >> 16)) {
 306                timer->revision = 1;
 307                timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
 308                timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
 309                timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
 310                timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
 311                timer->func_base = timer->io_base;
 312        } else {
 313                timer->revision = 2;
 314                timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
 315                timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
 316                timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
 317                timer->pend = timer->io_base +
 318                        _OMAP_TIMER_WRITE_PEND_OFFSET +
 319                                OMAP_TIMER_V2_FUNC_OFFSET;
 320                timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
 321        }
 322}
 323
 324/*
 325 * __omap_dm_timer_enable_posted - enables write posted mode
 326 * @timer:      pointer to timer instance handle
 327 *
 328 * Enables the write posted mode for the timer. When posted mode is enabled
 329 * writes to certain timer registers are immediately acknowledged by the
 330 * internal bus and hence prevents stalling the CPU waiting for the write to
 331 * complete. Enabling this feature can improve performance for writing to the
 332 * timer registers.
 333 */
 334static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
 335{
 336        if (timer->posted)
 337                return;
 338
 339        if (timer->errata & OMAP_TIMER_ERRATA_I103_I767)
 340                return;
 341
 342        __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
 343                              OMAP_TIMER_CTRL_POSTED, 0);
 344        timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
 345        timer->posted = OMAP_TIMER_POSTED;
 346}
 347
 348/**
 349 * __omap_dm_timer_override_errata - override errata flags for a timer
 350 * @timer:      pointer to timer handle
 351 * @errata:     errata flags to be ignored
 352 *
 353 * For a given timer, override a timer errata by clearing the flags
 354 * specified by the errata argument. A specific erratum should only be
 355 * overridden for a timer if the timer is used in such a way the erratum
 356 * has no impact.
 357 */
 358static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
 359                                                   u32 errata)
 360{
 361        timer->errata &= ~errata;
 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