diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/beagle/clock.c')
-rw-r--r-- | c/src/lib/libbsp/arm/beagle/clock.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/beagle/clock.c b/c/src/lib/libbsp/arm/beagle/clock.c new file mode 100644 index 0000000000..13c0607b8e --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/clock.c @@ -0,0 +1,332 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief Clock driver configuration. + */ + +/* + * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <rtems.h> +#include <bsp.h> + +#include <libcpu/omap_timer.h> + +#ifdef ARM_MULTILIB_ARCH_V4 + +static omap_timer_registers_t regs_v1 = { + .TIDR = OMAP3_TIMER_TIDR, + .TIOCP_CFG = OMAP3_TIMER_TIOCP_CFG, + .TISTAT = OMAP3_TIMER_TISTAT, + .TISR = OMAP3_TIMER_TISR, + .TIER = OMAP3_TIMER_TIER, + .TWER = OMAP3_TIMER_TWER, + .TCLR = OMAP3_TIMER_TCLR, + .TCRR = OMAP3_TIMER_TCRR, + .TLDR = OMAP3_TIMER_TLDR, + .TTGR = OMAP3_TIMER_TTGR, + .TWPS = OMAP3_TIMER_TWPS, + .TMAR = OMAP3_TIMER_TMAR, + .TCAR1 = OMAP3_TIMER_TCAR1, + .TSICR = OMAP3_TIMER_TSICR, + .TCAR2 = OMAP3_TIMER_TCAR2, + .TPIR = OMAP3_TIMER_TPIR, + .TNIR = OMAP3_TIMER_TNIR, + .TCVR = OMAP3_TIMER_TCVR, + .TOCR = OMAP3_TIMER_TOCR, + .TOWR = OMAP3_TIMER_TOWR, +}; + +/* AM335X has a different ip block for the non 1ms timers */ +static omap_timer_registers_t regs_v2 = { + .TIDR = AM335X_TIMER_TIDR, + .TIOCP_CFG = AM335X_TIMER_TIOCP_CFG, + .TISTAT = AM335X_TIMER_IRQSTATUS_RAW, + .TISR = AM335X_TIMER_IRQSTATUS, + .TIER = AM335X_TIMER_IRQENABLE_SET, + .TWER = AM335X_TIMER_IRQWAKEEN, + .TCLR = AM335X_TIMER_TCLR, + .TCRR = AM335X_TIMER_TCRR, + .TLDR = AM335X_TIMER_TLDR, + .TTGR = AM335X_TIMER_TTGR, + .TWPS = AM335X_TIMER_TWPS, + .TMAR = AM335X_TIMER_TMAR, + .TCAR1 = AM335X_TIMER_TCAR1, + .TSICR = AM335X_TIMER_TSICR, + .TCAR2 = AM335X_TIMER_TCAR2, + .TPIR = -1, /* UNDEF */ + .TNIR = -1, /* UNDEF */ + .TCVR = -1, /* UNDEF */ + .TOCR = -1, /* UNDEF */ + .TOWR = -1 /* UNDEF */ +}; + +/* which timers are in use? target-dependent. + * initialize at compile time. + */ + +#if IS_DM3730 + +static omap_timer_t dm37xx_timer = { + .base = OMAP3_GPTIMER1_BASE, + .irq_nr = OMAP3_GPT1_IRQ, + .regs = ®s_v1 +}; + +/* free running timer */ +static omap_timer_t dm37xx_fr_timer = { + .base = OMAP3_GPTIMER10_BASE, + .irq_nr = OMAP3_GPT10_IRQ, + .regs = ®s_v1 +}; + +static struct omap_timer *fr_timer = &dm37xx_fr_timer; +static struct omap_timer *timer = &dm37xx_timer; + +#endif + +#if IS_AM335X + +/* normal timer */ +static omap_timer_t am335x_timer = { + .base = AM335X_DMTIMER1_1MS_BASE, + .irq_nr = AM335X_INT_TINT1_1MS, + .regs = ®s_v1 +}; + +/* free running timer */ +static omap_timer_t am335x_fr_timer = { + .base = AM335X_DMTIMER7_BASE, + .irq_nr = AM335X_INT_TINT7, + .regs = ®s_v2 +}; + +static struct omap_timer *fr_timer = &am335x_fr_timer; +static struct omap_timer *timer = &am335x_timer; + +#endif + +static int done = 0; + +#if IS_AM335X +#define FRCLOCK_HZ (16*1500000) +#endif + +#if IS_DM3730 +#define FRCLOCK_HZ (8*1625000) +#endif + +#ifndef FRCLOCK_HZ +#error expected IS_AM335X or IS_DM3730 to be defined. +#endif + +static void +omap3_frclock_init(void) +{ + uint32_t tisr; + +#if IS_DM3730 + /* Stop timer */ + mmio_clear(fr_timer->base + fr_timer->regs->TCLR, + OMAP3_TCLR_ST); + + /* Use functional clock source for GPTIMER10 */ + mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10); +#endif + +#if IS_AM335X + /* Disable the module and wait for the module to be disabled */ + set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK, + CM_MODULEMODE_DISABLED); + while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST) + != CM_CLKCTRL_IDLEST_DISABLE); + + set32(CLKSEL_TIMER7_CLK, CLKSEL_TIMER7_CLK_SEL_MASK, + CLKSEL_TIMER7_CLK_SEL_SEL2); + while ((read32(CLKSEL_TIMER7_CLK) & CLKSEL_TIMER7_CLK_SEL_MASK) + != CLKSEL_TIMER7_CLK_SEL_SEL2); + + /* enable the module and wait for the module to be ready */ + set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK, + CM_MODULEMODE_ENABLE); + while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST) + != CM_CLKCTRL_IDLEST_FUNC); + + /* Stop timer */ + mmio_clear(fr_timer->base + fr_timer->regs->TCLR, + OMAP3_TCLR_ST); +#endif + + /* Start and auto-reload at 0 */ + mmio_write(fr_timer->base + fr_timer->regs->TLDR, 0x0); + mmio_write(fr_timer->base + fr_timer->regs->TCRR, 0x0); + + /* Set up overflow interrupt */ + tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | + OMAP3_TISR_TCAR_IT_FLAG; + /* Clear interrupt status */ + mmio_write(fr_timer->base + fr_timer->regs->TISR, tisr); + mmio_write(fr_timer->base + fr_timer->regs->TIER, + OMAP3_TIER_OVF_IT_ENA); + + /* Start timer, without prescaler */ + mmio_set(fr_timer->base + fr_timer->regs->TCLR, + OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST); + done = 1; +} + +static inline uint32_t +read_frc(void) +{ + if (done == 0) { + return 0; + } + return mmio_read(fr_timer->base + fr_timer->regs->TCRR); +} + +static uint32_t last_tick_nanoseconds; + +static void +beagle_clock_initialize(void) +{ + uint32_t freq = 1000000UL/rtems_configuration_get_microseconds_per_tick(); + + /* we only support 1ms resolution */ + uint32_t tisr; +#if IS_DM3730 + /* Stop timer */ + mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); + + /* Use 32 KHz clock source for GPTIMER1 */ + mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1); +#endif + +#if IS_AM335X + /* disable the module and wait for the module to be disabled */ + set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK, + CM_MODULEMODE_DISABLED); + while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST) + != CM_CLKCTRL_IDLEST_DISABLE); + + set32(CLKSEL_TIMER1MS_CLK, CLKSEL_TIMER1MS_CLK_SEL_MASK, + CLKSEL_TIMER1MS_CLK_SEL_SEL2); + while ((read32(CLKSEL_TIMER1MS_CLK) & + CLKSEL_TIMER1MS_CLK_SEL_MASK) != + CLKSEL_TIMER1MS_CLK_SEL_SEL2); + + /* enable the module and wait for the module to be ready */ + set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK, + CM_MODULEMODE_ENABLE); + while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST) + != CM_CLKCTRL_IDLEST_FUNC); + + /* Stop timer */ + mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); +#endif + + /* Use 1-ms tick mode for GPTIMER1 TRM 16.2.4.2.1 */ + mmio_write(timer->base + timer->regs->TPIR, 232000); + mmio_write(timer->base + timer->regs->TNIR, -768000); + mmio_write(timer->base + timer->regs->TLDR, + 0xffffffff - (32768 / freq) + 1); + mmio_write(timer->base + timer->regs->TCRR, + 0xffffffff - (32768 / freq) + 1); + + /* Set up overflow interrupt */ + tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | + OMAP3_TISR_TCAR_IT_FLAG; + /* Clear interrupt status */ + mmio_write(timer->base + timer->regs->TISR, tisr); + mmio_write(timer->base + timer->regs->TIER, OMAP3_TIER_OVF_IT_ENA); + + /* Start timer */ + mmio_set(timer->base + timer->regs->TCLR, + OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST); + /* also initilize the free runnning timer */ + omap3_frclock_init(); +} + +static void beagle_clock_at_tick(void) +{ + uint32_t tisr; + + last_tick_nanoseconds = read_frc(); + + mmio_write(timer->base + timer->regs->TISR, + OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | + OMAP3_TISR_TCAR_IT_FLAG); +} + +static rtems_interrupt_handler clock_isr = NULL; + +static void beagle_clock_handler_install(rtems_interrupt_handler isr) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_install( + timer->irq_nr, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + isr, + NULL + ); + + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(0xdeadbeef); + } + clock_isr = isr; +} + +static void beagle_clock_cleanup(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + /* Disable timer */ + mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST); + + /* Remove interrupt handler */ + sc = rtems_interrupt_handler_remove( + timer->irq_nr, + clock_isr, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(0xdeadbeef); + } + clock_isr = NULL; + + /* stop frclock */ + mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST); +} + +static inline uint32_t beagle_clock_nanoseconds_since_last_tick(void) +{ + /* this arithmetic also works if read_frc() wraps around, as long + * as the subtraction wraps around too + */ + return (read_frc() - (uint64_t) last_tick_nanoseconds) * 1000000000 / FRCLOCK_HZ; +} + +#define Clock_driver_support_at_tick() beagle_clock_at_tick() +#define Clock_driver_support_initialize_hardware() beagle_clock_initialize() +#define Clock_driver_support_install_isr(isr, old_isr) \ + do { \ + beagle_clock_handler_install(isr); \ + old_isr = NULL; \ + } while (0) + +#define Clock_driver_support_shutdown_hardware() beagle_clock_cleanup() +#define Clock_driver_nanoseconds_since_last_tick \ + beagle_clock_nanoseconds_since_last_tick + +/* Include shared source clock driver code */ +#include "../../shared/clockdrv_shell.h" + +#endif /* ARM_MULTILIB_ARCH_V4 */ |