Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Apr 2018 22:21:13 +0000 (UTC)
From:      Marcin Wojtas <mw@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r331961 - in head/sys: arm/mv dts/arm
Message-ID:  <201804032221.w33MLDTE019502@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mw
Date: Tue Apr  3 22:21:12 2018
New Revision: 331961
URL: https://svnweb.freebsd.org/changeset/base/331961

Log:
  Make Marvell AmadaXP timer driver more generic
  
  Store pointers to SoC specific functions in mv_timer_config structure
  and determine proper config in runtime based on compatible string from FDT.
  Compatible string for ArmadaXP timers is changed to match Linux FDT.
  Armada 38x uses generic Cortex-A9 timer and separate watchdog drivers, so
  it does not need to be supported by timer driver.
  
  Submitted by: Rafal Kozik <rk@semihalf.com>
  Reviewed by: manu
  Obtained from: Semihalf
  Sponsored by: Stormshield
  Differential Revision: https://reviews.freebsd.org/D14741

Modified:
  head/sys/arm/mv/timer.c
  head/sys/dts/arm/db78460.dts

Modified: head/sys/arm/mv/timer.c
==============================================================================
--- head/sys/arm/mv/timer.c	Tue Apr  3 22:15:53 2018	(r331960)
+++ head/sys/arm/mv/timer.c	Tue Apr  3 22:21:12 2018	(r331961)
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/cpu.h>
 #include <machine/intr.h>
+#include <machine/machdep.h>
 
 #include <arm/mv/mvreg.h>
 #include <arm/mv/mvvar.h>
@@ -60,18 +61,20 @@ __FBSDID("$FreeBSD$");
 #define	MV_WDT	0x2
 #define	MV_NONE	0x0
 
-#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X)
-#define MV_CLOCK_SRC		25000000	/* Timers' 25MHz mode */
-#else
-#define MV_CLOCK_SRC		get_tclk()
-#endif
+#define	MV_CLOCK_SRC_ARMV7	25000000	/* Timers' 25MHz mode */
 
-#if defined(SOC_MV_ARMADA38X)
-#define	WATCHDOG_TIMER	4
-#else
-#define	WATCHDOG_TIMER	2
-#endif
+#define	WATCHDOG_TIMER_ARMV5		2
 
+typedef void (*mv_watchdog_enable_t)(void);
+typedef void (*mv_watchdog_disable_t)(void);
+
+struct mv_timer_config {
+	enum soc_family		soc_family;
+	mv_watchdog_enable_t	watchdog_enable;
+	mv_watchdog_disable_t	watchdog_disable;
+	unsigned int 		clock_src;
+};
+
 struct mv_timer_softc {
 	struct resource	*	timer_res[2];
 	bus_space_tag_t		timer_bst;
@@ -79,6 +82,7 @@ struct mv_timer_softc {
 	struct mtx		timer_mtx;
 	struct eventtimer	et;
 	boolean_t		has_wdt;
+	struct mv_timer_config* config;
 };
 
 static struct resource_spec mv_timer_spec[] = {
@@ -89,8 +93,9 @@ static struct resource_spec mv_timer_spec[] = {
 
 /* Interrupt is not required by MV_WDT devices */
 static struct ofw_compat_data mv_timer_compat[] = {
+	{"marvell,armada-380-timer",	MV_NONE },
+	{"marvell,armada-xp-timer",	MV_TMR | MV_WDT },
 	{"mrvl,timer",			MV_TMR | MV_WDT },
-	{"marvell,armada-380-wdt",	MV_WDT },
 	{NULL,				MV_NONE }
 };
 
@@ -108,14 +113,42 @@ static void	mv_set_timer_control(uint32_t);
 static uint32_t	mv_get_timer(uint32_t);
 static void	mv_set_timer(uint32_t, uint32_t);
 static void	mv_set_timer_rel(uint32_t, uint32_t);
-static void	mv_watchdog_enable(void);
-static void	mv_watchdog_disable(void);
 static void	mv_watchdog_event(void *, unsigned int, int *);
 static int	mv_timer_start(struct eventtimer *et,
     sbintime_t first, sbintime_t period);
 static int	mv_timer_stop(struct eventtimer *et);
 static void	mv_setup_timers(void);
 
+static void mv_watchdog_enable_armv5(void);
+static void mv_watchdog_enable_armadaxp(void);
+static void mv_watchdog_disable_armv5(void);
+static void mv_watchdog_disable_armadaxp(void);
+
+#ifdef PLATFORM
+void mv_delay(int usec, void* arg);
+#endif
+
+static struct mv_timer_config timer_armadaxp_config =
+{
+	MV_SOC_ARMADA_XP,
+	&mv_watchdog_enable_armadaxp,
+	&mv_watchdog_disable_armadaxp,
+	MV_CLOCK_SRC_ARMV7,
+};
+static struct mv_timer_config timer_armv5_config =
+{
+	MV_SOC_ARMV5,
+	&mv_watchdog_enable_armv5,
+	&mv_watchdog_disable_armv5,
+	0,
+};
+
+static struct ofw_compat_data mv_timer_soc_config[] = {
+	{"marvell,armada-xp-timer",	(uintptr_t)&timer_armadaxp_config },
+	{"mrvl,timer",			(uintptr_t)&timer_armv5_config },
+	{NULL,				(uintptr_t)NULL },
+};
+
 static struct timecounter mv_timer_timecounter = {
 	.tc_get_timecount = mv_timer_get_timecount,
 	.tc_name = "CPUTimer1",
@@ -144,9 +177,7 @@ mv_timer_attach(device_t dev)
 	int	error;
 	void	*ihl;
 	struct	mv_timer_softc *sc;
-#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X)
 	uint32_t irq_cause, irq_mask;
-#endif
 
 	if (timer_softc != NULL)
 		return (ENXIO);
@@ -154,6 +185,12 @@ mv_timer_attach(device_t dev)
 	sc = (struct mv_timer_softc *)device_get_softc(dev);
 	timer_softc = sc;
 
+	sc->config = (struct mv_timer_config*)
+	    ofw_bus_search_compatible(dev, mv_timer_soc_config)->ocd_data;
+
+	if (sc->config->clock_src == 0)
+		sc->config->clock_src = get_tclk();
+
 	error = bus_alloc_resources(dev, mv_timer_spec, sc->timer_res);
 	if (error) {
 		device_printf(dev, "could not allocate resources\n");
@@ -163,13 +200,13 @@ mv_timer_attach(device_t dev)
 	sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
 	sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
 
-	sc->has_wdt = ofw_bus_has_prop(dev, "mrvl,has-wdt") ||
-	    ofw_bus_is_compatible(dev, "marvell,armada-380-wdt");
+	sc->has_wdt = ofw_bus_has_prop(dev, "mrvl,has-wdt");
 
 	mtx_init(&timer_softc->timer_mtx, "watchdog", NULL, MTX_DEF);
 
 	if (sc->has_wdt) {
-		mv_watchdog_disable();
+		if (sc->config->watchdog_disable)
+			sc->config->watchdog_disable();
 		EVENTHANDLER_REGISTER(watchdog_list, mv_watchdog_event, sc, 0);
 	}
 
@@ -192,30 +229,33 @@ mv_timer_attach(device_t dev)
 	}
 
 	mv_setup_timers();
-#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X)
-	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
-        irq_cause &= IRQ_TIMER0_CLR;
+	if (sc->config->soc_family != MV_SOC_ARMADA_XP ) {
+		irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+		irq_cause &= IRQ_TIMER0_CLR;
 
-	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
-	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
-	irq_mask |= IRQ_TIMER0_MASK;
-	irq_mask &= ~IRQ_TIMER1_MASK;
-	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
-#endif
+		write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+		irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
+		irq_mask |= IRQ_TIMER0_MASK;
+		irq_mask &= ~IRQ_TIMER1_MASK;
+		write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+	}
 	sc->et.et_name = "CPUTimer0";
 	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
 	sc->et.et_quality = 1000;
 
-	sc->et.et_frequency = MV_CLOCK_SRC;
+	sc->et.et_frequency = sc->config->clock_src;
 	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
 	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
 	sc->et.et_start = mv_timer_start;
 	sc->et.et_stop = mv_timer_stop;
 	sc->et.et_priv = sc;
 	et_register(&sc->et);
-	mv_timer_timecounter.tc_frequency = MV_CLOCK_SRC;
+	mv_timer_timecounter.tc_frequency = sc->config->clock_src;
 	tc_init(&mv_timer_timecounter);
 
+#ifdef PLATFORM
+	arm_set_delay(mv_delay, NULL);
+#endif
 	return (0);
 }
 
@@ -260,8 +300,13 @@ mv_timer_get_timecount(struct timecounter *tc)
 	return (INITIAL_TIMECOUNTER - mv_get_timer(1));
 }
 
+#ifdef PLATFORM
 void
+mv_delay(int usec, void* arg)
+#else
+void
 DELAY(int usec)
+#endif
 {
 	uint32_t	val, val_temp;
 	int32_t		nticks;
@@ -275,7 +320,7 @@ DELAY(int usec)
 	TSENTER();
 
 	val = mv_get_timer(1);
-	nticks = ((MV_CLOCK_SRC / 1000000 + 1) * usec);
+	nticks = ((timer_softc->config->clock_src / 1000000 + 1) * usec);
 
 	while (nticks > 0) {
 		val_temp = mv_get_timer(1);
@@ -330,26 +375,14 @@ mv_set_timer_rel(uint32_t timer, uint32_t val)
 }
 
 static void
-mv_watchdog_enable(void)
+mv_watchdog_enable_armv5(void)
 {
-	uint32_t val, irq_cause;
-#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X)
-	uint32_t irq_mask;
-#endif
+	uint32_t val, irq_cause, irq_mask;
 
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
 	irq_cause &= IRQ_TIMER_WD_CLR;
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 
-#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X)
-	val = read_cpu_mp_clocks(WD_RSTOUTn_MASK);
-	val |= (WD_GLOBAL_MASK | WD_CPU0_MASK);
-	write_cpu_mp_clocks(WD_RSTOUTn_MASK, val);
-
-	val = read_cpu_misc(RSTOUTn_MASK);
-	val &= ~RSTOUTn_MASK_WD;
-	write_cpu_misc(RSTOUTn_MASK, val);
-#else
 	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
 	irq_mask |= IRQ_TIMER_WD_MASK;
 	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
@@ -357,44 +390,43 @@ mv_watchdog_enable(void)
 	val = read_cpu_ctrl(RSTOUTn_MASK);
 	val |= WD_RST_OUT_EN;
 	write_cpu_ctrl(RSTOUTn_MASK, val);
-#endif
 
 	val = mv_get_timer_control();
-#if defined(SOC_MV_ARMADA38X)
-	val |= CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO | CPU_TIMER_WD_25MHZ_EN;
-#elif defined(SOC_MV_ARMADAXP)
-	val |= CPU_TIMER2_EN | CPU_TIMER2_AUTO | CPU_TIMER_WD_25MHZ_EN;
-#else
 	val |= CPU_TIMER2_EN | CPU_TIMER2_AUTO;
-#endif
 	mv_set_timer_control(val);
 }
 
 static void
-mv_watchdog_disable(void)
+mv_watchdog_enable_armadaxp(void)
 {
-	uint32_t val, irq_cause;
-#if !defined(SOC_MV_ARMADAXP) && !defined(SOC_MV_ARMADA38X)
-	uint32_t irq_mask;
-#endif
+	uint32_t irq_cause, val;
 
-	val = mv_get_timer_control();
-#if defined(SOC_MV_ARMADA38X)
-	val &= ~(CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO);
-#else
-	val &= ~(CPU_TIMER2_EN | CPU_TIMER2_AUTO);
-#endif
-	mv_set_timer_control(val);
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= IRQ_TIMER_WD_CLR;
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 
-#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X)
 	val = read_cpu_mp_clocks(WD_RSTOUTn_MASK);
-	val &= ~(WD_GLOBAL_MASK | WD_CPU0_MASK);
+	val |= (WD_GLOBAL_MASK | WD_CPU0_MASK);
 	write_cpu_mp_clocks(WD_RSTOUTn_MASK, val);
 
 	val = read_cpu_misc(RSTOUTn_MASK);
-	val |= RSTOUTn_MASK_WD;
-	write_cpu_misc(RSTOUTn_MASK, RSTOUTn_MASK_WD);
-#else
+	val &= ~RSTOUTn_MASK_WD;
+	write_cpu_misc(RSTOUTn_MASK, val);
+
+	val = mv_get_timer_control();
+	val |= CPU_TIMER2_EN | CPU_TIMER2_AUTO | CPU_TIMER_WD_25MHZ_EN;
+	mv_set_timer_control(val);
+}
+
+static void
+mv_watchdog_disable_armv5(void)
+{
+	uint32_t val, irq_cause,irq_mask;
+
+	val = mv_get_timer_control();
+	val &= ~(CPU_TIMER2_EN | CPU_TIMER2_AUTO);
+	mv_set_timer_control(val);
+
 	val = read_cpu_ctrl(RSTOUTn_MASK);
 	val &= ~WD_RST_OUT_EN;
 	write_cpu_ctrl(RSTOUTn_MASK, val);
@@ -402,14 +434,34 @@ mv_watchdog_disable(void)
 	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
 	irq_mask &= ~(IRQ_TIMER_WD_MASK);
 	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
-#endif
 
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
 	irq_cause &= IRQ_TIMER_WD_CLR;
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 }
 
+static void
+mv_watchdog_disable_armadaxp(void)
+{
+	uint32_t val, irq_cause;
 
+	val = read_cpu_mp_clocks(WD_RSTOUTn_MASK);
+	val &= ~(WD_GLOBAL_MASK | WD_CPU0_MASK);
+	write_cpu_mp_clocks(WD_RSTOUTn_MASK, val);
+
+	val = read_cpu_misc(RSTOUTn_MASK);
+	val |= RSTOUTn_MASK_WD;
+	write_cpu_misc(RSTOUTn_MASK, RSTOUTn_MASK_WD);
+
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= IRQ_TIMER_WD_CLR;
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+
+	val = mv_get_timer_control();
+	val &= ~(CPU_TIMER2_EN | CPU_TIMER2_AUTO);
+	mv_set_timer_control(val);
+}
+
 /*
  * Watchdog event handler.
  */
@@ -420,20 +472,23 @@ mv_watchdog_event(void *arg, unsigned int cmd, int *er
 	uint64_t ticks;
 
 	mtx_lock(&timer_softc->timer_mtx);
-	if (cmd == 0)
-		mv_watchdog_disable();
-	else {
+	if (cmd == 0) {
+		if (timer_softc->config->watchdog_disable != NULL)
+			timer_softc->config->watchdog_disable();
+	} else {
 		/*
 		 * Watchdog timeout is in nanosecs, calculation according to
 		 * watchdog(9)
 		 */
 		ns = (uint64_t)1 << (cmd & WD_INTERVAL);
-		ticks = (uint64_t)(ns * MV_CLOCK_SRC) / 1000000000;
-		if (ticks > MAX_WATCHDOG_TICKS)
-			mv_watchdog_disable();
-		else {
-			mv_set_timer(WATCHDOG_TIMER, ticks);
-			mv_watchdog_enable();
+		ticks = (uint64_t)(ns * timer_softc->config->clock_src) / 1000000000;
+		if (ticks > MAX_WATCHDOG_TICKS) {
+			if (timer_softc->config->watchdog_disable != NULL)
+				timer_softc->config->watchdog_disable();
+		} else {
+			mv_set_timer(WATCHDOG_TIMER_ARMV5, ticks);
+			if (timer_softc->config->watchdog_enable != NULL)
+				timer_softc->config->watchdog_enable();
 			*error = 0;
 		}
 	}
@@ -491,10 +546,12 @@ mv_setup_timers(void)
 	val = mv_get_timer_control();
 	val &= ~(CPU_TIMER0_EN | CPU_TIMER0_AUTO);
 	val |= CPU_TIMER1_EN | CPU_TIMER1_AUTO;
-#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X)
-	/* Enable 25MHz mode */
-	val |= CPU_TIMER0_25MHZ_EN | CPU_TIMER1_25MHZ_EN;
-#endif
+
+	if (timer_softc->config->soc_family == MV_SOC_ARMADA_XP) {
+		/* Enable 25MHz mode */
+		val |= CPU_TIMER0_25MHZ_EN | CPU_TIMER1_25MHZ_EN;
+	}
+
 	mv_set_timer_control(val);
 	timers_initialized = 1;
 }

Modified: head/sys/dts/arm/db78460.dts
==============================================================================
--- head/sys/dts/arm/db78460.dts	Tue Apr  3 22:15:53 2018	(r331960)
+++ head/sys/dts/arm/db78460.dts	Tue Apr  3 22:21:12 2018	(r331961)
@@ -85,7 +85,7 @@
 		};
 
 		timer@21840 {
-			compatible = "mrvl,timer";
+			compatible = "marvell,armada-xp-timer";
 			reg = <0x21840 0x30>;
 			interrupts = <5>;
 			interrupt-parent = <&MPIC>;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201804032221.w33MLDTE019502>