From 71c40203316122507479dd6dbc952a00b941d7ed Mon Sep 17 00:00:00 2001 From: Andreas Moltumyr Date: Wed, 15 May 2024 16:30:05 +0200 Subject: [PATCH] lib: nrf_modem_lib: nRF92 support Add support for running nrf_modem library on nRF92 application CPU. Signed-off-by: Andreas Moltumyr --- lib/nrf_modem_lib/CMakeLists.txt | 1 + lib/nrf_modem_lib/Kconfig | 3 +- lib/nrf_modem_lib/Kconfig.modemlib | 29 +++- lib/nrf_modem_lib/nrf_modem_lib.c | 51 ++++-- lib/nrf_modem_lib/nrf_modem_os.c | 23 ++- lib/nrf_modem_lib/nrf_modem_os_rpc.c | 244 +++++++++++++++++++++++++++ lib/nrf_modem_lib/sanity.c | 4 + 7 files changed, 335 insertions(+), 20 deletions(-) create mode 100644 lib/nrf_modem_lib/nrf_modem_os_rpc.c diff --git a/lib/nrf_modem_lib/CMakeLists.txt b/lib/nrf_modem_lib/CMakeLists.txt index 20318cd4ca14..217cec7f6eca 100644 --- a/lib/nrf_modem_lib/CMakeLists.txt +++ b/lib/nrf_modem_lib/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library() zephyr_library_sources(nrf_modem_lib.c) zephyr_library_sources(nrf_modem_os.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF92X nrf_modem_os_rpc.c) zephyr_library_sources_ifdef(CONFIG_NRF_MODEM_LIB_CFUN_HOOKS cfun_hooks.c) zephyr_library_sources_ifdef(CONFIG_NRF_MODEM_LIB_MEM_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS nrf9x_sockets.c) diff --git a/lib/nrf_modem_lib/Kconfig b/lib/nrf_modem_lib/Kconfig index c8fe1d183508..985061e9f624 100644 --- a/lib/nrf_modem_lib/Kconfig +++ b/lib/nrf_modem_lib/Kconfig @@ -5,8 +5,7 @@ menuconfig NRF_MODEM_LIB bool "Modem library" - depends on SOC_SERIES_NRF91X - depends on TRUSTED_EXECUTION_NONSECURE + depends on (SOC_SERIES_NRF91X && TRUSTED_EXECUTION_NONSECURE) || SOC_NRF9280_CPUAPP select NRF_MODEM imply NET_SOCKETS_OFFLOAD imply NET_SOCKETS_POSIX_NAMES if !POSIX_API diff --git a/lib/nrf_modem_lib/Kconfig.modemlib b/lib/nrf_modem_lib/Kconfig.modemlib index 7fd74700a40c..df556fcdffc5 100644 --- a/lib/nrf_modem_lib/Kconfig.modemlib +++ b/lib/nrf_modem_lib/Kconfig.modemlib @@ -20,6 +20,8 @@ config NRF_MODEM_LIB_HEAP_SIZE Size of the library heap. This heap is allocated from the application's RAM region. +DT_NODE_PATH_SHMEM_CTRL := $(dt_nodelabel_path,cpuapp_cpucell_ipc_shm_ctrl) + config NRF_MODEM_LIB_SHMEM_CTRL_SIZE hex default NRF_MODEM_SHMEM_CTRL_SIZE @@ -28,9 +30,12 @@ config NRF_MODEM_LIB_SHMEM_CTRL_SIZE This is a constant for a given library build, and is exported by the library via NRF_MODEM_SHMEM_CTRL_SIZE. +DT_NODE_PATH_SHMEM_TX := $(dt_nodelabel_path,cpuapp_cpucell_ipc_shm_heap) + config NRF_MODEM_LIB_SHMEM_TX_SIZE - int "TX region size" + int "TX region size" if !SOC_SERIES_NRF92X range 1024 32768 + default $(dt_node_reg_size_int,$(DT_NODE_PATH_SHMEM_TX)) if SOC_SERIES_NRF92X # Set default to 8k plus Zephyr heap overhead (128 bytes) default 8320 help @@ -38,16 +43,33 @@ config NRF_MODEM_LIB_SHMEM_TX_SIZE data from the application to the modem, e.g. buffers passed to `send()`, AT commands. The size must be a multiple of four to keep the memory partitions word-aligned. +DT_NODE_PATH_SHMEM_RX := $(dt_nodelabel_path,cpucell_cpuapp_ipc_shm_heap) + config NRF_MODEM_LIB_SHMEM_RX_SIZE - int "RX region size" + int "RX region size" if !SOC_SERIES_NRF92X range 2488 32768 if SOC_NRF9160 range 2616 32768 if SOC_NRF9120 + default $(dt_node_reg_size_int,$(DT_NODE_PATH_SHMEM_RX)) if SOC_SERIES_NRF92X default 8192 help Size of the shared memory region owned by the modem. This area holds all incoming data from the modem, plus the modem's own control structures. The size must be a multiple of four to keep the memory partitions word-aligned. +if SOC_SERIES_NRF92X + +config NRF_MODEM_LIB_TRANSPORT_MBOX + bool + default y + select MBOX + select IPC_SERVICE + select IPC_SERVICE_ICMSG + select IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC + +endif # SOC_SERIES_NRF92X + +if SOC_SERIES_NRF91X || UNITY + config NRF_MODEM_LIB_SHMEM_TRACE_SIZE_OVERRIDE bool "Custom trace region size" depends on NRF_MODEM_LIB_TRACE @@ -61,6 +83,8 @@ config NRF_MODEM_LIB_SHMEM_TRACE_SIZE help Size of the shared memory region used to receive modem traces. +endif # SOC_SERIES_NRF91X || UNITY + config NRF_MODEM_LIB_SENDMSG_BUF_SIZE int "Size of the sendmsg intermediate buffer" default 128 @@ -102,6 +126,7 @@ endmenu # Memory config menuconfig NRF_MODEM_LIB_TRACE bool "Tracing" + depends on SOC_SERIES_NRF91X || UNITY help When enabled, a portion of RAM (called Trace region) will be shared with the modem to receive modem's trace data. The size of the Trace region is defined by the NRF_MODEM_LIB_SHMEM_TRACE_SIZE option. diff --git a/lib/nrf_modem_lib/nrf_modem_lib.c b/lib/nrf_modem_lib/nrf_modem_lib.c index db3f0d735044..209f6303e887 100644 --- a/lib/nrf_modem_lib/nrf_modem_lib.c +++ b/lib/nrf_modem_lib/nrf_modem_lib.c @@ -4,16 +4,26 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include +#include #include #include #include #include #include -#include #include -#include + +#include +LOG_MODULE_DECLARE(nrf_modem, CONFIG_NRF_MODEM_LIB_LOG_LEVEL); + +#define AT_CFUN_READ "AT+CFUN?" +#define AT_CFUN0_VAL 0 +#define AT_CFUN4_VAL 4 + +static void nrf_modem_lib_dfu_handler(uint32_t dfu_res); + +#ifdef CONFIG_SOC_SERIES_NRF91X #include +#include #include #ifndef CONFIG_TRUSTED_EXECUTION_NONSECURE @@ -21,23 +31,15 @@ Are you building for the correct board ? #endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE */ -LOG_MODULE_DECLARE(nrf_modem, CONFIG_NRF_MODEM_LIB_LOG_LEVEL); - /* Interrupt used for communication with the network layer. */ #define NRF_MODEM_IPC_IRQ DT_IRQ_BY_IDX(DT_NODELABEL(ipc), 0, irq) BUILD_ASSERT(IPC_IRQn == NRF_MODEM_IPC_IRQ, "NRF_MODEM_IPC_IRQ mismatch"); -#define AT_CFUN_READ "AT+CFUN?" -#define AT_CFUN0_VAL 0 -#define AT_CFUN4_VAL 4 - /* The heap implementation in `nrf_modem_os.c` require some overhead * to allow allocating up to `NRF_MODEM_LIB_SHMEM_TX_SIZE` bytes. */ #define NRF_MODEM_LIB_SHMEM_TX_HEAP_OVERHEAD_SIZE 128 -static void nrf_modem_lib_dfu_handler(uint32_t dfu_res); - static const struct nrf_modem_init_params init_params = { .ipc_irq_prio = CONFIG_NRF_MODEM_LIB_IPC_IRQ_PRIO, .shmem.ctrl = { @@ -69,6 +71,27 @@ static const struct nrf_modem_bootloader_init_params bootloader_init_params = { .shmem.size = PM_NRF_MODEM_LIB_SRAM_SIZE, .fault_handler = nrf_modem_fault_handler }; +#endif /* CONFIG_SOC_SERIES_NRF91X */ + +#ifdef CONFIG_SOC_SERIES_NRF92X + +static const struct nrf_modem_init_params init_params = { + .shmem.ctrl = { + .base = DT_REG_ADDR(DT_NODELABEL(cpuapp_cpucell_ipc_shm)), + .size = CONFIG_NRF_MODEM_LIB_SHMEM_CTRL_SIZE, + }, + .shmem.tx = { + .base = DT_REG_ADDR(DT_NODELABEL(cpuapp_cpucell_ipc_shm_heap)), + .size = CONFIG_NRF_MODEM_LIB_SHMEM_TX_SIZE, + }, + .shmem.rx = { + .base = DT_REG_ADDR(DT_NODELABEL(cpucell_cpuapp_ipc_shm_heap)), + .size = CONFIG_NRF_MODEM_LIB_SHMEM_RX_SIZE, + }, + .fault_handler = nrf_modem_fault_handler, + .dfu_handler = nrf_modem_lib_dfu_handler, +}; +#endif /* CONFIG_SOC_SERIES_NRF92X */ #if CONFIG_NRF_MODEM_LIB_TRACE extern void nrf_modem_lib_trace_init(void); @@ -129,11 +152,13 @@ int nrf_modem_lib_init(void) { int err; +#ifdef CONFIG_SOC_SERIES_NRF91X /* Setup the network IRQ used by the Modem library. * Note: No call to irq_enable() here, that is done through nrf_modem_init(). */ IRQ_CONNECT(NRF_MODEM_IPC_IRQ, CONFIG_NRF_MODEM_LIB_IPC_IRQ_PRIO, nrfx_isr, nrfx_ipc_irq_handler, 0); +#endif /* CONFIG_SOC_SERIES_NRF91X */ err = nrf_modem_init(&init_params); if (err) { @@ -161,7 +186,11 @@ int nrf_modem_lib_init(void) int nrf_modem_lib_bootloader_init(void) { +#ifdef CONFIG_SOC_SERIES_NRF91X return nrf_modem_bootloader_init(&bootloader_init_params); +#else + return -ENOSYS; +#endif } int nrf_modem_lib_shutdown(void) diff --git a/lib/nrf_modem_lib/nrf_modem_os.c b/lib/nrf_modem_lib/nrf_modem_os.c index 8ccdad68684a..e44dfc7c10e5 100644 --- a/lib/nrf_modem_lib/nrf_modem_os.c +++ b/lib/nrf_modem_lib/nrf_modem_os.c @@ -12,14 +12,21 @@ #include #include #include -#include + #include +LOG_MODULE_REGISTER(nrf_modem, CONFIG_NRF_MODEM_LIB_LOG_LEVEL); + +#if CONFIG_SOC_SERIES_NRF91X +#include +#define SHMEM_TX_HEAP_ADDR (PM_NRF_MODEM_LIB_TX_ADDRESS) +#elif CONFIG_SOC_SERIES_NRF92X +#define SHMEM_TX_HEAP_ADDR (DT_REG_ADDR(DT_NODELABEL(cpuapp_cpucell_ipc_shm_heap))) +#endif +#define SHMEM_TX_HEAP_SIZE (CONFIG_NRF_MODEM_LIB_SHMEM_TX_SIZE) #define UNUSED_FLAGS 0 #define THREAD_MONITOR_ENTRIES 10 -LOG_MODULE_REGISTER(nrf_modem, CONFIG_NRF_MODEM_LIB_LOG_LEVEL); - struct sleeping_thread { sys_snode_t node; struct k_sem sem; @@ -375,7 +382,14 @@ void nrf_modem_os_free(void *mem) void *nrf_modem_os_shm_tx_alloc(size_t bytes) { extern uint32_t nrf_modem_lib_shmem_failed_allocs; + +#if (CONFIG_SOC_SERIES_NRF92X && CONFIG_DCACHE) + /* Allocate cache line aligned memory. */ + void * const addr = k_heap_aligned_alloc(&nrf_modem_lib_shmem_heap, CONFIG_DCACHE_LINE_SIZE, + ROUND_UP(bytes, CONFIG_DCACHE_LINE_SIZE), K_NO_WAIT); +#else void * const addr = k_heap_alloc(&nrf_modem_lib_shmem_heap, bytes, K_NO_WAIT); +#endif if (IS_ENABLED(CONFIG_NRF_MODEM_LIB_MEM_DIAG_ALLOC) && !addr) { nrf_modem_lib_shmem_failed_allocs++; @@ -487,8 +501,7 @@ void nrf_modem_os_init(void) { /* Initialize heaps */ k_heap_init(&nrf_modem_lib_heap, library_heap_buf, sizeof(library_heap_buf)); - k_heap_init(&nrf_modem_lib_shmem_heap, (void *)PM_NRF_MODEM_LIB_TX_ADDRESS, - CONFIG_NRF_MODEM_LIB_SHMEM_TX_SIZE); + k_heap_init(&nrf_modem_lib_shmem_heap, (void *)SHMEM_TX_HEAP_ADDR, SHMEM_TX_HEAP_SIZE); } void nrf_modem_os_shutdown(void) diff --git a/lib/nrf_modem_lib/nrf_modem_os_rpc.c b/lib/nrf_modem_lib/nrf_modem_os_rpc.c new file mode 100644 index 000000000000..6e9ec18478be --- /dev/null +++ b/lib/nrf_modem_lib/nrf_modem_os_rpc.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DCACHE_LINE_SIZE 0 + +struct nrf_modem_pbuf { + struct pbuf_cfg pb_cfg; + struct pbuf pb; +}; + +struct nrf_modem_os_rpc { + /** ICMsg internal data. */ + struct icmsg_data_t data; + /** ICMsg configuration. */ + struct icmsg_config_t conf; + /** ICMsg callbacks to nrf_modem. */ + struct ipc_service_cb cb; + /** TX pbuf. */ + struct nrf_modem_pbuf tx; + /** RX pbuf. */ + struct nrf_modem_pbuf rx; +}; + +struct nrf_modem_os_rpc_signal { + /** MBOX instance data. */ + struct mbox_dt_spec mbox; + /** Callback to nrf_modem. */ + nrf_modem_os_rpc_signal_cb_t recv; + /** Private context data usable by nrf_modem. */ + void *priv; +}; + +#define NRF_MODEM_OS_RPC_INIT(_inst, _dcache_line_size) \ + { \ + .data.tx_pb = &(_inst).tx.pb, \ + .data.rx_pb = &(_inst).rx.pb, \ + .tx.pb.cfg = &(_inst).tx.pb_cfg, \ + .rx.pb.cfg = &(_inst).rx.pb_cfg, \ + .tx.pb_cfg.dcache_alignment = (_dcache_line_size), \ + .rx.pb_cfg.dcache_alignment = (_dcache_line_size), \ + } + +struct nrf_modem_os_rpc inst_ctrl = NRF_MODEM_OS_RPC_INIT(inst_ctrl, DCACHE_LINE_SIZE); +struct nrf_modem_os_rpc inst_data = NRF_MODEM_OS_RPC_INIT(inst_data, DCACHE_LINE_SIZE); + +struct nrf_modem_os_rpc_signal inst_app_fault; +struct nrf_modem_os_rpc_signal inst_modem_fault; +struct nrf_modem_os_rpc_signal inst_modem_sysoff; + +uintptr_t nrf_modem_os_rpc_sigdev_app_get(void) +{ + const struct device *app_bellboard = DEVICE_DT_GET(DT_NODELABEL(cpuapp_bellboard)); + + return (uintptr_t)app_bellboard; +} + +uintptr_t nrf_modem_os_rpc_sigdev_modem_get(void) +{ + const struct device *modem_bellboard = DEVICE_DT_GET(DT_NODELABEL(cpucell_bellboard)); + + return (uintptr_t)modem_bellboard; +} + +static inline void pbuf_configure(struct pbuf_cfg *pb_cfg, uintptr_t mem_addr, size_t size) +{ + const uint32_t wr_idx_offset = MAX(pb_cfg->dcache_alignment, _PBUF_IDX_SIZE); + + pb_cfg->rd_idx_loc = (uint32_t *)(mem_addr); + pb_cfg->wr_idx_loc = (uint32_t *)(mem_addr + wr_idx_offset); + pb_cfg->len = (uint32_t)((uint32_t)size - wr_idx_offset - _PBUF_IDX_SIZE); + pb_cfg->data_loc = (uint8_t *)(mem_addr + wr_idx_offset + _PBUF_IDX_SIZE); +} + +int nrf_modem_os_rpc_open(struct nrf_modem_os_rpc *instance, + const struct nrf_modem_os_rpc_config *config) +{ + if (instance == NULL || config == NULL) { + return -NRF_EINVAL; + } + + pbuf_configure(&instance->tx.pb_cfg, config->tx.addr, config->tx.size); + pbuf_configure(&instance->rx.pb_cfg, config->rx.addr, config->rx.size); + + instance->conf.mbox_tx.dev = (struct device *)config->tx.sigdev; + instance->conf.mbox_rx.dev = (struct device *)config->rx.sigdev; + instance->conf.mbox_tx.channel_id = config->tx.ch; + instance->conf.mbox_rx.channel_id = config->rx.ch; + + instance->cb.bound = config->cb.bound; + instance->cb.received = config->cb.received; + + return icmsg_open(&instance->conf, &instance->data, &instance->cb, config->cb.priv); +} + +int nrf_modem_os_rpc_send(struct nrf_modem_os_rpc *instance, const void *msg, size_t len) +{ + int ret; + + ret = icmsg_send(&instance->conf, &instance->data, msg, len); + if (ret < 0) { + switch (ret) { + case -EBUSY: + case -EINVAL: + return -NRF_EBUSY; + case -ENOBUFS: + case -ENOMEM: + return -NRF_ENOMEM; + default: + return ret; + } + } + + return 0; +} + +int nrf_modem_os_rpc_close(struct nrf_modem_os_rpc *instance) +{ + return icmsg_close(&instance->conf, &instance->data); +} + +int nrf_modem_os_rpc_rx_suspend(struct nrf_modem_os_rpc *instance) +{ + return mbox_set_enabled_dt(&instance->conf.mbox_rx, false); +} + +int nrf_modem_os_rpc_rx_resume(struct nrf_modem_os_rpc *instance) +{ + return mbox_set_enabled_dt(&instance->conf.mbox_rx, true); +} + +static void mbox_common_callback(const struct device *dev, mbox_channel_id_t ch, void *ctx, + struct mbox_msg *data) +{ + struct nrf_modem_os_rpc_signal *inst = (struct nrf_modem_os_rpc_signal *)ctx; + + ARG_UNUSED(dev); + ARG_UNUSED(data); + + if (inst->recv != NULL) { + inst->recv(ch, inst->priv); + } +} + +int nrf_modem_os_rpc_signal_init(struct nrf_modem_os_rpc_signal *instance, + struct nrf_modem_os_rpc_signal_config *conf) +{ + int err; + + instance->mbox.dev = (struct device *)conf->sigdev; + instance->mbox.channel_id = (mbox_channel_id_t)conf->ch; + instance->priv = conf->priv; + instance->recv = conf->recv; + + if (instance->recv == NULL) { + return 0; + } + + err = mbox_register_callback_dt(&instance->mbox, mbox_common_callback, (void *)instance); + if (err) { + goto errout; + } + + err = mbox_set_enabled_dt(&instance->mbox, true); + if (err) { + goto errout; + } + + return 0; + +errout: + instance->recv = NULL; + return err; +} + +int nrf_modem_os_rpc_signal_send(struct nrf_modem_os_rpc_signal *instance) +{ + if (instance->recv != NULL) { + return -ENOSYS; + } + + return mbox_send_dt(&instance->mbox, NULL); +} + +int nrf_modem_os_rpc_signal_deinit(struct nrf_modem_os_rpc_signal *instance) +{ + if (instance->recv == NULL) { + return 0; + } + + return mbox_set_enabled_dt(&instance->mbox, false); +} + +int nrf_modem_os_rpc_cache_data_flush(void *addr, size_t size) +{ +#if CONFIG_DCACHE + /* Separate heaps are used for data payloads to and from the modem. + * Cache flush is only used on the tx heap. Therefore, cache coherency is + * maintained even when start address and size are not aligned with cache lines. + */ + addr = (void *)ROUND_DOWN((uint32_t)addr, CONFIG_DCACHE_LINE_SIZE); + size = ROUND_UP(size, CONFIG_DCACHE_LINE_SIZE); + + return sys_cache_data_flush_range(addr, size); +#else + ARG_UNUSED(addr); + ARG_UNUSED(size); + return 0; +#endif +} + +int nrf_modem_os_rpc_cache_data_invalidate(void *addr, size_t size) +{ +#if CONFIG_DCACHE + /* Separate heaps are used for data payloads to and from the modem. + * Cache invalidation is only used on the rx heap. Therefore, cache coherency is + * maintained even when start address and size are not aligned with cache lines. + */ + addr = (void *)ROUND_DOWN((uint32_t)addr, CONFIG_DCACHE_LINE_SIZE); + size = ROUND_UP(size, CONFIG_DCACHE_LINE_SIZE); + + return sys_cache_data_invd_range(addr, size); +#else + ARG_UNUSED(addr); + ARG_UNUSED(size); + return 0; +#endif +} diff --git a/lib/nrf_modem_lib/sanity.c b/lib/nrf_modem_lib/sanity.c index 64f6feaa13ae..226e36f5516c 100644 --- a/lib/nrf_modem_lib/sanity.c +++ b/lib/nrf_modem_lib/sanity.c @@ -6,7 +6,9 @@ #include #include +#ifdef CONFIG_SOC_SERIES_NRF91X #include +#endif /* CONFIG_SOC_SERIES_NRF91X */ #include #include @@ -110,6 +112,7 @@ BUILD_ASSERT(ETOOMANYREFS == NRF_ETOOMANYREFS, "Errno not aligned with nrf /* Shared memory sanity check */ +#ifdef CONFIG_SOC_SERIES_NRF91X #define SRAM_BASE 0x20000000 #define SHMEM_RANGE KB(128) #define SHMEM_END (SRAM_BASE + SHMEM_RANGE) @@ -131,6 +134,7 @@ BUILD_ASSERT(PM_NRF_MODEM_LIB_RX_ADDRESS % 4 == 0, BUILD_ASSERT(PM_NRF_MODEM_LIB_TRACE_ADDRESS % 4 == 0, "libmodem Trace region base address must be word aligned"); #endif +#endif /* CONFIG_SOC_SERIES_NRF91X */ /* Socket values sanity check */