Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.4 YOPAN-165 and YOPAN-168 #1958

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ config ARM_ON_ENTER_CPU_IDLE_HOOK
If needed, this hook can be used to prevent the CPU from actually
entering sleep by skipping the WFE/WFI instruction.

config ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK
bool
help
Enables a hook (z_arm_on_enter_cpu_idle_prepare()) that is called when
the CPU is made idle (by k_cpu_idle() or k_cpu_atomic_idle()).
If needed, this hook can prepare data to upcoming call to
z_arm_on_enter_cpu_idle(). The z_arm_on_enter_cpu_idle_prepare differs
from z_arm_on_enter_cpu_idle because it is called before interrupts are
disabled.

config ARM_ON_EXIT_CPU_IDLE
bool
help
Expand Down
25 changes: 20 additions & 5 deletions arch/arm/core/aarch32/cpu_idle.S
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,24 @@ _skip_\@:
.endm

SECTION_FUNC(TEXT, arch_cpu_idle)
#ifdef CONFIG_TRACING
#if defined(CONFIG_TRACING) || \
defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK)
push {r0, lr}

#ifdef CONFIG_TRACING
bl sys_trace_idle
#endif
#ifdef CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK
bl z_arm_on_enter_cpu_idle_prepare
#endif

#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
pop {r0, r1}
mov lr, r1
#else
pop {r0, lr}
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
#endif /* CONFIG_TRACING */
#endif

#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
/*
Expand Down Expand Up @@ -138,17 +146,24 @@ SECTION_FUNC(TEXT, arch_cpu_idle)
bx lr

SECTION_FUNC(TEXT, arch_cpu_atomic_idle)
#ifdef CONFIG_TRACING
#if defined(CONFIG_TRACING) || \
defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK)
push {r0, lr}

#ifdef CONFIG_TRACING
bl sys_trace_idle
#endif
#ifdef CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK
bl z_arm_on_enter_cpu_idle_prepare
#endif

#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
pop {r0, r1}
mov lr, r1
#else
pop {r0, lr}
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
#endif /* CONFIG_TRACING */

#endif
/*
* Lock PRIMASK while sleeping: wfe will still get interrupted by
* incoming interrupts but the CPU will not service them right away.
Expand Down
1 change: 1 addition & 0 deletions drivers/timer/Kconfig.nrf_rtc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ if NRF_RTC_TIMER

config NRF_RTC_TIMER_USER_CHAN_COUNT
int "Additional channels that can be used"
default 2 if NRF_802154_RADIO_DRIVER && SOC_NRF5340_CPUNET
default 3 if NRF_802154_RADIO_DRIVER
default 0
help
Expand Down
72 changes: 57 additions & 15 deletions drivers/timer/nrf_rtc_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@
#include <hal/nrf_rtc.h>
#include <zephyr/irq.h>

#define RTC_PRETICK (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && \
IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET))

#define EXT_CHAN_COUNT CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT
#define CHAN_COUNT (EXT_CHAN_COUNT + 1)

#define RTC NRF_RTC1
#define RTC_IRQn NRFX_IRQ_NUMBER_GET(RTC)
#define RTC_LABEL rtc1
#define RTC_CH_COUNT RTC1_CC_NUM
#define CHAN_COUNT_MAX (RTC1_CC_NUM - (RTC_PRETICK ? 1 : 0))

BUILD_ASSERT(CHAN_COUNT <= RTC_CH_COUNT, "Not enough compare channels");
BUILD_ASSERT(CHAN_COUNT <= CHAN_COUNT_MAX, "Not enough compare channels");
/* Ensure that counter driver for RTC1 is not enabled. */
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled),
"Counter for RTC1 must be disabled");
Expand All @@ -43,6 +46,8 @@ BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled),
#define ANCHOR_RANGE_END (7 * COUNTER_SPAN / 8)
#define TARGET_TIME_INVALID (UINT64_MAX)

extern void rtc_pretick_rtc1_isr_hook(void);

static volatile uint32_t overflow_cnt;
static volatile uint64_t anchor;
static uint64_t last_count;
Expand Down Expand Up @@ -231,9 +236,20 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t)
* @param[in] chan A channel for which a new CC value is to be set.
*
* @param[in] req_cc Requested CC register value to be set.
*
* @param[in] exact Use @c false to allow CC adjustment if @c req_cc value is
* close to the current value of the timer.
* Use @c true to disallow CC adjustment. The function can
* fail with -EINVAL result if @p req_cc is too close to the
* current value.
*
* @retval 0 The requested CC has been set successfully.
* @retval -EINVAL The requested CC value could not be reliably set.
*/
static void set_alarm(int32_t chan, uint32_t req_cc)
static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
{
int ret = 0;

/* Ensure that the value exposed in this driver API is consistent with
* assumptions of this function.
*/
Expand Down Expand Up @@ -300,9 +316,16 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
now = counter();
if (counter_sub(now, req_cc) > COUNTER_HALF_SPAN) {
event_clear(chan);
if (exact) {
ret = -EINVAL;
break;
}
} else {
break;
}
} else if (exact) {
ret = -EINVAL;
break;
}

cc_val = now + cc_inc;
Expand All @@ -311,11 +334,13 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
break;
}
}

return ret;
}

static int compare_set_nolocks(int32_t chan, uint64_t target_time,
z_nrf_rtc_timer_compare_handler_t handler,
void *user_data)
void *user_data, bool exact)
{
int ret = 0;
uint32_t cc_value = absolute_time_to_cc(target_time);
Expand All @@ -331,29 +356,33 @@ static int compare_set_nolocks(int32_t chan, uint64_t target_time,
/* Target time is valid and is different than currently set.
* Set CC value.
*/
set_alarm(chan, cc_value);
ret = set_alarm(chan, cc_value, exact);
}
} else {
} else if (!exact) {
/* Force ISR handling when exiting from critical section. */
atomic_or(&force_isr_mask, BIT(chan));
} else {
ret = -EINVAL;
}

cc_data[chan].target_time = target_time;
cc_data[chan].callback = handler;
cc_data[chan].user_context = user_data;
if (ret == 0) {
cc_data[chan].target_time = target_time;
cc_data[chan].callback = handler;
cc_data[chan].user_context = user_data;
}

return ret;
}

static int compare_set(int32_t chan, uint64_t target_time,
z_nrf_rtc_timer_compare_handler_t handler,
void *user_data)
void *user_data, bool exact)
{
bool key;

key = compare_int_lock(chan);

int ret = compare_set_nolocks(chan, target_time, handler, user_data);
int ret = compare_set_nolocks(chan, target_time, handler, user_data, exact);

compare_int_unlock(chan, key);

Expand All @@ -366,7 +395,16 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
{
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);

return compare_set(chan, target_time, handler, user_data);
return compare_set(chan, target_time, handler, user_data, false);
}

int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
z_nrf_rtc_timer_compare_handler_t handler,
void *user_data)
{
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);

return compare_set(chan, target_time, handler, user_data, true);
}

void z_nrf_rtc_timer_abort(int32_t chan)
Expand Down Expand Up @@ -447,7 +485,7 @@ static void sys_clock_timeout_handler(int32_t chan,
* so it won't get preempted by the interrupt.
*/
compare_set(chan, last_count + CYC_PER_TICK,
sys_clock_timeout_handler, NULL);
sys_clock_timeout_handler, NULL, false);
}

sys_clock_announce(dticks);
Expand Down Expand Up @@ -525,6 +563,10 @@ void rtc_nrf_isr(const void *arg)
{
ARG_UNUSED(arg);

if (RTC_PRETICK) {
rtc_pretick_rtc1_isr_hook();
}

if (nrf_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) &&
nrf_rtc_event_check(RTC, NRF_RTC_EVENT_OVERFLOW)) {
nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_OVERFLOW);
Expand Down Expand Up @@ -643,7 +685,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)

uint64_t target_time = cyc + last_count;

compare_set(0, target_time, sys_clock_timeout_handler, NULL);
compare_set(0, target_time, sys_clock_timeout_handler, NULL, false);
}

uint32_t sys_clock_elapsed(void)
Expand Down Expand Up @@ -721,7 +763,7 @@ static int sys_clock_driver_init(void)
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
MAX_CYCLES : CYC_PER_TICK;

compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL);
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false);

z_nrf_clock_control_lf_on(mode);

Expand Down
9 changes: 9 additions & 0 deletions include/zephyr/arch/arm/aarch32/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ extern bool z_arm_thread_is_in_user_mode(void);
bool z_arm_on_enter_cpu_idle(void);
#endif

#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_PREPARE_HOOK)
/* Prototype of a hook that can be enabled to be called every time the CPU is
* made idle (the calls will be done from k_cpu_idle() and k_cpu_atomic_idle()).
* The function is called before interrupts are disabled and can prepare to
* upcoming call to z_arm_on_enter_cpu_idle.
*/
void z_arm_on_enter_cpu_idle_prepare(void);
#endif

#endif

#ifdef __cplusplus
Expand Down
31 changes: 31 additions & 0 deletions include/zephyr/drivers/timer/nrf_rtc_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,42 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan);
* @retval 0 if the compare channel was set successfully.
* @retval -EINVAL if provided target time was further than
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future.
*
* @sa @ref z_nrf_rtc_timer_exact_set
*/
int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
z_nrf_rtc_timer_compare_handler_t handler,
void *user_data);

/** @brief Try to set compare channel exactly to given value.
*
* @note This function is similar to @ref z_nrf_rtc_timer_set, but the compare
* channel will be set to expected value only when it can be guaranteed that
* the hardware event will be generated exactly at expected @c target_time in
* the future. If the @c target_time is in the past or so close in the future
* that the reliable generation of event would require adjustment of compare
* value (as would @ref z_nrf_rtc_timer_set function do), neither the hardware
* event nor interrupt will be generated and the function fails.
*
* @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT.
*
* @param target_time Absolute target time in ticks.
*
* @param handler User function called in the context of the RTC interrupt.
*
* @param user_data Data passed to the handler.
*
* @retval 0 if the compare channel was set successfully.
* @retval -EINVAL if provided target time was further than
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future
* or the target time is in the past or is so close in the future that
* event generation could not be guaranteed without adjusting
* compare value of that channel.
*/
int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
z_nrf_rtc_timer_compare_handler_t handler,
void *user_data);

/** @brief Abort a timer requested with @ref z_nrf_rtc_timer_set.
*
* If an abort operation is performed too late it is still possible for an event
Expand Down
47 changes: 47 additions & 0 deletions include/zephyr/sys/barrier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SYS_BARRIER_H_
#define ZEPHYR_INCLUDE_SYS_BARRIER_H_

#include <zephyr/toolchain.h>

#if defined(CONFIG_BARRIER_OPERATIONS_ARCH)
/* Empty */
#elif defined(CONFIG_BARRIER_OPERATIONS_BUILTIN)
#include <zephyr/sys/barrier_builtin.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @addtogroup barrier_apis Barrier Services APIs
* @ingroup kernel_apis
* @{
*/

/**
* @brief Full/sequentially-consistent data memory barrier.
*
* This routine acts as a synchronization fence between threads and prevents
* re-ordering of data accesses instructions across the barrier instruction.
*/
static ALWAYS_INLINE void barrier_dmem_fence_full(void)
{
#if defined(CONFIG_BARRIER_OPERATIONS_ARCH) || defined(CONFIG_BARRIER_OPERATIONS_BUILTIN)
z_barrier_dmem_fence_full();
#endif
}

/** @} */

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
29 changes: 29 additions & 0 deletions include/zephyr/sys/barrier_builtin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SYS_BARRIER_BUILTIN_H_
#define ZEPHYR_INCLUDE_SYS_BARRIER_BUILTIN_H_

#ifndef ZEPHYR_INCLUDE_SYS_BARRIER_H_
#error Please include <zephyr/sys/barrier.h>
#endif

#include <zephyr/toolchain.h>

#ifdef __cplusplus
extern "C" {
#endif

static ALWAYS_INLINE void z_barrier_dmem_fence_full(void)
{
__atomic_thread_fence(__ATOMIC_SEQ_CST);
}

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_SYS_BARRIER_BUILTIN_H_ */
Loading
Loading