forked from Imagelibrary/rtems
sparc: Rework CPU counter support
Rework CPU counter support to enable use of the GR740 up-counter via %asr22 and %asr23.
This commit is contained in:
@@ -83,14 +83,14 @@ static void erc32_tc_tick( void )
|
||||
);
|
||||
}
|
||||
|
||||
static CPU_Counter_ticks erc32_counter_difference(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
static void erc32_counter_initialize( uint32_t frequency )
|
||||
{
|
||||
CPU_Counter_ticks period = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
return (first + period - second) % period;
|
||||
_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() \
|
||||
@@ -117,11 +117,7 @@ static CPU_Counter_ticks erc32_counter_difference(
|
||||
rtems_configuration_get_microseconds_per_tick(), \
|
||||
erc32_tc_get_timecount \
|
||||
); \
|
||||
_SPARC_Counter_initialize( \
|
||||
&ERC32_MEC.Real_Time_Clock_Counter, \
|
||||
erc32_counter_difference \
|
||||
); \
|
||||
rtems_counter_initialize_converter( frequency ); \
|
||||
erc32_counter_initialize( frequency ); \
|
||||
} while (0)
|
||||
|
||||
#define Clock_driver_timecounter_tick() erc32_tc_tick()
|
||||
@@ -137,3 +133,8 @@ static CPU_Counter_ticks erc32_counter_difference(
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
|
||||
SPARC_Counter _SPARC_Counter = {
|
||||
.counter_read = _SPARC_Counter_read_address,
|
||||
.counter_difference = _SPARC_Counter_difference_one,
|
||||
.counter_address = (uint32_t *) &_SPARC_Counter
|
||||
};
|
||||
|
||||
@@ -105,3 +105,9 @@ extern int CLOCK_SPEED;
|
||||
#define Clock_driver_timecounter_tick() leon2_tc_tick()
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
|
||||
SPARC_Counter _SPARC_Counter = {
|
||||
.counter_read = _SPARC_Counter_read_address,
|
||||
.counter_difference = _SPARC_Counter_difference_one,
|
||||
.counter_address = (uint32_t *) &_SPARC_Counter
|
||||
};
|
||||
|
||||
@@ -387,8 +387,6 @@ extern int leon3_timer_core_index;
|
||||
*/
|
||||
extern unsigned int leon3_timer_prescaler;
|
||||
|
||||
void leon3_cpu_counter_initialize(void);
|
||||
|
||||
/* GRLIB extended IRQ controller register */
|
||||
void leon3_ext_irq_init(void);
|
||||
|
||||
@@ -457,6 +455,51 @@ static inline bool leon3_irqmp_has_timestamp(
|
||||
return (irqmp_ts->control >> 27) > 0;
|
||||
}
|
||||
|
||||
static inline uint32_t leon3_up_counter_low(void)
|
||||
{
|
||||
uint32_t asr23;
|
||||
|
||||
__asm__ volatile (
|
||||
"mov %%asr23, %0"
|
||||
: "=&r" (asr23)
|
||||
);
|
||||
|
||||
return asr23;
|
||||
}
|
||||
|
||||
static inline uint32_t leon3_up_counter_high(void)
|
||||
{
|
||||
uint32_t asr22;
|
||||
|
||||
__asm__ volatile (
|
||||
"mov %%asr22, %0"
|
||||
: "=&r" (asr22)
|
||||
);
|
||||
|
||||
return asr22;
|
||||
}
|
||||
|
||||
static inline void leon3_up_counter_enable(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"mov %g0, %asr23"
|
||||
);
|
||||
}
|
||||
|
||||
static inline bool leon3_up_counter_is_available(void)
|
||||
{
|
||||
return leon3_up_counter_low() != leon3_up_counter_low();
|
||||
}
|
||||
|
||||
static inline uint32_t leon3_up_counter_frequency(void)
|
||||
{
|
||||
/*
|
||||
* For simplicity, assume that the interrupt controller uses the processor
|
||||
* clock. This is at least true on the GR740.
|
||||
*/
|
||||
return ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev);
|
||||
}
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -58,8 +58,6 @@ static inline int set_snooping(void)
|
||||
void bsp_start( void )
|
||||
{
|
||||
CPU_SPARC_HAS_SNOOPING = set_snooping();
|
||||
|
||||
leon3_cpu_counter_initialize();
|
||||
}
|
||||
|
||||
static void leon3_cpu_index_init(void)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -15,69 +15,66 @@
|
||||
#include <leon.h>
|
||||
|
||||
#include <rtems/counter.h>
|
||||
#include <rtems/sysinit.h>
|
||||
|
||||
static CPU_Counter_ticks timestamp_counter_difference(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
static void leon3_counter_initialize(void)
|
||||
{
|
||||
return second - first;
|
||||
}
|
||||
|
||||
static CPU_Counter_ticks clock_counter_difference(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
{
|
||||
CPU_Counter_ticks period = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
return (first + period - second) % period;
|
||||
}
|
||||
|
||||
static void gpt_counter_initialize(
|
||||
volatile struct gptimer_regs *gpt,
|
||||
size_t timer_index,
|
||||
uint32_t frequency,
|
||||
SPARC_Counter_difference counter_difference
|
||||
)
|
||||
{
|
||||
_SPARC_Counter_initialize(
|
||||
(volatile const uint32_t *) &gpt->timer[timer_index].value,
|
||||
counter_difference
|
||||
);
|
||||
|
||||
rtems_counter_initialize_converter(frequency);
|
||||
}
|
||||
|
||||
void leon3_cpu_counter_initialize(void)
|
||||
{
|
||||
volatile struct irqmp_timestamp_regs *irqmp_ts =
|
||||
&LEON3_IrqCtrl_Regs->timestamp[0];
|
||||
volatile struct irqmp_timestamp_regs *irqmp_ts;
|
||||
volatile struct gptimer_regs *gpt;
|
||||
unsigned int freq;
|
||||
|
||||
if (leon3_irqmp_has_timestamp(irqmp_ts)) {
|
||||
irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
|
||||
gpt = LEON3_Timer_Regs;
|
||||
|
||||
leon3_up_counter_enable();
|
||||
|
||||
if (leon3_up_counter_is_available()) {
|
||||
/* Use the LEON4 up-counter if available */
|
||||
|
||||
_SPARC_Counter_initialize(
|
||||
_SPARC_Counter_read_asr23,
|
||||
_SPARC_Counter_difference_normal,
|
||||
NULL
|
||||
);
|
||||
|
||||
freq = leon3_up_counter_frequency();
|
||||
rtems_counter_initialize_converter(freq);
|
||||
} else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
|
||||
/* Use the interrupt controller timestamp counter if available */
|
||||
|
||||
/* Enable interrupt timestamping for an arbitrary interrupt line */
|
||||
irqmp_ts->control = 0x1;
|
||||
|
||||
_SPARC_Counter_initialize(
|
||||
(volatile const uint32_t *) &irqmp_ts->counter,
|
||||
timestamp_counter_difference
|
||||
_SPARC_Counter_read_address,
|
||||
_SPARC_Counter_difference_normal,
|
||||
(volatile const uint32_t *) &irqmp_ts->counter
|
||||
);
|
||||
|
||||
/* Get and set the frequency */
|
||||
rtems_counter_initialize_converter(
|
||||
ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev));
|
||||
} else if (LEON3_Timer_Regs != NULL) {
|
||||
/* Fall back to the first GPTIMER if available */
|
||||
freq = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
|
||||
freq = ambapp_freq_get(&ambapp_plb, LEON3_IrqCtrl_Adev);
|
||||
rtems_counter_initialize_converter(freq);
|
||||
} else if (gpt != NULL) {
|
||||
/* Fall back to the first GPTIMER if available */
|
||||
|
||||
gpt_counter_initialize(
|
||||
LEON3_Timer_Regs,
|
||||
LEON3_CLOCK_INDEX,
|
||||
freq / (LEON3_Timer_Regs->scaler_reload - 1),
|
||||
clock_counter_difference
|
||||
);
|
||||
_SPARC_Counter_initialize(
|
||||
_SPARC_Counter_read_address,
|
||||
_SPARC_Counter_difference_clock_period,
|
||||
(volatile const uint32_t *) &gpt->timer[LEON3_CLOCK_INDEX].value
|
||||
);
|
||||
|
||||
freq = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
|
||||
rtems_counter_initialize_converter(freq / (gpt->scaler_reload - 1));
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_SYSINIT_ITEM(
|
||||
leon3_counter_initialize,
|
||||
RTEMS_SYSINIT_BSP_START,
|
||||
RTEMS_SYSINIT_ORDER_THIRD
|
||||
);
|
||||
|
||||
SPARC_Counter _SPARC_Counter = {
|
||||
.counter_read = _SPARC_Counter_read_address,
|
||||
.counter_difference = _SPARC_Counter_difference_one,
|
||||
.counter_address = (uint32_t *) &_SPARC_Counter
|
||||
};
|
||||
|
||||
@@ -451,10 +451,12 @@ dont_do_the_window:
|
||||
subcc %l7, 1, %l7 ! outermost interrupt handler?
|
||||
bnz dont_switch_stacks ! No, then do not switch stacks
|
||||
|
||||
#if defined( RTEMS_PROFILING )
|
||||
sethi %hi(SYM(_SPARC_Counter)), %o5
|
||||
ld [%o5 + %lo(SYM(_SPARC_Counter))], %l4
|
||||
ld [%l4], %o5
|
||||
#if defined(RTEMS_PROFILING)
|
||||
sethi %hi(_SPARC_Counter), %o5
|
||||
ld [%o5 + %lo(_SPARC_Counter)], %l4
|
||||
call %l4, 0
|
||||
nop
|
||||
mov %o0, %o5
|
||||
#else
|
||||
nop
|
||||
#endif
|
||||
@@ -536,13 +538,15 @@ pil_fixed:
|
||||
! WAS LOADED WHEN ISF WAS SAVED!!!
|
||||
mov %l3, %o0 ! o0 = 1st arg = vector number
|
||||
call %g4, 0
|
||||
#if defined( RTEMS_PROFILING )
|
||||
#if defined(RTEMS_PROFILING)
|
||||
mov %o5, %l3 ! save interrupt entry instant
|
||||
cmp %l7, 0
|
||||
bne profiling_not_outer_most_exit
|
||||
nop
|
||||
ta SPARC_SWTRAP_IRQDIS ! Call interrupt disable trap handler
|
||||
ld [%l4], %o2 ! o2 = 3rd arg = interrupt exit instant
|
||||
call %l4, 0 ! Call _SPARC_Counter.counter_read
|
||||
nop
|
||||
mov %o0, %o2 ! o2 = 3rd arg = interrupt exit instant
|
||||
mov %l3, %o1 ! o1 = 2nd arg = interrupt entry instant
|
||||
call SYM(_Profiling_Outer_most_interrupt_entry_and_exit), 0
|
||||
mov %g6, %o0 ! o0 = 1st arg = per-CPU control
|
||||
|
||||
@@ -14,6 +14,7 @@ libscorecpu_a_SOURCES = cpu.c cpu_asm.S
|
||||
libscorecpu_a_SOURCES += sparc-context-volatile-clobber.S
|
||||
libscorecpu_a_SOURCES += sparc-context-validate.S
|
||||
libscorecpu_a_SOURCES += sparc-counter.c
|
||||
libscorecpu_a_SOURCES += sparc-counter-asm.S
|
||||
libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
include $(srcdir)/preinstall.am
|
||||
|
||||
@@ -1304,6 +1304,8 @@ static inline uint32_t CPU_swap_u32(
|
||||
|
||||
typedef uint32_t CPU_Counter_ticks;
|
||||
|
||||
typedef CPU_Counter_ticks ( *SPARC_Counter_read )( void );
|
||||
|
||||
typedef CPU_Counter_ticks (*SPARC_Counter_difference)(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
@@ -1311,46 +1313,57 @@ typedef CPU_Counter_ticks (*SPARC_Counter_difference)(
|
||||
|
||||
/*
|
||||
* The SPARC processors supported by RTEMS have no built-in CPU counter
|
||||
* support. We have to use some hardware counter module for this purpose. The
|
||||
* BSP must provide a 32-bit register which contains the current CPU counter
|
||||
* value and a function for the difference calculation. It can use for example
|
||||
* the GPTIMER instance used for the clock driver.
|
||||
* support. We have to use some hardware counter module for this purpose, for
|
||||
* example the GPTIMER instance used by the clock driver. The BSP must provide
|
||||
* an implementation of the CPU counter read and difference functions. This
|
||||
* allows the use of dynamic hardware enumeration.
|
||||
*/
|
||||
typedef struct {
|
||||
volatile const CPU_Counter_ticks *counter_register;
|
||||
SPARC_Counter_difference counter_difference;
|
||||
SPARC_Counter_read counter_read;
|
||||
SPARC_Counter_difference counter_difference;
|
||||
volatile const CPU_Counter_ticks *counter_address;
|
||||
} SPARC_Counter;
|
||||
|
||||
extern SPARC_Counter _SPARC_Counter;
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_read_address( void );
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_read_asr23( void );
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_normal(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
);
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
);
|
||||
|
||||
/*
|
||||
* Returns always a value of one regardless of the parameters. This prevents
|
||||
* an infinite loop in rtems_counter_delay_ticks(). Its only a reasonably safe
|
||||
* default.
|
||||
*/
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_default(
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_one(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
);
|
||||
|
||||
static inline bool _SPARC_Counter_is_default( void )
|
||||
{
|
||||
return _SPARC_Counter.counter_difference
|
||||
== _SPARC_Counter_difference_default;
|
||||
}
|
||||
|
||||
static inline void _SPARC_Counter_initialize(
|
||||
volatile const CPU_Counter_ticks *counter_register,
|
||||
SPARC_Counter_difference counter_difference
|
||||
SPARC_Counter_read counter_read,
|
||||
SPARC_Counter_difference counter_difference,
|
||||
volatile const CPU_Counter_ticks *counter_address
|
||||
)
|
||||
{
|
||||
_SPARC_Counter.counter_register = counter_register;
|
||||
_SPARC_Counter.counter_read = counter_read;
|
||||
_SPARC_Counter.counter_difference = counter_difference;
|
||||
_SPARC_Counter.counter_address = counter_address;
|
||||
}
|
||||
|
||||
static inline CPU_Counter_ticks _CPU_Counter_read( void )
|
||||
{
|
||||
return *_SPARC_Counter.counter_register;
|
||||
return ( *_SPARC_Counter.counter_read )();
|
||||
}
|
||||
|
||||
static inline CPU_Counter_ticks _CPU_Counter_difference(
|
||||
@@ -1358,7 +1371,7 @@ static inline CPU_Counter_ticks _CPU_Counter_difference(
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
{
|
||||
return (*_SPARC_Counter.counter_difference)( second, first );
|
||||
return ( *_SPARC_Counter.counter_difference )( second, first );
|
||||
}
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
34
cpukit/score/cpu/sparc/sparc-counter-asm.S
Normal file
34
cpukit/score/cpu/sparc/sparc-counter-asm.S
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/asm.h>
|
||||
|
||||
.section ".text"
|
||||
.align 4
|
||||
|
||||
PUBLIC(_SPARC_Counter_read_address)
|
||||
SYM(_SPARC_Counter_read_address):
|
||||
sethi %hi(_SPARC_Counter + 8), %o0
|
||||
ld [%o0 + %lo(_SPARC_Counter + 8)], %o0
|
||||
jmp %o7 + 8
|
||||
ld [%o0], %o0
|
||||
|
||||
PUBLIC(_SPARC_Counter_read_asr23)
|
||||
SYM(_SPARC_Counter_read_asr23):
|
||||
jmp %o7 + 8
|
||||
mov %asr23, %o0
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -17,18 +17,32 @@
|
||||
#endif
|
||||
|
||||
#include <rtems/score/cpu.h>
|
||||
#include <rtems/config.h>
|
||||
|
||||
static CPU_Counter_ticks _SPARC_Counter_register_dummy;
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_normal(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
{
|
||||
return second - first;
|
||||
}
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_default(
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_clock_period(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
{
|
||||
CPU_Counter_ticks period;
|
||||
|
||||
period = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
return ( first + period - second ) % period;
|
||||
}
|
||||
|
||||
CPU_Counter_ticks _SPARC_Counter_difference_one(
|
||||
CPU_Counter_ticks second,
|
||||
CPU_Counter_ticks first
|
||||
)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
SPARC_Counter _SPARC_Counter = {
|
||||
.counter_register = &_SPARC_Counter_register_dummy,
|
||||
.counter_difference = _SPARC_Counter_difference_default
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user