1 /* $NetBSD: clock.c,v 1.15 2025/05/17 17:27:21 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 37 * 38 * @(#)clock.c 8.2 (Berkeley) 1/12/94 39 */ 40 41 #include <sys/param.h> 42 43 #include <net/if_ether.h> 44 #include <netinet/in.h> 45 #include <netinet/in_systm.h> 46 47 #include <hp300/stand/common/hilreg.h> 48 49 #include <hp300/dev/frodoreg.h> /* for APCI offsets */ 50 #include <hp300/dev/intioreg.h> /* for frodo offsets */ 51 #include <dev/ic/mc146818reg.h> 52 #include <dev/clock_subr.h> 53 54 #include <lib/libsa/stand.h> 55 #include <lib/libsa/net.h> 56 #include <hp300/stand/common/samachdep.h> 57 58 #define FEBRUARY 2 59 60 #define BBC_SET_REG 0xe0 61 #define BBC_WRITE_REG 0xc2 62 #define BBC_READ_REG 0xc3 63 #define NUM_BBC_REGS 12 64 65 #ifdef BBC_SLOW_GETSECS 66 #define NSKIP_READ_BBC 100 67 #endif 68 69 #define range_test(n, l, h) if ((n) < (l) || (n) > (h)) return false 70 #define bbc_to_decimal(a,b) (bbc_registers[a] * 10 + bbc_registers[b]) 71 72 static uint8_t bbc_registers[13]; 73 static struct hil_dev *bbcaddr = BBCADDR; 74 75 static volatile uint8_t *mcclock = 76 (volatile uint8_t *)(INTIOBASE + FRODO_BASE + FRODO_CALENDAR); 77 78 static bool clock_to_gmt(satime_t *); 79 80 static void read_bbc(void); 81 static uint8_t read_bbc_reg(int); 82 static uint8_t mc_read(u_int); 83 84 satime_t 85 getsecs(void) 86 { 87 static bool clockinited = false; 88 satime_t timbuf = 0; 89 90 if (!clock_to_gmt(&timbuf) && !clockinited) 91 printf("WARNING: bad date in battery clock\n"); 92 clockinited = true; 93 94 /* Battery clock does not store usec's, so forget about it. */ 95 return timbuf; 96 } 97 98 static bool 99 clock_to_gmt(satime_t *timbuf) 100 { 101 int i; 102 satime_t tmp; 103 int year, month, day, hour, min, sec; 104 #ifdef BBC_SLOW_GETSECS 105 static satime_t tim_prev = 0; 106 #endif 107 108 if (machineid == HP_425 && mmuid == MMUID_425_E) { 109 /* 425e uses mcclock on the frodo utility chip */ 110 while ((mc_read(MC_REGA) & MC_REGA_UIP) != 0) 111 continue; 112 sec = mc_read(MC_SEC); 113 min = mc_read(MC_MIN); 114 hour = mc_read(MC_HOUR); 115 day = mc_read(MC_DOM); 116 month = mc_read(MC_MONTH); 117 year = mc_read(MC_YEAR) + 1900; 118 } else { 119 #ifdef BBC_SLOW_GETSECS 120 /* 121 * XXX: 122 * The read_bbc() function against HIL seems extremely slow. 123 * It was being called on every timeout check via getsecs() 124 * so it significantly slowed down loading a kernel via NFS. 125 * 126 * In most cases (e.g., in common/if_le.c and libsa/net.c), 127 * timeout checks are performed using getsecs() in busy loops 128 * without any actual waiting. In such cases, it's not 129 * necessary to read the precise time from the RTC on 130 * every call. 131 */ 132 static int nskip = NSKIP_READ_BBC; 133 134 if (tim_prev != 0 && nskip-- > 0) { 135 *timbuf = tim_prev; 136 return true; 137 } 138 nskip = NSKIP_READ_BBC; 139 #endif 140 141 /* Use the traditional HIL bbc for all other models */ 142 read_bbc(); 143 144 sec = bbc_to_decimal(1, 0); 145 min = bbc_to_decimal(3, 2); 146 147 /* 148 * Hours are different for some reason. Makes no sense really. 149 */ 150 hour = ((bbc_registers[5] & 0x03) * 10) + bbc_registers[4]; 151 day = bbc_to_decimal(8, 7); 152 month = bbc_to_decimal(10, 9); 153 year = bbc_to_decimal(12, 11) + 1900; 154 } 155 156 if (year < POSIX_BASE_YEAR) 157 year += 100; 158 159 #ifdef CLOCK_DEBUG 160 printf("clock todr: %u/%u/%u %u:%u:%u\n", 161 year, month, day, hour, min, sec); 162 #endif 163 164 range_test(hour, 0, 23); 165 range_test(day, 1, 31); 166 range_test(month, 1, 12); 167 168 tmp = 0; 169 170 for (i = POSIX_BASE_YEAR; i < year; i++) 171 tmp += days_per_year(i); 172 if (is_leap_year(year) && month > FEBRUARY) 173 tmp++; 174 175 for (i = 1; i < month; i++) 176 tmp += days_in_month(i); 177 178 tmp += (day - 1); 179 tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 180 181 #ifdef BBC_SLOW_GETSECS 182 tim_prev = tmp; 183 #endif 184 *timbuf = tmp; 185 return true; 186 } 187 188 static void 189 read_bbc(void) 190 { 191 int i; 192 bool read_okay; 193 194 read_okay = false; 195 while (!read_okay) { 196 read_okay = true; 197 for (i = 0; i <= NUM_BBC_REGS; i++) 198 bbc_registers[i] = read_bbc_reg(i); 199 for (i = 0; i <= NUM_BBC_REGS; i++) 200 if (bbc_registers[i] != read_bbc_reg(i)) 201 read_okay = false; 202 } 203 } 204 205 static uint8_t 206 read_bbc_reg(int reg) 207 { 208 uint8_t data = reg; 209 210 if (bbcaddr != NULL) { 211 #if 0 212 send_hil_cmd(bbcaddr, BBC_SET_REG, &data, 1, NULL); 213 send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &data); 214 #else 215 HILWAIT(bbcaddr); 216 bbcaddr->hil_cmd = BBC_SET_REG; 217 HILWAIT(bbcaddr); 218 bbcaddr->hil_data = data; 219 HILWAIT(bbcaddr); 220 bbcaddr->hil_cmd = BBC_READ_REG; 221 HILDATAWAIT(bbcaddr); 222 data = bbcaddr->hil_data; 223 #endif 224 } 225 return data; 226 } 227 228 uint8_t 229 mc_read(u_int reg) 230 { 231 uint8_t datum; 232 233 mcclock[0] = (uint8_t)reg; 234 datum = mcclock[1 << 2]; /* frodo chip has 4 byte stride */ 235 236 return datum; 237 } 238