1/* 2 * Copyright (C) 1999 - 2003 ARM Limited 3 * Copyright (C) 2000 Deep Blue Solutions Ltd 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19#include <linux/kernel.h> 20#include <linux/init.h> 21#include <linux/clockchips.h> 22#include <linux/interrupt.h> 23#include <linux/irq.h> 24#include <linux/io.h> 25 26#include <plat/mpcore.h> 27#if defined(CONFIG_BUZZZ) 28#include <asm/buzzz.h> 29#endif /* CONFIG_BUZZZ */ 30 31/* 32 * The ARM9 MPCORE Global Timer is a continously-running 64-bit timer, 33 * which is used both as a "clock source" and as a "clock event" - 34 * there is a banked per-cpu compare and reload registers that are 35 * used to generated either one-shot or periodic interrupts on the cpu 36 * that calls the mode_set function. 37 * 38 * NOTE: This code does not support dynamic change of the source clock 39 * frequency. The interrupt interval is only calculated once during 40 * initialization. 41 */ 42 43/* 44 * Global Timer Registers 45 */ 46#define GTIMER_COUNT_LO 0x00 /* Lower 32 of 64 bits counter */ 47#define GTIMER_COUNT_HI 0x04 /* Higher 32 of 64 bits counter */ 48#define GTIMER_CTRL 0x08 /* Control (partially banked) */ 49#define GTIMER_CTRL_EN (1<<0) /* Timer enable bit */ 50#define GTIMER_CTRL_CMP_EN (1<<1) /* Comparator enable */ 51#define GTIMER_CTRL_IRQ_EN (1<<2) /* Interrupt enable */ 52#define GTIMER_CTRL_AUTO_EN (1<<3) /* Auto-increment enable */ 53#define GTIMER_INT_STAT 0x0C /* Interrupt Status (banked) */ 54#define GTIMER_COMP_LO 0x10 /* Lower half comparator (banked) */ 55#define GTIMER_COMP_HI 0x14 /* Upper half comparator (banked) */ 56#define GTIMER_RELOAD 0x18 /* Auto-increment (banked) */ 57 58#define GTIMER_MIN_RANGE 30 /* Minimum wrap-around time in sec */ 59 60/* Gobal variables */ 61static void __iomem *gtimer_base; 62static u32 ticks_per_jiffy; 63 64extern void soc_watchdog(void); 65 66 67static cycle_t gptimer_count_read(struct clocksource *cs) 68{ 69 u32 count_hi, count_ho, count_lo; 70 u64 count; 71 72 /* Avoid unexpected rollover with double-read of upper half */ 73 do { 74 count_hi = readl( gtimer_base + GTIMER_COUNT_HI ); 75 count_lo = readl( gtimer_base + GTIMER_COUNT_LO ); 76 count_ho = readl( gtimer_base + GTIMER_COUNT_HI ); 77 } while( count_hi != count_ho ); 78 79 count = (u64) count_hi << 32 | count_lo ; 80 return count; 81} 82 83static struct clocksource clocksource_gptimer = { 84 .name = "mpcore_gtimer", 85 .rating = 300, 86 .read = gptimer_count_read, 87 .mask = CLOCKSOURCE_MASK(64), 88 .shift = 20, 89 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 90}; 91 92static void __init gptimer_clocksource_init(u32 freq) 93{ 94 struct clocksource *cs = &clocksource_gptimer; 95 96 /* <freq> is timer clock in Hz */ 97 clocksource_calc_mult_shift(cs, freq, GTIMER_MIN_RANGE); 98 99 clocksource_register(cs); 100} 101 102/* 103 * IRQ handler for the global timer 104 * This interrupt is banked per CPU so is handled identically 105 */ 106static irqreturn_t gtimer_interrupt(int irq, void *dev_id) 107{ 108 struct clock_event_device *evt = dev_id; 109 110 /* clear the interrupt */ 111 writel(1, gtimer_base + GTIMER_INT_STAT); 112 113#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 2) 114 buzzz_kevt_log1(BUZZZ_KEVT_ID_GTIMER_EVENT, (u32)evt->event_handler); 115#endif /* BUZZZ_KEVT_LVL */ 116 117 evt->event_handler(evt); 118 119 soc_watchdog(); 120 121 return IRQ_HANDLED; 122} 123 124static void gtimer_set_mode( 125 enum clock_event_mode mode, 126 struct clock_event_device *evt 127 ) 128{ 129 u32 ctrl, period; 130 u64 count; 131 132 /* Get current register with global enable and prescaler */ 133 ctrl = readl( gtimer_base + GTIMER_CTRL ); 134 135 /* Clear the mode-related bits */ 136 ctrl &= ~( GTIMER_CTRL_CMP_EN | 137 GTIMER_CTRL_IRQ_EN | 138 GTIMER_CTRL_AUTO_EN); 139 140 switch (mode) { 141 case CLOCK_EVT_MODE_PERIODIC: 142 period = ticks_per_jiffy; 143 count = gptimer_count_read( NULL ); 144 count += period ; 145 writel(ctrl, gtimer_base + GTIMER_CTRL); 146 writel(count & 0xffffffffUL, gtimer_base + GTIMER_COMP_LO); 147 writel(count >> 32, gtimer_base + GTIMER_COMP_HI); 148 writel(period, gtimer_base + GTIMER_RELOAD); 149 ctrl |= GTIMER_CTRL_CMP_EN | 150 GTIMER_CTRL_IRQ_EN | 151 GTIMER_CTRL_AUTO_EN ; 152 break; 153 154 case CLOCK_EVT_MODE_ONESHOT: 155 /* period set, and timer enabled in 'next_event' hook */ 156 break; 157 158 case CLOCK_EVT_MODE_UNUSED: 159 case CLOCK_EVT_MODE_SHUTDOWN: 160 default: 161 break; 162 } 163 /* Apply the new mode */ 164 writel(ctrl, gtimer_base + GTIMER_CTRL); 165} 166 167static int gtimer_set_next_event( 168 unsigned long next, 169 struct clock_event_device *evt 170 ) 171{ 172 u32 ctrl; 173 u64 count; 174 175#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 2) 176 buzzz_kevt_log1(BUZZZ_KEVT_ID_GTIMER_NEXT, (u32)next); 177#endif /* BUZZZ_KEVT_LVL */ 178 179 ctrl = readl(gtimer_base + GTIMER_CTRL); 180 count = gptimer_count_read( NULL ); 181 182 ctrl &= ~GTIMER_CTRL_CMP_EN ; 183 writel(ctrl, gtimer_base + GTIMER_CTRL); 184 185 count += next ; 186 187 writel(count & 0xffffffffUL, gtimer_base + GTIMER_COMP_LO); 188 writel(count >> 32, gtimer_base + GTIMER_COMP_HI); 189 190 /* enable IRQ for the same cpu that loaded comparator */ 191 ctrl |= GTIMER_CTRL_CMP_EN ; 192 ctrl |= GTIMER_CTRL_IRQ_EN ; 193 194 writel(ctrl, gtimer_base + GTIMER_CTRL); 195 196 return 0; 197} 198 199static struct clock_event_device gtimer_clockevent = { 200 .name = "mpcore_gtimer", 201 .shift = 20, 202 .features = CLOCK_EVT_FEAT_PERIODIC, 203 .set_mode = gtimer_set_mode, 204 .set_next_event = gtimer_set_next_event, 205 .rating = 300, 206 .cpumask = cpu_all_mask, 207}; 208 209static struct irqaction gtimer_irq = { 210 .name = "mpcore_gtimer", 211 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU, 212 .handler = gtimer_interrupt, 213 .dev_id = >imer_clockevent, 214}; 215 216static void __init gtimer_clockevents_init(u32 freq, unsigned timer_irq) 217{ 218 struct clock_event_device *evt = >imer_clockevent; 219 220 evt->irq = timer_irq; 221 ticks_per_jiffy = DIV_ROUND_CLOSEST(freq, HZ); 222 223 clockevents_calc_mult_shift(evt, freq, GTIMER_MIN_RANGE); 224 225 evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); 226 evt->min_delta_ns = clockevent_delta2ns(0xf, evt); 227 228 /* Register the device to install handler before enabing IRQ */ 229 clockevents_register_device(evt); 230 setup_irq(timer_irq, >imer_irq); 231} 232 233/* 234 * MPCORE Global Timer initialization function 235 */ 236void __init mpcore_gtimer_init( 237 void __iomem *base, 238 unsigned long freq, 239 unsigned int timer_irq) 240{ 241 u32 ctrl ; 242 u64 count; 243 244 gtimer_base = base; 245 246 printk(KERN_INFO "MPCORE Global Timer Clock %luHz\n", 247 (unsigned long) freq); 248 249 /* Prescaler = 0; let the Global Timer run at native PERIPHCLK rate */ 250 251 ctrl = GTIMER_CTRL_EN; 252 253 /* Enable the free-running global counter */ 254 255 writel(ctrl, gtimer_base + GTIMER_CTRL); 256 257 /* Self-test the timer is running */ 258 count = gptimer_count_read(NULL); 259 260 /* Register as time source */ 261 gptimer_clocksource_init(freq); 262 263 /* Register as system timer */ 264 gtimer_clockevents_init(freq, timer_irq); 265 266 count = gptimer_count_read(NULL) - count ; 267 if( count == 0 ) 268 printk(KERN_CRIT "MPCORE Global Timer Dead!!\n"); 269} 270