1/* MN10300 Low level time management 2 * 3 * Copyright (C) 2007-2008 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * - Derived from arch/i386/kernel/time.c 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public Licence 9 * as published by the Free Software Foundation; either version 10 * 2 of the Licence, or (at your option) any later version. 11 */ 12#include <linux/sched.h> 13#include <linux/kernel.h> 14#include <linux/interrupt.h> 15#include <linux/time.h> 16#include <linux/init.h> 17#include <linux/smp.h> 18#include <linux/profile.h> 19#include <linux/cnt32_to_63.h> 20#include <linux/clocksource.h> 21#include <linux/clockchips.h> 22#include <asm/irq.h> 23#include <asm/div64.h> 24#include <asm/processor.h> 25#include <asm/intctl-regs.h> 26#include <asm/rtc.h> 27#include "internal.h" 28 29static unsigned long mn10300_last_tsc; /* time-stamp counter at last time 30 * interrupt occurred */ 31 32static unsigned long sched_clock_multiplier; 33 34/* 35 * scheduler clock - returns current time in nanosec units. 36 */ 37unsigned long long sched_clock(void) 38{ 39 union { 40 unsigned long long ll; 41 unsigned l[2]; 42 } tsc64, result; 43 unsigned long tmp; 44 unsigned product[3]; /* 96-bit intermediate value */ 45 46 /* cnt32_to_63() is not safe with preemption */ 47 preempt_disable(); 48 49 /* expand the tsc to 64-bits. 50 * - sched_clock() must be called once a minute or better or the 51 * following will go horribly wrong - see cnt32_to_63() 52 */ 53 tsc64.ll = cnt32_to_63(get_cycles()) & 0x7fffffffffffffffULL; 54 55 preempt_enable(); 56 57 /* scale the 64-bit TSC value to a nanosecond value via a 96-bit 58 * intermediate 59 */ 60 asm("mulu %2,%0,%3,%0 \n" /* LSW * mult -> 0:%3:%0 */ 61 "mulu %2,%1,%2,%1 \n" /* MSW * mult -> %2:%1:0 */ 62 "add %3,%1 \n" 63 "addc 0,%2 \n" /* result in %2:%1:%0 */ 64 : "=r"(product[0]), "=r"(product[1]), "=r"(product[2]), "=r"(tmp) 65 : "0"(tsc64.l[0]), "1"(tsc64.l[1]), "2"(sched_clock_multiplier) 66 : "cc"); 67 68 result.l[0] = product[1] << 16 | product[0] >> 16; 69 result.l[1] = product[2] << 16 | product[1] >> 16; 70 71 return result.ll; 72} 73 74/* 75 * initialise the scheduler clock 76 */ 77static void __init mn10300_sched_clock_init(void) 78{ 79 sched_clock_multiplier = 80 __muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK); 81} 82 83/** 84 * local_timer_interrupt - Local timer interrupt handler 85 * 86 * Handle local timer interrupts for this CPU. They may have been propagated 87 * to this CPU from the CPU that actually gets them by way of an IPI. 88 */ 89irqreturn_t local_timer_interrupt(void) 90{ 91 profile_tick(CPU_PROFILING); 92 update_process_times(user_mode(get_irq_regs())); 93 return IRQ_HANDLED; 94} 95 96/* 97 * initialise the various timers used by the main part of the kernel 98 */ 99void __init time_init(void) 100{ 101 /* we need the prescalar running to be able to use IOCLK/8 102 * - IOCLK runs at 1/4 (ST5 open) or 1/8 (ST5 closed) internal CPU clock 103 * - IOCLK runs at Fosc rate (crystal speed) 104 */ 105 TMPSCNT |= TMPSCNT_ENABLE; 106 107 init_clocksource(); 108 109 printk(KERN_INFO 110 "timestamp counter I/O clock running at %lu.%02lu" 111 " (calibrated against RTC)\n", 112 MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100); 113 114 mn10300_last_tsc = read_timestamp_counter(); 115 116 init_clockevents(); 117 118#ifdef CONFIG_MN10300_WD_TIMER 119 /* start the watchdog timer */ 120 watchdog_go(); 121#endif 122 123 mn10300_sched_clock_init(); 124} 125