drivers: can: mcan: move message RAM configuration to front-end drivers

Some Bosch M_CAN IP core implementations use a fixed Message RAM
configuration, other use a fixed memory area and relative addressing,
others again have custom registers for configuring the Message RAM.

Move the responsibility for configuring the various Bosch M_CAN Message RAM
addresses to the front-end drivers. This removes some of the front-end
specific code from the backend. Provide a helper function for configuring
the most common variations.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2023-05-07 19:00:15 +02:00 committed by Carles Cufí
commit a781ccde0f
6 changed files with 123 additions and 72 deletions

View file

@ -1200,71 +1200,16 @@ unlock:
k_mutex_unlock(&data->lock);
}
int can_mcan_init(const struct device *dev)
#ifndef CONFIG_CAN_STM32FD
int can_mcan_configure_message_ram(const struct device *dev, uintptr_t mrba)
{
const struct can_mcan_config *config = dev->config;
struct can_mcan_data *data = dev->data;
struct can_mcan_msg_sram *msg_ram = data->msg_ram;
struct can_timing timing;
#ifdef CONFIG_CAN_FD_MODE
struct can_timing timing_data;
#endif /* CONFIG_CAN_FD_MODE */
uint32_t reg;
int err;
k_mutex_init(&data->lock);
k_mutex_init(&data->tx_mtx);
k_sem_init(&data->tx_sem, NUM_TX_BUF_ELEMENTS, NUM_TX_BUF_ELEMENTS);
if (config->phy != NULL) {
if (!device_is_ready(config->phy)) {
LOG_ERR("CAN transceiver not ready");
return -ENODEV;
}
}
err = can_mcan_exit_sleep_mode(dev);
if (err != 0) {
LOG_ERR("Failed to exit sleep mode");
return -EIO;
}
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
if (err != 0) {
LOG_ERR("Failed to enter init mode");
return -EIO;
}
can_mcan_enable_configuration_change(dev);
#if CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG
err = can_mcan_read_reg(dev, CAN_MCAN_CREL, &reg);
if (err != 0) {
return -EIO;
}
LOG_DBG("IP rel: %lu.%lu.%lu %02lu.%lu.%lu", FIELD_GET(CAN_MCAN_CREL_REL, reg),
FIELD_GET(CAN_MCAN_CREL_STEP, reg), FIELD_GET(CAN_MCAN_CREL_SUBSTEP, reg),
FIELD_GET(CAN_MCAN_CREL_YEAR, reg), FIELD_GET(CAN_MCAN_CREL_MON, reg),
FIELD_GET(CAN_MCAN_CREL_DAY, reg));
#endif /* CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG */
#ifndef CONFIG_CAN_STM32FD
uintptr_t mrba = 0U;
#ifdef CONFIG_CAN_STM32H7
mrba = POINTER_TO_UINT(msg_ram);
#endif /* CONFIG_CAN_STM32H7 */
#ifdef CONFIG_CAN_MCUX_MCAN
mrba = POINTER_TO_UINT(msg_ram) & CAN_MCAN_MRBA_BA;
err = can_mcan_write_reg(dev, CAN_MCAN_MRBA, mrba);
if (err != 0) {
return -EIO;
}
#endif /* CONFIG_CAN_MCUX_MCAN */
reg = ((POINTER_TO_UINT(msg_ram->std_filt) - mrba) & CAN_MCAN_SIDFC_FLSSA) |
FIELD_PREP(CAN_MCAN_SIDFC_LSS, ARRAY_SIZE(msg_ram->std_filt));
err = can_mcan_write_reg(dev, CAN_MCAN_SIDFC, reg);
@ -1342,7 +1287,59 @@ int can_mcan_init(const struct device *dev)
return err;
}
return 0;
}
#endif /* !CONFIG_CAN_STM32FD */
int can_mcan_init(const struct device *dev)
{
const struct can_mcan_config *config = dev->config;
struct can_mcan_data *data = dev->data;
struct can_mcan_msg_sram *msg_ram = data->msg_ram;
struct can_timing timing;
#ifdef CONFIG_CAN_FD_MODE
struct can_timing timing_data;
#endif /* CONFIG_CAN_FD_MODE */
uint32_t reg;
int err;
k_mutex_init(&data->lock);
k_mutex_init(&data->tx_mtx);
k_sem_init(&data->tx_sem, NUM_TX_BUF_ELEMENTS, NUM_TX_BUF_ELEMENTS);
if (config->phy != NULL) {
if (!device_is_ready(config->phy)) {
LOG_ERR("CAN transceiver not ready");
return -ENODEV;
}
}
err = can_mcan_exit_sleep_mode(dev);
if (err != 0) {
LOG_ERR("Failed to exit sleep mode");
return -EIO;
}
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
if (err != 0) {
LOG_ERR("Failed to enter init mode");
return -EIO;
}
can_mcan_enable_configuration_change(dev);
#if CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG
err = can_mcan_read_reg(dev, CAN_MCAN_CREL, &reg);
if (err != 0) {
return -EIO;
}
LOG_DBG("IP rel: %lu.%lu.%lu %02lu.%lu.%lu", FIELD_GET(CAN_MCAN_CREL_REL, reg),
FIELD_GET(CAN_MCAN_CREL_STEP, reg), FIELD_GET(CAN_MCAN_CREL_SUBSTEP, reg),
FIELD_GET(CAN_MCAN_CREL_YEAR, reg), FIELD_GET(CAN_MCAN_CREL_MON, reg),
FIELD_GET(CAN_MCAN_CREL_DAY, reg));
#endif /* CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG */
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &reg);
if (err != 0) {
return err;
@ -1394,21 +1391,7 @@ int can_mcan_init(const struct device *dev)
}
#endif /* defined(CONFIG_CAN_DELAY_COMP) && defined(CONFIG_CAN_FD_MODE) */
#ifdef CONFIG_CAN_STM32FD
err = can_mcan_read_reg(dev, CAN_MCAN_RXGFC, &reg);
if (err != 0) {
return err;
}
reg |= FIELD_PREP(CAN_MCAN_RXGFC_LSS, CONFIG_CAN_MAX_STD_ID_FILTER) |
FIELD_PREP(CAN_MCAN_RXGFC_LSE, CONFIG_CAN_MAX_EXT_ID_FILTER) |
FIELD_PREP(CAN_MCAN_RXGFC_ANFS, 0x2) | FIELD_PREP(CAN_MCAN_RXGFC_ANFE, 0x2);
err = can_mcan_write_reg(dev, CAN_MCAN_RXGFC, reg);
if (err != 0) {
return err;
}
#else /* CONFIG_CAN_STM32FD*/
#ifndef CONFIG_CAN_STM32FD
err = can_mcan_read_reg(dev, CAN_MCAN_GFC, &reg);
if (err != 0) {
return err;

View file

@ -941,6 +941,31 @@ int can_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val);
*/
int can_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t val);
/**
* @brief Configure Bosch M_MCAN Message RAM start addresses.
*
* Bosch M_CAN driver front-end callback helper function for configuring the start addresses of the
* Bosch M_CAN Rx FIFO0 (RXFOC), Rx FIFO1 (RXF1C), Rx Buffer (RXBCC), Tx Buffer (TXBC), and Tx Event
* FIFO (TXEFC) in Message RAM.
*
* The start addresses (containing bits 15:2 since Bosch M_CAN message RAM is accessed as 32 bit
* words) are calculated relative to the provided Message RAM Base Address (mrba).
*
* Some Bosch M_CAN implementations use a fixed Message RAM configuration, other use a fixed memory
* area and relative addressing, others again have custom registers for configuring the Message
* RAM. It is the responsibility of the front-end driver to call this function during driver
* initialization as needed.
*
* @param dev Pointer to the device structure for the driver instance.
* @param mrba Message RAM Base Address.
*
* @retval 0 If successful.
* @retval -EIO General input/output error.
*/
#ifndef CONFIG_CAN_STM32FD
int can_mcan_configure_message_ram(const struct device *dev, uintptr_t mrba);
#endif /* !CONFIG_CAN_STM32FD */
int can_mcan_get_capabilities(const struct device *dev, can_mode_t *cap);
int can_mcan_start(const struct device *dev);

View file

@ -58,6 +58,9 @@ static int mcux_mcan_init(const struct device *dev)
{
const struct can_mcan_config *mcan_config = dev->config;
const struct mcux_mcan_config *mcux_config = mcan_config->custom;
struct can_mcan_data *mcan_data = dev->data;
struct mcux_mcan_data *mcux_data = mcan_data->custom;
const uintptr_t mrba = POINTER_TO_UINT(&mcux_data->msg_ram) & CAN_MCAN_MRBA_BA;
int err;
if (!device_is_ready(mcux_config->clock_dev)) {
@ -76,6 +79,16 @@ static int mcux_mcan_init(const struct device *dev)
return -EINVAL;
}
err = can_mcan_write_reg(dev, CAN_MCAN_MRBA, (uint32_t)mrba);
if (err != 0) {
return -EIO;
}
err = can_mcan_configure_message_ram(dev, mrba);
if (err != 0) {
return -EIO;
}
err = can_mcan_init(dev);
if (err) {
LOG_ERR("failed to initialize mcan (err %d)", err);

View file

@ -80,6 +80,11 @@ static int can_sam_init(const struct device *dev)
return ret;
}
ret = can_mcan_configure_message_ram(dev, 0U);
if (ret != 0) {
return ret;
}
ret = can_mcan_init(dev);
if (ret != 0) {
return ret;

View file

@ -112,6 +112,7 @@ static int can_stm32fd_init(const struct device *dev)
{
const struct can_mcan_config *mcan_cfg = dev->config;
const struct can_stm32fd_config *stm32fd_cfg = mcan_cfg->custom;
uint32_t rxgfc;
int ret;
/* Configure dt provided device signals when available */
@ -127,6 +128,23 @@ static int can_stm32fd_init(const struct device *dev)
return ret;
}
can_mcan_enable_configuration_change(dev);
/* Setup STM32 FDCAN Global Filter Configuration Register */
ret = can_mcan_read_reg(dev, CAN_MCAN_RXGFC, &rxgfc);
if (ret != 0) {
return ret;
}
rxgfc |= FIELD_PREP(CAN_MCAN_RXGFC_LSS, CONFIG_CAN_MAX_STD_ID_FILTER) |
FIELD_PREP(CAN_MCAN_RXGFC_LSE, CONFIG_CAN_MAX_EXT_ID_FILTER) |
FIELD_PREP(CAN_MCAN_RXGFC_ANFS, 0x2) | FIELD_PREP(CAN_MCAN_RXGFC_ANFE, 0x2);
ret = can_mcan_write_reg(dev, CAN_MCAN_RXGFC, rxgfc);
if (ret != 0) {
return ret;
}
ret = can_mcan_init(dev);
if (ret != 0) {
return ret;

View file

@ -93,6 +93,8 @@ static int can_stm32h7_init(const struct device *dev)
{
const struct can_mcan_config *mcan_cfg = dev->config;
const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
struct can_mcan_data *mcan_data = dev->data;
const uintptr_t mrba = POINTER_TO_UINT(mcan_data->msg_ram);
int ret;
/* Configure dt provided device signals when available */
@ -107,6 +109,11 @@ static int can_stm32h7_init(const struct device *dev)
return ret;
}
ret = can_mcan_configure_message_ram(dev, mrba);
if (ret != 0) {
return ret;
}
ret = can_mcan_init(dev);
if (ret != 0) {
return ret;