summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/dev
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-05-15 23:02:26 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-05-15 23:02:26 +0000
commitf465ca8986581eacce2f0ab962c6590956537ed0 (patch)
treeee65d955360a912331a303220f8ac2ce8d5a8f4b /sys/arch/sgi/dev
parentc38525da63f69afbdf3eb2d6740e009d7c8a68bc (diff)
TOD clock support for IOC3 flavours with DS174x chips (which are rebadged
MK48Txx). Entangled with preliminary changes which will hopefully eventually lead to power(4) attaching on IP30 (but not finished yet).
Diffstat (limited to 'sys/arch/sgi/dev')
-rw-r--r--sys/arch/sgi/dev/dsrtc.c245
-rw-r--r--sys/arch/sgi/dev/power.c77
2 files changed, 221 insertions, 101 deletions
diff --git a/sys/arch/sgi/dev/dsrtc.c b/sys/arch/sgi/dev/dsrtc.c
index 7bb27e719df..ace92d15148 100644
--- a/sys/arch/sgi/dev/dsrtc.c
+++ b/sys/arch/sgi/dev/dsrtc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsrtc.c,v 1.4 2009/05/08 18:35:13 miod Exp $ */
+/* $OpenBSD: dsrtc.c,v 1.5 2009/05/15 23:02:23 miod Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -31,32 +31,33 @@
#include <sys/systm.h>
#include <sys/device.h>
-#include <dev/ic/ds1687reg.h>
-
#include <machine/autoconf.h>
#include <machine/bus.h>
+#include <dev/ic/ds1687reg.h>
+#define todr_chip_handle_t void * /* XXX that's just to eat prototypes */
+#include <dev/ic/mk48txxreg.h>
+
#include <mips64/archtype.h>
#include <mips64/dev/clockvar.h>
+#include <sgi/dev/dsrtcvar.h>
#include <sgi/localbus/macebus.h>
#include <sgi/pci/iocreg.h>
#include <sgi/pci/iocvar.h>
-bus_space_handle_t clock_h; /* XXX */
-
struct dsrtc_softc {
struct device sc_dev;
bus_space_tag_t sc_clkt;
bus_space_handle_t sc_clkh, sc_clkh2;
+ int sc_yrbase;
int (*read)(struct dsrtc_softc *, int);
void (*write)(struct dsrtc_softc *, int, int);
};
-int dsrtc_match_ioc(struct device *, void *, void *);
+int dsrtc_match(struct device *, void *, void *);
void dsrtc_attach_ioc(struct device *, struct device *, void *);
-int dsrtc_match_macebus(struct device *, void *, void *);
void dsrtc_attach_macebus(struct device *, struct device *, void *);
struct cfdriver dsrtc_cd = {
@@ -64,20 +65,22 @@ struct cfdriver dsrtc_cd = {
};
struct cfattach dsrtc_macebus_ca = {
- sizeof(struct dsrtc_softc), dsrtc_match_macebus, dsrtc_attach_macebus
+ sizeof(struct dsrtc_softc), dsrtc_match, dsrtc_attach_macebus
};
struct cfattach dsrtc_ioc_ca = {
- sizeof(struct dsrtc_softc), dsrtc_match_ioc, dsrtc_attach_ioc
+ sizeof(struct dsrtc_softc), dsrtc_match, dsrtc_attach_ioc
};
int ip32_dsrtc_read(struct dsrtc_softc *, int);
void ip32_dsrtc_write(struct dsrtc_softc *, int, int);
-int ip30_dsrtc_read(struct dsrtc_softc *, int);
-void ip30_dsrtc_write(struct dsrtc_softc *, int, int);
+int ioc_ds1687_dsrtc_read(struct dsrtc_softc *, int);
+void ioc_ds1687_dsrtc_write(struct dsrtc_softc *, int, int);
void ds1687_get(void *, time_t, struct tod_time *);
void ds1687_set(void *, struct tod_time *);
+void ds1742_get(void *, time_t, struct tod_time *);
+void ds1742_set(void *, struct tod_time *);
static inline int frombcd(int, int);
static inline int tobcd(int, int);
@@ -93,24 +96,36 @@ tobcd(int x, int binary)
}
int
-dsrtc_match_ioc(struct device *parent, void *match, void *aux)
+dsrtc_match(struct device *parent, void *match, void *aux)
+{
+ return 1;
+}
+
+void
+dsrtc_attach_ioc(struct device *parent, struct device *self, void *aux)
{
+ struct dsrtc_softc *sc = (void *)self;
struct ioc_attach_args *iaa = aux;
bus_space_handle_t ih, ih2;
uint c, c2, c3;
- int rc = 0;
+ int ds1687 = 0;
/*
* The IOC3 RTC is either a Dallas (now Maxim) DS1386 or compatible
- * (likely a more recent DS1687), or a Mostek (now SGS Thomson)
- * MK48T35.
+ * (likely a more recent DS1687), or a DS1747 or compatible
+ * (itself being a Mostek MK48T35 clone).
+ *
+ * Surprisingly, the chip found on Fuel has a DS1742W label,
+ * which has much less memory than the DS1747. I guess whatever
+ * the chip is, it is mapped to the end of the DS1747 address
+ * space, so that the clock registers always appear at the same
+ * addresses in memory.
*/
if (bus_space_map(iaa->iaa_memt, IOC3_BYTEBUS_1, 1, 0, &ih) != 0)
- return 0;
-
+ goto fail0;
if (bus_space_map(iaa->iaa_memt, IOC3_BYTEBUS_2, 1, 0, &ih2) != 0)
- goto unmap;
+ goto fail1;
/*
* Check the low 4 bits of control register C. If any is set,
@@ -134,7 +149,7 @@ dsrtc_match_ioc(struct device *parent, void *match, void *aux)
bus_space_write_1(iaa->iaa_memt, ih, 0, DS1687_CTRL_C);
c2 = bus_space_read_1(iaa->iaa_memt, ih2, 0);
if ((c2 & 0x0f) == 0)
- rc = 1;
+ ds1687 = 1; /* maybe... */
bus_space_write_1(iaa->iaa_memt, ih, 0, DS1687_CTRL_C);
bus_space_write_1(iaa->iaa_memt, ih2, 0, c2 | 0x0f);
@@ -142,47 +157,62 @@ dsrtc_match_ioc(struct device *parent, void *match, void *aux)
bus_space_write_1(iaa->iaa_memt, ih, 0, DS1687_CTRL_C);
c3 = bus_space_read_1(iaa->iaa_memt, ih2, 0);
if ((c3 & 0x0f) != 0)
- rc = 0;
+ ds1687 = 0; /* ...well, no. */
- /* write back first value read in case this is not a Dallas chip */
- bus_space_write_1(iaa->iaa_memt, ih, 0, DS1687_CTRL_C);
- bus_space_write_1(iaa->iaa_memt, ih2, 0, c);
+ /* write back first value read in case this is not a DS1687 */
+ if (ds1687 == 0) {
+ bus_space_write_1(iaa->iaa_memt, ih, 0, DS1687_CTRL_C);
+ bus_space_write_1(iaa->iaa_memt, ih2, 0, c);
+ }
done:
- bus_space_unmap(iaa->iaa_memt, ih2, 1);
-unmap:
- bus_space_unmap(iaa->iaa_memt, ih, 1);
+ sc->sc_clkt = iaa->iaa_memt;
- return rc;
-}
+ if (ds1687) {
+ printf(": DS1687\n");
-void
-dsrtc_attach_ioc(struct device *parent, struct device *self, void *aux)
-{
- struct dsrtc_softc *sc = (void *)self;
- struct ioc_attach_args *iaa = aux;
+ sc->sc_clkh = ih;
+ sc->sc_clkh2 = ih2;
- sc->sc_clkt = iaa->iaa_memt;
- if (bus_space_map(sc->sc_clkt, IOC3_BYTEBUS_1, 1, 0, &sc->sc_clkh) ||
- bus_space_map(sc->sc_clkt, IOC3_BYTEBUS_2, 1, 0, &sc->sc_clkh2)) {
- printf(": can't map registers\n");
- return;
- }
+ sc->read = ioc_ds1687_dsrtc_read;
+ sc->write = ioc_ds1687_dsrtc_write;
- printf(": DS1687\n");
+ sys_tod.tod_cookie = self;
+ sys_tod.tod_get = ds1687_get;
+ sys_tod.tod_set = ds1687_set;
+ } else {
+ bus_space_unmap(iaa->iaa_memt, ih, 1);
+ bus_space_unmap(iaa->iaa_memt, ih2, 1);
- sc->read = ip30_dsrtc_read;
- sc->write = ip30_dsrtc_write;
+ if (bus_space_map(iaa->iaa_memt,
+ IOC3_BYTEBUS_0 + MK48T35_CLKOFF,
+ MK48T35_CLKSZ - MK48T35_CLKOFF, 0, &ih) != 0)
+ goto fail0;
- sys_tod.tod_cookie = self;
- sys_tod.tod_get = ds1687_get;
- sys_tod.tod_set = ds1687_set;
-}
+ printf(": DS1742W\n");
-int
-dsrtc_match_macebus(struct device *parent, void *match, void *aux)
-{
- return 1;
+ sc->sc_clkh = ih;
+
+ /*
+ * For some reason, the base year differs between IP27
+ * and IP35.
+ */
+ sc->sc_yrbase = sys_config.system_type == SGI_O300 ?
+ POSIX_BASE_YEAR - 2 : POSIX_BASE_YEAR;
+ /* mips64 clock code expects year relative to 1900 */
+ sc->sc_yrbase -= 1900;
+
+ sys_tod.tod_cookie = self;
+ sys_tod.tod_get = ds1742_get;
+ sys_tod.tod_set = ds1742_set;
+ }
+
+ return;
+
+fail1:
+ bus_space_unmap(iaa->iaa_memt, ih, 1);
+fail0:
+ printf(": can't map registers\n");
}
void
@@ -192,7 +222,7 @@ dsrtc_attach_macebus(struct device *parent, struct device *self, void *aux)
struct confargs *ca = aux;
sc->sc_clkt = ca->ca_iot;
- if (bus_space_map(sc->sc_clkt, MACE_ISA_RTC_OFFS, 128*256, 0,
+ if (bus_space_map(sc->sc_clkt, MACE_ISA_RTC_OFFS, 128 * 256, 0,
&sc->sc_clkh)) {
printf(": can't map registers\n");
return;
@@ -206,13 +236,6 @@ dsrtc_attach_macebus(struct device *parent, struct device *self, void *aux)
sys_tod.tod_cookie = self;
sys_tod.tod_get = ds1687_get;
sys_tod.tod_set = ds1687_set;
-
- /*
- * XXX Expose the clock address space so that it can be used
- * outside of clock(4). This is rather inelegant, however it
- * will have to do for now...
- */
- clock_h = sc->sc_clkh;
}
int
@@ -228,22 +251,23 @@ ip32_dsrtc_write(struct dsrtc_softc *sc, int reg, int val)
}
int
-ip30_dsrtc_read(struct dsrtc_softc *sc, int reg)
+ioc_ds1687_dsrtc_read(struct dsrtc_softc *sc, int reg)
{
bus_space_write_1(sc->sc_clkt, sc->sc_clkh, 0, reg);
return bus_space_read_1(sc->sc_clkt, sc->sc_clkh2, 0);
}
void
-ip30_dsrtc_write(struct dsrtc_softc *sc, int reg, int val)
+ioc_ds1687_dsrtc_write(struct dsrtc_softc *sc, int reg, int val)
{
bus_space_write_1(sc->sc_clkt, sc->sc_clkh, 0, reg);
bus_space_write_1(sc->sc_clkt, sc->sc_clkh2, 0, val);
}
/*
- * Dallas clock driver.
+ * Dallas DS1687 clock driver.
*/
+
void
ds1687_get(void *v, time_t base, struct tod_time *ct)
{
@@ -308,3 +332,102 @@ ds1687_set(void *v, struct tod_time *ct)
/* Enable updates. */
(*sc->write)(sc, DS1687_CTRL_B, ctrl);
}
+
+/*
+ * Dallas DS1742 clock driver.
+ */
+
+void
+ds1742_get(void *v, time_t base, struct tod_time *ct)
+{
+ struct dsrtc_softc *sc = v;
+ int csr;
+
+ /* Freeze update. */
+ csr = bus_space_read_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR);
+ csr |= MK48TXX_CSR_READ;
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR, csr);
+
+ /* Read the RTC. */
+ ct->sec = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_ISEC), 0);
+ ct->min = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_IMIN), 0);
+ ct->hour = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_IHOUR), 0);
+ ct->day = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_IDAY), 0);
+ ct->mon = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_IMON), 0);
+ ct->year = frombcd(bus_space_read_1(sc->sc_clkt, sc->sc_clkh,
+ MK48TXX_IYEAR), 0) + sc->sc_yrbase;
+
+ /* Enable updates again. */
+ csr = bus_space_read_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR);
+ csr &= ~MK48TXX_CSR_READ;
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR, csr);
+}
+
+void
+ds1742_set(void *v, struct tod_time *ct)
+{
+ struct dsrtc_softc *sc = v;
+ int csr;
+
+ /* Enable write. */
+ csr = bus_space_read_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR);
+ csr |= MK48TXX_CSR_WRITE;
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR, csr);
+
+ /* Update the RTC. */
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ISEC,
+ tobcd(ct->sec, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IMIN,
+ tobcd(ct->min, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IHOUR,
+ tobcd(ct->hour, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IWDAY,
+ tobcd(ct->dow, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IDAY,
+ tobcd(ct->day, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IMON,
+ tobcd(ct->mon, 0));
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_IYEAR,
+ tobcd(ct->year - sc->sc_yrbase, 0));
+
+ /* Load new values. */
+ csr = bus_space_read_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR);
+ csr &= ~MK48TXX_CSR_WRITE;
+ bus_space_write_1(sc->sc_clkt, sc->sc_clkh, MK48TXX_ICSR, csr);
+}
+
+/*
+ * Routines allowing external access to the RTC registers, used by
+ * power(4).
+ */
+
+int
+dsrtc_register_read(int reg)
+{
+ struct dsrtc_softc *sc;
+
+ if (dsrtc_cd.cd_ndevs == 0 ||
+ (sc = (struct dsrtc_softc *)dsrtc_cd.cd_devs[0]) == NULL ||
+ sc->read == NULL)
+ return -1;
+
+ return (*sc->read)(sc, reg);
+}
+
+void
+dsrtc_register_write(int reg, int val)
+{
+ struct dsrtc_softc *sc;
+
+ if (dsrtc_cd.cd_ndevs == 0 ||
+ (sc = (struct dsrtc_softc *)dsrtc_cd.cd_devs[0]) == NULL ||
+ sc->write == NULL)
+ return;
+
+ (*sc->write)(sc, reg, val);
+}
diff --git a/sys/arch/sgi/dev/power.c b/sys/arch/sgi/dev/power.c
index 35f5c8f3146..1afd06ef776 100644
--- a/sys/arch/sgi/dev/power.c
+++ b/sys/arch/sgi/dev/power.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: power.c,v 1.7 2008/09/16 16:38:25 jasper Exp $ */
+/* $OpenBSD: power.c,v 1.8 2009/05/15 23:02:23 miod Exp $ */
/*
* Copyright (c) 2007 Jasper Lievisse Adriaanse <jasper@openbsd.org>
@@ -36,18 +36,12 @@ struct power_softc {
struct device sc_dev;
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
- bus_space_handle_t sc_isash;
};
-int power_match(struct device *, void *, void *);
void power_attach(struct device *, struct device *, void *);
-int power_intr(void *aux);
-
-struct cfattach power_ca = {
- sizeof(struct power_softc),
- power_match,
- power_attach
-};
+int power_match(struct device *, void *, void *);
+int power_intr(void *);
+int power_intr_macebus(void *);
struct cfdriver power_cd = {
NULL, "power", DV_DULL
@@ -59,63 +53,66 @@ power_match(struct device *parent, void *match, void *aux)
return (1);
}
+struct cfattach power_ca = {
+ sizeof(struct power_softc), power_match, power_attach
+};
+
void
power_attach(struct device *parent, struct device *self, void *aux)
{
struct power_softc *sc = (void *)self;
struct confargs *ca = aux;
- extern bus_space_handle_t clock_h;
extern bus_space_handle_t mace_h;
sc->sc_st = ca->ca_iot;
- /* Map subregion to clock address space. */
- if (bus_space_subregion(sc->sc_st, clock_h, 0, 0x50, &sc->sc_sh)) {
- printf(": failed to map clock address space!\n");
- return;
- }
-
/* Map subregion to ISA control registers. */
- if (bus_space_subregion(sc->sc_st, mace_h, 0, 0x80, &sc->sc_isash)) {
+ if (bus_space_subregion(sc->sc_st, mace_h, 0, 0x80, &sc->sc_sh)) {
printf(": failed to map ISA control registers!\n");
return;
}
/* Establish interrupt handler. */
if (macebus_intr_establish(NULL, ca->ca_intr, IST_EDGE, IPL_TTY,
- power_intr, sc, sc->sc_dev.dv_xname))
+ power_intr_macebus, sc, sc->sc_dev.dv_xname))
printf("\n");
else
printf(": unable to establish interrupt!\n");
}
int
-power_intr(void *arg)
+power_intr_macebus(void *arg)
{
struct power_softc *sc = (void *)arg;
u_int64_t val;
- extern int kbd_reset;
/* Check to see if this interrupt is for us. */
- val = bus_space_read_8(sc->sc_st, sc->sc_isash, MACE_ISA_INT_STAT);
- if (val & MACE_ISA_INT_RTC) {
-
- /*
- * Prevent further interrupts by clearing the kickstart flag
- * in the DS1687's extended control register.
- */
- val = bus_space_read_1(sc->sc_st, sc->sc_sh, DS1687_EXT_CTRL);
- bus_space_write_1(sc->sc_st, sc->sc_sh, DS1687_EXT_CTRL,
- val & ~DS1687_KICKSTART);
-
- if (kbd_reset == 1) {
- kbd_reset = 0;
- psignal(initproc, SIGUSR2);
- }
-
- return (1);
- }
+ val = bus_space_read_8(sc->sc_st, sc->sc_sh, MACE_ISA_INT_STAT);
+ if (val & MACE_ISA_INT_RTC)
+ return power_intr(arg);
- return (0);
+ return 0;
}
+int
+power_intr(void *unused)
+{
+ extern int kbd_reset;
+ int val;
+
+ /*
+ * Prevent further interrupts by clearing the kickstart flag
+ * in the DS1687's extended control register.
+ */
+ val = dsrtc_register_read(DS1687_EXT_CTRL);
+ if (val == -1)
+ return 1; /* no rtc attached */
+ dsrtc_register_write(DS1687_EXT_CTRL, val & ~DS1687_KICKSTART);
+
+ if (kbd_reset == 1) {
+ kbd_reset = 0;
+ psignal(initproc, SIGUSR2);
+ }
+
+ return 1;
+}