From owner-svn-soc-all@FreeBSD.ORG Fri Jun 1 21:06:42 2012 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from socsvn.FreeBSD.org (unknown [IPv6:2001:4f8:fff6::2f]) by hub.freebsd.org (Postfix) with SMTP id 52334106566C for ; Fri, 1 Jun 2012 21:06:40 +0000 (UTC) (envelope-from aleek@FreeBSD.org) Received: by socsvn.FreeBSD.org (sSMTP sendmail emulation); Fri, 01 Jun 2012 21:06:40 +0000 Date: Fri, 01 Jun 2012 21:06:40 +0000 From: aleek@FreeBSD.org To: svn-soc-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <20120601210640.52334106566C@hub.freebsd.org> Cc: Subject: socsvn commit: r236899 - in soc2012/aleek/beaglexm-armv6/sys: arm/conf arm/ti arm/ti/am37x arm/ti/am37xx arm/ti/omap3 conf X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Jun 2012 21:06:42 -0000 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 . + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#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 ***