Module Name: src Committed By: jmcneill Date: Sun Oct 8 14:03:46 UTC 2017
Modified Files: src/sys/arch/arm/sunxi: sunxi_rtc.c Log Message: Add sun4i-a10 RTC support. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/sunxi/sunxi_rtc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sunxi_rtc.c diff -u src/sys/arch/arm/sunxi/sunxi_rtc.c:1.2 src/sys/arch/arm/sunxi/sunxi_rtc.c:1.3 --- src/sys/arch/arm/sunxi/sunxi_rtc.c:1.2 Sat Oct 7 17:03:49 2017 +++ src/sys/arch/arm/sunxi/sunxi_rtc.c Sun Oct 8 14:03:46 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_rtc.c,v 1.2 2017/10/07 17:03:49 jmcneill Exp $ */ +/* $NetBSD: sunxi_rtc.c,v 1.3 2017/10/08 14:03:46 jmcneill Exp $ */ /*- * Copyright (c) 2014-2017 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c,v 1.2 2017/10/07 17:03:49 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c,v 1.3 2017/10/08 14:03:46 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -40,6 +40,18 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c, #include <dev/fdt/fdtvar.h> +#define SUN4I_RTC_YY_MM_DD_REG 0x04 +#define SUN4I_RTC_LEAP __BIT(22) +#define SUN4I_RTC_YEAR __BITS(21,16) +#define SUN4I_RTC_MONTH __BITS(11,8) +#define SUN4I_RTC_DAY __BITS(4,0) +#define SUN4I_RTC_HH_MM_SS_REG 0x08 +#define SUN4I_RTC_WK_NO __BITS(31,29) +#define SUN4I_RTC_HOUR __BITS(20,16) +#define SUN4I_RTC_MINUTE __BITS(13,8) +#define SUN4I_RTC_SECOND __BITS(5,0) +#define SUN4I_RTC_BASE_YEAR 2010 + #define SUN7I_RTC_YY_MM_DD_REG 0x04 #define SUN7I_RTC_LEAP __BIT(24) #define SUN7I_RTC_YEAR __BITS(23,16) @@ -50,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c, #define SUN7I_RTC_HOUR __BITS(20,16) #define SUN7I_RTC_MINUTE __BITS(13,8) #define SUN7I_RTC_SECOND __BITS(5,0) +#define SUN7I_RTC_BASE_YEAR 1970 #define SUN6I_RTC_YY_MM_DD_REG 0x10 #define SUN6I_RTC_LEAP __BIT(22) @@ -61,17 +74,62 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c, #define SUN6I_RTC_HOUR __BITS(20,16) #define SUN6I_RTC_MINUTE __BITS(13,8) #define SUN6I_RTC_SECOND __BITS(5,0) +#define SUN6I_RTC_BASE_YEAR 2000 + +struct sunxi_rtc_config { + bus_size_t yy_mm_dd_reg; + uint32_t leap, year, month, day; + bus_size_t hh_mm_ss_reg; + uint32_t wk_no, hour, minute, second; + u_int base_year; +}; -#define SUNXI_RTC_BASE_YEAR 2000 +static const struct sunxi_rtc_config sun4i_rtc_config = { + .yy_mm_dd_reg = SUN4I_RTC_YY_MM_DD_REG, + .leap = SUN4I_RTC_LEAP, + .year = SUN4I_RTC_YEAR, + .month = SUN4I_RTC_MONTH, + .day = SUN4I_RTC_DAY, + .hh_mm_ss_reg = SUN4I_RTC_HH_MM_SS_REG, + .wk_no = SUN4I_RTC_WK_NO, + .hour = SUN4I_RTC_HOUR, + .minute = SUN4I_RTC_MINUTE, + .second = SUN4I_RTC_SECOND, + .base_year = SUN4I_RTC_BASE_YEAR, +}; + +static const struct sunxi_rtc_config sun6i_rtc_config = { + .yy_mm_dd_reg = SUN6I_RTC_YY_MM_DD_REG, + .leap = SUN6I_RTC_LEAP, + .year = SUN6I_RTC_YEAR, + .month = SUN6I_RTC_MONTH, + .day = SUN6I_RTC_DAY, + .hh_mm_ss_reg = SUN6I_RTC_HH_MM_SS_REG, + .wk_no = SUN6I_RTC_WK_NO, + .hour = SUN6I_RTC_HOUR, + .minute = SUN6I_RTC_MINUTE, + .second = SUN6I_RTC_SECOND, + .base_year = SUN6I_RTC_BASE_YEAR, +}; -enum sunxi_rtc_type { - RTC_SUN6I = 1, - RTC_SUN7I, +static const struct sunxi_rtc_config sun7i_rtc_config = { + .yy_mm_dd_reg = SUN7I_RTC_YY_MM_DD_REG, + .leap = SUN7I_RTC_LEAP, + .year = SUN7I_RTC_YEAR, + .month = SUN7I_RTC_MONTH, + .day = SUN7I_RTC_DAY, + .hh_mm_ss_reg = SUN7I_RTC_HH_MM_SS_REG, + .wk_no = SUN7I_RTC_WK_NO, + .hour = SUN7I_RTC_HOUR, + .minute = SUN7I_RTC_MINUTE, + .second = SUN7I_RTC_SECOND, + .base_year = SUN7I_RTC_BASE_YEAR, }; static const struct of_compat_data compat_data[] = { - { "allwinner,sun6i-a31-rtc", RTC_SUN6I }, - { "allwinner,sun7i-a20-rtc", RTC_SUN7I }, + { "allwinner,sun4i-a10-rtc", (uintptr_t)&sun4i_rtc_config }, + { "allwinner,sun6i-a31-rtc", (uintptr_t)&sun6i_rtc_config }, + { "allwinner,sun7i-a20-rtc", (uintptr_t)&sun7i_rtc_config }, { NULL } }; @@ -80,6 +138,7 @@ struct sunxi_rtc_softc { bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; struct todr_chip_handle sc_todr; + const struct sunxi_rtc_config *sc_conf; }; #define RTC_READ(sc, reg) \ @@ -90,11 +149,8 @@ struct sunxi_rtc_softc { static int sunxi_rtc_match(device_t, cfdata_t, void *); static void sunxi_rtc_attach(device_t, device_t, void *); -static int sun6i_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *); -static int sun6i_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *); - -static int sun7i_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *); -static int sun7i_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *); +static int sunxi_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *); +static int sunxi_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *); CFATTACH_DECL_NEW(sunxi_rtc, sizeof(struct sunxi_rtc_softc), sunxi_rtc_match, sunxi_rtc_attach, NULL, NULL); @@ -113,7 +169,6 @@ sunxi_rtc_attach(device_t parent, device struct sunxi_rtc_softc * const sc = device_private(self); struct fdt_attach_args * const faa = aux; const int phandle = faa->faa_phandle; - enum sunxi_rtc_type type; bus_addr_t addr; bus_size_t size; @@ -128,133 +183,71 @@ sunxi_rtc_attach(device_t parent, device aprint_error(": couldn't map registers\n"); return; } + sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data; aprint_naive("\n"); aprint_normal(": RTC\n"); - type = of_search_compatible(phandle, compat_data)->data; - sc->sc_todr.cookie = sc; - switch (type) { - case RTC_SUN6I: - sc->sc_todr.todr_gettime_ymdhms = sun6i_rtc_gettime; - sc->sc_todr.todr_settime_ymdhms = sun6i_rtc_settime; - break; - case RTC_SUN7I: - sc->sc_todr.todr_gettime_ymdhms = sun7i_rtc_gettime; - sc->sc_todr.todr_settime_ymdhms = sun7i_rtc_settime; - break; - } + sc->sc_todr.todr_gettime_ymdhms = sunxi_rtc_gettime; + sc->sc_todr.todr_settime_ymdhms = sunxi_rtc_settime; fdtbus_todr_attach(self, phandle, &sc->sc_todr); } static int -sun6i_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) -{ - struct sunxi_rtc_softc *sc = tch->cookie; - - const uint32_t yymmdd = RTC_READ(sc, SUN6I_RTC_YY_MM_DD_REG); - const uint32_t hhmmss = RTC_READ(sc, SUN6I_RTC_HH_MM_SS_REG); - - dt->dt_year = __SHIFTOUT(yymmdd, SUN6I_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; - dt->dt_mon = __SHIFTOUT(yymmdd, SUN6I_RTC_MONTH); - dt->dt_day = __SHIFTOUT(yymmdd, SUN6I_RTC_DAY); - dt->dt_wday = __SHIFTOUT(hhmmss, SUN6I_RTC_WK_NO); - dt->dt_hour = __SHIFTOUT(hhmmss, SUN6I_RTC_HOUR); - dt->dt_min = __SHIFTOUT(hhmmss, SUN6I_RTC_MINUTE); - dt->dt_sec = __SHIFTOUT(hhmmss, SUN6I_RTC_SECOND); - - return 0; -} - -static int -sun6i_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) -{ - struct sunxi_rtc_softc *sc = tch->cookie; - uint32_t yymmdd, hhmmss, maxyear; - - /* - * Sanity check the date before writing it back - */ - if (dt->dt_year < SUNXI_RTC_BASE_YEAR) { - aprint_normal_dev(sc->sc_dev, "year pre the epoch: %llu, " - "not writing back time\n", dt->dt_year); - return EIO; - } - maxyear = __SHIFTOUT(0xffffffff, SUN6I_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; - if (dt->dt_year > maxyear) { - aprint_normal_dev(sc->sc_dev, "year exceeds available field:" - " %llu, not writing back time\n", dt->dt_year); - return EIO; - } - - yymmdd = __SHIFTIN(dt->dt_year - SUNXI_RTC_BASE_YEAR, SUN6I_RTC_YEAR); - yymmdd |= __SHIFTIN(dt->dt_mon, SUN6I_RTC_MONTH); - yymmdd |= __SHIFTIN(dt->dt_day, SUN6I_RTC_DAY); - - hhmmss = __SHIFTIN(dt->dt_wday, SUN6I_RTC_WK_NO); - hhmmss |= __SHIFTIN(dt->dt_hour, SUN6I_RTC_HOUR); - hhmmss |= __SHIFTIN(dt->dt_min, SUN6I_RTC_MINUTE); - hhmmss |= __SHIFTIN(dt->dt_sec, SUN6I_RTC_SECOND); - - RTC_WRITE(sc, SUN6I_RTC_YY_MM_DD_REG, yymmdd); - RTC_WRITE(sc, SUN6I_RTC_HH_MM_SS_REG, hhmmss); - - return 0; -} - -static int -sun7i_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +sunxi_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct sunxi_rtc_softc *sc = tch->cookie; + const struct sunxi_rtc_config *conf = sc->sc_conf; - const uint32_t yymmdd = RTC_READ(sc, SUN7I_RTC_YY_MM_DD_REG); - const uint32_t hhmmss = RTC_READ(sc, SUN7I_RTC_HH_MM_SS_REG); + const uint32_t yymmdd = RTC_READ(sc, conf->yy_mm_dd_reg); + const uint32_t hhmmss = RTC_READ(sc, conf->hh_mm_ss_reg); - dt->dt_year = __SHIFTOUT(yymmdd, SUN7I_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; - dt->dt_mon = __SHIFTOUT(yymmdd, SUN7I_RTC_MONTH); - dt->dt_day = __SHIFTOUT(yymmdd, SUN7I_RTC_DAY); - dt->dt_wday = __SHIFTOUT(hhmmss, SUN7I_RTC_WK_NO); - dt->dt_hour = __SHIFTOUT(hhmmss, SUN7I_RTC_HOUR); - dt->dt_min = __SHIFTOUT(hhmmss, SUN7I_RTC_MINUTE); - dt->dt_sec = __SHIFTOUT(hhmmss, SUN7I_RTC_SECOND); + dt->dt_year = __SHIFTOUT(yymmdd, conf->year) + conf->base_year; + dt->dt_mon = __SHIFTOUT(yymmdd, conf->month); + dt->dt_day = __SHIFTOUT(yymmdd, conf->day); + dt->dt_wday = __SHIFTOUT(hhmmss, conf->wk_no); + dt->dt_hour = __SHIFTOUT(hhmmss, conf->hour); + dt->dt_min = __SHIFTOUT(hhmmss, conf->minute); + dt->dt_sec = __SHIFTOUT(hhmmss, conf->second); return 0; } static int -sun7i_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +sunxi_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct sunxi_rtc_softc *sc = tch->cookie; + const struct sunxi_rtc_config *conf = sc->sc_conf; uint32_t yymmdd, hhmmss, maxyear; /* * Sanity check the date before writing it back */ - if (dt->dt_year < SUNXI_RTC_BASE_YEAR) { + if (dt->dt_year < conf->base_year) { aprint_normal_dev(sc->sc_dev, "year pre the epoch: %llu, " "not writing back time\n", dt->dt_year); return EIO; } - maxyear = __SHIFTOUT(0xffffffff, SUN7I_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; + maxyear = __SHIFTOUT(0xffffffff, conf->year) + conf->base_year; if (dt->dt_year > maxyear) { aprint_normal_dev(sc->sc_dev, "year exceeds available field:" " %llu, not writing back time\n", dt->dt_year); return EIO; } - yymmdd = __SHIFTIN(dt->dt_year - SUNXI_RTC_BASE_YEAR, SUN7I_RTC_YEAR); - yymmdd |= __SHIFTIN(dt->dt_mon, SUN7I_RTC_MONTH); - yymmdd |= __SHIFTIN(dt->dt_day, SUN7I_RTC_DAY); - - hhmmss = __SHIFTIN(dt->dt_wday, SUN7I_RTC_WK_NO); - hhmmss |= __SHIFTIN(dt->dt_hour, SUN7I_RTC_HOUR); - hhmmss |= __SHIFTIN(dt->dt_min, SUN7I_RTC_MINUTE); - hhmmss |= __SHIFTIN(dt->dt_sec, SUN7I_RTC_SECOND); + yymmdd = __SHIFTIN(dt->dt_year - conf->base_year, conf->year); + yymmdd |= __SHIFTIN(dt->dt_mon, conf->month); + yymmdd |= __SHIFTIN(dt->dt_day, conf->day); + + hhmmss = __SHIFTIN(dt->dt_wday, conf->wk_no); + hhmmss |= __SHIFTIN(dt->dt_hour, conf->hour); + hhmmss |= __SHIFTIN(dt->dt_min, conf->minute); + hhmmss |= __SHIFTIN(dt->dt_sec, conf->second); - RTC_WRITE(sc, SUN7I_RTC_YY_MM_DD_REG, yymmdd); - RTC_WRITE(sc, SUN7I_RTC_HH_MM_SS_REG, hhmmss); + RTC_WRITE(sc, conf->yy_mm_dd_reg, yymmdd); + RTC_WRITE(sc, conf->hh_mm_ss_reg, hhmmss); return 0; }