From 3ed354eea1e629519fd410596483208d37cf67c5 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 10 May 2023 22:07:42 +0200 Subject: [PATCH] drivers: can: mcan: let front-end drivers supply message RAM functions Let the Bosch M_CAN front-end drivers supply their own Message RAM read/write/clear functions. This is preparation for supporting per-instance Bosch M_CAN Message RAM layouts and for accessing Bosch M_CAN IP cores over peripheral busses. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcan.c | 268 +++++++++-------- drivers/can/can_mcan.h | 562 ++++++++++++++++++++++++++++++------ drivers/can/can_mcux_mcan.c | 41 ++- drivers/can/can_sam.c | 43 ++- drivers/can/can_sam0.c | 44 ++- drivers/can/can_stm32fd.c | 47 ++- drivers/can/can_stm32h7.c | 57 +++- 7 files changed, 816 insertions(+), 246 deletions(-) diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index ca252e914ec..887f45091c9 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include @@ -19,39 +18,12 @@ LOG_MODULE_REGISTER(can_mcan, CONFIG_CAN_LOG_LEVEL); #define CAN_INIT_TIMEOUT_MS 100 -static void memcpy32_volatile(volatile void *dst_, const volatile void *src_, size_t len) -{ - volatile uint32_t *dst = dst_; - const volatile uint32_t *src = src_; - - __ASSERT(len % 4 == 0U, "len must be a multiple of 4!"); - len /= sizeof(uint32_t); - - while (len--) { - *dst = *src; - ++dst; - ++src; - } -} - -static void memset32_volatile(volatile void *dst_, uint32_t val, size_t len) -{ - volatile uint32_t *dst = dst_; - - __ASSERT(len % 4 == 0U, "len must be a multiple of 4!"); - len /= sizeof(uint32_t); - - while (len--) { - *dst++ = val; - } -} - int can_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) { const struct can_mcan_config *config = dev->config; int err; - err = config->read_reg(dev, reg, val); + err = config->ops->read_reg(dev, reg, val); if (err != 0) { LOG_ERR("failed to read reg 0x%03x (err %d)", reg, err); } else { @@ -66,7 +38,7 @@ int can_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t val) const struct can_mcan_config *config = dev->config; int err; - err = config->write_reg(dev, reg, val); + err = config->ops->write_reg(dev, reg, val); if (err != 0) { LOG_ERR("failed to write reg 0x%03x (err %d)", reg, err); } else { @@ -505,8 +477,7 @@ static void can_mcan_state_change_handler(const struct device *dev) static void can_mcan_tc_event_handler(const struct device *dev) { struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; - volatile struct can_mcan_tx_event_fifo *tx_event; + struct can_mcan_tx_event_fifo tx_event; can_tx_callback_t tx_cb; uint32_t event_idx; uint32_t tx_idx; @@ -520,10 +491,17 @@ static void can_mcan_tc_event_handler(const struct device *dev) while ((txefs & CAN_MCAN_TXEFS_EFFL) != 0U) { event_idx = FIELD_GET(CAN_MCAN_TXEFS_EFGI, txefs); - sys_cache_data_invd_range((void *)&msg_ram->tx_event_fifo[event_idx], - sizeof(struct can_mcan_tx_event_fifo)); - tx_event = &msg_ram->tx_event_fifo[event_idx]; - tx_idx = tx_event->mm.idx; + err = can_mcan_read_mram(dev, CAN_MCAN_MRAM_OFFSET_TX_EVENT_FIFO + + event_idx * sizeof(struct can_mcan_tx_event_fifo), + &tx_event, + sizeof(struct can_mcan_tx_event_fifo)); + if (err != 0) { + LOG_ERR("failed to read tx event fifo (err %d)", err); + return; + } + + tx_idx = tx_event.mm.idx; + /* Acknowledge TX event */ err = can_mcan_write_reg(dev, CAN_MCAN_TXEFA, event_idx); if (err != 0) { @@ -592,7 +570,7 @@ void can_mcan_line_0_isr(const struct device *dev) } } -static void can_mcan_get_message(const struct device *dev, volatile struct can_mcan_rx_fifo *fifo, +static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, uint16_t fifo_status_reg, uint16_t fifo_ack_reg) { struct can_mcan_data *data = dev->data; @@ -613,12 +591,17 @@ static void can_mcan_get_message(const struct device *dev, volatile struct can_m return; } - while ((fifo_status & CAN_MCAN_RXF0S_F0FL) != 0U) { + while (FIELD_GET(CAN_MCAN_RXF0S_F0FL, fifo_status) != 0U) { get_idx = FIELD_GET(CAN_MCAN_RXF0S_F0GI, fifo_status); - sys_cache_data_invd_range((void *)&fifo[get_idx].hdr, - sizeof(struct can_mcan_rx_fifo_hdr)); - memcpy32_volatile(&hdr, &fifo[get_idx].hdr, sizeof(struct can_mcan_rx_fifo_hdr)); + err = can_mcan_read_mram(dev, fifo_offset + get_idx * + sizeof(struct can_mcan_rx_fifo) + + offsetof(struct can_mcan_rx_fifo, hdr), + &hdr, sizeof(struct can_mcan_rx_fifo_hdr)); + if (err != 0) { + LOG_ERR("failed to read Rx FIFO header (err %d)", err); + return; + } frame.dlc = hdr.dlc; @@ -675,11 +658,15 @@ static void can_mcan_get_message(const struct device *dev, volatile struct can_m data_length = can_dlc_to_bytes(frame.dlc); if (data_length <= sizeof(frame.data)) { - /* Data needs to be written in 32 bit blocks! */ - sys_cache_data_invd_range((void *)fifo[get_idx].data_32, - ROUND_UP(data_length, sizeof(uint32_t))); - memcpy32_volatile(frame.data_32, fifo[get_idx].data_32, - ROUND_UP(data_length, sizeof(uint32_t))); + err = can_mcan_read_mram(dev, fifo_offset + get_idx * + sizeof(struct can_mcan_rx_fifo) + + offsetof(struct can_mcan_rx_fifo, data_32), + &frame.data_32, + ROUND_UP(data_length, sizeof(uint32_t))); + if (err != 0) { + LOG_ERR("failed to read Rx FIFO data (err %d)", err); + return; + } if ((frame.flags & CAN_FRAME_IDE) != 0) { LOG_DBG("Frame on filter %d, ID: 0x%x", @@ -718,8 +705,6 @@ void can_mcan_line_1_isr(const struct device *dev) { const uint32_t events = CAN_MCAN_IR_RF0N | CAN_MCAN_IR_RF1N | CAN_MCAN_IR_RF0L | CAN_MCAN_IR_RF1L; - struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; uint32_t ir; int err; @@ -731,13 +716,13 @@ void can_mcan_line_1_isr(const struct device *dev) while ((ir & events) != 0U) { if ((ir & CAN_MCAN_IR_RF0N) != 0U) { LOG_DBG("RX FIFO0 INT"); - can_mcan_get_message(dev, msg_ram->rx_fifo0, CAN_MCAN_RXF0S, + can_mcan_get_message(dev, CAN_MCAN_MRAM_OFFSET_RX_FIFO0, CAN_MCAN_RXF0S, CAN_MCAN_RXF0A); } if ((ir & CAN_MCAN_IR_RF1N) != 0U) { LOG_DBG("RX FIFO1 INT"); - can_mcan_get_message(dev, msg_ram->rx_fifo1, CAN_MCAN_RXF1S, + can_mcan_get_message(dev, CAN_MCAN_MRAM_OFFSET_RX_FIFO1, CAN_MCAN_RXF1S, CAN_MCAN_RXF1A); } @@ -817,7 +802,6 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim can_tx_callback_t callback, void *user_data) { struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; size_t data_length = can_dlc_to_bytes(frame->dlc); struct can_mcan_tx_buffer_hdr tx_hdr = { .rtr = (frame->flags & CAN_FRAME_RTR) != 0U ? 1U : 0U, @@ -921,12 +905,23 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim tx_hdr.std_id = frame->id & CAN_STD_ID_MASK; } - memcpy32_volatile(&msg_ram->tx_buffer[put_idx].hdr, &tx_hdr, sizeof(tx_hdr)); - memcpy32_volatile(msg_ram->tx_buffer[put_idx].data_32, frame->data_32, - ROUND_UP(data_length, 4)); - sys_cache_data_flush_range((void *)&msg_ram->tx_buffer[put_idx].hdr, sizeof(tx_hdr)); - sys_cache_data_flush_range((void *)&msg_ram->tx_buffer[put_idx].data_32, - ROUND_UP(data_length, 4)); + err = can_mcan_write_mram(dev, CAN_MCAN_MRAM_OFFSET_TX_BUFFER + put_idx * + sizeof(struct can_mcan_tx_buffer) + + offsetof(struct can_mcan_tx_buffer, hdr), + &tx_hdr, sizeof(struct can_mcan_tx_buffer_hdr)); + if (err != 0) { + LOG_ERR("failed to write Tx Buffer header (err %d)", err); + return err; + } + + err = can_mcan_write_mram(dev, CAN_MCAN_MRAM_OFFSET_TX_BUFFER + put_idx * + sizeof(struct can_mcan_tx_buffer) + + offsetof(struct can_mcan_tx_buffer, data_32), + &frame->data_32, ROUND_UP(data_length, sizeof(uint32_t))); + if (err != 0) { + LOG_ERR("failed to write Tx Buffer data (err %d)", err); + return err; + } data->tx_fin_cb[put_idx] = callback; data->tx_fin_cb_arg[put_idx] = user_data; @@ -942,12 +937,22 @@ unlock: return err; } -static int can_mcan_get_free_std(volatile struct can_mcan_std_filter *filters) +static int can_mcan_get_free_std(const struct device *dev) { + struct can_mcan_std_filter filter; + int err; int i; for (i = 0; i < NUM_STD_FILTER_DATA; ++i) { - if (filters[i].sfce == CAN_MCAN_FCE_DISABLE) { + err = can_mcan_read_mram(dev, CAN_MCAN_MRAM_OFFSET_STD_FILTER + + i * sizeof(struct can_mcan_std_filter), &filter, + sizeof(struct can_mcan_std_filter)); + if (err != 0) { + LOG_ERR("failed to read std filter (err %d)", err); + return err; + } + + if (filter.sfce == CAN_MCAN_FCE_DISABLE) { return i; } } @@ -975,15 +980,18 @@ int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callb void *user_data, const struct can_filter *filter) { struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; struct can_mcan_std_filter filter_element = { - .id1 = filter->id, .id2 = filter->mask, .sft = CAN_MCAN_SFT_MASKED}; + .id1 = filter->id, + .id2 = filter->mask, + .sft = CAN_MCAN_SFT_MASKED + }; int filter_id; + int err; k_mutex_lock(&data->lock, K_FOREVER); - filter_id = can_mcan_get_free_std(msg_ram->std_filt); + filter_id = can_mcan_get_free_std(dev); - if (filter_id == -ENOSPC) { + if (filter_id < 0) { LOG_WRN("No free standard id filter left"); k_mutex_unlock(&data->lock); return -ENOSPC; @@ -992,10 +1000,13 @@ int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callb /* TODO proper fifo balancing */ filter_element.sfce = filter_id & 0x01 ? CAN_MCAN_FCE_FIFO1 : CAN_MCAN_FCE_FIFO0; - memcpy32_volatile(&msg_ram->std_filt[filter_id], &filter_element, - sizeof(struct can_mcan_std_filter)); - sys_cache_data_flush_range((void *)&msg_ram->std_filt[filter_id], - sizeof(struct can_mcan_std_filter)); + err = can_mcan_write_mram(dev, CAN_MCAN_MRAM_OFFSET_STD_FILTER + + filter_id * sizeof(struct can_mcan_std_filter), + &filter_element, sizeof(filter_element)); + if (err != 0) { + LOG_ERR("failed to write std filter element (err %d)", err); + return err; + } k_mutex_unlock(&data->lock); @@ -1026,12 +1037,22 @@ int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callb return filter_id; } -static int can_mcan_get_free_ext(volatile struct can_mcan_ext_filter *filters) +static int can_mcan_get_free_ext(const struct device *dev) { + struct can_mcan_ext_filter filter; + int err; int i; for (i = 0; i < NUM_EXT_FILTER_DATA; ++i) { - if (filters[i].efce == CAN_MCAN_FCE_DISABLE) { + err = can_mcan_read_mram(dev, CAN_MCAN_MRAM_OFFSET_EXT_FILTER + + i * sizeof(struct can_mcan_ext_filter), &filter, + sizeof(struct can_mcan_ext_filter)); + if (err != 0) { + LOG_ERR("failed to read ext filter (err %d)", err); + return err; + } + + if (filter.efce == CAN_MCAN_FCE_DISABLE) { return i; } } @@ -1043,15 +1064,18 @@ static int can_mcan_add_rx_filter_ext(const struct device *dev, can_rx_callback_ void *user_data, const struct can_filter *filter) { struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; struct can_mcan_ext_filter filter_element = { - .id2 = filter->mask, .id1 = filter->id, .eft = CAN_MCAN_EFT_MASKED}; + .id2 = filter->mask, + .id1 = filter->id, + .eft = CAN_MCAN_EFT_MASKED + }; int filter_id; + int err; k_mutex_lock(&data->lock, K_FOREVER); - filter_id = can_mcan_get_free_ext(msg_ram->ext_filt); + filter_id = can_mcan_get_free_ext(dev); - if (filter_id == -ENOSPC) { + if (filter_id < 0) { LOG_WRN("No free extended id filter left"); k_mutex_unlock(&data->lock); return -ENOSPC; @@ -1060,10 +1084,13 @@ static int can_mcan_add_rx_filter_ext(const struct device *dev, can_rx_callback_ /* TODO proper fifo balancing */ filter_element.efce = filter_id & 0x01 ? CAN_MCAN_FCE_FIFO1 : CAN_MCAN_FCE_FIFO0; - memcpy32_volatile(&msg_ram->ext_filt[filter_id], &filter_element, - sizeof(struct can_mcan_ext_filter)); - sys_cache_data_flush_range((void *)&msg_ram->ext_filt[filter_id], - sizeof(struct can_mcan_ext_filter)); + err = can_mcan_write_mram(dev, CAN_MCAN_MRAM_OFFSET_EXT_FILTER + + filter_id * sizeof(struct can_mcan_ext_filter), + &filter_element, sizeof(filter_element)); + if (err != 0) { + LOG_ERR("failed to write std filter element (err %d)", err); + return err; + } k_mutex_unlock(&data->lock); @@ -1128,7 +1155,7 @@ int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, void can_mcan_remove_rx_filter(const struct device *dev, int filter_id) { struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; + int err; k_mutex_lock(&data->lock, K_FOREVER); @@ -1140,15 +1167,19 @@ void can_mcan_remove_rx_filter(const struct device *dev, int filter_id) return; } - memset32_volatile(&msg_ram->ext_filt[filter_id], 0, - sizeof(struct can_mcan_ext_filter)); - sys_cache_data_flush_range((void *)&msg_ram->ext_filt[filter_id], - sizeof(struct can_mcan_ext_filter)); + err = can_mcan_clear_mram(dev, CAN_MCAN_MRAM_OFFSET_EXT_FILTER + + filter_id * sizeof(struct can_mcan_ext_filter), + sizeof(struct can_mcan_ext_filter)); + if (err != 0) { + LOG_ERR("failed to clear ext filter element (err %d)", err); + } } else { - memset32_volatile(&msg_ram->std_filt[filter_id], 0, - sizeof(struct can_mcan_std_filter)); - sys_cache_data_flush_range((void *)&msg_ram->std_filt[filter_id], - sizeof(struct can_mcan_std_filter)); + err = can_mcan_clear_mram(dev, CAN_MCAN_MRAM_OFFSET_STD_FILTER + + filter_id * sizeof(struct can_mcan_std_filter), + sizeof(struct can_mcan_std_filter)); + if (err != 0) { + LOG_ERR("failed to clear std filter element (err %d)", err); + } } k_mutex_unlock(&data->lock); @@ -1200,10 +1231,8 @@ unlock: k_mutex_unlock(&data->lock); } -int can_mcan_configure_message_ram(const struct device *dev, uintptr_t mrba) +int can_mcan_configure_mram(const struct device *dev, uintptr_t mrba, uintptr_t mram) { - struct can_mcan_data *data = dev->data; - struct can_mcan_msg_sram *msg_ram = data->msg_ram; uint32_t reg; int err; @@ -1221,78 +1250,63 @@ int can_mcan_configure_message_ram(const struct device *dev, uintptr_t mrba) can_mcan_enable_configuration_change(dev); - 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)); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_STD_FILTER) & CAN_MCAN_SIDFC_FLSSA) | + FIELD_PREP(CAN_MCAN_SIDFC_LSS, NUM_STD_FILTER_ELEMENTS); err = can_mcan_write_reg(dev, CAN_MCAN_SIDFC, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->ext_filt) - mrba) & CAN_MCAN_XIDFC_FLESA) | - FIELD_PREP(CAN_MCAN_XIDFC_LSS, ARRAY_SIZE(msg_ram->ext_filt)); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_EXT_FILTER) & CAN_MCAN_XIDFC_FLESA) | + FIELD_PREP(CAN_MCAN_XIDFC_LSS, NUM_EXT_FILTER_ELEMENTS); err = can_mcan_write_reg(dev, CAN_MCAN_XIDFC, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->rx_fifo0) - mrba) & CAN_MCAN_RXF0C_F0SA) | - FIELD_PREP(CAN_MCAN_RXF0C_F0S, ARRAY_SIZE(msg_ram->rx_fifo0)); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_RX_FIFO0) & CAN_MCAN_RXF0C_F0SA) | + FIELD_PREP(CAN_MCAN_RXF0C_F0S, NUM_RX_FIFO0_ELEMENTS); err = can_mcan_write_reg(dev, CAN_MCAN_RXF0C, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->rx_fifo1) - mrba) & CAN_MCAN_RXF1C_F1SA) | - FIELD_PREP(CAN_MCAN_RXF1C_F1S, ARRAY_SIZE(msg_ram->rx_fifo1)); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_RX_FIFO1) & CAN_MCAN_RXF1C_F1SA) | + FIELD_PREP(CAN_MCAN_RXF1C_F1S, NUM_RX_FIFO1_ELEMENTS); err = can_mcan_write_reg(dev, CAN_MCAN_RXF1C, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->rx_buffer) - mrba) & CAN_MCAN_RXBC_RBSA); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_RX_BUFFER) & CAN_MCAN_RXBC_RBSA); err = can_mcan_write_reg(dev, CAN_MCAN_RXBC, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->tx_event_fifo) - mrba) & CAN_MCAN_TXEFC_EFSA) | - FIELD_PREP(CAN_MCAN_TXEFC_EFS, ARRAY_SIZE(msg_ram->tx_event_fifo)); + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_TX_EVENT_FIFO) & CAN_MCAN_TXEFC_EFSA) | + FIELD_PREP(CAN_MCAN_TXEFC_EFS, NUM_TX_EVENT_FIFO_ELEMENTS); err = can_mcan_write_reg(dev, CAN_MCAN_TXEFC, reg); if (err != 0) { return err; } - reg = ((POINTER_TO_UINT(msg_ram->tx_buffer) - mrba) & CAN_MCAN_TXBC_TBSA) | - FIELD_PREP(CAN_MCAN_TXBC_TFQS, ARRAY_SIZE(msg_ram->tx_buffer)) | CAN_MCAN_TXBC_TFQM; + reg = ((mram - mrba + CAN_MCAN_MRAM_OFFSET_TX_BUFFER) & CAN_MCAN_TXBC_TBSA) | + FIELD_PREP(CAN_MCAN_TXBC_TFQS, NUM_TX_BUF_ELEMENTS) | CAN_MCAN_TXBC_TFQM; err = can_mcan_write_reg(dev, CAN_MCAN_TXBC, reg); if (err != 0) { return err; } - if (sizeof(msg_ram->tx_buffer[0].data) <= 24) { - reg = (sizeof(msg_ram->tx_buffer[0].data) - 8) / 4; - } else { - reg = (sizeof(msg_ram->tx_buffer[0].data) - 32) / 16 + 5; - } - + /* 64 byte Tx Buffer data fields size */ + reg = CAN_MCAN_TXESC_TBDS; err = can_mcan_write_reg(dev, CAN_MCAN_TXESC, reg); if (err != 0) { return err; } - if (sizeof(msg_ram->rx_fifo0[0].data) <= 24) { - reg = FIELD_PREP(CAN_MCAN_RXESC_F0DS, (sizeof(msg_ram->rx_fifo0[0].data) - 8) / 4) | - FIELD_PREP(CAN_MCAN_RXESC_F1DS, (sizeof(msg_ram->rx_fifo1[0].data) - 8) / 4) | - FIELD_PREP(CAN_MCAN_RXESC_RBDS, (sizeof(msg_ram->rx_buffer[0].data) - 8) / 4); - } else { - reg = FIELD_PREP(CAN_MCAN_RXESC_F0DS, - (sizeof(msg_ram->rx_fifo0[0].data) - 32) / 16 + 5) | - FIELD_PREP(CAN_MCAN_RXESC_F1DS, - (sizeof(msg_ram->rx_fifo1[0].data) - 32) / 16 + 5) | - FIELD_PREP(CAN_MCAN_RXESC_RBDS, - (sizeof(msg_ram->rx_buffer[0].data) - 32) / 16 + 5); - } - + /* 64 byte Rx Buffer/FIFO1/FIFO0 data fields size */ + reg = CAN_MCAN_RXESC_RBDS | CAN_MCAN_RXESC_F1DS | CAN_MCAN_RXESC_F0DS; err = can_mcan_write_reg(dev, CAN_MCAN_RXESC, reg); if (err != 0) { return err; @@ -1305,7 +1319,6 @@ 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; @@ -1313,6 +1326,12 @@ int can_mcan_init(const struct device *dev) uint32_t reg; int err; + __ASSERT_NO_MSG(config->ops->read_reg != NULL); + __ASSERT_NO_MSG(config->ops->write_reg != NULL); + __ASSERT_NO_MSG(config->ops->read_mram != NULL); + __ASSERT_NO_MSG(config->ops->write_mram != NULL); + __ASSERT_NO_MSG(config->ops->clear_mram != NULL); + 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); @@ -1488,8 +1507,5 @@ int can_mcan_init(const struct device *dev) return err; } - memset32_volatile(msg_ram, 0, sizeof(struct can_mcan_msg_sram)); - sys_cache_data_flush_range(msg_ram, sizeof(struct can_mcan_msg_sram)); - - return 0; + return can_mcan_clear_mram(dev, 0, sizeof(struct can_mcan_msg_sram)); } diff --git a/drivers/can/can_mcan.h b/drivers/can/can_mcan.h index 474167107b2..4c661ce0f68 100644 --- a/drivers/can/can_mcan.h +++ b/drivers/can/can_mcan.h @@ -9,6 +9,7 @@ #ifndef ZEPHYR_DRIVERS_CAN_MCAN_H_ #define ZEPHYR_DRIVERS_CAN_MCAN_H_ +#include #include #include #include @@ -389,13 +390,173 @@ #define MCAN_DT_PATH DT_PATH(soc, can) #endif -#define NUM_STD_FILTER_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 1) -#define NUM_EXT_FILTER_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 2) -#define NUM_RX_FIFO0_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 3) -#define NUM_RX_FIFO1_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 4) -#define NUM_RX_BUF_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 5) -#define NUM_TX_EVENT_FIFO_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 6) -#define NUM_TX_BUF_ELEMENTS DT_PROP_BY_IDX(MCAN_DT_PATH, bosch_mram_cfg, 7) +/** + * @brief Indexes for the cells in the devicetree bosch,mram-cfg property. These match the + * description of the cells in the bosch,m_can-base devicetree binding. + */ +enum can_mcan_mram_cfg { + CAN_MCAN_MRAM_CFG_OFFSET = 0, + CAN_MCAN_MRAM_CFG_STD_FILTER, + CAN_MCAN_MRAM_CFG_EXT_FILTER, + CAN_MCAN_MRAM_CFG_RX_FIFO0, + CAN_MCAN_MRAM_CFG_RX_FIFO1, + CAN_MCAN_MRAM_CFG_RX_BUFFER, + CAN_MCAN_MRAM_CFG_TX_EVENT, + CAN_MCAN_MRAM_CFG_TX_BUFFER, + CAN_MCAN_MRAM_CFG_NUM_CELLS +}; + +/** + * @brief Get the Bosch M_CAN Message RAM offset + * + * @param node_id node identifier + * @return the Message RAM offset in bytes + */ +#define CAN_MCAN_DT_MRAM_OFFSET(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 0) + +/** + * @brief Get the number of standard (11-bit) filter elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of standard (11-bit) filter elements + */ +#define CAN_MCAN_DT_MRAM_STD_FILTER_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 1) + +/** + * @brief Get the number of extended (29-bit) filter elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of extended (29-bit) filter elements + */ +#define CAN_MCAN_DT_MRAM_EXT_FILTER_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 2) + +/** + * @brief Get the number of Rx FIFO 0 elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of Rx FIFO 0 elements + */ +#define CAN_MCAN_DT_MRAM_RX_FIFO0_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 3) + +/** + * @brief Get the number of Rx FIFO 1 elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of Rx FIFO 1 elements + */ +#define CAN_MCAN_DT_MRAM_RX_FIFO1_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 4) + +/** + * @brief Get the number of Rx Buffer elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of Rx Buffer elements + */ +#define CAN_MCAN_DT_MRAM_RX_BUFFER_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 5) + +/** + * @brief Get the number of Tx Event FIFO elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of Tx Event FIFO elements + */ +#define CAN_MCAN_DT_MRAM_TX_EVENT_FIFO_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 6) + +/** + * @brief Get the number of Tx Buffer elements in Bosch M_CAN Message RAM + * + * @param node_id node identifier + * @return the number of Tx Buffer elements + */ +#define CAN_MCAN_DT_MRAM_TX_BUFFER_ELEM(node_id) \ + DT_PROP_BY_IDX(node_id, bosch_mram_cfg, 7) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_OFFSET(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the Message RAM offset in bytes + * @see CAN_MCAN_DT_MRAM_OFFSET() + */ +#define CAN_MCAN_DT_INST_MRAM_OFFSET(inst) \ + CAN_MCAN_DT_MRAM_OFFSET(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_STD_FILTER_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of standard (11-bit) elements + * @see CAN_MCAN_DT_MRAM_STD_FILTER_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_STD_FILTER_ELEM(inst) \ + CAN_MCAN_DT_MRAM_STD_FILTER_ELEMDT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_EXT_FILTER_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of extended (29-bit) elements + * @see CAN_MCAN_DT_MRAM_EXT_FILTER_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_EXT_FILTER_ELEM(inst) \ + CAN_MCAN_DT_MRAM_EXT_FILTER_ELEM(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_RX_FIFO0_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of Rx FIFO 0 elements + * @see CAN_MCAN_DT_MRAM_RX_FIFO0_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_RX_FIFO0_ELEM(inst) \ + CAN_MCAN_DT_MRAM_RX_FIFO0_ELEM(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_RX_FIFO1_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of Rx FIFO 1 elements + * @see CAN_MCAN_DT_MRAM_RX_FIFO1_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_RX_FIFO1_ELEM(inst) \ + CAN_MCAN_DT_MRAM_RX_FIFO1_ELEM(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_RX_BUFFER_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of Rx Buffer elements + * @see CAN_MCAN_DT_MRAM_RX_BUFFER_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_RX_BUFFER_ELEM(inst) \ + CAN_MCAN_DT_MRAM_RX_BUFFER_ELEM(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_TX_EVENT_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of Tx Event FIFO elements + * @see CAN_MCAN_DT_MRAM_TX_EVENT_FIFO_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_TX_EVENT_FIFO_ELEM(inst) \ + CAN_MCAN_DT_MRAM_TX_EVENT_FIFO_ELEM(DT_DRV_INST(inst)) + +/** + * @brief Equivalent to CAN_MCAN_DT_MRAM_TX_BUFFER_ELEM(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the number of Tx Buffer elements + * @see CAN_MCAN_DT_MRAM_TX_BUFFER_ELEM() + */ +#define CAN_MCAN_DT_INST_MRAM_TX_BUFFER_ELEM(inst) \ + CAN_MCAN_DT_MRAM_TX_BUFFER_ELEM(DT_DRV_INST(inst)) + +#define NUM_STD_FILTER_ELEMENTS CAN_MCAN_DT_MRAM_STD_FILTER_ELEM(MCAN_DT_PATH) +#define NUM_EXT_FILTER_ELEMENTS CAN_MCAN_DT_MRAM_EXT_FILTER_ELEM(MCAN_DT_PATH) +#define NUM_RX_FIFO0_ELEMENTS CAN_MCAN_DT_MRAM_RX_FIFO0_ELEM(MCAN_DT_PATH) +#define NUM_RX_FIFO1_ELEMENTS CAN_MCAN_DT_MRAM_RX_FIFO1_ELEM(MCAN_DT_PATH) +#define NUM_RX_BUF_ELEMENTS CAN_MCAN_DT_MRAM_RX_BUFFER_ELEM(MCAN_DT_PATH) +#define NUM_TX_EVENT_FIFO_ELEMENTS CAN_MCAN_DT_MRAM_TX_EVENT_FIFO_ELEM(MCAN_DT_PATH) +#define NUM_TX_BUF_ELEMENTS CAN_MCAN_DT_MRAM_TX_BUFFER_ELEM(MCAN_DT_PATH) #ifdef CONFIG_CAN_STM32FD #define NUM_STD_FILTER_DATA CONFIG_CAN_MAX_STD_ID_FILTER @@ -408,68 +569,68 @@ struct can_mcan_rx_fifo_hdr { union { struct { - volatile uint32_t ext_id: 29; /* Extended Identifier */ - volatile uint32_t rtr: 1; /* Remote Transmission Request*/ - volatile uint32_t xtd: 1; /* Extended identifier */ - volatile uint32_t esi: 1; /* Error state indicator */ + uint32_t ext_id: 29; /* Extended Identifier */ + uint32_t rtr: 1; /* Remote Transmission Request*/ + uint32_t xtd: 1; /* Extended identifier */ + uint32_t esi: 1; /* Error state indicator */ }; struct { - volatile uint32_t pad1: 18; - volatile uint32_t std_id: 11; /* Standard Identifier */ - volatile uint32_t pad2: 3; + uint32_t pad1: 18; + uint32_t std_id: 11; /* Standard Identifier */ + uint32_t pad2: 3; }; }; - volatile uint32_t rxts: 16; /* Rx timestamp */ - volatile uint32_t dlc: 4; /* Data Length Code */ - volatile uint32_t brs: 1; /* Bit Rate Switch */ - volatile uint32_t fdf: 1; /* FD Format */ - volatile uint32_t res: 2; /* Reserved */ - volatile uint32_t fidx: 7; /* Filter Index */ - volatile uint32_t anmf: 1; /* Accepted non-matching frame */ + uint32_t rxts: 16; /* Rx timestamp */ + uint32_t dlc: 4; /* Data Length Code */ + uint32_t brs: 1; /* Bit Rate Switch */ + uint32_t fdf: 1; /* FD Format */ + uint32_t res: 2; /* Reserved */ + uint32_t fidx: 7; /* Filter Index */ + uint32_t anmf: 1; /* Accepted non-matching frame */ } __packed __aligned(4); struct can_mcan_rx_fifo { struct can_mcan_rx_fifo_hdr hdr; union { - volatile uint8_t data[64]; - volatile uint32_t data_32[16]; + uint8_t data[64]; + uint32_t data_32[16]; }; } __packed __aligned(4); struct can_mcan_mm { - volatile uint8_t idx: 5; - volatile uint8_t cnt: 3; + uint8_t idx: 5; + uint8_t cnt: 3; } __packed; struct can_mcan_tx_buffer_hdr { union { struct { - volatile uint32_t ext_id: 29; /* Identifier */ - volatile uint32_t rtr: 1; /* Remote Transmission Request*/ - volatile uint32_t xtd: 1; /* Extended identifier */ - volatile uint32_t esi: 1; /* Error state indicator */ + uint32_t ext_id: 29; /* Identifier */ + uint32_t rtr: 1; /* Remote Transmission Request*/ + uint32_t xtd: 1; /* Extended identifier */ + uint32_t esi: 1; /* Error state indicator */ }; struct { - volatile uint32_t pad1: 18; - volatile uint32_t std_id: 11; /* Identifier */ - volatile uint32_t pad2: 3; + uint32_t pad1: 18; + uint32_t std_id: 11; /* Identifier */ + uint32_t pad2: 3; }; }; - volatile uint16_t res1; /* Reserved */ - volatile uint8_t dlc: 4; /* Data Length Code */ - volatile uint8_t brs: 1; /* Bit Rate Switch */ - volatile uint8_t fdf: 1; /* FD Format */ - volatile uint8_t res2: 1; /* Reserved */ - volatile uint8_t efc: 1; /* Event FIFO control (Store Tx events) */ + uint16_t res1; /* Reserved */ + uint8_t dlc: 4; /* Data Length Code */ + uint8_t brs: 1; /* Bit Rate Switch */ + uint8_t fdf: 1; /* FD Format */ + uint8_t res2: 1; /* Reserved */ + uint8_t efc: 1; /* Event FIFO control (Store Tx events) */ struct can_mcan_mm mm; /* Message marker */ } __packed __aligned(4); struct can_mcan_tx_buffer { struct can_mcan_tx_buffer_hdr hdr; union { - volatile uint8_t data[64]; - volatile uint32_t data_32[16]; + uint8_t data[64]; + uint32_t data_32[16]; }; } __packed __aligned(4); @@ -477,16 +638,16 @@ struct can_mcan_tx_buffer { #define CAN_MCAN_TE_TXC 0x2 /* TX event in spite of cancellation */ struct can_mcan_tx_event_fifo { - volatile uint32_t id: 29; /* Identifier */ - volatile uint32_t rtr: 1; /* Remote Transmission Request*/ - volatile uint32_t xtd: 1; /* Extended identifier */ - volatile uint32_t esi: 1; /* Error state indicator */ + uint32_t id: 29; /* Identifier */ + uint32_t rtr: 1; /* Remote Transmission Request*/ + uint32_t xtd: 1; /* Extended identifier */ + uint32_t esi: 1; /* Error state indicator */ - volatile uint16_t txts; /* TX Timestamp */ - volatile uint8_t dlc: 4; /* Data Length Code */ - volatile uint8_t brs: 1; /* Bit Rate Switch */ - volatile uint8_t fdf: 1; /* FD Format */ - volatile uint8_t et: 2; /* Event type */ + uint16_t txts; /* TX Timestamp */ + uint8_t dlc: 4; /* Data Length Code */ + uint8_t brs: 1; /* Bit Rate Switch */ + uint8_t fdf: 1; /* FD Format */ + uint8_t et: 2; /* Event type */ struct can_mcan_mm mm; /* Message marker */ } __packed __aligned(4); @@ -504,11 +665,11 @@ struct can_mcan_tx_event_fifo { #define CAN_MCAN_SFT_DISABLED 0x3 struct can_mcan_std_filter { - volatile uint32_t id2: 11; /* ID2 for dual or range, mask otherwise */ - volatile uint32_t res: 5; - volatile uint32_t id1: 11; - volatile uint32_t sfce: 3; /* Filter config */ - volatile uint32_t sft: 2; /* Filter type */ + uint32_t id2: 11; /* ID2 for dual or range, mask otherwise */ + uint32_t res: 5; + uint32_t id1: 11; + uint32_t sfce: 3; /* Filter config */ + uint32_t sft: 2; /* Filter type */ } __packed __aligned(4); #define CAN_MCAN_EFT_RANGE_XIDAM 0x0 @@ -517,25 +678,32 @@ struct can_mcan_std_filter { #define CAN_MCAN_EFT_RANGE 0x3 struct can_mcan_ext_filter { - volatile uint32_t id1: 29; - volatile uint32_t efce: 3; /* Filter config */ - volatile uint32_t id2: 29; /* ID2 for dual or range, mask otherwise */ - volatile uint32_t res: 1; - volatile uint32_t eft: 2; /* Filter type */ + uint32_t id1: 29; + uint32_t efce: 3; /* Filter config */ + uint32_t id2: 29; /* ID2 for dual or range, mask otherwise */ + uint32_t res: 1; + uint32_t eft: 2; /* Filter type */ } __packed __aligned(4); struct can_mcan_msg_sram { - volatile struct can_mcan_std_filter std_filt[NUM_STD_FILTER_ELEMENTS]; - volatile struct can_mcan_ext_filter ext_filt[NUM_EXT_FILTER_ELEMENTS]; - volatile struct can_mcan_rx_fifo rx_fifo0[NUM_RX_FIFO0_ELEMENTS]; - volatile struct can_mcan_rx_fifo rx_fifo1[NUM_RX_FIFO1_ELEMENTS]; - volatile struct can_mcan_rx_fifo rx_buffer[NUM_RX_BUF_ELEMENTS]; - volatile struct can_mcan_tx_event_fifo tx_event_fifo[NUM_TX_EVENT_FIFO_ELEMENTS]; - volatile struct can_mcan_tx_buffer tx_buffer[NUM_TX_BUF_ELEMENTS]; + struct can_mcan_std_filter std_filt[NUM_STD_FILTER_ELEMENTS]; + struct can_mcan_ext_filter ext_filt[NUM_EXT_FILTER_ELEMENTS]; + struct can_mcan_rx_fifo rx_fifo0[NUM_RX_FIFO0_ELEMENTS]; + struct can_mcan_rx_fifo rx_fifo1[NUM_RX_FIFO1_ELEMENTS]; + struct can_mcan_rx_fifo rx_buffer[NUM_RX_BUF_ELEMENTS]; + struct can_mcan_tx_event_fifo tx_event_fifo[NUM_TX_EVENT_FIFO_ELEMENTS]; + struct can_mcan_tx_buffer tx_buffer[NUM_TX_BUF_ELEMENTS]; } __packed __aligned(4); +#define CAN_MCAN_MRAM_OFFSET_STD_FILTER offsetof(struct can_mcan_msg_sram, std_filt) +#define CAN_MCAN_MRAM_OFFSET_EXT_FILTER offsetof(struct can_mcan_msg_sram, ext_filt) +#define CAN_MCAN_MRAM_OFFSET_RX_FIFO0 offsetof(struct can_mcan_msg_sram, rx_fifo0) +#define CAN_MCAN_MRAM_OFFSET_RX_FIFO1 offsetof(struct can_mcan_msg_sram, rx_fifo1) +#define CAN_MCAN_MRAM_OFFSET_RX_BUFFER offsetof(struct can_mcan_msg_sram, rx_buffer) +#define CAN_MCAN_MRAM_OFFSET_TX_EVENT_FIFO offsetof(struct can_mcan_msg_sram, tx_event_fifo) +#define CAN_MCAN_MRAM_OFFSET_TX_BUFFER offsetof(struct can_mcan_msg_sram, tx_buffer) + struct can_mcan_data { - struct can_mcan_msg_sram *msg_ram; struct k_mutex lock; struct k_sem tx_sem; struct k_mutex tx_mtx; @@ -587,16 +755,71 @@ typedef int (*can_mcan_read_reg_t)(const struct device *dev, uint16_t reg, uint3 */ typedef int (*can_mcan_write_reg_t)(const struct device *dev, uint16_t reg, uint32_t val); -struct can_mcan_config { +/** + * @brief Bosch M_CAN driver front-end callback for reading from Message RAM + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param[out] dst Destination for the data read. The destination address must be 32-bit aligned. + * @param len Number of bytes to read. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +typedef int (*can_mcan_read_mram_t)(const struct device *dev, uint16_t offset, void *dst, + size_t len); + +/** + * @brief Bosch M_CAN driver front-end callback for writing to Message RAM + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param src Source for the data to be written. The source address must be 32-bit aligned. + * @param len Number of bytes to write. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +typedef int (*can_mcan_write_mram_t)(const struct device *dev, uint16_t offset, const void *src, + size_t len); + +/** + * @brief Bosch M_CAN driver front-end callback for clearing Message RAM + * + * Clear Message RAM by writing 0 to all words. + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param len Number of bytes to clear. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +typedef int (*can_mcan_clear_mram_t)(const struct device *dev, uint16_t offset, size_t len); + +/** + * @brief Bosch M_CAN driver front-end operations. + */ +struct can_mcan_ops { can_mcan_read_reg_t read_reg; can_mcan_write_reg_t write_reg; + can_mcan_read_mram_t read_mram; + can_mcan_write_mram_t write_mram; + can_mcan_clear_mram_t clear_mram; +}; + +struct can_mcan_config { + struct can_mcan_ops *ops; uint32_t bus_speed; - uint32_t bus_speed_data; uint16_t sjw; uint16_t sample_point; uint16_t prop_ts1; uint16_t ts2; #ifdef CONFIG_CAN_FD_MODE + uint32_t bus_speed_data; uint16_t sample_point_data; uint8_t sjw_data; uint8_t prop_ts1_data; @@ -613,14 +836,14 @@ struct can_mcan_config { * * @param node_id Devicetree node identifier * @param _custom Pointer to custom driver frontend configuration structure - * @param _read_reg Driver frontend Bosch M_CAN register read function - * @param _write_reg Driver frontend Bosch M_CAN register write function + * @param _ops Pointer to front-end @a can_mcan_ops */ #ifdef CONFIG_CAN_FD_MODE -#define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _read_reg, _write_reg) \ +#define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops) \ { \ - .read_reg = _read_reg, .write_reg = _write_reg, \ - .bus_speed = DT_PROP(node_id, bus_speed), .sjw = DT_PROP(node_id, sjw), \ + .ops = _ops, \ + .bus_speed = DT_PROP(node_id, bus_speed), \ + .sjw = DT_PROP(node_id, sjw), \ .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ @@ -636,10 +859,11 @@ struct can_mcan_config { .custom = _custom, \ } #else /* CONFIG_CAN_FD_MODE */ -#define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _read_reg, _write_reg) \ +#define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops) \ { \ - .read_reg = _read_reg, .write_reg = _write_reg, \ - .bus_speed = DT_PROP(node_id, bus_speed), .sjw = DT_PROP(node_id, sjw), \ + .ops = _ops, \ + .bus_speed = DT_PROP(node_id, bus_speed), \ + .sjw = DT_PROP(node_id, sjw), \ .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ @@ -654,21 +878,20 @@ struct can_mcan_config { * * @param inst DT_DRV_COMPAT instance number * @param _custom Pointer to custom driver frontend configuration structure - * @param _read_reg Driver frontend Bosch M_CAN register read function - * @param _write_reg Driver frontend Bosch M_CAN register write function + * @param _ops Pointer to front-end @a can_mcan_ops * @see CAN_MCAN_DT_CONFIG_GET() */ -#define CAN_MCAN_DT_CONFIG_INST_GET(inst, _custom, _read_reg, _write_reg) \ - CAN_MCAN_DT_CONFIG_GET(DT_DRV_INST(inst), _custom, _read_reg, _write_reg) +#define CAN_MCAN_DT_CONFIG_INST_GET(inst, _custom, _ops) \ + CAN_MCAN_DT_CONFIG_GET(DT_DRV_INST(inst), _custom, _ops) /** * @brief Initializer for a @a can_mcan_data struct * @param _msg_ram Pointer to message RAM structure * @param _custom Pointer to custom driver frontend data structure */ -#define CAN_MCAN_DATA_INITIALIZER(_msg_ram, _custom) \ +#define CAN_MCAN_DATA_INITIALIZER(_custom) \ { \ - .msg_ram = _msg_ram, .custom = _custom, \ + .custom = _custom, \ } /** @@ -703,6 +926,116 @@ static inline int can_mcan_sys_write_reg(mm_reg_t base, uint16_t reg, uint32_t v return 0; } +/** + * @brief Bosch M_CAN driver front-end callback helper for reading from memory mapped Message RAM + * + * @param base Base address of the Message RAM for the given Bosch M_CAN instance. The base address + * must be 32-bit aligned. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param[out] dst Destination for the data read. The destination address must be 32-bit aligned. + * @param len Number of bytes to read. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_sys_read_mram(mem_addr_t base, uint16_t offset, void *dst, size_t len) +{ + volatile uint32_t *src32 = (volatile uint32_t *)(base + offset); + uint32_t *dst32 = (uint32_t *)dst; + size_t len32 = len / sizeof(uint32_t); + + __ASSERT(base % 4U == 0U, "base must be a multiple of 4"); + __ASSERT(offset % 4U == 0U, "offset must be a multiple of 4"); + __ASSERT(POINTER_TO_UINT(dst) % 4U == 0U, "dst must be 32-bit aligned"); + __ASSERT(len % 4U == 0U, "len must be a multiple of 4"); + +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) + int err; + + err = sys_cache_data_invd_range((void *)(base + offset), len); + if (err != 0) { + return err; + } +#endif /* !defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) */ + + while (len32-- > 0) { + *dst32++ = *src32++; + } + + return 0; +} + +/** + * @brief Bosch M_CAN driver front-end callback helper for writing to memory mapped Message RAM + * + * @param base Base address of the Message RAM for the given Bosch M_CAN instance. The base address + * must be 32-bit aligned. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param src Source for the data to be written. The source address must be 32-bit aligned. + * @param len Number of bytes to write. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_sys_write_mram(mem_addr_t base, uint16_t offset, const void *src, + size_t len) +{ + volatile uint32_t *dst32 = (volatile uint32_t *)(base + offset); + const uint32_t *src32 = (const uint32_t *)src; + size_t len32 = len / sizeof(uint32_t); + + __ASSERT(base % 4U == 0U, "base must be a multiple of 4"); + __ASSERT(offset % 4U == 0U, "offset must be a multiple of 4"); + __ASSERT(POINTER_TO_UINT(src) % 4U == 0U, "src must be 32-bit aligned"); + __ASSERT(len % 4U == 0U, "len must be a multiple of 4"); + + while (len32-- > 0) { + *dst32++ = *src32++; + } + +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) + return sys_cache_data_flush_range((void *)(base + offset), len); +#else /* defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) */ + return 0; +#endif /* !defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) */ +} + +/** + * @brief Bosch M_CAN driver front-end callback helper for clearing memory mapped Message RAM + * + * Clear Message RAM by writing 0 to all words. + * + * @param base Base address of the Message RAM for the given Bosch M_CAN instance. The base address + * must be 32-bit aligned. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param len Number of bytes to clear. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_sys_clear_mram(mem_addr_t base, uint16_t offset, size_t len) +{ + volatile uint32_t *dst32 = (volatile uint32_t *)(base + offset); + size_t len32 = len / sizeof(uint32_t); + + __ASSERT(base % 4U == 0U, "base must be a multiple of 4"); + __ASSERT(offset % 4U == 0U, "offset must be a multiple of 4"); + __ASSERT(len % 4U == 0U, "len must be a multiple of 4"); + + while (len32-- > 0) { + *dst32++ = 0U; + } + +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) + return sys_cache_data_flush_range((void *)(base + offset), len); +#else /* defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) */ + return 0; +#endif /* !defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) */ +} + /** * @brief Read a Bosch M_CAN register * @@ -729,6 +1062,66 @@ 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 Read from Bosch M_CAN Message RAM + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param[out] dst Destination for the data read. + * @param len Number of bytes to read. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_read_mram(const struct device *dev, uint16_t offset, void *dst, + size_t len) +{ + const struct can_mcan_config *config = dev->config; + + return config->ops->read_mram(dev, offset, dst, len); +} + +/** + * @brief Write to Bosch M_CAN Message RAM + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param src Source for the data to be written + * @param len Number of bytes to write. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + const struct can_mcan_config *config = dev->config; + + return config->ops->write_mram(dev, offset, src, len); +} + +/** + * @brief Clear Bosch M_CAN Message RAM + * + * Clear Message RAM by writing 0 to all words. + * + * @param dev Pointer to the device structure for the driver instance. + * @param offset Offset from the start of the Message RAM for the given Bosch M_CAN instance. The + * offset must be 32-bit aligned. + * @param len Number of bytes to clear. Must be a multiple of 4. + * + * @retval 0 If successful. + * @retval -EIO General input/output error. + */ +static inline int can_mcan_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + const struct can_mcan_config *config = dev->config; + + return config->ops->clear_mram(dev, offset, len); +} + /** * @brief Configure Bosch M_MCAN Message RAM start addresses. * @@ -746,11 +1139,12 @@ int can_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t val); * * @param dev Pointer to the device structure for the driver instance. * @param mrba Message RAM Base Address. + * @param mram Message RAM Address. * * @retval 0 If successful. * @retval -EIO General input/output error. */ -int can_mcan_configure_message_ram(const struct device *dev, uintptr_t mrba); +int can_mcan_configure_mram(const struct device *dev, uintptr_t mrba, uintptr_t mram); int can_mcan_get_capabilities(const struct device *dev, can_mode_t *cap); diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index fe507b46587..0663c25e65e 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -49,6 +49,31 @@ static int mcux_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t return can_mcan_sys_write_reg(mcux_config->base, reg, val); } +static int mcux_mcan_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct mcux_mcan_data *mcux_data = mcan_data->custom; + + return can_mcan_sys_read_mram(POINTER_TO_UINT(&mcux_data->msg_ram), offset, dst, len); +} + +static int mcux_mcan_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct mcux_mcan_data *mcux_data = mcan_data->custom; + + return can_mcan_sys_write_mram(POINTER_TO_UINT(&mcux_data->msg_ram), offset, src, len); +} + +static int mcux_mcan_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct mcux_mcan_data *mcux_data = mcan_data->custom; + + return can_mcan_sys_clear_mram(POINTER_TO_UINT(&mcux_data->msg_ram), offset, len); +} + static int mcux_mcan_get_core_clock(const struct device *dev, uint32_t *rate) { const struct can_mcan_config *mcan_config = dev->config; @@ -88,7 +113,7 @@ static int mcux_mcan_init(const struct device *dev) return -EIO; } - err = can_mcan_configure_message_ram(dev, mrba); + err = can_mcan_configure_mram(dev, mrba, POINTER_TO_UINT(&mcux_data->msg_ram)); if (err != 0) { return -EIO; } @@ -170,6 +195,14 @@ static const struct can_driver_api mcux_mcan_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; +static const struct can_mcan_ops mcux_mcan_ops = { + .read_reg = mcux_mcan_read_reg, + .write_reg = mcux_mcan_write_reg, + .read_mram = mcux_mcan_read_mram, + .write_mram = mcux_mcan_write_mram, + .clear_mram = mcux_mcan_clear_mram, +}; + #define MCUX_MCAN_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ \ @@ -186,14 +219,12 @@ static const struct can_driver_api mcux_mcan_driver_api = { \ static const struct can_mcan_config can_mcan_config_##n = \ CAN_MCAN_DT_CONFIG_INST_GET(n, &mcux_mcan_config_##n, \ - mcux_mcan_read_reg, \ - mcux_mcan_write_reg); \ + &mcux_mcan_ops); \ \ static struct mcux_mcan_data mcux_mcan_data_##n; \ \ static struct can_mcan_data can_mcan_data_##n = \ - CAN_MCAN_DATA_INITIALIZER(&mcux_mcan_data_##n.msg_ram, \ - &mcux_mcan_data_##n); \ + CAN_MCAN_DATA_INITIALIZER(&mcux_mcan_data_##n); \ \ DEVICE_DT_INST_DEFINE(n, &mcux_mcan_init, NULL, \ &can_mcan_data_##n, \ diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index d80e05f45dc..350bb5e70b9 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -47,6 +47,31 @@ static int can_sam_write_reg(const struct device *dev, uint16_t reg, uint32_t va return can_mcan_sys_write_reg(sam_config->base, reg, val); } +static int can_sam_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam_data *sam_data = mcan_data->custom; + + return can_mcan_sys_read_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, dst, len); +} + +static int can_sam_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam_data *sam_data = mcan_data->custom; + + return can_mcan_sys_write_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, src, len); +} + +static int can_sam_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam_data *sam_data = mcan_data->custom; + + return can_mcan_sys_clear_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, len); +} + static int can_sam_get_core_clock(const struct device *dev, uint32_t *rate) { const struct can_mcan_config *mcan_cfg = dev->config; @@ -71,6 +96,8 @@ static int can_sam_init(const struct device *dev) { const struct can_mcan_config *mcan_cfg = dev->config; const struct can_sam_config *sam_cfg = mcan_cfg->custom; + struct can_mcan_data *mcan_data = dev->data; + struct can_sam_data *sam_data = mcan_data->custom; int ret; can_sam_clock_enable(sam_cfg); @@ -80,7 +107,7 @@ static int can_sam_init(const struct device *dev) return ret; } - ret = can_mcan_configure_message_ram(dev, 0U); + ret = can_mcan_configure_mram(dev, 0U, POINTER_TO_UINT(&sam_data->msg_ram)); if (ret != 0) { return ret; } @@ -145,6 +172,14 @@ static const struct can_driver_api can_sam_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; +static const struct can_mcan_ops can_sam_ops = { + .read_reg = can_sam_read_reg, + .write_reg = can_sam_write_reg, + .read_mram = can_sam_read_mram, + .write_mram = can_sam_write_mram, + .clear_mram = can_sam_clear_mram, +}; + #define CAN_SAM_IRQ_CFG_FUNCTION(inst) \ static void config_can_##inst##_irq(void) \ { \ @@ -170,15 +205,13 @@ static void config_can_##inst##_irq(void) \ static const struct can_mcan_config can_mcan_cfg_##inst = \ CAN_MCAN_DT_CONFIG_INST_GET(inst, &can_sam_cfg_##inst, \ - can_sam_read_reg, \ - can_sam_write_reg); + &can_sam_ops); #define CAN_SAM_DATA_INST(inst) \ static struct can_sam_data can_sam_data_##inst; \ \ static struct can_mcan_data can_mcan_data_##inst = \ - CAN_MCAN_DATA_INITIALIZER(&can_sam_data_##inst.msg_ram, \ - &can_sam_data_##inst); \ + CAN_MCAN_DATA_INITIALIZER(&can_sam_data_##inst); #define CAN_SAM_DEVICE_INST(inst) \ DEVICE_DT_INST_DEFINE(inst, &can_sam_init, NULL, \ diff --git a/drivers/can/can_sam0.c b/drivers/can/can_sam0.c index fbc259099d8..829acd11f1b 100644 --- a/drivers/can/can_sam0.c +++ b/drivers/can/can_sam0.c @@ -63,6 +63,31 @@ static int can_sam0_write_reg(const struct device *dev, uint16_t reg, uint32_t v return can_mcan_sys_write_reg(sam_config->base, reg, val); } +static int can_sam0_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam0_data *sam_data = mcan_data->custom; + + return can_mcan_sys_read_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, dst, len); +} + +static int can_sam0_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam0_data *sam_data = mcan_data->custom; + + return can_mcan_sys_write_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, src, len); +} + +static int can_sam0_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + struct can_mcan_data *mcan_data = dev->data; + struct can_sam0_data *sam_data = mcan_data->custom; + + return can_mcan_sys_clear_mram(POINTER_TO_UINT(&sam_data->msg_ram), offset, len); +} + void can_sam0_line_x_isr(const struct device *dev) { can_mcan_line_0_isr(dev); @@ -98,6 +123,8 @@ static int can_sam0_init(const struct device *dev) { const struct can_mcan_config *mcan_cfg = dev->config; const struct can_sam0_config *sam_cfg = mcan_cfg->custom; + struct can_mcan_data *mcan_data = dev->data; + struct can_sam0_data *sam_data = mcan_data->custom; int ret; can_sam0_clock_enable(sam_cfg); @@ -108,7 +135,7 @@ static int can_sam0_init(const struct device *dev) return ret; } - ret = can_mcan_configure_message_ram(dev, 0U); + ret = can_mcan_configure_mram(dev, 0U, POINTER_TO_UINT(&sam_data->msg_ram)); if (ret != 0) { LOG_ERR("failed to configure message ram"); return ret; @@ -175,6 +202,14 @@ static const struct can_driver_api can_sam0_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; +static const struct can_mcan_ops can_sam0_ops = { + .read_reg = can_sam0_read_reg, + .write_reg = can_sam0_write_reg, + .read_mram = can_sam0_read_mram, + .write_mram = can_sam0_write_mram, + .clear_mram = can_sam0_clear_mram, +}; + #define CAN_SAM0_IRQ_CFG_FUNCTION(inst) \ static void config_can_##inst##_irq(void) \ { \ @@ -197,16 +232,13 @@ static void config_can_##inst##_irq(void) \ }; \ \ static const struct can_mcan_config can_mcan_cfg_##inst = \ - CAN_MCAN_DT_CONFIG_INST_GET(inst, &can_sam0_cfg_##inst, \ - can_sam0_read_reg, \ - can_sam0_write_reg); + CAN_MCAN_DT_CONFIG_INST_GET(inst, &can_sam0_cfg_##inst, &can_sam0_ops); #define CAN_SAM0_DATA_INST(inst) \ static struct can_sam0_data can_sam0_data_##inst; \ \ static struct can_mcan_data can_mcan_data_##inst = \ - CAN_MCAN_DATA_INITIALIZER(&can_sam0_data_##inst.msg_ram, \ - &can_sam0_data_##inst); \ + CAN_MCAN_DATA_INITIALIZER(&can_sam0_data_##inst); #define CAN_SAM0_DEVICE_INST(inst) \ DEVICE_DT_INST_DEFINE(inst, &can_sam0_init, NULL, \ diff --git a/drivers/can/can_stm32fd.c b/drivers/can/can_stm32fd.c index a468f86b0a5..ae5ee52479d 100644 --- a/drivers/can/can_stm32fd.c +++ b/drivers/can/can_stm32fd.c @@ -169,6 +169,7 @@ LOG_MODULE_REGISTER(can_stm32fd, CONFIG_CAN_LOG_LEVEL); struct can_stm32fd_config { mm_reg_t base; + mem_addr_t mram; size_t pclk_len; const struct stm32_pclken *pclken; void (*config_irq)(void); @@ -445,6 +446,31 @@ static int can_stm32fd_write_reg(const struct device *dev, uint16_t reg, uint32_ return can_mcan_sys_write_reg(stm32fd_config->base, remap, bits); } +static int can_stm32fd_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_stm32fd_config *stm32fd_config = mcan_config->custom; + + return can_mcan_sys_read_mram(stm32fd_config->mram, offset, dst, len); +} + +static int can_stm32fd_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_stm32fd_config *stm32fd_config = mcan_config->custom; + + return can_mcan_sys_write_mram(stm32fd_config->mram, offset, src, len); +} + +static int can_stm32fd_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + const struct can_mcan_config *mcan_config = dev->config; + const struct can_stm32fd_config *stm32fd_config = mcan_config->custom; + + return can_mcan_sys_clear_mram(stm32fd_config->mram, offset, len); +} + static int can_stm32fd_get_core_clock(const struct device *dev, uint32_t *rate) { const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); @@ -601,12 +627,21 @@ static const struct can_driver_api can_stm32fd_driver_api = { #endif /* CONFIG_CAN_FD_MODE */ }; +static const struct can_mcan_ops can_stm32fd_ops = { + .read_reg = can_stm32fd_read_reg, + .write_reg = can_stm32fd_write_reg, + .read_mram = can_stm32fd_read_mram, + .write_mram = can_stm32fd_write_mram, + .clear_mram = can_stm32fd_clear_mram, +}; + /* Assert that the Message RAM configuration meets the hardware limitiations */ -BUILD_ASSERT(NUM_STD_FILTER_ELEMENTS <= 28, "Maximum standard filter elements exceeded"); -BUILD_ASSERT(NUM_EXT_FILTER_ELEMENTS <= 8, "Maximum extended filter elements exceeded"); +BUILD_ASSERT(NUM_STD_FILTER_ELEMENTS <= 28, "Standard filter elements must be 28"); +BUILD_ASSERT(NUM_EXT_FILTER_ELEMENTS <= 8, "Extended filter elements must be 8"); BUILD_ASSERT(NUM_RX_FIFO0_ELEMENTS == 3, "Rx FIFO 0 elements must be 3"); BUILD_ASSERT(NUM_RX_FIFO1_ELEMENTS == 3, "Rx FIFO 1 elements must be 3"); BUILD_ASSERT(NUM_RX_BUF_ELEMENTS == 0, "Rx Buffer elements must be 0"); +BUILD_ASSERT(NUM_TX_EVENT_FIFO_ELEMENTS == 3, "Tx Event FIFO elements must be 3"); BUILD_ASSERT(NUM_TX_BUF_ELEMENTS == 3, "Tx Buffer elements must be 0"); #define CAN_STM32FD_IRQ_CFG_FUNCTION(inst) \ @@ -630,6 +665,7 @@ static void config_can_##inst##_irq(void) \ \ static const struct can_stm32fd_config can_stm32fd_cfg_##inst = { \ .base = (mm_reg_t)DT_INST_REG_ADDR_BY_NAME(inst, m_can), \ + .mram = (mem_addr_t)DT_INST_REG_ADDR_BY_NAME(inst, message_ram), \ .pclken = can_stm32fd_pclken_##inst, \ .pclk_len = DT_INST_NUM_CLOCKS(inst), \ .config_irq = config_can_##inst##_irq, \ @@ -639,14 +675,11 @@ static void config_can_##inst##_irq(void) \ \ static const struct can_mcan_config can_mcan_cfg_##inst = \ CAN_MCAN_DT_CONFIG_INST_GET(inst, &can_stm32fd_cfg_##inst, \ - can_stm32fd_read_reg, \ - can_stm32fd_write_reg); + &can_stm32fd_ops); #define CAN_STM32FD_DATA_INST(inst) \ static struct can_mcan_data can_mcan_data_##inst = \ - CAN_MCAN_DATA_INITIALIZER((struct can_mcan_msg_sram *) \ - DT_INST_REG_ADDR_BY_NAME(inst, message_ram), \ - NULL); + CAN_MCAN_DATA_INITIALIZER(NULL); #define CAN_STM32FD_DEVICE_INST(inst) \ DEVICE_DT_INST_DEFINE(inst, &can_stm32fd_init, NULL, \ diff --git a/drivers/can/can_stm32h7.c b/drivers/can/can_stm32h7.c index a2f1ed86c22..cc85a7a596f 100644 --- a/drivers/can/can_stm32h7.c +++ b/drivers/can/can_stm32h7.c @@ -22,6 +22,7 @@ LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); struct can_stm32h7_config { mm_reg_t base; + mem_addr_t mram; void (*config_irq)(void); const struct pinctrl_dev_config *pcfg; struct stm32_pclken pclken; @@ -29,18 +30,43 @@ struct can_stm32h7_config { static int can_stm32h7_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) { - const struct can_mcan_config *mcan_config = dev->config; - const struct can_stm32h7_config *stm32h7_config = mcan_config->custom; + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; - return can_mcan_sys_read_reg(stm32h7_config->base, reg, val); + return can_mcan_sys_read_reg(stm32h7_cfg->base, reg, val); } static int can_stm32h7_write_reg(const struct device *dev, uint16_t reg, uint32_t val) { - const struct can_mcan_config *mcan_config = dev->config; - const struct can_stm32h7_config *stm32h7_config = mcan_config->custom; + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; - return can_mcan_sys_write_reg(stm32h7_config->base, reg, val); + return can_mcan_sys_write_reg(stm32h7_cfg->base, reg, val); +} + +static int can_stm32h7_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; + + return can_mcan_sys_read_mram(stm32h7_cfg->mram, offset, dst, len); +} + +static int can_stm32h7_write_mram(const struct device *dev, uint16_t offset, const void *src, + size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; + + return can_mcan_sys_write_mram(stm32h7_cfg->mram, offset, src, len); +} + +static int can_stm32h7_clear_mram(const struct device *dev, uint16_t offset, size_t len) +{ + const struct can_mcan_config *mcan_cfg = dev->config; + const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; + + return can_mcan_sys_clear_mram(stm32h7_cfg->mram, offset, len); } static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) @@ -93,8 +119,6 @@ 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 */ @@ -109,7 +133,7 @@ static int can_stm32h7_init(const struct device *dev) return ret; } - ret = can_mcan_configure_message_ram(dev, mrba); + ret = can_mcan_configure_mram(dev, stm32h7_cfg->mram, stm32h7_cfg->mram); if (ret != 0) { return ret; } @@ -182,6 +206,14 @@ static const struct can_driver_api can_stm32h7_driver_api = { #endif }; +static const struct can_mcan_ops can_stm32h7_ops = { + .read_reg = can_stm32h7_read_reg, + .write_reg = can_stm32h7_write_reg, + .read_mram = can_stm32h7_read_mram, + .write_mram = can_stm32h7_write_mram, + .clear_mram = can_stm32h7_clear_mram, +}; + #define CAN_STM32H7_MCAN_INIT(n) \ static void stm32h7_mcan_irq_config_##n(void); \ \ @@ -189,6 +221,7 @@ static const struct can_driver_api can_stm32h7_driver_api = { \ static const struct can_stm32h7_config can_stm32h7_cfg_##n = { \ .base = (mm_reg_t)DT_INST_REG_ADDR_BY_NAME(n, m_can), \ + .mram = (mem_addr_t)DT_INST_REG_ADDR_BY_NAME(n, message_ram), \ .config_irq = stm32h7_mcan_irq_config_##n, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .pclken = { \ @@ -199,12 +232,10 @@ static const struct can_driver_api can_stm32h7_driver_api = { \ static const struct can_mcan_config can_mcan_cfg_##n = \ CAN_MCAN_DT_CONFIG_INST_GET(n, &can_stm32h7_cfg_##n, \ - can_stm32h7_read_reg, \ - can_stm32h7_write_reg); \ + &can_stm32h7_ops); \ \ static struct can_mcan_data can_mcan_data_##n = \ - CAN_MCAN_DATA_INITIALIZER((struct can_mcan_msg_sram *) \ - DT_INST_REG_ADDR_BY_NAME(n, message_ram), NULL); \ + CAN_MCAN_DATA_INITIALIZER(NULL); \ \ DEVICE_DT_INST_DEFINE(n, &can_stm32h7_init, NULL, \ &can_mcan_data_##n, \