modules: hal_nordic: move IronSide SE supporting code to hal_nordic
Move most of the code that is used to interface with IronSide SE on the nRF54H20/nRF9280 from the soc/nordic directory to the hal_nordic repository. The interface code is now provided by the new IronSide support package. Build system code and glue code that makes use of Zephyr APIs is now located in the modules/hal_nordic directory. Update the directory path for IronSide SE interface code in MAINTAINERS.yml to match the move from soc/nordic/ironside to modules/hal_nordic/ironside. Also included are some refactoring changes and cleanup to match the new supporting code. C code and Kconfigs have been renamed to *ironside_se* / *IRONSIDE_SE* to match the supporting code changes. Users of these APIs in zephyr have been updated to match. Individual configurations for different "IronSide services" have been removed as the API serialization for all of these is now provided in a single C file / header file (ironside/se/api.h). The ironside_boot_report_get() API has been removed. The boot report structure can be accessed through the IRONSIDE_SE_BOOT_REPORT macro. Most configs relating to UICR / PERIPHCONF have been moved under the "IronSide SE" menu to make it clear that these are part of the IronSide SE interface. The macros that in uicr.h that were used to add entries to the PERIPHCONF section have been removed. The supporting code now provides PERIPHCONF_XYZ() macros that can be used to initialize structures that go into this section, and the zephyr part now only contains a macro UICR_PERIPHCONF_ENTRY() that is used to place an arbitrary structure into the section. The gen_periphconf_entries.py script used to generate PERIPHCONF entries based on devicetree has been updated to use the new macro system. IronSide SE integration code/configs is now guarded by HAS_IRONSIDE_SE. Note that the UICR build system integration that relies on Sysbuild remains under the soc/nordic directory for now, but will be moved to the modules/hal_nordic directory once it is clear how the integration will look there. Signed-off-by: Jonathan Nilsen <jonathan.nilsen@nordicsemi.no>
This commit is contained in:
committed by
Maureen Helm
parent
2c934f1dd8
commit
ef587e12f6
@@ -6417,7 +6417,7 @@ nRF IronSide SE Platforms:
|
||||
- karstenkoenig
|
||||
- SebastianBoe
|
||||
files:
|
||||
- soc/nordic/ironside/
|
||||
- modules/hal_nordic/ironside/
|
||||
- soc/nordic/common/uicr/
|
||||
labels:
|
||||
- "platform: nRF IronSide SE"
|
||||
|
||||
@@ -290,7 +290,7 @@ endif # CLOCK_CONTROL_NRF_HSFLL_LOCAL
|
||||
config CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL
|
||||
bool "NRF IronSide HSFLL LOCAL driver support"
|
||||
depends on DT_HAS_NORDIC_NRF_IRON_HSFLL_LOCAL_ENABLED
|
||||
select NRF_IRONSIDE_DVFS_SERVICE
|
||||
select IRONSIDE_SE_DVFS
|
||||
select CLOCK_CONTROL_NRF2_COMMON
|
||||
default y
|
||||
|
||||
|
||||
@@ -14,31 +14,31 @@ LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
|
||||
|
||||
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported");
|
||||
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#include <nrf_ironside/dvfs.h>
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
#include <ironside_zephyr/se/dvfs.h>
|
||||
|
||||
#define HSFLL_FREQ_LOW MHZ(64)
|
||||
#define HSFLL_FREQ_MEDLOW MHZ(128)
|
||||
#define HSFLL_FREQ_HIGH MHZ(320)
|
||||
|
||||
#define IRONSIDE_DVFS_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_DVFS_TIMEOUT_MS)
|
||||
#define IRONSIDE_SE_DVFS_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_DVFS_TIMEOUT_MS)
|
||||
|
||||
/* Clock options sorted from lowest to highest frequency */
|
||||
static const struct clock_options {
|
||||
uint32_t frequency;
|
||||
enum ironside_dvfs_oppoint setting;
|
||||
enum ironside_se_dvfs_oppoint setting;
|
||||
} clock_options[] = {
|
||||
{
|
||||
.frequency = HSFLL_FREQ_LOW,
|
||||
.setting = IRONSIDE_DVFS_OPP_LOW,
|
||||
.setting = IRONSIDE_SE_DVFS_OPP_LOW,
|
||||
},
|
||||
{
|
||||
.frequency = HSFLL_FREQ_MEDLOW,
|
||||
.setting = IRONSIDE_DVFS_OPP_MEDLOW,
|
||||
.setting = IRONSIDE_SE_DVFS_OPP_MEDLOW,
|
||||
},
|
||||
{
|
||||
.frequency = HSFLL_FREQ_HIGH,
|
||||
.setting = IRONSIDE_DVFS_OPP_HIGH,
|
||||
.setting = IRONSIDE_SE_DVFS_OPP_HIGH,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -57,17 +57,17 @@ static void hsfll_update_timeout_handler(struct k_timer *timer)
|
||||
static void hsfll_work_handler(struct k_work *work)
|
||||
{
|
||||
struct hsfll_dev_data *dev_data = CONTAINER_OF(work, struct hsfll_dev_data, clk_cfg.work);
|
||||
enum ironside_dvfs_oppoint required_setting;
|
||||
enum ironside_se_dvfs_oppoint required_setting;
|
||||
uint8_t to_activate_idx;
|
||||
int rc;
|
||||
|
||||
to_activate_idx = clock_config_update_begin(work);
|
||||
required_setting = clock_options[to_activate_idx].setting;
|
||||
|
||||
k_timer_start(&dev_data->timer, IRONSIDE_DVFS_TIMEOUT, K_NO_WAIT);
|
||||
k_timer_start(&dev_data->timer, IRONSIDE_SE_DVFS_TIMEOUT, K_NO_WAIT);
|
||||
|
||||
/* Request the DVFS service to change the OPP point. */
|
||||
rc = ironside_dvfs_change_oppoint(required_setting);
|
||||
rc = ironside_se_dvfs_change_oppoint(required_setting);
|
||||
k_timer_stop(&dev_data->timer);
|
||||
clock_config_update_end(&dev_data->clk_cfg, rc);
|
||||
}
|
||||
@@ -123,12 +123,12 @@ static struct onoff_manager *hsfll_find_mgr_by_spec(const struct device *dev,
|
||||
idx = hsfll_resolve_spec_to_idx(spec);
|
||||
return idx < 0 ? NULL : hsfll_get_mgr_by_idx(dev, idx);
|
||||
}
|
||||
#endif /* CONFIG_NRF_IRONSIDE_DVFS_SERVICE */
|
||||
#endif /* CONFIG_IRONSIDE_SE_DVFS */
|
||||
|
||||
static int api_request_hsfll(const struct device *dev, const struct nrf_clock_spec *spec,
|
||||
struct onoff_client *cli)
|
||||
{
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec);
|
||||
|
||||
if (mgr) {
|
||||
@@ -143,7 +143,7 @@ static int api_request_hsfll(const struct device *dev, const struct nrf_clock_sp
|
||||
|
||||
static int api_release_hsfll(const struct device *dev, const struct nrf_clock_spec *spec)
|
||||
{
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec);
|
||||
|
||||
if (mgr) {
|
||||
@@ -159,7 +159,7 @@ static int api_release_hsfll(const struct device *dev, const struct nrf_clock_sp
|
||||
static int api_cancel_or_release_hsfll(const struct device *dev, const struct nrf_clock_spec *spec,
|
||||
struct onoff_client *cli)
|
||||
{
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec);
|
||||
|
||||
if (mgr) {
|
||||
@@ -175,7 +175,7 @@ static int api_cancel_or_release_hsfll(const struct device *dev, const struct nr
|
||||
static int api_resolve_hsfll(const struct device *dev, const struct nrf_clock_spec *req_spec,
|
||||
struct nrf_clock_spec *res_spec)
|
||||
{
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
int idx;
|
||||
|
||||
idx = hsfll_resolve_spec_to_idx(req_spec);
|
||||
@@ -192,7 +192,7 @@ static int api_resolve_hsfll(const struct device *dev, const struct nrf_clock_sp
|
||||
|
||||
static int hsfll_init(const struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
struct hsfll_dev_data *dev_data = dev->data;
|
||||
int rc;
|
||||
|
||||
@@ -220,14 +220,14 @@ static DEVICE_API(nrf_clock_control, hsfll_drv_api) = {
|
||||
.resolve = api_resolve_hsfll,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE
|
||||
#ifdef CONFIG_IRONSIDE_SE_DVFS
|
||||
static struct hsfll_dev_data hsfll_data;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_REQ_LOW_FREQ
|
||||
static int dvfs_low_init(void)
|
||||
{
|
||||
static const k_timeout_t timeout = IRONSIDE_DVFS_TIMEOUT;
|
||||
static const k_timeout_t timeout = IRONSIDE_SE_DVFS_TIMEOUT;
|
||||
static const struct device *hsfll_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_NODELABEL(cpu)));
|
||||
static const struct nrf_clock_spec clk_spec = {.frequency = HSFLL_FREQ_LOW};
|
||||
|
||||
@@ -238,7 +238,7 @@ SYS_INIT(dvfs_low_init, APPLICATION, 0);
|
||||
#endif
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, hsfll_init, NULL,
|
||||
COND_CODE_1(CONFIG_NRF_IRONSIDE_DVFS_SERVICE,
|
||||
COND_CODE_1(CONFIG_IRONSIDE_SE_DVFS,
|
||||
(&hsfll_data),
|
||||
(NULL)), NULL, PRE_KERNEL_1,
|
||||
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &hsfll_drv_api);
|
||||
|
||||
@@ -117,7 +117,7 @@ menuconfig DEBUG_CORESIGHT_NRF
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_CORESIGHT_NRF_ENABLED
|
||||
select PINCTRL
|
||||
select NRF_IRONSIDE_TDD_SERVICE
|
||||
select IRONSIDE_SE_CALL
|
||||
help
|
||||
Support CoreSight peripherals in Test and Debug Domain for ARM
|
||||
CoreSight System Trace Macrocell (STM) trace support.
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/sys_io.h>
|
||||
#include <nrf_ironside/tdd.h>
|
||||
#include <uicr/uicr.h>
|
||||
#include <ironside/se/api.h>
|
||||
#include <ironside_zephyr/se/uicr_periphconf.h>
|
||||
|
||||
#undef ETR_MODE_MODE_CIRCULARBUF
|
||||
|
||||
@@ -262,7 +262,7 @@ static int coresight_nrf_init(const struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEBUG_CORESIGHT_NRF_INIT_PRIORITY UTIL_INC(CONFIG_NRF_IRONSIDE_CALL_INIT_PRIORITY)
|
||||
#define DEBUG_CORESIGHT_NRF_INIT_PRIORITY UTIL_INC(CONFIG_IRONSIDE_SE_CALL_INIT_PRIORITY)
|
||||
|
||||
#define CORESIGHT_NRF_INST(inst) \
|
||||
COND_CODE_1(DT_INST_PINCTRL_HAS_IDX(inst, 0), \
|
||||
|
||||
@@ -792,7 +792,7 @@ int etr_process_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NRF_ETR_INIT_PRIORITY UTIL_INC(UTIL_INC(CONFIG_NRF_IRONSIDE_CALL_INIT_PRIORITY))
|
||||
#define NRF_ETR_INIT_PRIORITY UTIL_INC(UTIL_INC(CONFIG_IRONSIDE_SE_CALL_INIT_PRIORITY))
|
||||
|
||||
SYS_INIT(etr_process_init, POST_KERNEL, NRF_ETR_INIT_PRIORITY);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ if(CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION)
|
||||
add_subdirectory(nrf_802154)
|
||||
endif(CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION)
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_HAS_IRONSIDE_SE ironside/se)
|
||||
add_subdirectory_ifdef(CONFIG_HAS_NRFX nrfx)
|
||||
add_subdirectory_ifdef(CONFIG_HAS_NRFS nrfs)
|
||||
|
||||
|
||||
@@ -258,6 +258,7 @@ endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION
|
||||
|
||||
endmenu # HAS_NORDIC_DRIVERS
|
||||
|
||||
rsource "ironside/se/Kconfig"
|
||||
rsource "nrfs/Kconfig"
|
||||
rsource "nrfx/Kconfig"
|
||||
rsource "Kconfig.nrf_regtool"
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# The IronSide source directory can be overridden by setting
|
||||
# IRONSIDE_SUPPORT_DIR before invoking the build system.
|
||||
zephyr_get(IRONSIDE_SUPPORT_DIR SYSBUILD GLOBAL)
|
||||
if(NOT DEFINED IRONSIDE_SUPPORT_DIR)
|
||||
set(IRONSIDE_SUPPORT_DIR
|
||||
${ZEPHYR_CURRENT_MODULE_DIR}/ironside CACHE PATH "IronSide Support Directory"
|
||||
)
|
||||
endif()
|
||||
|
||||
zephyr_include_directories(include)
|
||||
zephyr_include_directories(${IRONSIDE_SUPPORT_DIR}/se/include)
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_property(ALLOW_EMPTY TRUE)
|
||||
zephyr_library_sources_ifdef(CONFIG_IRONSIDE_SE_CALL
|
||||
${IRONSIDE_SUPPORT_DIR}/se/src/ironside_se_api.c
|
||||
call.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_IRONSIDE_SE_DVFS dvfs.c)
|
||||
|
||||
if(CONFIG_NRF_PERIPHCONF_SECTION)
|
||||
zephyr_linker_sources(SECTIONS uicr.ld)
|
||||
endif()
|
||||
@@ -10,7 +30,7 @@ if(CONFIG_NRF_PERIPHCONF_GENERATE_ENTRIES)
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env ZEPHYR_BASE=${ZEPHYR_BASE}
|
||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/gen_periphconf_entries.py
|
||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/scripts/gen_periphconf_entries.py
|
||||
--soc ${CONFIG_SOC}
|
||||
--in-edt-pickle ${EDT_PICKLE}
|
||||
--out-periphconf-source ${periphconf_entries_c_file}
|
||||
66
modules/hal_nordic/ironside/se/Kconfig
Normal file
66
modules/hal_nordic/ironside/se/Kconfig
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config HAS_IRONSIDE_SE
|
||||
bool
|
||||
|
||||
menu "IronSide SE"
|
||||
depends on HAS_IRONSIDE_SE
|
||||
|
||||
config IRONSIDE_SE_CALL
|
||||
bool "IronSide calls"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_IRONSIDE_CALL_ENABLED
|
||||
depends on MULTITHREADING
|
||||
select EVENTS
|
||||
select MBOX
|
||||
help
|
||||
Support for IronSide call APIs.
|
||||
|
||||
if IRONSIDE_SE_CALL
|
||||
|
||||
config IRONSIDE_SE_CALL_INIT_PRIORITY
|
||||
int "IronSide calls' driver initialization priority"
|
||||
default 41
|
||||
help
|
||||
Initialization priority of the IronSide call protocol driver.
|
||||
It must be below MBOX_INIT_PRIORITY, but higher than the priority of any feature
|
||||
that depends on IRONSIDE_SE_CALL.
|
||||
|
||||
endif # IRONSIDE_SE_CALL
|
||||
|
||||
config IRONSIDE_SE_DVFS
|
||||
bool "DVFS support"
|
||||
depends on SOC_NRF54H20_CPUAPP
|
||||
depends on IRONSIDE_SE_CALL
|
||||
help
|
||||
Support for changing the DVFS operating point.
|
||||
|
||||
if IRONSIDE_SE_DVFS
|
||||
|
||||
config IRONSIDE_SE_DVFS_ABB_STATUSANA_CHECK_MAX_ATTEMPTS
|
||||
int "ABB analog status check maximum attempts"
|
||||
range 0 255
|
||||
default 50
|
||||
help
|
||||
Maximum attempts with 10us intervals before busy status will be reported.
|
||||
|
||||
endif # IRONSIDE_SE_DVFS
|
||||
|
||||
menuconfig NRF_PERIPHCONF_SECTION
|
||||
bool "Global peripheral initialization section"
|
||||
depends on LINKER_DEVNULL_SUPPORT
|
||||
imply LINKER_DEVNULL_MEMORY
|
||||
help
|
||||
Include static global domain peripheral initialization values from the
|
||||
build in a dedicated section in the devnull region.
|
||||
|
||||
config NRF_PERIPHCONF_GENERATE_ENTRIES
|
||||
bool "Generate PERIPHCONF entries source file"
|
||||
default y
|
||||
depends on NRF_PERIPHCONF_SECTION
|
||||
help
|
||||
Generate a C file containing PERIPHCONF entries based on the
|
||||
device configuration in the devicetree.
|
||||
|
||||
endmenu # IronSide SE
|
||||
@@ -3,7 +3,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <nrf_ironside/call.h>
|
||||
#include <ironside/se/call.h>
|
||||
#include <ironside/se/glue.h>
|
||||
#include <zephyr/cache.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/mbox.h>
|
||||
@@ -15,15 +16,15 @@
|
||||
#define DT_DRV_COMPAT nordic_ironside_call
|
||||
|
||||
#define SHM_NODE DT_INST_PHANDLE(0, memory_region)
|
||||
#define NUM_BUFS (DT_REG_SIZE(SHM_NODE) / sizeof(struct ironside_call_buf))
|
||||
#define NUM_BUFS (DT_REG_SIZE(SHM_NODE) / sizeof(struct ironside_se_call_buf))
|
||||
#define ALL_BUF_BITS BIT_MASK(NUM_BUFS)
|
||||
|
||||
/* Note: this area is already zero-initialized at reset time. */
|
||||
static struct ironside_call_buf *const bufs = (void *)DT_REG_ADDR(SHM_NODE);
|
||||
static struct ironside_se_call_buf *const bufs = (void *)DT_REG_ADDR(SHM_NODE);
|
||||
|
||||
#if defined(CONFIG_DCACHE_LINE_SIZE)
|
||||
BUILD_ASSERT((DT_REG_ADDR(SHM_NODE) % CONFIG_DCACHE_LINE_SIZE) == 0);
|
||||
BUILD_ASSERT((sizeof(struct ironside_call_buf) % CONFIG_DCACHE_LINE_SIZE) == 0);
|
||||
BUILD_ASSERT((sizeof(struct ironside_se_call_buf) % CONFIG_DCACHE_LINE_SIZE) == 0);
|
||||
#endif
|
||||
|
||||
static const struct mbox_dt_spec mbox_rx = MBOX_DT_SPEC_INST_GET(0, rx);
|
||||
@@ -40,7 +41,7 @@ static void ironside_call_rsp(const struct device *dev, mbox_channel_id_t channe
|
||||
ARG_UNUSED(user_data);
|
||||
ARG_UNUSED(data);
|
||||
|
||||
struct ironside_call_buf *buf;
|
||||
struct ironside_se_call_buf *buf;
|
||||
uint32_t rsp_buf_bits = 0;
|
||||
|
||||
/* Check which buffers are not being dispatched currently. Those must
|
||||
@@ -62,8 +63,8 @@ static void ironside_call_rsp(const struct device *dev, mbox_channel_id_t channe
|
||||
sys_cache_data_invd_range(buf, sizeof(*buf));
|
||||
barrier_dmem_fence_full();
|
||||
|
||||
if (buf->status != IRONSIDE_CALL_STATUS_IDLE &&
|
||||
buf->status != IRONSIDE_CALL_STATUS_REQ) {
|
||||
if (buf->status != IRONSIDE_SE_CALL_STATUS_IDLE &&
|
||||
buf->status != IRONSIDE_SE_CALL_STATUS_REQ) {
|
||||
rsp_buf_bits |= BIT(i);
|
||||
}
|
||||
}
|
||||
@@ -89,9 +90,9 @@ static int ironside_call_init(const struct device *dev)
|
||||
}
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, ironside_call_init, NULL, NULL, NULL, POST_KERNEL,
|
||||
CONFIG_NRF_IRONSIDE_CALL_INIT_PRIORITY, NULL);
|
||||
CONFIG_IRONSIDE_SE_CALL_INIT_PRIORITY, NULL);
|
||||
|
||||
struct ironside_call_buf *ironside_call_alloc(void)
|
||||
struct ironside_se_call_buf *ironside_se_call_alloc(void)
|
||||
{
|
||||
uint32_t avail_buf_bits;
|
||||
uint32_t alloc_buf_bit;
|
||||
@@ -108,12 +109,12 @@ struct ironside_call_buf *ironside_call_alloc(void)
|
||||
return &bufs[u32_count_trailing_zeros(alloc_buf_bit)];
|
||||
}
|
||||
|
||||
void ironside_call_dispatch(struct ironside_call_buf *buf)
|
||||
void ironside_se_call_dispatch(struct ironside_se_call_buf *buf)
|
||||
{
|
||||
const uint32_t buf_bit = BIT(buf - bufs);
|
||||
int err;
|
||||
|
||||
buf->status = IRONSIDE_CALL_STATUS_REQ;
|
||||
buf->status = IRONSIDE_SE_CALL_STATUS_REQ;
|
||||
barrier_dmem_fence_full();
|
||||
|
||||
sys_cache_data_flush_range(buf, sizeof(*buf));
|
||||
@@ -126,11 +127,11 @@ void ironside_call_dispatch(struct ironside_call_buf *buf)
|
||||
k_event_wait(&rsp_evts, buf_bit, false, K_FOREVER);
|
||||
}
|
||||
|
||||
void ironside_call_release(struct ironside_call_buf *buf)
|
||||
void ironside_se_call_release(struct ironside_se_call_buf *buf)
|
||||
{
|
||||
const uint32_t buf_bit = BIT(buf - bufs);
|
||||
|
||||
buf->status = IRONSIDE_CALL_STATUS_IDLE;
|
||||
buf->status = IRONSIDE_SE_CALL_STATUS_IDLE;
|
||||
barrier_dmem_fence_full();
|
||||
|
||||
sys_cache_data_flush_range(buf, sizeof(*buf));
|
||||
@@ -2,13 +2,12 @@
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <ironside_zephyr/se/dvfs.h>
|
||||
#include <ironside/se/api.h>
|
||||
#include <hal/nrf_hsfll.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <nrf_ironside/dvfs.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
static enum ironside_dvfs_oppoint current_dvfs_oppoint = IRONSIDE_DVFS_OPP_HIGH;
|
||||
static enum ironside_se_dvfs_oppoint current_dvfs_oppoint = IRONSIDE_SE_DVFS_OPP_HIGH;
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_NRF54HX)
|
||||
#define ABB_STATUSANA_LOCKED_L_Pos (0UL)
|
||||
@@ -18,7 +17,7 @@ static enum ironside_dvfs_oppoint current_dvfs_oppoint = IRONSIDE_DVFS_OPP_HIGH;
|
||||
#error "Unsupported SoC series for IronSide DVFS"
|
||||
#endif
|
||||
|
||||
#define ABB_STATUSANA_CHECK_MAX_ATTEMPTS (CONFIG_NRF_IRONSIDE_ABB_STATUSANA_CHECK_MAX_ATTEMPTS)
|
||||
#define ABB_STATUSANA_CHECK_MAX_ATTEMPTS (CONFIG_IRONSIDE_SE_DVFS_ABB_STATUSANA_CHECK_MAX_ATTEMPTS)
|
||||
#define ABB_STATUSANA_CHECK_INTERVAL_US (10U)
|
||||
|
||||
struct dvfs_hsfll_data_t {
|
||||
@@ -48,7 +47,7 @@ static const struct dvfs_hsfll_data_t dvfs_hsfll_data[] = {
|
||||
},
|
||||
};
|
||||
|
||||
BUILD_ASSERT(ARRAY_SIZE(dvfs_hsfll_data) == (IRONSIDE_DVFS_OPPOINT_COUNT),
|
||||
BUILD_ASSERT(ARRAY_SIZE(dvfs_hsfll_data) == (IRONSIDE_SE_DVFS_OPPOINT_COUNT),
|
||||
"dvfs_hsfll_data size must match number of DVFS oppoints");
|
||||
|
||||
/**
|
||||
@@ -57,7 +56,7 @@ BUILD_ASSERT(ARRAY_SIZE(dvfs_hsfll_data) == (IRONSIDE_DVFS_OPPOINT_COUNT),
|
||||
* @param target_freq_setting The target oppoint to check.
|
||||
* @return true if the current oppoint is higher than the target, false otherwise.
|
||||
*/
|
||||
static bool ironside_dvfs_is_downscaling(enum ironside_dvfs_oppoint target_freq_setting)
|
||||
static bool is_downscaling(enum ironside_se_dvfs_oppoint target_freq_setting)
|
||||
{
|
||||
return current_dvfs_oppoint < target_freq_setting;
|
||||
}
|
||||
@@ -67,7 +66,7 @@ static bool ironside_dvfs_is_downscaling(enum ironside_dvfs_oppoint target_freq_
|
||||
*
|
||||
* @param enum oppoint target operation point
|
||||
*/
|
||||
static void ironside_dvfs_configure_hsfll(enum ironside_dvfs_oppoint oppoint)
|
||||
static void configure_hsfll(enum ironside_se_dvfs_oppoint oppoint)
|
||||
{
|
||||
nrf_hsfll_trim_t hsfll_trim = {};
|
||||
uint8_t freq_trim_idx = dvfs_hsfll_data[oppoint].new_f_trim_entry;
|
||||
@@ -93,15 +92,15 @@ static void ironside_dvfs_configure_hsfll(enum ironside_dvfs_oppoint oppoint)
|
||||
}
|
||||
|
||||
/* Function handling steps for DVFS oppoint change. */
|
||||
static void ironside_dvfs_prepare_to_scale(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
static void prepare_to_scale(enum ironside_se_dvfs_oppoint dvfs_oppoint)
|
||||
{
|
||||
if (ironside_dvfs_is_downscaling(dvfs_oppoint)) {
|
||||
ironside_dvfs_configure_hsfll(dvfs_oppoint);
|
||||
if (is_downscaling(dvfs_oppoint)) {
|
||||
configure_hsfll(dvfs_oppoint);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update MDK variable which is used by nrfx_coredep_delay_us (k_busy_wait). */
|
||||
static void ironside_dvfs_update_core_clock(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
static void update_core_clock(enum ironside_se_dvfs_oppoint dvfs_oppoint)
|
||||
{
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
@@ -109,14 +108,14 @@ static void ironside_dvfs_update_core_clock(enum ironside_dvfs_oppoint dvfs_oppo
|
||||
}
|
||||
|
||||
/* Perform scaling finnish procedure. */
|
||||
static void ironside_dvfs_change_oppoint_complete(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
static void change_oppoint_complete(enum ironside_se_dvfs_oppoint dvfs_oppoint)
|
||||
{
|
||||
if (!ironside_dvfs_is_downscaling(dvfs_oppoint)) {
|
||||
ironside_dvfs_configure_hsfll(dvfs_oppoint);
|
||||
if (!is_downscaling(dvfs_oppoint)) {
|
||||
configure_hsfll(dvfs_oppoint);
|
||||
}
|
||||
|
||||
current_dvfs_oppoint = dvfs_oppoint;
|
||||
ironside_dvfs_update_core_clock(dvfs_oppoint);
|
||||
update_core_clock(dvfs_oppoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +125,7 @@ static void ironside_dvfs_change_oppoint_complete(enum ironside_dvfs_oppoint dvf
|
||||
*
|
||||
* @return true if ABB is locked, false otherwise.
|
||||
*/
|
||||
static inline bool ironside_dvfs_is_abb_locked(NRF_ABB_Type *abb)
|
||||
static inline bool is_abb_locked(NRF_ABB_Type *abb)
|
||||
{
|
||||
/* Check if ABB analog part is locked. */
|
||||
/* Temporary workaround until STATUSANA register is visible. */
|
||||
@@ -142,46 +141,12 @@ static inline bool ironside_dvfs_is_abb_locked(NRF_ABB_Type *abb)
|
||||
return ((*statusana & ABB_STATUSANA_LOCKED_L_Msk) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request DVFS oppoint change from IronSide secure domain.
|
||||
* This function will send a request over IPC to the IronSide secure domain
|
||||
* This function is synchronous and will return when the request is completed.
|
||||
*
|
||||
* @param oppoint @ref enum ironside_dvfs_oppoint
|
||||
* @return int
|
||||
*/
|
||||
static int ironside_dvfs_req_oppoint(enum ironside_dvfs_oppoint oppoint)
|
||||
{
|
||||
int err;
|
||||
|
||||
struct ironside_call_buf *const buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_DVFS_SERVICE_V0;
|
||||
buf->args[IRONSIDE_DVFS_SERVICE_OPPOINT_IDX] = oppoint;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_DVFS_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ironside_dvfs_change_oppoint(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
int ironside_se_dvfs_change_oppoint(enum ironside_se_dvfs_oppoint dvfs_oppoint)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!ironside_dvfs_is_oppoint_valid(dvfs_oppoint)) {
|
||||
return -IRONSIDE_DVFS_ERROR_WRONG_OPPOINT;
|
||||
}
|
||||
|
||||
if (!ironside_dvfs_is_abb_locked(NRF_ABB)) {
|
||||
return -IRONSIDE_DVFS_ERROR_BUSY;
|
||||
if (!is_abb_locked(NRF_ABB)) {
|
||||
return -IRONSIDE_SE_DVFS_ERROR_BUSY;
|
||||
}
|
||||
|
||||
if (dvfs_oppoint == current_dvfs_oppoint) {
|
||||
@@ -189,17 +154,17 @@ int ironside_dvfs_change_oppoint(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
}
|
||||
|
||||
if (k_is_in_isr()) {
|
||||
return -IRONSIDE_DVFS_ERROR_ISR_NOT_ALLOWED;
|
||||
return -IRONSIDE_SE_DVFS_ERROR_ISR_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
ironside_dvfs_prepare_to_scale(dvfs_oppoint);
|
||||
|
||||
status = ironside_dvfs_req_oppoint(dvfs_oppoint);
|
||||
prepare_to_scale(dvfs_oppoint);
|
||||
|
||||
status = ironside_se_dvfs_req_oppoint(dvfs_oppoint);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
ironside_dvfs_change_oppoint_complete(dvfs_oppoint);
|
||||
|
||||
change_oppoint_complete(dvfs_oppoint);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_DVFS_H_
|
||||
#define ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_DVFS_H_
|
||||
|
||||
#include <ironside/se/api.h>
|
||||
|
||||
/** The DVFS oppoint change operation is not allowed in the ISR context. */
|
||||
#define IRONSIDE_SE_DVFS_ERROR_ISR_NOT_ALLOWED (7)
|
||||
|
||||
/**
|
||||
* @brief Change the current DVFS oppoint.
|
||||
*
|
||||
* This function will request a change of the current DVFS oppoint to the
|
||||
* specified value. It will block until the change is applied.
|
||||
*
|
||||
* @param dvfs_oppoint The new DVFS oppoint to set.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_WRONG_OPPOINT if the requested DVFS oppoint is not allowed.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_BUSY if waiting for mutex lock timed out, or hardware is busy.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_OPPOINT_DATA if there is configuration error in the DVFS service.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_PERMISSION if the caller does not have permission to change the
|
||||
* DVFS oppoint.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_NO_CHANGE_NEEDED if the requested DVFS oppoint is already set.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_TIMEOUT if the operation timed out, possibly due to a hardware
|
||||
* issue.
|
||||
* @retval -IRONSIDE_SE_DVFS_ERROR_ISR_NOT_ALLOWED if the DVFS oppoint change operation is not
|
||||
* allowed in the ISR context.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_se_dvfs_change_oppoint(enum ironside_se_dvfs_oppoint dvfs_oppoint);
|
||||
|
||||
#endif /* ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_DVFS_H_ */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_UICR_PERIPHCONF_H_
|
||||
#define ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_UICR_PERIPHCONF_H_
|
||||
|
||||
#include <ironside/se/periphconf.h>
|
||||
|
||||
#include <zephyr/sys/iterable_sections.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
/** Add an entry to the PERIPHCONF table section.
|
||||
*
|
||||
* This is a Zephyr integration with the IronSide UICR PERIPHCONF construction
|
||||
* macros that uses an iterable section to store the entries.
|
||||
*
|
||||
* The macro expects a struct periphconf_entry initializer as input.
|
||||
* The macros defined in ironside/se/periphconf.h can be used to construct the initializer.
|
||||
* For example:
|
||||
*
|
||||
* UICR_PERIPHCONF_ENTRY(PERIPHCONF_SPU_FEATURE_GRTC_CC(...));
|
||||
*
|
||||
*/
|
||||
#define UICR_PERIPHCONF_ENTRY(_entry) \
|
||||
static STRUCT_SECTION_ITERABLE(periphconf_entry, \
|
||||
_UICR_PERIPHCONF_ENTRY_NAME(__COUNTER__)) = _entry
|
||||
|
||||
#define _UICR_PERIPHCONF_ENTRY_NAME(_id) __UICR_PERIPHCONF_ENTRY_NAME(_id)
|
||||
#define __UICR_PERIPHCONF_ENTRY_NAME(_id) _uicr_periphconf_entry_##_id
|
||||
|
||||
#endif /* ZEPHYR_MODULES_HAL_NORDIC_IRONSIDE_SE_INCLUDE_IRONSIDE_ZEPHYR_SE_UICR_PERIPHCONF_H_ */
|
||||
@@ -19,8 +19,9 @@ except KeyError:
|
||||
sys.exit("Set the environment variable 'ZEPHYR_BASE' to point to the zephyr root directory")
|
||||
|
||||
# Add packages that are located in zephyr itself to the python path so we can import them below
|
||||
# The devicetree package is needed on the path for unpickling devicetree object, even if we aren't
|
||||
# importing anything from it directly.
|
||||
sys.path.insert(0, str(ZEPHYR_BASE / "scripts/dts/python-devicetree/src"))
|
||||
sys.path.insert(0, str(ZEPHYR_BASE / "soc/nordic/common/uicr"))
|
||||
|
||||
from periphconf.builder import (
|
||||
Ctrlsel,
|
||||
@@ -130,7 +130,7 @@ class PeriphconfBuilder:
|
||||
source_lines.extend(
|
||||
[
|
||||
"#include <zephyr/devicetree.h>",
|
||||
"#include <uicr/uicr.h>",
|
||||
"#include <ironside_zephyr/se/uicr_periphconf.h>",
|
||||
"",
|
||||
]
|
||||
)
|
||||
@@ -270,7 +270,7 @@ class PeriphconfBuilder:
|
||||
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_PERIPH_PERM_SET",
|
||||
"PERIPHCONF_SPU_PERIPH_PERM",
|
||||
[
|
||||
Address(spu_address),
|
||||
periph_slave_index,
|
||||
@@ -318,7 +318,7 @@ class PeriphconfBuilder:
|
||||
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_IRQMAP_IRQ_SINK_SET",
|
||||
"PERIPHCONF_IRQMAP_IRQ_SINK",
|
||||
[
|
||||
macro_irqn,
|
||||
irq_processor.c_enum,
|
||||
@@ -339,7 +339,7 @@ class PeriphconfBuilder:
|
||||
for num, secure in dt_split_channels_get(node):
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_GPIOTE_CH_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_GPIOTE_CH",
|
||||
[
|
||||
Address(spu_address),
|
||||
0,
|
||||
@@ -370,7 +370,7 @@ class PeriphconfBuilder:
|
||||
for num, secure in channels:
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_DPPIC_CH_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_DPPIC_CH",
|
||||
[
|
||||
Address(spu_address),
|
||||
num,
|
||||
@@ -384,7 +384,7 @@ class PeriphconfBuilder:
|
||||
for num, secure in channel_groups:
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_DPPIC_CHG_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_DPPIC_CHG",
|
||||
[
|
||||
Address(spu_address),
|
||||
num,
|
||||
@@ -435,7 +435,7 @@ class PeriphconfBuilder:
|
||||
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_PPIB_SUBSCRIBE_SEND_ENABLE",
|
||||
"PERIPHCONF_PPIB_SUBSCRIBE_SEND",
|
||||
[
|
||||
Address(sub_ppib_addr),
|
||||
sub_ppib_ch,
|
||||
@@ -447,7 +447,7 @@ class PeriphconfBuilder:
|
||||
)
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_PPIB_PUBLISH_RECEIVE_ENABLE",
|
||||
"PERIPHCONF_PPIB_PUBLISH_RECEIVE",
|
||||
[
|
||||
Address(pub_ppib_addr),
|
||||
pub_ppib_ch,
|
||||
@@ -470,7 +470,7 @@ class PeriphconfBuilder:
|
||||
for num, secure in dt_split_channels_get(node):
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_IPCT_CH_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_IPCT_CH",
|
||||
[
|
||||
Address(spu_address),
|
||||
num,
|
||||
@@ -536,8 +536,18 @@ class PeriphconfBuilder:
|
||||
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_IPCMAP_CHANNEL_CFG",
|
||||
[self._ipcmap_idx, *link_args],
|
||||
"PERIPHCONF_IPCMAP_CHANNEL_SOURCE",
|
||||
[self._ipcmap_idx, source_domain.c_enum, source_ch],
|
||||
comment=(
|
||||
f"{source_domain.name} IPCT ch. {source_ch} => "
|
||||
f"{sink_domain.name} IPCT ch. {sink_ch}"
|
||||
),
|
||||
)
|
||||
)
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"PERIPHCONF_IPCMAP_CHANNEL_SINK",
|
||||
[self._ipcmap_idx, sink_domain.c_enum, sink_ch],
|
||||
comment=(
|
||||
f"{source_domain.name} IPCT ch. {source_ch} => "
|
||||
f"{sink_domain.name} IPCT ch. {sink_ch}"
|
||||
@@ -557,7 +567,7 @@ class PeriphconfBuilder:
|
||||
for num, secure in dt_split_channels_get(node):
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_GRTC_CC_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_GRTC_CC",
|
||||
[
|
||||
Address(spu_address),
|
||||
num,
|
||||
@@ -679,7 +689,7 @@ class PeriphconfBuilder:
|
||||
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_SPU_FEATURE_GPIO_PIN_SET",
|
||||
"PERIPHCONF_SPU_FEATURE_GPIO_PIN",
|
||||
[
|
||||
Address(spu_address),
|
||||
gpio_port,
|
||||
@@ -695,7 +705,7 @@ class PeriphconfBuilder:
|
||||
ctrlsel_int = int(ctrlsel)
|
||||
self._macros.append(
|
||||
MacroCall(
|
||||
"UICR_GPIO_PIN_CNF_CTRLSEL_SET",
|
||||
"PERIPHCONF_GPIO_PIN_CNF_CTRLSEL",
|
||||
[
|
||||
Address(gpio_addr),
|
||||
num,
|
||||
@@ -737,7 +747,8 @@ class MacroCall:
|
||||
str_args.append(str(arg))
|
||||
|
||||
comment = f"/* {self.comment} */\n" if self.comment else ""
|
||||
return f"{comment}{self.name}({', '.join(str_args)});"
|
||||
entry_macro = f"UICR_PERIPHCONF_ENTRY({self.name}({', '.join(str_args)}))"
|
||||
return f"{comment}{entry_macro};"
|
||||
|
||||
|
||||
def c_hex_addr(address: int) -> str:
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <zephyr/linker/iterable_sections.h>
|
||||
|
||||
SECTION_PROLOGUE(uicr_periphconf_entry,(COPY),SUBALIGN(Z_LINK_ITERABLE_SUBALIGN))
|
||||
SECTION_PROLOGUE(periphconf_entry,(COPY),SUBALIGN(Z_LINK_ITERABLE_SUBALIGN))
|
||||
{
|
||||
Z_LINK_ITERABLE(uicr_periphconf_entry);
|
||||
Z_LINK_ITERABLE(periphconf_entry);
|
||||
} GROUP_ROM_LINK_IN(DEVNULL_REGION, DEVNULL_REGION)
|
||||
@@ -1,4 +1 @@
|
||||
CONFIG_LOG=y
|
||||
|
||||
CONFIG_NRF_IRONSIDE_UPDATE_SERVICE=y
|
||||
CONFIG_NRF_IRONSIDE_BOOT_REPORT=y
|
||||
|
||||
@@ -4,23 +4,21 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <nrf_ironside/boot_report.h>
|
||||
#include <nrf_ironside/update.h>
|
||||
#include <ironside/se/api.h>
|
||||
#include <ironside/se/boot_report.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);
|
||||
|
||||
BUILD_ASSERT(CONFIG_UPDATE_BLOB_ADDRESS >= IRONSIDE_UPDATE_MIN_ADDRESS);
|
||||
BUILD_ASSERT(CONFIG_UPDATE_BLOB_ADDRESS <= IRONSIDE_UPDATE_MAX_ADDRESS);
|
||||
BUILD_ASSERT(CONFIG_UPDATE_BLOB_ADDRESS >= IRONSIDE_SE_UPDATE_MIN_ADDRESS);
|
||||
BUILD_ASSERT(CONFIG_UPDATE_BLOB_ADDRESS <= IRONSIDE_SE_UPDATE_MAX_ADDRESS);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
const struct ironside_update_blob *update = (void *)CONFIG_UPDATE_BLOB_ADDRESS;
|
||||
const struct ironside_boot_report *report;
|
||||
const struct ironside_se_update_blob *update = (void *)CONFIG_UPDATE_BLOB_ADDRESS;
|
||||
const struct ironside_se_boot_report *report = IRONSIDE_SE_BOOT_REPORT;
|
||||
|
||||
err = ironside_boot_report_get(&report);
|
||||
LOG_INF("ironside_boot_report_get err: %d", err);
|
||||
/* Extract version components from packed 32-bit integer (8-bit MAJOR.MINOR.PATCH.SEQNUM) */
|
||||
uint8_t se_major = (report->ironside_se_version_int >> 24) & 0xFF;
|
||||
uint8_t se_minor = (report->ironside_se_version_int >> 16) & 0xFF;
|
||||
@@ -37,9 +35,9 @@ int main(void)
|
||||
LOG_INF("recovery version: %d.%d.%d-%s+%d", recovery_major, recovery_minor, recovery_patch,
|
||||
report->ironside_se_recovery_extraversion, recovery_seqnum);
|
||||
LOG_INF("update status: 0x%x", report->ironside_update_status);
|
||||
LOG_HEXDUMP_INF((void *)report->random_data, sizeof(report->random_data), "random data");
|
||||
LOG_HEXDUMP_INF((void *)report->random.data, sizeof(report->random.data), "random data");
|
||||
|
||||
err = ironside_update(update);
|
||||
err = ironside_se_update(update);
|
||||
LOG_INF("IronSide update retval: 0x%x", err);
|
||||
|
||||
if (err == 0) {
|
||||
|
||||
@@ -50,4 +50,3 @@ if(CONFIG_SOC_NORDIC_BSP_NAME STREQUAL "stable")
|
||||
endif()
|
||||
|
||||
add_subdirectory(common)
|
||||
add_subdirectory_ifdef(CONFIG_NRF_IRONSIDE ironside)
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_RISCV_CORE_NORDIC_VPR vpr)
|
||||
|
||||
add_subdirectory(uicr)
|
||||
|
||||
# Let SystemInit() be called in place of soc_reset_hook() by default.
|
||||
zephyr_linker_symbol(SYMBOL soc_reset_hook EXPR "@SystemInit@")
|
||||
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config NRF_PERIPHCONF_SECTION
|
||||
bool "Populate global peripheral initialization section"
|
||||
default y if SOC_NRF54H20_CPUAPP || SOC_NRF54H20_CPURAD || SOC_NRF9280_CPUAPP
|
||||
depends on LINKER_DEVNULL_SUPPORT
|
||||
imply LINKER_DEVNULL_MEMORY
|
||||
help
|
||||
Include static global domain peripheral initialization values from the
|
||||
build in a dedicated section in the devnull region.
|
||||
|
||||
config NRF_PERIPHCONF_GENERATE_ENTRIES
|
||||
bool "Generate PERIPHCONF entries source file"
|
||||
default y if SOC_NRF54H20_CPUAPP || SOC_NRF54H20_CPURAD || SOC_NRF9280_CPUAPP
|
||||
depends on NRF_PERIPHCONF_SECTION
|
||||
depends on NRF_PLATFORM_HALTIUM
|
||||
help
|
||||
Generate a C file containing PERIPHCONF entries based on the
|
||||
device configuration in the devicetree.
|
||||
|
||||
config IS_IRONSIDE_SE_SECONDARY_IMAGE
|
||||
bool "Ironside SE secondary image indicator (informative only, do not change)"
|
||||
help
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config NRF_HALTIUM_GENERATE_UICR
|
||||
bool "Generate UICR file"
|
||||
bool "Generate UICR artifacts"
|
||||
depends on SOC_SERIES_NRF54HX || SOC_SERIES_NRF92X
|
||||
default y
|
||||
help
|
||||
Generate UICR HEX file.
|
||||
When enabled, a UICR generator image is included in the build.
|
||||
This generates binary configuration artifacts based on the Kconfig and device tree
|
||||
of the UICR generator image. See the UICR generator options for further details.
|
||||
|
||||
@@ -1,859 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ctypes as c
|
||||
import sys
|
||||
from itertools import groupby, pairwise
|
||||
from typing import NamedTuple
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from intelhex import IntelHex
|
||||
|
||||
# The UICR format version produced by this script
|
||||
UICR_FORMAT_VERSION_MAJOR = 2
|
||||
UICR_FORMAT_VERSION_MINOR = 0
|
||||
|
||||
# Name of the ELF section containing PERIPHCONF entries.
|
||||
# Must match the name used in the linker script.
|
||||
PERIPHCONF_SECTION = "uicr_periphconf_entry"
|
||||
|
||||
# Common values for representing enabled/disabled in the UICR format.
|
||||
ENABLED_VALUE = 0xFFFF_FFFF
|
||||
DISABLED_VALUE = 0xBD23_28A8
|
||||
PROTECTED_VALUE = ENABLED_VALUE # UICR_PROTECTED = UICR_ENABLED per uicr_defs.h
|
||||
UNPROTECTED_VALUE = DISABLED_VALUE # Unprotected uses the default erased value
|
||||
|
||||
KB_4 = 4096
|
||||
|
||||
|
||||
class ScriptError(RuntimeError): ...
|
||||
|
||||
|
||||
class PartitionInfo(NamedTuple):
|
||||
"""Information about a partition for secure storage validation."""
|
||||
|
||||
address: int
|
||||
size: int
|
||||
name: str
|
||||
|
||||
|
||||
class PeriphconfEntry(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("regptr", c.c_uint32),
|
||||
("value", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
PERIPHCONF_ENTRY_SIZE = c.sizeof(PeriphconfEntry)
|
||||
|
||||
|
||||
class Version(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("MINOR", c.c_uint16),
|
||||
("MAJOR", c.c_uint16),
|
||||
]
|
||||
|
||||
|
||||
class Approtect(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("APPLICATION", c.c_uint32),
|
||||
("RADIOCORE", c.c_uint32),
|
||||
("RESERVED", c.c_uint32),
|
||||
("CORESIGHT", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class Protectedmem(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("SIZE4KB", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class Wdtstart(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("INSTANCE", c.c_uint32),
|
||||
("CRV", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecurestorageCrypto(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("APPLICATIONSIZE1KB", c.c_uint32),
|
||||
("RADIOCORESIZE1KB", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecurestorageIts(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("APPLICATIONSIZE1KB", c.c_uint32),
|
||||
("RADIOCORESIZE1KB", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class Securestorage(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("CRYPTO", SecurestorageCrypto),
|
||||
("ITS", SecurestorageIts),
|
||||
]
|
||||
|
||||
|
||||
class Periphconf(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("MAXCOUNT", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class Mpcconf(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("MAXCOUNT", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecondaryTrigger(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("RESETREAS", c.c_uint32),
|
||||
("RESERVED", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecondaryProtectedmem(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("SIZE4KB", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecondaryWdtstart(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("INSTANCE", c.c_uint32),
|
||||
("CRV", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecondaryPeriphconf(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("MAXCOUNT", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class SecondaryMpcconf(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("MAXCOUNT", c.c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class Secondary(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("ENABLE", c.c_uint32),
|
||||
("PROCESSOR", c.c_uint32),
|
||||
("TRIGGER", SecondaryTrigger),
|
||||
("ADDRESS", c.c_uint32),
|
||||
("PROTECTEDMEM", SecondaryProtectedmem),
|
||||
("WDTSTART", SecondaryWdtstart),
|
||||
("PERIPHCONF", SecondaryPeriphconf),
|
||||
("MPCCONF", SecondaryMpcconf),
|
||||
]
|
||||
|
||||
|
||||
class Uicr(c.LittleEndianStructure):
|
||||
_pack_ = 1
|
||||
_fields_ = [
|
||||
("VERSION", Version),
|
||||
("RESERVED", c.c_uint32),
|
||||
("LOCK", c.c_uint32),
|
||||
("RESERVED1", c.c_uint32),
|
||||
("APPROTECT", Approtect),
|
||||
("ERASEPROTECT", c.c_uint32),
|
||||
("PROTECTEDMEM", Protectedmem),
|
||||
("WDTSTART", Wdtstart),
|
||||
("RESERVED2", c.c_uint32),
|
||||
("SECURESTORAGE", Securestorage),
|
||||
("RESERVED3", c.c_uint32 * 5),
|
||||
("PERIPHCONF", Periphconf),
|
||||
("MPCCONF", Mpcconf),
|
||||
("SECONDARY", Secondary),
|
||||
("PADDING", c.c_uint32 * 15),
|
||||
]
|
||||
|
||||
|
||||
def validate_secure_storage_partitions(args: argparse.Namespace) -> None:
|
||||
"""
|
||||
Validate that secure storage partitions are laid out correctly.
|
||||
|
||||
Args:
|
||||
args: Parsed command line arguments containing partition information
|
||||
|
||||
Raises:
|
||||
ScriptError: If validation fails
|
||||
"""
|
||||
# Expected order: cpuapp_crypto_partition, cpurad_crypto_partition,
|
||||
# cpuapp_its_partition, cpurad_its_partition
|
||||
partitions = [
|
||||
PartitionInfo(
|
||||
args.cpuapp_crypto_address, args.cpuapp_crypto_size, "cpuapp_crypto_partition"
|
||||
),
|
||||
PartitionInfo(
|
||||
args.cpurad_crypto_address, args.cpurad_crypto_size, "cpurad_crypto_partition"
|
||||
),
|
||||
PartitionInfo(args.cpuapp_its_address, args.cpuapp_its_size, "cpuapp_its_partition"),
|
||||
PartitionInfo(args.cpurad_its_address, args.cpurad_its_size, "cpurad_its_partition"),
|
||||
]
|
||||
|
||||
# Filter out zero-sized partitions (missing partitions)
|
||||
present_partitions = [p for p in partitions if p.size > 0]
|
||||
|
||||
# Require at least one subpartition to be present
|
||||
if not present_partitions:
|
||||
raise ScriptError(
|
||||
"At least one secure storage subpartition must be defined. "
|
||||
"Define one or more of: cpuapp_crypto_partition, cpurad_crypto_partition, "
|
||||
"cpuapp_its_partition, cpurad_its_partition"
|
||||
)
|
||||
|
||||
# Check 4KB alignment for secure storage start address
|
||||
if args.securestorage_address % 4096 != 0:
|
||||
raise ScriptError(
|
||||
f"Secure storage address {args.securestorage_address:#x} must be aligned to 4KB "
|
||||
f"(4096 bytes)"
|
||||
)
|
||||
|
||||
# Check 4KB alignment for secure storage size
|
||||
if args.securestorage_size % 4096 != 0:
|
||||
raise ScriptError(
|
||||
f"Secure storage size {args.securestorage_size} bytes must be aligned to 4KB "
|
||||
f"(4096 bytes)"
|
||||
)
|
||||
|
||||
# Check that the first present partition starts at the secure storage address
|
||||
first_partition = present_partitions[0]
|
||||
if first_partition.address != args.securestorage_address:
|
||||
raise ScriptError(
|
||||
f"First partition {first_partition.name} starts at {first_partition.address:#x}, "
|
||||
f"but must start at secure storage address {args.securestorage_address:#x}"
|
||||
)
|
||||
|
||||
# Check that all present partitions have sizes that are multiples of 1KB
|
||||
for partition in present_partitions:
|
||||
if partition.size % 1024 != 0:
|
||||
raise ScriptError(
|
||||
f"Partition {partition.name} has size {partition.size} bytes, but must be "
|
||||
f"a multiple of 1024 bytes (1KB)"
|
||||
)
|
||||
|
||||
# Check that partitions are in correct order and don't overlap
|
||||
for curr_partition, next_partition in pairwise(present_partitions):
|
||||
# Check order - partitions should be in ascending address order
|
||||
if curr_partition.address >= next_partition.address:
|
||||
raise ScriptError(
|
||||
f"Partition {curr_partition.name} (starts at {curr_partition.address:#x}) "
|
||||
f"must come before {next_partition.name} (starts at {next_partition.address:#x})"
|
||||
)
|
||||
|
||||
# Check for overlap
|
||||
curr_end = curr_partition.address + curr_partition.size
|
||||
if curr_end > next_partition.address:
|
||||
raise ScriptError(
|
||||
f"Partition {curr_partition.name} (ends at {curr_end:#x}) overlaps with "
|
||||
f"{next_partition.name} (starts at {next_partition.address:#x})"
|
||||
)
|
||||
|
||||
# Check for gaps (should be no gaps between consecutive partitions)
|
||||
if curr_end < next_partition.address:
|
||||
gap = next_partition.address - curr_end
|
||||
raise ScriptError(
|
||||
f"Gap of {gap} bytes between {curr_partition.name} (ends at {curr_end:#x}) and "
|
||||
f"{next_partition.name} (starts at {next_partition.address:#x})"
|
||||
)
|
||||
|
||||
# Check that combined subpartition sizes equal secure_storage_partition size
|
||||
total_subpartition_size = sum(p.size for p in present_partitions)
|
||||
if total_subpartition_size != args.securestorage_size:
|
||||
raise ScriptError(
|
||||
f"Combined size of subpartitions ({total_subpartition_size} bytes) does not match "
|
||||
f"secure_storage_partition size ({args.securestorage_size} bytes). "
|
||||
f"The definition is not coherent."
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
description=(
|
||||
"Generate artifacts for the UICR and associated configuration blobs from application "
|
||||
"build outputs. User Information Configuration Registers (UICR), in the context of "
|
||||
"certain Nordic SoCs, are used to configure system resources, like memory and "
|
||||
"peripherals, and to protect the device in various ways."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--in-periphconf-elf",
|
||||
dest="in_periphconf_elfs",
|
||||
default=[],
|
||||
action="append",
|
||||
type=argparse.FileType("rb"),
|
||||
help=(
|
||||
"Path to an ELF file to extract PERIPHCONF data from. Can be provided multiple times. "
|
||||
"The PERIPHCONF data from each ELF file is combined in a single list which is sorted "
|
||||
"by ascending address and cleared of duplicate entries."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-merged-hex",
|
||||
required=True,
|
||||
type=argparse.FileType("w", encoding="utf-8"),
|
||||
help="Path to write the merged UICR+PERIPHCONF HEX file to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-uicr-hex",
|
||||
required=True,
|
||||
type=argparse.FileType("w", encoding="utf-8"),
|
||||
help="Path to write the UICR-only HEX file to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-periphconf-hex",
|
||||
type=argparse.FileType("w", encoding="utf-8"),
|
||||
help="Path to write the PERIPHCONF-only HEX file to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--periphconf-address",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--periphconf-size",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--uicr-address",
|
||||
required=True,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of the UICR region (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--securestorage",
|
||||
action="store_true",
|
||||
help="Enable secure storage support in UICR",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--securestorage-address",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of the secure storage partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--securestorage-size",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of the secure storage partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpuapp-crypto-address",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpuapp-crypto-size",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpurad-crypto-address",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpurad-crypto-size",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpuapp-its-address",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of cpuapp_its_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpuapp-its-size",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of cpuapp_its_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpurad-its-address",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of cpurad_its_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cpurad-its-size",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of cpurad_its_partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--permit-permanently-transitioning-device-to-deployed",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Safety flag required to enable both UICR.LOCK and UICR.ERASEPROTECT together. "
|
||||
"Must be explicitly provided to acknowledge permanent device state changes."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lock",
|
||||
action="store_true",
|
||||
help="Enable UICR.LOCK to prevent modifications without ERASEALL",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--eraseprotect",
|
||||
action="store_true",
|
||||
help="Enable UICR.ERASEPROTECT to block ERASEALL operations",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--approtect-application-protected",
|
||||
action="store_true",
|
||||
help="Protect application domain access port (disable debug access)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--approtect-radiocore-protected",
|
||||
action="store_true",
|
||||
help="Protect radio core access port (disable debug access)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--approtect-coresight-protected",
|
||||
action="store_true",
|
||||
help="Protect CoreSight access port (disable debug access)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--protectedmem",
|
||||
action="store_true",
|
||||
help="Enable protected memory region in UICR",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--protectedmem-size-bytes",
|
||||
type=int,
|
||||
help="Protected memory size in bytes (must be divisible by 4096)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--wdtstart",
|
||||
action="store_true",
|
||||
help="Enable watchdog timer start in UICR",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--wdtstart-instance-code",
|
||||
type=lambda s: int(s, 0),
|
||||
help="Watchdog timer instance code (0xBD2328A8 for WDT0, 0x1730C77F for WDT1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--wdtstart-crv",
|
||||
type=int,
|
||||
help="Initial Counter Reload Value (CRV) for watchdog timer (minimum: 0xF)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-wdtstart",
|
||||
action="store_true",
|
||||
help="Enable watchdog timer start in UICR.SECONDARY",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-wdtstart-instance-code",
|
||||
type=lambda s: int(s, 0),
|
||||
help="Secondary watchdog timer instance code (0xBD2328A8 for WDT0, 0x1730C77F for WDT1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-wdtstart-crv",
|
||||
type=int,
|
||||
help="Secondary initial Counter Reload Value (CRV) for watchdog timer (minimum: 0xF)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary",
|
||||
action="store_true",
|
||||
help="Enable secondary firmware support in UICR",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-address",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Absolute flash address of the secondary firmware (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-processor",
|
||||
default=0xBD2328A8,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Processor to boot for the secondary firmware ",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-trigger",
|
||||
action="store_true",
|
||||
help="Enable UICR.SECONDARY.TRIGGER for automatic secondary firmware boot on reset events",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-trigger-resetreas",
|
||||
default=0,
|
||||
type=lambda s: int(s, 0),
|
||||
help=(
|
||||
"Bitmask of reset reasons that trigger secondary firmware boot "
|
||||
"(decimal or 0x-prefixed hex)"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-protectedmem-size",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of the secondary protected memory region (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-periphconf-address",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help=(
|
||||
"Absolute flash address of the secondary PERIPHCONF partition "
|
||||
"(decimal or 0x-prefixed hex)"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--secondary-periphconf-size",
|
||||
default=None,
|
||||
type=lambda s: int(s, 0),
|
||||
help="Size in bytes of the secondary PERIPHCONF partition (decimal or 0x-prefixed hex)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--in-secondary-periphconf-elf",
|
||||
dest="in_secondary_periphconf_elfs",
|
||||
default=[],
|
||||
action="append",
|
||||
type=argparse.FileType("rb"),
|
||||
help=(
|
||||
"Path to an ELF file to extract secondary PERIPHCONF data from. "
|
||||
"Can be provided multiple times. The secondary PERIPHCONF data from each ELF file "
|
||||
"is combined in a single list which is sorted by ascending address and cleared "
|
||||
"of duplicate entries."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-secondary-periphconf-hex",
|
||||
type=argparse.FileType("w", encoding="utf-8"),
|
||||
help="Path to write the secondary PERIPHCONF-only HEX file to",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
# Validate argument dependencies
|
||||
if args.out_periphconf_hex:
|
||||
if args.periphconf_address is None:
|
||||
raise ScriptError(
|
||||
"--periphconf-address is required when --out-periphconf-hex is used"
|
||||
)
|
||||
if args.periphconf_size is None:
|
||||
raise ScriptError("--periphconf-size is required when --out-periphconf-hex is used")
|
||||
|
||||
# Validate secondary argument dependencies
|
||||
if args.secondary and args.secondary_address is None:
|
||||
raise ScriptError("--secondary-address is required when --secondary is used")
|
||||
|
||||
if args.out_secondary_periphconf_hex:
|
||||
if args.secondary_periphconf_address is None:
|
||||
raise ScriptError(
|
||||
"--secondary-periphconf-address is required when "
|
||||
"--out-secondary-periphconf-hex is used"
|
||||
)
|
||||
if args.secondary_periphconf_size is None:
|
||||
raise ScriptError(
|
||||
"--secondary-periphconf-size is required when "
|
||||
"--out-secondary-periphconf-hex is used"
|
||||
)
|
||||
|
||||
# Validate secure storage argument dependencies
|
||||
if args.securestorage:
|
||||
if args.securestorage_address is None:
|
||||
raise ScriptError(
|
||||
"--securestorage-address is required when --securestorage is used"
|
||||
)
|
||||
if args.securestorage_size is None:
|
||||
raise ScriptError("--securestorage-size is required when --securestorage is used")
|
||||
|
||||
# Validate partition layout
|
||||
validate_secure_storage_partitions(args)
|
||||
|
||||
init_values = DISABLED_VALUE.to_bytes(4, "little") * (c.sizeof(Uicr) // 4)
|
||||
uicr = Uicr.from_buffer_copy(init_values)
|
||||
|
||||
uicr.VERSION.MAJOR = UICR_FORMAT_VERSION_MAJOR
|
||||
uicr.VERSION.MINOR = UICR_FORMAT_VERSION_MINOR
|
||||
|
||||
# Handle secure storage configuration
|
||||
if args.securestorage:
|
||||
uicr.SECURESTORAGE.ENABLE = ENABLED_VALUE
|
||||
uicr.SECURESTORAGE.ADDRESS = args.securestorage_address
|
||||
|
||||
# Set partition sizes in 1KB units
|
||||
uicr.SECURESTORAGE.CRYPTO.APPLICATIONSIZE1KB = args.cpuapp_crypto_size // 1024
|
||||
uicr.SECURESTORAGE.CRYPTO.RADIOCORESIZE1KB = args.cpurad_crypto_size // 1024
|
||||
uicr.SECURESTORAGE.ITS.APPLICATIONSIZE1KB = args.cpuapp_its_size // 1024
|
||||
uicr.SECURESTORAGE.ITS.RADIOCORESIZE1KB = args.cpurad_its_size // 1024
|
||||
|
||||
# Handle LOCK and ERASEPROTECT configuration
|
||||
# Check if both are enabled together - this requires explicit acknowledgment
|
||||
if (
|
||||
args.lock
|
||||
and args.eraseprotect
|
||||
and not args.permit_permanently_transitioning_device_to_deployed
|
||||
):
|
||||
raise ScriptError(
|
||||
"Enabling both --lock and --eraseprotect requires "
|
||||
"--permit-permanently-transitioning-device-to-deployed to be specified. "
|
||||
"This combination permanently locks the device configuration and prevents "
|
||||
"ERASEALL."
|
||||
)
|
||||
|
||||
if args.lock:
|
||||
uicr.LOCK = ENABLED_VALUE
|
||||
if args.eraseprotect:
|
||||
uicr.ERASEPROTECT = ENABLED_VALUE
|
||||
# Handle APPROTECT configuration
|
||||
if args.approtect_application_protected:
|
||||
uicr.APPROTECT.APPLICATION = PROTECTED_VALUE
|
||||
|
||||
if args.approtect_radiocore_protected:
|
||||
uicr.APPROTECT.RADIOCORE = PROTECTED_VALUE
|
||||
|
||||
if args.approtect_coresight_protected:
|
||||
uicr.APPROTECT.CORESIGHT = PROTECTED_VALUE
|
||||
# Handle protected memory configuration
|
||||
if args.protectedmem:
|
||||
if args.protectedmem_size_bytes % KB_4 != 0:
|
||||
raise ScriptError(
|
||||
f"Protected memory size ({args.protectedmem_size_bytes} bytes) "
|
||||
f"must be divisible by {KB_4}"
|
||||
)
|
||||
uicr.PROTECTEDMEM.ENABLE = ENABLED_VALUE
|
||||
uicr.PROTECTEDMEM.SIZE4KB = args.protectedmem_size_bytes // KB_4
|
||||
|
||||
# Handle WDTSTART configuration
|
||||
if args.wdtstart:
|
||||
uicr.WDTSTART.ENABLE = ENABLED_VALUE
|
||||
uicr.WDTSTART.CRV = args.wdtstart_crv
|
||||
uicr.WDTSTART.INSTANCE = args.wdtstart_instance_code
|
||||
|
||||
# Process periphconf data first and configure UICR completely before creating hex objects
|
||||
periphconf_hex = IntelHex()
|
||||
secondary_periphconf_hex = IntelHex()
|
||||
|
||||
if args.out_periphconf_hex:
|
||||
periphconf_combined = extract_and_combine_periphconfs(args.in_periphconf_elfs)
|
||||
|
||||
padding_len = args.periphconf_size - len(periphconf_combined)
|
||||
periphconf_final = periphconf_combined + bytes([0xFF for _ in range(padding_len)])
|
||||
|
||||
# Add periphconf data to periphconf hex object
|
||||
periphconf_hex.frombytes(periphconf_final, offset=args.periphconf_address)
|
||||
|
||||
# Configure UICR with periphconf settings
|
||||
uicr.PERIPHCONF.ENABLE = ENABLED_VALUE
|
||||
uicr.PERIPHCONF.ADDRESS = args.periphconf_address
|
||||
|
||||
# MAXCOUNT is given in number of 8-byte peripheral
|
||||
# configuration entries and periphconf_size is given in
|
||||
# bytes. When setting MAXCOUNT based on the
|
||||
# periphconf_size we must first assert that
|
||||
# periphconf_size has not been misconfigured.
|
||||
if args.periphconf_size % 8 != 0:
|
||||
raise ScriptError(
|
||||
f"args.periphconf_size was {args.periphconf_size}, but must be divisible by 8"
|
||||
)
|
||||
|
||||
uicr.PERIPHCONF.MAXCOUNT = args.periphconf_size // 8
|
||||
|
||||
# Handle secondary firmware configuration
|
||||
if args.secondary:
|
||||
uicr.SECONDARY.ENABLE = ENABLED_VALUE
|
||||
uicr.SECONDARY.ADDRESS = args.secondary_address
|
||||
uicr.SECONDARY.PROCESSOR = args.secondary_processor
|
||||
|
||||
# Handle secondary TRIGGER configuration
|
||||
if args.secondary_trigger:
|
||||
uicr.SECONDARY.TRIGGER.ENABLE = ENABLED_VALUE
|
||||
uicr.SECONDARY.TRIGGER.RESETREAS = args.secondary_trigger_resetreas
|
||||
|
||||
# Handle secondary PROTECTEDMEM configuration
|
||||
if args.secondary_protectedmem_size:
|
||||
uicr.SECONDARY.PROTECTEDMEM.ENABLE = ENABLED_VALUE
|
||||
if args.secondary_protectedmem_size % 4096 != 0:
|
||||
raise ScriptError(
|
||||
f"args.secondary_protectedmem_size was {args.secondary_protectedmem_size}, "
|
||||
f"but must be divisible by 4096"
|
||||
)
|
||||
uicr.SECONDARY.PROTECTEDMEM.SIZE4KB = args.secondary_protectedmem_size // 4096
|
||||
# Handle secondary periphconf if provided
|
||||
if args.out_secondary_periphconf_hex:
|
||||
secondary_periphconf_combined = extract_and_combine_periphconfs(
|
||||
args.in_secondary_periphconf_elfs
|
||||
)
|
||||
|
||||
padding_len = args.secondary_periphconf_size - len(secondary_periphconf_combined)
|
||||
secondary_periphconf_final = secondary_periphconf_combined + bytes(
|
||||
[0xFF for _ in range(padding_len)]
|
||||
)
|
||||
|
||||
# Add secondary periphconf data to secondary periphconf hex object
|
||||
secondary_periphconf_hex.frombytes(
|
||||
secondary_periphconf_final, offset=args.secondary_periphconf_address
|
||||
)
|
||||
|
||||
# Configure UICR with secondary periphconf settings
|
||||
uicr.SECONDARY.PERIPHCONF.ENABLE = ENABLED_VALUE
|
||||
uicr.SECONDARY.PERIPHCONF.ADDRESS = args.secondary_periphconf_address
|
||||
|
||||
# MAXCOUNT is given in number of 8-byte peripheral
|
||||
# configuration entries and secondary_periphconf_size is given in
|
||||
# bytes. When setting MAXCOUNT based on the
|
||||
# secondary_periphconf_size we must first assert that
|
||||
# secondary_periphconf_size has not been misconfigured.
|
||||
if args.secondary_periphconf_size % 8 != 0:
|
||||
raise ScriptError(
|
||||
f"args.secondary_periphconf_size was {args.secondary_periphconf_size}, "
|
||||
f"but must be divisible by 8"
|
||||
)
|
||||
|
||||
uicr.SECONDARY.PERIPHCONF.MAXCOUNT = args.secondary_periphconf_size // 8
|
||||
|
||||
# Handle secondary WDTSTART configuration
|
||||
if args.secondary_wdtstart:
|
||||
uicr.SECONDARY.WDTSTART.ENABLE = ENABLED_VALUE
|
||||
uicr.SECONDARY.WDTSTART.CRV = args.secondary_wdtstart_crv
|
||||
uicr.SECONDARY.WDTSTART.INSTANCE = args.secondary_wdtstart_instance_code
|
||||
|
||||
# Create UICR hex object with final UICR data
|
||||
uicr_hex = IntelHex()
|
||||
uicr_hex.frombytes(bytes(uicr), offset=args.uicr_address)
|
||||
|
||||
# Create merged hex by combining UICR and periphconf hex objects
|
||||
merged_hex = IntelHex()
|
||||
merged_hex.fromdict(uicr_hex.todict())
|
||||
|
||||
if args.out_periphconf_hex:
|
||||
periphconf_hex.write_hex_file(args.out_periphconf_hex)
|
||||
merged_hex.fromdict(periphconf_hex.todict())
|
||||
|
||||
if args.out_secondary_periphconf_hex:
|
||||
secondary_periphconf_hex.write_hex_file(args.out_secondary_periphconf_hex)
|
||||
merged_hex.fromdict(secondary_periphconf_hex.todict())
|
||||
|
||||
merged_hex.write_hex_file(args.out_merged_hex)
|
||||
uicr_hex.write_hex_file(args.out_uicr_hex)
|
||||
|
||||
except ScriptError as e:
|
||||
print(f"Error: {e!s}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes:
|
||||
combined_periphconf = []
|
||||
ipcmap_index = 0
|
||||
|
||||
for in_file in elf_files:
|
||||
elf = ELFFile(in_file)
|
||||
conf_section = elf.get_section_by_name(PERIPHCONF_SECTION)
|
||||
if conf_section is None:
|
||||
continue
|
||||
|
||||
conf_section_data = conf_section.data()
|
||||
num_entries = len(conf_section_data) // PERIPHCONF_ENTRY_SIZE
|
||||
periphconf = (PeriphconfEntry * num_entries).from_buffer_copy(conf_section_data)
|
||||
ipcmap_index = adjust_ipcmap_entries(periphconf, offset_index=ipcmap_index)
|
||||
combined_periphconf.extend(periphconf)
|
||||
|
||||
combined_periphconf.sort(key=lambda e: e.regptr)
|
||||
deduplicated_periphconf = []
|
||||
|
||||
for regptr, regptr_entries in groupby(combined_periphconf, key=lambda e: e.regptr):
|
||||
entries = list(regptr_entries)
|
||||
if len(entries) > 1:
|
||||
unique_values = {e.value for e in entries}
|
||||
if len(unique_values) > 1:
|
||||
raise ScriptError(
|
||||
f"PERIPHCONF has conflicting values for register 0x{regptr:09_x}: "
|
||||
+ ", ".join([f"0x{val:09_x}" for val in unique_values])
|
||||
)
|
||||
deduplicated_periphconf.append(entries[0])
|
||||
|
||||
final_periphconf = (PeriphconfEntry * len(deduplicated_periphconf))()
|
||||
for i, entry in enumerate(deduplicated_periphconf):
|
||||
final_periphconf[i] = entry
|
||||
|
||||
return bytes(final_periphconf)
|
||||
|
||||
|
||||
# This workaround is currently needed to avoid conflicts in IPCMAP whenever more than
|
||||
# one image uses IPCMAP, because at the moment each image has no way of knowing which
|
||||
# IPCMAP channel indices it should use for the configuration it generates locally.
|
||||
#
|
||||
# What the workaround does is adjust all IPCMAP entries found in the periphconf by the
|
||||
# given index offset.
|
||||
#
|
||||
# The workaround assumes that IPCMAP entries are allocated sequentially starting from 0
|
||||
# in each image, it will probably not work for arbitrary IPCMAP entries.
|
||||
def adjust_ipcmap_entries(periphconf: c.Array[PeriphconfEntry], offset_index: int) -> int:
|
||||
max_ipcmap_index = offset_index
|
||||
|
||||
for entry in sorted(periphconf, key=lambda e: e.regptr):
|
||||
if IPCMAP_CHANNEL_START_ADDR <= entry.regptr < IPCMAP_CHANNEL_END_ADDR:
|
||||
entry.regptr += offset_index * IPCMAP_CHANNEL_SIZE
|
||||
entry_ipcmap_index = (entry.regptr - IPCMAP_CHANNEL_START_ADDR) // IPCMAP_CHANNEL_SIZE
|
||||
max_ipcmap_index = max(max_ipcmap_index, entry_ipcmap_index)
|
||||
|
||||
return max_ipcmap_index + 1
|
||||
|
||||
|
||||
# Size of each IPCMAP.CHANNEL[i]
|
||||
IPCMAP_CHANNEL_SIZE = 8
|
||||
# Number of entries in IPCMAP.CHANNEL
|
||||
IPCMAP_CHANNEL_COUNT = 16
|
||||
# Address of IPCMAP.CHANNEL[0]
|
||||
IPCMAP_CHANNEL_START_ADDR = 0x5F92_3000 + 256 * 4
|
||||
# Address of IPCMAP.CHANNEL[channel count] + 1
|
||||
IPCMAP_CHANNEL_END_ADDR = IPCMAP_CHANNEL_START_ADDR + IPCMAP_CHANNEL_SIZE * IPCMAP_CHANNEL_COUNT
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -264,11 +264,13 @@ endif()
|
||||
# Generate hex files (merged, uicr-only, periphconf-only, and secondary-periphconf-only)
|
||||
add_custom_command(
|
||||
OUTPUT ${merged_hex_file} ${uicr_hex_file} ${periphconf_hex_file} ${secondary_periphconf_hex_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${ZEPHYR_BASE}/scripts/dts/python-devicetree/src
|
||||
${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/soc/nordic/common/uicr/gen_uicr.py
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_HAL_NORDIC_MODULE_DIR}/ironside/se/tool/ironside/__main__.py
|
||||
gen-uicr
|
||||
--uicr-address ${UICR_ADDRESS}
|
||||
--out-merged-hex ${merged_hex_file}
|
||||
--out-uicr-hex ${uicr_hex_file}
|
||||
--periphconf-section-name "periphconf_entry"
|
||||
--periphconf-ipcmap-reallocate
|
||||
${lock_args}
|
||||
${eraseprotect_args}
|
||||
${approtect_args}
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef SOC_NORDIC_COMMON_UICR_UICR_H_
|
||||
#define SOC_NORDIC_COMMON_UICR_UICR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <nrfx.h>
|
||||
#include <zephyr/sys/iterable_sections.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
/** Entry in the PERIPHCONF table. */
|
||||
struct uicr_periphconf_entry {
|
||||
/** Register pointer. */
|
||||
uint32_t regptr;
|
||||
/** Register value. */
|
||||
uint32_t value;
|
||||
} __packed;
|
||||
|
||||
/** @brief Add an entry to the PERIPHCONF table section.
|
||||
*
|
||||
* This should typically not be used directly.
|
||||
* Prefer to use one of the higher level macros.
|
||||
*/
|
||||
#define UICR_PERIPHCONF_ADD(_regptr, _value) \
|
||||
static STRUCT_SECTION_ITERABLE(uicr_periphconf_entry, \
|
||||
_UICR_PERIPHCONF_ENTRY_NAME(__COUNTER__)) = { \
|
||||
.regptr = (_regptr), \
|
||||
.value = (_value), \
|
||||
}
|
||||
|
||||
#define _UICR_PERIPHCONF_ENTRY_NAME(_id) __UICR_PERIPHCONF_ENTRY_NAME(_id)
|
||||
#define __UICR_PERIPHCONF_ENTRY_NAME(_id) _uicr_periphconf_entry_##_id
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU PERIPH[n].PERM register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Peripheral slave index on the bus (PERIPH[n] register index).
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _dmasec If true, set DMASEC to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_PERIPH_PERM_SET(_spu, _index, _secattr, _dmasec, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->PERIPH[(_index)].PERM, \
|
||||
(uint32_t)((((_ownerid) << SPU_PERIPH_PERM_OWNERID_Pos) & \
|
||||
SPU_PERIPH_PERM_OWNERID_Msk) | \
|
||||
(((_secattr) ? SPU_PERIPH_PERM_SECATTR_Secure \
|
||||
: SPU_PERIPH_PERM_SECATTR_NonSecure) \
|
||||
<< SPU_PERIPH_PERM_SECATTR_Pos) | \
|
||||
(((_dmasec) ? SPU_PERIPH_PERM_DMASEC_Secure \
|
||||
: SPU_PERIPH_PERM_DMASEC_NonSecure) \
|
||||
<< SPU_PERIPH_PERM_DMASEC_Pos) | \
|
||||
(SPU_PERIPH_PERM_LOCK_Locked << SPU_PERIPH_PERM_LOCK_Pos)))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.IPCT.CH[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_IPCT_CH_SET(_spu, _index, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.IPCT.CH[_index], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.IPCT.INTERRUPT[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_IPCT_INTERRUPT_SET(_spu, _index, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.IPCT.INTERRUPT[_index], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.DPPIC.CH[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_DPPIC_CH_SET(_spu, _index, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.DPPIC.CH[_index], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.DPPIC.CHG[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Register index.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_DPPIC_CHG_SET(_spu, _index, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.DPPIC.CHG[_index], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.GPIOTE[n].CH[m] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index (GPIOTE[n] register index).
|
||||
* @param _subindex Feature subindex (CH[m] register index).
|
||||
* @param _secattr If true, set the SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_GPIOTE_CH_SET(_spu, _index, _subindex, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD( \
|
||||
(uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.GPIOTE[_index].CH[_subindex], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.GPIOTE.INTERRUPT[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _subindex Feature subindex.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_GPIOTE_INTERRUPT_SET(_spu, _index, _subindex, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD( \
|
||||
(uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.GPIOTE[_index].INTERRUPT[_subindex], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.GPIO[n].PIN[m] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _subindex Feature subindex.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_GPIO_PIN_SET(_spu, _index, _subindex, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD( \
|
||||
(uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.GPIO[_index].PIN[_subindex], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a SPU FEATURE.GRTC.CC[n] register value.
|
||||
*
|
||||
* @param _spu Global domain SPU instance address.
|
||||
* @param _index Feature index.
|
||||
* @param _secattr If true, set SECATTR to secure, otherwise set it to non-secure.
|
||||
* @param _ownerid OWNERID field value.
|
||||
*/
|
||||
#define UICR_SPU_FEATURE_GRTC_CC_SET(_spu, _index, _secattr, _ownerid) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_SPU_Type *)(_spu))->FEATURE.GRTC.CC[_index], \
|
||||
_UICR_SPU_FEATURE_VAL(_secattr, _ownerid))
|
||||
|
||||
/* Common macro for encoding a SPU FEATURE.* register value.
|
||||
* Note that the MDK SPU_FEATURE_IPCT_CH_ macros are used for all since all the FEATURE registers
|
||||
* have the same layout with different naming.
|
||||
*/
|
||||
#define _UICR_SPU_FEATURE_VAL(_secattr, _ownerid) \
|
||||
(uint32_t)((((_ownerid) << SPU_FEATURE_IPCT_CH_OWNERID_Pos) & \
|
||||
SPU_FEATURE_IPCT_CH_OWNERID_Msk) | \
|
||||
(((_secattr) ? SPU_FEATURE_IPCT_CH_SECATTR_Secure \
|
||||
: SPU_FEATURE_IPCT_CH_SECATTR_NonSecure) \
|
||||
<< SPU_FEATURE_IPCT_CH_SECATTR_Pos) | \
|
||||
(SPU_FEATURE_IPCT_CH_LOCK_Locked << SPU_FEATURE_IPCT_CH_LOCK_Pos))
|
||||
|
||||
/** @brief Add PERIPHCONF entries for configuring IPCMAP CHANNEL.SOURCE[n] and CHANNEL.SINK[n].
|
||||
*
|
||||
* @param _index CHANNEL.SOURCE[n]/CHANNEL.SINK[n] register index.
|
||||
* @param _source_domain DOMAIN field value in CHANNEL[n].SOURCE.
|
||||
* @param _source_ch SOURCE field value in CHANNEL[n].SOURCE.
|
||||
* @param _sink_domain DOMAIN field value in CHANNEL[n].SINK.
|
||||
* @param _sink_ch SINK field value in CHANNEL[n].SINK.
|
||||
*/
|
||||
#define UICR_IPCMAP_CHANNEL_CFG(_index, _source_domain, _source_ch, _sink_domain, _sink_ch) \
|
||||
UICR_IPCMAP_CHANNEL_SOURCE_SET(_index, _source_domain, _source_ch, 1); \
|
||||
UICR_IPCMAP_CHANNEL_SINK_SET(_index, _sink_domain, _sink_ch)
|
||||
|
||||
#define UICR_IPCMAP_CHANNEL_SOURCE_SET(_index, _domain, _ch, _enable) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&NRF_IPCMAP->CHANNEL[(_index)].SOURCE, \
|
||||
(uint32_t)((((_domain) << IPCMAP_CHANNEL_SOURCE_DOMAIN_Pos) & \
|
||||
IPCMAP_CHANNEL_SOURCE_DOMAIN_Msk) | \
|
||||
(((_ch) << IPCMAP_CHANNEL_SOURCE_SOURCE_Pos) & \
|
||||
IPCMAP_CHANNEL_SOURCE_SOURCE_Msk) | \
|
||||
(((_enable) ? IPCMAP_CHANNEL_SOURCE_ENABLE_Enabled \
|
||||
: IPCMAP_CHANNEL_SOURCE_ENABLE_Disabled) \
|
||||
<< IPCMAP_CHANNEL_SOURCE_ENABLE_Pos)))
|
||||
|
||||
#define UICR_IPCMAP_CHANNEL_SINK_SET(_index, _domain, _ch) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&NRF_IPCMAP->CHANNEL[(_index)].SINK, \
|
||||
(uint32_t)((((_domain) << IPCMAP_CHANNEL_SINK_DOMAIN_Pos) & \
|
||||
IPCMAP_CHANNEL_SINK_DOMAIN_Msk) | \
|
||||
(((_ch) << IPCMAP_CHANNEL_SINK_SINK_Pos) & \
|
||||
IPCMAP_CHANNEL_SINK_SINK_Msk)))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for an IRQMAP IRQ[n].SINK register value.
|
||||
*
|
||||
* @param _irqnum IRQ number (IRQ[n] register index).
|
||||
* @param _processor Processor to route the interrupt to (PROCESSORID field value).
|
||||
*/
|
||||
#define UICR_IRQMAP_IRQ_SINK_SET(_irqnum, _processor) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&NRF_IRQMAP->IRQ[(_irqnum)].SINK, \
|
||||
(uint32_t)(((_processor) << IRQMAP_IRQ_SINK_PROCESSORID_Pos) & \
|
||||
IRQMAP_IRQ_SINK_PROCESSORID_Msk))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for configuring a GPIO PIN_CNF[n] CTRLSEL field value.
|
||||
*
|
||||
* @param _gpio GPIO instance address.
|
||||
* @param _pin Pin number (PIN_CNF[n] register index).
|
||||
* @param _ctrlsel CTRLSEL field value.
|
||||
*/
|
||||
#define UICR_GPIO_PIN_CNF_CTRLSEL_SET(_gpio, _pin, _ctrlsel) \
|
||||
UICR_PERIPHCONF_ADD( \
|
||||
(uint32_t)&((NRF_GPIO_Type *)(_gpio))->PIN_CNF[(_pin)], \
|
||||
((GPIO_PIN_CNF_ResetValue) | \
|
||||
(uint32_t)(((_ctrlsel) << GPIO_PIN_CNF_CTRLSEL_Pos) & GPIO_PIN_CNF_CTRLSEL_Msk)))
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a PPIB SUBSCRIBE_SEND[n] register.
|
||||
*
|
||||
* @param _ppib Global domain PPIB instance address.
|
||||
* @param _ppib_ch PPIB channel number.
|
||||
*/
|
||||
#define UICR_PPIB_SUBSCRIBE_SEND_ENABLE(_ppib, _ppib_ch) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_PPIB_Type *)(_ppib))->SUBSCRIBE_SEND[(_ppib_ch)], \
|
||||
(uint32_t)PPIB_SUBSCRIBE_SEND_EN_Msk)
|
||||
|
||||
/** @brief Add a PERIPHCONF entry for a PPIB PUBLISH_RECEIVE[n] register.
|
||||
*
|
||||
* @param _ppib Global domain PPIB instance address.
|
||||
* @param _ppib_ch PPIB channel number.
|
||||
*/
|
||||
#define UICR_PPIB_PUBLISH_RECEIVE_ENABLE(_ppib, _ppib_ch) \
|
||||
UICR_PERIPHCONF_ADD((uint32_t)&((NRF_PPIB_Type *)(_ppib))->PUBLISH_RECEIVE[(_ppib_ch)], \
|
||||
(uint32_t)PPIB_PUBLISH_RECEIVE_EN_Msk)
|
||||
|
||||
/* The definitions below are not currently available in the MDK but are needed for the macros
|
||||
* above. When they are, this can be deleted.
|
||||
*/
|
||||
#ifndef IPCMAP_CHANNEL_SOURCE_SOURCE_Msk
|
||||
|
||||
typedef struct {
|
||||
__IOM uint32_t SOURCE;
|
||||
__IOM uint32_t SINK;
|
||||
} NRF_IPCMAP_CHANNEL_Type;
|
||||
|
||||
#define IPCMAP_CHANNEL_SOURCE_SOURCE_Pos (0UL)
|
||||
#define IPCMAP_CHANNEL_SOURCE_SOURCE_Msk (0xFUL << IPCMAP_CHANNEL_SOURCE_SOURCE_Pos)
|
||||
#define IPCMAP_CHANNEL_SOURCE_DOMAIN_Pos (8UL)
|
||||
#define IPCMAP_CHANNEL_SOURCE_DOMAIN_Msk (0xFUL << IPCMAP_CHANNEL_SOURCE_DOMAIN_Pos)
|
||||
#define IPCMAP_CHANNEL_SOURCE_ENABLE_Pos (31UL)
|
||||
#define IPCMAP_CHANNEL_SOURCE_ENABLE_Disabled (0x0UL)
|
||||
#define IPCMAP_CHANNEL_SOURCE_ENABLE_Enabled (0x1UL)
|
||||
#define IPCMAP_CHANNEL_SINK_SINK_Pos (0UL)
|
||||
#define IPCMAP_CHANNEL_SINK_SINK_Msk (0xFUL << IPCMAP_CHANNEL_SINK_SINK_Pos)
|
||||
#define IPCMAP_CHANNEL_SINK_DOMAIN_Pos (8UL)
|
||||
#define IPCMAP_CHANNEL_SINK_DOMAIN_Msk (0xFUL << IPCMAP_CHANNEL_SINK_DOMAIN_Pos)
|
||||
|
||||
typedef struct {
|
||||
__IM uint32_t RESERVED[256];
|
||||
__IOM NRF_IPCMAP_CHANNEL_Type CHANNEL[16];
|
||||
} NRF_IPCMAP_Type;
|
||||
|
||||
#endif /* IPCMAP_CHANNEL_SOURCE_SOURCE_Msk */
|
||||
|
||||
#ifndef NRF_IPCMAP
|
||||
#define NRF_IPCMAP ((NRF_IPCMAP_Type *)0x5F923000UL)
|
||||
#endif
|
||||
|
||||
#ifndef IRQMAP_IRQ_SINK_PROCESSORID_Msk
|
||||
|
||||
typedef struct {
|
||||
__IOM uint32_t SINK;
|
||||
} NRF_IRQMAP_IRQ_Type;
|
||||
|
||||
#define IRQMAP_IRQ_SINK_PROCESSORID_Pos (8UL)
|
||||
#define IRQMAP_IRQ_SINK_PROCESSORID_Msk (0xFUL << IRQMAP_IRQ_SINK_PROCESSORID_Pos)
|
||||
|
||||
typedef struct {
|
||||
__IM uint32_t RESERVED[256];
|
||||
__IOM NRF_IRQMAP_IRQ_Type IRQ[480];
|
||||
} NRF_IRQMAP_Type;
|
||||
|
||||
#endif /* IRQMAP_IRQ_SINK_PROCESSORID_Msk */
|
||||
|
||||
#ifndef NRF_IRQMAP
|
||||
#define NRF_IRQMAP ((NRF_IRQMAP_Type *)0x5F924000UL)
|
||||
#endif /* NRF_IRQMAP */
|
||||
|
||||
#ifndef GPIO_PIN_CNF_CTRLSEL_Pos
|
||||
|
||||
#define GPIO_PIN_CNF_CTRLSEL_Pos (28UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_Msk (0x7UL << GPIO_PIN_CNF_CTRLSEL_Pos)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_Min (0x0UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_Max (0x7UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_GPIO (0x0UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_VPR (0x1UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_GRC (0x1UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_SecureDomain (0x2UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_PWM (0x2UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_I3C (0x2UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_Serial (0x3UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_HSSPI (0x3UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_RadioCore (0x4UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_EXMIF (0x4UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_CELL (0x4UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_DTB (0x6UL)
|
||||
#define GPIO_PIN_CNF_CTRLSEL_TND (0x7UL)
|
||||
|
||||
#endif /* GPIO_PIN_CNF_CTRLSEL_Pos */
|
||||
|
||||
#endif /* SOC_NORDIC_COMMON_UICR_UICR_H_ */
|
||||
@@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_include_directories(include)
|
||||
zephyr_library()
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CALL call.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_BOOT_REPORT boot_report.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CPUCONF_SERVICE cpuconf.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_BOOTMODE_SERVICE bootmode.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_TDD_SERVICE tdd.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_DVFS_SERVICE dvfs.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_COUNTER_SERVICE counter.c)
|
||||
@@ -1,89 +0,0 @@
|
||||
# Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config NRF_IRONSIDE
|
||||
bool
|
||||
depends on SOC_NRF54H20 || SOC_NRF9280
|
||||
help
|
||||
This is selected by drivers interacting with Nordic IronSide firmware.
|
||||
|
||||
config NRF_IRONSIDE_CALL
|
||||
bool
|
||||
depends on DT_HAS_NORDIC_IRONSIDE_CALL_ENABLED
|
||||
select NRF_IRONSIDE
|
||||
select EVENTS
|
||||
select MBOX
|
||||
help
|
||||
This is selected by features that require support for IronSide calls.
|
||||
|
||||
if NRF_IRONSIDE_CALL
|
||||
|
||||
config NRF_IRONSIDE_CALL_INIT_PRIORITY
|
||||
int "IronSide calls' initialization priority"
|
||||
default 41
|
||||
help
|
||||
Initialization priority of IronSide calls. It must be below MBOX_INIT_PRIORITY,
|
||||
but higher than the priority of any feature that selects NRF_IRONSIDE_CALL.
|
||||
|
||||
endif # NRF_IRONSIDE_CALL
|
||||
|
||||
menu "Nordic IronSide services"
|
||||
depends on SOC_NRF54H20 || SOC_NRF9280
|
||||
|
||||
config NRF_IRONSIDE_CPUCONF_SERVICE
|
||||
bool "IronSide CPUCONF service"
|
||||
depends on SOC_NRF54H20_CPUAPP || SOC_NRF9280_CPUAPP
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to boot local domain cores.
|
||||
|
||||
config NRF_IRONSIDE_TDD_SERVICE
|
||||
bool "IronSide TDD service"
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to control the trace and debug domain.
|
||||
|
||||
config NRF_IRONSIDE_UPDATE_SERVICE
|
||||
bool "IronSide update service"
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to update the IronSide SE firmware.
|
||||
|
||||
config NRF_IRONSIDE_BOOT_REPORT
|
||||
bool "IronSide boot report"
|
||||
depends on $(dt_nodelabel_exists,ironside_se_boot_report)
|
||||
select NRF_IRONSIDE
|
||||
help
|
||||
Support for parsing the Boot Report populated by Nordic IronSide firmware.
|
||||
|
||||
config NRF_IRONSIDE_BOOTMODE_SERVICE
|
||||
bool "IronSide boot mode service"
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to reboot into secondary firmware boot mode.
|
||||
|
||||
config NRF_IRONSIDE_DVFS_SERVICE
|
||||
bool "IronSide DVFS service"
|
||||
depends on SOC_NRF54H20_CPUAPP
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to handle DVFS operating point requests.
|
||||
|
||||
config NRF_IRONSIDE_COUNTER_SERVICE
|
||||
bool "IronSide counter service"
|
||||
select NRF_IRONSIDE_CALL
|
||||
help
|
||||
Service used to manage secure monotonic counters.
|
||||
|
||||
if NRF_IRONSIDE_DVFS_SERVICE
|
||||
|
||||
config NRF_IRONSIDE_ABB_STATUSANA_CHECK_MAX_ATTEMPTS
|
||||
int "IRONSside DVFS ABB analog status check maximum attempts"
|
||||
range 0 255
|
||||
default 50
|
||||
help
|
||||
Maximum attempts with 10us intervals before busy status will be reported.
|
||||
|
||||
endif # NRF_IRONSIDE_DVFS_SERVICE
|
||||
|
||||
endmenu
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <nrf_ironside/boot_report.h>
|
||||
|
||||
#define IRONSIDE_SE_BOOT_REPORT_ADDR DT_REG_ADDR(DT_NODELABEL(ironside_se_boot_report))
|
||||
|
||||
int ironside_boot_report_get(const struct ironside_boot_report **report)
|
||||
{
|
||||
const struct ironside_boot_report *tmp_report = (void *)IRONSIDE_SE_BOOT_REPORT_ADDR;
|
||||
|
||||
if (tmp_report->magic != IRONSIDE_BOOT_REPORT_MAGIC) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*report = tmp_report;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <nrf_ironside/bootmode.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
#define BOOT_MODE_SECONDARY (0x1)
|
||||
|
||||
BUILD_ASSERT(IRONSIDE_BOOTMODE_SERVICE_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
|
||||
|
||||
int ironside_bootmode_secondary_reboot(const uint8_t *msg, size_t msg_size)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *buf;
|
||||
uint8_t *buf_msg;
|
||||
|
||||
if (msg_size > IRONSIDE_BOOTMODE_SERVICE_MSG_MAX_SIZE) {
|
||||
return -IRONSIDE_BOOTMODE_ERROR_MESSAGE_TOO_LARGE;
|
||||
}
|
||||
|
||||
buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_BOOTMODE_SERVICE_V1;
|
||||
|
||||
buf->args[IRONSIDE_BOOTMODE_SERVICE_MODE_IDX] = BOOT_MODE_SECONDARY;
|
||||
|
||||
buf_msg = (uint8_t *)&buf->args[IRONSIDE_BOOTMODE_SERVICE_MSG_0_IDX];
|
||||
|
||||
memset(buf_msg, 0, IRONSIDE_BOOTMODE_SERVICE_MSG_MAX_SIZE);
|
||||
|
||||
if (msg_size > 0) {
|
||||
memcpy(buf_msg, msg, msg_size);
|
||||
}
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_BOOTMODE_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <nrf_ironside/counter.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
int ironside_counter_set(enum ironside_counter counter_id, uint32_t value)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *const buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_COUNTER_SET_V1;
|
||||
buf->args[IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
|
||||
buf->args[IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX] = value;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *buf;
|
||||
|
||||
if (value == NULL) {
|
||||
return -IRONSIDE_COUNTER_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_COUNTER_GET_V1;
|
||||
buf->args[IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX];
|
||||
if (err == 0) {
|
||||
*value = buf->args[IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX];
|
||||
}
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ironside_counter_lock(enum ironside_counter counter_id)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *const buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_COUNTER_LOCK_V1;
|
||||
buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <nrf_ironside/call.h>
|
||||
#include <nrf_ironside/cpuconf.h>
|
||||
|
||||
#define CPU_PARAMS_CPU_OFFSET (0)
|
||||
#define CPU_PARAMS_CPU_MASK (0xF)
|
||||
#define CPU_PARAMS_WAIT_BIT BIT(4)
|
||||
|
||||
int ironside_cpuconf(NRF_PROCESSORID_Type cpu, const void *vector_table, bool cpu_wait,
|
||||
const uint8_t *msg, size_t msg_size)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *buf;
|
||||
uint8_t *buf_msg;
|
||||
|
||||
if (msg_size > IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE) {
|
||||
return -IRONSIDE_CPUCONF_ERROR_MESSAGE_TOO_LARGE;
|
||||
}
|
||||
|
||||
buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_CPUCONF_V0;
|
||||
|
||||
buf->args[IRONSIDE_CPUCONF_SERVICE_CPU_PARAMS_IDX] =
|
||||
(((uint32_t)cpu << CPU_PARAMS_CPU_OFFSET) & CPU_PARAMS_CPU_MASK) |
|
||||
(cpu_wait ? CPU_PARAMS_WAIT_BIT : 0);
|
||||
|
||||
buf->args[IRONSIDE_CPUCONF_SERVICE_VECTOR_TABLE_IDX] = (uint32_t)vector_table;
|
||||
|
||||
buf_msg = (uint8_t *)&buf->args[IRONSIDE_CPUCONF_SERVICE_MSG_0];
|
||||
if (msg_size > 0) {
|
||||
memcpy(buf_msg, msg, msg_size);
|
||||
}
|
||||
if (msg_size < IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE) {
|
||||
memset(&buf_msg[msg_size], 0, IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE - msg_size);
|
||||
}
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_CPUCONF_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOT_REPORT_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOT_REPORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Constant used to check if an Nordic IronSide SE boot report has been written. */
|
||||
#define IRONSIDE_BOOT_REPORT_MAGIC (0x4d69546fUL)
|
||||
|
||||
/** UICR had no errors. */
|
||||
#define IRONSIDE_UICR_SUCCESS 0
|
||||
/** There was an unexpected error processing the UICR. */
|
||||
#define IRONSIDE_UICR_ERROR_UNEXPECTED 1
|
||||
/** The UICR integrity check failed. */
|
||||
#define IRONSIDE_UICR_ERROR_INTEGRITY 2
|
||||
/** The UICR content check failed. */
|
||||
#define IRONSIDE_UICR_ERROR_CONTENT 3
|
||||
/** Failed to configure system based on UICR. */
|
||||
#define IRONSIDE_UICR_ERROR_CONFIG 4
|
||||
/** Unsupported UICR format version. */
|
||||
#define IRONSIDE_UICR_ERROR_FORMAT 5
|
||||
|
||||
/** Error found in UICR.PROTECTEDMEM. */
|
||||
#define IRONSIDE_UICR_REGID_PROTECTEDMEM 36
|
||||
/** Error found in UICR.SECURESTORAGE. */
|
||||
#define IRONSIDE_UICR_REGID_SECURESTORAGE 64
|
||||
/** Error found in UICR.PERIPHCONF. */
|
||||
#define IRONSIDE_UICR_REGID_PERIPHCONF 104
|
||||
/** Error found in UICR.MPCCONF. */
|
||||
#define IRONSIDE_UICR_REGID_MPCCONF 116
|
||||
/** Error found in UICR.SECONDARY.ADDRESS/SIZE4KB */
|
||||
#define IRONSIDE_UICR_REGID_SECONDARY 128
|
||||
/** Error found in UICR.SECONDARY.PROTECTEDMEM. */
|
||||
#define IRONSIDE_UICR_REGID_SECONDARY_PROTECTEDMEM 152
|
||||
/** Error found in UICR.SECONDARY.PERIPHCONF. */
|
||||
#define IRONSIDE_UICR_REGID_SECONDARY_PERIPHCONF 172
|
||||
/** Error found in UICR.SECONDARY.MPCCONF. */
|
||||
#define IRONSIDE_UICR_REGID_SECONDARY_MPCCONF 184
|
||||
|
||||
/** Failed to mount a CRYPTO secure storage partition in MRAM. */
|
||||
#define IRONSIDE_UICR_SECURESTORAGE_ERROR_MOUNT_CRYPTO_FAILED 1
|
||||
/** Failed to mount an ITS secure storage partition in MRAM. */
|
||||
#define IRONSIDE_UICR_SECURESTORAGE_ERROR_MOUNT_ITS_FAILED 2
|
||||
/** The start address and total size of all ITS partitions are not aligned to 4 KB. */
|
||||
#define IRONSIDE_UICR_SECURESTORAGE_ERROR_MISALIGNED 3
|
||||
|
||||
/** There was an unexpected error processing UICR.PERIPHCONF. */
|
||||
#define IRONSIDE_UICR_PERIPHCONF_ERROR_UNEXPECTED 1
|
||||
/** The address contained in a UICR.PERIPHCONF array entry is not permitted. */
|
||||
#define IRONSIDE_UICR_PERIPHCONF_ERROR_NOT_PERMITTED 2
|
||||
/** The readback of the value for a UICR.PERIPHCONF array entry did not match. */
|
||||
#define IRONSIDE_UICR_PERIPHCONF_ERROR_READBACK_MISMATCH 3
|
||||
|
||||
/** Booted in secondary mode. */
|
||||
#define IRONSIDE_BOOT_MODE_FLAGS_SECONDARY_MASK 0x1
|
||||
|
||||
/** Booted normally by IronSide SE.*/
|
||||
#define IRONSIDE_BOOT_REASON_DEFAULT 0
|
||||
/** Booted because of a cpuconf service call by a different core. */
|
||||
#define IRONSIDE_BOOT_REASON_CPUCONF_CALL 1
|
||||
/** Booted in secondary mode because of a bootmode service call. */
|
||||
#define IRONSIDE_BOOT_REASON_BOOTMODE_SECONDARY_CALL 2
|
||||
/** Booted in secondary mode because of a boot error in the primary mode. */
|
||||
#define IRONSIDE_BOOT_REASON_BOOTERROR 3
|
||||
/** Booted in secondary mode because of local domain reset reason trigger. */
|
||||
#define IRONSIDE_BOOT_REASON_TRIGGER_RESETREAS 4
|
||||
/** Booted in secondary mode via the CTRL-AP. */
|
||||
#define IRONSIDE_BOOT_REASON_CTRLAP_SECONDARYMODE 5
|
||||
|
||||
/** The boot had no errors. */
|
||||
#define IRONSIDE_BOOT_ERROR_SUCCESS 0x0
|
||||
/** The reset vector for the application firmware was not programmed. */
|
||||
#define IRONSIDE_BOOT_ERROR_NO_APPLICATION_FIRMWARE 0x1
|
||||
/** The IronSide SE was unable to parse the SysCtrl ROM report. */
|
||||
#define IRONSIDE_BOOT_ERROR_ROM_REPORT_INVALID 0x2
|
||||
/** The SysCtrl ROM booted the system in current limited mode due to an issue in the BICR. */
|
||||
#define IRONSIDE_BOOT_ERROR_ROM_REPORT_CURRENT_LIMITED 0x3
|
||||
/** The IronSide SE detected an issue with the HFXO configuration in the BICR. */
|
||||
#define IRONSIDE_BOOT_ERROR_BICR_HFXO_INVALID 0x4
|
||||
/** The IronSide SE detected an issue with the LFXO configuration in the BICR. */
|
||||
#define IRONSIDE_BOOT_ERROR_BICR_LFXO_INVALID 0x5
|
||||
/** The IronSide SE failed to boot the SysCtrl Firmware. */
|
||||
#define IRONSIDE_BOOT_ERROR_SYSCTRL_START_FAILED 0x6
|
||||
/** The UICR integrity check failed. */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_INTEGRITY_FAILED 0x7
|
||||
/** The UICR content is not valid */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_CONTENT_INVALID 0x8
|
||||
/** Integrity check of PROTECTEDMEM failed. */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_PROTECTEDMEM_INTEGRITY_FAILED 0x9
|
||||
/** Failed to configure system based on UICR. */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_CONFIG_FAILED 0xA
|
||||
/** The IronSide SE failed to mount its own storage. */
|
||||
#define IRONSIDE_BOOT_ERROR_SECDOM_STORAGE_MOUNT_FAILED 0xB
|
||||
/** Failed to initialize DVFS service */
|
||||
#define IRONSIDE_BOOT_ERROR_DVFS_INIT_FAILED 0xC
|
||||
/** Failed to boot secondary application firmware; configuration missing from UICR. */
|
||||
#define IRONSIDE_BOOT_ERROR_NO_SECONDARY_APPLICATION_FIRMWARE 0xD
|
||||
/** Integrity check of secondary PROTECTEDMEM failed. */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_SECONDARY_PROTECTEDMEM_INTEGRITY_FAILED 0xE
|
||||
/** Unsupported UICR format version. */
|
||||
#define IRONSIDE_BOOT_ERROR_UICR_FORMAT_UNSUPPORTED 0xF
|
||||
/** Value reserved for conditions that should never happen. */
|
||||
#define IRONSIDE_BOOT_ERROR_UNEXPECTED 0xff
|
||||
|
||||
/** Index for RESETREAS.DOMAIN[NRF_DOMAIN_APPLICATION]. */
|
||||
#define IRONSIDE_SECONDARY_RESETREAS_APPLICATION 0
|
||||
/** Index for RESETREAS.DOMAIN[NRF_DOMAIN_RADIOCORE]. */
|
||||
#define IRONSIDE_SECONDARY_RESETREAS_RADIOCORE 1
|
||||
|
||||
/** Length of the local domain context buffer in bytes. */
|
||||
#define IRONSIDE_BOOT_REPORT_LOCAL_DOMAIN_CONTEXT_SIZE (16UL)
|
||||
/** Length of the random data buffer in bytes. */
|
||||
#define IRONSIDE_BOOT_REPORT_RANDOM_DATA_SIZE (32UL)
|
||||
/** Length of the uuid buffer in bytes. */
|
||||
#define IRONSIDE_BOOT_REPORT_UUID_SIZE (16UL)
|
||||
|
||||
/** @brief Initialization/boot status description contained in the boot report. */
|
||||
struct ironside_boot_report_init_status {
|
||||
/** Reserved for Future Use. */
|
||||
uint8_t rfu1[3];
|
||||
/** Boot error for the current boot (same as reported in BOOTSTATUS)*/
|
||||
uint8_t boot_error;
|
||||
/** Overall UICR status. */
|
||||
uint8_t uicr_status;
|
||||
/** Reserved for Future Use. */
|
||||
uint8_t rfu2;
|
||||
/** ID of the register that caused the error.
|
||||
* Only relevant for IRONSIDE_UICR_ERROR_CONTENT and IRONSIDE_UICR_ERROR_CONFIG.
|
||||
*/
|
||||
uint16_t uicr_regid;
|
||||
/** Additional description for IRONSIDE_UICR_ERROR_CONFIG. */
|
||||
union {
|
||||
/** UICR.SECURESTORAGE error description. */
|
||||
struct {
|
||||
/** Reason that UICR.SECURESTORAGE configuration failed. */
|
||||
uint16_t status;
|
||||
/** Owner ID of the failing secure storage partition.
|
||||
* Only relevant for IRONSIDE_UICR_SECURESTORAGE_ERROR_MOUNT_CRYPTO_FAILED
|
||||
* and IRONSIDE_UICR_SECURESTORAGE_ERROR_MOUNT_ITS_FAILED.
|
||||
*/
|
||||
uint16_t owner_id;
|
||||
} securestorage;
|
||||
/** UICR.PERIPHCONF error description. */
|
||||
struct {
|
||||
/** Reason that UICR.PERIPHCONF configuration failed. */
|
||||
uint16_t status;
|
||||
/** Index of the failing entry in the UICR.PERIPHCONF array. */
|
||||
uint16_t index;
|
||||
} periphconf;
|
||||
} uicr_detail;
|
||||
};
|
||||
|
||||
/** @brief Initialization/boot context description contained in the boot report. */
|
||||
struct ironside_boot_report_init_context {
|
||||
/** Reserved for Future Use */
|
||||
uint8_t rfu[3];
|
||||
/** Reason the processor was started. */
|
||||
uint8_t boot_reason;
|
||||
|
||||
union {
|
||||
/** Data passed from booting local domain to local domain being booted.
|
||||
*
|
||||
* Valid if the boot reason is one of the following:
|
||||
* - IRONSIDE_BOOT_REASON_CPUCONF_CALL
|
||||
* - IRONSIDE_BOOT_REASON_BOOTMODE_SECONDARY_CALL
|
||||
*/
|
||||
uint8_t local_domain_context[IRONSIDE_BOOT_REPORT_LOCAL_DOMAIN_CONTEXT_SIZE];
|
||||
|
||||
/** Initialiation error that triggered the boot.
|
||||
*
|
||||
* Valid if the boot reason is IRONSIDE_BOOT_REASON_BOOTERROR.
|
||||
*/
|
||||
struct ironside_boot_report_init_status trigger_init_status;
|
||||
|
||||
/** RESETREAS.DOMAIN that triggered the boot.
|
||||
*
|
||||
* Valid if the boot reason is IRONSIDE_BOOT_REASON_TRIGGER_RESETREAS.
|
||||
*/
|
||||
uint32_t trigger_resetreas[4];
|
||||
};
|
||||
};
|
||||
|
||||
/** @brief IronSide boot report. */
|
||||
struct ironside_boot_report {
|
||||
/** Magic value used to identify valid boot report */
|
||||
uint32_t magic;
|
||||
/** Firmware version of IronSide SE. 8bit MAJOR.MINOR.PATCH.SEQNUM */
|
||||
uint32_t ironside_se_version_int;
|
||||
/** Human readable extraversion of IronSide SE */
|
||||
char ironside_se_extraversion[12];
|
||||
/** Firmware version of IronSide SE recovery firmware. 8bit MAJOR.MINOR.PATCH.SEQNUM */
|
||||
uint32_t ironside_se_recovery_version_int;
|
||||
/** Human readable extraversion of IronSide SE recovery firmware */
|
||||
char ironside_se_recovery_extraversion[12];
|
||||
/** Copy of SICR.UROT.UPDATE.STATUS.*/
|
||||
uint32_t ironside_update_status;
|
||||
/** Initialization/boot status. */
|
||||
struct ironside_boot_report_init_status init_status;
|
||||
/** Reserved for Future Use */
|
||||
uint16_t rfu1;
|
||||
/** Flags describing the current boot mode. */
|
||||
uint16_t boot_mode_flags;
|
||||
/** Data describing the context under which the CPU was booted. */
|
||||
struct ironside_boot_report_init_context init_context;
|
||||
/** CSPRNG data */
|
||||
uint8_t random_data[IRONSIDE_BOOT_REPORT_RANDOM_DATA_SIZE];
|
||||
/** Device Info data : 128-bit Universally Unique IDentifier (UUID) */
|
||||
uint8_t device_info_uuid[IRONSIDE_BOOT_REPORT_UUID_SIZE];
|
||||
/** Reserved for Future Use */
|
||||
uint32_t rfu2[60];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the IronSide boot report.
|
||||
*
|
||||
* @param[out] report Will be set to point to the IronSide boot report.
|
||||
*
|
||||
* @retval 0 if successful.
|
||||
* @retval -EFAULT if the magic field in the report is incorrect.
|
||||
* @retval -EINVAL if @p report is NULL.
|
||||
*/
|
||||
int ironside_boot_report_get(const struct ironside_boot_report **report);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOT_REPORT_H_ */
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOTMODE_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOTMODE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @name Boot mode service error codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Invalid/unsupported boot mode transition. */
|
||||
#define IRONSIDE_BOOTMODE_ERROR_UNSUPPORTED_MODE (1)
|
||||
/** Failed to reboot into the boot mode due to other activity preventing a reset. */
|
||||
#define IRONSIDE_BOOTMODE_ERROR_BUSY (2)
|
||||
/** The boot message is too large to fit in the buffer. */
|
||||
#define IRONSIDE_BOOTMODE_ERROR_MESSAGE_TOO_LARGE (3)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* IronSide call identifiers with implicit versions. */
|
||||
#define IRONSIDE_CALL_ID_BOOTMODE_SERVICE_V1 5
|
||||
|
||||
enum {
|
||||
IRONSIDE_BOOTMODE_SERVICE_MODE_IDX,
|
||||
IRONSIDE_BOOTMODE_SERVICE_MSG_0_IDX,
|
||||
IRONSIDE_BOOTMODE_SERVICE_MSG_1_IDX,
|
||||
IRONSIDE_BOOTMODE_SERVICE_MSG_2_IDX,
|
||||
IRONSIDE_BOOTMODE_SERVICE_MSG_3_IDX,
|
||||
/* The last enum value is reserved for the number of arguments */
|
||||
IRONSIDE_BOOTMODE_SERVICE_NUM_ARGS,
|
||||
};
|
||||
|
||||
/* Maximum size of the message parameter. */
|
||||
#define IRONSIDE_BOOTMODE_SERVICE_MSG_MAX_SIZE (4 * sizeof(uint32_t))
|
||||
|
||||
/* Index of the return code within the service buffer. */
|
||||
#define IRONSIDE_BOOTMODE_SERVICE_RETCODE_IDX (0)
|
||||
|
||||
/**
|
||||
* @brief Request a reboot into the secondary firmware boot mode.
|
||||
*
|
||||
* This invokes the IronSide SE boot mode service to restart the system into the secondary boot
|
||||
* mode. In this mode, the secondary configuration defined in UICR is applied instead of the
|
||||
* primary one. The system immediately reboots without a reply if the request succeeds.
|
||||
*
|
||||
* The given message data is passed to the boot report of the CPU booted in the secondary boot mode.
|
||||
*
|
||||
* @note This function does not return if the request is successful.
|
||||
* @note The device will boot into the secondary firmware instead of primary firmware.
|
||||
* @note The request does not fail if the secondary firmware is not defined.
|
||||
*
|
||||
* @param msg A message that can be placed in the cpu's boot report.
|
||||
* @param msg_size Size of the message in bytes.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_BOOTMODE_ERROR_UNSUPPORTED_MODE if the secondary boot mode is unsupported.
|
||||
* @retval -IRONSIDE_BOOTMODE_ERROR_BUSY if the reboot was blocked.
|
||||
* @retval -IRONSIDE_BOOTMODE_ERROR_MESSAGE_TOO_LARGE if msg_size is greater than
|
||||
* IRONSIDE_BOOTMODE_SERVICE_MSG_MAX_SIZE.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_bootmode_secondary_reboot(const uint8_t *msg, size_t msg_size);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_BOOTMODE_H_ */
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CALL_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CALL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** @brief Maximum number of arguments to an IronSide call.
|
||||
*
|
||||
* This is chosen so that the containing message buffer size is minimal but
|
||||
* cache line aligned.
|
||||
*/
|
||||
#define NRF_IRONSIDE_CALL_NUM_ARGS 7
|
||||
|
||||
/** @brief Message buffer. */
|
||||
struct ironside_call_buf {
|
||||
/** Status code. This is set by the API. */
|
||||
uint16_t status;
|
||||
/** Operation identifier. This is set by the user. */
|
||||
uint16_t id;
|
||||
/** Operation arguments. These are set by the user. */
|
||||
uint32_t args[NRF_IRONSIDE_CALL_NUM_ARGS];
|
||||
};
|
||||
|
||||
/**
|
||||
* @name Message buffer status codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Buffer is idle and available for allocation. */
|
||||
#define IRONSIDE_CALL_STATUS_IDLE 0
|
||||
/** Request was processed successfully by the server. */
|
||||
#define IRONSIDE_CALL_STATUS_RSP_SUCCESS 1
|
||||
/** Request status code is unknown. */
|
||||
#define IRONSIDE_CALL_STATUS_RSP_ERR_UNKNOWN_STATUS 2
|
||||
/** Request status code is no longer supported. */
|
||||
#define IRONSIDE_CALL_STATUS_RSP_ERR_EXPIRED_STATUS 3
|
||||
/** Operation identifier is unknown. */
|
||||
#define IRONSIDE_CALL_STATUS_RSP_ERR_UNKNOWN_ID 4
|
||||
/** Operation identifier is no longer supported. */
|
||||
#define IRONSIDE_CALL_STATUS_RSP_ERR_EXPIRED_ID 5
|
||||
/** Buffer contains a request from the client. */
|
||||
#define IRONSIDE_CALL_STATUS_REQ 6
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for an IronSide call.
|
||||
*
|
||||
* This function will block when no buffers are available, until one is
|
||||
* released by another thread on the client side.
|
||||
*
|
||||
* @return Pointer to the allocated buffer.
|
||||
*/
|
||||
struct ironside_call_buf *ironside_call_alloc(void);
|
||||
|
||||
/**
|
||||
* @brief Dispatch an IronSide call.
|
||||
*
|
||||
* This function will block until a response is received from the server.
|
||||
*
|
||||
* @param buf Buffer returned by ironside_call_alloc(). It should be populated
|
||||
* with request data before calling this function. Upon returning,
|
||||
* this data will have been replaced by response data.
|
||||
*/
|
||||
void ironside_call_dispatch(struct ironside_call_buf *buf);
|
||||
|
||||
/**
|
||||
* @brief Release an IronSide call buffer.
|
||||
*
|
||||
* This function must be called after processing the response.
|
||||
*
|
||||
* @param buf Buffer used to perform the call.
|
||||
*/
|
||||
void ironside_call_release(struct ironside_call_buf *buf);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CALL_H_ */
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/toolchain.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
/**
|
||||
* @name Counter service error codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Counter value is lower than current value (monotonic violation). */
|
||||
#define IRONSIDE_COUNTER_ERROR_TOO_LOW (1)
|
||||
/** Invalid counter ID. */
|
||||
#define IRONSIDE_COUNTER_ERROR_INVALID_ID (2)
|
||||
/** Counter is locked and cannot be modified. */
|
||||
#define IRONSIDE_COUNTER_ERROR_LOCKED (3)
|
||||
/** Invalid parameter. */
|
||||
#define IRONSIDE_COUNTER_ERROR_INVALID_PARAM (4)
|
||||
/** Storage operation failed. */
|
||||
#define IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE (5)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** Maximum value for a counter */
|
||||
#define IRONSIDE_COUNTER_MAX_VALUE UINT32_MAX
|
||||
|
||||
/** Number of counters */
|
||||
#define IRONSIDE_COUNTER_NUM 4
|
||||
|
||||
/**
|
||||
* @brief Counter identifiers.
|
||||
*/
|
||||
enum ironside_counter {
|
||||
IRONSIDE_COUNTER_0 = 0,
|
||||
IRONSIDE_COUNTER_1,
|
||||
IRONSIDE_COUNTER_2,
|
||||
IRONSIDE_COUNTER_3
|
||||
};
|
||||
|
||||
/* IronSide call identifiers with implicit versions. */
|
||||
#define IRONSIDE_CALL_ID_COUNTER_SET_V1 6
|
||||
#define IRONSIDE_CALL_ID_COUNTER_GET_V1 7
|
||||
#define IRONSIDE_CALL_ID_COUNTER_LOCK_V1 8
|
||||
|
||||
enum {
|
||||
IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX,
|
||||
IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX,
|
||||
/* The last enum value is reserved for the number of arguments */
|
||||
IRONSIDE_COUNTER_SET_NUM_ARGS
|
||||
};
|
||||
|
||||
enum {
|
||||
IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX,
|
||||
/* The last enum value is reserved for the number of arguments */
|
||||
IRONSIDE_COUNTER_GET_NUM_ARGS
|
||||
};
|
||||
|
||||
enum {
|
||||
IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX,
|
||||
/* The last enum value is reserved for the number of arguments */
|
||||
IRONSIDE_COUNTER_LOCK_NUM_ARGS
|
||||
};
|
||||
|
||||
/* Index of the return code within the service buffer. */
|
||||
#define IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX (0)
|
||||
#define IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX (0)
|
||||
#define IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX (0)
|
||||
|
||||
/* Index of the value within the GET response buffer. */
|
||||
#define IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX (1)
|
||||
|
||||
BUILD_ASSERT(IRONSIDE_COUNTER_SET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
|
||||
BUILD_ASSERT(IRONSIDE_COUNTER_GET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
|
||||
BUILD_ASSERT(IRONSIDE_COUNTER_LOCK_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
|
||||
|
||||
/**
|
||||
* @brief Set a counter value.
|
||||
*
|
||||
* This sets the specified counter to the given value. The counter is monotonic,
|
||||
* so the new value must be greater than or equal to the current value.
|
||||
* If the counter is locked, the operation will fail.
|
||||
*
|
||||
* @note Counters are automatically initialized to 0 during the first boot in LCS ROT.
|
||||
* The monotonic constraint applies to all subsequent writes.
|
||||
*
|
||||
* @param counter_id Counter identifier.
|
||||
* @param value New counter value.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_TOO_LOW if value is lower than current value.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_LOCKED if counter is locked.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_counter_set(enum ironside_counter counter_id, uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Get a counter value.
|
||||
*
|
||||
* This retrieves the current value of the specified counter.
|
||||
*
|
||||
* @note Counters are automatically initialized to 0 during the first boot in LCS ROT,
|
||||
* so this function will always succeed for valid counter IDs.
|
||||
*
|
||||
* @param counter_id Counter identifier.
|
||||
* @param value Pointer to store the counter value.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_PARAM if value is NULL.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value);
|
||||
|
||||
/**
|
||||
* @brief Lock a counter for the current boot.
|
||||
*
|
||||
* This locks the specified counter, preventing any further modifications until the next reboot.
|
||||
* The lock state is not persistent and will be cleared on reboot.
|
||||
*
|
||||
* @note The intended use case is for a bootloader to lock a counter before transferring control
|
||||
* to the next boot stage, preventing that image from modifying the counter value.
|
||||
*
|
||||
* @param counter_id Counter identifier.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_counter_lock(enum ironside_counter counter_id);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_ */
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CPUCONF_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CPUCONF_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <zephyr/toolchain/common.h>
|
||||
#include <nrfx.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
/**
|
||||
* @name CPUCONF service error codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** An invalid or unsupported processor ID was specified. */
|
||||
#define IRONSIDE_CPUCONF_ERROR_WRONG_CPU (1)
|
||||
/** The boot message is too large to fit in the buffer. */
|
||||
#define IRONSIDE_CPUCONF_ERROR_MESSAGE_TOO_LARGE (2)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define IRONSIDE_CALL_ID_CPUCONF_V0 2
|
||||
|
||||
enum {
|
||||
IRONSIDE_CPUCONF_SERVICE_CPU_PARAMS_IDX,
|
||||
IRONSIDE_CPUCONF_SERVICE_VECTOR_TABLE_IDX,
|
||||
IRONSIDE_CPUCONF_SERVICE_MSG_0,
|
||||
IRONSIDE_CPUCONF_SERVICE_MSG_1,
|
||||
IRONSIDE_CPUCONF_SERVICE_MSG_2,
|
||||
IRONSIDE_CPUCONF_SERVICE_MSG_3,
|
||||
/* The last enum value is reserved for the number of arguments */
|
||||
IRONSIDE_CPUCONF_NUM_ARGS
|
||||
};
|
||||
|
||||
/* Maximum size of the CPUCONF message parameter. */
|
||||
#define IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE (4 * sizeof(uint32_t))
|
||||
|
||||
/* IDX 0 is re-used by the error return code and the 'cpu' parameter. */
|
||||
#define IRONSIDE_CPUCONF_SERVICE_RETCODE_IDX 0
|
||||
|
||||
BUILD_ASSERT(IRONSIDE_CPUCONF_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
|
||||
|
||||
/**
|
||||
* @brief Boot a local domain CPU
|
||||
*
|
||||
* @param cpu The CPU to be booted
|
||||
* @param vector_table Pointer to the vector table used to boot the CPU.
|
||||
* @param cpu_wait When this is true, the CPU will WAIT even if the CPU has clock.
|
||||
* @param msg A message that can be placed in cpu's boot report.
|
||||
* @param msg_size Size of the message in bytes.
|
||||
*
|
||||
* @note cpu_wait is only intended to be enabled for debug purposes
|
||||
* and it is only supported that a debugger resumes the CPU.
|
||||
*
|
||||
* @note the call always sends IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE message bytes.
|
||||
* If the given msg_size is less than that, the remaining bytes are set to zero.
|
||||
*
|
||||
* @retval 0 on success or if the CPU has already booted.
|
||||
* @retval -IRONSIDE_CPUCONF_ERROR_WRONG_CPU if cpu is unrecognized.
|
||||
* @retval -IRONSIDE_CPUCONF_ERROR_MESSAGE_TOO_LARGE if msg_size is greater than
|
||||
* IRONSIDE_CPUCONF_SERVICE_MSG_MAX_SIZE.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_cpuconf(NRF_PROCESSORID_Type cpu, const void *vector_table, bool cpu_wait,
|
||||
const uint8_t *msg, size_t msg_size);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_CPUCONF_H_ */
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_DVFS_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_DVFS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
enum ironside_dvfs_oppoint {
|
||||
IRONSIDE_DVFS_OPP_HIGH = 0,
|
||||
IRONSIDE_DVFS_OPP_MEDLOW = 1,
|
||||
IRONSIDE_DVFS_OPP_LOW = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Number of DVFS oppoints supported by IronSide.
|
||||
*
|
||||
* This is the number of different DVFS oppoints that can be set on IronSide.
|
||||
* The oppoints are defined in the `ironside_dvfs_oppoint` enum.
|
||||
*/
|
||||
#define IRONSIDE_DVFS_OPPOINT_COUNT (3)
|
||||
|
||||
/**
|
||||
* @name IronSide DVFS service error codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** The requested DVFS oppoint is not allowed. */
|
||||
#define IRONSIDE_DVFS_ERROR_WRONG_OPPOINT (1)
|
||||
/** Waiting for mutex lock timed out, or hardware is busy. */
|
||||
#define IRONSIDE_DVFS_ERROR_BUSY (2)
|
||||
/** There is configuration error in the DVFS service. */
|
||||
#define IRONSIDE_DVFS_ERROR_OPPOINT_DATA (3)
|
||||
/** The caller does not have permission to change the DVFS oppoint. */
|
||||
#define IRONSIDE_DVFS_ERROR_PERMISSION (4)
|
||||
/** The requested DVFS oppoint is already set, no change needed. */
|
||||
#define IRONSIDE_DVFS_ERROR_NO_CHANGE_NEEDED (5)
|
||||
/** The operation timed out, possibly due to a hardware issue. */
|
||||
#define IRONSIDE_DVFS_ERROR_TIMEOUT (6)
|
||||
/** The DVFS oppoint change operation is not allowed in the ISR context. */
|
||||
#define IRONSIDE_DVFS_ERROR_ISR_NOT_ALLOWED (7)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* IronSide call identifiers with implicit versions.
|
||||
*
|
||||
* With the initial "version 0", the service ABI is allowed to break until the
|
||||
* first production release of IronSide SE.
|
||||
*/
|
||||
#define IRONSIDE_CALL_ID_DVFS_SERVICE_V0 3
|
||||
|
||||
/* Index of the DVFS oppoint within the service buffer. */
|
||||
#define IRONSIDE_DVFS_SERVICE_OPPOINT_IDX (0)
|
||||
/* Index of the return code within the service buffer. */
|
||||
#define IRONSIDE_DVFS_SERVICE_RETCODE_IDX (0)
|
||||
|
||||
/**
|
||||
* @brief Change the current DVFS oppoint.
|
||||
*
|
||||
* This function will request a change of the current DVFS oppoint to the
|
||||
* specified value. It will block until the change is applied.
|
||||
*
|
||||
* @param dvfs_oppoint The new DVFS oppoint to set.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_WRONG_OPPOINT if the requested DVFS oppoint is not allowed.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_BUSY if waiting for mutex lock timed out, or hardware is busy.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_OPPOINT_DATA if there is configuration error in the DVFS service.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_PERMISSION if the caller does not have permission to change the DVFS
|
||||
* oppoint.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_NO_CHANGE_NEEDED if the requested DVFS oppoint is already set.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_TIMEOUT if the operation timed out, possibly due to a hardware
|
||||
* issue.
|
||||
* @retval -IRONSIDE_DVFS_ERROR_ISR_NOT_ALLOWED if the DVFS oppoint change operation is not allowed
|
||||
* in the ISR context.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_dvfs_change_oppoint(enum ironside_dvfs_oppoint dvfs_oppoint);
|
||||
|
||||
/**
|
||||
* @brief Check if the given oppoint is valid.
|
||||
*
|
||||
* @param dvfs_oppoint The oppoint to check.
|
||||
* @return true if the oppoint is valid, false otherwise.
|
||||
*/
|
||||
static inline bool ironside_dvfs_is_oppoint_valid(enum ironside_dvfs_oppoint dvfs_oppoint)
|
||||
{
|
||||
if (dvfs_oppoint != IRONSIDE_DVFS_OPP_HIGH && dvfs_oppoint != IRONSIDE_DVFS_OPP_MEDLOW &&
|
||||
dvfs_oppoint != IRONSIDE_DVFS_OPP_LOW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_DVFS_H_ */
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_TDD_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_TDD_H_
|
||||
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
#include <nrfx.h>
|
||||
|
||||
#define IRONSIDE_SE_TDD_SERVICE_ERROR_INVALID_CONFIG (1)
|
||||
|
||||
#define IRONSIDE_SE_CALL_ID_TDD_V0 4
|
||||
|
||||
#define IRONSIDE_SE_TDD_SERVICE_REQ_CONFIG_IDX 0
|
||||
#define IRONSIDE_SE_TDD_SERVICE_RSP_RETCODE_IDX 0
|
||||
|
||||
enum ironside_se_tdd_config {
|
||||
RESERVED0 = 0, /* Reserved */
|
||||
/** Turn off the TDD */
|
||||
IRONSIDE_SE_TDD_CONFIG_OFF = 1,
|
||||
/** Turn on the TDD with default configuration */
|
||||
IRONSIDE_SE_TDD_CONFIG_ON_DEFAULT = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Control the Trace and Debug Domain (TDD).
|
||||
*
|
||||
* @param config The configuration to be applied.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -IRONSIDE_SE_TDD_SERVICE_ERROR_INVALID_CONFIG if the configuration is invalid.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*/
|
||||
int ironside_se_tdd_configure(const enum ironside_se_tdd_config config);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_TDD_H_ */
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_UPDATE_H_
|
||||
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_UPDATE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @name Update service error codes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Caller does not have access to the provided update candidate buffer. */
|
||||
#define IRONSIDE_UPDATE_ERROR_NOT_PERMITTED (1)
|
||||
/** Failed to write the update metadata to SICR. */
|
||||
#define IRONSIDE_UPDATE_ERROR_SICR_WRITE_FAILED (2)
|
||||
/** Update candidate is placed outside of valid range */
|
||||
#define IRONSIDE_UPDATE_ERROR_INVALID_ADDRESS (3)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** Size of the update blob */
|
||||
#ifdef CONFIG_SOC_SERIES_NRF54HX
|
||||
#define IRONSIDE_UPDATE_BLOB_SIZE (160 * 1024)
|
||||
#elif CONFIG_SOC_SERIES_NRF92X
|
||||
#define IRONSIDE_UPDATE_BLOB_SIZE (160 * 1024)
|
||||
#else
|
||||
#error "Missing update blob size"
|
||||
#endif
|
||||
|
||||
/** Min address used for storing the update candidate */
|
||||
#define IRONSIDE_UPDATE_MIN_ADDRESS (0x0e100000)
|
||||
/** Max address used for storing the update candidate */
|
||||
#define IRONSIDE_UPDATE_MAX_ADDRESS (0x0e200000 - IRONSIDE_UPDATE_BLOB_SIZE)
|
||||
|
||||
/** Length of the update manifest in bytes */
|
||||
#define IRONSIDE_UPDATE_MANIFEST_LENGTH (256)
|
||||
/** Length of the update public key in bytes. */
|
||||
#define IRONSIDE_UPDATE_PUBKEY_LENGTH (32)
|
||||
/** Length of the update signature in bytes. */
|
||||
#define IRONSIDE_UPDATE_SIGNATURE_LENGTH (64)
|
||||
|
||||
/* IronSide call identifiers with implicit versions.
|
||||
*
|
||||
* With the initial "version 0", the service ABI is allowed to break until the
|
||||
* first production release of IronSide SE.
|
||||
*/
|
||||
#define IRONSIDE_CALL_ID_UPDATE_SERVICE_V0 1
|
||||
|
||||
/* Index of the update blob pointer within the service buffer. */
|
||||
#define IRONSIDE_UPDATE_SERVICE_UPDATE_PTR_IDX (0)
|
||||
/* Index of the return code within the service buffer. */
|
||||
#define IRONSIDE_UPDATE_SERVICE_RETCODE_IDX (0)
|
||||
|
||||
/**
|
||||
* @brief IronSide update blob.
|
||||
*/
|
||||
struct ironside_update_blob {
|
||||
uint8_t manifest[IRONSIDE_UPDATE_MANIFEST_LENGTH];
|
||||
uint8_t pubkey[IRONSIDE_UPDATE_PUBKEY_LENGTH];
|
||||
uint8_t signature[IRONSIDE_UPDATE_SIGNATURE_LENGTH];
|
||||
uint32_t firmware[];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Request a firmware upgrade of the IronSide SE.
|
||||
*
|
||||
* This invokes the IronSide SE update service. The device must be restarted for the update
|
||||
* to be installed. Check the update status in the application boot report to see if the update
|
||||
* was successfully installed.
|
||||
*
|
||||
* @param update Pointer to update blob
|
||||
*
|
||||
* @retval 0 on a successful request (although the update itself may still fail).
|
||||
* @retval -IRONSIDE_UPDATE_ERROR_INVALID_ADDRESS if the address of the update is outside of the
|
||||
* accepted range.
|
||||
* @retval -IRONSIDE_UPDATE_ERROR_NOT_PERMITTED if missing access to the update candidate.
|
||||
* @retval -IRONSIDE_UPDATE_ERROR_SICR_WRITE_FAILED if writing update parameters to SICR failed.
|
||||
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
|
||||
*
|
||||
*/
|
||||
int ironside_update(const struct ironside_update_blob *update);
|
||||
|
||||
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_UPDATE_H_ */
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <nrf_ironside/tdd.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
int ironside_se_tdd_configure(const enum ironside_se_tdd_config config)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *const buf = ironside_call_alloc();
|
||||
|
||||
buf->id = IRONSIDE_SE_CALL_ID_TDD_V0;
|
||||
buf->args[IRONSIDE_SE_TDD_SERVICE_REQ_CONFIG_IDX] = (uint32_t)config;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_SE_TDD_SERVICE_RSP_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <nrf_ironside/update.h>
|
||||
#include <nrf_ironside/call.h>
|
||||
|
||||
int ironside_update(const struct ironside_update_blob *update)
|
||||
{
|
||||
int err;
|
||||
struct ironside_call_buf *const buf = ironside_call_alloc();
|
||||
|
||||
if ((uintptr_t)update < IRONSIDE_UPDATE_MIN_ADDRESS ||
|
||||
(uintptr_t)update > IRONSIDE_UPDATE_MAX_ADDRESS) {
|
||||
return -IRONSIDE_UPDATE_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
buf->id = IRONSIDE_CALL_ID_UPDATE_SERVICE_V0;
|
||||
buf->args[IRONSIDE_UPDATE_SERVICE_UPDATE_PTR_IDX] = (uintptr_t)update;
|
||||
|
||||
ironside_call_dispatch(buf);
|
||||
|
||||
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
|
||||
err = buf->args[IRONSIDE_UPDATE_SERVICE_RETCODE_IDX];
|
||||
} else {
|
||||
err = buf->status;
|
||||
}
|
||||
|
||||
ironside_call_release(buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SOC_SERIES_NRF54HX
|
||||
select HAS_IRONSIDE_SE
|
||||
select HAS_NRFS
|
||||
select HAS_NRFX
|
||||
select HAS_NORDIC_DRIVERS
|
||||
@@ -71,7 +72,7 @@ config SOC_NRF54H20_CPURAD_ENABLE
|
||||
bool "Boot the nRF54H20 Radio core"
|
||||
default y if NRF_802154_SER_HOST || BT_HCI_HOST
|
||||
depends on SOC_NRF54H20_CPUAPP
|
||||
select NRF_IRONSIDE_CPUCONF_SERVICE
|
||||
select IRONSIDE_SE_CALL
|
||||
select SOC_LATE_INIT_HOOK
|
||||
help
|
||||
This will at application boot time enable clock to the
|
||||
|
||||
@@ -17,4 +17,7 @@ config POWER_DOMAIN
|
||||
config CODE_DATA_RELOCATION
|
||||
default y if (PM || POWEROFF) && !MCUBOOT
|
||||
|
||||
config NRF_PERIPHCONF_SECTION
|
||||
default y
|
||||
|
||||
endif # SOC_NRF54H20_CPUAPP
|
||||
|
||||
@@ -17,4 +17,7 @@ config POWER_DOMAIN
|
||||
config CODE_DATA_RELOCATION
|
||||
default y if PM || POWEROFF
|
||||
|
||||
config NRF_PERIPHCONF_SECTION
|
||||
default y
|
||||
|
||||
endif # SOC_NRF54H20_CPURAD
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <dmm.h>
|
||||
|
||||
#if defined(CONFIG_SOC_NRF54H20_CPURAD_ENABLE)
|
||||
#include <nrf_ironside/cpuconf.h>
|
||||
#include <ironside/se/api.h>
|
||||
#endif
|
||||
|
||||
LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
|
||||
@@ -225,8 +225,8 @@ void soc_late_init_hook(void)
|
||||
|
||||
bool cpu_wait = IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD_ENABLE_DEBUG_WAIT);
|
||||
|
||||
err_cpuconf = ironside_cpuconf(NRF_PROCESSOR_RADIOCORE, radiocore_address, cpu_wait, msg,
|
||||
msg_size);
|
||||
err_cpuconf = ironside_se_cpuconf(NRF_PROCESSOR_RADIOCORE, radiocore_address, cpu_wait, msg,
|
||||
msg_size);
|
||||
__ASSERT(err_cpuconf == 0, "err_cpuconf was %d", err_cpuconf);
|
||||
#endif /* CONFIG_SOC_NRF54H20_CPURAD_ENABLE */
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SOC_SERIES_NRF92X
|
||||
select HAS_IRONSIDE_SE
|
||||
select HAS_NRFS
|
||||
select HAS_NRFX
|
||||
select HAS_NORDIC_DRIVERS
|
||||
|
||||
@@ -8,4 +8,7 @@ if SOC_NRF9280_CPUAPP
|
||||
config NUM_IRQS
|
||||
default 471
|
||||
|
||||
config NRF_PERIPHCONF_SECTION
|
||||
default y
|
||||
|
||||
endif # SOC_NRF9280_CPUAPP
|
||||
|
||||
@@ -8,4 +8,7 @@ if SOC_NRF9280_CPURAD
|
||||
config NUM_IRQS
|
||||
default 471
|
||||
|
||||
config NRF_PERIPHCONF_SECTION
|
||||
default y
|
||||
|
||||
endif # SOC_NRF9280_CPURAD
|
||||
|
||||
Reference in New Issue
Block a user