diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 7bea8d670e40f..3680391c4052e 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -1043,9 +1043,12 @@ endmenu # IMX9_ENET config IMX9_FLEXCAN bool default n - select NET_CAN - select NET_CAN_HAVE_CANFD + select ARCH_HAVE_CAN_ERRORS select ARCH_HAVE_NETDEV_STATISTICS + select CAN + select NET_CAN + select NET_CAN_HAVE_CANFD + select NET_CAN_HAVE_TX_DEADLINE menu "FLEXCAN Peripherals" @@ -1053,13 +1056,11 @@ config IMX9_FLEXCAN1 bool "FLEXCAN1" default n select IMX9_FLEXCAN - select NET_CAN_HAVE_TX_DEADLINE config IMX9_FLEXCAN2 bool "FLEXCAN2" default n select IMX9_FLEXCAN - select NET_CAN_HAVE_TX_DEADLINE if IMX9_FLEXCAN1 || IMX9_FLEXCAN2 diff --git a/arch/arm64/src/imx9/hardware/imx9_flexcan.h b/arch/arm64/src/imx9/hardware/imx9_flexcan.h index f4aa35af9d423..b0da8f9ef8696 100644 --- a/arch/arm64/src/imx9/hardware/imx9_flexcan.h +++ b/arch/arm64/src/imx9/hardware/imx9_flexcan.h @@ -58,7 +58,7 @@ #define IMX9_CAN_ET_OFFSET 0x0078 /* External Timer Register */ #define IMX9_CAN_FLTC_IE_OFFSET 0x007c /* Fault Confinement Interrupt Enable Register */ -#define IMX9_CAN_MB_OFFSET 0x0080 /* CAN MB register */ +#define IMX9_CAN_MB_OFFSET 0x0080 /* CAN MB start */ #define IMX9_CAN_MB_SIZE 0x0600 #define IMX9_CAN_MB_END (IMX9_CAN_MB_OFFSET + IMX9_CAN_MB_SIZE) @@ -71,6 +71,9 @@ #define IMX9_CAN_TXSMB_OFFSET 0x0ab0 /* Tx_SMB */ #define IMX9_CAN_RXSMB0_OFFSET 0x0ac0 /* Rx_SMB0 */ #define IMX9_CAN_TXSMB1_OFFSET 0x0ad0 /* Rx_SMB1 */ +#define IMX9_CAN_TXSMBFD_OFFSET 0x0f28 /* Tx_SMB for can-fd */ +#define IMX9_CAN_RXSMB0FD_OFFSET 0x0f70 /* Rx_SMB0 for can-fd */ +#define IMX9_CAN_TXSMB1FD_OFFSET 0x0fb8 /* Rx_SMB1 for can-fd */ #define IMX9_CAN_MECR_OFFSET 0x0ae0 /* Memory Error Control Register */ #define IMX9_CAN_ERRIAR_OFFSET 0x0ae4 /* Error Injection Address Register */ @@ -363,6 +366,9 @@ #define CAN_IFLAG3(n) (1 << (n)) /* Bit n: Buffer MBn Interrupt (95TO64) */ +#define IMX9_CAN_FLTC_ATP_IE (1 << 0) /* Active to passive interrupt enable */ +#define IMX9_CAN_FLTC_PTA_IE (1 << 1) /* Passive to active interrupt enable */ + /* TODO: add bit definitions for FLTCONF_IO to ETDC registers when needed */ /* CAN FD Control register */ @@ -424,7 +430,7 @@ #define CAN_FDCRC_FD_MBCRC(x) (((uint32_t)(((uint32_t)(x)) << CAN_FDCRC_FD_MBCRC_SHIFT)) & CAN_FDCRC_FD_MBCRC_MASK) /* Bit 31: Reserved */ -/* CAN MB RX codes */ +/* CAN MB TX & RX codes */ #define CAN_RXMB_INACTIVE 0x0 /* MB is inactive */ #define CAN_RXMB_FULL 0x2 /* MB is full */ diff --git a/arch/arm64/src/imx9/imx9_flexcan.c b/arch/arm64/src/imx9/imx9_flexcan.c index 17e06976818e6..eb9d5138bf368 100644 --- a/arch/arm64/src/imx9/imx9_flexcan.c +++ b/arch/arm64/src/imx9/imx9_flexcan.c @@ -109,6 +109,14 @@ # error Only 21 MB are allowed to be used #endif +#ifdef CONFIG_NET_CAN_CANFD +# define TX_POOL_SIZE ((sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE) +# define RX_POOL_SIZE ((sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE) +#else +# define TX_POOL_SIZE ((sizeof(struct can_frame)*POOL_SIZE) +# define RX_POOL_SIZE ((sizeof(struct can_frame)*POOL_SIZE) +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -155,6 +163,9 @@ struct imx9_driver_s const uintptr_t base; /* FLEXCAN base address */ const int irq; /* irq number */ const bool canfd_capable; + const uint32_t *txdesc; /* A pointer to the list of TX descriptor */ + const uint32_t *rxdesc; /* A pointer to the list of RX descriptors */ + uint32_t clk_freq; /* Peripheral clock frequency */ bool bifup; /* true:ifup false:ifdown */ #ifdef TX_TIMEOUT_WQ @@ -163,10 +174,6 @@ struct imx9_driver_s struct work_s rcvwork; /* For deferring interrupt work to the wq */ 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 */ struct flexcan_timeseg arbi_timing; /* Timing for arbitration phase */ struct flexcan_timeseg data_timing; /* Timing for data phase */ @@ -180,6 +187,10 @@ struct imx9_driver_s ****************************************************************************/ #ifdef CONFIG_IMX9_FLEXCAN1 + +static uint32_t g_tx_pool_can1[(TX_POOL_SIZE + 3) / 4]; +static uint32_t g_rx_pool_can1[(RX_POOL_SIZE + 3) / 4]; + static struct imx9_driver_s g_flexcan1 = { .base = IMX9_CAN1_BASE, @@ -208,12 +219,19 @@ static struct imx9_driver_s g_flexcan1 = { .bitrate = CONFIG_IMX9_FLEXCAN1_BITRATE, .samplep = CONFIG_IMX9_FLEXCAN1_SAMPLEP, - } + }, # endif + + .txdesc = g_tx_pool_can1, + .rxdesc = g_rx_pool_can1, }; #endif #ifdef CONFIG_IMX9_FLEXCAN2 + +static uint32_t g_tx_pool_can2[(TX_POOL_SIZE + 3) / 4]; +static uint32_t g_rx_pool_can2[(RX_POOL_SIZE + 3) / 4]; + static struct imx9_driver_s g_flexcan2 = { .base = IMX9_CAN2_BASE, @@ -242,17 +260,12 @@ static struct imx9_driver_s g_flexcan2 = { .bitrate = CONFIG_IMX9_FLEXCAN2_BITRATE, .samplep = CONFIG_IMX9_FLEXCAN2_SAMPLEP, - } + }, # endif - }; -#endif -#ifdef CONFIG_NET_CAN_CANFD -static uint8_t g_tx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE]; -static uint8_t g_rx_pool[(sizeof(struct canfd_frame)+MSG_DATA)*POOL_SIZE]; -#else -static uint8_t g_tx_pool[sizeof(struct can_frame)*POOL_SIZE]; -static uint8_t g_rx_pool[sizeof(struct can_frame)*POOL_SIZE]; + .txdesc = g_tx_pool_can2, + .rxdesc = g_rx_pool_can2, + }; #endif /**************************************************************************** @@ -277,8 +290,8 @@ static inline uint32_t arm64_lsb(unsigned int value) { uint32_t ret; volatile uint32_t rvalue = value; - __asm__ __volatile__ ("rbit %1,%0" : "=r" (rvalue) : "r" (rvalue)); - __asm__ __volatile__ ("clz %0, %1" : "=r"(ret) : "r"(rvalue)); + __asm__ __volatile__ ("rbit %w1,%w0" : "=r" (rvalue) : "r" (rvalue)); + __asm__ __volatile__ ("clz %w0, %w1" : "=r"(ret) : "r"(rvalue)); return ret; } @@ -497,7 +510,7 @@ static bool imx9_waitmcr_change(uint32_t base, uint32_t mask, bool target_state); static struct mb_s *flexcan_get_mb(struct imx9_driver_s *priv, - uint32_t mbi); + int mbi); /* Interrupt handling */ @@ -554,14 +567,18 @@ static void imx9_reset(struct imx9_driver_s *priv); static bool imx9_txringfull(struct imx9_driver_s *priv) { - uint32_t flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); + int mbi; - if ((flags & IFLAG1_TX) != IFLAG1_TX) + for (mbi = RXMBCOUNT; mbi < TOTALMBCOUNT; mbi++) { - return 0; + struct mb_s *mb = flexcan_get_mb(priv, mbi); + if (CAN_MB_CS_CODE(mb->cs) != CAN_TXMB_DATAORREMOTE) + { + return false; + } } - return 1; + return true; } /**************************************************************************** @@ -598,7 +615,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) #endif uint32_t cs = 0; canid_t can_id; - uint8_t can_dlc; + uint32_t can_dlc; uint8_t len; for (mbi = RXMBCOUNT; mbi < TOTALMBCOUNT; mbi++) @@ -620,7 +637,7 @@ static int imx9_transmit(struct imx9_driver_s *priv) { nwarn("No TX MB available mbi %" PRIi32 "\n", mbi); NETDEV_TXERRORS(&priv->dev); - return 0; + return ERROR; } #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE @@ -636,7 +653,8 @@ static int imx9_transmit(struct imx9_driver_s *priv) + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; if (timeout < 0) { - return 0; /* No transmission for you! */ + _alert("TO already?\n"); + return ERROR; } } else @@ -679,35 +697,47 @@ static int imx9_transmit(struct imx9_driver_s *priv) len = frame->len; can_dlc = g_len_to_can_dlc[len]; frame_data_word = (uint32_t *)&frame->data[0]; + + _alert("can_id %x, len %d\n", can_id, len); + } #endif if (can_id & CAN_EFF_FLAG) { cs |= CAN_MB_CS_IDE; - mb->id = (can_id << CAN_MB_ID_ID_SHIFT) & CAN_MB_ID_ID_MASK; + mb->id = can_id & CAN_MB_ID_ID_MASK; } else { - mb->id = (can_id << CAN_MB_ID_ID_STD_SHIFT) & CAN_MB_ID_ID_STD_MASK; + mb->id = ((can_id & CAN_SFF_MASK) << CAN_MB_ID_ID_STD_SHIFT) & + CAN_MB_ID_ID_STD_MASK; } cs |= (can_id & CAN_RTR_FLAG) ? CAN_MB_CS_RTR : 0; - cs |= (((uint32_t)can_dlc) << CAN_MB_CS_DLC_SHIFT) & CAN_MB_CS_DLC_MASK; + cs |= (can_dlc << CAN_MB_CS_DLC_SHIFT) & CAN_MB_CS_DLC_MASK; for (i = 0; i < (len + 4 - 1) / 4; i++) { mb->data[i] = __builtin_bswap32(frame_data_word[i]); } - /* Go */ - - mb->cs = (cs | (CAN_TXMB_DATAORREMOTE << CAN_MB_CS_CODE_SHIFT)); + _alert("IFLAG1 %x\n", getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET)); + _alert("IMASK1 %x\n", getreg32(priv->base + IMX9_CAN_IMASK1_OFFSET)); + _alert("MCR %x\n", getreg32(priv->base + IMX9_CAN_MCR_OFFSET)); /* Enable interrupt */ modifyreg32(priv->base + IMX9_CAN_IMASK1_OFFSET, 0, 1 << mbi); + _alert("IMASK1 now %x\n", getreg32(priv->base + IMX9_CAN_IMASK1_OFFSET)); + _alert("CS now %x\n", mb->cs); + _alert("write CS %x, ID %x\n", cs, mb->id); + + /* Go */ + + mb->cs = (cs | (CAN_TXMB_DATAORREMOTE << CAN_MB_CS_CODE_SHIFT)); + /* Increment statistics */ NETDEV_TXPACKETS(&priv->dev); @@ -819,8 +849,9 @@ static void imx9_receive(struct imx9_driver_s *priv) uint32_t f; uint32_t flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); - + _alert("receive\n"); flags &= IFLAG1_RX; + while ((f = flags) != 0) { mbj = mbi = arm64_lsb(f); @@ -847,7 +878,7 @@ static void imx9_receive(struct imx9_driver_s *priv) { /* CAN FD frame */ - struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc_fd; + struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc; if (rf->cs & CAN_MB_CS_IDE) { @@ -866,7 +897,7 @@ static void imx9_receive(struct imx9_driver_s *priv) frame->can_id |= CAN_RTR_FLAG; } - /* Enable bitrate switch by default if frame is CANFD */ + /* Set bitrate switch by default if frame is CANFD */ frame->flags = CANFD_BRS; if (rf->cs & CAN_MB_CS_ESI) @@ -938,7 +969,6 @@ static void imx9_receive(struct imx9_driver_s *priv) /* Send to socket interface */ NETDEV_RXPACKETS(&priv->dev); - can_input(&priv->dev); /* Point the packet buffer back to the next Tx buffer that will be @@ -948,14 +978,7 @@ static void imx9_receive(struct imx9_driver_s *priv) * queue is not full. */ - if (priv->canfd_capable) - { - priv->dev.d_buf = (uint8_t *)priv->txdesc_fd; - } - else - { - priv->dev.d_buf = (uint8_t *)priv->txdesc; - } + priv->dev.d_buf = (uint8_t *)priv->txdesc; flags &= ~(1 << mbi); } @@ -977,6 +1000,7 @@ static void imx9_receive(struct imx9_driver_s *priv) static void imx9_txdone(struct imx9_driver_s *priv) { + struct mb_s *mb; uint32_t flags; uint32_t mbi; uint32_t mb_bit; @@ -984,7 +1008,7 @@ static void imx9_txdone(struct imx9_driver_s *priv) uint32_t txmb; #endif - flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); + flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); /* Process TX completions */ @@ -994,18 +1018,32 @@ static void imx9_txdone(struct imx9_driver_s *priv) for (mbi = RXMBCOUNT; mbi < TOTALMBCOUNT; mbi++) { + // _alert("mbi %d, cs: %x\n", mbi, flexcan_get_mb(priv, mbi)->cs); mb_bit = 1 << mbi; if (flags & mb_bit) { - NETDEV_TXDONE(&priv->dev); + mb = flexcan_get_mb(priv, mbi); + if (CAN_MB_CS_CODE(mb->cs) == CAN_TXMB_ABORT) + { + NETDEV_TXERRORS(dev); + } + else + { + NETDEV_TXDONE(dev); + } + + /* Clear interrupt */ + + putreg32(mb_bit, priv->base + IMX9_CAN_IFLAG1_OFFSET); + + //_alert("Txdone %d %X\n", mbi, code); + #ifdef TX_TIMEOUT_WQ /* We are here because a transmission completed, so the * corresponding watchdog can be canceled - * mailbox be set to inactive */ wd_cancel(&priv->txtimeout[txmb]); - putreg32(mb_bit, priv->base + IMX9_CAN_IFLAG1_OFFSET); #endif } @@ -1101,43 +1139,86 @@ static int imx9_flexcan_interrupt(int irq, void *context, void *arg) { struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + uint32_t esr1; + struct mb_s *mb; + int mbi; -#if 0 - uint32_t esr1 = getreg32(priv->base + IMX9_CAN_ESR1_OFFSET); - _alert("ESR1: %x\n", esr1); - _alert("ESR2: %x\n", getreg32(priv->base + IMX9_CAN_ESR2_OFFSET)); - _alert("IFLAG1: %x\n", getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET)); - _alert("ECR: %x\n", getreg32(priv->base + IMX9_CAN_ECR_OFFSET)); - - /* ERRSR[HANCEIF], ERRSR[FANCEIF], and ERRSR[CEIF] */ - - _alert("ERRSR: %x\n", getreg32(priv->base + IMX9_CAN_ERRSR_OFFSET)); - _alert("RERRAR: %x\n", getreg32(priv->base + IMX9_CAN_RERRAR_OFFSET)); - _alert("RERRDR: %x\n", getreg32(priv->base + IMX9_CAN_RERRDR_OFFSET)); - _alert("RERRSYNR: %x\n", getreg32(priv->base + IMX9_CAN_RERRSYNR_OFFSET)); - - putreg32(esr1, priv->base + IMX9_CAN_ESR1_OFFSET); - putreg32(0, priv->base + IMX9_CAN_ECR_OFFSET); -#endif + _alert("IRQ %d\n", irq); if (irq == priv->irq) { uint32_t flags; flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); + //_alert("ISR flags %x TXMASK %x\n",flags,IFLAG1_TX); + if (flags & IFLAG1_RX) { work_queue(CANRCVWORK, &priv->rcvwork, imx9_rxdone_work, priv, 0); } + /* If any of the tx buffers have transitioned to RX EMPTY after + * sending RTR, invalidate that buffer already here. + */ + + for (mbi = RXMBCOUNT; mbi < TOTALMBCOUNT; mbi++) + { + if (flags & (1 << mbi)) + { + mb = flexcan_get_mb(priv, mbi); + + if ((CAN_MB_CS_CODE(mb->cs) & CAN_RXMB_BUSY_BIT) != 0 || + CAN_MB_CS_CODE(mb->cs) == CAN_RXMB_FULL) + { + /* Received something in this buffer, just unlock th MB. + * This should only happen if we sent RTR and then did + * run out of RX MBs (which are at lower indecies). + */ + + NETDEV_RXDROPPED(priv->dev); + canerr("RCV in TX MB\n"); + } + + /* Only possible TX codes after transmission are ABORT or + * INACTIVE. If it transitioned to RX MB, inactivate it. + */ + + if (CAN_MB_CS_CODE(mb->cs) != CAN_TXMB_ABORT && + CAN_MB_CS_CODE(mb->cs) != CAN_TXMB_INACTIVE) + { + mb->cs = CAN_TXMB_INACTIVE << CAN_MB_CS_CODE_SHIFT; + } + } + } + if (flags & IFLAG1_TX) { work_queue(CANWORK, &priv->irqwork, imx9_txdone_work, priv, 0); } + + /* Mask interrupts until handled in the work queue */ + + modifyreg32(priv->base + IMX9_CAN_IMASK1_OFFSET, + flags & (IFLAG1_RX | IFLAG1_TX), + 0); } else { /* Error interrupt */ + + esr1 = getreg32(priv->base + IMX9_CAN_ESR1_OFFSET); + + canerr("ESR1 %x\n", esr1); + canerr("ERRSR: %x\n", getreg32(priv->base + IMX9_CAN_ERRSR_OFFSET)); + canerr("RERRAR: %x\n", getreg32(priv->base + IMX9_CAN_RERRAR_OFFSET)); + + /* Clear the interrupt */ + + putreg32(esr1 & (CAN_ESR1_PTA | CAN_ESR1_ATP | CAN_ESR1_ERROVR | + CAN_ESR1_ERRINTFAST | CAN_ESR1_BOFFDONEINT | + CAN_ESR1_TWRNINT | CAN_ESR1_RWRNINT | + CAN_ESR1_BOFFINT | CAN_ESR1_ERRINT | CAN_ESR1_WAKINT), + priv->base + IMX9_CAN_ESR1_OFFSET); } return OK; @@ -1163,7 +1244,6 @@ static int imx9_flexcan_interrupt(int irq, void *context, static void imx9_txtimeout_work(void *arg) { struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; - uint32_t flags; uint32_t mbi; uint32_t mb_bit; @@ -1175,27 +1255,35 @@ static void imx9_txtimeout_work(void *arg) /* The watchdog timed out, yet we still check mailboxes in case the * transmit function transmitted a new frame */ - - flags = getreg32(priv->base + IMX9_CAN_IFLAG1_OFFSET); + _alert("TXTIMeOUT\n"); for (mbi = 0; mbi < TXMBCOUNT; mbi++) { + mb_bit = 1 << (RXMBCOUNT + mbi); + + /* Disable interrupt for this MB */ + + modifyreg32(priv->base + IMX9_CAN_IMASK1_OFFSET, mb_bit, 0); + if (priv->txmb[mbi].deadline.tv_sec != 0 && (now->tv_sec > priv->txmb[mbi].deadline.tv_sec || now->tv_usec > priv->txmb[mbi].deadline.tv_usec)) { - NETDEV_TXTIMEOUTS(&priv->dev); - - mb_bit = 1 << (RXMBCOUNT + mbi); + /* This MB was timed out */ - if (flags & mb_bit) - { - putreg32(mb_bit, priv->base + IMX9_CAN_IFLAG1_OFFSET); - } + NETDEV_TXTIMEOUTS(&priv->dev); struct mb_s *mb = flexcan_get_mb(priv, mbi + RXMBCOUNT); mb->cs = CAN_TXMB_ABORT << CAN_MB_CS_CODE_SHIFT; priv->txmb[mbi].pending = TX_ABORT; + + putreg32(mb_bit, priv->base + IMX9_CAN_IFLAG1_OFFSET); + } + else + { + /* Not timed out, re-enable interrupt for this MB */ + + modifyreg32(priv->base + IMX9_CAN_IMASK1_OFFSET, mb_bit, 0); } } } @@ -1222,8 +1310,7 @@ static void imx9_txtimeout_expiry(wdparm_t arg) { struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; - /* Schedule to perform the TX timeout processing on the worker thread - */ + /* Schedule to perform the TX timeout processing on the worker thread */ work_queue(CANWORK, &priv->irqwork, imx9_txtimeout_work, priv, 0); } @@ -1276,6 +1363,20 @@ static bool imx9_waitmcr_change(uint32_t base, uint32_t mask, up_udelay(10); } + uint32_t esr1 = getreg32(base + IMX9_CAN_ESR1_OFFSET); + _alert("MCR: %x\n",getreg32(base + IMX9_CAN_MCR_OFFSET)); + _alert("ESR1: %x\n", esr1); + _alert("ESR2: %x\n", getreg32(base + IMX9_CAN_ESR2_OFFSET)); + _alert("IFLAG1: %x\n", getreg32(base + IMX9_CAN_IFLAG1_OFFSET)); + _alert("ECR: %x\n", getreg32(base + IMX9_CAN_ECR_OFFSET)); + + /* ERRSR[HANCEIF], ERRSR[FANCEIF], and ERRSR[CEIF] */ + + _alert("ERRSR: %x\n", getreg32(base + IMX9_CAN_ERRSR_OFFSET)); + _alert("RERRAR: %x\n", getreg32(base + IMX9_CAN_RERRAR_OFFSET)); + _alert("RERRDR: %x\n", getreg32(base + IMX9_CAN_RERRDR_OFFSET)); + _alert("RERRSYNR: %x\n", getreg32(base + IMX9_CAN_RERRSYNR_OFFSET)); + return false; } @@ -1298,7 +1399,7 @@ static bool imx9_waitmcr_change(uint32_t base, uint32_t mask, ****************************************************************************/ static struct mb_s *flexcan_get_mb(struct imx9_driver_s *priv, - uint32_t mbi) + int mbi) { uintptr_t mb_offset; size_t data_bytes = priv->canfd_capable ? 64 : 8; @@ -1337,23 +1438,12 @@ static int imx9_ifup(struct net_driver_s *dev) if (imx9_initialize(priv) != OK) { - nerr("initialize failed"); + canerr("initialize failed"); return ERROR; } priv->bifup = true; - priv->txdesc = (struct can_frame *)&g_tx_pool; - priv->rxdesc = (struct can_frame *)&g_rx_pool; - 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; - } + priv->dev.d_buf = (uint8_t *)priv->txdesc; /* Set interrupts */ @@ -1585,54 +1675,35 @@ static int imx9_ioctl(struct net_driver_s *dev, int cmd, static int imx9_init_eccram(struct imx9_driver_s *priv) { volatile uint32_t *data = (uint32_t *)(priv->base + IMX9_CAN_MB_OFFSET); - const uint32_t *data_end = (uint32_t *)(priv->base + IMX9_CAN_MB_END); - int mbi = 0; - struct mb_s *mb; + volatile uint32_t *data_end = (uint32_t *)(priv->base + IMX9_CAN_MB_END); int i; /* Set WRMFRZ bit in CTRL2 Register to grant write access to memory */ modifyreg32(priv->base + IMX9_CAN_CTRL2_OFFSET, 0, CAN_CTRL2_WRMFRZ); - /* Fill in the inactive RX buffers */ + /* Fill in the whole MB area as inactive RX buffers */ - mb = flexcan_get_mb(priv, mbi); - for (mbi = 0; mbi < RXMBCOUNT; mbi++) + while (data < data_end) { - mb->cs = (CAN_RXMB_EMPTY << CAN_MB_CS_CODE_SHIFT) | CAN_MB_CS_IDE; - - /* ID + Data fields until next mb */ - - data = &mb->id; - mb = flexcan_get_mb(priv, mbi + 1); - while (data < (uint32_t *)mb && data < data_end) - { - *data++ = 0; - } + *data++ = 0; } + + /* Clear Mask registers - allow all for RX MBs */ - /* Fill in the rest of the area as inactive TX buffers */ - - mb = flexcan_get_mb(priv, mbi); - while (data < (uint32_t *)(priv->base + IMX9_CAN_MB_END)) + for (i = 0; i < RXMBCOUNT; i++) { - mb->cs = CAN_TXMB_INACTIVE << CAN_MB_CS_CODE_SHIFT; - - /* ID + Data fields */ - - data = &mb->id; - mb = flexcan_get_mb(priv, ++mbi); - while (data < (uint32_t *)mb && data < data_end) - { - *data++ = 0; - } + putreg32(0, priv->base + IMX9_CAN_RXIMR_OFFSET(i)); } - /* Clear Mask registers */ + /* Set Mask registers to compare all for TX MBs; + * sending an RTR will result TX MB to become RX EMPTY. + * We don't want to match anything in this case + */ - for (int i = 0; i < IMX9_CAN_N_RXIMR; i++) + for (; i < IMX9_CAN_N_RXIMR; i++) { - putreg32(0, priv->base + IMX9_CAN_RXIMR_OFFSET(i)); + putreg32(0xffffffff, priv->base + IMX9_CAN_RXIMR_OFFSET(i)); } /* Clear legacy fifo information registers */ @@ -1649,12 +1720,22 @@ static int imx9_init_eccram(struct imx9_driver_s *priv) putreg32(0x3fffffff, priv->base + IMX9_CAN_RXMGMASK_OFFSET); putreg32(0x0, priv->base + IMX9_CAN_RXFGMASK_OFFSET); - /* Clear Tx_SMB, Rx_SMB0 and Rx_SMB1 - each size of 8-byte mb */ + /* Clear Tx_SMB, Rx_SMB0 and Rx_SMB1 */ - data = (uint32_t *)(priv->base + IMX9_CAN_TXSMB_OFFSET); - for (int i = 0; i < 3 * 4; i++) + if (!priv->canfd_capable) + { + data = (uint32_t *)(priv->base + IMX9_CAN_TXSMB_OFFSET); + data_end = &data[3 * (sizeof(struct mb_s) + 8) / 4]; + } + else { - data[i] = 0; + data = (uint32_t *)(priv->base + IMX9_CAN_TXSMBFD_OFFSET); + data_end = &data[3 * (sizeof(struct mb_s) + 64) / 4]; + } + + while (data < data_end) + { + *data++ = 0; } /* Clear WRMFRZ bit in CTRL2 Register */ @@ -1683,12 +1764,13 @@ static int imx9_init_eccram(struct imx9_driver_s *priv) static int imx9_initialize(struct imx9_driver_s *priv) { uint32_t tdcoff; + int i; /* Enable module */ if (!imx9_setenable(priv->base, true)) { - nerr("FLEXCAN: enable fail\n"); + canerr("FLEXCAN: enable fail\n"); return ERROR; } @@ -1696,7 +1778,7 @@ static int imx9_initialize(struct imx9_driver_s *priv) if (!imx9_setfreeze(priv->base, true)) { - nerr("FLEXCAN: freeze fail\n"); + canerr("FLEXCAN: freeze fail\n"); return ERROR; } @@ -1707,9 +1789,9 @@ static int imx9_initialize(struct imx9_driver_s *priv) /* Configure MCR */ modifyreg32(priv->base + IMX9_CAN_MCR_OFFSET, CAN_MCR_MAXMB_MASK, - CAN_MCR_SLFWAK | CAN_MCR_WRNEN | CAN_MCR_SRXDIS | - CAN_MCR_IRMQ | CAN_MCR_AEN | - ((TOTALMBCOUNT << CAN_MCR_MAXMB_SHIFT) & CAN_MCR_MAXMB_MASK)); + /*CAN_MCR_WAKMSK |*/ CAN_MCR_SLFWAK | CAN_MCR_WRNEN | CAN_MCR_SRXDIS | + CAN_MCR_WAKSRC | CAN_MCR_IRMQ | CAN_MCR_AEN | + (((TOTALMBCOUNT - 1) << CAN_MCR_MAXMB_SHIFT) & CAN_MCR_MAXMB_MASK)); if (!priv->canfd_capable) { @@ -1770,23 +1852,21 @@ static int imx9_initialize(struct imx9_driver_s *priv) CAN_CTRL2_ISOCANFDEN); } + /* Always compare also IDE and RTR bits to mask */ + + modifyreg32(priv->base + IMX9_CAN_CTRL2_OFFSET, 0, + CAN_CTRL2_RRS | CAN_CTRL2_EACEN); + + _alert("CTRL2 : %x\n", getreg32(priv->base + IMX9_CAN_CTRL2_OFFSET)); + // modifyreg32(priv->base + IMX9_CAN_CTRL2_OFFSET, CAN_CTRL2_RETRY_MASK, 0); + /* Exit supervisor mode */ modifyreg32(priv->base + IMX9_CAN_MCR_OFFSET, CAN_MCR_SUPV, 0); -#if 0 - for (i = 0; i < RXMBCOUNT; i++) - { - struct mb_s *rx = flexcan_get_mb(priv, i); - ninfo("Set MB%" PRIi32 " to receive %p\n", i, rx); - rx->cs = (CAN_RXMB_EMPTY << CAN_MB_CS_CODE_SHIFT) | CAN_MB_CS_IDE; - } -#endif + /* Clear IFLAG1 interrupts (MB 0-20) */ - /* Clear and enable IFLAG1 interrupts (MB 0-20) */ - - putreg32(IFLAG1_RX, priv->base + IMX9_CAN_IFLAG1_OFFSET); - putreg32(IFLAG1_RX, priv->base + IMX9_CAN_IMASK1_OFFSET); + putreg32(IFLAG1_RX | IFLAG1_TX, priv->base + IMX9_CAN_IFLAG1_OFFSET); /* Disable IFLAG2 & 3 interrupts */ @@ -1797,10 +1877,23 @@ static int imx9_initialize(struct imx9_driver_s *priv) if (!imx9_setfreeze(priv->base, false)) { - nerr("FLEXCAN: unfreeze fail\n"); + canerr("FLEXCAN: unfreeze fail\n"); return ERROR; } + /* Enable IFLAG1 interrupts for RX */ + + putreg32(IFLAG1_RX, priv->base + IMX9_CAN_IMASK1_OFFSET); + + /* Set RX buffers to receive */ + + for (i = 0; i < RXMBCOUNT; i++) + { + struct mb_s *rx = flexcan_get_mb(priv, i); + ninfo("Set MB%" PRIi32 " to receive %p\n", i, rx); + rx->cs = (CAN_RXMB_EMPTY << CAN_MB_CS_CODE_SHIFT) | CAN_MB_CS_IDE; + } + return OK; } @@ -1930,8 +2023,8 @@ int imx9_caninitialize(int intf) if (imx9_bitratetotimeseg(priv, &priv->arbi_timing, false) != OK) { - nerr("ERROR: Invalid CAN timings please try another sample point " - "or refer to the reference manual\n"); + canerr("ERROR: Invalid CAN timings please try another sample point " + "or refer to the reference manual\n"); return -1; } @@ -1939,8 +2032,8 @@ int imx9_caninitialize(int intf) { if (imx9_bitratetotimeseg(priv, &priv->data_timing, true) != OK) { - nerr("ERROR: Invalid CAN data phase timings please try another " - "sample point or refer to the reference manual\n"); + canerr("ERROR: Invalid CAN data phase timings please try another " + "sample point or refer to the reference manual\n"); return -1; } } @@ -1953,15 +2046,15 @@ int imx9_caninitialize(int intf) { /* We could not attach the ISR to the interrupt */ - nerr("ERROR: Failed to attach CAN bus IRQ\n"); + canerr("ERROR: Failed to attach CAN bus IRQ\n"); return -EAGAIN; } if (irq_attach(priv->irq + 1, imx9_flexcan_interrupt, priv)) { - /* We could not attach the ISR to the interrupt */ + /* We could not attach the error ISR to the interrupt */ - nerr("ERROR: Failed to attach CAN bus error IRQ\n"); + canerr("ERROR: Failed to attach CAN bus error IRQ\n"); irq_detach(priv->irq); return -EAGAIN; }