1 /* $NetBSD: au_timer.c,v 1.2 2003/07/15 02:43:34 lukem Exp $ */ 2 3 /* 4 * Copyright 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: au_timer.c,v 1.2 2003/07/15 02:43:34 lukem Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/kernel.h> 43 44 #include <machine/bus.h> 45 #include <mips/locore.h> 46 47 #include <evbmips/evbmips/clockvar.h> 48 #include <mips/alchemy/include/aureg.h> 49 #include <mips/alchemy/include/auvar.h> 50 51 /* 52 * Set a programmable clock register. 53 * If "wait" is non-zero, wait for that bit to become 0 in the 54 * counter control register before and after writing to the 55 * specified clock register. 56 */ 57 #define SET_PC_REG(reg, wait, val) \ 58 do { \ 59 if (wait) \ 60 while (bus_space_read_4(st, sh, PC_COUNTER_CONTROL) \ 61 & (wait)) \ 62 /* nothing */; \ 63 bus_space_write_4(st, sh, (reg), (val)); \ 64 if (wait) \ 65 while (bus_space_read_4(st, sh, (reg)) & (wait)) \ 66 /* nothing */; \ 67 } while (0) 68 69 void 70 au_cal_timers(bus_space_tag_t st, bus_space_handle_t sh) 71 { 72 uint32_t ctrdiff[4], startctr, endctr; 73 uint32_t ctl, ctr, octr; 74 int i; 75 76 /* Enable the programmable counter 1. */ 77 ctl = bus_space_read_4(st, sh, PC_COUNTER_CONTROL); 78 if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1)); 79 SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl | CC_EO | CC_EN1); 80 81 /* Initialize for 16Hz. */ 82 SET_PC_REG(PC_TRIM1, CC_T1S, PC_RATE / 16 - 1); 83 84 /* Run the loop an extra time to prime the cache. */ 85 for (i = 0; i < 4; i++) { 86 /* Reset the counter. */ 87 SET_PC_REG(PC_COUNTER_WRITE1, CC_C1S, 0); 88 89 /* Wait for 1/16th of a second. */ 90 //startctr = mips3_cp0_count_read(); 91 92 /* Wait for the PC to tick over. */ 93 ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 94 do { 95 octr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 96 } while (ctr == octr); 97 98 startctr = mips3_cp0_count_read(); 99 do { 100 ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 101 } while (ctr == octr); // while (ctr <= octr + 1); 102 endctr = mips3_cp0_count_read(); 103 ctrdiff[i] = endctr - startctr; 104 } 105 106 /* Disable the counter (if it wasn't enabled already). */ 107 if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1)); 108 SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl); 109 110 /* Compute the number of cycles per second. */ 111 curcpu()->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16; 112 113 /* Compute the number of ticks for hz. */ 114 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; 115 116 /* Compute the delay divisor. */ 117 curcpu()->ci_divisor_delay = 118 ((curcpu()->ci_cpu_freq + 500000) / 1000000); 119 120 /* 121 * To implement a more accurate microtime using the CP0 COUNT 122 * register we need to divide that register by the number of 123 * cycles per MHz. But... 124 * 125 * DIV and DIVU are expensive on MIPS (eg 75 clocks on the 126 * R4000). MULT and MULTU are only 12 clocks on the same CPU. 127 * On the SB1 these appear to be 40-72 clocks for DIV/DIVU and 3 128 * clocks for MUL/MULTU. 129 * 130 * The strategy we use to to calculate the reciprical of cycles 131 * per MHz, scaled by 1<<32. Then we can simply issue a MULTU 132 * and pluck of the HI register and have the results of the 133 * division. 134 */ 135 curcpu()->ci_divisor_recip = 136 0x100000000ULL / curcpu()->ci_divisor_delay; 137 138 /* 139 * Get correct cpu frequency if the CPU runs at twice the 140 * external/cp0-count frequency. 141 */ 142 if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) 143 curcpu()->ci_cpu_freq *= 2; 144 145 #ifdef DEBUG 146 printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n", 147 curcpu()->ci_cpu_freq, ctrdiff[2], ctrdiff[3]); 148 #endif 149 } 150