forked from Imagelibrary/rtems
bsp/leon3: Add LEON3_IRQAMP_PROBE_TIMESTAMP
This commit is contained in:
@@ -64,11 +64,29 @@
|
||||
/* LEON3 Timer system interrupt number */
|
||||
static int clkirq;
|
||||
|
||||
static void (*leon3_tc_tick)(void);
|
||||
|
||||
static struct timecounter leon3_tc;
|
||||
|
||||
#ifdef RTEMS_PROFILING
|
||||
static void leon3_tc_tick_default(void)
|
||||
{
|
||||
#if !defined(RTEMS_SMP)
|
||||
SPARC_Counter *counter;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
rtems_interrupt_local_disable(level);
|
||||
|
||||
grlib_store_32(&LEON3_IrqCtrl_Regs->iclear, counter->pending_mask);
|
||||
counter->accumulated += counter->interval;
|
||||
|
||||
rtems_interrupt_local_enable(level);
|
||||
#endif
|
||||
|
||||
rtems_timecounter_tick();
|
||||
}
|
||||
|
||||
#if defined(RTEMS_PROFILING)
|
||||
static void (*leon3_tc_tick)(void) = leon3_tc_tick_default;
|
||||
|
||||
#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
|
||||
|
||||
static void leon3_tc_tick_irqmp_timestamp(void)
|
||||
@@ -86,11 +104,9 @@ static void leon3_tc_tick_irqmp_timestamp(void)
|
||||
|
||||
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.
|
||||
@@ -117,32 +133,18 @@ static void leon3_tc_tick_irqmp_timestamp_init(void)
|
||||
if (done) {
|
||||
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
|
||||
}
|
||||
#endif
|
||||
|
||||
rtems_timecounter_tick();
|
||||
}
|
||||
|
||||
static void leon3_tc_tick_default(void)
|
||||
{
|
||||
#if !defined(RTEMS_SMP)
|
||||
SPARC_Counter *counter;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
rtems_interrupt_local_disable(level);
|
||||
|
||||
grlib_store_32(&LEON3_IrqCtrl_Regs->iclear, counter->pending_mask);
|
||||
counter->accumulated += counter->interval;
|
||||
|
||||
rtems_interrupt_local_enable(level);
|
||||
#endif
|
||||
|
||||
rtems_timecounter_tick();
|
||||
}
|
||||
#endif /* RTEMS_PROFILING */
|
||||
|
||||
static void leon3_tc_do_tick(void)
|
||||
{
|
||||
#if defined(RTEMS_PROFILING)
|
||||
(*leon3_tc_tick)();
|
||||
#else
|
||||
leon3_tc_tick_default();
|
||||
#endif
|
||||
}
|
||||
|
||||
#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
|
||||
@@ -185,9 +187,87 @@ static void bsp_clock_handler_install(rtems_interrupt_handler isr)
|
||||
#define Clock_driver_support_set_interrupt_affinity(online_processors) \
|
||||
bsp_interrupt_set_affinity(clkirq, online_processors)
|
||||
|
||||
static void leon3_clock_use_up_counter(struct timecounter *tc)
|
||||
{
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
|
||||
tc->tc_frequency = leon3_up_counter_frequency();
|
||||
|
||||
#if defined(RTEMS_PROFILING)
|
||||
if (irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs) == NULL) {
|
||||
bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
|
||||
}
|
||||
|
||||
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
|
||||
#endif
|
||||
|
||||
rtems_timecounter_install(tc);
|
||||
}
|
||||
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
static void leon3_clock_use_irqamp_timestamp(
|
||||
struct timecounter *tc,
|
||||
irqamp_timestamp *irqmp_ts
|
||||
)
|
||||
{
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_up;
|
||||
#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
|
||||
tc->tc_frequency = leon3_processor_local_bus_frequency();
|
||||
#else
|
||||
tc->tc_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev);
|
||||
#endif
|
||||
|
||||
#if defined(RTEMS_PROFILING)
|
||||
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* At least one TSISEL field must be non-zero to enable the timestamp
|
||||
* counter. Use an arbitrary interrupt source.
|
||||
*/
|
||||
grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
|
||||
|
||||
rtems_timecounter_install(tc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void leon3_clock_use_gptimer(
|
||||
struct timecounter *tc,
|
||||
gptimer_timer *timer
|
||||
)
|
||||
{
|
||||
#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. The timer is initialized by
|
||||
* leon3_counter_initialize().
|
||||
*/
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_down;
|
||||
#else
|
||||
SPARC_Counter *counter;
|
||||
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
|
||||
counter->read = _SPARC_Counter_read_clock;
|
||||
counter->counter_register = &timer->tcntval;
|
||||
counter->pending_register = &LEON3_IrqCtrl_Regs->ipend;
|
||||
counter->pending_mask = UINT32_C(1) << clkirq;
|
||||
counter->accumulated = rtems_configuration_get_microseconds_per_tick();
|
||||
counter->interval = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_clock;
|
||||
#endif
|
||||
|
||||
tc->tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
|
||||
|
||||
rtems_timecounter_install(tc);
|
||||
}
|
||||
|
||||
static void leon3_clock_initialize(void)
|
||||
{
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
irqamp_timestamp *irqmp_ts;
|
||||
#endif
|
||||
gptimer_timer *timer;
|
||||
struct timecounter *tc;
|
||||
|
||||
@@ -202,73 +282,29 @@ static void leon3_clock_initialize(void)
|
||||
GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS | GPTIMER_TCTRL_LD | GPTIMER_TCTRL_IE
|
||||
);
|
||||
|
||||
irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
|
||||
tc = &leon3_tc;
|
||||
tc->tc_counter_mask = 0xffffffff;
|
||||
tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
|
||||
|
||||
leon3_up_counter_enable();
|
||||
|
||||
if (leon3_up_counter_is_available()) {
|
||||
/* Use the LEON4 up-counter if available */
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
|
||||
tc->tc_frequency = leon3_up_counter_frequency();
|
||||
|
||||
#ifdef RTEMS_PROFILING
|
||||
if (irqmp_ts == NULL) {
|
||||
bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
|
||||
leon3_clock_use_up_counter(tc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
|
||||
} else if (irqmp_ts != NULL) {
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
|
||||
|
||||
if (irqmp_ts != NULL) {
|
||||
/* Use the interrupt controller timestamp counter if available */
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_up;
|
||||
#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
|
||||
tc->tc_frequency = leon3_processor_local_bus_frequency();
|
||||
#else
|
||||
tc->tc_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev);
|
||||
#endif
|
||||
|
||||
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.
|
||||
*/
|
||||
grlib_store_32(&irqmp_ts->itstmpc, IRQAMP_ITSTMPC_TSISEL(1));
|
||||
} 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.
|
||||
*/
|
||||
grlib_store_32(
|
||||
&LEON3_Timer_Regs->timer[LEON3_COUNTER_GPTIMER_INDEX].tctrl,
|
||||
GPTIMER_TCTRL_EN | GPTIMER_TCTRL_IE
|
||||
);
|
||||
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_down;
|
||||
#else
|
||||
SPARC_Counter *counter;
|
||||
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
|
||||
counter->read = _SPARC_Counter_read_clock;
|
||||
counter->counter_register = &timer->tcntval;
|
||||
counter->pending_register = grlib_load_32(&LEON3_IrqCtrl_Regs->ipend);
|
||||
counter->pending_mask = UINT32_C(1) << clkirq;
|
||||
counter->accumulated = rtems_configuration_get_microseconds_per_tick();
|
||||
counter->interval = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
tc->tc_get_timecount = _SPARC_Get_timecount_clock;
|
||||
#endif
|
||||
|
||||
tc->tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
|
||||
leon3_tc_tick = leon3_tc_tick_default;
|
||||
leon3_clock_use_irqamp_timestamp(tc, irqmp_ts);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
tc->tc_counter_mask = 0xffffffff;
|
||||
tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
|
||||
rtems_timecounter_install(tc);
|
||||
leon3_clock_use_gptimer(tc, timer);
|
||||
}
|
||||
|
||||
#define Clock_driver_support_initialize_hardware() \
|
||||
|
||||
@@ -39,26 +39,20 @@ uint32_t _CPU_Counter_frequency(void)
|
||||
return leon3_counter_frequency;
|
||||
}
|
||||
|
||||
static void leon3_counter_initialize(void)
|
||||
static void leon3_counter_use_up_counter(SPARC_Counter *counter)
|
||||
{
|
||||
irqamp_timestamp *irqmp_ts;
|
||||
gptimer *gpt;
|
||||
SPARC_Counter *counter;
|
||||
|
||||
irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
|
||||
gpt = LEON3_Timer_Regs;
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
|
||||
leon3_up_counter_enable();
|
||||
|
||||
if (leon3_up_counter_is_available()) {
|
||||
/* Use the LEON4 up-counter if available */
|
||||
counter->read_isr_disabled = _SPARC_Counter_read_asr23;
|
||||
counter->read = _SPARC_Counter_read_asr23;
|
||||
|
||||
leon3_counter_frequency = leon3_up_counter_frequency();
|
||||
} else if (irqmp_ts != NULL) {
|
||||
/* Use the interrupt controller timestamp counter if available */
|
||||
}
|
||||
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
static void leon3_counter_use_irqamp_timestamp(
|
||||
SPARC_Counter *counter,
|
||||
irqamp_timestamp *irqmp_ts
|
||||
)
|
||||
{
|
||||
counter->read_isr_disabled = _SPARC_Counter_read_up;
|
||||
counter->read = _SPARC_Counter_read_up;
|
||||
counter->counter_register = &irqmp_ts->itcnt;
|
||||
@@ -71,21 +65,21 @@ static void leon3_counter_initialize(void)
|
||||
#else
|
||||
leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_IrqCtrl_Adev);
|
||||
#endif
|
||||
} else if (gpt != NULL) {
|
||||
gptimer_timer *timer;
|
||||
uint32_t tctrl;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void leon3_counter_use_gptimer(SPARC_Counter *counter, gptimer *gpt)
|
||||
{
|
||||
gptimer_timer *timer;
|
||||
|
||||
/* Fall back to the first GPTIMER if available */
|
||||
timer = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX];
|
||||
counter->read_isr_disabled = _SPARC_Counter_read_down;
|
||||
counter->read = _SPARC_Counter_read_down;
|
||||
counter->counter_register = &timer->tcntval;
|
||||
|
||||
/* Enable timer just in case no clock driver is configured */
|
||||
/* Make timer free running */
|
||||
grlib_store_32(&timer->trldval, 0xffffffff);
|
||||
tctrl = grlib_load_32(&timer->tctrl);
|
||||
tctrl |= GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS | GPTIMER_TCTRL_LD;
|
||||
grlib_store_32(&timer->tctrl, tctrl);
|
||||
grlib_store_32(&timer->tctrl, GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS);
|
||||
|
||||
#if defined(LEON3_PLB_FREQUENCY_DEFINED_BY_GPTIMER)
|
||||
leon3_counter_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
|
||||
@@ -93,6 +87,41 @@ static void leon3_counter_initialize(void)
|
||||
leon3_counter_frequency = ambapp_freq_get(ambapp_plb(), LEON3_Timer_Adev) /
|
||||
(grlib_load_32(&gpt->sreload) + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void leon3_counter_initialize(void)
|
||||
{
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
irqamp_timestamp *irqmp_ts;
|
||||
#endif
|
||||
gptimer *gpt;
|
||||
SPARC_Counter *counter;
|
||||
|
||||
counter = &_SPARC_Counter_mutable;
|
||||
|
||||
leon3_up_counter_enable();
|
||||
|
||||
if (leon3_up_counter_is_available()) {
|
||||
/* Use the LEON4 up-counter if available */
|
||||
leon3_counter_use_up_counter(counter);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(LEON3_IRQAMP_PROBE_TIMESTAMP)
|
||||
irqmp_ts = irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
|
||||
|
||||
if (irqmp_ts != NULL) {
|
||||
/* Use the interrupt controller timestamp counter if available */
|
||||
leon3_counter_use_irqamp_timestamp(counter, irqmp_ts);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
gpt = LEON3_Timer_Regs;
|
||||
|
||||
if (gpt != NULL) {
|
||||
/* Fall back to the first GPTIMER if available */
|
||||
leon3_counter_use_gptimer(counter, gpt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ links:
|
||||
uid: optgptimerbase
|
||||
- role: build-dependency
|
||||
uid: optirqampbase
|
||||
- role: build-dependency
|
||||
uid: optirqampts
|
||||
- role: build-dependency
|
||||
uid: optconirq
|
||||
- role: build-dependency
|
||||
|
||||
24
spec/build/bsps/sparc/leon3/optirqampts.yml
Normal file
24
spec/build/bsps/sparc/leon3/optirqampts.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
copyrights:
|
||||
- Copyright (C) 2021 embedded brains GmbH & Co. KG
|
||||
actions:
|
||||
- get-boolean: null
|
||||
- define-condition: null
|
||||
build-type: option
|
||||
default:
|
||||
- enabled-by:
|
||||
- sparc/gr712rc
|
||||
- sparc/gr740
|
||||
- sparc/ut699
|
||||
- sparc/ut700
|
||||
value: false
|
||||
- enabled-by: true
|
||||
value: true
|
||||
enabled-by: true
|
||||
links: []
|
||||
name: LEON3_IRQAMP_PROBE_TIMESTAMP
|
||||
description: |
|
||||
If this option is set to true, then the interrupt timestamping feature of the
|
||||
IRQ(A)MP is probed. If it is available, then it may be used for the CPU
|
||||
counter and interrupt profiling.
|
||||
type: build
|
||||
Reference in New Issue
Block a user