clock.c revision 212453
1135549Sdes/*- 2135549Sdes * Copyright (C) 1995, 1996 Wolfgang Solfrank. 3135549Sdes * Copyright (C) 1995, 1996 TooLs GmbH. 4218384Sdougb * All rights reserved. 5135549Sdes * 6135549Sdes * Redistribution and use in source and binary forms, with or without 7135549Sdes * modification, are permitted provided that the following conditions 8135549Sdes * are met: 9135549Sdes * 1. Redistributions of source code must retain the above copyright 10135549Sdes * notice, this list of conditions and the following disclaimer. 11135549Sdes * 2. Redistributions in binary form must reproduce the above copyright 12135549Sdes * notice, this list of conditions and the following disclaimer in the 13135549Sdes * documentation and/or other materials provided with the distribution. 14135549Sdes * 3. All advertising materials mentioning features or use of this software 15135549Sdes * must display the following acknowledgement: 16135549Sdes * This product includes software developed by TooLs GmbH. 17135549Sdes * 4. The name of TooLs GmbH may not be used to endorse or promote products 18135549Sdes * derived from this software without specific prior written permission. 19135549Sdes * 20135549Sdes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21135549Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22135549Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23135549Sdes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24135549Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25135549Sdes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26135549Sdes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27170224Sdougb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28170224Sdougb * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29135549Sdes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30135549Sdes * 31135549Sdes * $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $ 32135549Sdes */ 33135549Sdes/* 34135549Sdes * Copyright (C) 2001 Benno Rice. 35135549Sdes * All rights reserved. 36135549Sdes * 37135549Sdes * Redistribution and use in source and binary forms, with or without 38170224Sdougb * modification, are permitted provided that the following conditions 39135549Sdes * are met: 40135549Sdes * 1. Redistributions of source code must retain the above copyright 41135549Sdes * notice, this list of conditions and the following disclaimer. 42135549Sdes * 2. Redistributions in binary form must reproduce the above copyright 43135549Sdes * notice, this list of conditions and the following disclaimer in the 44135549Sdes * documentation and/or other materials provided with the distribution. 45135549Sdes * 46135549Sdes * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47135549Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48135549Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49135549Sdes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50135549Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51135549Sdes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52135549Sdes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53135549Sdes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54135549Sdes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55135549Sdes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56135549Sdes */ 57135549Sdes 58135549Sdes#include <sys/cdefs.h> 59135549Sdes__FBSDID("$FreeBSD: head/sys/powerpc/aim/clock.c 212453 2010-09-11 04:45:51Z mav $"); 60135549Sdes 61135549Sdes#include <sys/param.h> 62135549Sdes#include <sys/systm.h> 63135549Sdes#include <sys/kernel.h> 64135549Sdes#include <sys/bus.h> 65135549Sdes#include <sys/interrupt.h> 66135549Sdes#include <sys/pcpu.h> 67135549Sdes#include <sys/sysctl.h> 68135549Sdes#include <sys/timeet.h> 69135549Sdes#include <sys/timetc.h> 70135549Sdes 71135549Sdes#include <dev/ofw/openfirm.h> 72135549Sdes 73135549Sdes#include <machine/clock.h> 74135549Sdes#include <machine/cpu.h> 75135549Sdes#include <machine/intr_machdep.h> 76135549Sdes#include <machine/md_var.h> 77135549Sdes#include <machine/smp.h> 78135549Sdes 79170224Sdougb/* 80135549Sdes * Initially we assume a processor with a bus frequency of 12.5 MHz. 81135549Sdes */ 82135549Sdesstatic int initialized = 0; 83193149Sdougbstatic u_long ns_per_tick = 80; 84193149Sdougbstatic u_long ticks_per_sec = 12500000; 85193149Sdougbstatic u_long *decr_counts[MAXCPU]; 86224093Sdougb 87170224Sdougbstatic int decr_et_start(struct eventtimer *et, 88135549Sdes struct bintime *first, struct bintime *period); 89135549Sdesstatic int decr_et_stop(struct eventtimer *et); 90135549Sdesstatic timecounter_get_t decr_get_timecount; 91165077Sdougb 92224093Sdougbstruct decr_state { 93135549Sdes int mode; /* 0 - off, 1 - periodic, 2 - one-shot. */ 94135549Sdes int32_t div; /* Periodic divisor. */ 95135549Sdes}; 96135549Sdesstatic DPCPU_DEFINE(struct decr_state, decr_state); 97135549Sdes 98135549Sdesstatic struct eventtimer decr_et; 99135549Sdesstatic struct timecounter decr_tc = { 100170224Sdougb decr_get_timecount, /* get_timecount */ 101135549Sdes 0, /* no poll_pps */ 102135549Sdes ~0u, /* counter_mask */ 103135549Sdes 0, /* frequency */ 104135549Sdes "timebase" /* name */ 105135549Sdes}; 106135549Sdes 107135549Sdes/* 108135549Sdes * Decrementor interrupt handler. 109135549Sdes */ 110135549Sdesvoid 111135549Sdesdecr_intr(struct trapframe *frame) 112135549Sdes{ 113135549Sdes struct decr_state *s = DPCPU_PTR(decr_state); 114135549Sdes int nticks = 0; 115135549Sdes int32_t val; 116135549Sdes 117135549Sdes if (!initialized) 118135549Sdes return; 119135549Sdes 120135549Sdes (*decr_counts[curcpu])++; 121135549Sdes 122135549Sdes if (s->mode == 1) { 123135549Sdes /* 124135549Sdes * Based on the actual time delay since the last decrementer 125135549Sdes * reload, we arrange for earlier interrupt next time. 126135549Sdes */ 127135549Sdes __asm ("mfdec %0" : "=r"(val)); 128135549Sdes while (val < 0) { 129135549Sdes val += s->div; 130135549Sdes nticks++; 131135549Sdes } 132135549Sdes mtdec(val); 133135549Sdes } else if (s->mode == 2) { 134135549Sdes nticks = 1; 135135549Sdes decr_et_stop(NULL); 136135549Sdes } 137135549Sdes 138135549Sdes while (nticks-- > 0) { 139135549Sdes if (decr_et.et_active) 140135549Sdes decr_et.et_event_cb(&decr_et, decr_et.et_arg); 141135549Sdes } 142135549Sdes} 143135549Sdes 144135549Sdes/* 145135549Sdes * BSP early initialization. 146135549Sdes */ 147135549Sdesvoid 148135549Sdesdecr_init(void) 149135549Sdes{ 150135549Sdes struct cpuref cpu; 151135549Sdes char buf[32]; 152135549Sdes 153135549Sdes /* 154135549Sdes * Check the BSP's timebase frequency. Sometimes we can't find the BSP, so fall 155135549Sdes * back to the first CPU in this case. 156135549Sdes */ 157135549Sdes if (platform_smp_get_bsp(&cpu) != 0) 158135549Sdes platform_smp_first_cpu(&cpu); 159135549Sdes ticks_per_sec = platform_timebase_freq(&cpu); 160135549Sdes ns_per_tick = 1000000000 / ticks_per_sec; 161135549Sdes 162135549Sdes set_cputicker(mftb, ticks_per_sec, 0); 163135549Sdes snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); 164135549Sdes intrcnt_add(buf, &decr_counts[curcpu]); 165135549Sdes decr_et_stop(NULL); 166135549Sdes initialized = 1; 167135549Sdes} 168135549Sdes 169135549Sdes#ifdef SMP 170135549Sdes/* 171135549Sdes * AP early initialization. 172135549Sdes */ 173135549Sdesvoid 174135549Sdesdecr_ap_init(void) 175135549Sdes{ 176135549Sdes char buf[32]; 177135549Sdes 178135549Sdes snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); 179135549Sdes intrcnt_add(buf, &decr_counts[curcpu]); 180135549Sdes decr_et_stop(NULL); 181135549Sdes} 182135549Sdes#endif 183135549Sdes 184170224Sdougb/* 185135549Sdes * Final initialization. 186135549Sdes */ 187135549Sdesvoid 188193149Sdougbdecr_tc_init(void) 189193149Sdougb{ 190193149Sdougb 191193149Sdougb decr_tc.tc_frequency = ticks_per_sec; 192193149Sdougb tc_init(&decr_tc); 193193149Sdougb decr_et.et_name = "decrementer"; 194193149Sdougb decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | 195224093Sdougb ET_FLAGS_PERCPU; 196170224Sdougb decr_et.et_quality = 1000; 197135549Sdes decr_et.et_frequency = ticks_per_sec; 198135549Sdes decr_et.et_min_period.sec = 0; 199135549Sdes decr_et.et_min_period.frac = 200135549Sdes ((0x00000002LLU << 32) / ticks_per_sec) << 32; 201135549Sdes decr_et.et_max_period.sec = 0x7fffffffLLU / ticks_per_sec; 202135549Sdes decr_et.et_max_period.frac = 203135549Sdes ((0x7fffffffLLU << 32) / ticks_per_sec) << 32; 204165077Sdougb decr_et.et_start = decr_et_start; 205224093Sdougb decr_et.et_stop = decr_et_stop; 206135549Sdes decr_et.et_priv = NULL; 207135549Sdes et_register(&decr_et); 208135549Sdes} 209135549Sdes 210135549Sdes/* 211135549Sdes * Event timer start method. 212135549Sdes */ 213170224Sdougbstatic int 214135549Sdesdecr_et_start(struct eventtimer *et, 215135549Sdes struct bintime *first, struct bintime *period) 216135549Sdes{ 217135549Sdes struct decr_state *s = DPCPU_PTR(decr_state); 218135549Sdes uint32_t fdiv; 219135549Sdes 220135549Sdes if (period != NULL) { 221135549Sdes s->mode = 1; 222135549Sdes s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32; 223135549Sdes if (period->sec != 0) 224135549Sdes s->div += decr_et.et_frequency * period->sec; 225135549Sdes } else { 226135549Sdes s->mode = 2; 227135549Sdes s->div = 0x7fffffff; 228135549Sdes } 229135549Sdes if (first != NULL) { 230135549Sdes fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32; 231135549Sdes if (first->sec != 0) 232135549Sdes fdiv += decr_et.et_frequency * first->sec; 233135549Sdes } else 234135549Sdes fdiv = s->div; 235135549Sdes 236135549Sdes mtdec(fdiv); 237135549Sdes return (0); 238135549Sdes} 239135549Sdes 240135549Sdes/* 241135549Sdes * Event timer stop method. 242135549Sdes */ 243135549Sdesstatic int 244135549Sdesdecr_et_stop(struct eventtimer *et) 245135549Sdes{ 246135549Sdes struct decr_state *s = DPCPU_PTR(decr_state); 247135549Sdes 248135549Sdes s->mode = 0; 249135549Sdes s->div = 0x7fffffff; 250135549Sdes mtdec(s->div); 251135549Sdes return (0); 252135549Sdes} 253135549Sdes 254135549Sdes/* 255135549Sdes * Timecounter get method. 256135549Sdes */ 257135549Sdesstatic unsigned 258135549Sdesdecr_get_timecount(struct timecounter *tc) 259135549Sdes{ 260135549Sdes register_t tb; 261135549Sdes 262135549Sdes __asm __volatile("mftb %0" : "=r"(tb)); 263135549Sdes return (tb); 264135549Sdes} 265135549Sdes 266135549Sdes/* 267135549Sdes * Wait for about n microseconds (at least!). 268135549Sdes */ 269135549Sdesvoid 270135549SdesDELAY(int n) 271135549Sdes{ 272135549Sdes u_quad_t tb, ttb; 273135549Sdes 274135549Sdes tb = mftb(); 275135549Sdes ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick; 276135549Sdes while (tb < ttb) 277135549Sdes tb = mftb(); 278135549Sdes} 279135549Sdes 280135549Sdes