Add support for newer SoCs that store the data as number of days since the
authorkettenis <kettenis@openbsd.org>
Sat, 27 Jan 2024 11:22:16 +0000 (11:22 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 27 Jan 2024 11:22:16 +0000 (11:22 +0000)
Unix epoch instead of a calender date.

ok jca@

sys/dev/fdt/sxirtc.c

index 06c2948..05c8b80 100644 (file)
@@ -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;
 }