Author: manu Date: Tue Apr 16 12:39:31 2019 New Revision: 346271 URL: https://svnweb.freebsd.org/changeset/base/346271
Log: aw_rtc: Register the clocks Since latest DTS update the rtc is supposed to register two clocks : - osc32k (the 32k oscillator on the board that the RTC uses directly and that other peripheral can use) - iosc (the internal oscillator of the RTC when available which frequency depend on the SoC revision) Since we need the RTC before the proper clock control unit (because it uses those clocks) attach it a BUS_PASS_BUS + MIDDLE and attach the clock control unit at BUS_PASS_BUS + LAST for the SoC that requires it. Tested On: A20, H3, A64 MFC after: 1 month Modified: head/sys/arm/allwinner/aw_rtc.c head/sys/arm/allwinner/clkng/ccu_a31.c head/sys/arm/allwinner/clkng/ccu_a64.c head/sys/arm/allwinner/clkng/ccu_a83t.c head/sys/arm/allwinner/clkng/ccu_h3.c Modified: head/sys/arm/allwinner/aw_rtc.c ============================================================================== --- head/sys/arm/allwinner/aw_rtc.c Tue Apr 16 12:25:15 2019 (r346270) +++ head/sys/arm/allwinner/aw_rtc.c Tue Apr 16 12:39:31 2019 (r346271) @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2019 Emmanuel Vadot <m...@freebsd.org> * Copyright (c) 2016 Vladimir Belian <fat...@gmail.com> * All rights reserved. * @@ -43,6 +44,8 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> +#include <dev/extres/clk/clk_fixed.h> + #include <arm/allwinner/aw_machdep.h> #include "clock_if.h" @@ -62,7 +65,7 @@ __FBSDID("$FreeBSD$"); #define LOSC_MAGIC 0x16aa0000 #define LOSC_BUSY_MASK 0x00000380 -#define IS_SUN7I (sc->type == A20_RTC) +#define IS_SUN7I (sc->conf->is_a20 == true) #define YEAR_MIN (IS_SUN7I ? 1970 : 2010) #define YEAR_MAX (IS_SUN7I ? 2100 : 2073) @@ -92,27 +95,68 @@ __FBSDID("$FreeBSD$"); #define RTC_READ(sc, reg) bus_read_4((sc)->res, (reg)) #define RTC_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) -#define IS_LEAP_YEAR(y) \ - (((y) % 400) == 0 || (((y) % 100) != 0 && ((y) % 4) == 0)) +#define IS_LEAP_YEAR(y) (((y) % 400) == 0 || (((y) % 100) != 0 && ((y) % 4) == 0)) -#define A10_RTC 1 -#define A20_RTC 2 -#define A31_RTC 3 +struct aw_rtc_conf { + uint64_t iosc_freq; + bus_size_t rtc_date; + bus_size_t rtc_time; + bus_size_t rtc_losc_sta; + bool is_a20; +}; +struct aw_rtc_conf a10_conf = { + .rtc_date = A10_RTC_DATE_REG, + .rtc_time = A10_RTC_TIME_REG, + .rtc_losc_sta = LOSC_CTRL_REG, +}; + +struct aw_rtc_conf a20_conf = { + .rtc_date = A10_RTC_DATE_REG, + .rtc_time = A10_RTC_TIME_REG, + .rtc_losc_sta = LOSC_CTRL_REG, + .is_a20 = true, +}; + +struct aw_rtc_conf a31_conf = { + .iosc_freq = 650000, /* between 600 and 700 Khz */ + .rtc_date = A31_RTC_DATE_REG, + .rtc_time = A31_RTC_TIME_REG, + .rtc_losc_sta = A31_LOSC_AUTO_SWT_STA, +}; + +struct aw_rtc_conf h3_conf = { + .iosc_freq = 16000000, + .rtc_date = A31_RTC_DATE_REG, + .rtc_time = A31_RTC_TIME_REG, + .rtc_losc_sta = A31_LOSC_AUTO_SWT_STA, +}; + static struct ofw_compat_data compat_data[] = { - { "allwinner,sun4i-a10-rtc", A10_RTC }, - { "allwinner,sun7i-a20-rtc", A20_RTC }, - { "allwinner,sun6i-a31-rtc", A31_RTC }, + { "allwinner,sun4i-a10-rtc", (uintptr_t) &a10_conf }, + { "allwinner,sun7i-a20-rtc", (uintptr_t) &a20_conf }, + { "allwinner,sun6i-a31-rtc", (uintptr_t) &a31_conf }, + { "allwinner,sun8i-h3-rtc", (uintptr_t) &h3_conf }, { NULL, 0 } }; struct aw_rtc_softc { struct resource *res; + struct aw_rtc_conf *conf; int type; - bus_size_t rtc_date; - bus_size_t rtc_time; }; +static struct clk_fixed_def aw_rtc_osc32k = { + .clkdef.id = 0, + .freq = 32768, +}; + +static struct clk_fixed_def aw_rtc_iosc = { + .clkdef.id = 2, +}; + +static void aw_rtc_install_clocks(struct aw_rtc_softc *sc, device_t dev); + static int aw_rtc_probe(device_t dev); static int aw_rtc_attach(device_t dev); static int aw_rtc_detach(device_t dev); @@ -140,9 +184,8 @@ static driver_t aw_rtc_driver = { static devclass_t aw_rtc_devclass; EARLY_DRIVER_MODULE(aw_rtc, simplebus, aw_rtc_driver, aw_rtc_devclass, 0, 0, - BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); + BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); - static int aw_rtc_probe(device_t dev) { @@ -161,7 +204,6 @@ static int aw_rtc_attach(device_t dev) { struct aw_rtc_softc *sc = device_get_softc(dev); - bus_size_t rtc_losc_sta; uint32_t val; int rid = 0; @@ -171,20 +213,7 @@ aw_rtc_attach(device_t dev) return (ENXIO); } - sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; - switch (sc->type) { - case A10_RTC: - case A20_RTC: - sc->rtc_date = A10_RTC_DATE_REG; - sc->rtc_time = A10_RTC_TIME_REG; - rtc_losc_sta = LOSC_CTRL_REG; - break; - case A31_RTC: - sc->rtc_date = A31_RTC_DATE_REG; - sc->rtc_time = A31_RTC_TIME_REG; - rtc_losc_sta = A31_LOSC_AUTO_SWT_STA; - break; - } + sc->conf = (struct aw_rtc_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; val = RTC_READ(sc, LOSC_CTRL_REG); val |= LOSC_AUTO_SW_EN; val |= LOSC_MAGIC | LOSC_GSM | LOSC_OSC_SRC; @@ -193,13 +222,15 @@ aw_rtc_attach(device_t dev) DELAY(100); if (bootverbose) { - val = RTC_READ(sc, rtc_losc_sta); + val = RTC_READ(sc, sc->conf->rtc_losc_sta); if ((val & LOSC_OSC_SRC) == 0) device_printf(dev, "Using internal oscillator\n"); else device_printf(dev, "Using external oscillator\n"); } + aw_rtc_install_clocks(sc, dev); + clock_register(dev, RTC_RES_US); return (0); @@ -212,6 +243,41 @@ aw_rtc_detach(device_t dev) return (EBUSY); } +static void +aw_rtc_install_clocks(struct aw_rtc_softc *sc, device_t dev) { + struct clkdom *clkdom; + const char **clknames; + phandle_t node; + int nclocks; + + node = ofw_bus_get_node(dev); + nclocks = ofw_bus_string_list_to_array(node, "clock-output-names", &clknames); + /* No clocks to export */ + if (nclocks <= 0) + return; + + if (nclocks != 3) { + device_printf(dev, "Having only %d clocks instead of 3, aborting\n", nclocks); + return; + } + + clkdom = clkdom_create(dev); + + aw_rtc_osc32k.clkdef.name = clknames[0]; + if (clknode_fixed_register(clkdom, &aw_rtc_osc32k) != 0) + device_printf(dev, "Cannot register osc32k clock\n"); + + aw_rtc_iosc.clkdef.name = clknames[2]; + aw_rtc_iosc.freq = sc->conf->iosc_freq; + if (clknode_fixed_register(clkdom, &aw_rtc_iosc) != 0) + device_printf(dev, "Cannot register iosc clock\n"); + + clkdom_finit(clkdom); + + if (bootverbose) + clkdom_dump(clkdom); +} + static int aw_rtc_gettime(device_t dev, struct timespec *ts) { @@ -219,11 +285,11 @@ aw_rtc_gettime(device_t dev, struct timespec *ts) struct clocktime ct; uint32_t rdate, rtime; - rdate = RTC_READ(sc, sc->rtc_date); - rtime = RTC_READ(sc, sc->rtc_time); + rdate = RTC_READ(sc, sc->conf->rtc_date); + rtime = RTC_READ(sc, sc->conf->rtc_time); if ((rtime & TIME_MASK) == 0) - rdate = RTC_READ(sc, sc->rtc_date); + rdate = RTC_READ(sc, sc->conf->rtc_date); ct.sec = GET_SEC_VALUE(rtime); ct.min = GET_MIN_VALUE(rtime); @@ -265,7 +331,7 @@ aw_rtc_settime(device_t dev, struct timespec *ts) DELAY(1); } /* reset time register to avoid unexpected date increment */ - RTC_WRITE(sc, sc->rtc_time, 0); + RTC_WRITE(sc, sc->conf->rtc_time, 0); rdate = SET_DAY_VALUE(ct.day) | SET_MON_VALUE(ct.mon) | SET_YEAR_VALUE(ct.year - YEAR_OFFSET) | @@ -281,7 +347,7 @@ aw_rtc_settime(device_t dev, struct timespec *ts) } DELAY(1); } - RTC_WRITE(sc, sc->rtc_date, rdate); + RTC_WRITE(sc, sc->conf->rtc_date, rdate); for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) { if (clk > RTC_TIMEOUT) { @@ -290,7 +356,7 @@ aw_rtc_settime(device_t dev, struct timespec *ts) } DELAY(1); } - RTC_WRITE(sc, sc->rtc_time, rtime); + RTC_WRITE(sc, sc->conf->rtc_time, rtime); DELAY(RTC_TIMEOUT); Modified: head/sys/arm/allwinner/clkng/ccu_a31.c ============================================================================== --- head/sys/arm/allwinner/clkng/ccu_a31.c Tue Apr 16 12:25:15 2019 (r346270) +++ head/sys/arm/allwinner/clkng/ccu_a31.c Tue Apr 16 12:39:31 2019 (r346271) @@ -973,4 +973,4 @@ DEFINE_CLASS_1(ccu_a31ng, ccu_a31ng_driver, ccu_a31ng_ sizeof(struct aw_ccung_softc), aw_ccung_driver); EARLY_DRIVER_MODULE(ccu_a31ng, simplebus, ccu_a31ng_driver, - ccu_a31ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + ccu_a31ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LAST); Modified: head/sys/arm/allwinner/clkng/ccu_a64.c ============================================================================== --- head/sys/arm/allwinner/clkng/ccu_a64.c Tue Apr 16 12:25:15 2019 (r346270) +++ head/sys/arm/allwinner/clkng/ccu_a64.c Tue Apr 16 12:39:31 2019 (r346271) @@ -825,4 +825,4 @@ DEFINE_CLASS_1(ccu_a64ng, ccu_a64ng_driver, ccu_a64ng_ sizeof(struct aw_ccung_softc), aw_ccung_driver); EARLY_DRIVER_MODULE(ccu_a64ng, simplebus, ccu_a64ng_driver, - ccu_a64ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + ccu_a64ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LAST); Modified: head/sys/arm/allwinner/clkng/ccu_a83t.c ============================================================================== --- head/sys/arm/allwinner/clkng/ccu_a83t.c Tue Apr 16 12:25:15 2019 (r346270) +++ head/sys/arm/allwinner/clkng/ccu_a83t.c Tue Apr 16 12:39:31 2019 (r346271) @@ -786,4 +786,4 @@ DEFINE_CLASS_1(ccu_a83tng, ccu_a83tng_driver, ccu_a83t sizeof(struct aw_ccung_softc), aw_ccung_driver); EARLY_DRIVER_MODULE(ccu_a83tng, simplebus, ccu_a83tng_driver, - ccu_a83tng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + ccu_a83tng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LAST); Modified: head/sys/arm/allwinner/clkng/ccu_h3.c ============================================================================== --- head/sys/arm/allwinner/clkng/ccu_h3.c Tue Apr 16 12:25:15 2019 (r346270) +++ head/sys/arm/allwinner/clkng/ccu_h3.c Tue Apr 16 12:39:31 2019 (r346271) @@ -787,4 +787,4 @@ DEFINE_CLASS_1(ccu_h3ng, ccu_h3ng_driver, ccu_h3ng_met sizeof(struct aw_ccung_softc), aw_ccung_driver); EARLY_DRIVER_MODULE(ccu_h3ng, simplebus, ccu_h3ng_driver, - ccu_h3ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); + ccu_h3ng_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LAST); _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"