Skip to content

Commit

Permalink
drivers: nxp_s32_canxl: add support RX FIFO
Browse files Browse the repository at this point in the history
Driver supports both CAN classic and CAN FD frames
when using RX FIFO mode

Signed-off-by: Cong Nguyen Huu <cong.nguyenhuu@nxp.com>
  • Loading branch information
congnguyenhuu authored and nashif committed Jan 17, 2024
1 parent c78f583 commit 9eb0a55
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 34 deletions.
14 changes: 10 additions & 4 deletions drivers/can/Kconfig.nxp_s32
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2022-2023 NXP
# Copyright 2022-2024 NXP
# SPDX-License-Identifier: Apache-2.0

config CAN_NXP_S32_CANXL
Expand All @@ -10,17 +10,23 @@ config CAN_NXP_S32_CANXL
Enable support for NXP S32 CANXL driver.

if CAN_NXP_S32_CANXL
config CAN_NXP_S32_RX_FIFO
bool "NXP S32 CANXL uses RX FIFO"
default y
help
If this is enabled, NXP S32 CANXL uses RX FIFO.
Otherwise NXP S32 CANXL uses RX Message Descriptor.

config CAN_NXP_S32_MAX_RX
int "Maximum number of RX descriptors"
depends on CAN_NXP_S32_CANXL
default 16
range 1 128
range 1 32 if CAN_NXP_S32_RX_FIFO
range 1 128 if !CAN_NXP_S32_RX_FIFO
help
Maximum number of RX descriptors.

config CAN_NXP_S32_MAX_TX
int "Maximum number of TX descriptors"
depends on CAN_NXP_S32_CANXL
default 16
range 1 128
help
Expand Down
199 changes: 178 additions & 21 deletions drivers/can/can_nxp_s32_canxl.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 NXP
* Copyright 2022-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -23,8 +23,14 @@
* Convert from RX message buffer index to allocated filter ID and
* vice versa.
*/
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
#define RX_MBIDX_TO_ALLOC_IDX(x) (x)
#define ALLOC_IDX_TO_RXMB_IDX(x) (x)
#else
#define RX_MBIDX_TO_ALLOC_IDX(x) (x - CONFIG_CAN_NXP_S32_MAX_TX)
#define ALLOC_IDX_TO_RXMB_IDX(x) (x + CONFIG_CAN_NXP_S32_MAX_TX)
#endif


/*
* Convert from TX message buffer index to allocated TX ID and vice
Expand All @@ -37,6 +43,13 @@
#define CAN_NXP_S32_MAX_BITRATE 8000000
#define CAN_NXP_S32_DATA_LENGTH 64

#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
/* RX FIFO depth is fixed to the maximum value */
#define CAN_NXP_S32_RX_FIFO_DEPTH 32
/* RX FIFO water mark equal 1 that allows the interrupt is generated after 1 message received */
#define CAN_NXP_S32_RX_FIFO_WATERMARK 1
#endif

LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL);

#define SP_AND_TIMING_NOT_SET(inst) \
Expand Down Expand Up @@ -66,6 +79,10 @@ struct can_nxp_s32_config {
CANXL_SIC_Type *base_sic;
CANXL_GRP_CONTROL_Type *base_grp_ctrl;
CANXL_DSC_CONTROL_Type *base_dsc_ctrl;
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
CANXL_RXFIFO_Type * base_rx_fifo;
CANXL_RXFIFO_CONTROL_Type *base_rx_fifo_ctrl;
#endif
uint8 instance;
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
Expand Down Expand Up @@ -98,7 +115,9 @@ struct can_nxp_s32_tx_callback {

struct can_nxp_s32_rx_callback {
struct can_filter filter;
#ifndef CONFIG_CAN_NXP_S32_RX_FIFO
Canexcel_Ip_DataInfoType rx_info;
#endif
can_rx_callback_t function;
void *arg;
};
Expand All @@ -109,14 +128,21 @@ struct can_nxp_s32_data {
ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX);
struct k_mutex rx_mutex;
struct can_nxp_s32_rx_callback rx_cbs[CONFIG_CAN_NXP_S32_MAX_RX];
#ifndef CONFIG_CAN_NXP_S32_RX_FIFO
Canexcel_RxFdMsg *rx_msg;
#endif

ATOMIC_DEFINE(tx_allocs, CONFIG_CAN_NXP_S32_MAX_TX);
struct k_sem tx_allocs_sem;
struct k_mutex tx_mutex;
struct can_nxp_s32_tx_callback tx_cbs[CONFIG_CAN_NXP_S32_MAX_TX];
Canexcel_TxFdMsgType *tx_msg;

#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
Canexcel_Ip_RxFifoFilterID_ADDR * rx_fifo_filter;
Canexcel_RxFdMsg *rx_fifo;
#endif

struct can_timing timing;
#ifdef CONFIG_CAN_FD_MODE
struct can_timing timing_data;
Expand All @@ -140,6 +166,50 @@ static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *ca
return 0;
}

#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
static void can_nxp_s32_config_rx_fifo_filter(const struct device *dev, int filter_id)
{
const struct can_nxp_s32_config *config = dev->config;
struct can_nxp_s32_data *data = dev->data;

/* Lock the RxFIFO by System by reading register */
(void)config->base_rx_fifo_ctrl->RXFSYSLOCK;

CanXL_ConfigIDFilter(config->base_rx_fifo,
&data->rx_fifo_filter[filter_id], filter_id);

if ((config->base_rx_fifo_ctrl->RXFCSTA & CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK)
== CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) {
/* Clear the sys lock to enable transfers */
config->base_rx_fifo_ctrl->RXFSYSLOCK =
CANXL_RXFIFO_CONTROL_RXFSYSLOCK_SYSLOCK_MASK;
}
}

/* Get the RxFiFO filter matched with the received RxFIFO message queue */
static inline int can_nxp_s32_get_rx_fifo_filter(struct can_nxp_s32_data *data)
{
int alloc = -ENOSPC;
uint32_t mask;

for (int filter_id = 0; filter_id < CONFIG_CAN_NXP_S32_MAX_RX; filter_id++) {
mask = data->rx_fifo_filter[filter_id].idAddrFilterL;

if (mask == 0) {
continue;
}

if ((data->rx_fifo[0].Header.Id & mask) ==
(data->rx_fifo_filter[filter_id].idAddrFilterH & mask)) {
alloc = filter_id;
break;
}
}

return alloc;
}
#endif

static int can_nxp_s32_start(const struct device *dev)
{
const struct can_nxp_s32_config *config = dev->config;
Expand Down Expand Up @@ -404,9 +474,20 @@ static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id
k_mutex_lock(&data->rx_mutex, K_FOREVER);

if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
data->rx_fifo_filter[mb_indx].idAddrFilterL = 0;
data->rx_fifo_filter[mb_indx].idAddrFilterH = 0;

Canexcel_Ip_EnterFreezeMode(config->instance);

can_nxp_s32_config_rx_fifo_filter(dev, mb_indx);

Canexcel_Ip_ExitFreezeMode(config->instance);
#else
if (can_nxp_s32_abort_msg(config, mb_indx)) {
LOG_ERR("Can't abort message !");
};
#endif

data->rx_cbs[filter_id].function = NULL;
data->rx_cbs[filter_id].arg = NULL;
Expand Down Expand Up @@ -458,31 +539,47 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev,
data->rx_cbs[alloc].arg = user_data;
data->rx_cbs[alloc].filter = *filter;

data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) {
.frame = !!(filter->flags & CAN_FILTER_FDF) ?
CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME,
.idType = !!(filter->flags & CAN_FILTER_IDE) ?
CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
.dataLength = CAN_NXP_S32_DATA_LENGTH,
};

/* Set Rx Mb individual mask for */
mb_indx = ALLOC_IDX_TO_RXMB_IDX(alloc);
if (!!(filter->flags & CAN_FILTER_IDE)) {
mask = (filter->mask & CANXL_IP_ID_EXT_MASK);
mask = filter->mask & CANXL_IP_ID_EXT_MASK;
} else {
mask = ((filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK);
mask = (filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK;
}

Canexcel_Ip_EnterFreezeMode(config->instance);

#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
uint32_t filter_id;

if (!!(filter->flags & CAN_FILTER_IDE)) {
filter_id = filter->id & CANXL_IP_ID_EXT_MASK;
} else {
filter_id = (filter->id << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK;
}

data->rx_fifo_filter[mb_indx].filterType = CANEXCEL_IP_RX_FIFO_MASK_FILTER;
data->rx_fifo_filter[mb_indx].idAddrFilterL = mask;
data->rx_fifo_filter[mb_indx].idAddrFilterH = filter_id;

can_nxp_s32_config_rx_fifo_filter(dev, mb_indx);
#else
data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) {
.frame = !!(filter->flags & CAN_FILTER_FDF) ?
CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME,
.idType = !!(filter->flags & CAN_FILTER_IDE) ?
CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD,
.dataLength = CAN_NXP_S32_DATA_LENGTH,
};

Canexcel_Ip_SetRxIndividualMask(config->instance, mb_indx,
data->rx_cbs[alloc].rx_info.frame, mask);

Canexcel_Ip_ConfigRx(config->instance, mb_indx, filter->id,
&data->rx_cbs[alloc].rx_info);

Canexcel_Ip_ReceiveFD(config->instance, mb_indx, &data->rx_msg[alloc], FALSE);
#endif

Canexcel_Ip_ExitFreezeMode(config->instance);

Expand Down Expand Up @@ -775,7 +872,6 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev,
struct can_frame frame = {0};
can_tx_callback_t tx_func;
can_rx_callback_t rx_func;
Canexcel_Ip_StatusType status;
int alloc;

if (eventType == CANEXCEL_EVENT_TX_COMPLETE) {
Expand All @@ -786,6 +882,33 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev,
tx_func(dev, 0, data->tx_cbs[alloc].arg);
k_sem_give(&data->tx_allocs_sem);
}
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
} else if (eventType == CANEXCEL_EVENT_RXFIFO_COMPLETE) {
alloc = can_nxp_s32_get_rx_fifo_filter(data);

if (alloc != -ENOSPC) {
rx_func = data->rx_cbs[alloc].function;
if (atomic_test_bit(data->rx_allocs, alloc)) {
nxp_s32_msg_data_to_zcan_frame(data->rx_fifo[0], &frame);

LOG_DBG("%s: Received %d bytes Rx FiFo %d, "
"Rx Id: 0x%x, "
"Id type: %s %s %s %s",
dev->name, can_dlc_to_bytes(frame.dlc),
alloc, frame.id,
!!(frame.flags & CAN_FRAME_IDE) ?
"extended" : "standard",
!!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "",
!!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "",
!!(frame.flags & CAN_FRAME_BRS) ? "BRS" : "");

rx_func(dev, &frame, data->rx_cbs[alloc].arg);
}
}

/* Pop 1 (= RXFSYSPOP + 1) received RxFIFO message queue */
config->base_rx_fifo_ctrl->RXFSYSPOP = 0;
#else
} else if (eventType == CANEXCEL_EVENT_RX_COMPLETE) {
alloc = RX_MBIDX_TO_ALLOC_IDX(buffidx);
rx_func = data->rx_cbs[alloc].function;
Expand All @@ -805,12 +928,12 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev,

rx_func(dev, &frame, data->rx_cbs[alloc].arg);

status = Canexcel_Ip_ReceiveFD(config->instance, buffidx,
&data->rx_msg[alloc], FALSE);
if (status != CANEXCEL_STATUS_SUCCESS) {
if (Canexcel_Ip_ReceiveFD(config->instance, buffidx,
&data->rx_msg[alloc], FALSE) != CANEXCEL_STATUS_SUCCESS) {
LOG_ERR("MB %d is not ready for receiving next message", buffidx);
}
}
#endif
}
}

Expand Down Expand Up @@ -925,6 +1048,13 @@ static int can_nxp_s32_init(const struct device *dev)
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_ERR, TRUE);
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_BUSOFF, TRUE);
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_PASIVE_ERR, TRUE);
#ifdef CONFIG_CAN_NXP_S32_RX_FIFO
CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RXFIFO_OVER, TRUE);

/* Configure number of ID acceptance filters*/
config->base_rx_fifo->AFCFG =
CANXL_RXFIFO_AFCFG_ACPTID(CONFIG_CAN_NXP_S32_MAX_RX - 1);
#endif

config->irq_config_func();

Expand Down Expand Up @@ -1063,30 +1193,57 @@ static const struct can_driver_api can_nxp_s32_driver_api = {
CAN_NXP_S32_ERR_CALLBACK(n) \
CAN_NXP_S32_IRQ_CONFIG(n) \
PINCTRL_DT_INST_DEFINE(n); \
\
__nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \
__nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \
IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(__nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(__nocache Canexcel_RxFdMsg rx_fifo_##n[CAN_NXP_S32_RX_FIFO_DEPTH]; \
static Canexcel_Ip_RxFifoFilterID_ADDR \
rx_fifo_filter##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \
Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \
.rx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_RX, \
.rx_mbdesc = (uint8)IS_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO) ? \
0 : CONFIG_CAN_NXP_S32_MAX_RX, \
.tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \
.CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \
.fd_enable = (boolean)CAN_NXP_S32_FD_MODE, \
.bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \
.ctrlOptions = (uint32)CAN_NXP_S32_CTRL_OPTIONS, \
.Callback = nxp_s32_can_##n##_ctrl_callback, \
.ErrorCallback = nxp_s32_can_##n##_err_callback \
.ErrorCallback = nxp_s32_can_##n##_err_callback, \
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(.is_rx_fifo_needed = (boolean)TRUE, \
.pRxFifoConfig = { \
.Rx_Fifo_Depth = CAN_NXP_S32_RX_FIFO_DEPTH, \
.Rx_Fifo_Watermark = CAN_NXP_S32_RX_FIFO_WATERMARK, \
.Rx_Fifo_Msg_Size = CAN_NXP_S32_DATA_LENGTH, \
.Rx_Fifo_KeepLast = (boolean)FALSE, \
.isPolling = (boolean)FALSE, \
.MsgBuffersPtr = (uint32 *)rx_fifo_##n, \
},)) \
}; \
__nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \
__nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \
__nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX]; \
static struct can_nxp_s32_data can_nxp_s32_data_##n = { \
.can_state = (Canexcel_Ip_StateType *)&can_nxp_s32_state##n, \
.tx_msg = tx_msg##n, \
.rx_msg = rx_msg_##n, \
IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(.rx_msg = rx_msg_##n,)) \
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(.rx_fifo = rx_fifo_##n, \
.rx_fifo_filter = \
(Canexcel_Ip_RxFifoFilterID_ADDR *)&rx_fifo_filter##n,))\
}; \
static struct can_nxp_s32_config can_nxp_s32_config_##n = { \
.base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \
.base_grp_ctrl = (CANXL_GRP_CONTROL_Type *) \
DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \
.base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \
DT_INST_REG_ADDR_BY_NAME(n, dsc_ctrl), \
IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \
(.base_rx_fifo = (CANXL_RXFIFO_Type *) \
DT_INST_REG_ADDR_BY_NAME(n, rx_fifo), \
.base_rx_fifo_ctrl = (CANXL_RXFIFO_CONTROL_Type *) \
DT_INST_REG_ADDR_BY_NAME(n, rx_fifo_ctrl),)) \
.instance = CAN_NXP_S32_HW_INSTANCE(n), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.clock_subsys = (clock_control_subsys_t) \
Expand Down

0 comments on commit 9eb0a55

Please sign in to comment.