linux/arch/mips/kernel/cevt-txx9.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Based on linux/arch/mips/kernel/cevt-r4k.c,
   7 *          linux/arch/mips/jmr3927/rbhma3100/setup.c
   8 *
   9 * Copyright 2001 MontaVista Software Inc.
  10 * Copyright (C) 2000-2001 Toshiba Corporation
  11 * Copyright (C) 2007 MIPS Technologies, Inc.
  12 * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
  13 */
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <asm/time.h>
  18#include <asm/txx9tmr.h>
  19
  20#define TCR_BASE (TXx9_TMTCR_CCDE | TXx9_TMTCR_CRE | TXx9_TMTCR_TMODE_ITVL)
  21#define TIMER_CCD       0       /* 1/2 */
  22#define TIMER_CLK(imclk)        ((imclk) / (2 << TIMER_CCD))
  23
  24struct txx9_clocksource {
  25        struct clocksource cs;
  26        struct txx9_tmr_reg __iomem *tmrptr;
  27};
  28
  29static cycle_t txx9_cs_read(struct clocksource *cs)
  30{
  31        struct txx9_clocksource *txx9_cs =
  32                container_of(cs, struct txx9_clocksource, cs);
  33        return __raw_readl(&txx9_cs->tmrptr->trr);
  34}
  35
  36/* Use 1 bit smaller width to use full bits in that width */
  37#define TXX9_CLOCKSOURCE_BITS (TXX9_TIMER_BITS - 1)
  38
  39static struct txx9_clocksource txx9_clocksource = {
  40        .cs = {
  41                .name           = "TXx9",
  42                .rating         = 200,
  43                .read           = txx9_cs_read,
  44                .mask           = CLOCKSOURCE_MASK(TXX9_CLOCKSOURCE_BITS),
  45                .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  46        },
  47};
  48
  49void __init txx9_clocksource_init(unsigned long baseaddr,
  50                                  unsigned int imbusclk)
  51{
  52        struct txx9_tmr_reg __iomem *tmrptr;
  53
  54        clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
  55        clocksource_register(&txx9_clocksource.cs);
  56
  57        tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
  58        __raw_writel(TCR_BASE, &tmrptr->tcr);
  59        __raw_writel(0, &tmrptr->tisr);
  60        __raw_writel(TIMER_CCD, &tmrptr->ccdr);
  61        __raw_writel(TXx9_TMITMR_TZCE, &tmrptr->itmr);
  62        __raw_writel(1 << TXX9_CLOCKSOURCE_BITS, &tmrptr->cpra);
  63        __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
  64        txx9_clocksource.tmrptr = tmrptr;
  65}
  66
  67struct txx9_clock_event_device {
  68        struct clock_event_device cd;
  69        struct txx9_tmr_reg __iomem *tmrptr;
  70};
  71
  72static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr)
  73{
  74        /* stop and reset counter */
  75        __raw_writel(TCR_BASE, &tmrptr->tcr);
  76        /* clear pending interrupt */
  77        __raw_writel(0, &tmrptr->tisr);
  78}
  79
  80static void txx9tmr_set_mode(enum clock_event_mode mode,
  81                             struct clock_event_device *evt)
  82{
  83        struct txx9_clock_event_device *txx9_cd =
  84                container_of(evt, struct txx9_clock_event_device, cd);
  85        struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr;
  86
  87        txx9tmr_stop_and_clear(tmrptr);
  88        switch (mode) {
  89        case CLOCK_EVT_MODE_PERIODIC:
  90                __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE,
  91                             &tmrptr->itmr);
  92                /* start timer */
  93                __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >>
  94                             evt->shift,
  95                             &tmrptr->cpra);
  96                __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
  97                break;
  98        case CLOCK_EVT_MODE_SHUTDOWN:
  99        case CLOCK_EVT_MODE_UNUSED:
 100                __raw_writel(0, &tmrptr->itmr);
 101                break;
 102        case CLOCK_EVT_MODE_ONESHOT:
 103                __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr);
 104                break;
 105        case CLOCK_EVT_MODE_RESUME:
 106                __raw_writel(TIMER_CCD, &tmrptr->ccdr);
 107                __raw_writel(0, &tmrptr->itmr);
 108                break;
 109        }
 110}
 111
 112static int txx9tmr_set_next_event(unsigned long delta,
 113                                  struct clock_event_device *evt)
 114{
 115        struct txx9_clock_event_device *txx9_cd =
 116                container_of(evt, struct txx9_clock_event_device, cd);
 117        struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr;
 118
 119        txx9tmr_stop_and_clear(tmrptr);
 120        /* start timer */
 121        __raw_writel(delta, &tmrptr->cpra);
 122        __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
 123        return 0;
 124}
 125
 126static struct txx9_clock_event_device txx9_clock_event_device = {
 127        .cd = {
 128                .name           = "TXx9",
 129                .features       = CLOCK_EVT_FEAT_PERIODIC |
 130                                  CLOCK_EVT_FEAT_ONESHOT,
 131                .rating         = 200,
 132                .set_mode       = txx9tmr_set_mode,
 133                .set_next_event = txx9tmr_set_next_event,
 134        },
 135};
 136
 137static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id)
 138{
 139        struct txx9_clock_event_device *txx9_cd = dev_id;
 140        struct clock_event_device *cd = &txx9_cd->cd;
 141        struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr;
 142
 143        __raw_writel(0, &tmrptr->tisr); /* ack interrupt */
 144        cd->event_handler(cd);
 145        return IRQ_HANDLED;
 146}
 147
 148static struct irqaction txx9tmr_irq = {
 149        .handler        = txx9tmr_interrupt,
 150        .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 151        .name           = "txx9tmr",
 152        .dev_id         = &txx9_clock_event_device,
 153};
 154
 155void __init txx9_clockevent_init(unsigned long baseaddr, int irq,
 156                                 unsigned int imbusclk)
 157{
 158        struct clock_event_device *cd = &txx9_clock_event_device.cd;
 159        struct txx9_tmr_reg __iomem *tmrptr;
 160
 161        tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
 162        txx9tmr_stop_and_clear(tmrptr);
 163        __raw_writel(TIMER_CCD, &tmrptr->ccdr);
 164        __raw_writel(0, &tmrptr->itmr);
 165        txx9_clock_event_device.tmrptr = tmrptr;
 166
 167        clockevent_set_clock(cd, TIMER_CLK(imbusclk));
 168        cd->max_delta_ns =
 169                clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd);
 170        cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
 171        cd->irq = irq;
 172        cd->cpumask = cpumask_of(0),
 173        clockevents_register_device(cd);
 174        setup_irq(irq, &txx9tmr_irq);
 175        printk(KERN_INFO "TXx9: clockevent device at 0x%lx, irq %d\n",
 176               baseaddr, irq);
 177}
 178
 179void __init txx9_tmr_init(unsigned long baseaddr)
 180{
 181        struct txx9_tmr_reg __iomem *tmrptr;
 182
 183        tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
 184        /* Start once to make CounterResetEnable effective */
 185        __raw_writel(TXx9_TMTCR_CRE | TXx9_TMTCR_TCE, &tmrptr->tcr);
 186        /* Stop and reset the counter */
 187        __raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr);
 188        __raw_writel(0, &tmrptr->tisr);
 189        __raw_writel(0xffffffff, &tmrptr->cpra);
 190        __raw_writel(0, &tmrptr->itmr);
 191        __raw_writel(0, &tmrptr->ccdr);
 192        __raw_writel(0, &tmrptr->pgmr);
 193        iounmap(tmrptr);
 194}
 195