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