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 <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2023-05-10 22:07:42 +02:00 committed by Anas Nashif
commit 3ed354eea1
7 changed files with 816 additions and 246 deletions

View file

@ -5,7 +5,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/cache.h>
#include <zephyr/drivers/can.h>
#include <zephyr/drivers/can/transceiver.h>
#include <zephyr/kernel.h>
@ -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));
}

View file

@ -9,6 +9,7 @@
#ifndef ZEPHYR_DRIVERS_CAN_MCAN_H_
#define ZEPHYR_DRIVERS_CAN_MCAN_H_
#include <zephyr/cache.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/can.h>
#include <zephyr/kernel.h>
@ -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);

View file

@ -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, \

View file

@ -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, \

View file

@ -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, \

View file

@ -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, \

View file

@ -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, \