diff options
-rw-r--r-- | sys/dev/fdt/sxirtc.c | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/sys/dev/fdt/sxirtc.c b/sys/dev/fdt/sxirtc.c index 06c29482762..05c8b80ec42 100644 --- a/sys/dev/fdt/sxirtc.c +++ b/sys/dev/fdt/sxirtc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxirtc.c,v 1.8 2022/10/17 19:09:46 kettenis Exp $ */ +/* $OpenBSD: sxirtc.c,v 1.9 2024/01/27 11:22:16 kettenis Exp $ */ /* * Copyright (c) 2008 Mark Kettenis * Copyright (c) 2013 Artturi Alm @@ -58,6 +58,7 @@ struct sxirtc_softc { uint32_t base_year; uint32_t year_mask; uint32_t leap_shift; + int linear_day; }; int sxirtc_match(struct device *, void *, void *); @@ -85,7 +86,9 @@ sxirtc_match(struct device *parent, void *match, void *aux) OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-rtc") || OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-rtc") || OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") || - OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc")); + OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc") || + OF_is_compatible(faa->fa_node, "allwinner,sun50i-h616-rtc") || + OF_is_compatible(faa->fa_node, "allwinner,sun50i-r329-rtc")); } void @@ -109,7 +112,9 @@ sxirtc_attach(struct device *parent, struct device *self, void *aux) if (OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-rtc") || OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") || - OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc")) { + OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc") || + OF_is_compatible(faa->fa_node, "allwinner,sun50i-h616-rtc") || + OF_is_compatible(faa->fa_node, "allwinner,sun50i-r329-rtc")) { sc->sc_yymmdd = SXIRTC_YYMMDD_A31; sc->sc_hhmmss = SXIRTC_HHMMSS_A31; } else { @@ -127,6 +132,17 @@ sxirtc_attach(struct device *parent, struct device *self, void *aux) sc->leap_shift = 22; } + /* + * Newer SoCs store the number of days since a fixed epoch + * instead of YYMMDD. Take this to be the number of days + * since the Unix epoch since that is what Linux does. + */ + if (OF_is_compatible(faa->fa_node, "allwinner,sun50i-h616-rtc") || + OF_is_compatible(faa->fa_node, "allwinner,sun50i-r329-rtc")) { + sc->base_year = 1970; + sc->linear_day = 1; + } + if (OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") || OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc")) { /* Switch to external oscillator. */ @@ -199,17 +215,21 @@ sxirtc_gettime(todr_chip_handle_t handle, struct timeval *tv) struct clock_ymdhms dt; uint32_t reg; + reg = SXIREAD4(sc, sc->sc_yymmdd); + if (sc->linear_day) { + clock_secs_to_ymdhms(reg * SECDAY, &dt); + } else { + dt.dt_day = reg & 0x1f; + dt.dt_mon = reg >> 8 & 0x0f; + dt.dt_year = (reg >> 16 & sc->year_mask) + sc->base_year; + } + reg = SXIREAD4(sc, sc->sc_hhmmss); dt.dt_sec = reg & 0x3f; dt.dt_min = reg >> 8 & 0x3f; dt.dt_hour = reg >> 16 & 0x1f; dt.dt_wday = reg >> 29 & 0x07; - reg = SXIREAD4(sc, sc->sc_yymmdd); - dt.dt_day = reg & 0x1f; - dt.dt_mon = reg >> 8 & 0x0f; - dt.dt_year = (reg >> 16 & sc->year_mask) + sc->base_year; - if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || dt.dt_wday > 6 || dt.dt_day > 31 || dt.dt_day == 0 || @@ -247,10 +267,14 @@ sxirtc_settime(todr_chip_handle_t handle, struct timeval *tv) dt.dt_sec | (dt.dt_min << 8) | (dt.dt_hour << 16) | (dt.dt_wday << 29)); - SXICMS4(sc, sc->sc_yymmdd, 0x00400000 | (sc->year_mask << 16) | - 0x0f00 | 0x1f, dt.dt_day | (dt.dt_mon << 8) | - ((dt.dt_year - sc->base_year) << 16) | - (LEAPYEAR(dt.dt_year) << sc->leap_shift)); + if (sc->linear_day) { + SXICMS4(sc, sc->sc_yymmdd, 0xffff, tv->tv_sec / SECDAY); + } else { + SXICMS4(sc, sc->sc_yymmdd, 0x00400000 | (sc->year_mask << 16) | + 0x0f00 | 0x1f, dt.dt_day | (dt.dt_mon << 8) | + ((dt.dt_year - sc->base_year) << 16) | + (LEAPYEAR(dt.dt_year) << sc->leap_shift)); + } return 0; } |