1 /* $OpenBSD: clock.c,v 1.25 2021/02/23 04:44:30 cheloha Exp $ */ 2 /* $NetBSD: clock.c,v 1.29 2000/06/05 21:47:10 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1988 University of Utah. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * the Systems Programming Group of the University of Utah Computer 11 * Science Department and Ralph Campbell. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: Utah Hdr: clock.c 1.18 91/01/21 38 * 39 * @(#)clock.c 8.1 (Berkeley) 6/10/93 40 */ 41 42 #include <sys/param.h> 43 #include <sys/kernel.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/evcount.h> 47 #include <sys/timetc.h> 48 49 #include <dev/clock_subr.h> 50 51 #include <machine/rpb.h> 52 #include <machine/autoconf.h> 53 #include <machine/cpuconf.h> 54 55 #include <alpha/alpha/clockvar.h> 56 57 extern int schedhz; 58 59 struct device *clockdev; 60 const struct clockfns *clockfns; 61 62 struct evcount clk_count; 63 int clk_irq = 0; 64 65 u_int rpcc_get_timecount(struct timecounter *); 66 struct timecounter rpcc_timecounter = { 67 .tc_get_timecount = rpcc_get_timecount, 68 .tc_poll_pps = NULL, 69 .tc_counter_mask = ~0u, 70 .tc_frequency = 0, 71 .tc_name = "rpcc", 72 .tc_quality = 0, 73 .tc_priv = NULL, 74 .tc_user = 0, 75 }; 76 77 extern todr_chip_handle_t todr_handle; 78 struct todr_chip_handle rtc_todr; 79 80 int 81 rtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 82 { 83 struct clock_ymdhms dt; 84 struct clocktime ct; 85 int year; 86 87 (*clockfns->cf_get)(clockdev, tv->tv_sec, &ct); 88 89 year = 1900 + ct.year; 90 if (year < 1970) 91 year += 100; 92 dt.dt_year = year; 93 dt.dt_mon = ct.mon; 94 dt.dt_day = ct.day; 95 dt.dt_hour = ct.hour; 96 dt.dt_min = ct.min; 97 dt.dt_sec = ct.sec; 98 99 tv->tv_sec = clock_ymdhms_to_secs(&dt); 100 tv->tv_usec = 0; 101 return 0; 102 } 103 104 int 105 rtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 106 { 107 struct clock_ymdhms dt; 108 struct clocktime ct; 109 110 clock_secs_to_ymdhms(tv->tv_sec, &dt); 111 112 /* rt clock wants 2 digits */ 113 ct.year = dt.dt_year % 100; 114 ct.mon = dt.dt_mon; 115 ct.day = dt.dt_day; 116 ct.hour = dt.dt_hour; 117 ct.min = dt.dt_min; 118 ct.sec = dt.dt_sec; 119 ct.dow = dt.dt_wday; 120 121 (*clockfns->cf_set)(clockdev, &ct); 122 return 0; 123 } 124 125 void 126 clockattach(dev, fns) 127 struct device *dev; 128 const struct clockfns *fns; 129 { 130 131 /* 132 * Just bookkeeping. 133 */ 134 printf("\n"); 135 136 if (clockfns != NULL) 137 panic("clockattach: multiple clocks"); 138 clockdev = dev; 139 clockfns = fns; 140 } 141 142 /* 143 * Machine-dependent clock routines. 144 */ 145 146 /* 147 * Start the real-time and statistics clocks. Leave stathz 0 since there 148 * are no other timers available. 149 */ 150 void 151 cpu_initclocks(void) 152 { 153 u_int32_t cycles_per_sec; 154 struct clocktime ct; 155 u_int32_t first_rpcc, second_rpcc; /* only lower 32 bits are valid */ 156 int first_sec; 157 158 if (clockfns == NULL) 159 panic("cpu_initclocks: no clock attached"); 160 161 tick = 1000000 / hz; /* number of microseconds between interrupts */ 162 163 /* 164 * Establish the clock interrupt; it's a special case. 165 * 166 * We establish the clock interrupt this late because if 167 * we do it at clock attach time, we may have never been at 168 * spl0() since taking over the system. Some versions of 169 * PALcode save a clock interrupt, which would get delivered 170 * when we spl0() in autoconf.c. If established the clock 171 * interrupt handler earlier, that interrupt would go to 172 * hardclock, which would then fall over because the pointer 173 * to the virtual timers wasn't set at that time. 174 */ 175 platform.clockintr = hardclock; 176 schedhz = 16; 177 178 evcount_attach(&clk_count, "clock", &clk_irq); 179 180 /* 181 * Get the clock started. 182 */ 183 (*clockfns->cf_init)(clockdev); 184 185 /* 186 * Calibrate the cycle counter frequency. 187 */ 188 (*clockfns->cf_get)(clockdev, 0, &ct); 189 first_sec = ct.sec; 190 191 /* Let the clock tick one second. */ 192 do { 193 first_rpcc = alpha_rpcc(); 194 (*clockfns->cf_get)(clockdev, 0, &ct); 195 } while (ct.sec == first_sec); 196 first_sec = ct.sec; 197 /* Let the clock tick one more second. */ 198 do { 199 second_rpcc = alpha_rpcc(); 200 (*clockfns->cf_get)(clockdev, 0, &ct); 201 } while (ct.sec == first_sec); 202 203 cycles_per_sec = second_rpcc - first_rpcc; 204 205 rpcc_timecounter.tc_frequency = cycles_per_sec; 206 tc_init(&rpcc_timecounter); 207 208 rtc_todr.todr_gettime = rtc_gettime; 209 rtc_todr.todr_settime = rtc_settime; 210 todr_handle = &rtc_todr; 211 } 212 213 /* 214 * We assume newhz is either stathz or profhz, and that neither will 215 * change after being set up above. Could recalculate intervals here 216 * but that would be a drag. 217 */ 218 void 219 setstatclockrate(newhz) 220 int newhz; 221 { 222 223 /* nothing we can do */ 224 } 225 226 u_int 227 rpcc_get_timecount(struct timecounter *tc) 228 { 229 return alpha_rpcc(); 230 } 231