This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 04fc5e314da0e5d0039e721ccf1127ba7ee3f92e Author: Michal Lenc <michall...@seznam.cz> AuthorDate: Thu Feb 25 23:30:45 2021 +0100 arch/arm/src/imxrt: updated flexcan driver to support classical and FD frames at once Signed-off-by: Michal Lenc <michall...@seznam.cz> --- arch/arm/src/imxrt/Kconfig | 24 +- arch/arm/src/imxrt/hardware/imxrt_flexcan.h | 60 ++-- arch/arm/src/imxrt/imxrt_flexcan.c | 410 ++++++++++++++++------------ 3 files changed, 279 insertions(+), 215 deletions(-) diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 4783121..af12180 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -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 diff --git a/arch/arm/src/imxrt/hardware/imxrt_flexcan.h b/arch/arm/src/imxrt/hardware/imxrt_flexcan.h index f02a31f..1530587 100644 --- a/arch/arm/src/imxrt/hardware/imxrt_flexcan.h +++ b/arch/arm/src/imxrt/hardware/imxrt_flexcan.h @@ -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. */ diff --git a/arch/arm/src/imxrt/imxrt_flexcan.c b/arch/arm/src/imxrt/imxrt_flexcan.c index 6b2f978..68d1788 100644 --- a/arch/arm/src/imxrt/imxrt_flexcan.c +++ b/arch/arm/src/imxrt/imxrt_flexcan.c @@ -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 (ret == OK && imxrt_bitratetotimeseg(&data_timing, 10, 1)) - { - ret = OK; - } - else - { - ret = -EINVAL; - } -#endif + 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; + } + } 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 */ + if (!priv->canfd_capable) + { + 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); + } - regval = getreg32(priv->base + IMXRT_CAN_MCR_OFFSET); - regval |= CAN_MCR_FDEN; - putreg32(regval, priv->base + IMXRT_CAN_MCR_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 + */ - 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 + struct mb_s *buffer = flexcan_get_mb(priv, RXMBCOUNT); + buffer->cs.code = 0x3; - for (i = TXMBCOUNT; i < TOTALMBCOUNT; i++) + for (i = RXMBCOUNT + 1; i < TOTALMBCOUNT; i++) { - priv->rx[i].id.w = 0x0; + 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().