Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 26 Oct 2014 03:55:10 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r273673 - stable/10/sys/arm/arm
Message-ID:  <201410260355.s9Q3tAGV034391@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Sun Oct 26 03:55:09 2014
New Revision: 273673
URL: https://svnweb.freebsd.org/changeset/base/273673

Log:
  MFC r271906:
  
    Make the ARM MPCore Timer driver work with published standard FDT bindings.

Modified:
  stable/10/sys/arm/arm/mpcore_timer.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/arm/arm/mpcore_timer.c
==============================================================================
--- stable/10/sys/arm/arm/mpcore_timer.c	Sun Oct 26 03:52:45 2014	(r273672)
+++ stable/10/sys/arm/arm/mpcore_timer.c	Sun Oct 26 03:55:09 2014	(r273673)
@@ -97,36 +97,25 @@ __FBSDID("$FreeBSD$");
 #define GBL_TIMER_INTR_EVENT           (1UL << 0)
 
 struct arm_tmr_softc {
-	struct resource *	tmr_res[4];
-	bus_space_tag_t		prv_bst;
-	bus_space_tag_t		gbl_bst;
-	bus_space_handle_t	prv_bsh;
-	bus_space_handle_t	gbl_bsh;
+	device_t		dev;
+	int			irqrid;
+	int			memrid;
+	struct resource *	gbl_mem;
+	struct resource *	prv_mem;
+	struct resource *	prv_irq;
 	uint64_t		clkfreq;
 	struct eventtimer	et;
 };
 
-static struct resource_spec arm_tmr_spec[] = {
-	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Global registers */
-	{ SYS_RES_IRQ,		0,	RF_ACTIVE },    /* Global timer interrupt (unused) */
-	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* Private (per-CPU) registers */
-	{ SYS_RES_IRQ,		1,	RF_ACTIVE },    /* Private timer interrupt */
-	{ -1, 0 }
-};
-
-static struct arm_tmr_softc *arm_tmr_sc = NULL;
-
-static uint64_t platform_arm_tmr_freq = 0;
-
-#define	tmr_prv_read_4(reg)		\
-    bus_space_read_4(arm_tmr_sc->prv_bst, arm_tmr_sc->prv_bsh, reg)
-#define	tmr_prv_write_4(reg, val)		\
-    bus_space_write_4(arm_tmr_sc->prv_bst, arm_tmr_sc->prv_bsh, reg, val)
-#define	tmr_gbl_read_4(reg)		\
-    bus_space_read_4(arm_tmr_sc->gbl_bst, arm_tmr_sc->gbl_bsh, reg)
-#define	tmr_gbl_write_4(reg, val)		\
-    bus_space_write_4(arm_tmr_sc->gbl_bst, arm_tmr_sc->gbl_bsh, reg, val)
-
+static struct eventtimer *arm_tmr_et;
+static struct timecounter *arm_tmr_tc;
+static uint64_t arm_tmr_freq;
+static boolean_t arm_tmr_freq_varies;
+
+#define	tmr_prv_read_4(sc, reg)         bus_read_4((sc)->prv_mem, reg)
+#define	tmr_prv_write_4(sc, reg, val)   bus_write_4((sc)->prv_mem, reg, val)
+#define	tmr_gbl_read_4(sc, reg)         bus_read_4((sc)->gbl_mem, reg)
+#define	tmr_gbl_write_4(sc, reg, val)   bus_write_4((sc)->gbl_mem, reg, val)
 
 static timecounter_get_t arm_tmr_get_timecount;
 
@@ -139,6 +128,21 @@ static struct timecounter arm_tmr_timeco
 	.tc_quality        = 800,
 };
 
+#define	TMR_GBL		0x01
+#define	TMR_PRV		0x02
+#define	TMR_BOTH	(TMR_GBL | TMR_PRV)
+#define	TMR_NONE	0
+
+static struct ofw_compat_data compat_data[] = {
+	{"arm,mpcore-timers",		TMR_BOTH}, /* Non-standard, FreeBSD. */
+	{"arm,cortex-a9-global-timer",	TMR_GBL},
+	{"arm,cortex-a5-global-timer",	TMR_GBL},
+	{"arm,cortex-a9-twd-timer",	TMR_PRV},
+	{"arm,cortex-a5-twd-timer",	TMR_PRV},
+	{"arm,arm11mp-twd-timer",	TMR_PRV},
+	{NULL,				TMR_NONE}
+};
+
 /**
  *	arm_tmr_get_timecount - reads the timecount (global) timer
  *	@tc: pointer to arm_tmr_timecount struct
@@ -152,7 +156,10 @@ static struct timecounter arm_tmr_timeco
 static unsigned
 arm_tmr_get_timecount(struct timecounter *tc)
 {
-	return (tmr_gbl_read_4(GBL_TIMER_COUNT_LOW));
+	struct arm_tmr_softc *sc;
+
+	sc = tc->tc_priv;
+	return (tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW));
 }
 
 /**
@@ -172,11 +179,13 @@ arm_tmr_get_timecount(struct timecounter
 static int
 arm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
 {
+	struct arm_tmr_softc *sc;
 	uint32_t load, count;
 	uint32_t ctrl;
 
-	tmr_prv_write_4(PRV_TIMER_CTRL, 0);
-	tmr_prv_write_4(PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
+	sc = et->et_priv;
+	tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0);
+	tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
 
 	ctrl = PRV_TIMER_CTRL_IRQ_ENABLE | PRV_TIMER_CTRL_TIMER_ENABLE;
 
@@ -191,9 +200,9 @@ arm_tmr_start(struct eventtimer *et, sbi
 	else
 		count = load;
 
-	tmr_prv_write_4(PRV_TIMER_LOAD, load);
-	tmr_prv_write_4(PRV_TIMER_COUNT, count);
-	tmr_prv_write_4(PRV_TIMER_CTRL, ctrl);
+	tmr_prv_write_4(sc, PRV_TIMER_LOAD, load);
+	tmr_prv_write_4(sc, PRV_TIMER_COUNT, count);
+	tmr_prv_write_4(sc, PRV_TIMER_CTRL, ctrl);
 
 	return (0);
 }
@@ -210,8 +219,11 @@ arm_tmr_start(struct eventtimer *et, sbi
 static int
 arm_tmr_stop(struct eventtimer *et)
 {
-	tmr_prv_write_4(PRV_TIMER_CTRL, 0);
-	tmr_prv_write_4(PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
+	struct arm_tmr_softc *sc;
+
+	sc = et->et_priv;
+	tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0);
+	tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
 	return (0);
 }
 
@@ -227,13 +239,12 @@ arm_tmr_stop(struct eventtimer *et)
 static int
 arm_tmr_intr(void *arg)
 {
-	struct arm_tmr_softc *sc = (struct arm_tmr_softc *)arg;
-
-	tmr_prv_write_4(PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
+	struct arm_tmr_softc *sc;
 
+	sc = arg;
+	tmr_prv_write_4(sc, PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
 	if (sc->et.et_active)
 		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
-
 	return (FILTER_HANDLED);
 }
 
@@ -257,13 +268,98 @@ arm_tmr_probe(device_t dev)
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-	if (!ofw_bus_is_compatible(dev, "arm,mpcore-timers"))
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == TMR_NONE)
 		return (ENXIO);
 
 	device_set_desc(dev, "ARM MPCore Timers");
 	return (BUS_PROBE_DEFAULT);
 }
 
+static int
+attach_tc(struct arm_tmr_softc *sc)
+{
+	int rid;
+
+	if (arm_tmr_tc != NULL)
+		return (EBUSY);
+
+	rid = sc->memrid;
+	sc->gbl_mem = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->gbl_mem == NULL) {
+		device_printf(sc->dev, "could not allocate gbl mem resources\n");
+		return (ENXIO);
+	}
+	tmr_gbl_write_4(sc, GBL_TIMER_CTRL, 0x00000000);
+
+	arm_tmr_timecount.tc_frequency = sc->clkfreq;
+	arm_tmr_timecount.tc_priv = sc;
+	tc_init(&arm_tmr_timecount);
+	arm_tmr_tc = &arm_tmr_timecount;
+
+	tmr_gbl_write_4(sc, GBL_TIMER_CTRL, GBL_TIMER_CTRL_TIMER_ENABLE);
+
+	return (0);
+}
+
+static int
+attach_et(struct arm_tmr_softc *sc)
+{
+	void *ihl;
+	int irid, mrid;
+
+	if (arm_tmr_et != NULL)
+		return (EBUSY);
+
+	mrid = sc->memrid;
+	sc->prv_mem = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &mrid,
+	    RF_ACTIVE);
+	if (sc->prv_mem == NULL) {
+		device_printf(sc->dev, "could not allocate prv mem resources\n");
+		return (ENXIO);
+	}
+	tmr_prv_write_4(sc, PRV_TIMER_CTRL, 0x00000000);
+
+	irid = sc->irqrid;
+	sc->prv_irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irid, RF_ACTIVE);
+	if (sc->prv_irq == NULL) {
+		bus_release_resource(sc->dev, SYS_RES_MEMORY, mrid, sc->prv_mem);
+		device_printf(sc->dev, "could not allocate prv irq resources\n");
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(sc->dev, sc->prv_irq, INTR_TYPE_CLK, arm_tmr_intr,
+			NULL, sc, &ihl) != 0) {
+		bus_release_resource(sc->dev, SYS_RES_MEMORY, mrid, sc->prv_mem);
+		bus_release_resource(sc->dev, SYS_RES_IRQ, irid, sc->prv_irq);
+		device_printf(sc->dev, "unable to setup the et irq handler.\n");
+		return (ENXIO);
+	}
+
+	/*
+	 * Setup and register the eventtimer.  Most event timers set their min
+	 * and max period values to some value calculated from the clock
+	 * frequency.  We might not know yet what our runtime clock frequency
+	 * will be, so we just use some safe values.  A max of 2 seconds ensures
+	 * that even if our base clock frequency is 2GHz (meaning a 4GHz CPU),
+	 * we won't overflow our 32-bit timer count register.  A min of 20
+	 * nanoseconds is pretty much completely arbitrary.
+	 */
+	sc->et.et_name = "MPCore";
+	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
+	sc->et.et_quality = 1000;
+	sc->et.et_frequency = sc->clkfreq;
+	sc->et.et_min_period = 20 * SBT_1NS;
+	sc->et.et_max_period =  2 * SBT_1S;
+	sc->et.et_start = arm_tmr_start;
+	sc->et.et_stop = arm_tmr_stop;
+	sc->et.et_priv = sc;
+	et_register(&sc->et);
+	arm_tmr_et = &sc->et;
+
+	return (0);
+}
+
 /**
  *	arm_tmr_attach - attaches the timer to the simplebus
  *	@dev: new device
@@ -277,21 +373,19 @@ arm_tmr_probe(device_t dev)
 static int
 arm_tmr_attach(device_t dev)
 {
-	struct arm_tmr_softc *sc = device_get_softc(dev);
+	struct arm_tmr_softc *sc;
 	phandle_t node;
 	pcell_t clock;
-	void *ihl;
-	boolean_t fixed_freq;
+	int et_err, tc_err, tmrtype;
 
-	if (arm_tmr_sc)
-		return (ENXIO);
+	sc = device_get_softc(dev);
+	sc->dev = dev;
 
-	if (platform_arm_tmr_freq == ARM_TMR_FREQUENCY_VARIES) {
-		fixed_freq = false;
+	if (arm_tmr_freq_varies) {
+		sc->clkfreq = arm_tmr_freq;
 	} else {
-		fixed_freq = true;
-		if (platform_arm_tmr_freq != 0) {
-			sc->clkfreq = platform_arm_tmr_freq;
+		if (arm_tmr_freq != 0) {
+			sc->clkfreq = arm_tmr_freq;
 		} else {
 			/* Get the base clock frequency */
 			node = ofw_bus_get_node(dev);
@@ -305,66 +399,40 @@ arm_tmr_attach(device_t dev)
 		}
 	}
 
-	if (bus_alloc_resources(dev, arm_tmr_spec, sc->tmr_res)) {
-		device_printf(dev, "could not allocate resources\n");
-		return (ENXIO);
-	}
-
-	/* Global timer interface */
-	sc->gbl_bst = rman_get_bustag(sc->tmr_res[0]);
-	sc->gbl_bsh = rman_get_bushandle(sc->tmr_res[0]);
-
-	/* Private per-CPU timer interface */
-	sc->prv_bst = rman_get_bustag(sc->tmr_res[2]);
-	sc->prv_bsh = rman_get_bushandle(sc->tmr_res[2]);
-
-	arm_tmr_sc = sc;
-
-	/* Disable both timers to start off */
-	tmr_prv_write_4(PRV_TIMER_CTRL, 0x00000000);
-	tmr_gbl_write_4(GBL_TIMER_CTRL, 0x00000000);
-
-	if (bus_setup_intr(dev, sc->tmr_res[3], INTR_TYPE_CLK, arm_tmr_intr,
-			NULL, sc, &ihl) != 0) {
-		bus_release_resources(dev, arm_tmr_spec, sc->tmr_res);
-		device_printf(dev, "Unable to setup the clock irq handler.\n");
-		return (ENXIO);
-	}
+	tmrtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+	tc_err = ENXIO;
+	et_err = ENXIO;
 
 	/*
-	 * If the clock is fixed-frequency, setup and enable the global timer to
-	 * use as the timecounter.  If it's variable frequency it won't work as
-	 * a timecounter.  We also can't use it for DELAY(), so hopefully the
-	 * platform provides its own implementation.  If it doesn't, ours will
+	 * If we're handling the global timer and it is fixed-frequency, set it
+	 * up to use as a timecounter.  If it's variable frequency it won't work
+	 * as a timecounter.  We also can't use it for DELAY(), so hopefully the
+	 * platform provides its own implementation. If it doesn't, ours will
 	 * get used, but since the frequency isn't set, it will only use the
 	 * bogus loop counter.
 	 */
-	if (fixed_freq)  {
-		tmr_gbl_write_4(GBL_TIMER_CTRL, GBL_TIMER_CTRL_TIMER_ENABLE);
-		arm_tmr_timecount.tc_frequency = sc->clkfreq;
-		tc_init(&arm_tmr_timecount);
+	if (tmrtype & TMR_GBL) {
+		if (!arm_tmr_freq_varies)
+			tc_err = attach_tc(sc);
+		else if (bootverbose)
+			device_printf(sc->dev, 
+			    "not using variable-frequency device as timecounter");
+		sc->memrid++;
+		sc->irqrid++;
+	}
+
+	/* If we are handling the private timer, set it up as an eventtimer. */
+	if (tmrtype & TMR_PRV) {
+		et_err = attach_et(sc);
 	}
 
 	/*
-	 * Setup and register the eventtimer.  Most event timers set their min
-	 * and max period values to some value calculated from the clock
-	 * frequency.  We might not know yet what our runtime clock frequency
-	 * will be, so we just use some safe values.  A max of 2 seconds ensures
-	 * that even if our base clock frequency is 2GHz (meaning a 4GHz CPU),
-	 * we won't overflow our 32-bit timer count register.  A min of 20
-	 * nanoseconds is pretty much completely arbitrary.
+	 * If we didn't successfully set up a timecounter or eventtimer then we
+	 * didn't actually attach at all, return error.
 	 */
-	sc->et.et_name = "MPCore";
-	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
-	sc->et.et_quality = 1000;
-	sc->et.et_frequency = sc->clkfreq;
-	sc->et.et_min_period = 20 * SBT_1NS;
-	sc->et.et_max_period =  2 * SBT_1S;
-	sc->et.et_start = arm_tmr_start;
-	sc->et.et_stop = arm_tmr_stop;
-	sc->et.et_priv = sc;
-	et_register(&sc->et);
-
+	if (tc_err != 0 && et_err != 0) {
+		return (ENXIO);
+	}
 	return (0);
 }
 
@@ -384,6 +452,8 @@ static devclass_t arm_tmr_devclass;
 
 EARLY_DRIVER_MODULE(mp_tmr, simplebus, arm_tmr_driver, arm_tmr_devclass, 0, 0,
     BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(mp_tmr, ofwbus, arm_tmr_driver, arm_tmr_devclass, 0, 0,
+    BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
 
 /*
  * Handle a change in clock frequency.  The mpcore timer runs at half the CPU
@@ -404,10 +474,14 @@ void
 arm_tmr_change_frequency(uint64_t newfreq)
 {
 
-	if (arm_tmr_sc == NULL)
-		platform_arm_tmr_freq = newfreq;
-	else
-		et_change_frequency(&arm_tmr_sc->et, newfreq);
+	if (newfreq == ARM_TMR_FREQUENCY_VARIES) {
+		arm_tmr_freq_varies = true;
+		return;
+	}
+
+	arm_tmr_freq = newfreq;
+	if (arm_tmr_et != NULL)
+		et_change_frequency(arm_tmr_et, newfreq);
 }
 
 /**
@@ -424,12 +498,13 @@ arm_tmr_change_frequency(uint64_t newfre
 static void __used /* Must emit function code for the weak ref below. */
 arm_tmr_DELAY(int usec)
 {
+	struct arm_tmr_softc *sc;
 	int32_t counts_per_usec;
 	int32_t counts;
 	uint32_t first, last;
 
 	/* Check the timers are setup, if not just use a for loop for the meantime */
-	if (arm_tmr_sc == NULL || arm_tmr_timecount.tc_frequency == 0) {
+	if (arm_tmr_tc == NULL || arm_tmr_timecount.tc_frequency == 0) {
 		for (; usec > 0; usec--)
 			for (counts = 200; counts > 0; counts--)
 				cpufunc_nullop();	/* Prevent gcc from optimizing
@@ -438,6 +513,8 @@ arm_tmr_DELAY(int usec)
 		return;
 	}
 
+	sc = arm_tmr_tc->tc_priv;
+
 	/* Get the number of times to count */
 	counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1);
 
@@ -452,10 +529,10 @@ arm_tmr_DELAY(int usec)
 	else
 		counts = usec * counts_per_usec;
 
-	first = tmr_gbl_read_4(GBL_TIMER_COUNT_LOW);
+	first = tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW);
 
 	while (counts > 0) {
-		last = tmr_gbl_read_4(GBL_TIMER_COUNT_LOW);
+		last = tmr_gbl_read_4(sc, GBL_TIMER_COUNT_LOW);
 		counts -= (int32_t)(last - first);
 		first = last;
 	}



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