summaryrefslogtreecommitdiffstats
path: root/sys/dev/mk48txx
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2004-09-19 21:38:11 +0000
committermarius <marius@FreeBSD.org>2004-09-19 21:38:11 +0000
commit517c86564e65d04c23914a65676c6317eab6d343 (patch)
treeb980233a1abdeed19d48821a3bea758bcdf693c3 /sys/dev/mk48txx
parenta327ab2ee1e532b5b11b3d67bf08e12d42b18597 (diff)
downloadFreeBSD-src-517c86564e65d04c23914a65676c6317eab6d343.zip
FreeBSD-src-517c86564e65d04c23914a65676c6317eab6d343.tar.gz
- Some of the upper bits of the time related (seconds, minutes, etc.)
registers are control bits or depending on the model contain additional time bits with a different meaning than the lower ones. In order to only read the desired time bits and not change the upper bits on write use appropriate masks in the gettime and settime function respectively. Due to the polarity of the stop oscillator bit and the fact that the century bits aren't used on sparc64 not masking them didn't cause problems so far. - Fix two off-by-one errors in the handling of the day of week. The genclock code represents the dow as 0 - 6 with 0 being Sunday but the mk48txx use 1 - 7 with 1 being Sunday. In the settime function when writing the dow to the clock the range wasn't adjusted accordingly but the clock apparently played along nicely otherwise the second bug in the gettime function which mapped 1 - 7 to 0 - 6 but with 0 meaning Saturday would have been triggered. Fixing these makes the date being stored in the same format Sun/Solaris uses and cures the "Invalid time in real time clock. Check and reset the date immediately!" when the date was set under Solaris prior to booting FreeBSD/sparc64. [1] Looking at other clock drivers/code e.g. FreeBSD/alpha the former "bug", i.e. storing the dow as 0 - 6 even when the clock uses 1 - 7, seems to be common but might be on purpose for compatibility when multi-booting with other OS which do the same. So it might make sense to add a flag to handle the dow off-by-one for use of this driver on platforms other than sparc64. - Check the state of the battery on mk48txx that support this in the attach function. - Add a note that use of the century bit should be implemented but isn't required at the moment because it isn't used on sparc64. Problem noted by: joerg [1] MT5 candidate.
Diffstat (limited to 'sys/dev/mk48txx')
-rw-r--r--sys/dev/mk48txx/mk48txx.c67
-rw-r--r--sys/dev/mk48txx/mk48txxreg.h83
2 files changed, 131 insertions, 19 deletions
diff --git a/sys/dev/mk48txx/mk48txx.c b/sys/dev/mk48txx/mk48txx.c
index 9d28084..1cbb526 100644
--- a/sys/dev/mk48txx/mk48txx.c
+++ b/sys/dev/mk48txx/mk48txx.c
@@ -101,6 +101,13 @@ mk48txx_attach(device_t dev, bus_space_tag_t bt, bus_space_handle_t bh,
}
printf("\n");
+ if ((mk48txx_models[i].flags & MK48TXX_EXT_REGISTERS) &&
+ (bus_space_read_1(bt, bh, clkoff + MK48TXX_FLAGS) &
+ MK48TXX_FLAGS_BL)) {
+ device_printf(dev, "mk48txx_attach: battery low\n");
+ return (ENXIO);
+ }
+
sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
sc->mk_bt = bt;
sc->mk_bh = bh;
@@ -133,14 +140,33 @@ mk48txx_gettime(device_t dev, struct timespec *ts)
csr |= MK48TXX_CSR_READ;
bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
+#define FROMREG(reg, mask) \
+ (bus_space_read_1(bt, bh, clkoff + (reg)) & (mask))
+
ct.nsec = 0;
- ct.sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC));
- ct.min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN));
- ct.hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR));
- ct.day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY));
- ct.dow = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)) % 7;
- ct.mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON));
- year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR));
+ ct.sec = FROMBCD(FROMREG(MK48TXX_ISEC, MK48TXX_SEC_MASK));
+ ct.min = FROMBCD(FROMREG(MK48TXX_IMIN, MK48TXX_MIN_MASK));
+ ct.hour = FROMBCD(FROMREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK));
+ ct.day = FROMBCD(FROMREG(MK48TXX_IDAY, MK48TXX_DAY_MASK));
+ /* Map dow from 1 - 7 to 0 - 6; FROMBCD() isn't necessary here. */
+ ct.dow = FROMREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK) - 1;
+ ct.mon = FROMBCD(FROMREG(MK48TXX_IMON, MK48TXX_MON_MASK));
+ year = FROMBCD(FROMREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK));
+
+ /*
+ * XXX: At least the MK48T59 (probably all MK48Txx models with
+ * extended registers) has a century bit in the MK48TXX_IWDAY
+ * register which should be used here to make up the century
+ * when mk48txx_auto_century_adjust (which actually means
+ * manually adjust the century in the driver) is set to 0.
+ * Sun/Solaris doesn't use this bit (probably for backwards
+ * compatibility with Sun hardware equipped with older MK48Txx
+ * models) and at present this driver is only used on sparc64
+ * so not respecting the century bit doesn't really matter at
+ * the moment but generally this should be implemented.
+ */
+
+#undef FROMREG
year += mk->mk_year0;
if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0)
@@ -186,13 +212,26 @@ mk48txx_settime(device_t dev, struct timespec *ts)
csr |= MK48TXX_CSR_WRITE;
bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
- bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(ct.sec));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(ct.min));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(ct.hour));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(ct.dow));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(ct.day));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(ct.mon));
- bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year));
+#define TOREG(reg, mask, val) \
+ (bus_space_write_1(bt, bh, clkoff + (reg), \
+ (bus_space_read_1(bt, bh, clkoff + (reg)) & ~(mask)) | \
+ ((val) & (mask))))
+
+ TOREG(MK48TXX_ISEC, MK48TXX_SEC_MASK, TOBCD(ct.sec));
+ TOREG(MK48TXX_IMIN, MK48TXX_MIN_MASK, TOBCD(ct.min));
+ TOREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK, TOBCD(ct.hour));
+ /* Map dow from 0 - 6 to 1 - 7; TOBCD() isn't necessary here. */
+ TOREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK, ct.dow + 1);
+ TOREG(MK48TXX_IDAY, MK48TXX_DAY_MASK, TOBCD(ct.day));
+ TOREG(MK48TXX_IMON, MK48TXX_MON_MASK, TOBCD(ct.mon));
+ TOREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK, TOBCD(year));
+
+ /*
+ * XXX: Use the century bit for storing the century when
+ * mk48txx_auto_century_adjust is set to 0.
+ */
+
+#undef TOREG
/* load them up */
csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR);
diff --git a/sys/dev/mk48txx/mk48txxreg.h b/sys/dev/mk48txx/mk48txxreg.h
index 817f122..8bcadc2 100644
--- a/sys/dev/mk48txx/mk48txxreg.h
+++ b/sys/dev/mk48txx/mk48txxreg.h
@@ -59,22 +59,95 @@
* The first bank of eight registers at offset (nvramsz - 16) is
* available only on recenter (which?) MK48Txx models.
*/
-#define MK48TXX_X0 0 /* find out later */
- /* ... */
-#define MK48TXX_X7 7 /* find out later */
+#define MK48TXX_FLAGS 0 /* flags register */
+#define MK48TXX_UNUSED 1 /* unused */
+#define MK48TXX_ASEC 2 /* alarm seconds (0..59; BCD) */
+#define MK48TXX_AMIN 3 /* alarm minutes (0..59; BCD) */
+#define MK48TXX_AHOUR 4 /* alarm hours (0..23; BCD) */
+#define MK48TXX_ADAY 5 /* alarm day in month (1..31; BCD) */
+#define MK48TXX_INTR 6 /* interrupts register */
+#define MK48TXX_WDOG 7 /* watchdog register */
+
#define MK48TXX_ICSR 8 /* control register */
#define MK48TXX_ISEC 9 /* seconds (0..59; BCD) */
#define MK48TXX_IMIN 10 /* minutes (0..59; BCD) */
-#define MK48TXX_IHOUR 11 /* hour (0..23; BCD) */
+#define MK48TXX_IHOUR 11 /* hours (0..23; BCD) */
#define MK48TXX_IWDAY 12 /* weekday (1..7) */
#define MK48TXX_IDAY 13 /* day in month (1..31; BCD) */
#define MK48TXX_IMON 14 /* month (1..12; BCD) */
#define MK48TXX_IYEAR 15 /* year (0..99; BCD) */
+/*
+ * Note that some of the bits below that are not in the first eight
+ * registers are also only available on models with an extended
+ * register set.
+ */
+
+/* Bits in the flags register (extended only) */
+#define MK48TXX_FLAGS_BL 0x10 /* battery low (read only) */
+#define MK48TXX_FLAGS_AF 0x40 /* alarm flag (read only) */
+#define MK48TXX_FLAGS_WDF 0x80 /* watchdog flag (read only) */
+
+/* Bits in the alarm seconds register (extended only) */
+#define MK48TXX_ASEC_MASK 0x7f /* mask for alarm seconds */
+#define MK48TXX_ASEC_RPT1 0x80 /* alarm repeat mode bit 1 */
+
+/* Bits in the alarm minutes register (extended only) */
+#define MK48TXX_AMIN_MASK 0x7f /* mask for alarm minutes */
+#define MK48TXX_AMIN_RPT2 0x80 /* alarm repeat mode bit 2 */
+
+/* Bits in the alarm hours register (extended only) */
+#define MK48TXX_AHOUR_MASK 0x3f /* mask for alarm hours */
+#define MK48TXX_AHOUR_RPT3 0x80 /* alarm repeat mode bit 3 */
+
+/* Bits in the alarm day in month register (extended only) */
+#define MK48TXX_ADAY_MASK 0x3f /* mask for alarm day in month */
+#define MK48TXX_ADAY_RPT4 0x80 /* alarm repeat mode bit 4 */
+
+/* Bits in the interrupts register (extended only) */
+#define MK48TXX_INTR_ABE 0x20 /* alarm in battery back-up mode */
+#define MK48TXX_INTR_AFE 0x80 /* alarm flag enable */
+
+/* Bits in the watchdog register (extended only) */
+#define MK48TXX_WDOG_RB_1_16 0x00 /* watchdog resolution 1/16 second */
+#define MK48TXX_WDOG_RB_1_4 0x01 /* watchdog resolution 1/4 second */
+#define MK48TXX_WDOG_RB_1 0x02 /* watchdog resolution 1 second */
+#define MK48TXX_WDOG_RB_4 0x03 /* watchdog resolution 4 seconds */
+#define MK48TXX_WDOG_BMB_MASK 0x7c /* mask for watchdog multiplier */
+#define MK48TXX_WDOG_WDS 0x80 /* watchdog steering bit */
+
/* Bits in the control register */
-#define MK48TXX_CSR_WRITE 0x80 /* want to write */
+#define MK48TXX_CSR_CALIB_MASK 0x1f /* mask for calibration step width */
+#define MK48TXX_CSR_SIGN 0x20 /* sign of above calibration witdh */
#define MK48TXX_CSR_READ 0x40 /* want to read (freeze clock) */
+#define MK48TXX_CSR_WRITE 0x80 /* want to write */
+
+/* Bits in the seconds register */
+#define MK48TXX_SEC_MASK 0x7f /* mask for seconds */
+#define MK48TXX_SEC_ST 0x80 /* stop oscillator */
+
+/* Bits in the minutes register */
+#define MK48TXX_MIN_MASK 0x7f /* mask for minutes */
+
+/* Bits in the hours register */
+#define MK48TXX_HOUR_MASK 0x3f /* mask for hours */
+
+/* Bits in the century/weekday register */
+#define MK48TXX_WDAY_MASK 0x07 /* mask for weekday */
+#define MK48TXX_WDAY_CB 0x10 /* century bit (extended only) */
+#define MK48TXX_WDAY_CEB 0x20 /* century enable bit (extended only) */
+#define MK48TXX_WDAY_FT 0x30 /* frequency bit */
+
+/* Bits in the day in month register */
+#define MK48TXX_DAY_MASK 0x3f /* mask for day in month */
+
+/* Bits in the month register */
+#define MK48TXX_MON_MASK 0x1f /* mask for month */
+
+/* Bits in the year register */
+#define MK48TXX_YEAR_MASK 0xff /* mask for year */
+/* Model specific NVRAM sizes and clock offsets */
#define MK48T02_CLKSZ 2048
#define MK48T02_CLKOFF 0x7f0
OpenPOWER on IntegriCloud