1/*- 2 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * from: NetBSD: mc146818.c,v 1.4 2003/11/24 06:20:40 tsutsui Exp 27 */ 28 29#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * from: NetBSD: mc146818.c,v 1.4 2003/11/24 06:20:40 tsutsui Exp 27 */ 28 29#include <sys/cdefs.h>
|
30__FBSDID("$FreeBSD: head/sys/dev/mc146818/mc146818.c 146417 2005-05-19 21:20:42Z marius $");
| 30__FBSDID("$FreeBSD: head/sys/dev/mc146818/mc146818.c 146982 2005-06-04 23:24:50Z marius $");
|
31 32/* 33 * mc146818 and compatible time of day chip subroutines 34 */ 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/bus.h> 39#include <sys/clock.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42 43#include <machine/bus.h> 44 45#include <dev/mc146818/mc146818reg.h> 46#include <dev/mc146818/mc146818var.h> 47 48#include "clock_if.h" 49 50static u_int mc146818_def_getcent(device_t); 51static void mc146818_def_setcent(device_t, u_int); 52static u_int mc146818_def_read(device_t, u_int); 53static void mc146818_def_write(device_t, u_int, u_int); 54 55int 56mc146818_attach(device_t dev) 57{ 58 struct mc146818_softc *sc; 59 60 sc = device_get_softc(dev); 61 62 if (mtx_initialized(&sc->sc_mtx) == 0) { 63 device_printf(dev, "%s: mutex not initialized\n", __func__); 64 return (ENXIO); 65 } 66 67 if (sc->sc_mcread == NULL) 68 sc->sc_mcread = mc146818_def_read; 69 if (sc->sc_mcwrite == NULL) 70 sc->sc_mcwrite = mc146818_def_write; 71 72 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 73 /* 74 * Note that setting MC146818_NO_CENT_ADJUST means that 75 * the century has to be stored in NVRAM somewhere. 76 */ 77 if (sc->sc_getcent == NULL) 78 sc->sc_getcent = mc146818_def_getcent; 79 if (sc->sc_setcent == NULL) 80 sc->sc_setcent = mc146818_def_setcent; 81 } 82
| 31 32/* 33 * mc146818 and compatible time of day chip subroutines 34 */ 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/bus.h> 39#include <sys/clock.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42 43#include <machine/bus.h> 44 45#include <dev/mc146818/mc146818reg.h> 46#include <dev/mc146818/mc146818var.h> 47 48#include "clock_if.h" 49 50static u_int mc146818_def_getcent(device_t); 51static void mc146818_def_setcent(device_t, u_int); 52static u_int mc146818_def_read(device_t, u_int); 53static void mc146818_def_write(device_t, u_int, u_int); 54 55int 56mc146818_attach(device_t dev) 57{ 58 struct mc146818_softc *sc; 59 60 sc = device_get_softc(dev); 61 62 if (mtx_initialized(&sc->sc_mtx) == 0) { 63 device_printf(dev, "%s: mutex not initialized\n", __func__); 64 return (ENXIO); 65 } 66 67 if (sc->sc_mcread == NULL) 68 sc->sc_mcread = mc146818_def_read; 69 if (sc->sc_mcwrite == NULL) 70 sc->sc_mcwrite = mc146818_def_write; 71 72 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 73 /* 74 * Note that setting MC146818_NO_CENT_ADJUST means that 75 * the century has to be stored in NVRAM somewhere. 76 */ 77 if (sc->sc_getcent == NULL) 78 sc->sc_getcent = mc146818_def_getcent; 79 if (sc->sc_setcent == NULL) 80 sc->sc_setcent = mc146818_def_setcent; 81 } 82
|
83 mtx_lock(&sc->sc_mtx);
| 83 mtx_lock_spin(&sc->sc_mtx);
|
84 if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
| 84 if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
|
85 mtx_unlock(&sc->sc_mtx);
| 85 mtx_unlock_spin(&sc->sc_mtx);
|
86 device_printf(dev, "%s: battery low\n", __func__); 87 return (ENXIO); 88 } 89 90 sc->sc_rega = MC_BASE_32_KHz; 91 (*sc->sc_mcwrite)(dev, MC_REGA, sc->sc_rega); 92 93 sc->sc_regb = 0; 94 sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY; 95 sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR; 96 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
| 86 device_printf(dev, "%s: battery low\n", __func__); 87 return (ENXIO); 88 } 89 90 sc->sc_rega = MC_BASE_32_KHz; 91 (*sc->sc_mcwrite)(dev, MC_REGA, sc->sc_rega); 92 93 sc->sc_regb = 0; 94 sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY; 95 sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR; 96 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
|
97 mtx_unlock(&sc->sc_mtx);
| 97 mtx_unlock_spin(&sc->sc_mtx);
|
98 99 clock_register(dev, 1000000); /* 1 second resolution. */ 100 101 return (0); 102} 103 104/* 105 * Get time of day and convert it to a struct timespec. 106 * Return 0 on success, an error number otherwise. 107 */ 108int 109mc146818_gettime(device_t dev, struct timespec *ts) 110{ 111 struct mc146818_softc *sc; 112 struct clocktime ct; 113 int timeout, cent, year; 114 115 sc = device_get_softc(dev); 116 117 timeout = 1000000; /* XXX how long should we wait? */ 118
| 98 99 clock_register(dev, 1000000); /* 1 second resolution. */ 100 101 return (0); 102} 103 104/* 105 * Get time of day and convert it to a struct timespec. 106 * Return 0 on success, an error number otherwise. 107 */ 108int 109mc146818_gettime(device_t dev, struct timespec *ts) 110{ 111 struct mc146818_softc *sc; 112 struct clocktime ct; 113 int timeout, cent, year; 114 115 sc = device_get_softc(dev); 116 117 timeout = 1000000; /* XXX how long should we wait? */ 118
|
119 mtx_lock(&sc->sc_mtx);
| |
120 /* 121 * If MC_REGA_UIP is 0 we have at least 244us before the next 122 * update. If it's 1 an update is imminent. 123 */ 124 for (;;) {
| 119 /* 120 * If MC_REGA_UIP is 0 we have at least 244us before the next 121 * update. If it's 1 an update is imminent. 122 */ 123 for (;;) {
|
| 124 mtx_lock_spin(&sc->sc_mtx);
|
125 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) 126 break;
| 125 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) 126 break;
|
| 127 mtx_unlock_spin(&sc->sc_mtx);
|
127 if (--timeout < 0) {
| 128 if (--timeout < 0) {
|
128 mtx_unlock(&sc->sc_mtx);
| |
129 device_printf(dev, "%s: timeout\n", __func__); 130 return (EBUSY); 131 } 132 } 133 134#define FROMREG(x) ((sc->sc_flag & MC146818_BCD) ? FROMBCD(x) : (x)) 135 136 ct.nsec = 0; 137 ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC)); 138 ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN)); 139 ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR)); 140 /* Map dow from 1 - 7 to 0 - 6. */ 141 ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1; 142 ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM)); 143 ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH)); 144 year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR)); 145 year += sc->sc_year0; 146 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 147 cent = (*sc->sc_getcent)(dev); 148 year += cent * 100; 149 } else if (year < POSIX_BASE_YEAR) 150 year += 100;
| 129 device_printf(dev, "%s: timeout\n", __func__); 130 return (EBUSY); 131 } 132 } 133 134#define FROMREG(x) ((sc->sc_flag & MC146818_BCD) ? FROMBCD(x) : (x)) 135 136 ct.nsec = 0; 137 ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC)); 138 ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN)); 139 ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR)); 140 /* Map dow from 1 - 7 to 0 - 6. */ 141 ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1; 142 ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM)); 143 ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH)); 144 year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR)); 145 year += sc->sc_year0; 146 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 147 cent = (*sc->sc_getcent)(dev); 148 year += cent * 100; 149 } else if (year < POSIX_BASE_YEAR) 150 year += 100;
|
151 mtx_unlock(&sc->sc_mtx);
| 151 mtx_unlock_spin(&sc->sc_mtx);
|
152 153 ct.year = year; 154 155 return (clock_ct_to_ts(&ct, ts)); 156} 157 158#ifdef notyet 159int 160mc146818_getsecs(device_t dev, int *secp) 161{ 162 struct mc146818_softc *sc; 163 int sec, timeout; 164 165 sc = device_get_softc(dev); 166 167 timeout = 1000000; /* XXX how long should we wait? */ 168
| 152 153 ct.year = year; 154 155 return (clock_ct_to_ts(&ct, ts)); 156} 157 158#ifdef notyet 159int 160mc146818_getsecs(device_t dev, int *secp) 161{ 162 struct mc146818_softc *sc; 163 int sec, timeout; 164 165 sc = device_get_softc(dev); 166 167 timeout = 1000000; /* XXX how long should we wait? */ 168
|
169 mtx_lock(&sc->sc_mtx);
| |
170 for (;;) {
| 169 for (;;) {
|
| 170 mtx_lock_spin(&sc->sc_mtx);
|
171 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) { 172 sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
| 171 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) { 172 sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
|
| 173 mtx_unlock_spin(&sc->sc_mtx);
|
173 break; 174 }
| 174 break; 175 }
|
| 176 mtx_unlock_spin(&sc->sc_mtx);
|
175 if (--timeout == 0) {
| 177 if (--timeout == 0) {
|
176 mtx_unlock(&sc->sc_mtx);
| |
177 device_printf(dev, "%s: timeout\n", __func__); 178 return (EBUSY); 179 } 180 }
| 178 device_printf(dev, "%s: timeout\n", __func__); 179 return (EBUSY); 180 } 181 }
|
181 mtx_unlock(&sc->sc_mtx);
| |
182 183#undef FROMREG 184 185 *secp = sec; 186 return (0); 187} 188#endif 189 190/* 191 * Set the time of day clock based on the value of the struct timespec arg. 192 * Return 0 on success, an error number otherwise. 193 */ 194int 195mc146818_settime(device_t dev, struct timespec *ts) 196{ 197 struct mc146818_softc *sc; 198 struct clocktime ct; 199 int cent, year; 200 201 sc = device_get_softc(dev); 202 203 /* Accuracy is only one second. */ 204 if (ts->tv_nsec >= 500000000) 205 ts->tv_sec++; 206 ts->tv_nsec = 0; 207 clock_ts_to_ct(ts, &ct); 208
| 182 183#undef FROMREG 184 185 *secp = sec; 186 return (0); 187} 188#endif 189 190/* 191 * Set the time of day clock based on the value of the struct timespec arg. 192 * Return 0 on success, an error number otherwise. 193 */ 194int 195mc146818_settime(device_t dev, struct timespec *ts) 196{ 197 struct mc146818_softc *sc; 198 struct clocktime ct; 199 int cent, year; 200 201 sc = device_get_softc(dev); 202 203 /* Accuracy is only one second. */ 204 if (ts->tv_nsec >= 500000000) 205 ts->tv_sec++; 206 ts->tv_nsec = 0; 207 clock_ts_to_ct(ts, &ct); 208
|
209 mtx_lock(&sc->sc_mtx);
| 209 mtx_lock_spin(&sc->sc_mtx);
|
210 /* Disable RTC updates and interrupts (if enabled). */ 211 (*sc->sc_mcwrite)(dev, MC_REGB, 212 ((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET)); 213 214#define TOREG(x) ((sc->sc_flag & MC146818_BCD) ? TOBCD(x) : (x)) 215 216 (*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec)); 217 (*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min)); 218 (*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour)); 219 /* Map dow from 0 - 6 to 1 - 7. */ 220 (*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1)); 221 (*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day)); 222 (*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon)); 223 224 year = ct.year - sc->sc_year0; 225 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 226 cent = year / 100; 227 (*sc->sc_setcent)(dev, cent); 228 year -= cent * 100; 229 } else if (year > 99) 230 year -= 100; 231 (*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year)); 232 233 /* Reenable RTC updates and interrupts. */ 234 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
| 210 /* Disable RTC updates and interrupts (if enabled). */ 211 (*sc->sc_mcwrite)(dev, MC_REGB, 212 ((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET)); 213 214#define TOREG(x) ((sc->sc_flag & MC146818_BCD) ? TOBCD(x) : (x)) 215 216 (*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec)); 217 (*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min)); 218 (*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour)); 219 /* Map dow from 0 - 6 to 1 - 7. */ 220 (*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1)); 221 (*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day)); 222 (*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon)); 223 224 year = ct.year - sc->sc_year0; 225 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) { 226 cent = year / 100; 227 (*sc->sc_setcent)(dev, cent); 228 year -= cent * 100; 229 } else if (year > 99) 230 year -= 100; 231 (*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year)); 232 233 /* Reenable RTC updates and interrupts. */ 234 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
|
235 mtx_unlock(&sc->sc_mtx);
| 235 mtx_unlock_spin(&sc->sc_mtx);
|
236 237#undef TOREG 238 239 return (0); 240} 241 242#define MC_ADDR 0 243#define MC_DATA 1 244 245static u_int 246mc146818_def_read(device_t dev, u_int reg) 247{ 248 struct mc146818_softc *sc; 249 250 sc = device_get_softc(dev); 251 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg); 252 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, MC_DATA)); 253} 254 255static void 256mc146818_def_write(device_t dev, u_int reg, u_int val) 257{ 258 struct mc146818_softc *sc; 259 260 sc = device_get_softc(dev); 261 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg); 262 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_DATA, val); 263} 264 265/* 266 * Looks like it's common even across platforms to store the century at 267 * 0x32 in the NVRAM of the mc146818. 268 */ 269#define MC_CENT 0x32 270 271static u_int 272mc146818_def_getcent(device_t dev) 273{ 274 struct mc146818_softc *sc; 275 276 sc = device_get_softc(dev); 277 return ((*sc->sc_mcread)(dev, MC_CENT)); 278} 279 280static void 281mc146818_def_setcent(device_t dev, u_int cent) 282{ 283 struct mc146818_softc *sc; 284 285 sc = device_get_softc(dev); 286 (*sc->sc_mcwrite)(dev, MC_CENT, cent); 287}
| 236 237#undef TOREG 238 239 return (0); 240} 241 242#define MC_ADDR 0 243#define MC_DATA 1 244 245static u_int 246mc146818_def_read(device_t dev, u_int reg) 247{ 248 struct mc146818_softc *sc; 249 250 sc = device_get_softc(dev); 251 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg); 252 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, MC_DATA)); 253} 254 255static void 256mc146818_def_write(device_t dev, u_int reg, u_int val) 257{ 258 struct mc146818_softc *sc; 259 260 sc = device_get_softc(dev); 261 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg); 262 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_DATA, val); 263} 264 265/* 266 * Looks like it's common even across platforms to store the century at 267 * 0x32 in the NVRAM of the mc146818. 268 */ 269#define MC_CENT 0x32 270 271static u_int 272mc146818_def_getcent(device_t dev) 273{ 274 struct mc146818_softc *sc; 275 276 sc = device_get_softc(dev); 277 return ((*sc->sc_mcread)(dev, MC_CENT)); 278} 279 280static void 281mc146818_def_setcent(device_t dev, u_int cent) 282{ 283 struct mc146818_softc *sc; 284 285 sc = device_get_softc(dev); 286 (*sc->sc_mcwrite)(dev, MC_CENT, cent); 287}
|