Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 01 Jun 2012 21:06:40 +0000
From:      aleek@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r236899 - in soc2012/aleek/beaglexm-armv6/sys: arm/conf arm/ti arm/ti/am37x arm/ti/am37xx arm/ti/omap3 conf
Message-ID:  <20120601210640.52334106566C@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: aleek
Date: Fri Jun  1 21:06:39 2012
New Revision: 236899
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=236899

Log:
  added gptimer and timer for soc

Added:
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/
  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/am37x_timer.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.beagleboardxm
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/std.am37x
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/std.beagleboardxm
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/files.omap3
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/std.omap3
Deleted:
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37xx/
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/files.omap35xx
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/omap35xx.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/omap3_intr.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/omap3_prcm_clks.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/omap3_scm_padconf.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/std.omap35xx
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/std.omap37xx
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/uart_bus_omap3.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/uart_cpu_omap3.c
Modified:
  soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/omap3/omap3_timer.c
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/ti_cpuid.h
  soc2012/aleek/beaglexm-armv6/sys/arm/ti/ti_machdep.c
  soc2012/aleek/beaglexm-armv6/sys/conf/options.arm

Modified: soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM
==============================================================================
--- soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM	Fri Jun  1 19:26:38 2012	(r236898)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/conf/BEAGLEBOARD-XM	Fri Jun  1 21:06:39 2012	(r236899)
@@ -26,7 +26,7 @@
 
 #hints       "BEAGLEBOARD.hints"
 
-include     "../ti/omap3/std.omap35xx"
+include     "../ti/am37x/std.beagleboardxm"
 
 #To statically compile in device wiring instead of /boot/device.hints
 makeoptions	MODULES_OVERRIDE=""
@@ -37,7 +37,7 @@
 options 	HZ=100
 
 options 	SCHED_4BSD		#4BSD scheduler
-options 	INET			#InterNETworking
+#options 	INET			#InterNETworking
 #options 	INET6			#IPv6 communications protocols
 options 	FFS			#Berkeley Fast Filesystem
 options 	SOFTUPDATES		#Enable FFS soft updates support
@@ -72,14 +72,14 @@
 device		loop
 #device		ether
 #device		mii
-device		smc
-device		smcphy
-device		uart
-device		uart_ns8250
+#device		smc
+#device		smcphy
+#device		uart
+#device		uart_ns8250
 
 device		pty
 
-device		gpio
+#device		gpio
 
 # Debugging for use in -current
 options		VERBOSE_SYSINIT		#Enable verbose sysinit messages
@@ -114,3 +114,7 @@
 #device		axe			# ASIX Electronics USB Ethernet
 
 
+# Flattened Device Tree
+#options         FDT
+#options         FDT_DTB_STATIC
+#makeoptions     FDT_DTS_FILE=beaglebone.dts

Added: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c	Fri Jun  1 21:06:39 2012	(r236899)
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray@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 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 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/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/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 <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/am37x/am37x_gptimer.h>
+
+
+#define MAX_NUM_TIMERS               12
+
+#define OMAP_GPTIMER_PROFILE_UNKNOWN -1
+#define OMAP_GPTIMER_PROFILE_OMAP3   3
+#define OMAP_GPTIMER_PROFILE_OMAP4   4
+
+
+/* Standard registers for OMAP3 and some OMAP4 devices */
+#define OMAP_GPT_TIDR           0x0000
+#define OMAP_GPT_TIOCP_CFG      0x0010
+#define OMAP_GPT_TISTAT         0x0014
+#define OMAP_GPT_TISR           0x0018
+#define OMAP_GPT_TIER           0x001C
+#define OMAP_GPT_TWER           0x0020
+#define OMAP_GPT_TCLR           0x0024
+#define OMAP_GPT_TCRR           0x0028
+#define OMAP_GPT_TLDR           0x002C
+#define OMAP_GPT_TTGR           0x0030
+#define OMAP_GPT_TWPS           0x0034
+#define OMAP_GPT_TMAR           0x0038
+#define OMAP_GPT_TCAR1          0x003C
+#define OMAP_GPT_TSICR          0x0040
+#define OMAP_GPT_TCAR2          0x0044
+#define OMAP_GPT_TPIR           0x0048
+#define OMAP_GPT_TNIR           0x004C
+#define OMAP_GPT_TCVR           0x0050
+#define OMAP_GPT_TOCR           0x0054
+#define OMAP_GPT_TOWR           0x0058
+
+/* Register set for OMAP4 timers 3,4,5,6,7,8,9 & 11 */
+#define OMAP4_GPT_IRQSTATUS_RAW 0x0024
+#define OMAP4_GPT_IRQSTATUS     0x0028
+#define OMAP4_GPT_IRQENABLE_SET 0x002C
+#define OMAP4_GPT_IRQENABLE_CLR 0x0030
+#define OMAP4_GPT_IRQWAKEEN     0x0034
+#define OMAP4_GPT_TCLR          0x0038
+#define OMAP4_GPT_TCRR          0x003C
+#define OMAP4_GPT_TLDR          0x0040
+#define OMAP4_GPT_TTGR          0x0044
+#define OMAP4_GPT_TWPS          0x0048
+#define OMAP4_GPT_TMAR          0x004C
+#define OMAP4_GPT_TCAR1         0x0050
+#define OMAP4_GPT_TSICR         0x0054
+#define OMAP4_GPT_TCAR2         0x0058
+
+
+
+/* GPT_TCLR Register bit fields */
+#define TCLR_GPO_CFG            (0x1 << 14)
+#define TCLR_CAPT_MODE          (0x1 << 13)
+#define TCLR_PT                 (0x1 << 12)
+#define TCLR_TRG_MASK           (0x3 << 10)
+#define TCLR_TCM_MASK           (0x3 << 8)
+#define TCLR_SCPWM              (0x1 << 7)
+#define TCLR_CE                 (0x1 << 6)
+#define TCLR_PRE                (0x1 << 5)
+#define TCLR_PTV_MASK           (0x7 << 2)
+#define TCLR_AR                 (0x1 << 1)
+#define TCLR_ST                 (0x1 << 0)
+
+/* The interrupt/status bits used in the timer registers. */
+#define TCAR                    (0x1 << 2)
+#define OVF                     (0x1 << 1)
+#define MAT                     (0x1 << 0)
+
+
+
+
+struct omap_gptimer_dev {
+	/* The profile of the timer */
+	int          profile;
+	
+	/* The source clock to use */
+	unsigned int source;
+	
+	/* The register offsets of these key registers */
+	uint32_t     tclr;
+	uint32_t     tcrr;
+	uint32_t     tldr;
+};
+
+
+
+/**
+ *	Data structure per Timer. 
+ *
+ *
+ */
+struct omap_gptimer {
+	
+	/* Flags indicating current and configured status */
+	unsigned int        flags;
+
+#define OMAP_GPTIMER_AVAILABLE_FLAG      0x01000000
+#define OMAP_GPTIMER_ACTIVATED_FLAG      0x02000000
+	
+    /* Lock taken when configuring the registers */
+	struct mtx          mtx;
+	    
+    /* 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;
+
+	/* Callback function used when an interrupt is tripped on the given channel */
+	void (*callback)(void *data);
+	
+	/* Callback data passed in the callback ... duh */
+	void*               callback_data;
+	
+	/* The profile of the timer, basically defines the register layout */
+	unsigned int        profile;
+
+	/* The source clock to use */
+	unsigned int        source;
+
+	/* Stores the address of the registers, needed because different version
+	 * of the timer have different register offsets.
+	 */
+	uint32_t            tclr;
+	uint32_t            tcrr;
+	uint32_t            tldr;
+	
+};
+
+
+/**
+ *	Macros for driver mutex locking
+ */
+#define OMAP_GPTIMER_LOCK(_tmr)            mtx_lock(&(_tmr)->mtx)
+#define	OMAP_GPTIMER_UNLOCK(_tmr)          mtx_unlock(&(_tmr)->mtx)
+#define OMAP_GPTIMER_ASSERT_LOCKED(_tmr)   mtx_assert(&(_tmr)->mtx, MA_OWNED);
+#define OMAP_GPTIMER_ASSERT_UNLOCKED(_tmr) mtx_assert(&(_tmr)->mtx, MA_NOTOWNED);
+
+
+
+/**
+ *	Timer driver context, allocated and stored globally, this driver is not
+ *	intended to ever be unloaded (see g_omap_gptimer_sc).
+ *
+ */
+struct omap_gptimer_softc {
+	device_t              sc_dev;
+	unsigned int          sc_num_timers;
+	struct omap_gptimer   sc_timers[MAX_NUM_TIMERS];
+	struct omap_gptimer  *sc_tick_timer;
+	
+};
+
+static struct omap_gptimer_softc *g_omap_gptimer_sc = NULL;
+
+
+
+
+
+
+/**
+ *	omap_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
+omap_gptimer_readl(struct omap_gptimer *timer, bus_size_t off)
+{
+	return (bus_read_4(timer->mem_res, off));
+}
+
+/**
+ *	omap_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
+omap_gptimer_writel(struct omap_gptimer *timer, bus_size_t off, uint32_t val)
+{
+	bus_write_4(timer->mem_res, off, val);
+}
+
+
+
+
+/**
+ *	omap_gptimer_intr - interrupt handler for the timers
+ *	@arg: pointer to the timer structure
+ *
+ *	Interrupt handler for all the timer interrupts, invovkes the callback
+ *	function supplied when the timer was activated.
+ *
+ *
+ *	RETURNS:
+ *	Nothing
+ */
+static void
+omap_gptimer_intr(void *arg)
+{
+	struct omap_gptimer *timer = (struct omap_gptimer *) arg;
+	void (*callback)(void *data);
+	void*    callback_data;
+	uint32_t stat = 0x0000;
+
+	OMAP_GPTIMER_LOCK(timer);
+
+	/* Read the interrupt status flag and clear it */
+	if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		
+		/* Read the status and it with the enable flag */
+		stat =  omap_gptimer_readl(timer, OMAP_GPT_TISR);
+		stat &= omap_gptimer_readl(timer, OMAP_GPT_TIER);
+		
+		/* Clear the status flag */
+		omap_gptimer_writel(timer, OMAP_GPT_TISR, stat);
+	}
+	else if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP4) {
+		
+		/* Read the status */
+		stat = omap_gptimer_readl(timer, OMAP4_GPT_IRQSTATUS);
+		
+		/* Clear the status flag */
+		omap_gptimer_writel(timer, OMAP4_GPT_IRQENABLE_CLR, stat);
+	}
+	
+	/* Store the callback details before releasing the lock */
+	callback = timer->callback;
+	callback_data = timer->callback_data;
+	
+	OMAP_GPTIMER_UNLOCK(timer);
+
+	/* Check if an actual overflow interrupt */
+	if ((stat & OVF) && (callback != NULL))
+		callback(timer->callback_data);
+
+
+}
+
+
+
+/**
+ *	omap_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
+omap_gptimer_intr_filter_ack(unsigned int n)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	uint32_t stat;
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+
+	OMAP_GPTIMER_LOCK(timer);
+	
+	/* Read the interrupt status flag and clear it */
+	if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		
+		/* Read the status and it with the enable flag */
+		stat =  omap_gptimer_readl(timer, OMAP_GPT_TISR);
+		stat &= omap_gptimer_readl(timer, OMAP_GPT_TIER);
+		
+		/* Clear the status flag */
+		omap_gptimer_writel(timer, OMAP_GPT_TISR, stat);
+	}
+	else if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP4) {
+		
+		/* Read the status */
+		stat = omap_gptimer_readl(timer, OMAP4_GPT_IRQSTATUS);
+		
+		/* Clear the status flag */
+		omap_gptimer_writel(timer, OMAP4_GPT_IRQENABLE_CLR, stat);
+	}
+
+	OMAP_GPTIMER_UNLOCK(timer);
+}
+
+
+
+/**
+ *	omap_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
+omap_gptimer_set_intr_filter(unsigned int n, driver_filter_t filter)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > sc->sc_num_timers))
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+
+	OMAP_GPTIMER_LOCK(timer);
+
+	/* If a callback is already installed this won't work */
+	if (timer->callback != NULL) {
+		OMAP_GPTIMER_UNLOCK(timer);
+		return(EINVAL);
+	}
+	
+	/* Sanity check the timer is already activated and periodic type */
+	if ((timer->flags & (OMAP_GPTIMER_ACTIVATED_FLAG | OMAP_GPTIMER_PERIODIC_FLAG))
+	    != (OMAP_GPTIMER_ACTIVATED_FLAG | OMAP_GPTIMER_PERIODIC_FLAG)) {
+		OMAP_GPTIMER_UNLOCK(timer);
+		return(EINVAL);
+	}
+	
+	
+	/* Attempt to activate the interrupt for the tick */
+	if (bus_setup_intr(sc->sc_dev, timer->irq_res, INTR_TYPE_CLK,
+	                   filter, NULL, NULL, &timer->irq_h)) {
+		device_printf(sc->sc_dev, "Error: failed to activate interrupt\n");
+		OMAP_GPTIMER_UNLOCK(timer);
+		return(EINVAL);
+	}
+	
+	
+	/* Enable the overflow interrupts */
+	if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		val = omap_gptimer_readl(timer, OMAP_GPT_TIER);
+		val |= OVF;
+		omap_gptimer_writel(timer, OMAP_GPT_TIER, val);
+	}
+	else if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP4) {
+		omap_gptimer_writel(timer, OMAP4_GPT_IRQENABLE_SET, OVF);
+	}
+	
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	return(0);
+}
+
+
+
+
+
+/**
+ *	omap_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
+omap_gptimer_activate(unsigned int n, unsigned int flags, unsigned int time_us,
+                    void (*callback)(void *data), void *data)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	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);
+	if ((n == 0) || (n > sc->sc_num_timers))
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	
+	/* Sanity check the timer is availabe and not activated */
+	if (!(timer->flags & OMAP_GPTIMER_AVAILABLE_FLAG)) {
+		device_printf(sc->sc_dev, "Error: timer %d not available\n", n);
+		return (EINVAL);
+	}
+	if (timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG) {
+		device_printf(sc->sc_dev, "Error: timer %d already activated\n", n);
+		return (EINVAL);
+	}
+
+	/* Set up system clock information */
+	if (ti_prcm_clk_valid(timer->source) != 0) {
+		device_printf(sc->sc_dev, "Error: failed to find source clock\n");
+		return (EINVAL);
+	}
+
+
+	OMAP_GPTIMER_LOCK(timer);
+
+	/* Enable the functional and interface clock */
+	if (flags & OMAP_GPTIMER_32KCLK_FLAG)
+		ti_prcm_clk_set_source(timer->source, F32KHZ_CLK);
+	else
+		ti_prcm_clk_set_source(timer->source, SYSCLK_CLK);
+	
+	ti_prcm_clk_enable(timer->source);
+
+
+	/* Store the flags in the timer context */
+	timer->flags &=  0xFF000000;
+	timer->flags |= (0x00FFFFFF & flags);
+
+
+	/* Reset the timer and poll on the reset complete flag */
+	if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+		omap_gptimer_writel(timer, OMAP_GPT_TIOCP_CFG, 0x2);
+		/* TODO: add a timeout */
+		while ((omap_gptimer_readl(timer, OMAP_GPT_TISTAT) & 0x01) == 0x00)
+			continue;
+
+		/* Clear the interrupt status */
+		omap_gptimer_writel(timer, OMAP_GPT_TISR, TCAR | OVF | MAT);
+	}
+
+	else if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP4) {
+		omap_gptimer_writel(timer, OMAP_GPT_TIOCP_CFG, 0x1);
+		/* TODO: add a timeout */
+		while ((omap_gptimer_readl(timer, OMAP_GPT_TIOCP_CFG) & 0x01) == 0x01)
+			continue;
+
+		/* Clear the interrupt status */
+		omap_gptimer_writel(timer, OMAP4_GPT_IRQSTATUS, 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(timer->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 = omap_gptimer_readl(timer, timer->tclr);
+			val &= ~TCLR_PTV_MASK;
+			val |= TCLR_PRE | (prescaler << 2);
+			omap_gptimer_writel(timer, timer->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 */
+	omap_gptimer_writel(timer, timer->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 & OMAP_GPTIMER_PERIODIC_FLAG) {
+		/* Enable auto reload */
+		val = omap_gptimer_readl(timer, timer->tclr);
+		val |= TCLR_AR;
+		omap_gptimer_writel(timer, timer->tclr, val);
+		
+		/* Set the reload value */
+		omap_gptimer_writel(timer, timer->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 */
+		timer->callback = callback;
+		timer->callback_data = data;
+		
+		/* Activate the interrupt */
+		if (bus_setup_intr(sc->sc_dev, timer->irq_res, 
+		                   INTR_TYPE_MISC | INTR_MPSAFE, NULL, omap_gptimer_intr,
+						   (void*)timer, &timer->irq_h)) {
+			device_printf(sc->sc_dev, "Error: failed to activate interrupt\n");
+		}
+
+		/* Enable the overflow interrupts. */
+		if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP3) {
+			val = omap_gptimer_readl(timer, OMAP_GPT_TIER);
+			val |= OVF;
+			omap_gptimer_writel(timer, OMAP_GPT_TIER, val);
+		}
+		else if (timer->profile == OMAP_GPTIMER_PROFILE_OMAP4) {
+			omap_gptimer_writel(timer, OMAP4_GPT_IRQENABLE_SET, OVF);
+		}
+	}
+
+
+	/* Finally set the activated flag */
+	timer->flags |= OMAP_GPTIMER_ACTIVATED_FLAG;
+
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+printf("[BRG] %s, %d\n", __func__, __LINE__);
+
+	return (0);
+}
+
+
+
+/**
+ *	omap_gptimer_deactivate - deactivates an individual timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap_gptimer_deactivate(unsigned int n)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+	
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+
+	/* Stop the timer if running */
+	val = omap_gptimer_readl(timer, timer->tclr);
+	val &= ~TCLR_ST;
+	omap_gptimer_writel(timer, timer->tclr, val);
+
+
+	/* Uninstall the interrupt handler (if installed) */
+	if (timer->irq_h) {
+		bus_teardown_intr(sc->sc_dev, timer->irq_res, timer->irq_h);
+		timer->irq_h = NULL;
+	}
+
+	/* Disable the functional and interface clock */
+	ti_prcm_clk_disable(timer->source);
+
+	
+	/* Finally clear the active flag */
+	timer->flags &= ~OMAP_GPTIMER_ACTIVATED_FLAG;
+
+	return (0);
+}
+
+
+/**
+ *	omap_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
+omap_gptimer_start(unsigned int n)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+	
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP_GPTIMER_LOCK(timer);
+
+	val = omap_gptimer_readl(timer, timer->tclr);
+	val |= TCLR_ST;
+	omap_gptimer_writel(timer, timer->tclr, val);
+
+	OMAP_GPTIMER_UNLOCK(timer);
+
+	return (0);
+}
+
+
+/**
+ *	omap_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
+omap_gptimer_stop(unsigned int n)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	uint32_t val;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+	
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP_GPTIMER_LOCK(timer);
+	
+	val = omap_gptimer_readl(timer, timer->tclr);
+	val &= ~TCLR_ST;
+	omap_gptimer_writel(timer, timer->tclr, val);
+
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	return (0);
+}
+
+
+
+/**
+ *	omap_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
+omap_gptimer_read_count(unsigned int n, uint32_t *cnt)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	int ret;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > sc->sc_num_timers))
+		return (EINVAL);
+		
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	
+	OMAP_GPTIMER_LOCK(timer);
+	
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG)) {
+		ret = EINVAL;
+	} else {
+		*cnt = omap_gptimer_readl(timer, timer->tcrr);
+		ret = 0;
+	}
+
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	return (ret);
+}
+
+
+/**
+ *	omap_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
+omap_gptimer_write_count(unsigned int n, uint32_t cnt)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP_GPTIMER_LOCK(timer);
+	
+	omap_gptimer_writel(timer, timer->tcrr, cnt);
+
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	return (0);
+}
+
+
+
+/**
+ *	omap_gptimer_set_reload - sets the reload value for the driver if periodic
+ *                            timer
+ *	@n: the number of the timer (first timer is number 1)
+ *	@reload: the value to put in the reload register
+ *
+ *	
+ *
+ *	RETURNS:
+ *	Returns 0 on success, otherwise an error code
+ */
+int
+omap_gptimer_set_reload(unsigned int n, uint32_t reload)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+
+	/* Sanity checks */
+	if (sc == NULL)
+		return (ENOMEM);
+	if ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	OMAP_GPTIMER_LOCK(timer);
+
+	omap_gptimer_writel(timer, timer->tldr, reload);
+	
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	return (0);
+}
+
+
+
+
+/**
+ *	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
+omap_gptimer_get_freq(unsigned int n, uint32_t *freq)
+{
+	struct omap_gptimer_softc *sc = g_omap_gptimer_sc;
+	struct omap_gptimer *timer;
+	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 ((n == 0) || (n > MAX_NUM_TIMERS))
+		return (EINVAL);
+	if (freq == NULL)
+		return (EINVAL);
+
+	/* Get a pointer to the individual timer struct */
+	timer = &sc->sc_timers[n-1];
+	if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG))
+		return (EINVAL);
+
+	/* We get the frequency by first reading the source frequency */
+	if ((rc = ti_prcm_clk_get_source_freq(timer->source, &src_freq)) != 0)
+		return (rc);
+
+
+	OMAP_GPTIMER_LOCK(timer);
+	
+	/* Determine if the pre-scalar is enabled and if so the prescaler value */
+	tclr = omap_gptimer_readl(timer, timer->tclr);
+	if (tclr & TCLR_PRE)
+		prescaler = 1UL << (((tclr & TCLR_PTV_MASK) >> 2) + 1);
+	else
+		prescaler = 1;
+
+	/* Get the reload count */
+	tldr = omap_gptimer_readl(timer, timer->tldr);
+	
+	OMAP_GPTIMER_UNLOCK(timer);
+	
+	
+	/* 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);
+}
+
+
+
+/**
+ *	omap_gptimer_probe - driver probe function
+ *	@dev: timer device handle
+ *
+ *	
+ *
+ *	RETURNS:
+ *	Always returns 0.
+ */
+static int
+omap_gptimer_probe(device_t dev)
+{
+	
+	device_set_desc(dev, "TI OMAP General Purpose Timers");
+	return (0);
+}
+
+

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



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