socsvn commit: r236899 - in soc2012/aleek/beaglexm-armv6/sys:
arm/conf arm/ti arm/ti/am37x arm/ti/am37xx arm/ti/omap3 conf
aleek at FreeBSD.org
aleek at FreeBSD.org
Fri Jun 1 21:06:42 UTC 2012
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 at 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 ***
More information about the svn-soc-all
mailing list