Date: Tue, 12 Jun 2012 13:59:22 +0000 From: aleek@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r237548 - soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x Message-ID: <20120612135922.2F174106564A@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: aleek Date: Tue Jun 12 13:59:21 2012 New Revision: 237548 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=237548 Log: Extending GPTimer support Added: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c ============================================================================== --- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c Tue Jun 12 13:46:54 2012 (r237547) +++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.c Tue Jun 12 13:59:21 2012 (r237548) @@ -29,86 +29,32 @@ /* * Based on gptimer driver by Ben Gray */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); -#define OMAP3_NUM_TIMERS 12 +#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> -/* - * Ids of the timers used by the kernel - */ -#define TICKTIMER_GPTIMER 10 -#define TIMECOUNT_GPTIMER 11 - -/* - * Standard registers for OMAP3 General Purpose Timers - */ -#define OMAP3_GPT_TIDR 0x0000 -#define OMAP3_GPT_TIOCP_CFG 0x0010 -#define OMAP3_GPT_TISTAT 0x0014 -#define OMAP3_GPT_TISR 0x0018 -#define OMAP3_GPT_TIER 0x001C -#define OMAP3_GPT_TWER 0x0020 -#define OMAP3_GPT_TCLR 0x0024 -#define OMAP3_GPT_TCRR 0x0028 -#define OMAP3_GPT_TLDR 0x002C -#define OMAP3_GPT_TTGR 0x0030 -#define OMAP3_GPT_TWPS 0x0034 -#define OMAP3_GPT_TMAR 0x0038 -#define OMAP3_GPT_TCAR1 0x003C -#define OMAP3_GPT_TSICR 0x0040 -#define OMAP3_GPT_TCAR2 0x0044 -#define OMAP3_GPT_TPIR 0x0048 -#define OMAP3_GPT_TNIR 0x004C -#define OMAP3_GPT_TCVR 0x0050 -#define OMAP3_GPT_TOCR 0x0054 -#define OMAP3_GPT_TOWR 0x0058 - -/** - * Data structure per Timer. - */ -struct omap3_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; -}; - - -/** - * Timer driver context, allocated and stored globally, this driver is not - * intended to ever be unloaded (see g_omap_gptimer_sc). - * - */ -struct omap3_gptimer_softc { - device_t sc_dev; - unsigned int sc_num_timers; - struct omap3_gptimer sc_timers[MAX_NUM_TIMERS]; - struct omap3_gptimer *sc_tick_timer; - -}; static struct omap3_gptimer_softc *g_omap3_gptimer_sc = NULL; @@ -146,9 +92,121 @@ static unsigned omap3_gptimer_tc_get_timecount(struct timecounter *tc) { - return omap3_gptimer_tc_read_4(DMTIMER_TCRR); + uint32_t count; + omap3_gptimer_read_count(TIMECOUNT_GPTIMER, &count); + return(count); + +} + +/** + * 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 +omap3_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]; + + OMAP3_GPTIMER_LOCK(timer); + + if (!(timer->flags & OMAP_GPTIMER_ACTIVATED_FLAG)) { + ret = EINVAL; + } else { + *cnt = omap_gptimer_readl(timer, timer->tcrr); + ret = 0; + } + + OMAP3_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 +omap3_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); + + OMAP3_GPTIMER_LOCK(timer); + + omap_gptimer_writel(timer, timer->tcrr, cnt); + + OMAP3_GPTIMER_UNLOCK(timer); + + return (0); } + +/** + * 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 +omap3_gptimer_readl(struct omap3_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 +omap3_gptimer_writel(struct omap3_gptimer *timer, bus_size_t off, uint32_t val) +{ + bus_write_4(timer->mem_res, off, val); +} + + /** * omap_gptimer_activate - configures the timer * @n: the number of the timer (first timer is number 1) @@ -201,15 +259,15 @@ } - OMAP_GPTIMER_LOCK(timer); + OMAP3_GPTIMER_LOCK(timer); /* Enable the functional and interface clock */ - if (flags & OMAP_GPTIMER_32KCLK_FLAG) - omap_prcm_clk_set_source(timer->source, F32KHZ_CLK); + if (flags & OMAP3_GPTIMER_32KCLK_FLAG) + ti_prcm_clk_set_source(timer->source, F32KHZ_CLK); else - omap_prcm_clk_set_source(timer->source, SYSCLK_CLK); + ti_prcm_clk_set_source(timer->source, SYSCLK_CLK); - omap_prcm_clk_enable(timer->source); + ti_prcm_clk_enable(timer->source); /* Store the flags in the timer context */ @@ -219,38 +277,24 @@ /* 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); + omap_gptimer_writel(timer, OMAP3_GPT_TIOCP_CFG, 0x2); /* TODO: add a timeout */ - while ((omap_gptimer_readl(timer, OMAP_GPT_TISTAT) & 0x01) == 0x00) + while ((omap_gptimer_readl(timer, OMAP3_GPT_TISTAT) & 0x01) == 0x00) continue; /* Clear the interrupt status */ - omap_gptimer_writel(timer, OMAP_GPT_TISR, TCAR | OVF | MAT); + omap_gptimer_writel(timer, OMAP3_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 */ - omap_prcm_clk_get_source_freq(timer->source, &freq); + ti_prcm_clk_get_source_freq(timer->source, &freq); freq64 = freq; /* Calculate the period of the timer, 64 bit calculations used to @@ -277,35 +321,35 @@ /* Adjust the count and apply the prescaler */ tickcount >>= (prescaler + 1); - val = omap_gptimer_readl(timer, timer->tclr); + val = omap3_gptimer_readl(timer, timer->tclr); val &= ~TCLR_PTV_MASK; val |= TCLR_PRE | (prescaler << 2); - omap_gptimer_writel(timer, timer->tclr, val); + omap3_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", + 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); + omap3_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) { + if (flags & OMAP3_GPTIMER_PERIODIC_FLAG) { /* Enable auto reload */ - val = omap_gptimer_readl(timer, timer->tclr); + val = omap3_gptimer_readl(timer, timer->tclr); val |= TCLR_AR; - omap_gptimer_writel(timer, timer->tclr, val); + omap3_gptimer_writel(timer, timer->tclr, val); /* Set the reload value */ - omap_gptimer_writel(timer, timer->tldr, startcount); + omap3_gptimer_writel(timer, timer->tldr, startcount); } @@ -318,19 +362,16 @@ /* Activate the interrupt */ if (bus_setup_intr(sc->sc_dev, timer->irq_res, - INTR_TYPE_MISC | INTR_MPSAFE, NULL, omap_gptimer_intr, + INTR_TYPE_MISC | INTR_MPSAFE, NULL, omap3_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 = omap3_gptimer_readl(timer, OMAP3_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); + omap3_gptimer_writel(timer, OMAP3_GPT_TIER, val); } } @@ -338,9 +379,9 @@ /* Finally set the activated flag */ timer->flags |= OMAP_GPTIMER_ACTIVATED_FLAG; - OMAP_GPTIMER_UNLOCK(timer); + OMAP3_GPTIMER_UNLOCK(timer); -printf("[BRG] %s, %d\n", __func__, __LINE__); + printf("[BRG] %s, %d\n", __func__, __LINE__); return (0); } Added: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_gptimer.h Tue Jun 12 13:59:21 2012 (r237548) @@ -0,0 +1,139 @@ +#define OMAP3_NUM_TIMERS 12 + +/* + * Ids of the timers used by the kernel + */ +#define TICKTIMER_GPTIMER 10 +#define TIMECOUNT_GPTIMER 11 + +/* + * Standard registers for OMAP3 General Purpose Timers + */ +#define OMAP3_GPT_TIDR 0x0000 +#define OMAP3_GPT_TIOCP_CFG 0x0010 +#define OMAP3_GPT_TISTAT 0x0014 +#define OMAP3_GPT_TISR 0x0018 +#define OMAP3_GPT_TIER 0x001C +#define OMAP3_GPT_TWER 0x0020 +#define OMAP3_GPT_TCLR 0x0024 +#define OMAP3_GPT_TCRR 0x0028 +#define OMAP3_GPT_TLDR 0x002C +#define OMAP3_GPT_TTGR 0x0030 +#define OMAP3_GPT_TWPS 0x0034 +#define OMAP3_GPT_TMAR 0x0038 +#define OMAP3_GPT_TCAR1 0x003C +#define OMAP3_GPT_TSICR 0x0040 +#define OMAP3_GPT_TCAR2 0x0044 +#define OMAP3_GPT_TPIR 0x0048 +#define OMAP3_GPT_TNIR 0x004C +#define OMAP3_GPT_TCVR 0x0050 +#define OMAP3_GPT_TOCR 0x0054 +#define OMAP3_GPT_TOWR 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 following flags define the clocking source, if specified the timer will + * be clocked from the 32Khz source, otherwise it clocked from the sysclk. + */ +#define OMAP_GPTIMER_32KCLK_FLAG 0x00000100 + + +/** + * Macros for driver mutex locking + */ +#define OMAP3_GPTIMER_LOCK(_tmr) mtx_lock(&(_tmr)->mtx) +#define OMAP3_GPTIMER_UNLOCK(_tmr) mtx_unlock(&(_tmr)->mtx) +#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. + */ +struct omap3_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; +}; + + +/** + * Timer driver context, allocated and stored globally, this driver is not + * intended to ever be unloaded (see g_omap_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; + +}; + + +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); + + +static inline void +omap3_gptimer_writel(struct omap3_gptimer *timer, bus_size_t off, uint32_t val); + +int +omap_gptimer_activate(unsigned int n, unsigned int flags, unsigned int time_us, + void (*callback)(void *data), void *data); + +static void +omap3_gptimer_intr(void *arg); + + +static int +omap3_gptimer_probe(device_t dev); + + +static int +omap3_gptimer_attach(device_t dev); + +int +omap3_gptimer_write_count(unsigned int n, uint32_t cnt); + +int +omap3_gptimer_read_count(unsigned int n, uint32_t *cnt); Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x ============================================================================== --- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x Tue Jun 12 13:46:54 2012 (r237547) +++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/files.am37x Tue Jun 12 13:59:21 2012 (r237548) @@ -2,7 +2,7 @@ arm/ti/aintc.c standard arm/ti/am37x/am37x_prcm.c standard -arm/ti/am37x/am37x_dmtimer.c standard +arm/ti/am37x/am37x_gptimer.c standard arm/ti/am37x/am37x_scm_padconf.c standard arm/ti/ti_edma3.c standard arm/ti/ti_mmchs.c optional mmc
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120612135922.2F174106564A>