socsvn commit: r238005 - in soc2012/aleek/beaglexm-armv6/sys: arm/conf arm/ti/am37x boot/fdt/dts

aleek at FreeBSD.org aleek at FreeBSD.org
Wed Jun 20 15:37:57 UTC 2012


Author: aleek
Date: Wed Jun 20 15:37:54 2012
New Revision: 238005
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=238005

Log:
  Major refactoring to gptimer driver

Added:
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer_tc.c
Modified:
  soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x
  soc2012/aleek/beaglexm-armv6/sys/boot/fdt/dts/beagleboardxm.dts

Modified: soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM
==============================================================================
--- soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM	Wed Jun 20 14:47:39 2012	(r238004)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM	Wed Jun 20 15:37:54 2012	(r238005)
@@ -58,7 +58,7 @@
 options		WITNESS			#Enable checks to detect deadlocks and cycles
 options		WITNESS_SKIPSPIN	#Don't run witness on spinlocks for speed
 #options	DIAGNOSTIC
-options	DEBUG
+#options	DEBUG
 
 # NFS support
 #options	NFSCL

Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c
==============================================================================
--- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c	Wed Jun 20 14:47:39 2012	(r238004)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c	Wed Jun 20 15:37:54 2012	(r238005)
@@ -798,10 +798,7 @@
 static int
 omap3_gptimer_probe(device_t dev)
 {
-	struct	omap3_gptimer_softc *sc;
-	sc = (struct omap3_gptimer_softc *)device_get_softc(dev);
-	device_printf(dev, "PROBING...\n");
-	printf("gptimer: PROBING...\n");
+	//struct	omap3_gptimer_softc *sc = (struct omap3_gptimer_softc *)device_get_softc(dev);
 
 	if (ofw_bus_is_compatible(dev, "ti,omap3_gptimer")) {
 		device_set_desc(dev, "OMAP3 General Purpose Timer");
@@ -951,6 +948,6 @@
 };
 static devclass_t g_omap3_gptimer_devclass;
 
-DRIVER_MODULE(omap3_gptimer, omap, g_omap3_gptimer_driver, g_omap3_gptimer_devclass, 0, 0);
-MODULE_DEPEND(omap3_gptimer, ti_prcm, 1, 1, 1);
+DRIVER_MODULE(omap3_gptimer, simplebus, g_omap3_gptimer_driver, g_omap3_gptimer_devclass, 0, 0);
+///MODULE_DEPEND(omap3_gptimer, ti_prcm, 1, 1, 1);
 

Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h
==============================================================================
--- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h	Wed Jun 20 14:47:39 2012	(r238004)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h	Wed Jun 20 15:37:54 2012	(r238005)
@@ -74,11 +74,13 @@
 #define OMAP3_GPTIMER_ASSERT_LOCKED(_tmr)   mtx_assert(&(_tmr)->mtx, MA_OWNED);
 #define OMAP3_GPTIMER_ASSERT_UNLOCKED(_tmr) mtx_assert(&(_tmr)->mtx, MA_NOTOWNED);
 
-/*
- *	Data structure per Timer. 
+/**
+ *	Timer driver context, allocated and stored globally, this driver is not
+ *	intended to ever be unloaded (see g_omap3_gptimer_sc).
+ *
  */
-struct omap3_gptimer {
-	
+struct omap3_gptimer_softc {
+	device_t              sc_dev;
 	/* Flags indicating current and configured status */
 	unsigned int        flags;
 
@@ -90,7 +92,7 @@
 	    
     /* The memory resource for the timer register set */
 	struct resource*    mem_res;
-	
+	;
 	/* The IRQ resource and handle (if installed) for the timer */
 	struct resource*    irq_res;
 	void*               irq_h;
@@ -106,60 +108,47 @@
 
 	/* The source clock to use */
 	unsigned int        source;
-};
-
-
-/**
- *	Timer driver context, allocated and stored globally, this driver is not
- *	intended to ever be unloaded (see g_omap3_gptimer_sc).
- *
- */
-struct omap3_gptimer_softc {
-	device_t              sc_dev;
-	unsigned int          sc_num_timers;
-	struct omap3_gptimer   sc_timers[OMAP3_NUM_TIMERS];
-	struct omap3_gptimer  *sc_tick_timer;
 	
 };
 
 void
-omap3_gptimer_intr_filter_ack(unsigned int n);
+omap3_gptimer_intr_filter_ack(struct omap3_gptimer_softc *sc);
 
 static unsigned
 omap3_gptimer_tc_get_timecount(struct timecounter *tc);
 
 static inline uint32_t
-omap3_gptimer_readl(struct omap3_gptimer *timer, bus_size_t off);
+omap3_gptimer_readl(struct omap3_gptimer_softc *sc, bus_size_t off);
 
 
 static inline void
-omap3_gptimer_writel(struct omap3_gptimer *timer, bus_size_t off, uint32_t val);
+omap3_gptimer_writel(struct omap3_gptimer_softc *sc, bus_size_t off, uint32_t val);
 
 int
-omap3_gptimer_activate(unsigned int n, unsigned int flags, unsigned int time_us,
+omap3_gptimer_activate(struct omap3_gptimer_softc *sc, unsigned int flags, unsigned int time_us,
                     void (*callback)(void *data), void *data);
 
 int
-omap3_gptimer_start(unsigned int n);
+omap3_gptimer_start(struct omap3_gptimer_softc *sc);
 
 int
-omap3_gptimer_stop(unsigned int n);
+omap3_gptimer_stop(struct omap3_gptimer_softc *sc);
 
 int
-omap3_gptimer_get_freq(unsigned int n, uint32_t *freq);
+omap3_gptimer_get_freq(struct omap3_gptimer_softc *sc, uint32_t *freq);
 
 static int
 omap3_calibrate_delay_loop(struct timecounter *tc);
 
 int
-omap3_gptimer_set_intr_filter(unsigned int n, driver_filter_t filter);
+omap3_gptimer_set_intr_filter(struct omap3_gptimer_softc *sc, driver_filter_t filter);
 
 static void
 omap3_gptimer_intr(void *arg);
-
+#if 0
 static int
 omap3_timer_tick_intr(void *arg);
-
+#endif
 static int
 omap3_gptimer_probe(device_t dev);
 
@@ -167,7 +156,8 @@
 omap3_gptimer_attach(device_t dev);
 
 int
-omap3_gptimer_write_count(unsigned int n, uint32_t cnt);
+omap3_gptimer_write_count(struct omap3_gptimer_softc *sc, uint32_t cnt);
 
 int
-omap3_gptimer_read_count(unsigned int n, uint32_t *cnt);
+omap3_gptimer_read_count(struct omap3_gptimer_softc *sc, uint32_t *cnt);
+

Added: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer_tc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer_tc.c	Wed Jun 20 15:37:54 2012	(r238005)
@@ -0,0 +1,863 @@
+
+/*-
+ * Copyright (c) 2012 Aleksander Dutkowski <aleek at Freebsd.org>
+ * 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.
+ */
+
+/*
+ * Based on gptimer driver by Ben Gray
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/lock.h>
+#include <sys/gpio.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/am37x/am37x_gptimer.h>
+
+static struct omap3_gptimer_softc *g_omap3_gptimer_sc = NULL;
+
+static unsigned int delay_loops_per_us = 100;
+
+
+/**
+ * Timer for tick counting. This is used to measure time by CPU
+ */
+//static struct omap3_gptimer *omap3_gptimer_tc_tmr = NULL;
+
+/**
+ * Struct used by tc_init(), to init the timecounter
+ */
+static struct timecounter omap3_gptimer_tc = {
+	/* Name of the timecounter. */
+	.tc_name           = "OMAP3 Timecouter",
+	/*
+	 * This function reads the counter.  It is not required to
+	 * mask any unimplemented bits out, as long as they are
+	 * constant.
+	 */
+	.tc_get_timecount  = omap3_gptimer_tc_get_timecount,
+	.tc_poll_pps       = NULL,
+	/* This mask should mask off any unimplemented bits. */
+	.tc_counter_mask   = ~0u,
+	/* Frequency of the counter in Hz. */
+	.tc_frequency      = 0,
+	/*
+	 * Used to determine if this timecounter is better than
+	 * another timecounter higher means better.  Negative
+	 * means "only use at explicit request".
+	 */
+	.tc_quality        = 1000,
+};
+
+#define __omap3_delay(i)                                     \
+	do {                                                     \
+		unsigned int cnt = (i);                              \
+		__asm __volatile("1:  subs   %0, %0, 1\n"            \
+		                 "    bne    1b\n"                   \
+		                 : "+r" (cnt) : : "cc");             \
+	} while(0)
+
+/**
+ *	omap3_calibrate_delay_loop - uses the setup timecounter to configure delay
+ *
+ *	This is not very scientfic, basically just use the timecount to measure the
+ *	time to do 1000 delay loops (for loop with 1024 loops).
+ *
+ *
+ */
+static int
+omap3_calibrate_delay_loop(struct timecounter *tc)
+{
+	u_int oldirqstate;
+	unsigned int start, end;
+	uint64_t nanosecs;
+	
+	/* Disable interrupts to ensure they don't mess up the calculation */
+	oldirqstate = disable_interrupts(I32_bit);
+
+	start = omap3_gptimer_tc_get_timecount(tc);
+	//__omap3_delay(10240);
+		for (int usec=10240; usec > 0; usec--)
+			for (int32_t counts = 200; counts > 0; counts--)
+				/* Prevent gcc from optimizing  out the loop */
+				cpufunc_nullop();
+	
+	end = omap3_gptimer_tc_get_timecount(tc);
+
+	restore_interrupts(oldirqstate);
+
+	/* Calculate the number of loops in 1us */
+	nanosecs = ((uint64_t)(end - start) * 1000000000ULL) / tc->tc_frequency;
+	delay_loops_per_us = (unsigned int)((uint64_t)(10240 * 1000) / nanosecs);
+
+	printf("OMAP3: delay loop calibrated to %u cycles\n", delay_loops_per_us);
+	
+	return (0);
+}
+
+
+static unsigned
+omap3_gptimer_tc_get_timecount(struct timecounter *tc)
+{
+	uint32_t count;
+	omap3_gptimer_read_count(g_omap3_gptimer_sc, &count);
+	return(count);
+
+}
+
+/**
+ *	omap3_gptimer_read_count - reads the current timer value
+ *	@n: the number of the timer (first timer is number 1)
+ *	@cnt:
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_read_count(struct omap3_gptimer_softc *sc, uint32_t *cnt)
+{
+	int ret;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+		
+	/* Get a pointer to the individual sc struct */
+	
+	OMAP3_GPTIMER_LOCK(sc);
+	
+	if (!(sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG)) {
+		ret = EINVAL;
+	} else {
+		*cnt = omap3_gptimer_readl(sc, OMAP3_GPT_TCRR);
+		ret = 0;
+	}
+
+	OMAP3_GPTIMER_UNLOCK(sc);
+	
+	return (ret);
+}
+
+
+/**
+ *	omap3_gptimer_write_count - writes a value into the current count
+ *	@n: the number of the timer (first timer is number 1)
+ *	@cnt: the value to put in the count register
+ *
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_write_count(struct omap3_gptimer_softc *sc, uint32_t cnt)
+{
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	if (!(sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP3_GPTIMER_LOCK(sc);
+	
+	omap3_gptimer_writel(sc, OMAP3_GPT_TCRR, cnt);
+
+	OMAP3_GPTIMER_UNLOCK(sc);
+	
+	return (0);
+}
+
+
+/**
+ *	omap3_gptimer_readl - reads a 32-bit value from one of the timer registers
+ *	@timer: Timer device context
+ *	@off: The offset of a register from the timer register address range
+ *
+ *
+ *	RETURNS:
+ *	32-bit value read from the register.
+ */
+static inline uint32_t
+omap3_gptimer_readl(struct omap3_gptimer_softc *sc, bus_size_t off)
+{
+	return (bus_read_4(sc->mem_res, off));
+}
+
+/**
+ *	omap3_gptimer_writel - writes a 32-bit value to one of the timer registers
+ *	@timer: Timer device context
+ *	@off: The offset of a register from the timer register address range
+ *	@val: The value to write into the register
+ *
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static inline void
+omap3_gptimer_writel(struct omap3_gptimer_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->mem_res, off, val);
+}
+
+/**
+ *	omap_gptimer_get_freq - gets the frequency of an activated timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	@freq: unpon return will contain the current freq
+ *
+ *	The timer must be activated, if not this function will return EINVAL.
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_get_freq(struct omap3_gptimer_softc *sc, uint32_t *freq)
+{
+	unsigned int src_freq;
+	unsigned int tmr_freq;
+	unsigned int prescaler;
+	uint32_t tclr, tldr;
+	int rc;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if (freq == NULL)
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	if (!(sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	/* We get the frequency by first reading the source frequency */
+	if ((rc = ti_prcm_clk_get_source_freq(sc->source, &src_freq)) != 0)
+		return (rc);
+
+
+	OMAP3_GPTIMER_LOCK(sc);
+	
+	/* Determine if the pre-scalar is enabled and if so the prescaler value */
+	tclr = omap3_gptimer_readl(sc, OMAP3_GPT_TCLR);
+	if (tclr & TCLR_PRE)
+		prescaler = 1UL << (((tclr & TCLR_PTV_MASK) >> 2) + 1);
+	else
+		prescaler = 1;
+
+	/* Get the reload count */
+	tldr = omap3_gptimer_readl(sc, OMAP3_GPT_TLDR);
+	
+	OMAP3_GPTIMER_UNLOCK(sc);
+	
+	
+	/* Calculate the tick freq */
+	tmr_freq = (src_freq / prescaler);
+
+	/* If auto-reload mode is set and the reload count is not zero then the
+	 * frequency is the period between overflows.
+	 */
+	if ((tclr & TCLR_AR) && (tldr != 0x00000000)) {
+		tmr_freq /= ((0xffffffff - tldr) + 1);
+	}
+	
+	
+	if (freq != NULL)
+		*freq = tmr_freq;
+	
+	return (0);
+}
+
+
+
+/**
+ *	omap3_gptimer_activate - configures the timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	@flags: defines the type of timer to turn on
+ *	@time_ns: the period of the timer in nanoseconds
+ *	@callback: if defined this function will be called when the timer overflows
+ *	@data: data value to pass to the callback
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_activate(struct omap3_gptimer_softc *sc, unsigned int flags, unsigned int time_us,
+                    void (*callback)(void *data), void *data)
+{
+	uint32_t val;
+	uint64_t tickcount;
+	unsigned int freq;
+	uint64_t freq64;
+	uint32_t prescaler;
+	uint32_t startcount;
+	
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	
+	/* Sanity check the timer is availabe and not activated */
+	if (!(sc->flags & OMAP3_GPTIMER_AVAILABLE_FLAG)) {
+		device_printf(sc->sc_dev, "Error: timer not available\n");
+		return (EINVAL);
+	}
+	if (sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG) {
+		device_printf(sc->sc_dev, "Error: timer already activated\n");
+		return (EINVAL);
+	}
+
+	/* Set up system clock information */
+	if (ti_prcm_clk_valid(sc->source) != 0) {
+		device_printf(sc->sc_dev, "Error: failed to find source clock\n");
+		return (EINVAL);
+	}
+
+	OMAP3_GPTIMER_LOCK(sc);
+
+	/* Enable the functional and interface clock */
+	if (flags & OMAP3_GPTIMER_32KCLK_FLAG)
+		ti_prcm_clk_set_source(sc->source, F32KHZ_CLK);
+	else
+		ti_prcm_clk_set_source(sc->source, SYSCLK_CLK);
+	
+	ti_prcm_clk_enable(sc->source);
+
+
+	/* Store the flags in the timer context */
+	sc->flags &=  0xFF000000;
+	sc->flags |= (0x00FFFFFF & flags);
+
+
+	/* Reset the timer and poll on the reset complete flag */
+	if (sc->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		omap3_gptimer_writel(sc, OMAP3_GPT_TIOCP_CFG, 0x2);
+		/* TODO: add a timeout */
+		while ((omap3_gptimer_readl(sc, OMAP3_GPT_TISTAT) & 0x01) == 0x00)
+			continue;
+
+		/* Clear the interrupt status */
+		omap3_gptimer_writel(sc, OMAP3_GPT_TISR, TCAR | OVF | MAT);
+	}
+
+	/* If the user supplied a zero value we set a free running timer */
+	if (time_us == 0) {
+		/* Set the initial value and roll over value to 0 */
+		startcount = 0x00000000;
+	} else {
+		/* We need to calculate the number of timer ticks in either the reload
+		 * value (for periodic timers) or the overflow
+		 */
+		ti_prcm_clk_get_source_freq(sc->source, &freq);
+		freq64 = freq;
+		
+		/* Calculate the period of the timer, 64 bit calculations used to
+		 * prevent rollover.
+		 */
+		tickcount = (freq64 * (uint64_t)time_us) / 1000000;
+
+		/* Must have a count of at least 1 */
+		if (tickcount == 0)
+			tickcount = 1;
+
+		/* If the number is too large then see if by enabling the prescaler it
+		 * will fit, otherwise just set the max count we can do.
+		 */
+		if (tickcount > 0xFFFFFFFFULL) {
+		
+			/* Try and find a prescaler that will match */
+			for (prescaler = 0; prescaler < 7; prescaler++) {
+				if (tickcount < (0x1ULL << (32 + prescaler))) {
+					break;
+				}
+			}
+			
+			/* Adjust the count and apply the prescaler */
+			tickcount >>= (prescaler + 1);
+
+			val = omap3_gptimer_readl(sc, OMAP3_GPT_TCLR);
+			val &= ~TCLR_PTV_MASK;
+			val |= TCLR_PRE | (prescaler << 2);
+			omap3_gptimer_writel(sc, OMAP3_GPT_TCLR, val);
+		}
+	
+		/* Calculate the start value */
+		startcount = 0xFFFFFFFFUL - (uint32_t)(tickcount & 0xFFFFFFFFUL);
+
+		printf("[BRG] %s, %d : freq64=%llu : tickcount=%llu : startcount=%u : time_us=%u\n",
+       __func__, __LINE__, freq64, tickcount, startcount, time_us);
+	}
+	
+	/* Load the start value into the count register */
+	omap3_gptimer_writel(sc, OMAP3_GPT_TCRR, startcount);
+
+	/* Enable autoload mode if configuring a periodic timer or system tick
+	 * timer. Also set the reload count to match the period tick count.
+	 */
+	if (flags & OMAP3_GPTIMER_PERIODIC_FLAG) {
+		/* Enable auto reload */
+		val = omap3_gptimer_readl(sc, OMAP3_GPT_TCLR);
+		val |= TCLR_AR;
+		omap3_gptimer_writel(sc, OMAP3_GPT_TCLR, val);
+		
+		/* Set the reload value */
+		omap3_gptimer_writel(sc, OMAP3_GPT_TLDR, startcount);
+	}
+
+	/* If a callback function has been supplied setup a overflow interrupt */
+	if (callback != NULL) {
+	
+		/* Save the callback function and the data for it */
+		sc->callback = callback;
+		sc->callback_data = data;
+		
+		/* Activate the interrupt */
+		if (bus_setup_intr(sc->sc_dev, sc->irq_res, 
+		                   INTR_TYPE_MISC | INTR_MPSAFE, NULL, omap3_gptimer_intr,
+						   (void*)sc, &sc->irq_h)) {
+			device_printf(sc->sc_dev, "Error: failed to activate interrupt\n");
+		}
+
+		/* Enable the overflow interrupts. */
+		if (sc->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+			val = omap3_gptimer_readl(sc, OMAP3_GPT_TIER);
+			val |= OVF;
+			omap3_gptimer_writel(sc, OMAP3_GPT_TIER, val);
+		}
+	}
+
+	/* Finally set the activated flag */
+	sc->flags |= OMAP3_GPTIMER_ACTIVATED_FLAG;
+
+	OMAP3_GPTIMER_UNLOCK(sc);
+	
+	printf("[BRG] %s, %d\n", __func__, __LINE__);
+
+	return (0);
+}
+
+/**
+ *	omap3_gptimer_start - starts a one-shot or periodic timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_start(struct omap3_gptimer_softc *sc)
+{
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if (!(sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP3_GPTIMER_LOCK(sc);
+
+	val = omap3_gptimer_readl(sc, OMAP3_GPT_TCLR);
+	val |= TCLR_ST;
+	omap3_gptimer_writel(sc, OMAP3_GPT_TCLR, val);
+
+	OMAP3_GPTIMER_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	omap3_gptimer_stop - stops a one-shot or periodic timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_stop(struct omap3_gptimer_softc *sc)
+{
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if (!(sc->flags & OMAP3_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP3_GPTIMER_LOCK(sc);
+	
+	val = omap3_gptimer_readl(sc, OMAP3_GPT_TCLR);
+	val &= ~TCLR_ST;
+	omap3_gptimer_writel(sc, OMAP3_GPT_TCLR, val);
+
+	OMAP3_GPTIMER_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	omap3_gptimer_set_intr_filter - sets a filter 
+ *	@n: the number of the timer (first timer is number 1)
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap3_gptimer_set_intr_filter(struct omap3_gptimer_softc *sc, driver_filter_t filter)
+{
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	OMAP3_GPTIMER_LOCK(sc);
+
+	/* If a callback is already installed this won't work */
+	if (sc->callback != NULL) {
+		OMAP3_GPTIMER_UNLOCK(sc);
+		return(EINVAL);
+	}
+	
+	/* Sanity check the timer is already activated and periodic type */
+	if ((sc->flags & (OMAP3_GPTIMER_ACTIVATED_FLAG | OMAP3_GPTIMER_PERIODIC_FLAG))
+	    != (OMAP3_GPTIMER_ACTIVATED_FLAG | OMAP3_GPTIMER_PERIODIC_FLAG)) {
+		OMAP3_GPTIMER_UNLOCK(sc);
+		return(EINVAL);
+	}
+	
+	
+	/* Attempt to activate the interrupt for the tick */
+	if (bus_setup_intr(sc->sc_dev, sc->irq_res, INTR_TYPE_CLK,
+	                   filter, NULL, NULL, &sc->irq_h)) {
+		device_printf(sc->sc_dev, "Error: failed to activate interrupt\n");
+		OMAP3_GPTIMER_UNLOCK(sc);
+		return(EINVAL);
+	}
+	
+	
+	/* Enable the overflow interrupts */
+	if (sc->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		val = omap3_gptimer_readl(sc, OMAP3_GPT_TIER);
+		val |= OVF;
+		omap3_gptimer_writel(sc, OMAP3_GPT_TIER, val);
+	}
+	
+	OMAP3_GPTIMER_UNLOCK(sc);
+	
+	return(0);
+}
+
+/**
+ *	omap3_gptimer_intr_filter_ack - acknowledges a timer interrupt
+ *	@n: the number of the timer (first timer is number 1)
+ *
+ *	This function should only be called from filter interrupt handler installed
+ *	by calling the omap_gptimer_set_intr_filter() function.
+ *
+ *	RETURNS:
+ *	Nothing
+ */
+void
+omap3_gptimer_intr_filter_ack(struct omap3_gptimer_softc *sc)
+{
+	uint32_t stat;
+
+	OMAP3_GPTIMER_LOCK(sc);
+	
+	/* Read the interrupt status flag and clear it */
+	/* Read the status and it with the enable flag */
+	stat =  omap3_gptimer_readl(sc, OMAP3_GPT_TISR);
+	stat &= omap3_gptimer_readl(sc, OMAP3_GPT_TIER);
+		
+	/* Clear the status flag */
+	omap3_gptimer_writel(sc, OMAP3_GPT_TISR, stat);
+	OMAP3_GPTIMER_UNLOCK(sc);
+}
+
+
+
+/**
+ *	cpu_initclocks - function called by the system in init the tick clock/timer
+ *
+ *	This is where both the timercount and system ticks timer are started.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+void
+cpu_initclocks(void)
+{
+	cpu_initclocks_bsp();
+}
+
+/**
+ *	DELAY - Delay for at least N microseconds.
+ *	@n: number of microseconds to delay by
+ *
+ *	This function is called all over the kernel and is suppose to provide a
+ *	consistent delay.  It is a busy loop and blocks polling a timer when called.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+void
+DELAY(int usec)
+{
+	int32_t counts;
+	//uint32_t first, last;
+
+	if (g_omap3_gptimer_sc == NULL) {
+		for (; usec > 0; usec--)
+			for (counts = 200; counts > 0; counts--)
+				/* Prevent gcc from optimizing  out the loop */
+				cpufunc_nullop();
+		return;
+	}
+}
+
+static void
+omap3_gptimer_intr(void *arg)
+{
+	struct omap3_gptimer_softc *sc = (struct omap3_gptimer_softc *)arg;
+	void (*callback)(void *data);
+	void*    callback_data;
+	uint32_t stat = 0x0000;
+
+	OMAP3_GPTIMER_LOCK(sc);
+
+	/* Read the interrupt status flag and clear it */
+	if (sc->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		
+		/* Read the status and it with the enable flag */
+		stat =  omap3_gptimer_readl(sc, OMAP3_GPT_TISR);
+		stat &= omap3_gptimer_readl(sc, OMAP3_GPT_TIER);
+		
+		/* Clear the status flag */
+		omap3_gptimer_writel(sc, OMAP3_GPT_TISR, stat);
+	}
+	
+	/* Store the callback details before releasing the lock */
+	callback = sc->callback;
+	callback_data = sc->callback_data;
+	
+	OMAP3_GPTIMER_UNLOCK(sc);
+
+	/* Check if an actual overflow interrupt */
+	if ((stat & OVF) && (callback != NULL))
+		callback(sc->callback_data);
+}
+
+/**
+ *	omap3_clk_intr - interrupt handler for the tick timer (GPTIMER10)
+ *	@arg: the trapframe, needed for the hardclock system function.
+ *
+ *	This interrupt is triggered every hz times a second.  It's role is basically
+ *	to just clear the interrupt status and set it up for triggering again, plus
+ *	tell the system a tick timer has gone off by calling the hardclock()
+ *	function from the kernel API.
+ *
+ *	RETURNS:
+ *	Always returns FILTER_HANDLED. 
+ */
+#if 0
+static int
+omap3_timer_tick_intr(void *arg)
+{
+	struct trapframe *frame = arg;
+#if defined(OMAP3_HEARTBEAT_GPIO)
+	static int heartbeat_cnt = 0;
+#endif
+
+	/* Acknowledge the interrupt */
+	omap3_gptimer_intr_filter_ack(TICKTIMER_GPTIMER);
+
+	/* Heartbeat */
+#if defined(OMAP3_HEARTBEAT_GPIO)
+	if (heartbeat_cnt++ >= (hz/2)) {
+		//printf("[BRG] ** tick **\n");
+		gpio_pin_toggle(OMAP3_HEARTBEAT_GPIO);
+		heartbeat_cnt = 0;
+	}
+#endif
+
+	/* Do what we came here for */
+	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+	
+	/* Indicate we've handed the interrupt */
+	return (FILTER_HANDLED);
+}
+#endif
+
+
+static int
+omap3_gptimer_probe(device_t dev)
+{
+	//struct	omap3_gptimer_softc *sc = (struct omap3_gptimer_softc *)device_get_softc(dev);
+
+	if (ofw_bus_is_compatible(dev, "ti,omap3_gptimer_tc")) {
+		device_set_desc(dev, "OMAP3 General Purpose Timer - Tick Counter");
+		return(BUS_PROBE_DEFAULT);
+	}
+
+	return (ENXIO);
+}
+
+static int
+omap3_gptimer_attach(device_t dev)
+{
+	struct omap3_gptimer_softc *sc = device_get_softc(dev);
+	char name[32];
+	int rid=0; // resource id for device, unique
+	uint32_t rev;
+	u_int oldirqstate;
+	unsigned int timer_freq;
+
+	device_printf( dev, "Attaching the device..." );
+
+
+	// Setup the basics
+	//sc->sc_dev = dev;
+	//sc->sc_tick_timer = NULL;
+
+	/* First try and get the register addresses, if this fails we assume
+	 * there are no more timers.
+	 */
+	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if(sc->mem_res == NULL)
+	{
+		device_printf(dev, "could not allocate resources\n" );
+		return (ENXIO);
+	}
+
+	/* Next try and get the interrupt resource, this is not fatal */
+	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); //@TODO XXX Why shareable?
+
+	/* Mutex to protect the shared data structures */
+	snprintf(name, 32, "omap_gptimer_tc");
+	mtx_init(&sc->mtx, device_get_nameunit(dev), name, MTX_SPIN);
+
+	// I decided to delete support for OMAP4 timers from the original code - aleek
+	rev = omap3_gptimer_readl(sc, OMAP3_GPT_TIDR);
+	switch (rev) {
+		case 0x00000013:  /* OMAP3 without 1ms generation */
+		case 0x00000015:
+		case 0x00000021:  /* OMAP3 with 1ms generation */
+			sc->profile = OMAP_GPTIMER_PROFILE_OMAP3;
+			break;
+			break;
+		default:
+			sc->profile = OMAP_GPTIMER_PROFILE_UNKNOWN;
+			break;
+	}
+		
+	if (sc->profile == OMAP_GPTIMER_PROFILE_UNKNOWN) {
+		device_printf(dev, "Error: failed to determine the type of "
+		              "GPTIMER_tc, ignoring timer (rev: 0x%08x)\n",
+		              rev);
+		return (ENXIO);
+	}
+	/* Set the clock source for the timer, this is just a one to one
+	 * mapping of the clock id to timer, i.e. n=0 => GPTIMER1_CLK.
+	 */
+	sc->source = GPTIMER10_CLK; // @TODO XXX fix this - the timer number shouldn't be hardcoded
+
+	/* Finally mark the timer as available */
+	sc->flags = OMAP3_GPTIMER_AVAILABLE_FLAG;
+
+	/* setup GPTIMER10 for system ticks, and GPTIMER11 for general purpose counter */
+	oldirqstate = disable_interrupts(I32_bit);
+
+	/* Setup another timer to be the timecounter */
+	if (omap3_gptimer_activate(sc, OMAP3_GPTIMER_PERIODIC_FLAG, 0, NULL, NULL)) {
+		device_printf(dev, "Error: failed to activate system tick timer\n");
+	} else if (omap3_gptimer_start(sc)) {
+		device_printf(dev, "Error: failed to start system tick timer\n");
+	}
+
+	/* Save the system clock speed */
+	omap3_gptimer_get_freq(sc, &timer_freq);
+	omap3_gptimer_tc.tc_frequency = timer_freq;
+	
+	/* Setup the time counter */
+	tc_init(&omap3_gptimer_tc);
+
+	/* Calibrate the delay loop */
+	omap3_calibrate_delay_loop(&omap3_gptimer_tc);
+
+	/* Restore interrupt state */
+	restore_interrupts(oldirqstate);
+
+	g_omap3_gptimer_sc = sc;
+
+	return 0;
+}
+
+static device_method_t g_omap3_gptimer_methods[] = {
+	DEVMETHOD(device_probe, omap3_gptimer_probe),
+	DEVMETHOD(device_attach, omap3_gptimer_attach),
+	{0, 0},
+};

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-soc-all mailing list