1/* 2 * Copyright 2001, 2002, 2003 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) 5 * 6 * Common time service routines for MIPS machines. See 7 * Documents/MIPS/README.txt. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14#include <linux/types.h> 15#include <linux/kernel.h> 16#include <linux/init.h> 17#include <linux/sched.h> 18#include <linux/param.h> 19#include <linux/time.h> 20#include <linux/timer.h> 21#include <linux/smp.h> 22#include <linux/kernel_stat.h> 23#include <linux/spinlock.h> 24#include <linux/interrupt.h> 25 26#include <asm/bootinfo.h> 27#include <asm/cpu.h> 28#include <asm/time.h> 29#include <asm/hardirq.h> 30#include <asm/div64.h> 31#include <asm/debug.h> 32 33#include <int.h> 34#include <cm.h> 35 36static unsigned long cpj; 37 38static cycle_t hpt_read(struct clocksource *cs) 39{ 40 return read_c0_count2(); 41} 42 43static struct clocksource pnx_clocksource = { 44 .name = "pnx8xxx", 45 .rating = 200, 46 .read = hpt_read, 47 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 48}; 49 50static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id) 51{ 52 struct clock_event_device *c = dev_id; 53 54 /* clear MATCH, signal the event */ 55 c->event_handler(c); 56 57 return IRQ_HANDLED; 58} 59 60static struct irqaction pnx8xxx_timer_irq = { 61 .handler = pnx8xxx_timer_interrupt, 62 .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, 63 .name = "pnx8xxx_timer", 64}; 65 66static irqreturn_t monotonic_interrupt(int irq, void *dev_id) 67{ 68 /* Timer 2 clear interrupt */ 69 write_c0_compare2(-1); 70 return IRQ_HANDLED; 71} 72 73static struct irqaction monotonic_irqaction = { 74 .handler = monotonic_interrupt, 75 .flags = IRQF_DISABLED | IRQF_TIMER, 76 .name = "Monotonic timer", 77}; 78 79static int pnx8xxx_set_next_event(unsigned long delta, 80 struct clock_event_device *evt) 81{ 82 write_c0_compare(delta); 83 return 0; 84} 85 86static struct clock_event_device pnx8xxx_clockevent = { 87 .name = "pnx8xxx_clockevent", 88 .features = CLOCK_EVT_FEAT_ONESHOT, 89 .set_next_event = pnx8xxx_set_next_event, 90}; 91 92static inline void timer_ack(void) 93{ 94 write_c0_compare(cpj); 95} 96 97__init void plat_time_init(void) 98{ 99 unsigned int configPR; 100 unsigned int n; 101 unsigned int m; 102 unsigned int p; 103 unsigned int pow2p; 104 105 pnx8xxx_clockevent.cpumask = cpu_none_mask; 106 clockevents_register_device(&pnx8xxx_clockevent); 107 clocksource_register(&pnx_clocksource); 108 109 /* Timer 1 start */ 110 configPR = read_c0_config7(); 111 configPR &= ~0x00000008; 112 write_c0_config7(configPR); 113 114 /* Timer 2 start */ 115 configPR = read_c0_config7(); 116 configPR &= ~0x00000010; 117 write_c0_config7(configPR); 118 119 /* Timer 3 stop */ 120 configPR = read_c0_config7(); 121 configPR |= 0x00000020; 122 write_c0_config7(configPR); 123 124 125 /* PLL0 sets MIPS clock (PLL1 <=> TM1, PLL6 <=> TM2, PLL5 <=> mem) */ 126 127 n = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_N_MASK) >> 16; 128 m = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_M_MASK) >> 8; 129 p = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_P_MASK) >> 2; 130 pow2p = (1 << p); 131 132 db_assert(m != 0 && pow2p != 0); 133 134 /* 135 * Compute the frequency as in the PNX8550 User Manual 1.0, p.186 136 * (a.k.a. 8-10). Divide by HZ for a timer offset that results in 137 * HZ timer interrupts per second. 138 */ 139 mips_hpt_frequency = 27UL * ((1000000UL * n)/(m * pow2p)); 140 cpj = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); 141 write_c0_count(0); 142 timer_ack(); 143 144 /* Setup Timer 2 */ 145 write_c0_count2(0); 146 write_c0_compare2(0xffffffff); 147 148 setup_irq(PNX8550_INT_TIMER1, &pnx8xxx_timer_irq); 149 setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction); 150} 151