diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-09 19:59:07 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2007-04-09 19:59:07 +0000 |
commit | 8c8f5bd419d108f0f3ecbab1329a68f355f29b8a (patch) | |
tree | d98403246bea6121d7a9f399afbb94056605eec5 /sys | |
parent | 21b68edc7afad6c54cd759b8827a39e0bd34c33e (diff) |
Seperate rtc(4) code out into its own file. Add support for catching the
power button interrupts on ds1287 models. The hardware will stil power off
automatically about 20 seconds after the power button is pressed, but we get
a decent chance at doing a clean shutdown before that.
"a good start" deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sparc64/conf/files.sparc64 | 9 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/rtc.c | 309 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/clock.c | 257 |
3 files changed, 316 insertions, 259 deletions
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64 index ad9919a5ade..1a0a1cd545a 100644 --- a/sys/arch/sparc64/conf/files.sparc64 +++ b/sys/arch/sparc64/conf/files.sparc64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc64,v 1.79 2007/04/04 18:48:25 kettenis Exp $ +# $OpenBSD: files.sparc64,v 1.80 2007/04/09 19:59:06 kettenis Exp $ # $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $ # maxpartitions must be first item in files.${ARCH} @@ -118,9 +118,6 @@ attach clock at mainbus, sbus with clock_sbus attach clock at ebus with clock_ebus attach clock at fhc with clock_fhc -device rtc -attach rtc at ebus with rtc_ebus - device timer attach timer at mainbus, sbus @@ -153,6 +150,10 @@ device power attach power at ebus file arch/sparc64/dev/power.c power +device rtc +attach rtc at ebus +file arch/sparc64/dev/rtc.c rtc + device sab {} attach sab at ebus device sabtty diff --git a/sys/arch/sparc64/dev/rtc.c b/sys/arch/sparc64/dev/rtc.c new file mode 100644 index 00000000000..47b85cb3085 --- /dev/null +++ b/sys/arch/sparc64/dev/rtc.c @@ -0,0 +1,309 @@ +/* $OpenBSD: rtc.c,v 1.1 2007/04/09 19:59:06 kettenis Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1996 Paul Kranenburg + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Harvard University. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * This product includes software developed by Paul Kranenburg. + * This product includes software developed by Harvard University. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Driver for rtc device on Blade 1000, Fire V210, etc. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/autoconf.h> + +#include <dev/clock_subr.h> +#include <dev/ic/mc146818reg.h> + +#include <sparc64/dev/ebusreg.h> +#include <sparc64/dev/ebusvar.h> + +extern todr_chip_handle_t todr_handle; + +struct rtc_softc { + struct device sc_dv; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct intrhand *sc_ih; +}; + +int rtc_match(struct device *, void *, void *); +void rtc_attach(struct device *, struct device *, void *); + +struct cfattach rtc_ca = { + sizeof(struct rtc_softc), rtc_match, rtc_attach +}; + +struct cfdriver rtc_cd = { + NULL, "rtc", DV_DULL +}; + +int rtc_intr(void *arg); + +u_int8_t rtc_read_reg(struct rtc_softc *, bus_size_t); +void rtc_write_reg(struct rtc_softc *sc, bus_size_t, u_int8_t); + +int rtc_gettime(todr_chip_handle_t, struct timeval *); +int rtc_settime(todr_chip_handle_t, struct timeval *); +int rtc_getcal(todr_chip_handle_t, int *); +int rtc_setcal(todr_chip_handle_t, int); + +int +rtc_match(struct device *parent, void *cf, void *aux) +{ + struct ebus_attach_args *ea = aux; + + if (strcmp("rtc", ea->ea_name) == 0) + return (1); + return (0); +} + +void +rtc_attach(struct device *parent, struct device *self, void *aux) +{ + struct rtc_softc *sc = (void *)self; + struct ebus_attach_args *ea = aux; + todr_chip_handle_t handle; + char *model; + + if (ebus_bus_map(ea->ea_iotag, 0, + EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), + ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { + sc->sc_iot = ea->ea_iotag; + } else if (ebus_bus_map(ea->ea_memtag, 0, + EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), + ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { + sc->sc_iot = ea->ea_memtag; + } else { + printf("%s: can't map register\n", self->dv_xname); + return; + } + + model = getpropstring(ea->ea_node, "model"); +#ifdef DIAGNOSTIC + if (model == NULL) + panic("rtc_attach: no model property"); +#endif + printf(": %s\n", model); + + /* Setup our todr_handle */ + handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF, M_NOWAIT); + if (handle == NULL) + panic("couldn't allocate todr_handle"); + handle->cookie = sc; + handle->todr_gettime = rtc_gettime; + handle->todr_settime = rtc_settime; + handle->todr_getcal = rtc_getcal; + handle->todr_setcal = rtc_setcal; + + handle->bus_cookie = NULL; + handle->todr_setwen = NULL; + todr_handle = handle; + + /* + * Turn interrupts off, just in case. (Although they shouldn't + * be wired to an interrupt controller on sparcs). + */ + rtc_write_reg(sc->sc_iot, sc->sc_ioh, + MC_REGB, MC_REGB_BINARY | MC_REGB_24HR); + + /* + * On ds1287 models (which really are ns87317 chips), the + * interrupt is wired to the powerbutton. + */ + if(strcmp(model, "ds1287") == 0 && ea->ea_nintrs > 0) { + sc->sc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0], + IPL_BIO, 0, rtc_intr, sc, self->dv_xname); + if (sc->sc_ih == NULL) { + printf("%s: can't establush interrupt\n", + self->dv_xname); + } + } +} + +int +rtc_intr(void *arg) +{ + extern int kbd_reset; + + if (kbd_reset == 1) { + kbd_reset = 0; + psignal(initproc, SIGUSR1); + } + return (1); +} + +/* + * Register access is indirect, through an address and data port. + */ + +#define RTC_ADDR 0 +#define RTC_DATA 1 + +u_int8_t +rtc_read_reg(struct rtc_softc *sc, bus_size_t reg) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR, reg); + return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA)); +} + +void +rtc_write_reg(struct rtc_softc *sc, bus_size_t reg, u_int8_t val) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR, reg); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA, val); +} + +/* + * RTC todr routines. + */ + +/* + * Get time-of-day and convert to a `struct timeval' + * Return 0 on success; an error number otherwise. + */ +int +rtc_gettime(todr_chip_handle_t handle, struct timeval *tv) +{ + struct rtc_softc *sc = handle->cookie; + struct clock_ymdhms dt; + int year; + u_int8_t csr; + + /* Stop updates. */ + csr = rtc_read_reg(sc, MC_REGB); + csr |= MC_REGB_SET; + rtc_write_reg(sc, MC_REGB, csr); + + /* Read time */ + dt.dt_sec = rtc_read_reg(sc, MC_SEC); + dt.dt_min = rtc_read_reg(sc, MC_MIN); + dt.dt_hour = rtc_read_reg(sc, MC_HOUR); + dt.dt_day = rtc_read_reg(sc, MC_DOM); + dt.dt_wday = rtc_read_reg(sc, MC_DOW); + dt.dt_mon = rtc_read_reg(sc, MC_MONTH); + year = rtc_read_reg(sc, MC_YEAR); + + if ((year += 1900) < POSIX_BASE_YEAR) + year += 100; + + dt.dt_year = year; + + /* time wears on */ + csr = rtc_read_reg(sc, MC_REGB); + csr &= ~MC_REGB_SET; + rtc_write_reg(sc, MC_REGB, csr); + + /* simple sanity checks */ + if (dt.dt_mon > 12 || dt.dt_day > 31 || + dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) + return (1); + + tv->tv_sec = clock_ymdhms_to_secs(&dt); + tv->tv_usec = 0; + return (0); +} + +/* + * Set the time-of-day clock based on the value of the `struct timeval' arg. + * Return 0 on success; an error number otherwise. + */ +int +rtc_settime(todr_chip_handle_t handle, struct timeval *tv) +{ + struct rtc_softc *sc = handle->cookie; + struct clock_ymdhms dt; + u_int8_t csr; + int year; + + /* Note: we ignore `tv_usec' */ + clock_secs_to_ymdhms(tv->tv_sec, &dt); + + year = dt.dt_year % 100; + + /* enable write */ + csr = rtc_read_reg(sc, MC_REGB); + csr |= MC_REGB_SET; + rtc_write_reg(sc, MC_REGB, csr); + + rtc_write_reg(sc, MC_SEC, dt.dt_sec); + rtc_write_reg(sc, MC_MIN, dt.dt_min); + rtc_write_reg(sc, MC_HOUR, dt.dt_hour); + rtc_write_reg(sc, MC_DOW, dt.dt_wday); + rtc_write_reg(sc, MC_DOM, dt.dt_day); + rtc_write_reg(sc, MC_MONTH, dt.dt_mon); + rtc_write_reg(sc, MC_YEAR, year); + + /* load them up */ + csr = rtc_read_reg(sc, MC_REGB); + csr &= ~MC_REGB_SET; + rtc_write_reg(sc, MC_REGB, csr); + return (0); +} + +int +rtc_getcal(todr_chip_handle_t handle, int *vp) +{ + return (EOPNOTSUPP); +} + +int +rtc_setcal(todr_chip_handle_t handle, int v) +{ + return (EOPNOTSUPP); +} diff --git a/sys/arch/sparc64/sparc64/clock.c b/sys/arch/sparc64/sparc64/clock.c index 86b7a2590b9..51dcff77c03 100644 --- a/sys/arch/sparc64/sparc64/clock.c +++ b/sys/arch/sparc64/sparc64/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.31 2007/04/07 19:24:58 kettenis Exp $ */ +/* $OpenBSD: clock.c,v 1.32 2007/04/09 19:59:06 kettenis Exp $ */ /* $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */ /* @@ -86,7 +86,6 @@ #include <dev/clock_subr.h> #include <dev/ic/mk48txxreg.h> -#include <dev/ic/mc146818reg.h> #include <sparc64/sparc64/intreg.h> #include <sparc64/sparc64/timerreg.h> @@ -99,11 +98,6 @@ extern u_int64_t cpu_clockrate; -struct rtc_info { - bus_space_tag_t rtc_bt; /* bus tag & handle */ - bus_space_handle_t rtc_bh; /* */ -}; - struct clock_wenable_info { bus_space_tag_t cwi_bt; bus_space_handle_t cwi_bh; @@ -149,8 +143,6 @@ static int clockmatch_ebus(struct device *, void *, void *); static void clockattach_ebus(struct device *, struct device *, void *); static int clockmatch_fhc(struct device *, void *, void *); static void clockattach_fhc(struct device *, struct device *, void *); -static int clockmatch_rtc(struct device *, void *, void *); -static void clockattach_rtc(struct device *, struct device *, void *); static void clockattach(int, bus_space_tag_t, bus_space_handle_t); struct cfattach clock_sbus_ca = { @@ -165,16 +157,8 @@ struct cfattach clock_fhc_ca = { sizeof(struct device), clockmatch_fhc, clockattach_fhc }; -struct cfattach rtc_ebus_ca = { - sizeof(struct device), clockmatch_rtc, clockattach_rtc -}; - -struct cfdriver rtc_cd = { - NULL, "rtc", DV_DULL -}; - /* Global TOD clock handle & idprom pointer */ -static todr_chip_handle_t todr_handle = NULL; +todr_chip_handle_t todr_handle = NULL; static struct idprom *idprom; static int timermatch(struct device *, void *, void *); @@ -200,15 +184,6 @@ void stopcounter(struct timer_4u *); int timerblurb = 10; /* Guess a value; used before clock is attached */ -u_int8_t rtc_read_reg(bus_space_tag_t, bus_space_handle_t, int); -void rtc_write_reg(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); -int rtc_gettime(todr_chip_handle_t, struct timeval *); -int rtc_settime(todr_chip_handle_t, struct timeval *); -int rtc_getcal(todr_chip_handle_t, int *); -int rtc_setcal(todr_chip_handle_t, int); - -int rtc_auto_century_adjust = 1; - /* * The OPENPROM calls the clock the "eeprom", so we have to have our * own special match function to call it the "clock". @@ -246,17 +221,6 @@ clockmatch_fhc(parent, cf, aux) return (strcmp("eeprom", fa->fa_name) == 0); } -static int -clockmatch_rtc(parent, cf, aux) - struct device *parent; - void *cf; - void *aux; -{ - struct ebus_attach_args *ea = aux; - - return (strcmp("rtc", ea->ea_name) == 0); -} - /* * Attach a clock (really `eeprom') to the sbus or ebus. * @@ -468,106 +432,6 @@ getidprom() } /* - * `rtc' is a ds1287 on an ebus (actually an isa bus, but we use the - * ebus driver for isa.) So we can use ebus_wenable() but need to do - * different attach work and use different todr routines. It does not - * incorporate an IDPROM. - */ - -/* - * XXX the stupid ds1287 is not mapped directly but uses an address - * and a data reg so we cannot access the stuuupid thing w/o having - * write access to the registers. - * - * XXXX We really need to mutex register access! - */ -#define RTC_ADDR 0 -#define RTC_DATA 1 -u_int8_t -rtc_read_reg(bus_space_tag_t bt, bus_space_handle_t bh, int reg) -{ - bus_space_write_1(bt, bh, RTC_ADDR, reg); - return (bus_space_read_1(bt, bh, RTC_DATA)); -} -void -rtc_write_reg(bus_space_tag_t bt, bus_space_handle_t bh, int reg, u_int8_t val) -{ - bus_space_write_1(bt, bh, RTC_ADDR, reg); - bus_space_write_1(bt, bh, RTC_DATA, val); -} - -/* ARGSUSED */ -static void -clockattach_rtc(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct ebus_attach_args *ea = aux; - bus_space_tag_t bt; - todr_chip_handle_t handle; - struct rtc_info *rtc; - char *model; - int sz; - static struct clock_wenable_info cwi; - - /* hard code to 8K? */ - sz = ea->ea_regs[0].size; - - if (ebus_bus_map(ea->ea_iotag, 0, - EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) { - bt = ea->ea_iotag; - } else if (ebus_bus_map(ea->ea_memtag, 0, - EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, - BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, - 0, &cwi.cwi_bh) == 0) { - bt = ea->ea_memtag; - } else { - printf("%s: can't map register\n", self->dv_xname); - return; - } - - model = getpropstring(ea->ea_node, "model"); -#ifdef DIAGNOSTIC - if (model == NULL) - panic("clockattach_rtc: no model property"); -#endif - printf(": %s\n", model); - - /* Setup our todr_handle */ - sz = ALIGN(sizeof(struct todr_chip_handle)) + sizeof(struct rtc_info); - handle = malloc(sz, M_DEVBUF, M_NOWAIT); - if (handle == NULL) - panic("clockattach_rtc"); - rtc = (struct rtc_info*)((u_long)handle + - ALIGN(sizeof(struct todr_chip_handle))); - handle->cookie = rtc; - handle->todr_gettime = rtc_gettime; - handle->todr_settime = rtc_settime; - handle->todr_getcal = rtc_getcal; - handle->todr_setcal = rtc_setcal; - rtc->rtc_bt = bt; - rtc->rtc_bh = cwi.cwi_bh; - - /* Save info for the clock wenable call. */ - cwi.cwi_bt = bt; - cwi.cwi_size = sz; - handle->bus_cookie = &cwi; - handle->todr_setwen = (ea->ea_memtag == bt) ? - clock_bus_wenable : NULL; - todr_handle = handle; - - /* - * Turn interrupts off, just in case. (Although they shouldn't - * be wired to an interrupt controller on sparcs). - */ - todr_wenable(handle, 1); - rtc_write_reg(bt, cwi.cwi_bh, - MC_REGB, MC_REGB_BINARY | MC_REGB_24HR); - todr_wenable(handle, 0); - -} - -/* * The sun4u OPENPROMs call the timer the "counter-timer", except for * the lame UltraSPARC IIi PCI machines that don't have them. */ @@ -1022,123 +886,6 @@ eeprom_uio(uio) return (ENODEV); } - -/* - * RTC todr routines. - */ - -/* - * Get time-of-day and convert to a `struct timeval' - * Return 0 on success; an error number otherwise. - */ -int -rtc_gettime(handle, tv) - todr_chip_handle_t handle; - struct timeval *tv; -{ - struct rtc_info *rtc = handle->cookie; - bus_space_tag_t bt = rtc->rtc_bt; - bus_space_handle_t bh = rtc->rtc_bh; - struct clock_ymdhms dt; - int year; - u_int8_t csr; - - todr_wenable(handle, 1); - - /* Stop updates. */ - csr = rtc_read_reg(bt, bh, MC_REGB); - csr |= MC_REGB_SET; - rtc_write_reg(bt, bh, MC_REGB, csr); - - /* Read time */ - dt.dt_sec = rtc_read_reg(bt, bh, MC_SEC); - dt.dt_min = rtc_read_reg(bt, bh, MC_MIN); - dt.dt_hour = rtc_read_reg(bt, bh, MC_HOUR); - dt.dt_day = rtc_read_reg(bt, bh, MC_DOM); - dt.dt_wday = rtc_read_reg(bt, bh, MC_DOW); - dt.dt_mon = rtc_read_reg(bt, bh, MC_MONTH); - year = rtc_read_reg(bt, bh, MC_YEAR); - - if ((year += 1900) < POSIX_BASE_YEAR) - year += 100; - - dt.dt_year = year; - - /* time wears on */ - csr = rtc_read_reg(bt, bh, MC_REGB); - csr &= ~MC_REGB_SET; - rtc_write_reg(bt, bh, MC_REGB, csr); - todr_wenable(handle, 0); - - /* simple sanity checks */ - if (dt.dt_mon > 12 || dt.dt_day > 31 || - dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) - return (1); - - tv->tv_sec = clock_ymdhms_to_secs(&dt); - tv->tv_usec = 0; - return (0); -} - -/* - * Set the time-of-day clock based on the value of the `struct timeval' arg. - * Return 0 on success; an error number otherwise. - */ -int -rtc_settime(handle, tv) - todr_chip_handle_t handle; - struct timeval *tv; -{ - struct rtc_info *rtc = handle->cookie; - bus_space_tag_t bt = rtc->rtc_bt; - bus_space_handle_t bh = rtc->rtc_bh; - struct clock_ymdhms dt; - u_int8_t csr; - int year; - - /* Note: we ignore `tv_usec' */ - clock_secs_to_ymdhms(tv->tv_sec, &dt); - - year = dt.dt_year % 100; - - todr_wenable(handle, 1); - /* enable write */ - csr = rtc_read_reg(bt, bh, MC_REGB); - csr |= MC_REGB_SET; - rtc_write_reg(bt, bh, MC_REGB, csr); - - rtc_write_reg(bt, bh, MC_SEC, dt.dt_sec); - rtc_write_reg(bt, bh, MC_MIN, dt.dt_min); - rtc_write_reg(bt, bh, MC_HOUR, dt.dt_hour); - rtc_write_reg(bt, bh, MC_DOW, dt.dt_wday); - rtc_write_reg(bt, bh, MC_DOM, dt.dt_day); - rtc_write_reg(bt, bh, MC_MONTH, dt.dt_mon); - rtc_write_reg(bt, bh, MC_YEAR, year); - - /* load them up */ - csr = rtc_read_reg(bt, bh, MC_REGB); - csr &= ~MC_REGB_SET; - rtc_write_reg(bt, bh, MC_REGB, csr); - todr_wenable(handle, 0); - return (0); -} - -int -rtc_getcal(handle, vp) - todr_chip_handle_t handle; - int *vp; -{ - return (EOPNOTSUPP); -} - -int -rtc_setcal(handle, v) - todr_chip_handle_t handle; - int v; -{ - return (EOPNOTSUPP); -} - u_int tick_get_timecount(struct timecounter *tc) { |