Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142642315
D5414.id13699.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D5414.id13699.diff
View Options
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -16,5 +16,6 @@
arm/allwinner/axp209.c optional axp209
arm/allwinner/if_emac.c optional emac
arm/allwinner/sunxi_dma_if.m standard
+arm/allwinner/sunxi_rtc.c standard
dev/iicbus/twsi/a10_twsi.c optional twsi
#arm/allwinner/console.c standard
Index: sys/arm/allwinner/sunxi_rtc.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/sunxi_rtc.c
@@ -0,0 +1,266 @@
+/*-
+ * Copyright (c) 2016 Vladimir Belian <fate10@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/time.h>
+#include <sys/rman.h>
+#include <sys/clock.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/allwinner/allwinner_machdep.h>
+
+#include "clock_if.h"
+
+#define LOSC_CTRL_REG 0x00
+#define RTC_DATE_REG 0x04
+#define RTC_TIME_REG 0x08
+
+#define TIME_MASK 0x001f3f3f
+
+#define LOSC_OSC_SRC 0x00000001
+#define LOSC_GSM 0x00000008
+#define LOSC_AUTO_SW_EN 0x00004000
+#define LOSC_MAGIC 0x16aa0000
+#define LOSC_BUSY_MASK 0x00000380
+
+#define IS_SUN7I (allwinner_soc_family() == ALLWINNERSOC_SUN7I)
+
+#define YEAR_MIN (IS_SUN7I ? 1970 : 2010)
+#define YEAR_MAX (IS_SUN7I ? 2100 : 2073)
+#define YEAR_OFFSET (IS_SUN7I ? 1900 : 2010)
+#define YEAR_MASK (IS_SUN7I ? 0xff : 0x3f)
+#define LEAP_BIT (IS_SUN7I ? 24 : 22)
+
+#define GET_SEC_VALUE(x) ((x) & 0x0000003f)
+#define GET_MIN_VALUE(x) (((x) & 0x00003f00) >> 8)
+#define GET_HOUR_VALUE(x) (((x) & 0x001f0000) >> 16)
+#define GET_DAY_VALUE(x) ((x) & 0x0000001f)
+#define GET_MON_VALUE(x) (((x) & 0x00000f00) >> 8)
+#define GET_YEAR_VALUE(x) (((x) >> 16) & YEAR_MASK)
+
+#define SET_DAY_VALUE(x) GET_DAY_VALUE(x)
+#define SET_MON_VALUE(x) (((x) & 0x0000000f) << 8)
+#define SET_YEAR_VALUE(x) (((x) & YEAR_MASK) << 16)
+#define SET_LEAP_VALUE(x) (((x) & 0x00000001) << LEAP_BIT)
+#define SET_SEC_VALUE(x) GET_SEC_VALUE(x)
+#define SET_MIN_VALUE(x) (((x) & 0x0000003f) << 8)
+#define SET_HOUR_VALUE(x) (((x) & 0x0000001f) << 16)
+
+#define HALF_OF_SEC_NS 500000000
+#define RTC_RES_US 1000000
+#define RTC_TIMEOUT 70
+
+#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))
+
+
+static struct ofw_compat_data compat_data[] = {
+ { "allwinner,sun4i-a10-rtc", true },
+ { "allwinner,sun7i-a20-rtc", true },
+ { NULL, false }
+};
+
+struct sunxi_rtc_softc {
+ struct resource *res;
+};
+
+static int sunxi_rtc_probe(device_t dev);
+static int sunxi_rtc_attach(device_t dev);
+
+static int sunxi_rtc_gettime(device_t dev, struct timespec *ts);
+static int sunxi_rtc_settime(device_t dev, struct timespec *ts);
+
+static device_method_t sunxi_rtc_methods[] = {
+ DEVMETHOD(device_probe, sunxi_rtc_probe),
+ DEVMETHOD(device_attach, sunxi_rtc_attach),
+
+ DEVMETHOD(clock_gettime, sunxi_rtc_gettime),
+ DEVMETHOD(clock_settime, sunxi_rtc_settime),
+
+ DEVMETHOD_END
+};
+
+static driver_t sunxi_rtc_driver = {
+ "rtc",
+ sunxi_rtc_methods,
+ sizeof(struct sunxi_rtc_softc),
+};
+
+static devclass_t sunxi_rtc_devclass;
+
+EARLY_DRIVER_MODULE(sunxi_rtc, simplebus, sunxi_rtc_driver, sunxi_rtc_devclass, 0, 0,
+ BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+
+
+static int
+sunxi_rtc_probe(device_t dev)
+{
+ u_int soc_family;
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ soc_family = allwinner_soc_family();
+ if (soc_family != ALLWINNERSOC_SUN7I &&
+ soc_family != ALLWINNERSOC_SUN4I) return (ENXIO);
+
+ device_set_desc(dev, "Allwinner RTC");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+sunxi_rtc_attach(device_t dev)
+{
+ struct sunxi_rtc_softc *sc = device_get_softc(dev);
+ uint32_t val;
+ int rid = 0;
+
+ sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!sc->res) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ val = RTC_READ(sc, LOSC_CTRL_REG);
+ val &= ~LOSC_AUTO_SW_EN;
+ val |= LOSC_MAGIC | LOSC_GSM | LOSC_OSC_SRC;
+ RTC_WRITE(sc, LOSC_CTRL_REG, val);
+
+ DELAY(100);
+
+ val = RTC_READ(sc, LOSC_CTRL_REG);
+ if (!(val & LOSC_OSC_SRC)) {
+ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
+ device_printf(dev, "set LOSC to external failed\n");
+ return (ENXIO);
+ }
+
+ clock_register(dev, RTC_RES_US);
+
+ return (0);
+}
+
+static int
+sunxi_rtc_gettime(device_t dev, struct timespec *ts)
+{
+ struct sunxi_rtc_softc *sc = device_get_softc(dev);
+ struct clocktime ct;
+ uint32_t rdate, rtime;
+
+ rdate = RTC_READ(sc, RTC_DATE_REG);
+ rtime = RTC_READ(sc, RTC_TIME_REG);
+
+ if ((rtime & TIME_MASK) == 0)
+ rdate = RTC_READ(sc, RTC_DATE_REG);
+
+ ct.sec = GET_SEC_VALUE(rtime);
+ ct.min = GET_MIN_VALUE(rtime);
+ ct.hour = GET_HOUR_VALUE(rtime);
+ ct.day = GET_DAY_VALUE(rdate);
+ ct.mon = GET_MON_VALUE(rdate);
+ ct.year = GET_YEAR_VALUE(rdate) + YEAR_OFFSET;
+ ct.dow = -1;
+ /* RTC resolution is 1 sec */
+ ct.nsec = 0;
+
+ return (clock_ct_to_ts(&ct, ts));
+}
+
+static int
+sunxi_rtc_settime(device_t dev, struct timespec *ts)
+{
+ struct sunxi_rtc_softc *sc = device_get_softc(dev);
+ struct clocktime ct;
+ uint32_t clk, rdate, rtime;
+
+ /* RTC resolution is 1 sec */
+ if (ts->tv_nsec >= HALF_OF_SEC_NS)
+ ts->tv_sec++;
+ ts->tv_nsec = 0;
+
+ clock_ts_to_ct(ts, &ct);
+
+ if ((ct.year < YEAR_MIN) || (ct.year > YEAR_MAX)) {
+ device_printf(dev, "could not set time, year out of range\n");
+ return (EINVAL);
+ }
+
+ for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+ if (clk > RTC_TIMEOUT) {
+ device_printf(dev, "could not set time, RTC busy\n");
+ return (EINVAL);
+ }
+ DELAY(1);
+ }
+ /* reset time register to avoid unexpected date increment */
+ RTC_WRITE(sc, RTC_TIME_REG, 0);
+
+ rdate = SET_DAY_VALUE(ct.day) | SET_MON_VALUE(ct.mon) |
+ SET_YEAR_VALUE(ct.year - YEAR_OFFSET) |
+ SET_LEAP_VALUE(IS_LEAP_YEAR(ct.year));
+
+ rtime = SET_SEC_VALUE(ct.sec) | SET_MIN_VALUE(ct.min) |
+ SET_HOUR_VALUE(ct.hour);
+
+ for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+ if (clk > RTC_TIMEOUT) {
+ device_printf(dev, "could not set date, RTC busy\n");
+ return (EINVAL);
+ }
+ DELAY(1);
+ }
+ RTC_WRITE(sc, RTC_DATE_REG, rdate);
+
+ for (clk = 0; RTC_READ(sc, LOSC_CTRL_REG) & LOSC_BUSY_MASK; clk++) {
+ if (clk > RTC_TIMEOUT) {
+ device_printf(dev, "could not set time, RTC busy\n");
+ return (EINVAL);
+ }
+ DELAY(1);
+ }
+ RTC_WRITE(sc, RTC_TIME_REG, rtime);
+
+ DELAY(RTC_TIMEOUT);
+
+ return (0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 22, 7:11 PM (13 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27859883
Default Alt Text
D5414.id13699.diff (8 KB)
Attached To
Mode
D5414: Allwinner A10/A20 rtc
Attached
Detach File
Event Timeline
Log In to Comment