Index: src/sys/conf/files =================================================================== RCS file: /cvsroot/src/sys/conf/files,v retrieving revision 1.1320 diff -u -r1.1320 files --- src/sys/conf/files 10 Jun 2026 00:09:43 -0000 1.1320 +++ src/sys/conf/files 16 Jun 2026 12:19:04 -0000 @@ -1125,7 +1125,7 @@ # Motorola mc146818 (and compatible) time-of-day clock # -define mc146818 +define mc146818: sysmon_envsys file dev/ic/mc146818.c mc146818 # Ricoh RS5C313 time of-day-clock Index: src/sys/dev/ic/mc146818.c =================================================================== RCS file: /cvsroot/src/sys/dev/ic/mc146818.c,v retrieving revision 1.22 diff -u -r1.22 mc146818.c --- src/sys/dev/ic/mc146818.c 7 Sep 2025 21:45:16 -0000 1.22 +++ src/sys/dev/ic/mc146818.c 16 Jun 2026 12:19:05 -0000 @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -43,10 +44,14 @@ #include #include +static int sysctl_mc146818_osc(SYSCTLFN_ARGS); + void mc146818_attach(struct mc146818_softc *sc) { todr_chip_handle_t handle; + const struct sysctlnode *me = NULL, *node = NULL; + u_int rega, regd; #ifdef DIAGNOSTIC if (sc->sc_mcread == NULL || @@ -68,6 +73,67 @@ } todr_attach(handle); + + /* Setup envsys for the valid RAM and time bit */ + sc->sc_sme = sysmon_envsys_create(); + + sc->sc_sensor.units = ENVSYS_INDICATOR; + sc->sc_sensor.state = ENVSYS_SINVALID; + sc->sc_sensor.value_cur = 0; + sc->sc_sensor.flags |= ENVSYS_FMONCRITICAL; + (void)strlcpy(sc->sc_sensor.desc, "battery low", + sizeof(sc->sc_sensor.desc)); + if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { + sysmon_envsys_destroy(sc->sc_sme); + sc->sc_sme = NULL; + aprint_error_dev(sc->sc_dev, + "unable to attach sensor to sysmon\n"); + } else { + sc->sc_sme->sme_name = device_xname(sc->sc_dev); + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_refresh = mc146818_refresh; + regd = (*sc->sc_mcread)(sc, MC_REGD); + sc->sc_vrt = regd & MC_REGD_VRT; + if (sysmon_envsys_register(sc->sc_sme)) { + sysmon_envsys_destroy(sc->sc_sme); + sc->sc_sme = NULL; + aprint_error_dev(sc->sc_dev, + "unable to register with sysmon\n"); + } + } + + sc->sc_osc_stp = 0; + if (sc->sc_flag & MC146818_OSC_CTRL) { + /* Check the oscillator state */ + rega = (*sc->sc_mcread)(sc, MC_REGA); +printf(": osc 0x%02x", rega); + if ((rega & MC_REGA_OSMASK) == MC_OSC_OFF) { + aprint_error_dev(sc->sc_dev, + "WARNING: oscillator is stopped (0x%02x)\n", rega); + sc->sc_osc_stp = 1; + } + + /* Setup sysctl for the oscillator control */ + sysctl_createv(NULL, 0, NULL, &me, + CTLFLAG_READWRITE, + CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, + NULL, 0, NULL, 0, + CTL_HW, CTL_CREATE, CTL_EOL); + if (me == NULL) + aprint_error_dev(sc->sc_dev, + "unable to add sysctl root\n"); + else { + sysctl_createv(NULL, 0, NULL, &node, + CTLFLAG_READWRITE | CTLFLAG_OWNDESC, + CTLTYPE_INT, "stop_oscillator", + "Stop the chip oscillator", + sysctl_mc146818_osc, 1, (void *)sc, 0, + CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); + if (node == NULL) + aprint_error_dev(sc->sc_dev, + "unable to add sysctl node\n"); + } + } } /* @@ -116,6 +182,7 @@ dt->dt_year = year; splx(s); +printf("%s: %04ld%02d%02d %02d%02d%02d\n", device_xname(sc->sc_dev), dt->dt_year, dt->dt_mon, dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec); return 0; } @@ -173,3 +240,74 @@ return 0; } + +/* Refresh for sysmon */ +void +mc146818_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) +{ + struct mc146818_softc *sc = sme->sme_cookie; + + /* + * The valid RAM and time bit is only set at power-up, + * so we always return the saved value. + * Note, that we make vrt 0 into low battery 1. + */ + if (sc->sc_vrt) { + edata->value_cur = 0; + edata->state = ENVSYS_SVALID; + } else { + edata->value_cur = 1; + edata->state = ENVSYS_SCRITICAL; + } +} + +/* Oscillator control routine for sysctl */ +static int +sysctl_mc146818_osc(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + struct mc146818_softc *sc = node.sysctl_data; + int stp; + u_int rega; + + if (newp) { + /* write */ + stp = sc->sc_osc_stp; + node.sysctl_data = &stp; + if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { + if (stp != 0 && stp != 1) + return EINVAL; + + if (stp != sc->sc_osc_stp) { + sc->sc_osc_stp = stp; + rega = (*sc->sc_mcread)(sc, MC_REGA); + rega &= ~MC_REGA_OSMASK; + if (stp) + rega |= MC_OSC_OFF; + else + rega |= sc->sc_osc_on; + (*sc->sc_mcwrite)(sc, MC_REGA, rega); +printf("\n%s: rega: 0x%02x\n\n", device_xname(sc->sc_dev), (*sc->sc_mcread)(sc, MC_REGA)); + } + + return 0; + } + return EINVAL; + } else { + node.sysctl_data = &sc->sc_osc_stp; + node.sysctl_size = 4; + return (sysctl_lookup(SYSCTLFN_CALL(&node))); + } + + return 0; +} + +SYSCTL_SETUP(sysctl_mc146818_setup, "sysctl mc146818 subtree setup") +{ + + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "hw", NULL, + NULL, 0, NULL, 0, + CTL_HW, CTL_EOL); +} Index: src/sys/dev/ic/mc146818reg.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/mc146818reg.h,v retrieving revision 1.9 diff -u -r1.9 mc146818reg.h --- src/sys/dev/ic/mc146818reg.h 8 Mar 2006 23:46:25 -0000 1.9 +++ src/sys/dev/ic/mc146818reg.h 16 Jun 2026 12:19:05 -0000 @@ -36,6 +36,15 @@ * The MC146818A has 16 registers. The first 10 contain time-of-year * and alarm data. The rest contain various control and status bits. * + * The Dallas DS1287A is compatible with the MC146818A but does not have + * the divider select. These bits are used to turn the oscillator on or + * off and reset the countdown chain. + * + * The NS PC87317 includes a MC146818A-compatible part as a combined + * general purpose (bank 0) real-time clock (bank 1) and + * advanced power control block (bank 2). + * The divider select bits are used to select the bank. + * * To read or write the registers, one writes the register number to * the RTC's control port, then either reads from or writes the new * data to the RTC's data port. Since the locations of these ports @@ -86,6 +95,7 @@ #define MC_REGA_RSMASK 0x0f /* Interrupt rate select mask (see below) */ #define MC_REGA_DVMASK 0x70 /* Divisor select mask (see below) */ #define MC_REGA_UIP 0x80 /* Update in progress; read only. */ +#define MC_REGA_OSMASK MC_REGA_DVMASK /* Oscillator ctrl mask ( see below) */ #define MC_REGB 0xb /* Control register B */ @@ -118,6 +128,19 @@ #define MC_NVRAM_START 0xe /* start of NVRAM: offset 14 */ #define MC_NVRAM_SIZE 50 /* 50 bytes of NVRAM */ +/* + * PC87317 Bank 2 registers, containing the address of the data. + * Bit 7 selects the bank (0x00 bank 0, 0x80 bank 1). + * Bits 6-0 contain the address in the bank. + * Note, only RTC-related registers are defined here. + */ +#define PC_BANK2_DADDR 0x4f /* Day-of-Month Alarm Address */ +#define PC_BANK2_MADDR 0x50 /* Month Alarm Address */ +#define PC_BANK2_CADDR 0x51 /* Century Address */ +#define PC_CADDR_DEF 0xc8 /* Default CADDR (Century Address) */ +#define PC_CADDR_BANK1 0x80 /* CADDR is bank 1 (bank 0 if not set) */ +#define PC_CADDR_ADMSK 0x7f /* CADDR address mask */ + /* * Periodic Interrupt Rate Select constants (Control register A) */ @@ -139,13 +162,22 @@ #define MC_RATE_2_Hz 0xf /* 500 ms period */ /* - * Time base (divisor select) constants (Control register A) + * MC146818 Time base (divisor select) constants + * DS1287 oscillator constants + * ACPI-compatible bank switching constants + * (Control register A) + * */ #define MC_BASE_4_MHz 0x00 /* 4 MHz crystal */ #define MC_BASE_1_MHz 0x10 /* 1 MHz crystal */ #define MC_BASE_32_KHz 0x20 /* 32 kHz crystal */ #define MC_BASE_NONE 0x60 /* actually, both of these reset */ #define MC_BASE_RESET 0x70 +#define MC_OSC_OFF 0x00 /* Oscillator off (DS1287)*/ +#define MC_OSC_ON 0x20 /* Oscillator on (DS1287)*/ +#define MC_BANK_SEL0 0x20 /* Bank select 0 and osc. on (ACPI) */ +#define MC_BANK_SEL1 0x30 /* Bank select 1 and osc. on (ACPI) */ +#define MC_BANK_SEL2 0x40 /* Bank select 2 and osc. on (ACPI) */ #ifndef USE_TODR_MCCLOCK /* Index: src/sys/dev/ic/mc146818var.h =================================================================== RCS file: /cvsroot/src/sys/dev/ic/mc146818var.h,v retrieving revision 1.8 diff -u -r1.8 mc146818var.h --- src/sys/dev/ic/mc146818var.h 6 Mar 2024 02:31:44 -0000 1.8 +++ src/sys/dev/ic/mc146818var.h 16 Jun 2026 12:19:05 -0000 @@ -27,6 +27,9 @@ #ifndef _DEV_IC_MC146818VAR_H_ #define _DEV_IC_MC146818VAR_H_ +#include + + struct mc146818_softc { device_t sc_dev; @@ -39,6 +42,14 @@ #define MC146818_NO_CENT_ADJUST 0x0001 /* don't adjust century */ #define MC146818_BCD 0x0002 /* use BCD mode */ #define MC146818_12HR 0x0004 /* use AM/PM mode */ +#define MC146818_OSC_CTRL 0x0008 /* Oscillator ctcl (DS1287) */ + u_int sc_osc_on; /* Oscillator on value */ + + struct sysmon_envsys *sc_sme; /* envsys config. */ + envsys_data_t sc_sensor; + int sc_vrt; /* Valid RAM and time bit */ + + int sc_osc_stp; /* Oscillator stop (sysctl) */ /* MD chip register read/write functions */ u_int (*sc_mcread)(struct mc146818_softc *, u_int); @@ -51,5 +62,6 @@ void mc146818_attach(struct mc146818_softc *); int mc146818_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); int mc146818_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *); +void mc146818_refresh(struct sysmon_envsys *, envsys_data_t *); #endif /* _DEV_IC_MC146818VAR_H_ */ Index: src/share/man/man4/mcclock.4 =================================================================== RCS file: /cvsroot/src/share/man/man4/mcclock.4,v retrieving revision 1.6 diff -u -r1.6 mcclock.4 --- src/share/man/man4/mcclock.4 30 Apr 2008 13:10:54 -0000 1.6 +++ src/share/man/man4/mcclock.4 16 Jun 2026 12:19:05 -0000 @@ -32,7 +32,7 @@ .Os .Sh NAME .Nm mcclock -.Nd DS1287 real-time clock +.Nd MC146816, DS1287, and compatibles real-time clock .Sh SYNOPSIS .Ss algor .Cd "mcclock* at isa? port 0x70" @@ -50,12 +50,59 @@ .Cd "mcclock* at ioasic? offset ?" .Ss sgimips .Cd "mcclock* at mace0 offset 0x3a0000" +.Ss sparc64 +.Cd "rtc0 at ebus0 addr 300070-300071 ipl 24: mc146818 compatible time-of-day clock: ds1287" +.Cd "rtc0 at ebus0 addr 70-71: mc146818 compatible time-of-day clock: m5819p" .Sh DESCRIPTION The .Nm -driver provides support for the DS1287 real-time clock (RTC). Note -that the kernel expects the RTC to run in UTC. +driver provides support for the MC146818, DS1287 and compatibles +real-time clock (RTC). +Note, that the kernel expects the RTC to run in UTC. +Access methods to retrieve and set date and time +are provided through the +.Em TODR +interface defined in +.Xr todr 9 . +.Pp +The chip checks the battery on power-up, and alters an internal +.EM RAM and Time bit +if the external battery source is exhausted. +The status of this bit is reported through the +.Xr envstat 8 +interface. +.Bl -column ".Li battery low" "TRUE/FALSE" -offset indent +.It Sy Sensor Ta Sy Units Ta Sy Description +.It Li battery low Ta TRUE/FALSE Ta Battery low alert +.El +.Pp +DS1287 and compatible chips also support stopping the oscillator to +conserve battery life if the computer will be stored for an extended +period. +The +.Nm +driver +makes the oscillator control available via +.Xr sysctl 8 . +For example: +.Bd -literal -offset indent +hw.mcclock0.stop_oscillator = 0 +hw.rtc0.stop_oscillator = 0 +.Ed +.Pp +A value of +.Dq 0 +means that the oscillator is running when the computer is powered off, +and a value of +.Dq 1 +means that the oscillator is stopped. +If the oscillator is stopped, then the driver will output a warning message +at attach time, but does not automatically restart the oscillator. .Sh SEE ALSO .Xr intro 4 , +.Xr ebus 4 , .Xr ioasic 4 , .Xr isa 4 +.Xr envstat 8 , +.Xr sysctl 8, +.Xr todr 9 Index: src/share/man/man4/ebus.4 =================================================================== RCS file: /cvsroot/src/share/man/man4/ebus.4,v retrieving revision 1.7 diff -u -r1.7 ebus.4 --- src/share/man/man4/ebus.4 17 Mar 2012 11:15:42 -0000 1.7 +++ src/share/man/man4/ebus.4 16 Jun 2026 12:19:05 -0000 @@ -38,19 +38,30 @@ bus is designed to provide the ability to put ISA and traditional Intel-style peripherals in a SPARC based system with a minimal amount of glue logic. -Typically, it is implemented in the PCIO IC from SME, which also -implements a +.Pp +In older machines, it is typically implemented in the PCIO IC from SME, +which also implements a .Xr hme 4 compatible PCI network device -.Pf ( Ql network ) . -The -.Nm -has four DMA channels, similar to the DMA seen in the +.Pf ( Ql network ) +and four DMA channels, similar to the DMA seen in the .Xr esp 4 .\" XXX: prevent SC-SI .hw SCSI SCSI DMA. +.Pp +In newer machines, it is typically implemented using a ALi Super I/O or +Southbridge chip, which may also provide +.Xr com 4 +serial ports and a +.Xr mcclock 4 +real-time clock. .Sh SEE ALSO +.Xr intro 4 , +.Xr com 4 +.Xr esp 4 +.Xr hme 4 +.Xr mcclock 4 .Rs .%A Sun Microelectronics .%B Peripheral Component Interconnect Input Output Controller