arch/arm/src/imxrt: updated flexcan driver to support classical and FD frames at once

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2021-02-25 23:30:45 +01:00 committed by Xiang Xiao
parent 3b219fb2da
commit 04fc5e314d
3 changed files with 281 additions and 217 deletions

View file

@ -450,6 +450,26 @@ config IMXRT_FLEXCAN3
select NET_CAN_HAVE_TX_DEADLINE
select NET_CAN_HAVE_CANFD
if IMXRT_FLEXCAN1 || IMXRT_FLEXCAN2 || IMXRT_FLEXCAN3
config IMXRT_FLEXCAN_TXMB
int "Number of TX message buffers"
default 3
---help---
This defines number of TX messages buffers. Please note that
maximum number of all message buffers is 13 (one MB has to
be reserved for chip errata ERR005829).
config IMXRT_FLEXCAN_RXMB
int "Number of RX message buffers"
default 10
---help---
This defines number of RX messages buffers. Please note that
maximum number of all message buffers is 13 (one MB has to
be reserved for chip errata ERR005829).
endif
endmenu # FLEXCAN Peripherals
menu "FLEXCAN1 Configuration"
@ -457,12 +477,10 @@ menu "FLEXCAN1 Configuration"
config FLEXCAN1_BITRATE
int "CAN bitrate"
depends on !NET_CAN_CANFD
default 1000000
config FLEXCAN1_SAMPLEP
int "CAN sample point"
depends on !NET_CAN_CANFD
default 80
endmenu # IMXRT_FLEXCAN1
@ -472,12 +490,10 @@ menu "FLEXCAN2 Configuration"
config FLEXCAN2_BITRATE
int "CAN bitrate"
depends on !NET_CAN_CANFD
default 1000000
config FLEXCAN2_SAMPLEP
int "CAN sample point"
depends on !NET_CAN_CANFD
default 80
endmenu # IMXRT_FLEXCAN2

View file

@ -122,11 +122,9 @@
#define IMXRT_CAN_RXIMR62_OFFSET 0x0978 /* R62 Individual Mask Registers */
#define IMXRT_CAN_RXIMR63_OFFSET 0x097c /* R63 Individual Mask Registers */
#ifdef CONFIG_IMXRT_FLEXCAN3
#define IMXRT_CAN_FDCTRL_OFFSET 0x0c00 /* CAN FD Control Register */
#define IMXRT_CAN_FDCBT_OFFSET 0x0c04 /* CAN FD Bit Timing Register */
#define IMXRT_CAN_FDCRC_OFFSET 0x0c08 /* CAN FD CRC register */
#endif /* CONFIG_IMXRT_FLEXCAN3 */
/* Register Bit Definitions *************************************************/
@ -143,20 +141,17 @@
# define CAN_MCR_IDAM_FMTD (3 << CAN_MCR_IDAM_SHIFT) /* Format D: All frames rejected */
/* Bit 10: Reserved */
#ifdef CONFIG_IMXRT_FLEXCAN3
# define CAN_MCR_FDEN (1 << 11) /* Bit 11: CAN FD Operation Enable */
#endif /* Bit 11: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_FDEN (1 << 11) /* Bit 11: CAN FD Operation Enable */
/* Bit 11: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_AEN (1 << 12) /* Bit 12: Abort Enable */
#define CAN_MCR_LPRIOEN (1 << 13) /* Bit 13: Local Priority Enable */
/* Bit 14: Reserved */
#ifdef CONFIG_IMXRT_FLEXCAN3
# define CAN_MCR_DMA (1 << 15) /* Bit 15: DMA Enable */
#endif /* Bit 15: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_DMA (1 << 15) /* Bit 15: DMA Enable */
/* Bit 15: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_IRMQ (1 << 16) /* Bit 16: Individual Rx Masking and Queue Enable */
#define CAN_MCR_SRXDIS (1 << 17) /* Bit 17: Self Reception Disable */
#ifdef CONFIG_IMXRT_FLEXCAN3
# define CAN_MCR_DOZE (1 << 18) /* Bit 18: Doze Mode Enable */
#endif /* Bit 18: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_DOZE (1 << 18) /* Bit 18: Doze Mode Enable */
/* Bit 18: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_MCR_WAKSRC (1 << 19) /* Bit 19: Wake Up Source */
#define CAN_MCR_LPMACK (1 << 20) /* Bit 20: Low Power Mode Acknowledge */
#define CAN_MCR_WRNEN (1 << 21) /* Bit 21: Warning Interrupt Enable */
@ -185,9 +180,8 @@
#define CAN_CTRL1_RWRNMSK (1 << 10) /* Bit 10: Rx Warning Interrupt Mask */
#define CAN_CTRL1_TWRNMSK (1 << 11) /* Bit 11: Tx Warning Interrupt Mask */
#define CAN_CTRL1_LPB (1 << 12) /* Bit 12: Loop Back Mode */
#ifdef CONFIG_IMXRT_FLEXCAN3
# define CAN_CTRL1_CLKSRC (1 << 13) /* Bit 13: CAN Engine Clock Source */
#endif /* Bit 13: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_CTRL1_CLKSRC (1 << 13) /* Bit 13: CAN Engine Clock Source */
/* Bit 13: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_CTRL1_ERRMSK (1 << 14) /* Bit 14: Error Mask */
#define CAN_CTRL1_BOFFMSK (1 << 15) /* Bit 15: Bus Off Mask */
#define CAN_CTRL1_PSEG2_SHIFT (16) /* Bits 16-18: Phase Segment 2 */
@ -227,12 +221,11 @@
#define CAN_ECR_TXERRCNT_MASK (0xff << CAN_ECR_TXERRCNT_SHIFT)
#define CAN_ECR_RXERRCNT_SHIFT (8) /* Bits 8-15: Receive Error Counter */
#define CAN_ECR_RXERRCNT_MASK (0xff << CAN_ECR_RXERRCNT_SHIFT)
#ifdef CONFIG_IMXRT_FLEXCAN3
# define CAN_ECR_TXERRCNTFAST_SHIFT (16) /* Bits 16-23: Transmit Error Counter for fast bits */
# define CAN_ECR_TXERRCNTFAST_MASK (0xff << CAN_ECR_TXERRCNTFAST_SHIFT)
# define CAN_ECR_RXERRCNTFAST_SHIFT (24) /* Bits 24-31: Receive Error Counter for fast bits */
# define CAN_ECR_RXERRCNTFAST_MASK (0xff << CAN_ECR_RXERRCNTFAST_SHIFT)
#endif /* Bits 16-31: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_ECR_TXERRCNTFAST_SHIFT (16) /* Bits 16-23: Transmit Error Counter for fast bits */
#define CAN_ECR_TXERRCNTFAST_MASK (0xff << CAN_ECR_TXERRCNTFAST_SHIFT)
#define CAN_ECR_RXERRCNTFAST_SHIFT (24) /* Bits 24-31: Receive Error Counter for fast bits */
#define CAN_ECR_RXERRCNTFAST_MASK (0xff << CAN_ECR_RXERRCNTFAST_SHIFT)
/* Bits 16-31: Reserved for FlexCAN1 and FlexCAN2 */
/* Error and Status 1 Register */
@ -261,7 +254,6 @@
#define CAN_ESR1_RWRNINT (1 << 16) /* Bit 16: Rx Warning Interrupt Flag */
#define CAN_ESR1_TWRNINT (1 << 17) /* Bit 17: Tx Warning Interrupt Flag */
#define CAN_ESR1_SYNCH (1 << 18) /* Bit 18: CAN Synchronization Status */
#ifdef CONFIG_IMXRT_FLEXCAN3
#define CAN_ESR1_BOFFDONEINT (1 << 19) /* Bit 19: Bus Off Done Interrupt */
#define CAN_ESR1_ERRINTFAST (1 << 20) /* Bit 20: Error Iterrupt for Errors Detected in Data Phase of CAN FD frames */
#define CAN_ESR1_ERROVR (1 << 21) /* Bit 21: Error Overrun */
@ -272,7 +264,7 @@
/* Bit 29: Reserved */
#define CAN_ESR1_BIT0ERRFAST (1 << 30) /* Bit 30: Bit0 Error in the Data Phase of CAN FD frames */
#define CAN_ESR1_BIT1ERRFAST (1 << 31) /* Bit 31: Bit1 Error in the Data Phase of CAN FD frames */
#endif /* Bits 19-31: Reserved for FlexCAN1 and FlexCAN2 */
/* Bits 19-31: Reserved for FlexCAN1 and FlexCAN2 */
/* Interrupt Masks 2 Register */
@ -292,14 +284,13 @@
/* Control 2 Register */
#ifdef CONFIG_IMXRT_FLEXCAN3
/* Bits 0-10: Reserved */
# define CAN_CTRL2_EDFLTDIS (1 << 11) /* Bit 11: Edge Filter Disable */
# define CAN_CTRL2_ISOCANFDEN (1 << 12) /* Bit 12: ISO CAN FD Enable */
#define CAN_CTRL2_EDFLTDIS (1 << 11) /* Bit 11: Edge Filter Disable */
#define CAN_CTRL2_ISOCANFDEN (1 << 12) /* Bit 12: ISO CAN FD Enable */
/* Bit 13: Reserved */
# define CAN_CTRL2_PREXCEN (1 << 14) /* Bit 14: Protocol Exception Enable */
# define CAN_CTRL2_TIMERSRC (1 << 15) /* Bit 15: Timer Source */
#endif /* Bits 0-15: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_CTRL2_PREXCEN (1 << 14) /* Bit 14: Protocol Exception Enable */
#define CAN_CTRL2_TIMERSRC (1 << 15) /* Bit 15: Timer Source */
/* Bits 0-15: Reserved for FlexCAN1 and FlexCAN2 */
#define CAN_CTRL2_EACEN (1 << 16) /* Bit 16: Entire Frame Arbitration Field Comparison Enable (Rx) */
#define CAN_CTRL2_RRS (1 << 17) /* Bit 17: Remote Request Storing */
#define CAN_CTRL2_MRP (1 << 18) /* Bit 18: Mailboxes Reception Priority */
@ -323,14 +314,11 @@
# define CAN_CTRL2_RFFN_112MB (13 << CAN_CTRL2_RFFN_SHIFT)
# define CAN_CTRL2_RFFN_120MB (14 << CAN_CTRL2_RFFN_SHIFT)
# define CAN_CTRL2_RFFN_128MB (15 << CAN_CTRL2_RFFN_SHIFT)
#ifdef CONFIG_IMXRT_FLEXCAN3
/* Bits 28-29: Reserved */
# define CAN_CTRL2_BOFFDONEMSK (1 << 30) /* Bit 30: Bus Off Done Interrupt Mask */
# define CAN_CTRL2_ERRMSKFAST (1 << 31) /* Bit 31: Error Interrupt for Errors Detected in the Data Phase of CAN FD frames */
#else
# define CAN_CTRL2_WRMFRZ (1 << 28) /* Bit 28: Enable unrestricted write access to FlexCAN memory in Freeze mode */
#define CAN_CTRL2_BOFFDONEMSK (1 << 30) /* Bit 30: Bus Off Done Interrupt Mask */
#define CAN_CTRL2_ERRMSKFAST (1 << 31) /* Bit 31: Error Interrupt for Errors Detected in the Data Phase of CAN FD frames */
#define CAN_CTRL2_WRMFRZ (1 << 28) /* Bit 28: Enable unrestricted write access to FlexCAN memory in Freeze mode */
/* Bits 29-31: Reserved */
#endif
/* Error and Status 2 Register */
@ -365,8 +353,6 @@
#define CAN_RXIMR(n) (1 << (n)) /* Bit n: Individual Mask Bits */
#ifdef CONFIG_IMXRT_FLEXCAN3
/* CAN Bit Timing register */
#define CAN_CBT_EPSEG2_SHIFT (0) /* Bits 0-4: Extended Phase Segment 2 */
@ -441,8 +427,6 @@
#define CAN_FDCRC_FD_MBCRC(x) (((uint32_t)(((uint32_t)(x)) << CAN_FDCRC_FD_MBCRC_SHIFT)) & CAN_FDCRC_FD_MBCRC_MASK)
/* Bit 31: Reserved */
#endif /* CONFIG_IMXRT_FLEXCAN3 */
/* CAN MB TX codes */
#define CAN_TXMB_INACTIVE 0x8 /* MB is not active. */
#define CAN_TXMB_ABORT 0x9 /* MB is aborted. */

View file

@ -39,6 +39,7 @@
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/signal.h>
#include <nuttx/spinlock.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/can.h>
@ -78,12 +79,12 @@
#define FLAGEFF (1 << 31) /* Extended frame format */
#define FLAGRTR (1 << 30) /* Remote transmission request */
#define RXMBCOUNT 10
#define TXMBCOUNT 4
#define RXMBCOUNT CONFIG_IMXRT_FLEXCAN_RXMB
#define TXMBCOUNT (CONFIG_IMXRT_FLEXCAN_TXMB + 1)
#define TOTALMBCOUNT RXMBCOUNT + TXMBCOUNT
#define IFLAG1_RX ((1 << RXMBCOUNT)-1)
#define IFLAG1_TX (((1 << TXMBCOUNT)-1) << RXMBCOUNT)
#define IFLAG1_TX (((1 << TXMBCOUNT)-2) << RXMBCOUNT)
#define CAN_FIFO_NE (1 << 5)
#define CAN_FIFO_OV (1 << 6)
@ -125,11 +126,23 @@
#define TX_TIMEOUT_WQ
#endif
#if (CONFIG_IMXRT_FLEXCAN_RXMB + CONFIG_IMXRT_FLEXCAN_TXMB) > 13
# error Only 13 MB are allowed to be used
#endif
/* Interrupt flags for RX fifo */
#define IFLAG1_RXFIFO (CAN_FIFO_NE | CAN_FIFO_WARN | CAN_FIFO_OV)
static int peak_tx_mailbox_index_ = 0;
static uint8_t mb_address[] =
{
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c,
0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a,
0x10, 0x19, 0x22, 0x2b, 0x34, 0x3d, 0x46,
0x50, 0x59, 0x62, 0x6b, 0x74, 0x7d, 0x86
};
/****************************************************************************
* Private Types
****************************************************************************/
@ -185,11 +198,7 @@ struct mb_s
{
union cs_e cs;
union id_e id;
#ifdef CONFIG_NET_CAN_CANFD
union data_e data[16];
#else
union data_e data[2];
#endif
union data_e data[];
};
#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
@ -260,30 +269,24 @@ struct imxrt_driver_s
{
uint32_t base; /* FLEXCAN base address */
bool bifup; /* true:ifup false:ifdown */
bool canfd_capable;
int mb_address_offset;
#ifdef TX_TIMEOUT_WQ
WDOG_ID txtimeout[TXMBCOUNT]; /* TX timeout timer */
#endif
struct work_s irqwork; /* For deferring interrupt work to the wq */
struct work_s pollwork; /* For deferring poll work to the work wq */
#ifdef CONFIG_NET_CAN_CANFD
struct canfd_frame *txdesc; /* A pointer to the list of TX descriptor */
struct canfd_frame *rxdesc; /* A pointer to the list of RX descriptors */
#else
struct can_frame *txdesc; /* A pointer to the list of TX descriptor */
struct can_frame *rxdesc; /* A pointer to the list of RX descriptors */
#endif
struct work_s irqwork; /* For deferring interrupt work to the wq */
struct work_s pollwork; /* For deferring poll work to the work wq */
struct canfd_frame *txdesc_fd; /* A pointer to the list of TX descriptor for FD frames */
struct canfd_frame *rxdesc_fd; /* A pointer to the list of RX descriptors for FD frames */
struct can_frame *txdesc; /* A pointer to the list of TX descriptor */
struct can_frame *rxdesc; /* A pointer to the list of RX descriptors */
/* This holds the information visible to the NuttX network */
struct net_driver_s dev; /* Interface understood by the network */
struct mb_s *rx;
struct mb_s *tx;
struct flexcan_timeseg arbi_timing; /* Timing for arbitration phase */
#ifdef CONFIG_NET_CAN_CANFD
struct flexcan_timeseg data_timing; /* Timing for data phase */
#endif
const struct flexcan_config_s *config;
@ -476,6 +479,8 @@ static uint32_t imxrt_waitmcr_change(uint32_t base,
static uint32_t imxrt_waitesr2_change(uint32_t base,
uint32_t mask,
uint32_t target_state);
static struct mb_s *flexcan_get_mb(FAR struct imxrt_driver_s *priv,
uint32_t mbi);
/* Interrupt handling */
@ -532,11 +537,13 @@ static void imxrt_reset(struct imxrt_driver_s *priv);
static bool imxrt_txringfull(FAR struct imxrt_driver_s *priv)
{
uint32_t mbi = 0;
uint32_t mbi = RXMBCOUNT;
struct mb_s *mb;
while (mbi < TXMBCOUNT)
{
if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
mb = flexcan_get_mb(priv, mbi);
if (mb->cs.code != CAN_TXMB_DATAORREMOTE)
{
return 0;
}
@ -588,14 +595,14 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv)
{
mbi = ((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) &
CAN_ESR2_LPTM_MASK) >> CAN_ESR2_LPTM_SHIFT);
mbi -= RXMBCOUNT;
}
mb_bit = 1 << (RXMBCOUNT + mbi);
mb_bit = 1 << mbi;
while (mbi < TXMBCOUNT)
while (mbi < TOTALMBCOUNT)
{
if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
struct mb_s *mb = flexcan_get_mb(priv, mbi);
if (mb->cs.code != CAN_TXMB_DATAORREMOTE)
{
putreg32(mb_bit, priv->base + IMXRT_CAN_IFLAG1_OFFSET);
break;
@ -605,7 +612,7 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv)
mbi++;
}
if (mbi == TXMBCOUNT)
if (mbi == TOTALMBCOUNT)
{
nwarn("No TX MB available mbi %" PRIi32 "\r\n", mbi);
NETDEV_TXERRORS(&priv->dev);
@ -655,7 +662,7 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv)
union cs_e cs;
cs.code = CAN_TXMB_DATAORREMOTE;
struct mb_s *mb = &priv->tx[mbi];
struct mb_s *mb = flexcan_get_mb(priv, mbi);
mb->cs.code = CAN_TXMB_INACTIVE;
if (priv->dev.d_len == sizeof(struct can_frame))
@ -710,6 +717,16 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv)
mb->cs = cs; /* Go. */
/* Errata ER005829 step 8: Write twice into the first TX MB
* Errata mentions writng 0x8 value, but this one couses
* the ESR2_LPTM register to choose the reserved MB for
* transmiting the package, hence we write 0x3
*/
struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT);
buffer->cs.code = 0x3;
buffer->cs.code = 0x3;
regval = getreg32(priv->base + IMXRT_CAN_IMASK1_OFFSET);
regval |= mb_bit;
putreg32(regval, priv->base + IMXRT_CAN_IMASK1_OFFSET);
@ -779,15 +796,12 @@ static int imxrt_txpoll(struct net_driver_s *dev)
* not, return a non-zero value to terminate the poll.
*/
if ((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) &
if (!((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) &
(CAN_ESR2_IMB | CAN_ESR2_VPS)) ==
(CAN_ESR2_IMB | CAN_ESR2_VPS))
{
if (!imxrt_txringfull(priv))
(CAN_ESR2_IMB | CAN_ESR2_VPS)) || (imxrt_txringfull(priv)))
{
return -EBUSY;
}
}
}
}
@ -818,23 +832,40 @@ static int imxrt_txpoll(struct net_driver_s *dev)
static void imxrt_receive(FAR struct imxrt_driver_s *priv,
uint32_t flags)
{
uint32_t mb_index;
uint32_t mbi;
uint32_t mbj;
struct mb_s *rf;
#ifdef CONFIG_NET_CAN_CANFD
# ifdef CONFIG_NET_CAN_CANFD
uint32_t *frame_data_word;
uint32_t i;
#endif
# endif
uint32_t f;
while ((mb_index = arm_lsb(flags)) != 32)
while ((f = flags) != 0)
{
rf = &priv->rx[mb_index];
mbj = mbi = arm_lsb(f);
rf = flexcan_get_mb(priv, mbi);
uint32_t t = rf->cs.time_stamp;
while ((f &= ~(1 << mbj)) != 0)
{
mbj = arm_lsb(f);
struct mb_s *rf_next = flexcan_get_mb(priv, mbj);
uint16_t t_next = rf_next->cs.time_stamp;
if ((int16_t)(t - t_next) > 0)
{
t = t_next;
mbi = mbj;
}
}
rf = flexcan_get_mb(priv, mbi);
/* Read the frame contents */
#ifdef CONFIG_NET_CAN_CANFD
if (rf->cs.edl) /* CAN FD frame */
{
struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc;
struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc_fd;
if (rf->cs.ide)
{
@ -862,7 +893,7 @@ static void imxrt_receive(FAR struct imxrt_driver_s *priv,
/* Clear MB interrupt flag */
putreg32(1 << mb_index,
putreg32(1 << mbi,
priv->base + IMXRT_CAN_IFLAG1_OFFSET);
/* Copy the buffer pointer to priv->dev.. Set amount of data
@ -899,7 +930,7 @@ static void imxrt_receive(FAR struct imxrt_driver_s *priv,
/* Clear MB interrupt flag */
putreg32(1 << mb_index,
putreg32(1 << mbi,
priv->base + IMXRT_CAN_IFLAG1_OFFSET);
/* Copy the buffer pointer to priv->dev.. Set amount of data
@ -923,9 +954,16 @@ static void imxrt_receive(FAR struct imxrt_driver_s *priv,
* queue is not full.
*/
priv->dev.d_buf = (uint8_t *)priv->txdesc;
if (priv->canfd_capable)
{
priv->dev.d_buf = (uint8_t *)priv->txdesc_fd;
}
else
{
priv->dev.d_buf = (uint8_t *)priv->txdesc;
}
flags &= ~(1 << mb_index);
flags &= ~(1 << mbi);
/* Reread interrupt flags and process them in this loop */
@ -1241,6 +1279,13 @@ static uint32_t imxrt_waitesr2_change(uint32_t base, uint32_t mask,
return false;
}
static struct mb_s *flexcan_get_mb(FAR struct imxrt_driver_s *priv,
uint32_t mbi)
{
return (struct mb_s *)(priv->base +
(mb_address[priv->mb_address_offset + mbi] << 3));
}
/****************************************************************************
* Function: imxrt_ifup
*
@ -1270,16 +1315,18 @@ static int imxrt_ifup(struct net_driver_s *dev)
}
priv->bifup = true;
#ifdef CONFIG_NET_CAN_CANFD
priv->txdesc = (struct canfd_frame *)&g_tx_pool;
priv->rxdesc = (struct canfd_frame *)&g_rx_pool;
#else
priv->txdesc = (struct can_frame *)&g_tx_pool;
priv->rxdesc = (struct can_frame *)&g_rx_pool;
#endif
priv->dev.d_buf = (uint8_t *)priv->txdesc;
if (priv->canfd_capable)
{
priv->txdesc_fd = (struct canfd_frame *)&g_tx_pool;
priv->rxdesc_fd = (struct canfd_frame *)&g_rx_pool;
priv->dev.d_buf = (uint8_t *)priv->txdesc_fd;
}
else
{
priv->dev.d_buf = (uint8_t *)priv->txdesc;
}
/* Set interrupts */
@ -1434,13 +1481,17 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd,
(struct can_ioctl_data_s *)((uintptr_t)arg);
req->arbi_bitrate = priv->arbi_timing.bitrate / 1000; /* kbit/s */
req->arbi_samplep = priv->arbi_timing.samplep;
#ifdef CONFIG_NET_CAN_CANFD
req->data_bitrate = priv->data_timing.bitrate / 1000; /* kbit/s */
req->data_samplep = priv->data_timing.samplep;
#else
req->data_bitrate = 0;
req->data_samplep = 0;
#endif
if (priv->canfd_capable)
{
req->data_bitrate = priv->data_timing.bitrate / 1000; /* kbit/s */
req->data_samplep = priv->data_timing.samplep;
}
else
{
req->data_bitrate = 0;
req->data_samplep = 0;
}
ret = OK;
}
break;
@ -1463,29 +1514,32 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd,
ret = -EINVAL;
}
#ifdef CONFIG_NET_CAN_CANFD
struct flexcan_timeseg data_timing;
data_timing.bitrate = req->data_bitrate * 1000;
data_timing.samplep = req->data_samplep;
if (priv->canfd_capable)
{
struct flexcan_timeseg data_timing;
data_timing.bitrate = req->data_bitrate * 1000;
data_timing.samplep = req->data_samplep;
if (ret == OK && imxrt_bitratetotimeseg(&data_timing, 10, 1))
{
ret = OK;
}
else
{
ret = -EINVAL;
}
#endif
if (ret == OK && imxrt_bitratetotimeseg(&data_timing, 10, 1))
{
ret = OK;
}
else
{
ret = -EINVAL;
}
}
if (ret == OK)
{
/* Reset CAN controller and start with new timings */
priv->arbi_timing = arbi_timing;
#ifdef CONFIG_NET_CAN_CANFD
priv->data_timing = data_timing;
#endif
if (priv->canfd_capable)
{
priv->data_timing = data_timing;
}
imxrt_ifup(dev);
}
}
@ -1546,69 +1600,82 @@ static int imxrt_initialize(struct imxrt_driver_s *priv)
return -1;
}
#ifndef CONFIG_NET_CAN_CANFD
regval = getreg32(priv->base + IMXRT_CAN_CTRL1_OFFSET);
regval &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_PROPSEG_MASK |
CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
CAN_CTRL1_RJW_MASK);
regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) | /* Phase buffer segment 1 */
CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) | /* Phase buffer segment 2 */
CAN_CTRL1_RJW(1); /* Resynchronization jump width */
putreg32(regval, priv->base + IMXRT_CAN_CTRL1_OFFSET);
#else
regval = getreg32(priv->base + IMXRT_CAN_CBT_OFFSET);
regval &= ~(CAN_CBT_EPRESDIV_MASK | CAN_CBT_EPROPSEG_MASK |
CAN_CBT_EPSEG1_MASK | CAN_CBT_EPSEG2_MASK |
CAN_CBT_ERJW_MASK);
regval |= CAN_CBT_BTF | /* Enable extended bit timing
* configurations for CAN-FD for setting up
* separately nominal and data phase */
CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) | /* Phase buffer segment 1 */
CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) | /* Phase buffer segment 2 */
CAN_CBT_ERJW(1); /* Resynchronization jump width */
putreg32(regval, priv->base + IMXRT_CAN_CBT_OFFSET);
/* Enable CAN FD feature */
regval = getreg32(priv->base + IMXRT_CAN_MCR_OFFSET);
regval |= CAN_MCR_FDEN;
putreg32(regval, priv->base + IMXRT_CAN_MCR_OFFSET);
regval = getreg32(priv->base + IMXRT_CAN_FDCBT_OFFSET);
regval &= ~(CAN_FDCBT_FPRESDIV_MASK | CAN_FDCBT_FPROPSEG_MASK |
CAN_FDCBT_FPSEG1_MASK | CAN_FDCBT_FPSEG2_MASK |
CAN_FDCBT_FRJW_MASK);
regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) | /* Prescaler divisor factor of 1 */
CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
* segment (only register that doesn't add 1) */
CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) | /* Phase buffer segment 1 */
CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) | /* Phase buffer segment 2 */
CAN_FDCBT_FRJW(priv->data_timing.pseg2); /* Resynchorinzation jump width same as PSEG2 */
putreg32(regval, priv->base + IMXRT_CAN_FDCBT_OFFSET);
/* Additional CAN-FD configurations */
regval = getreg32(priv->base + IMXRT_CAN_FDCTRL_OFFSET);
regval |= CAN_FDCTRL_FDRATE | /* Enable bit rate switch in data phase of frame */
CAN_FDCTRL_TDCEN | /* Enable transceiver delay compensation */
CAN_FDCTRL_TDCOFF(5) | /* Setup 5 cycles for data phase sampling delay */
CAN_FDCTRL_MSBSR0(3); /* Setup 64 bytes per message buffer (7 MB's) */
putreg32(regval, priv->base + IMXRT_CAN_FDCTRL_OFFSET);
regval = getreg32(priv->base + IMXRT_CAN_CTRL2_OFFSET);
regval |= CAN_CTRL2_ISOCANFDEN;
putreg32(regval, priv->base + IMXRT_CAN_CTRL2_OFFSET);
#endif
for (i = TXMBCOUNT; i < TOTALMBCOUNT; i++)
if (!priv->canfd_capable)
{
priv->rx[i].id.w = 0x0;
regval = getreg32(priv->base + IMXRT_CAN_CTRL1_OFFSET);
regval &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_PROPSEG_MASK |
CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
CAN_CTRL1_RJW_MASK);
regval |= CAN_CTRL1_PRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
CAN_CTRL1_PROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
CAN_CTRL1_PSEG1(priv->arbi_timing.pseg1) | /* Phase buffer segment 1 */
CAN_CTRL1_PSEG2(priv->arbi_timing.pseg2) | /* Phase buffer segment 2 */
CAN_CTRL1_RJW(1); /* Resynchronization jump width */
putreg32(regval, priv->base + IMXRT_CAN_CTRL1_OFFSET);
}
else
{
regval = getreg32(priv->base + IMXRT_CAN_CBT_OFFSET);
regval &= ~(CAN_CBT_EPRESDIV_MASK | CAN_CBT_EPROPSEG_MASK |
CAN_CBT_EPSEG1_MASK | CAN_CBT_EPSEG2_MASK |
CAN_CBT_ERJW_MASK);
regval |= CAN_CBT_BTF | /* Enable extended bit timing
* configurations for CAN-FD for setting up
* separately nominal and data phase */
CAN_CBT_EPRESDIV(priv->arbi_timing.presdiv) | /* Prescaler divisor factor */
CAN_CBT_EPROPSEG(priv->arbi_timing.propseg) | /* Propagation segment */
CAN_CBT_EPSEG1(priv->arbi_timing.pseg1) | /* Phase buffer segment 1 */
CAN_CBT_EPSEG2(priv->arbi_timing.pseg2) | /* Phase buffer segment 2 */
CAN_CBT_ERJW(1); /* Resynchronization jump width */
putreg32(regval, priv->base + IMXRT_CAN_CBT_OFFSET);
/* Enable CAN FD feature */
regval = getreg32(priv->base + IMXRT_CAN_MCR_OFFSET);
regval |= CAN_MCR_FDEN;
putreg32(regval, priv->base + IMXRT_CAN_MCR_OFFSET);
regval = getreg32(priv->base + IMXRT_CAN_FDCBT_OFFSET);
regval &= ~(CAN_FDCBT_FPRESDIV_MASK | CAN_FDCBT_FPROPSEG_MASK |
CAN_FDCBT_FPSEG1_MASK | CAN_FDCBT_FPSEG2_MASK |
CAN_FDCBT_FRJW_MASK);
regval |= CAN_FDCBT_FPRESDIV(priv->data_timing.presdiv) | /* Prescaler divisor factor of 1 */
CAN_FDCBT_FPROPSEG(priv->data_timing.propseg) | /* Propagation
* segment (only register that doesn't add 1) */
CAN_FDCBT_FPSEG1(priv->data_timing.pseg1) | /* Phase buffer segment 1 */
CAN_FDCBT_FPSEG2(priv->data_timing.pseg2) | /* Phase buffer segment 2 */
CAN_FDCBT_FRJW(priv->data_timing.pseg2); /* Resynchorinzation jump width same as PSEG2 */
putreg32(regval, priv->base + IMXRT_CAN_FDCBT_OFFSET);
/* Additional CAN-FD configurations */
regval = getreg32(priv->base + IMXRT_CAN_FDCTRL_OFFSET);
regval |= CAN_FDCTRL_FDRATE | /* Enable bit rate switch in data phase of frame */
CAN_FDCTRL_TDCEN | /* Enable transceiver delay compensation */
CAN_FDCTRL_TDCOFF(5) | /* Setup 5 cycles for data phase sampling delay */
CAN_FDCTRL_MSBSR0(3) | /* Setup 64 bytes per MB 0-6 */
CAN_FDCTRL_MSBSR1(3); /* Setup 64 bytes per MB 7-13 */
putreg32(regval, priv->base + IMXRT_CAN_FDCTRL_OFFSET);
regval = getreg32(priv->base + IMXRT_CAN_CTRL2_OFFSET);
regval |= CAN_CTRL2_ISOCANFDEN;
putreg32(regval, priv->base + IMXRT_CAN_CTRL2_OFFSET);
}
/* Errata ER005829 step 7: Reserve first TX MB
* Errata mentions writng 0x8 value, but this one couses
* the ESR2_LPTM register to choose the reserved MB for
* transmiting the package, hence we write 0x3
*/
struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT);
buffer->cs.code = 0x3;
for (i = RXMBCOUNT + 1; i < TOTALMBCOUNT; i++)
{
struct mb_s *rx = flexcan_get_mb(priv, i);
rx->id.w = 0x0;
/* FIXME sometimes we get a hard fault here */
}
@ -1622,14 +1689,15 @@ static int imxrt_initialize(struct imxrt_driver_s *priv)
for (i = 0; i < RXMBCOUNT; i++)
{
ninfo("Set MB%" PRIi32 " to receive %p\r\n", i, &priv->rx[i]);
priv->rx[i].cs.edl = 0x1;
priv->rx[i].cs.brs = 0x1;
priv->rx[i].cs.esi = 0x0;
priv->rx[i].cs.code = 4;
priv->rx[i].cs.srr = 0x0;
priv->rx[i].cs.ide = 0x1;
priv->rx[i].cs.rtr = 0x0;
struct mb_s *rx = flexcan_get_mb(priv, i);
ninfo("Set MB%" PRIi32 " to receive %p\r\n", i, rx);
rx->cs.edl = 0x1;
rx->cs.brs = 0x1;
rx->cs.esi = 0x0;
rx->cs.code = 4;
rx->cs.srr = 0x0;
rx->cs.ide = 0x1;
rx->cs.rtr = 0x0;
}
putreg32(IFLAG1_RX, priv->base + IMXRT_CAN_IFLAG1_OFFSET);
@ -1686,12 +1754,13 @@ static void imxrt_reset(struct imxrt_driver_s *priv)
for (i = 0; i < TOTALMBCOUNT; i++)
{
ninfo("MB %" PRIi32 " %p\r\n", i, &priv->rx[i]);
ninfo("MB %" PRIi32 " %p\r\n", i, &priv->rx[i].id.w);
priv->rx[i].cs.cs = 0x0;
priv->rx[i].id.w = 0x0;
priv->rx[i].data[0].w00 = 0x0;
priv->rx[i].data[1].w00 = 0x0;
struct mb_s *rx = flexcan_get_mb(priv, i);
ninfo("MB %" PRIi32 " %p\r\n", i, rx);
ninfo("MB %" PRIi32 " %p\r\n", i, &rx->id.w);
rx->cs.cs = 0x0;
rx->id.w = 0x0;
rx->data[0].w00 = 0x0;
rx->data[1].w00 = 0x0;
}
regval = getreg32(priv->base + IMXRT_CAN_MCR_OFFSET);
@ -1756,18 +1825,13 @@ int imxrt_caninitialize(int intf)
memset(priv, 0, sizeof(struct imxrt_driver_s));
priv->base = IMXRT_CAN1_BASE;
priv->config = &imxrt_flexcan1_config;
priv->canfd_capable = false;
priv->mb_address_offset = 0;
/* Default bitrate configuration */
# ifdef CONFIG_NET_CAN_CANFD
priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_ARBI_BITRATE;
priv->arbi_timing.samplep = CONFIG_FLEXCAN1_ARBI_SAMPLEP;
priv->data_timing.bitrate = CONFIG_FLEXCAN1_DATA_BITRATE;
priv->data_timing.samplep = CONFIG_FLEXCAN1_DATA_SAMPLEP;
# else
priv->arbi_timing.bitrate = CONFIG_FLEXCAN1_BITRATE;
priv->arbi_timing.samplep = CONFIG_FLEXCAN1_SAMPLEP;
# endif
break;
#endif
@ -1779,18 +1843,13 @@ int imxrt_caninitialize(int intf)
memset(priv, 0, sizeof(struct imxrt_driver_s));
priv->base = IMXRT_CAN2_BASE;
priv->config = &imxrt_flexcan2_config;
priv->canfd_capable = false;
priv->mb_address_offset = 0;
/* Default bitrate configuration */
# ifdef CONFIG_NET_CAN_CANFD
priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_ARBI_BITRATE;
priv->arbi_timing.samplep = CONFIG_FLEXCAN2_ARBI_SAMPLEP;
priv->data_timing.bitrate = CONFIG_FLEXCAN2_DATA_BITRATE;
priv->data_timing.samplep = CONFIG_FLEXCAN2_DATA_SAMPLEP;
# else
priv->arbi_timing.bitrate = CONFIG_FLEXCAN2_BITRATE;
priv->arbi_timing.samplep = CONFIG_FLEXCAN2_SAMPLEP;
# endif
break;
#endif
@ -1802,6 +1861,13 @@ int imxrt_caninitialize(int intf)
memset(priv, 0, sizeof(struct imxrt_driver_s));
priv->base = IMXRT_CAN3_BASE;
priv->config = &imxrt_flexcan3_config;
# ifdef CONFIG_NET_CAN_CANFD
priv->canfd_capable = true;
priv->mb_address_offset = 14;
# else
priv->canfd_capable = false;
priv->mb_address_offset = 0;
# endif
/* Default bitrate configuration */
@ -1828,14 +1894,15 @@ int imxrt_caninitialize(int intf)
return -1;
}
#ifdef CONFIG_NET_CAN_CANFD
if (!imxrt_bitratetotimeseg(&priv->data_timing, 1, 1))
if (priv->canfd_capable)
{
nerr("ERROR: Invalid CAN data phase timings please try another "
"sample point or refer to the reference manual\n");
return -1;
if (!imxrt_bitratetotimeseg(&priv->data_timing, 1, 1))
{
nerr("ERROR: Invalid CAN data phase timings please try another "
"sample point or refer to the reference manual\n");
return -1;
}
}
#endif
imxrt_config_gpio(priv->config->tx_pin);
imxrt_config_gpio(priv->config->rx_pin);
@ -1865,9 +1932,6 @@ int imxrt_caninitialize(int intf)
}
#endif
priv->rx = (struct mb_s *)(priv->base + IMXRT_CAN_MB_OFFSET);
priv->tx = (struct mb_s *)(priv->base + IMXRT_CAN_MB_OFFSET +
(sizeof(struct mb_s) * RXMBCOUNT));
/* Put the interface in the down state. This usually amounts to resetting
* the device and/or calling imxrt_ifdown().