1/* 2 * Copyright 2001, 2002, 2003 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * 5 * Common time service routines for MIPS machines. See 6 * Documents/MIPS/README.txt. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13#include <linux/types.h> 14#include <linux/kernel.h> 15#include <linux/init.h> 16#include <linux/sched.h> 17#include <linux/param.h> 18#include <linux/time.h> 19#include <linux/timer.h> 20#include <linux/smp.h> 21#include <linux/kernel_stat.h> 22#include <linux/spinlock.h> 23#include <linux/interrupt.h> 24#include <linux/module.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(void) 39{ 40 return read_c0_count2(); 41} 42 43static void timer_ack(void) 44{ 45 write_c0_compare(cpj); 46} 47 48/* 49 * pnx8550_time_init() - it does the following things: 50 * 51 * 1) board_time_init() - 52 * a) (optional) set up RTC routines, 53 * b) (optional) calibrate and set the mips_hpt_frequency 54 * (only needed if you intended to use cpu counter as timer interrupt 55 * source) 56 */ 57 58void pnx8550_time_init(void) 59{ 60 unsigned int n; 61 unsigned int m; 62 unsigned int p; 63 unsigned int pow2p; 64 65 /* PLL0 sets MIPS clock (PLL1 <=> TM1, PLL6 <=> TM2, PLL5 <=> mem) */ 66 67 n = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_N_MASK) >> 16; 68 m = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_M_MASK) >> 8; 69 p = (PNX8550_CM_PLL0_CTL & PNX8550_CM_PLL_P_MASK) >> 2; 70 pow2p = (1 << p); 71 72 db_assert(m != 0 && pow2p != 0); 73 74 /* 75 * Compute the frequency as in the PNX8550 User Manual 1.0, p.186 76 * (a.k.a. 8-10). Divide by HZ for a timer offset that results in 77 * HZ timer interrupts per second. 78 */ 79 mips_hpt_frequency = 27UL * ((1000000UL * n)/(m * pow2p)); 80 cpj = (mips_hpt_frequency + HZ / 2) / HZ; 81 write_c0_count(0); 82 timer_ack(); 83 84 /* Setup Timer 2 */ 85 write_c0_count2(0); 86 write_c0_compare2(0xffffffff); 87 88 clocksource_mips.read = hpt_read; 89 mips_timer_ack = timer_ack; 90} 91 92static irqreturn_t monotonic_interrupt(int irq, void *dev_id) 93{ 94 /* Timer 2 clear interrupt */ 95 write_c0_compare2(-1); 96 return IRQ_HANDLED; 97} 98 99static struct irqaction monotonic_irqaction = { 100 .handler = monotonic_interrupt, 101 .flags = IRQF_DISABLED, 102 .name = "Monotonic timer", 103}; 104 105void __init plat_timer_setup(struct irqaction *irq) 106{ 107 int configPR; 108 109 setup_irq(PNX8550_INT_TIMER1, irq); 110 setup_irq(PNX8550_INT_TIMER2, &monotonic_irqaction); 111 112 /* Timer 1 start */ 113 configPR = read_c0_config7(); 114 configPR &= ~0x00000008; 115 write_c0_config7(configPR); 116 117 /* Timer 2 start */ 118 configPR = read_c0_config7(); 119 configPR &= ~0x00000010; 120 write_c0_config7(configPR); 121 122 /* Timer 3 stop */ 123 configPR = read_c0_config7(); 124 configPR |= 0x00000020; 125 write_c0_config7(configPR); 126} 127