svn commit: r346271 - in head/sys/arm/allwinner: . clkng

Emmanuel Vadot manu at FreeBSD.org
Tue Apr 16 12:39:33 UTC 2019


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 <manu at FreeBSD.Org>
  * Copyright (c) 2016 Vladimir Belian <fate10 at 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);


More information about the svn-src-head mailing list