1 /* $NetBSD: au_timer.c,v 1.1 2002/07/29 15:39:12 simonb 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/param.h> 39 #include <sys/kernel.h> 40 41 #include <machine/bus.h> 42 #include <mips/locore.h> 43 44 #include <evbmips/evbmips/clockvar.h> 45 #include <mips/alchemy/include/aureg.h> 46 #include <mips/alchemy/include/auvar.h> 47 48 /* 49 * Set a programmable clock register. 50 * If "wait" is non-zero, wait for that bit to become 0 in the 51 * counter control register before and after writing to the 52 * specified clock register. 53 */ 54 #define SET_PC_REG(reg, wait, val) \ 55 do { \ 56 if (wait) \ 57 while (bus_space_read_4(st, sh, PC_COUNTER_CONTROL) \ 58 & (wait)) \ 59 /* nothing */; \ 60 bus_space_write_4(st, sh, (reg), (val)); \ 61 if (wait) \ 62 while (bus_space_read_4(st, sh, (reg)) & (wait)) \ 63 /* nothing */; \ 64 } while (0) 65 66 void 67 au_cal_timers(bus_space_tag_t st, bus_space_handle_t sh) 68 { 69 uint32_t ctrdiff[4], startctr, endctr; 70 uint32_t ctl, ctr, octr; 71 int i; 72 73 /* Enable the programmable counter 1. */ 74 ctl = bus_space_read_4(st, sh, PC_COUNTER_CONTROL); 75 if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1)); 76 SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl | CC_EO | CC_EN1); 77 78 /* Initialize for 16Hz. */ 79 SET_PC_REG(PC_TRIM1, CC_T1S, PC_RATE / 16 - 1); 80 81 /* Run the loop an extra time to prime the cache. */ 82 for (i = 0; i < 4; i++) { 83 /* Reset the counter. */ 84 SET_PC_REG(PC_COUNTER_WRITE1, CC_C1S, 0); 85 86 /* Wait for 1/16th of a second. */ 87 //startctr = mips3_cp0_count_read(); 88 89 /* Wait for the PC to tick over. */ 90 ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 91 do { 92 octr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 93 } while (ctr == octr); 94 95 startctr = mips3_cp0_count_read(); 96 do { 97 ctr = bus_space_read_4(st, sh, PC_COUNTER_READ_1); 98 } while (ctr == octr); // while (ctr <= octr + 1); 99 endctr = mips3_cp0_count_read(); 100 ctrdiff[i] = endctr - startctr; 101 } 102 103 /* Disable the counter (if it wasn't enabled already). */ 104 if ((ctl & (CC_EO | CC_EN1)) != (CC_EO | CC_EN1)); 105 SET_PC_REG(PC_COUNTER_CONTROL, 0, ctl); 106 107 /* Compute the number of cycles per second. */ 108 curcpu()->ci_cpu_freq = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16; 109 110 /* Compute the number of ticks for hz. */ 111 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; 112 113 /* Compute the delay divisor. */ 114 curcpu()->ci_divisor_delay = 115 ((curcpu()->ci_cpu_freq + 500000) / 1000000); 116 117 /* 118 * To implement a more accurate microtime using the CP0 COUNT 119 * register we need to divide that register by the number of 120 * cycles per MHz. But... 121 * 122 * DIV and DIVU are expensive on MIPS (eg 75 clocks on the 123 * R4000). MULT and MULTU are only 12 clocks on the same CPU. 124 * On the SB1 these appear to be 40-72 clocks for DIV/DIVU and 3 125 * clocks for MUL/MULTU. 126 * 127 * The strategy we use to to calculate the reciprical of cycles 128 * per MHz, scaled by 1<<32. Then we can simply issue a MULTU 129 * and pluck of the HI register and have the results of the 130 * division. 131 */ 132 curcpu()->ci_divisor_recip = 133 0x100000000ULL / curcpu()->ci_divisor_delay; 134 135 /* 136 * Get correct cpu frequency if the CPU runs at twice the 137 * external/cp0-count frequency. 138 */ 139 if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) 140 curcpu()->ci_cpu_freq *= 2; 141 142 #ifdef DEBUG 143 printf("Timer calibration: %lu cycles/sec [(%u, %u) * 16]\n", 144 curcpu()->ci_cpu_freq, ctrdiff[2], ctrdiff[3]); 145 #endif 146 } 147