-/* $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
uint32_t base_year;
uint32_t year_mask;
uint32_t leap_shift;
+ int linear_day;
};
int sxirtc_match(struct device *, void *, void *);
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
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 {
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. */
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 ||
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;
}