drivers: ipm: add driver based on stm32 hsem
Some STM32 SOC, like stm32h745 and stm32h747 doesn't have IPCC. Provide a STM32 HSEM based ipm driver for these SOC. Signed-off-by: HaiLong Yang <hailong.yang@brainco.cn>
This commit is contained in:
parent
9a80196e28
commit
559e1269e7
3 changed files with 229 additions and 0 deletions
|
@ -9,5 +9,6 @@ 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_IPM_CAVS_IDC ipm_cavs_idc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IPM_INTEL_ADSP ipm_intel_adsp.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IPM_STM32_HSEM ipm_stm32_hsem.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c)
|
||||
|
|
|
@ -112,6 +112,20 @@ config IPM_INTEL_ADSP
|
|||
help
|
||||
Driver for the Host-DSP Mailbox Communication channel.
|
||||
|
||||
config IPM_STM32_HSEM
|
||||
bool "STM32 HSEM controller"
|
||||
depends on STM32H7_DUAL_CORE
|
||||
help
|
||||
Driver for stm32 HSEM mailbox
|
||||
|
||||
config IPM_STM32_HSEM_CPU
|
||||
int "HSEM CPU ID"
|
||||
default 1
|
||||
range 1 2
|
||||
depends on IPM_STM32_HSEM
|
||||
help
|
||||
use to define the CPU ID used by HSEM
|
||||
|
||||
module = IPM
|
||||
module-str = ipm
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
|
214
drivers/ipm/ipm_stm32_hsem.c
Normal file
214
drivers/ipm/ipm_stm32_hsem.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (c) 2021 BrainCo Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT st_stm32_hsem_mailbox
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/clock_control.h>
|
||||
#include <drivers/ipm.h>
|
||||
#include <drivers/clock_control/stm32_clock_control.h>
|
||||
|
||||
#include "stm32_hsem.h"
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(ipm_stm32_hsem, CONFIG_IPM_LOG_LEVEL);
|
||||
|
||||
#define HSEM_CPU1 1
|
||||
#define HSEM_CPU2 2
|
||||
|
||||
#if CONFIG_IPM_STM32_HSEM_CPU == HSEM_CPU1
|
||||
#define ll_hsem_enableit_cier LL_HSEM_EnableIT_C1IER
|
||||
#define ll_hsem_disableit_cier LL_HSEM_DisableIT_C1IER
|
||||
#define ll_hsem_clearflag_cicr LL_HSEM_ClearFlag_C1ICR
|
||||
#define ll_hsem_isactiveflag_cmisr LL_HSEM_IsActiveFlag_C1MISR
|
||||
#else /* HSEM_CPU2 */
|
||||
#define ll_hsem_enableit_cier LL_HSEM_EnableIT_C2IER
|
||||
#define ll_hsem_disableit_cier LL_HSEM_DisableIT_C2IER
|
||||
#define ll_hsem_clearflag_cicr LL_HSEM_ClearFlag_C2ICR
|
||||
#define ll_hsem_isactiveflag_cmisr LL_HSEM_IsActiveFlag_C2MISR
|
||||
#endif /* CONFIG_IPM_STM32_HSEM_CPU */
|
||||
|
||||
struct stm32_hsem_mailbox_config {
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
struct stm32_pclken pclken;
|
||||
};
|
||||
|
||||
struct stm32_hsem_mailbox_data {
|
||||
uint32_t tx_semid;
|
||||
uint32_t rx_semid;
|
||||
ipm_callback_t callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static struct stm32_hsem_mailbox_data stm32_hsem_mailbox_0_data;
|
||||
|
||||
void stm32_hsem_mailbox_ipm_rx_isr(const struct device *dev)
|
||||
{
|
||||
struct stm32_hsem_mailbox_data *data = dev->data;
|
||||
uint32_t mask_semid = (1U << data->rx_semid);
|
||||
|
||||
/* Check semaphore rx_semid interrupt status */
|
||||
if (!ll_hsem_isactiveflag_cmisr(HSEM, mask_semid))
|
||||
return;
|
||||
|
||||
/* Notify user with NULL data pointer */
|
||||
if (data->callback) {
|
||||
data->callback(dev, data->user_data, 0, NULL);
|
||||
}
|
||||
|
||||
/* Clear semaphore rx_semid interrupt status and masked status */
|
||||
ll_hsem_clearflag_cicr(HSEM, mask_semid);
|
||||
}
|
||||
|
||||
static void stm32_hsem_mailbox_irq_config_func(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
IRQ_CONNECT(DT_INST_IRQN(0),
|
||||
DT_INST_IRQ(0, priority),
|
||||
stm32_hsem_mailbox_ipm_rx_isr, DEVICE_DT_INST_GET(0), 0);
|
||||
|
||||
irq_enable(DT_INST_IRQN(0));
|
||||
}
|
||||
|
||||
int stm32_hsem_mailbox_ipm_send(const struct device *dev, int wait, uint32_t id,
|
||||
const void *buff, int size)
|
||||
{
|
||||
struct stm32_hsem_mailbox_data *data = dev->data;
|
||||
|
||||
ARG_UNUSED(wait);
|
||||
ARG_UNUSED(buff);
|
||||
|
||||
if (size) {
|
||||
LOG_WRN("stm32 HSEM not support data transfer");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
LOG_WRN("stm32 HSEM only support a single instance of mailbox");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Lock the semaphore tx_semid */
|
||||
z_stm32_hsem_lock(data->tx_semid, HSEM_LOCK_DEFAULT_RETRY);
|
||||
|
||||
/**
|
||||
* Release the semaphore tx_semid.
|
||||
* This will trigger a HSEMx interrupt on another CPU.
|
||||
*/
|
||||
z_stm32_hsem_unlock(data->tx_semid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stm32_hsem_mailbox_ipm_register_callback(const struct device *dev,
|
||||
ipm_callback_t cb,
|
||||
void *user_data)
|
||||
{
|
||||
struct stm32_hsem_mailbox_data *data = dev->data;
|
||||
|
||||
data->callback = cb;
|
||||
data->user_data = user_data;
|
||||
}
|
||||
|
||||
int stm32_hsem_mailbox_ipm_max_data_size_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
/* stm32 HSEM not support data transfer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t stm32_hsem_mailbox_ipm_max_id_val_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
/* stm32 HSEM only support a single instance of mailbox */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32_hsem_mailbox_ipm_set_enabled(const struct device *dev, int enable)
|
||||
{
|
||||
struct stm32_hsem_mailbox_data *data = dev->data;
|
||||
uint32_t mask_semid = (1U << data->rx_semid);
|
||||
|
||||
if (enable) {
|
||||
/* Clear semaphore rx_semid interrupt status and masked status */
|
||||
ll_hsem_clearflag_cicr(HSEM, mask_semid);
|
||||
/* Enable semaphore rx_semid on HESMx interrupt */
|
||||
ll_hsem_enableit_cier(HSEM, mask_semid);
|
||||
} else {
|
||||
/* Disable semaphore rx_semid on HSEMx interrupt */
|
||||
ll_hsem_disableit_cier(HSEM, mask_semid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_hsem_mailbox_init(const struct device *dev)
|
||||
{
|
||||
struct stm32_hsem_mailbox_data *data = dev->data;
|
||||
const struct stm32_hsem_mailbox_config *cfg = dev->config;
|
||||
const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
|
||||
|
||||
/* Config transfer semaphore */
|
||||
switch (CONFIG_IPM_STM32_HSEM_CPU) {
|
||||
case HSEM_CPU1:
|
||||
/* Enable clock */
|
||||
if (clock_control_on(clk, (clock_control_subsys_t *)&cfg->pclken) != 0) {
|
||||
LOG_WRN("Failed to enable clock");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->tx_semid = CFG_HW_IPM_CPU2_SEMID;
|
||||
data->rx_semid = CFG_HW_IPM_CPU1_SEMID;
|
||||
break;
|
||||
case HSEM_CPU2:
|
||||
data->tx_semid = CFG_HW_IPM_CPU1_SEMID;
|
||||
data->rx_semid = CFG_HW_IPM_CPU2_SEMID;
|
||||
break;
|
||||
}
|
||||
|
||||
cfg->irq_config_func(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ipm_driver_api stm32_hsem_mailbox_ipm_dirver_api = {
|
||||
.send = stm32_hsem_mailbox_ipm_send,
|
||||
.register_callback = stm32_hsem_mailbox_ipm_register_callback,
|
||||
.max_data_size_get = stm32_hsem_mailbox_ipm_max_data_size_get,
|
||||
.max_id_val_get = stm32_hsem_mailbox_ipm_max_id_val_get,
|
||||
.set_enabled = stm32_hsem_mailbox_ipm_set_enabled,
|
||||
};
|
||||
|
||||
static const struct stm32_hsem_mailbox_config stm32_hsem_mailbox_0_config = {
|
||||
.irq_config_func = stm32_hsem_mailbox_irq_config_func,
|
||||
.pclken = {
|
||||
.bus = DT_INST_CLOCKS_CELL(0, bus),
|
||||
.enr = DT_INST_CLOCKS_CELL(0, bits)
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* STM32 HSEM has its own LL_HSEM(low-level HSEM) API provided by the hal_stm32 module.
|
||||
* The ipm_stm32_hsem driver only picks up two semaphore IDs from stm32_hsem.h to simulate
|
||||
* a virtual mailbox device. So there will have only one instance.
|
||||
*/
|
||||
#define IPM_STM32_HSEM_INIT(inst) \
|
||||
BUILD_ASSERT((inst) == 0, \
|
||||
"multiple instances not supported"); \
|
||||
DEVICE_DT_INST_DEFINE(0, \
|
||||
&stm32_hsem_mailbox_init, \
|
||||
NULL, \
|
||||
&stm32_hsem_mailbox_0_data, \
|
||||
&stm32_hsem_mailbox_0_config, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&stm32_hsem_mailbox_ipm_dirver_api); \
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(IPM_STM32_HSEM_INIT)
|
Loading…
Add table
Add a link
Reference in a new issue