summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/beagle/clock.c
diff options
context:
space:
mode:
authorBen Gras <beng@shrike-systems.com>2014-11-03 19:53:40 +0100
committerJoel Sherrill <joel.sherrill@oarcorp.com>2014-11-03 14:19:47 -0600
commit53dd6d6130c870d12351d8ca75e4ac9dcc834c86 (patch)
tree022804b833f8fdb47a15ab8940743f91726776b5 /c/src/lib/libbsp/arm/beagle/clock.c
parentAdded BeagleBoard BSP (diff)
downloadrtems-53dd6d6130c870d12351d8ca75e4ac9dcc834c86.tar.bz2
BSP for several Beagle products
Specifically the beagleboard, beagleboard xM, beaglebone, beaglebone black. More info on these targets: http://www.beagleboard.org/ This commit forms a basic BSP by combining Claas's work with . new clock and irq code and definitions for beagle targets (beagleboard and beaglebones), mostly reused from the Minix codebase, thus making irqs, ticks and non-polled console mode work too . new timer code for ns timing with high timer resolution, 24MHz on the AM335X and 13MHz on the DM37XX . select the console uart based on target at configure time . removing all the lpc32xx-specific macros and code and other unused code and definitions that the beagle bsp was based on . re-using some standard functions instead of lpc32xx versions . fixed some whitespace problem in preinstall.am . fixed some compile warnings . configure MMU: set 1MB sections directly in the TTBR, just to show the difference between cacheable RAM and non-cacheable device memory and invalid ranges; this lets us turn on caches and not rely on boot loader MMU configuration. Verified to work when MMU is initially either on or off when RTEMS gets control. Thanks for testing, commentary, improvements and fixes to Chris Johns, Brandon Matthews, Matt Carberry, Romain Bornet, AZ technology and others. Signed-Off-By: Ben Gras <beng@shrike-systems.com>
Diffstat (limited to 'c/src/lib/libbsp/arm/beagle/clock.c')
-rw-r--r--c/src/lib/libbsp/arm/beagle/clock.c332
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 = &regs_v1
+};
+
+/* free running timer */
+static omap_timer_t dm37xx_fr_timer = {
+ .base = OMAP3_GPTIMER10_BASE,
+ .irq_nr = OMAP3_GPT10_IRQ,
+ .regs = &regs_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 = &regs_v1
+};
+
+/* free running timer */
+static omap_timer_t am335x_fr_timer = {
+ .base = AM335X_DMTIMER7_BASE,
+ .irq_nr = AM335X_INT_TINT7,
+ .regs = &regs_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 */