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