diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-19 06:35:52 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 09:57:01 +0200 |
commit | 7632906fc290b652416ab59eb5fb49356c064ed6 (patch) | |
tree | ac036b1f95637e044e10138ceea8d2b56d80ec97 /bsps/sparc | |
parent | bsps: Move bspsmpgetcurrentprocessor.c to bsps (diff) | |
download | rtems-7632906fc290b652416ab59eb5fb49356c064ed6.tar.bz2 |
bsps: Move clock drivers to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/sparc')
-rw-r--r-- | bsps/sparc/erc32/clock/ckinit.c | 131 | ||||
-rw-r--r-- | bsps/sparc/leon2/clock/ckinit.c | 104 | ||||
-rw-r--r-- | bsps/sparc/leon3/clock/ckinit.c | 280 |
3 files changed, 515 insertions, 0 deletions
diff --git a/bsps/sparc/erc32/clock/ckinit.c b/bsps/sparc/erc32/clock/ckinit.c new file mode 100644 index 0000000000..7f8c0f5aad --- /dev/null +++ b/bsps/sparc/erc32/clock/ckinit.c @@ -0,0 +1,131 @@ +/* + * This routine initializes the Real Time Clock Counter Timer which is + * part of the MEC on the ERC32 CPU. + * + * The tick frequency is directly programmed to the configured number of + * microseconds per tick. + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * Ported to ERC32 implementation of the SPARC by On-Line Applications + * Research Corporation (OAR) under contract to the European Space + * Agency (ESA). + * + * ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995. + * European Space Agency. + */ + +#include <bsp.h> +#include <bspopts.h> +#include <rtems/counter.h> +#include <rtems/timecounter.h> +#include <rtems/score/sparcimpl.h> + +/* + * The Real Time Clock Counter Timer uses this trap type. + */ +#define CLOCK_VECTOR ERC32_TRAP_TYPE( ERC32_INTERRUPT_REAL_TIME_CLOCK ) + +#define Clock_driver_support_install_isr( _new ) \ + set_vector( _new, CLOCK_VECTOR, 1 ) + +#define Clock_driver_support_set_interrupt_affinity( _online_processors ) \ + do { \ + (void) _online_processors; \ + } while (0) + +extern int CLOCK_SPEED; + +static rtems_timecounter_simple erc32_tc; + +static uint32_t erc32_tc_get( rtems_timecounter_simple *tc ) +{ + return ERC32_MEC.Real_Time_Clock_Counter; +} + +static bool erc32_tc_is_pending( rtems_timecounter_simple *tc ) +{ + return ERC32_Is_interrupt_pending( ERC32_INTERRUPT_REAL_TIME_CLOCK ); +} + +static uint32_t erc32_tc_get_timecount( struct timecounter *tc ) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + erc32_tc_get, + erc32_tc_is_pending + ); +} + +static void erc32_tc_at_tick( rtems_timecounter_simple *tc ) +{ + /* Nothing to do */ +} + +static void erc32_tc_tick( void ) +{ + rtems_timecounter_simple_downcounter_tick( + &erc32_tc, + erc32_tc_get, + erc32_tc_at_tick + ); +} + +static void erc32_counter_initialize( uint32_t frequency ) +{ + _SPARC_Counter_initialize( + _SPARC_Counter_read_address, + _SPARC_Counter_difference_clock_period, + &ERC32_MEC.Real_Time_Clock_Counter + ); + rtems_counter_initialize_converter( frequency ); +} + +#define Clock_driver_support_initialize_hardware() \ + do { \ + uint32_t frequency = 1000000; \ + /* approximately 1 us per countdown */ \ + ERC32_MEC.Real_Time_Clock_Scalar = CLOCK_SPEED - 1; \ + ERC32_MEC.Real_Time_Clock_Counter = \ + rtems_configuration_get_microseconds_per_tick(); \ + \ + ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \ + ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \ + ERC32_MEC_TIMER_COUNTER_LOAD_SCALER | \ + ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER \ + ); \ + \ + ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \ + ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING | \ + ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO \ + ); \ + rtems_timecounter_simple_install( \ + &erc32_tc, \ + frequency, \ + rtems_configuration_get_microseconds_per_tick(), \ + erc32_tc_get_timecount \ + ); \ + erc32_counter_initialize( frequency ); \ + } while (0) + +#define Clock_driver_timecounter_tick() erc32_tc_tick() + +#define Clock_driver_support_shutdown_hardware() \ + do { \ + ERC32_Mask_interrupt( ERC32_INTERRUPT_REAL_TIME_CLOCK ); \ + \ + ERC32_MEC_Set_Real_Time_Clock_Timer_Control( \ + ERC32_MEC_TIMER_COUNTER_DISABLE_COUNTING \ + ); \ + } while (0) + +#include "../../../shared/dev/clock/clockimpl.h" + +SPARC_COUNTER_DEFINITION; diff --git a/bsps/sparc/leon2/clock/ckinit.c b/bsps/sparc/leon2/clock/ckinit.c new file mode 100644 index 0000000000..a1dfc12806 --- /dev/null +++ b/bsps/sparc/leon2/clock/ckinit.c @@ -0,0 +1,104 @@ +/** + * @file + * @ingroup sparc_leon2 + * @brief Clock Tick Device Driver + * + * This routine initializes LEON timer 1 which used for the clock tick. + * + * The tick frequency is directly programmed to the configured number of + * microseconds per tick. + */ + +/* + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * Modified for LEON BSP + * COPYRIGHT (c) 2004. + * Gaisler Research. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bspopts.h> +#include <rtems/timecounter.h> +#include <rtems/score/sparcimpl.h> + +static rtems_timecounter_simple leon2_tc; + +static uint32_t leon2_tc_get( rtems_timecounter_simple *tc ) +{ + return LEON_REG.Timer_Counter_1; +} + +static bool leon2_tc_is_pending( rtems_timecounter_simple *tc ) +{ + return LEON_Is_interrupt_pending( LEON_INTERRUPT_TIMER1 ); +} + +static uint32_t leon2_tc_get_timecount( struct timecounter *tc ) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + leon2_tc_get, + leon2_tc_is_pending + ); +} + +static void leon2_tc_at_tick( rtems_timecounter_simple *tc ) +{ + /* Nothing to do */ +} + +static void leon2_tc_tick( void ) +{ + rtems_timecounter_simple_downcounter_tick( + &leon2_tc, + leon2_tc_get, + leon2_tc_at_tick + ); +} + +/* + * The Real Time Clock Counter Timer uses this trap type. + */ + +#define CLOCK_VECTOR LEON_TRAP_TYPE( LEON_INTERRUPT_TIMER1 ) + +#define Clock_driver_support_install_isr( _new ) \ + set_vector( _new, CLOCK_VECTOR, 1 ) + +extern int CLOCK_SPEED; + +#define Clock_driver_support_initialize_hardware() \ + do { \ + LEON_REG.Timer_Reload_1 = \ + rtems_configuration_get_microseconds_per_tick() - 1; \ + \ + LEON_REG.Timer_Control_1 = ( \ + LEON_REG_TIMER_COUNTER_ENABLE_COUNTING | \ + LEON_REG_TIMER_COUNTER_RELOAD_AT_ZERO | \ + LEON_REG_TIMER_COUNTER_LOAD_COUNTER \ + ); \ + rtems_timecounter_simple_install( \ + &leon2_tc, \ + 1000000, \ + rtems_configuration_get_microseconds_per_tick(), \ + leon2_tc_get_timecount \ + ); \ + } while (0) + +#define Clock_driver_support_shutdown_hardware() \ + do { \ + LEON_Mask_interrupt( LEON_INTERRUPT_TIMER1 ); \ + LEON_REG.Timer_Control_1 = 0; \ + } while (0) + +#define Clock_driver_timecounter_tick() leon2_tc_tick() + +#include "../../../shared/dev/clock/clockimpl.h" + +SPARC_COUNTER_DEFINITION; diff --git a/bsps/sparc/leon3/clock/ckinit.c b/bsps/sparc/leon3/clock/ckinit.c new file mode 100644 index 0000000000..fd194aba21 --- /dev/null +++ b/bsps/sparc/leon3/clock/ckinit.c @@ -0,0 +1,280 @@ +/* + * Clock Tick Device Driver + * + * This routine initializes LEON timer 1 which used for the clock tick. + * + * The tick frequency is directly programmed to the configured number of + * microseconds per tick. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * Modified for LEON3 BSP. + * COPYRIGHT (c) 2004. + * Gaisler Research. + * + * Copyright (c) 2014, 2018 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bspopts.h> +#include <bsp/fatal.h> +#include <rtems/rtems/intr.h> +#include <ambapp.h> +#include <rtems/score/profiling.h> +#include <rtems/timecounter.h> + +/* The LEON3 BSP Timer driver can rely on the Driver Manager if the + * DrvMgr is initialized during startup. Otherwise the classic driver + * must be used. + * + * The DrvMgr Clock driver is located in the shared/timer directory + */ +#ifndef RTEMS_DRVMGR_STARTUP + +/* LEON3 Timer system interrupt number */ +static int clkirq; + +static void (*leon3_tc_tick)(void); + +static rtems_timecounter_simple leon3_tc; + +#ifndef RTEMS_SMP +static uint32_t leon3_tc_get(rtems_timecounter_simple *tc) +{ + return LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value; +} + +static bool leon3_tc_is_pending(rtems_timecounter_simple *tc) +{ + return LEON_Is_interrupt_pending(clkirq); +} + +static void leon3_tc_at_tick( rtems_timecounter_simple *tc ) +{ + /* Nothing to do */ +} + +static uint32_t leon3_tc_get_timecount(struct timecounter *tc) +{ + return rtems_timecounter_simple_downcounter_get( + tc, + leon3_tc_get, + leon3_tc_is_pending + ); +} + +static void leon3_tc_tick_simple(void) +{ + rtems_timecounter_simple_downcounter_tick( + &leon3_tc, + leon3_tc_get, + leon3_tc_at_tick + ); +} +#endif + +static uint32_t leon3_tc_get_timecount_up_counter(struct timecounter *tc) +{ + return leon3_up_counter_low(); +} + +static uint32_t leon3_tc_get_timecount_irqmp(struct timecounter *tc) +{ + return LEON3_IrqCtrl_Regs->timestamp[0].counter; +} + +#ifdef RTEMS_SMP +static uint32_t leon3_tc_get_timecount_second_timer(struct timecounter *tc) +{ + return 0xffffffff - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX + 1].value; +} +#endif + +#ifdef RTEMS_PROFILING +#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26)) + +static void leon3_tc_tick_irqmp_timestamp(void) +{ + volatile struct irqmp_timestamp_regs *irqmp_ts = + &LEON3_IrqCtrl_Regs->timestamp[0]; + unsigned int first = irqmp_ts->assertion; + unsigned int second = irqmp_ts->counter; + + irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2; + + _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first); + + rtems_timecounter_tick(); +} +#endif + +static void leon3_tc_tick_irqmp_timestamp_init(void) +{ +#ifdef RTEMS_PROFILING + /* + * Ignore the first clock interrupt, since it contains the sequential system + * initialization time. Do the timestamp initialization on the fly. + */ + +#ifdef RTEMS_SMP + static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0); + + bool done = + _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED) + == rtems_get_processor_count() - 1; +#else + bool done = true; +#endif + + volatile struct irqmp_timestamp_regs *irqmp_ts = + &LEON3_IrqCtrl_Regs->timestamp[0]; + unsigned int ks = 1U << 5; + + irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq; + + if (done) { + leon3_tc_tick = leon3_tc_tick_irqmp_timestamp; + } +#endif + + rtems_timecounter_tick(); +} + +#ifdef RTEMS_SMP +static void leon3_tc_tick_second_timer(void) +{ + rtems_timecounter_tick(); +} +#endif + +static void leon3_tc_do_tick(void) +{ + (*leon3_tc_tick)(); +} + +#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0) + +#define Clock_driver_support_find_timer() \ + do { \ + /* Assume timer found during BSP initialization */ \ + if (LEON3_Timer_Regs) { \ + clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \ + \ + Adjust_clkirq_for_node(); \ + } \ + } while (0) + +#define Clock_driver_support_install_isr( _new ) \ + bsp_clock_handler_install(_new) + +static void bsp_clock_handler_install(rtems_isr *new) +{ + rtems_status_code sc; + + sc = rtems_interrupt_handler_install( + clkirq, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + new, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION); + } +} + +#define Clock_driver_support_set_interrupt_affinity(online_processors) \ + bsp_interrupt_set_affinity(clkirq, online_processors) + +static void leon3_clock_initialize(void) +{ + volatile struct irqmp_timestamp_regs *irqmp_ts; + volatile struct gptimer_regs *gpt; + + irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0]; + gpt = LEON3_Timer_Regs; + + gpt->timer[LEON3_CLOCK_INDEX].reload = + rtems_configuration_get_microseconds_per_tick() - 1; + gpt->timer[LEON3_CLOCK_INDEX].ctrl = + GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS | + GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE; + + leon3_up_counter_enable(); + + if (leon3_up_counter_is_available()) { + /* Use the LEON4 up-counter if available */ + leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_up_counter; + leon3_tc.tc.tc_counter_mask = 0xffffffff; + leon3_tc.tc.tc_frequency = leon3_up_counter_frequency(); + leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + +#ifdef RTEMS_PROFILING + if (!leon3_irqmp_has_timestamp(irqmp_ts)) { + bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT); + } +#endif + + leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init; + rtems_timecounter_install(&leon3_tc.tc); + } else if (leon3_irqmp_has_timestamp(irqmp_ts)) { + /* Use the interrupt controller timestamp counter if available */ + leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_irqmp; + leon3_tc.tc.tc_counter_mask = 0xffffffff; + leon3_tc.tc.tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev); + leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init; + + /* + * At least one TSISEL field must be non-zero to enable the timestamp + * counter. Use an arbitrary interrupt source. + */ + irqmp_ts->control = 0x1; + + rtems_timecounter_install(&leon3_tc.tc); + } else { +#ifdef RTEMS_SMP + /* + * The GR712RC for example has no timestamp unit in the interrupt + * controller. At least on SMP configurations we must use a second timer + * in free running mode for the timecounter. + */ + gpt->timer[LEON3_CLOCK_INDEX + 1].ctrl = + GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_IE; + leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_second_timer; + leon3_tc.tc.tc_counter_mask = 0xffffffff; + leon3_tc.tc.tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER; + leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + leon3_tc_tick = leon3_tc_tick_second_timer; + rtems_timecounter_install(&leon3_tc.tc); +#else + leon3_tc_tick = leon3_tc_tick_simple; + rtems_timecounter_simple_install( + &leon3_tc, + LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER, + rtems_configuration_get_microseconds_per_tick(), + leon3_tc_get_timecount + ); +#endif + } +} + +#define Clock_driver_support_initialize_hardware() \ + leon3_clock_initialize() + +#define Clock_driver_support_shutdown_hardware() \ + do { \ + LEON_Mask_interrupt(LEON_TRAP_TYPE(clkirq)); \ + LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].ctrl = 0; \ + } while (0) + +#define Clock_driver_timecounter_tick() leon3_tc_do_tick() + +#include "../../../shared/dev/clock/clockimpl.h" + +#endif |