drivers: ipm: add nRFx IPM driver
This commit contributes the nRFx IPM driver. Signed-off-by: Karol Lasończyk <karol.lasonczyk@nordicsemi.no>
This commit is contained in:
parent
8cdd25cdf5
commit
434c3cb22c
6 changed files with 419 additions and 0 deletions
|
@ -6,5 +6,6 @@ zephyr_library_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_IPM_IMX ipm_imx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IPM_MHU ipm_mhu.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IPM_STM32_IPCC ipm_stm32_ipcc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IPM_NRFX ipm_nrfx_ipc.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c)
|
||||
|
|
|
@ -67,6 +67,23 @@ config IPM_MHU
|
|||
help
|
||||
Driver for SSE 200 MHU (Message Handling Unit)
|
||||
|
||||
config IPM_NRFX
|
||||
bool "IPM NRF driver"
|
||||
depends on IPM && HAS_HW_NRF_IPC
|
||||
select NRFX_IPC
|
||||
help
|
||||
Driver for Nordic nRF messaging unit, based
|
||||
on nRF IPC peripheral HW.
|
||||
|
||||
config IPM_NRF_SINGLE_INSTANCE
|
||||
bool "Single instance of IPM device"
|
||||
help
|
||||
Enable this option if the IPM device should have
|
||||
a single instance, instead of one per IPC
|
||||
message channel.
|
||||
|
||||
source "drivers/ipm/Kconfig.nrfx"
|
||||
|
||||
config IPM_STM32_IPCC
|
||||
bool "STM32 IPCC controller"
|
||||
depends on IPM
|
||||
|
|
41
drivers/ipm/Kconfig.nrfx
Normal file
41
drivers/ipm/Kconfig.nrfx
Normal file
|
@ -0,0 +1,41 @@
|
|||
# nRF IPM driver configuration
|
||||
|
||||
# Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if IPM_NRFX
|
||||
|
||||
nrfx_ipc_num = 0
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 1
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 2
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 3
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 4
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 5
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 6
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 7
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 8
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 9
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 10
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 11
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 12
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 13
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 14
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
nrfx_ipc_num = 15
|
||||
rsource "Kconfig.nrfx_ipc_channel"
|
||||
|
||||
endif # IPM_NRFX
|
20
drivers/ipm/Kconfig.nrfx_ipc_channel
Normal file
20
drivers/ipm/Kconfig.nrfx_ipc_channel
Normal file
|
@ -0,0 +1,20 @@
|
|||
# nRF IPM driver channel configuration
|
||||
|
||||
# Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "IPM Message Channel [$(nrfx_ipc_num)] configuration"
|
||||
|
||||
config IPM_MSG_CH_$(nrfx_ipc_num)_ENABLE
|
||||
bool "Enable IPM Message Channel $(nrfx_ipc_num)"
|
||||
|
||||
config IPM_MSG_CH_$(nrfx_ipc_num)_RX
|
||||
bool "IPM Message RX Channel"
|
||||
depends on IPM_MSG_CH_$(nrfx_ipc_num)_ENABLE
|
||||
|
||||
config IPM_MSG_CH_$(nrfx_ipc_num)_TX
|
||||
bool "IPM Message TX Channel"
|
||||
depends on IPM_MSG_CH_$(nrfx_ipc_num)_ENABLE
|
||||
default ! IPM_MSG_CH_$(nrfx_ipc_num)_RX
|
||||
|
||||
endmenu
|
252
drivers/ipm/ipm_nrfx_ipc.c
Normal file
252
drivers/ipm/ipm_nrfx_ipc.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ipm.h>
|
||||
#include <nrfx_ipc.h>
|
||||
#include "ipm_nrfx_ipc.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_IPM_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(ipm_nrfx_ipc);
|
||||
|
||||
struct ipm_nrf_data {
|
||||
ipm_callback_t callback;
|
||||
void *callback_ctx;
|
||||
};
|
||||
|
||||
static struct ipm_nrf_data nrfx_ipm_data;
|
||||
|
||||
static void gipm_init(void);
|
||||
static void gipm_send(u32_t id);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPM_NRF_SINGLE_INSTANCE)
|
||||
|
||||
static void nrfx_ipc_handler(u32_t event_mask, void *p_context)
|
||||
{
|
||||
if (nrfx_ipm_data.callback) {
|
||||
while (event_mask) {
|
||||
u8_t event_idx = __CLZ(__RBIT(event_mask));
|
||||
|
||||
event_mask &= ~BIT(event_idx);
|
||||
nrfx_ipm_data.callback(nrfx_ipm_data.callback_ctx,
|
||||
event_idx,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ipm_nrf_send(struct device *dev, int wait, u32_t id,
|
||||
const void *data, int size)
|
||||
{
|
||||
if (id > NRFX_IPC_ID_MAX_VALUE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
LOG_WRN("nRF driver does not support sending data over IPM");
|
||||
}
|
||||
|
||||
gipm_send(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipm_nrf_max_data_size_get(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32_t ipm_nrf_max_id_val_get(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return NRFX_IPC_ID_MAX_VALUE;
|
||||
}
|
||||
|
||||
static void ipm_nrf_register_callback(struct device *dev,
|
||||
ipm_callback_t cb,
|
||||
void *context)
|
||||
{
|
||||
nrfx_ipm_data.callback = cb;
|
||||
nrfx_ipm_data.callback_ctx = context;
|
||||
}
|
||||
|
||||
static int ipm_nrf_set_enabled(struct device *dev, int enable)
|
||||
{
|
||||
/* Enable configured channels */
|
||||
if (enable) {
|
||||
irq_enable(DT_INST_0_NORDIC_NRF_IPC_IRQ_0);
|
||||
nrfx_ipc_receive_event_group_enable((uint32_t)IPC_EVENT_BITS);
|
||||
} else {
|
||||
irq_disable(DT_INST_0_NORDIC_NRF_IPC_IRQ_0);
|
||||
nrfx_ipc_receive_event_group_disable((uint32_t)IPC_EVENT_BITS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipm_nrf_init(struct device *dev)
|
||||
{
|
||||
gipm_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ipm_driver_api ipm_nrf_driver_api = {
|
||||
.send = ipm_nrf_send,
|
||||
.register_callback = ipm_nrf_register_callback,
|
||||
.max_data_size_get = ipm_nrf_max_data_size_get,
|
||||
.max_id_val_get = ipm_nrf_max_id_val_get,
|
||||
.set_enabled = ipm_nrf_set_enabled
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(ipm_nrf, DT_INST_0_NORDIC_NRF_IPC_LABEL,
|
||||
ipm_nrf_init, NULL, NULL,
|
||||
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&ipm_nrf_driver_api);
|
||||
|
||||
#else
|
||||
|
||||
struct vipm_nrf_data {
|
||||
ipm_callback_t callback[NRFX_IPC_ID_MAX_VALUE];
|
||||
void *callback_ctx[NRFX_IPC_ID_MAX_VALUE];
|
||||
bool ipm_init;
|
||||
struct device *ipm_device;
|
||||
};
|
||||
|
||||
static struct vipm_nrf_data nrfx_vipm_data;
|
||||
|
||||
static void vipm_dispatcher(u32_t event_mask, void *p_context)
|
||||
{
|
||||
while (event_mask) {
|
||||
u8_t event_idx = __CLZ(__RBIT(event_mask));
|
||||
|
||||
event_mask &= ~BIT(event_idx);
|
||||
if (nrfx_vipm_data.callback[event_idx] != NULL) {
|
||||
nrfx_vipm_data.callback[event_idx]
|
||||
(nrfx_vipm_data.callback_ctx[event_idx],
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int vipm_nrf_max_data_size_get(struct device *dev)
|
||||
{
|
||||
return ipm_max_data_size_get(dev);
|
||||
}
|
||||
|
||||
static u32_t vipm_nrf_max_id_val_get(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vipm_nrf_init(struct device *dev)
|
||||
{
|
||||
if (!nrfx_vipm_data.ipm_init) {
|
||||
gipm_init();
|
||||
nrfx_vipm_data.ipm_init = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define VIPM_DEVICE_1(_idx) \
|
||||
static int vipm_nrf_##_idx##_send(struct device *dev, int wait, \
|
||||
u32_t id, const void *data, int size) \
|
||||
{ \
|
||||
if (!IS_ENABLED(CONFIG_IPM_MSG_CH_##_idx##_TX)) { \
|
||||
LOG_ERR("IPM_" #_idx " is RX message channel"); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (id > NRFX_IPC_ID_MAX_VALUE) { \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (id != 0) { \
|
||||
LOG_WRN("Passing message ID to IPM with" \
|
||||
"predefined message ID"); \
|
||||
} \
|
||||
\
|
||||
if (size > 0) { \
|
||||
LOG_WRN("nRF driver does not support" \
|
||||
"sending data over IPM"); \
|
||||
} \
|
||||
\
|
||||
gipm_send(_idx); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static void vipm_nrf_##_idx##_register_callback(struct device *dev, \
|
||||
ipm_callback_t cb, \
|
||||
void *context) \
|
||||
{ \
|
||||
if (IS_ENABLED(CONFIG_IPM_MSG_CH_##_idx##_RX)) { \
|
||||
nrfx_vipm_data.callback[_idx] = cb; \
|
||||
nrfx_vipm_data.callback_ctx[_idx] = context; \
|
||||
} else { \
|
||||
LOG_WRN("Trying to register a callback" \
|
||||
"for TX channel IPM_" #_idx); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static int vipm_nrf_##_idx##_set_enabled(struct device *dev, int enable)\
|
||||
{ \
|
||||
if (!IS_ENABLED(CONFIG_IPM_MSG_CH_##_idx##_RX)) { \
|
||||
LOG_ERR("IPM_" #_idx " is TX message channel"); \
|
||||
return -EINVAL; \
|
||||
} else if (enable) { \
|
||||
irq_enable(DT_INST_0_NORDIC_NRF_IPC_IRQ_0); \
|
||||
nrfx_ipc_receive_event_enable(_idx); \
|
||||
} else if (!enable) { \
|
||||
nrfx_ipc_receive_event_disable(_idx); \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static const struct ipm_driver_api vipm_nrf_##_idx##_driver_api = { \
|
||||
.send = vipm_nrf_##_idx##_send, \
|
||||
.register_callback = vipm_nrf_##_idx##_register_callback, \
|
||||
.max_data_size_get = vipm_nrf_max_data_size_get, \
|
||||
.max_id_val_get = vipm_nrf_max_id_val_get, \
|
||||
.set_enabled = vipm_nrf_##_idx##_set_enabled \
|
||||
}; \
|
||||
\
|
||||
DEVICE_AND_API_INIT(vipm_nrf_##_idx, "IPM_"#_idx, \
|
||||
vipm_nrf_init, NULL, NULL, \
|
||||
PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&vipm_nrf_##_idx##_driver_api)
|
||||
|
||||
#define VIPM_DEVICE(_idx, _) \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_IPM_MSG_CH_##_idx##_ENABLE), \
|
||||
(VIPM_DEVICE_1(_idx);), ())
|
||||
|
||||
UTIL_LISTIFY(NRFX_IPC_ID_MAX_VALUE, VIPM_DEVICE, _);
|
||||
|
||||
#endif
|
||||
|
||||
static void gipm_init(void)
|
||||
{
|
||||
/* Init IPC */
|
||||
#if IS_ENABLED(CONFIG_IPM_NRF_SINGLE_INSTANCE)
|
||||
nrfx_ipc_init(0, nrfx_ipc_handler, (void *)&nrfx_ipm_data);
|
||||
#else
|
||||
nrfx_ipc_init(0, vipm_dispatcher, (void *)&nrfx_ipm_data);
|
||||
#endif
|
||||
IRQ_CONNECT(DT_INST_0_NORDIC_NRF_IPC_IRQ_0,
|
||||
DT_INST_0_NORDIC_NRF_IPC_IRQ_0_PRIORITY,
|
||||
nrfx_isr, nrfx_ipc_irq_handler, 0);
|
||||
|
||||
/* Set up signals and channels */
|
||||
nrfx_ipc_config_load(&ipc_cfg);
|
||||
}
|
||||
|
||||
static void gipm_send(u32_t id)
|
||||
{
|
||||
nrfx_ipc_signal(id);
|
||||
}
|
88
drivers/ipm/ipm_nrfx_ipc.h
Normal file
88
drivers/ipm/ipm_nrfx_ipc.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <nrfx_ipc.h>
|
||||
|
||||
#define NRFX_IPC_ID_MAX_VALUE IPC_CONF_NUM
|
||||
|
||||
/*
|
||||
* Group IPC signals, events and channels into message channels.
|
||||
* Message channels are one-way connections between cores.
|
||||
*
|
||||
* For example Message Channel 0 is configured as TX on core 0
|
||||
* and as RX on core 1:
|
||||
*
|
||||
* [C0] [C1]
|
||||
* SIGNAL0 -> CHANNEL0 -> EVENT0
|
||||
*
|
||||
* Message Channel 1 is configured as RX on core 0 and as TX
|
||||
* on core 1:
|
||||
* [C0] [C1]
|
||||
* EVENT1 <- CHANNEL1 <- SIGNAL1
|
||||
*/
|
||||
|
||||
#define IPC_EVENT_BIT(idx) \
|
||||
((IS_ENABLED(CONFIG_IPM_MSG_CH_##idx##_RX)) << idx)
|
||||
|
||||
#define IPC_EVENT_BITS \
|
||||
( \
|
||||
IPC_EVENT_BIT(0) | \
|
||||
IPC_EVENT_BIT(1) | \
|
||||
IPC_EVENT_BIT(2) | \
|
||||
IPC_EVENT_BIT(3) | \
|
||||
IPC_EVENT_BIT(4) | \
|
||||
IPC_EVENT_BIT(5) | \
|
||||
IPC_EVENT_BIT(6) | \
|
||||
IPC_EVENT_BIT(7) | \
|
||||
IPC_EVENT_BIT(8) | \
|
||||
IPC_EVENT_BIT(9) | \
|
||||
IPC_EVENT_BIT(10) | \
|
||||
IPC_EVENT_BIT(11) | \
|
||||
IPC_EVENT_BIT(12) | \
|
||||
IPC_EVENT_BIT(13) | \
|
||||
IPC_EVENT_BIT(14) | \
|
||||
IPC_EVENT_BIT(15) \
|
||||
)
|
||||
|
||||
static const nrfx_ipc_config_t ipc_cfg = {
|
||||
.send_task_config = {
|
||||
[0] = BIT(0),
|
||||
[1] = BIT(1),
|
||||
[2] = BIT(2),
|
||||
[3] = BIT(3),
|
||||
[4] = BIT(4),
|
||||
[5] = BIT(5),
|
||||
[6] = BIT(6),
|
||||
[7] = BIT(7),
|
||||
[8] = BIT(8),
|
||||
[9] = BIT(9),
|
||||
[10] = BIT(10),
|
||||
[11] = BIT(11),
|
||||
[12] = BIT(12),
|
||||
[13] = BIT(13),
|
||||
[14] = BIT(14),
|
||||
[15] = BIT(15),
|
||||
},
|
||||
.receive_event_config = {
|
||||
[0] = BIT(0),
|
||||
[1] = BIT(1),
|
||||
[2] = BIT(2),
|
||||
[3] = BIT(3),
|
||||
[4] = BIT(4),
|
||||
[5] = BIT(5),
|
||||
[6] = BIT(6),
|
||||
[7] = BIT(7),
|
||||
[8] = BIT(8),
|
||||
[9] = BIT(9),
|
||||
[10] = BIT(10),
|
||||
[11] = BIT(11),
|
||||
[12] = BIT(12),
|
||||
[13] = BIT(13),
|
||||
[14] = BIT(14),
|
||||
[15] = BIT(15),
|
||||
},
|
||||
.receive_events_enabled = IPC_EVENT_BITS,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue