From e1b8c02f96d3d82cebe6894e53ebd09b2e503a5f Mon Sep 17 00:00:00 2001 From: TimJTi <56726697+TimJTi@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:52:22 +0000 Subject: [PATCH] Add SAMA5D2 MCAN support Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko Update arch/arm/src/sama5/sam_mcan.c Co-authored-by: Petro Karashchenko --- arch/arm/src/sama5/Kconfig | 723 ++- arch/arm/src/sama5/Make.defs | 8 + .../src/sama5/hardware/_sama5d2x_memorymap.h | 8 +- arch/arm/src/sama5/hardware/sam_mcan.h | 816 ++++ arch/arm/src/sama5/sam_mcan.c | 4202 +++++++++++++++++ arch/arm/src/sama5/sam_mcan.h | 95 + 6 files changed, 5842 insertions(+), 10 deletions(-) create mode 100644 arch/arm/src/sama5/hardware/sam_mcan.h create mode 100644 arch/arm/src/sama5/sam_mcan.c create mode 100644 arch/arm/src/sama5/sam_mcan.h diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index 931b590ad9..1f3c0b7673 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -89,6 +89,18 @@ config SAMA5_HAVE_CAN1 bool default n +config SAMA5_MCAN + bool + default n + +config SAMA5_HAVE_MCAN0 + bool + default n + +config SAMA5_HAVE_MCAN1 + bool + default n + config SAMA5_HAVE_DMA bool default n @@ -274,12 +286,12 @@ config ARCH_CHIP_ATSAMA5D21 config ARCH_CHIP_ATSAMA5D22 bool "Atmel ATSAMA5D22" select ARCH_CHIP_SAMA5D2 - select SAMA5_HAVE_CAN0 + select SAMA5_HAVE_MCAN0 config ARCH_CHIP_ATSAMA5D23 bool "Atmel ATSAMA5D23" select ARCH_CHIP_SAMA5D2 - select SAMA5_HAVE_CAN0 + select SAMA5_HAVE_MCAN0 config ARCH_CHIP_ATSAMA5D24 bool "Atmel ATSAMA5D24" @@ -294,8 +306,8 @@ config ARCH_CHIP_ATSAMA5D26 config ARCH_CHIP_ATSAMA5D27 bool "Atmel ATSAMA5D27" select ARCH_CHIP_SAMA5D2 - select SAMA5_HAVE_CAN0 - select SAMA5_HAVE_CAN1 + select SAMA5_HAVE_MCAN0 + select SAMA5_HAVE_MCAN1 select SAMA5_HAVE_DDR32 select SAMA5_HAVE_SDMMC select SAMA5_HAVE_GMAC @@ -303,8 +315,8 @@ config ARCH_CHIP_ATSAMA5D27 config ARCH_CHIP_ATSAMA5D28 bool "Atmel ATSAMA5D28" select ARCH_CHIP_SAMA5D2 - select SAMA5_HAVE_CAN0 - select SAMA5_HAVE_CAN1 + select SAMA5_HAVE_MCAN0 + select SAMA5_HAVE_MCAN1 select SAMA5_HAVE_DDR32 config ARCH_CHIP_ATSAMA5D31 @@ -733,6 +745,24 @@ config SAMA5_CAN1 select CAN depends on SAMA5_HAVE_CAN1 +config SAMA5_MCAN0 + bool "MCAN controller 0 (MCAN0)" + default n + depends on SAMA5_HAVE_MCAN0 + select CAN + select ARCH_HAVE_CAN_ERRORS + select CAN_TXREADY + select SAMA5_MCAN + +config SAMA5_MCAN1 + bool "MCAN controller 1 (MCAN1)" + default n + depends on SAMA5_HAVE_MCAN1 + select CAN + select ARCH_HAVE_CAN_ERRORS + select CAN_TXREADY + select SAMA5_MCAN + config SAMA5_SHA bool "Secure Hash Algorithm (SHA)" default n @@ -1453,6 +1483,687 @@ config SAMA5_LCDC_REGDEBUG endmenu # LCDC configuration endif # SAMA5_LCDC +if SAMA5_MCAN + +config SAMA5_MCAN_QUEUE_MODE + bool "MCAN QUEUE mode (vs FIFO mode)" + default n + +menu "MCAN device driver options" + +choice + prompt "MCAN clock source" + default SAMA5_MCAN_CLKSRC_UPLL + +config SAMA5_MCAN_CLKSRC_SLOW + bool "Slow clock" + +config SAMA5_MCAN_CLKSRC_MAIN + bool "Main clock" + +config SAMA5_MCAN_CLKSRC_PLLA + bool "PLLA clock" + +config SAMA5_MCAN_CLKSRC_UPLL + bool "UPLL clock" + +config SAMA5_MCAN_CLKSRC_MCK + bool "Master clock" + +endchoice # MCAN clock source + +config SAMA5_MCAN_CLKSRC_PRESCALER + int "MCAN clock prescaler" + default 6 + range 1 1024 + ---help--- + The frequency associated with time quanta is derived by dividing + down the input frequency. This setting provides prescaler/divider + must lie the range of 1 to 1024. + +menu "MCAN0 device driver options" + depends on SAMA5_MCAN0 + +choice + prompt "MCAN0 mode" + default SAMA5_MCAN0_ISO11898_1 + +config SAMA5_MCAN0_ISO11898_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 mode + +config SAMA5_MCAN0_FD + bool "FD" + depends on CAN_FD + ---help--- + Enable FD mode + +config SAMA5_MCAN0_FD_BSW + bool "FD with fast bit rate switching" + depends on CAN_FD + ---help--- + Enable FD mode with fast bit rate switching mode. + +endchoice # MCAN0 mode + +config SAMA5_MCAN0_LOOPBACK + bool "Enable MCAN0 loopback mode" + default n + ---help--- + Enable the MCAN0 local loopback mode for testing purposes. + +config SAMA5_MCAN0_BITRATE + int "MCAN0 bitrate" + default 500000 + ---help--- + MCAN0 bitrate in bits per second. Required if SAMA5_MCAN0 is defined. + +config SAMA5_MCAN0_PROPSEG + int "MCAN0 PropSeg" + default 2 + range 1 8 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN0_PHASESEG1 + int "MCAN0 PhaseSeg1" + default 11 + range 1 255 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + PhaseSeg1+PropSeg must be between 2 and 256 + +config SAMA5_MCAN0_PHASESEG2 + int "MCAN0 PhaseSeg2" + default 2 + range 1 128 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN0_FSJW + int "MCAN0 synchronization jump width" + default 1 + range 1 128 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMA5_MCAN0_FBITRATE + int "MCAN0 fast bitrate" + default 2000000 + ---help--- + MCAN0 bitrate in bits per second. Required if SAMA5_MCAN0 is + defined. + +config SAMA5_MCAN0_FPROPSEG + int "MCAN0 fast PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN0_FPHASESEG1 + int "MCAN0 fast PhaseSeg1" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN0_FPHASESEG2 + int "MCAN0 fast PhaseSeg2" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN0_FFSJW + int "MCAN0 fast synchronization jump width" + default 2 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMA5_MCAN0_NSTDFILTERS + int "MCAN0 number of standard filters" + default 0 + range 0 128 + ---help--- + Number of standard message ID filters. + +config SAMA5_MCAN0_NEXTFILTERS + int "MCAN0 number of extended filters" + default 0 + range 0 64 + depends on CAN_EXTID + ---help--- + Number of extended message ID filters. + +choice + prompt "MCAN0 RX FIFO0 element size" + default SAMA5_MCAN0_RXFIFO0_8BYTES + +config SAMA5_MCAN0_RXFIFO0_8BYTES + bool "8 bytes" + +config SAMA5_MCAN0_RXFIFO0_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO0_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMA5_MCAN0_RXFIFO0_SIZE + int "MCAN0 RX FIFO0 size" + default 8 + range 1 64 + ---help--- + Number of receive FIFO 0 elements. Zero disables FIFO 0. + +choice + prompt "MCAN0 RX FIFO1 element size" + default SAMA5_MCAN0_RXFIFO1_8BYTES + +config SAMA5_MCAN0_RXFIFO1_8BYTES + bool "8 bytes" + +config SAMA5_MCAN0_RXFIFO1_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXFIFO1_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMA5_MCAN0_RXFIFO1_SIZE + int "MCAN0 RX FIFO1 size" + default 4 + range 1 64 + ---help--- + Number of receive FIFO 1 elements for MCAN0. Zero disables FIFO 1. + +choice + prompt "MCAN0 RX buffer element size" + default SAMA5_MCAN0_RXBUFFER_8BYTES + +config SAMA5_MCAN0_RXBUFFER_8BYTES + bool "8 bytes" + +config SAMA5_MCAN0_RXBUFFER_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_RXBUFFER_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE + int "MCAN0 dedicated RX buffer size" + default 0 + range 0 64 + depends on EXPERIMENTAL + ---help--- + Number of dedicated RX buffer elements for MCAN0. + + NOTE: Dedicated RX buffers are not used in the current MCAN design. + +choice + prompt "MCAN0 TX buffer element size" + default SAMA5_MCAN0_TXBUFFER_8BYTES + +config SAMA5_MCAN0_TXBUFFER_8BYTES + bool "8 bytes" + +config SAMA5_MCAN0_TXBUFFER_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN0_FD + +config SAMA5_MCAN0_TXBUFFER_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN0_FD + +endchoice # MCAN0 TX buffer element size + +config SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE + int "MCAN0 dedicated TX buffer size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of dedicated TX buffer elements for MCAN0. + + NOTE: Dedicated TX buffers are not used in the current MCAN design. + +config SAMA5_MCAN0_TXFIFOQ_SIZE + int "MCAN0 TX FIFO queue size" + default 4 + range 1 32 + ---help--- + Number of dedicated TX buffer elements for MCAN0. + +config SAMA5_MCAN0_TXEVENTFIFO_SIZE + int "MCAN0 TX event FIFO size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of TX event FIFO elements for MCAN0. Zero disables TX event FIFO. + +endmenu # MCAN0 device driver options + +menu "MCAN1 device driver options" + depends on SAMA5_MCAN1 + +choice + prompt "MCAN1 mode" + default SAMA5_MCAN1_ISO11899_1 + +config SAMA5_MCAN1_ISO11899_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 mode + +config SAMA5_MCAN1_FD + bool "FD" + depends on CAN_FD + ---help--- + Enable FD mode + +config SAMA5_MCAN1_FD_BSW + bool "FD with fast bit rate switching" + depends on CAN_FD + ---help--- + Enable FD mode with fast bit rate switching mode. + +endchoice # MCAN0 mode + +config SAMA5_MCAN1_LOOPBACK + bool "Enable MCAN1 loopback mode" + default n + ---help--- + Enable the MCAN1 local loopback mode for testing purposes. + +config SAMA5_MCAN1_BITRATE + int "MCAN1 bitrate" + default 500000 + ---help--- + MCAN1 bitrate in bits per second. Required if SAMA5_MCAN1 is + defined. + +config SAMA5_MCAN1_PROPSEG + int "MCAN1 PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_PHASESEG1 + int "MCAN1 PhaseSeg1" + default 11 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_PHASESEG2 + int "MCAN1 PhaseSeg2" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_FSJW + int "MCAN1 synchronization jump width" + default 1 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMA5_MCAN1_FBITRATE + int "MCAN1 fast bitrate" + default 2000000 + ---help--- + MCAN1 bitrate in bits per second. Required if SAMA5_MCAN1 is + defined. + +config SAMA5_MCAN1_FPROPSEG + int "MCAN1 fast PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_FPHASESEG1 + int "MCAN1 fast PhaseSeg1" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_FPHASESEG2 + int "MCAN1 fast PhaseSeg2" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMA5_MCAN1_FFSJW + int "MCAN1 fast synchronization jump width" + default 2 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMA5_MCAN1_NSTDFILTERS + int "MCAN1 number of standard filters" + default 8 + range 0 128 + ---help--- + Number of standard message ID filters. + +config SAMA5_MCAN1_NEXTFILTERS + int "MCAN1 number of extended filters" + default 8 + range 0 64 + depends on CAN_EXTID + ---help--- + Number of extended message ID filters. + +choice + prompt "MCAN1 RX FIFO0 element size" + default SAMA5_MCAN1_RXFIFO0_8BYTES + +config SAMA5_MCAN1_RXFIFO0_8BYTES + bool "8 bytes" + +config SAMA5_MCAN1_RXFIFO0_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO0_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMA5_MCAN1_RXFIFO0_SIZE + int "MCAN1 RX FIFO0 size" + default 8 + range 1 64 + ---help--- + Number of receive FIFO 0 elements. Zero disables FIFO 0. + +choice + prompt "MCAN1 RX FIFO1 element size" + default SAMA5_MCAN1_RXFIFO1_8BYTES + +config SAMA5_MCAN1_RXFIFO1_8BYTES + bool "8 bytes" + +config SAMA5_MCAN1_RXFIFO1_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXFIFO1_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMA5_MCAN1_RXFIFO1_SIZE + int "MCAN1 RX FIFO1 size" + default 4 + range 1 64 + ---help--- + Number of receive FIFO 1 elements for MCAN1. Zero disables FIFO 1. + +choice + prompt "MCAN1 RX buffer element size" + default SAMA5_MCAN1_RXBUFFER_8BYTES + +config SAMA5_MCAN1_RXBUFFER_8BYTES + bool "8 bytes" + +config SAMA5_MCAN1_RXBUFFER_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_RXBUFFER_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE + int "MCAN1 dedicated RX buffer size" + default 0 + range 0 64 + depends on EXPERIMENTAL + ---help--- + Number of dedicated RX buffer elements for MCAN1. + + NOTE: Dedicated RX buffers are not used in the current MCAN design. + +choice + prompt "MCAN1 TX buffer element size" + default SAMA5_MCAN1_TXBUFFER_8BYTES + +config SAMA5_MCAN1_TXBUFFER_8BYTES + bool "8 bytes" + +config SAMA5_MCAN1_TXBUFFER_12BYTES + bool "12 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_16BYTES + bool "16 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_20BYTES + bool "20 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_24BYTES + bool "24 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_32BYTES + bool "32 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_48BYTES + bool "48 bytes" + depends on SAMA5_MCAN1_FD + +config SAMA5_MCAN1_TXBUFFER_64BYTES + bool "64 bytes" + depends on SAMA5_MCAN1_FD + +endchoice # MCAN1 TX buffer element size + +config SAMA5_MCAN1_TXEVENTFIFO_SIZE + int "MCAN1 TX event FIFO size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of TX event FIFO elements for MCAN1. Zero disables TX event FIFO. + +config SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE + int "MCAN1 dedicated TX buffer size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of dedicated TX buffer elements for MCAN1. + + NOTE: Dedicated TX buffers are not used in the current MCAN design. + +config SAMA5_MCAN1_TXFIFOQ_SIZE + int "MCAN1 TX FIFO queue" + default 4 + range 1 32 + ---help--- + Number of dedicated TX buffer elements for MCAN1. + +endmenu # MCAN1 device driver options + +config SAMA5_MCAN_REGDEBUG + bool "CAN Register level debug" + depends on DEBUG_CAN_INFO + default n + ---help--- + Output detailed register-level CAN device debug information. + Requires also CONFIG_DEBUG_CAN_INFO. + +endmenu # CAN device driver options +endif # SAMA5_MCAN + if SAMA5_GMAC menu "GMAC device driver options" diff --git a/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index 91a5e256a8..c26f442a6a 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/arch/arm/src/sama5/Make.defs @@ -170,6 +170,14 @@ CHIP_CSRCS += sam_can.c endif endif +ifeq ($(CONFIG_SAMA5_MCAN0),y) +CHIP_CSRCS += sam_mcan.c +else +ifeq ($(CONFIG_SAMA5_MCAN1),y) +CHIP_CSRCS += sam_mcan.c +endif +endif + ifeq ($(CONFIG_SAMA5_TWI0),y) CHIP_CSRCS += sam_twi.c else diff --git a/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h b/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h index 022acc8904..c8dddb7255 100644 --- a/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h +++ b/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h @@ -140,7 +140,7 @@ /* 0x0004b000-0x0004bfff: Reserved */ # define SAM_SFC_OFFSET 0x0004c000 /* 0x0004c000-0x0004ffff: SFC */ # define SAM_I2SC0_OFFSET 0x00050000 /* 0x00050000-0x00053fff: I2SC0 */ -# define SAM_CAN0_OFFSET 0x00054000 /* 0x00054000-0x00057fff: CAN0 */ +# define SAM_MCAN0_OFFSET 0x00054000 /* 0x00054000-0x00057fff: MCAN0 */ # define SAM_SYSC_PSECTION 0xf8048000 /* 0xf8048000-0xf8048fff: System Controller */ # define SAM_SYSC_PADDR 0xf8048000 /* 0xf8048000-0xf8048fff: System Controller */ @@ -165,7 +165,7 @@ # define SAM_TDES_OFFSET 0x00044000 /* 0x00044000-0x00047fff: TDES */ # define SAM_CLASSD_OFFSET 0x00048000 /* 0x00048000-0x0004bfff: Class D */ # define SAM_I2SC1_OFFSET 0x0004c000 /* 0x0004c000-0x0004ffff: I2SC1 */ -# define SAM_CAN1_OFFSET 0x00050000 /* 0x00050000-0x00053fff: CAN1 */ +# define SAM_MCAN1_OFFSET 0x00050000 /* 0x00050000-0x00053fff: MCAN1 */ # define SAM_UTMI_OFFSET 0x00054000 /* 0x00054000-0x00057fff: UTMI */ /* 0x00058000-0x0005bfff: Reserved */ # define SAM_SFRBU_OFFSET 0x0005c000 /* 0x0005c000-0x0005ffff: SFRBU */ @@ -492,7 +492,7 @@ #define SAM_ACC_VBASE (SAM_PERIPHB_VSECTION+SAM_ACC_OFFSET) #define SAM_SFC_VBASE (SAM_PERIPHB_VSECTION+SAM_SFC_OFFSET) #define SAM_I2SC0_VBASE (SAM_PERIPHB_VSECTION+SAM_I2SC0_OFFSET) -#define SAM_CAN0_VBASE (SAM_PERIPHB_VSECTION+SAM_CAN0_OFFSET) +#define SAM_MCAN0_VBASE (SAM_PERIPHB_VSECTION+SAM_MCAN0_OFFSET) #define SAM_SPI1_VBASE (SAM_PERIPHC_VSECTION+SAM_SPI1_OFFSET) #define SAM_SSC1_VBASE (SAM_PERIPHC_VSECTION+SAM_SSC1_OFFSET) @@ -512,7 +512,7 @@ #define SAM_TDES_VBASE (SAM_PERIPHC_VSECTION+SAM_TDES_OFFSET) #define SAM_CLASSD_VBASE (SAM_PERIPHC_VSECTION+SAM_CLASSD_OFFSET) #define SAM_I2SC1_VBASE (SAM_PERIPHC_VSECTION+SAM_I2SC1_OFFSET) -#define SAM_CAN1_VBASE (SAM_PERIPHC_VSECTION+SAM_CAN1_OFFSET) +#define SAM_MCAN1_VBASE (SAM_PERIPHC_VSECTION+SAM_MCAN1_OFFSET) #define SAM_UTMI_VBASE (SAM_PERIPHC_VSECTION+SAM_UTMI_OFFSET) #define SAM_SFRBU_VBASE (SAM_PERIPHC_VSECTION+SAM_SFRBU_OFFSET) #define SAM_CHIPID_VBASE (SAM_PERIPHC_VSECTION+SAM_CHIPID_OFFSET) diff --git a/arch/arm/src/sama5/hardware/sam_mcan.h b/arch/arm/src/sama5/hardware/sam_mcan.h new file mode 100644 index 0000000000..d00d652434 --- /dev/null +++ b/arch/arm/src/sama5/hardware/sam_mcan.h @@ -0,0 +1,816 @@ +/**************************************************************************** + * arch/arm/src/sama5/hardware/sam_mcan.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_MCAN_H +#define __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_MCAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/sam_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* MCAN register offsets ****************************************************/ + +#define SAM_MCAN_CREL_OFFSET 0x0000 /* Core Release Register */ +#define SAM_MCAN_ENDN_OFFSET 0x0004 /* Endian Register */ +#define SAM_MCAN_CUST_OFFSET 0x0008 /* Customer Register */ +#define SAM_MCAN_FBTP_OFFSET 0x000c /* Data Bit Timing and Prescaler Register */ +#define SAM_MCAN_TEST_OFFSET 0x0010 /* Test Register */ +#define SAM_MCAN_RWD_OFFSET 0x0014 /* RAM Watchdog Register */ +#define SAM_MCAN_CCCR_OFFSET 0x0018 /* CC Control Register */ +#define SAM_MCAN_BTP_OFFSET 0x001c /* Nominal Bit Timing and Prescaler Register */ +#define SAM_MCAN_TSCC_OFFSET 0x0020 /* Timestamp Counter Configuration Register */ +#define SAM_MCAN_TSCV_OFFSET 0x0024 /* Timestamp Counter Value Register */ +#define SAM_MCAN_TOCC_OFFSET 0x0028 /* Timeout Counter Configuration Register */ +#define SAM_MCAN_TOCV_OFFSET 0x002c /* Timeout Counter Value Register */ + /* 0x0030-0x003c Reserved */ +#define SAM_MCAN_ECR_OFFSET 0x0040 /* Error Counter Register */ +#define SAM_MCAN_PSR_OFFSET 0x0044 /* Protocol Status Register */ +#define SAM_MCAN_TDCR_OFFSET 0x0048 /* Transmitter Delay Compensation Register */ + /* 0x004c Reserved */ +#define SAM_MCAN_IR_OFFSET 0x0050 /* Interrupt Register*/ +#define SAM_MCAN_IE_OFFSET 0x0054 /* Interrupt Enable Register */ +#define SAM_MCAN_ILS_OFFSET 0x0058 /* Interrupt Line Select Register */ +#define SAM_MCAN_ILE_OFFSET 0x005c /* Interrupt Line Enable Register */ + /* 0x0060-0x007c Reserved */ +#define SAM_MCAN_GFC_OFFSET 0x0080 /* Global Filter Configuration Register */ +#define SAM_MCAN_SIDFC_OFFSET 0x0084 /* Standard ID Filter Configuration Register */ +#define SAM_MCAN_XIDFC_OFFSET 0x0088 /* Extended ID Filter Configuration Register */ + /* 0x008c Reserved */ +#define SAM_MCAN_XIDAM_OFFSET 0x0090 /* Extended ID AND Mask Register */ +#define SAM_MCAN_HPMS_OFFSET 0x0094 /* High Priority Message Status Register */ +#define SAM_MCAN_NDAT1_OFFSET 0x0098 /* New Data 1 Register */ +#define SAM_MCAN_NDAT2_OFFSET 0x009c /* New Data 2 Register */ +#define SAM_MCAN_RXF0C_OFFSET 0x00a0 /* Receive FIFO 0 Configuration Register */ +#define SAM_MCAN_RXF0S_OFFSET 0x00a4 /* Receive FIFO 0 Status Register */ +#define SAM_MCAN_RXF0A_OFFSET 0x00a8 /* Receive FIFO 0 Acknowledge Register */ +#define SAM_MCAN_RXBC_OFFSET 0x00ac /* Receive Rx Buffer Configuration Register */ +#define SAM_MCAN_RXF1C_OFFSET 0x00b0 /* Receive FIFO 1 Configuration Register */ +#define SAM_MCAN_RXF1S_OFFSET 0x00b4 /* Receive FIFO 1 Status Register */ +#define SAM_MCAN_RXF1A_OFFSET 0x00b8 /* Receive FIFO 1 Acknowledge Register */ +#define SAM_MCAN_RXESC_OFFSET 0x00bc /* Receive Buffer / FIFO Element Size Configuration Register */ +#define SAM_MCAN_TXBC_OFFSET 0x00c0 /* Transmit Buffer Configuration Register */ +#define SAM_MCAN_TXFQS_OFFSET 0x00c4 /* Transmit FIFO/Queue Status Register */ +#define SAM_MCAN_TXESC_OFFSET 0x00c8 /* Transmit Buffer Element Size Configuration Register */ +#define SAM_MCAN_TXBRP_OFFSET 0x00cc /* Transmit Buffer Request Pending Register */ +#define SAM_MCAN_TXBAR_OFFSET 0x00d0 /* Transmit Buffer Add Request Register */ +#define SAM_MCAN_TXBCR_OFFSET 0x00d4 /* Transmit Buffer Cancellation Request Register */ +#define SAM_MCAN_TXBTO_OFFSET 0x00d8 /* Transmit Buffer Transmission Occurred Register */ +#define SAM_MCAN_TXBCF_OFFSET 0x00dc /* Transmit Buffer Cancellation Finished Register */ +#define SAM_MCAN_TXBTIE_OFFSET 0x00e0 /* Transmit Buffer Transmission Interrupt Enable Register */ +#define SAM_MCAN_TXBCIE_OFFSET 0x00e4 /* Transmit Buffer Cancellation Finished Interrupt Enable Register */ + /* 0x00e8-0x00ec Reserved */ +#define SAM_MCAN_TXEFC_OFFSET 0x00f0 /* Transmit Event FIFO Configuration Register */ +#define SAM_MCAN_TXEFS_OFFSET 0x00f4 /* Transmit Event FIFO Status Register */ +#define SAM_MCAN_TXEFA_OFFSET 0x00f8 /* Transmit Event FIFO Acknowledge Register */ + /* 0x00fc Reserved */ + +/* MCAN register addresses **************************************************/ + +#define SAM_MCAN0_CUST (SAM_MCAN0_BASE+SAM_MCAN_CUST_OFFSET) +#define SAM_MCAN0_FBTP (SAM_MCAN0_BASE+SAM_MCAN_FBTP_OFFSET) +#define SAM_MCAN0_TEST (SAM_MCAN0_BASE+SAM_MCAN_TEST_OFFSET) +#define SAM_MCAN0_RWD (SAM_MCAN0_BASE+SAM_MCAN_RWD_OFFSET) +#define SAM_MCAN0_CCCR (SAM_MCAN0_BASE+SAM_MCAN_CCCR_OFFSET) +#define SAM_MCAN0_BTP (SAM_MCAN0_BASE+SAM_MCAN_BTP_OFFSET) +#define SAM_MCAN0_TSCC (SAM_MCAN0_BASE+SAM_MCAN_TSCC_OFFSET) +#define SAM_MCAN0_TSCV (SAM_MCAN0_BASE+SAM_MCAN_TSCV_OFFSET) +#define SAM_MCAN0_TOCC (SAM_MCAN0_BASE+SAM_MCAN_TOCC_OFFSET) +#define SAM_MCAN0_TOCV (SAM_MCAN0_BASE+SAM_MCAN_TOCV_OFFSET) +#define SAM_MCAN0_ECR (SAM_MCAN0_BASE+SAM_MCAN_ECR_OFFSET) +#define SAM_MCAN0_PSR (SAM_MCAN0_BASE+SAM_MCAN_PSR_OFFSET) +#define SAM_MCAN0_IR (SAM_MCAN0_BASE+SAM_MCAN_IR_OFFSET) +#define SAM_MCAN0_IE (SAM_MCAN0_BASE+SAM_MCAN_IE_OFFSET) +#define SAM_MCAN0_ILS (SAM_MCAN0_BASE+SAM_MCAN_ILS_OFFSET) +#define SAM_MCAN0_ILE (SAM_MCAN0_BASE+SAM_MCAN_ILE_OFFSET) +#define SAM_MCAN0_GFC (SAM_MCAN0_BASE+SAM_MCAN_GFC_OFFSET) +#define SAM_MCAN0_SIDFC (SAM_MCAN0_BASE+SAM_MCAN_SIDFC_OFFSET) +#define SAM_MCAN0_XIDFC (SAM_MCAN0_BASE+SAM_MCAN_XIDFC_OFFSET) +#define SAM_MCAN0_XIDAM (SAM_MCAN0_BASE+SAM_MCAN_XIDAM_OFFSET) +#define SAM_MCAN0_HPMS (SAM_MCAN0_BASE+SAM_MCAN_HPMS_OFFSET) +#define SAM_MCAN0_NDAT1 (SAM_MCAN0_BASE+SAM_MCAN_NDAT1_OFFSET) +#define SAM_MCAN0_NDAT2 (SAM_MCAN0_BASE+SAM_MCAN_NDAT2_OFFSET) +#define SAM_MCAN0_RXF0C (SAM_MCAN0_BASE+SAM_MCAN_RXF0C_OFFSET) +#define SAM_MCAN0_RXF0S (SAM_MCAN0_BASE+SAM_MCAN_RXF0S_OFFSET) +#define SAM_MCAN0_RXF0A (SAM_MCAN0_BASE+SAM_MCAN_RXF0A_OFFSET) +#define SAM_MCAN0_RXBC (SAM_MCAN0_BASE+SAM_MCAN_RXBC_OFFSET) +#define SAM_MCAN0_RXF1C (SAM_MCAN0_BASE+SAM_MCAN_RXF1C_OFFSET) +#define SAM_MCAN0_RXF1S (SAM_MCAN0_BASE+SAM_MCAN_RXF1S_OFFSET) +#define SAM_MCAN0_RXF1A (SAM_MCAN0_BASE+SAM_MCAN_RXF1A_OFFSET) +#define SAM_MCAN0_RXESC (SAM_MCAN0_BASE+SAM_MCAN_RXESC_OFFSET) +#define SAM_MCAN0_TXBC (SAM_MCAN0_BASE+SAM_MCAN_TXBC_OFFSET) +#define SAM_MCAN0_TXFQS (SAM_MCAN0_BASE+SAM_MCAN_TXFQS_OFFSET) +#define SAM_MCAN0_TXESC (SAM_MCAN0_BASE+SAM_MCAN_TXESC_OFFSET) +#define SAM_MCAN0_TXBRP (SAM_MCAN0_BASE+SAM_MCAN_TXBRP_OFFSET) +#define SAM_MCAN0_TXBAR (SAM_MCAN0_BASE+SAM_MCAN_TXBAR_OFFSET) +#define SAM_MCAN0_TXBCR (SAM_MCAN0_BASE+SAM_MCAN_TXBCR_OFFSET) +#define SAM_MCAN0_TXBTO (SAM_MCAN0_BASE+SAM_MCAN_TXBTO_OFFSET) +#define SAM_MCAN0_TXBCF (SAM_MCAN0_BASE+SAM_MCAN_TXBCF_OFFSET) +#define SAM_MCAN0_TXBTIE (SAM_MCAN0_BASE+SAM_MCAN_TXBTIE_OFFSET) +#define SAM_MCAN0_TXBCIE (SAM_MCAN0_BASE+SAM_MCAN_TXBCIE_OFFSET) +#define SAM_MCAN0_TXEFC (SAM_MCAN0_BASE+SAM_MCAN_TXEFC_OFFSET) +#define SAM_MCAN0_TXEFS (SAM_MCAN0_BASE+SAM_MCAN_TXEFS_OFFSET) +#define SAM_MCAN0_TXEFA (SAM_MCAN0_BASE+SAM_MCAN_TXEFA_OFFSET) + +#define SAM_MCAN1_CUST (SAM_MCAN1_BASE+SAM_MCAN_CUST_OFFSET) +#define SAM_MCAN1_FBTP (SAM_MCAN1_BASE+SAM_MCAN_FBTP_OFFSET) +#define SAM_MCAN1_TEST (SAM_MCAN1_BASE+SAM_MCAN_TEST_OFFSET) +#define SAM_MCAN1_RWD (SAM_MCAN1_BASE+SAM_MCAN_RWD_OFFSET) +#define SAM_MCAN1_CCCR (SAM_MCAN1_BASE+SAM_MCAN_CCCR_OFFSET) +#define SAM_MCAN1_BTP (SAM_MCAN1_BASE+SAM_MCAN_BTP_OFFSET) +#define SAM_MCAN1_TSCC (SAM_MCAN1_BASE+SAM_MCAN_TSCC_OFFSET) +#define SAM_MCAN1_TSCV (SAM_MCAN1_BASE+SAM_MCAN_TSCV_OFFSET) +#define SAM_MCAN1_TOCC (SAM_MCAN1_BASE+SAM_MCAN_TOCC_OFFSET) +#define SAM_MCAN1_TOCV (SAM_MCAN1_BASE+SAM_MCAN_TOCV_OFFSET) +#define SAM_MCAN1_ECR (SAM_MCAN1_BASE+SAM_MCAN_ECR_OFFSET) +#define SAM_MCAN1_PSR (SAM_MCAN1_BASE+SAM_MCAN_PSR_OFFSET) +#define SAM_MCAN1_IR (SAM_MCAN1_BASE+SAM_MCAN_IR_OFFSET) +#define SAM_MCAN1_IE (SAM_MCAN1_BASE+SAM_MCAN_IE_OFFSET) +#define SAM_MCAN1_ILS (SAM_MCAN1_BASE+SAM_MCAN_ILS_OFFSET) +#define SAM_MCAN1_ILE (SAM_MCAN1_BASE+SAM_MCAN_ILE_OFFSET) +#define SAM_MCAN1_GFC (SAM_MCAN1_BASE+SAM_MCAN_GFC_OFFSET) +#define SAM_MCAN1_SIDFC (SAM_MCAN1_BASE+SAM_MCAN_SIDFC_OFFSET) +#define SAM_MCAN1_XIDFC (SAM_MCAN1_BASE+SAM_MCAN_XIDFC_OFFSET) +#define SAM_MCAN1_XIDAM (SAM_MCAN1_BASE+SAM_MCAN_XIDAM_OFFSET) +#define SAM_MCAN1_HPMS (SAM_MCAN1_BASE+SAM_MCAN_HPMS_OFFSET) +#define SAM_MCAN1_NDAT1 (SAM_MCAN1_BASE+SAM_MCAN_NDAT1_OFFSET) +#define SAM_MCAN1_NDAT2 (SAM_MCAN1_BASE+SAM_MCAN_NDAT2_OFFSET) +#define SAM_MCAN1_RXF0C (SAM_MCAN1_BASE+SAM_MCAN_RXF0C_OFFSET) +#define SAM_MCAN1_RXF0S (SAM_MCAN1_BASE+SAM_MCAN_RXF0S_OFFSET) +#define SAM_MCAN1_RXF0A (SAM_MCAN1_BASE+SAM_MCAN_RXF0A_OFFSET) +#define SAM_MCAN1_RXBC (SAM_MCAN1_BASE+SAM_MCAN_RXBC_OFFSET) +#define SAM_MCAN1_RXF1C (SAM_MCAN1_BASE+SAM_MCAN_RXF1C_OFFSET) +#define SAM_MCAN1_RXF1S (SAM_MCAN1_BASE+SAM_MCAN_RXF1S_OFFSET) +#define SAM_MCAN1_RXF1A (SAM_MCAN1_BASE+SAM_MCAN_RXF1A_OFFSET) +#define SAM_MCAN1_RXESC (SAM_MCAN1_BASE+SAM_MCAN_RXESC_OFFSET) +#define SAM_MCAN1_TXBC (SAM_MCAN1_BASE+SAM_MCAN_TXBC_OFFSET) +#define SAM_MCAN1_TXFQS (SAM_MCAN1_BASE+SAM_MCAN_TXFQS_OFFSET) +#define SAM_MCAN1_TXESC (SAM_MCAN1_BASE+SAM_MCAN_TXESC_OFFSET) +#define SAM_MCAN1_TXBRP (SAM_MCAN1_BASE+SAM_MCAN_TXBRP_OFFSET) +#define SAM_MCAN1_TXBAR (SAM_MCAN1_BASE+SAM_MCAN_TXBAR_OFFSET) +#define SAM_MCAN1_TXBCR (SAM_MCAN1_BASE+SAM_MCAN_TXBCR_OFFSET) +#define SAM_MCAN1_TXBTO (SAM_MCAN1_BASE+SAM_MCAN_TXBTO_OFFSET) +#define SAM_MCAN1_TXBCF (SAM_MCAN1_BASE+SAM_MCAN_TXBCF_OFFSET) +#define SAM_MCAN1_TXBTIE (SAM_MCAN1_BASE+SAM_MCAN_TXBTIE_OFFSET) +#define SAM_MCAN1_TXBCIE (SAM_MCAN1_BASE+SAM_MCAN_TXBCIE_OFFSET) +#define SAM_MCAN1_TXEFC (SAM_MCAN1_BASE+SAM_MCAN_TXEFC_OFFSET) +#define SAM_MCAN1_TXEFS (SAM_MCAN1_BASE+SAM_MCAN_TXEFS_OFFSET) +#define SAM_MCAN1_TXEFA (SAM_MCAN1_BASE+SAM_MCAN_TXEFA_OFFSET) + +/* MCAN register bit definitions ********************************************/ + +/* Customer Register (32-bit value) */ + +/* Fast Bit Timing and Prescaler Register */ + +#define MCAN_FBTP_FSJW_SHIFT (0) /* Bits 0-2: Fast (Re) Synchronization Jump Width */ +#define MCAN_FBTP_FSJW_MASK (7 << MCAN_FBTP_FSJW_SHIFT) +# define MCAN_FBTP_FSJW(n) ((uint32_t)(n) << MCAN_FBTP_FSJW_SHIFT) +#define MCAN_FBTP_FTSEG2_SHIFT (4) /* Bits 4-6: Fast Time Segment After Sample Point */ +#define MCAN_FBTP_FTSEG2_MASK (0xf << MCAN_FBTP_FTSEG2_SHIFT) +# define MCAN_FBTP_FTSEG2(n) ((uint32_t)(n) << MCAN_FBTP_FTSEG2_SHIFT) +#define MCAN_FBTP_FTSEG1_SHIFT (8) /* Bits 8-11: Fast Time Segment Before Sample Point */ +#define MCAN_FBTP_FTSEG1_MASK (0x1f << MCAN_FBTP_FTSEG1_SHIFT) +# define MCAN_FBTP_FTSEG1(n) ((uint32_t)(n) << MCAN_FBTP_FTSEG1_SHIFT) +#define MCAN_FBTP_FBRP_SHIFT (16) /* Bits 16-20: Fast Baud Rate Prescaler */ +#define MCAN_FBTP_FBRP_MASK (0x1f << MCAN_FBTP_FBRP_SHIFT) +# define MCAN_FBTP_FBRP(n) ((uint32_t)(n) << MCAN_FBTP_FBRP_SHIFT) +#define MCAN_FBTP_TDC (1 << 23) /* Bit: 23: Transceiver Delay Compensation */ +#define MCAN_FBTP_TDCO_SHIFT (24) /* Bits 24-28: Transceiver Delay Compensation Offset */ +#define MCAN_FBTP_TDCO_MASK (1 << MCAN_FBTP_TDC_SHIFT) +# define MCAN_FBTP_TDCO(n) ((uint32_t)(n) << MCAN_FBTP_TDC_SHIFT) + +/* Test Register */ + +#define MCAN_TEST_LBCK (1 << 4) /* Bit 4: Loop Back Mode */ +#define MCAN_TEST_TX_SHIFT (5) /* Bits 5-6: Control of Transmit Pin */ +#define MCAN_TEST_TX_MASK (3 << MCAN_TEST_TX_SHIFT) +# define MCAN_TEST_TX_RESET (0 << MCAN_TEST_TX_SHIFT) /* Reset value */ +# define MCAN_TEST_TX_SPMON (1 << MCAN_TEST_TX_SHIFT) /* Sample Point can be monitored at CANTX */ +# define MCAN_TEST_TX_DOMINANT (2 << MCAN_TEST_TX_SHIFT) /* Dominant (0) level at CANTX. */ +# define MCAN_TEST_TX_RECESSIVE (3 << MCAN_TEST_TX_SHIFT) /* Recessive (1) at CANTX. */ + +#define MCAN_TEST_RX (1 << 7) /* Bit 7: Receive Pin */ +#define MCAN_TEST_TDCV_SHIFT (8) /* Bits 8-13: Transceiver Delay Compensation Value */ +#define MCAN_TEST_TDCV_MASK (0x3f << MCAN_TEST_TDCV_SHIFT) +# define MCAN_TEST_TDCV(n) ((uint32_t)(n) << MCAN_TEST_TDCV_SHIFT) + +/* RAM Watchdog Register */ + +#define MCAN_RWD_WDC_SHIFT (0) /* Bits 0-7: Watchdog Configuration */ +#define MCAN_RWD_WDC_MASK (0xff << MCAN_RWD_WDC_SHIFT) +# define MCAN_RWD_WDC(n) ((uint32_t)(n) << MCAN_RWD_WDC_SHIFT) +#define MCAN_RWD_WDV_SHIFT (8) /* Bits 8-15: Watchdog Value */ +#define MCAN_RWD_WDV_MASK (0xff << MCAN_RWD_WDV_SHIFT) +# define MCAN_RWD_WDV(n) ((uint32_t)(n) << MCAN_RWD_WDV_SHIFT) + +/* CC Control Register */ + +#define MCAN_CCCR_INIT (1 << 0) /* Bit 0: Initialization */ +#define MCAN_CCCR_CCE (1 << 1) /* Bit 1: Configuration Change Enable */ +#define MCAN_CCCR_ASM (1 << 2) /* Bit 2: Restricted Operation Mode */ +#define MCAN_CCCR_CSA (1 << 3) /* Bit 3: Clock Stop Acknowledge */ +#define MCAN_CCCR_CSR (1 << 4) /* Bit 4: Clock Stop Request */ +#define MCAN_CCCR_MON (1 << 5) /* Bit 5: Bus Monitoring Mode */ +#define MCAN_CCCR_DAR (1 << 6) /* Bit 6: Disable Automatic Retransmission */ +#define MCAN_CCCR_TEST (1 << 7) /* Bit 7: Test Mode Enable */ +#define MCAN_CCCR_CME_SHIFT (8) /* Bits 8-9: CAN Mode Enable */ +#define MCAN_CCCR_CME_MASK (3 << MCAN_CCCR_CME_SHIFT) +# define MCAN_CCCR_CME_ISO11898_1 (0 << MCAN_CCCR_CME_SHIFT) /* CAN operation according to ISO11898-1 enabled */ +# define MCAN_CCCR_CME_FD (1 << MCAN_CCCR_CME_SHIFT) /* CAN FD operation enabled */ +# define MCAN_CCCR_CME_FD_BSW (2 << MCAN_CCCR_CME_SHIFT) /* CAN FD operation with bit rate switching enabled */ + +#define MCAN_CCCR_CMR_SHIFT (10) /* Bits 10-11: CAN Mode Request */ +#define MCAN_CCCR_CMR_MASK (3 << MCAN_CCCR_CMR_SHIFT) +# define MCAN_CCCR_CMR_NOCHG (0 << MCAN_CCCR_CMR_SHIFT) /* No mode change */ +# define MCAN_CCCR_CMR_FD (1 << MCAN_CCCR_CMR_SHIFT) /* Request CAN FD operation */ +# define MCAN_CCCR_CMR_FD_BSW (2 << MCAN_CCCR_CMR_SHIFT) /* Request CAN FD operation with bit rate switching */ +# define MCAN_CCCR_CMR_ISO11898_1 (3 << MCAN_CCCR_CMR_SHIFT) /* Request CAN operation according ISO11898-1 */ + +#define MCAN_CCCR_FDO (1 << 12) /* Bit 12: CAN FD Operation */ +#define MCAN_CCCR_FDBS (1 << 13) /* Bit 13: CAN FD Bit Rate Switching */ +#define MCAN_CCCR_TXP (1 << 14) /* Bit 14: Transmit Pause */ + +/* Nominal Bit Timing and Prescaler Register */ + +#define MCAN_BTP_SJW_SHIFT (25) /* Bits 25..31: (Re) Synchronization Jump Width */ +#define MCAN_BTP_SJW_MASK (0x7f << MCAN_BTP_SJW_SHIFT) +#define MCAN_BTP_SJW(n) ((uint32_t)(n) << MCAN_BTP_SJW_SHIFT) +#define MCAN_BTP_TSEG2_SHIFT (0) /* Bits 4-7: Time Segment After Sample Point */ +#define MCAN_BTP_TSEG2_MASK (0x7f << MCAN_BTP_TSEG2_SHIFT) +#define MCAN_BTP_TSEG2(n) ((uint32_t)(n) << MCAN_BTP_TSEG2_SHIFT) +#define MCAN_BTP_TSEG1_SHIFT (8) /* Bits 8-13: Time Segment Before Sample Point */ +#define MCAN_BTP_TSEG1_MASK (0xff << MCAN_BTP_TSEG1_SHIFT) +#define MCAN_BTP_TSEG1(n) ((uint32_t)(n) << MCAN_BTP_TSEG1_SHIFT) +#define MCAN_BTP_BRP_SHIFT (16) /* Bits 16-24: Baud Rate Prescaler */ +#define MCAN_BTP_BRP_MASK (0x1ff << MCAN_BTP_BRP_SHIFT) +#define MCAN_BTP_BRP(n) ((uint32_t)(n) << MCAN_BTP_BRP_SHIFT) + +/* Timestamp Counter Configuration Register */ + +#define MCAN_TSCC_TSS_SHIFT (0) /* Bits 0-1: Timestamp Select */ +#define MCAN_TSCC_TSS_MASK (3 << MCAN_TSCC_TSS_SHIFT) +# define MCAN_TSCC_TSS_ ZERO (0 << MCAN_TSCC_TSS_SHIFT) /* Timestamp counter value always 0x0000 */ +# define MCAN_TSCC_TSS_TCP_INC (1 << MCAN_TSCC_TSS_SHIFT) /* Timestamp counter value incremented according to TCP */ +# define MCAN_TSCC_TSS_EXT_TS (2 << MCAN_TSCC_TSS_SHIFT) /* External timestamp counter value used */ + +#define MCAN_TSCC_TCP_SHIFT (16) /* Bits 16-19: Timestamp Counter Prescaler */ +#define MCAN_TSCC_TCP_MASK (15 << MCAN_TSCC_TCP_SHIFT) +# define MCAN_TSCC_TCP(n) ((uint32_t)(n) << MCAN_TSCC_TCP_SHIFT) + +/* Timestamp Counter Value Register */ + +#define MCAN_TSCV_MASK 0x0000ffff /* Timestamp counter mask */ + +/* Timeout Counter Configuration Register */ + +#define MCAN_TOCC_ETOC (1 << 0) /* Bit 0: Enable Timeout Counter */ +#define MCAN_TOCC_TOS_SHIFT (1) /* Bits 1-2: Timeout Select */ +#define MCAN_TOCC_TOS_MASK (3 << MCAN_TOCC_TOS_SHIFT) +# define MCAN_TOCC_TOS_CONTINUOUS (0 << MCAN_TOCC_TOS_SHIFT) /* Continuous operation */ +# define MCAN_TOCC_TOS_TX_TIMEOUT (1 << MCAN_TOCC_TOS_SHIFT) /* Timeout controlled by Tx Event FIFO */ +# define MCAN_TOCC_TOS_RX0_TIMEOUT (2 << MCAN_TOCC_TOS_SHIFT) /* Timeout controlled by Receive FIFO 0 */ +# define MCAN_TOCC_TOS_RX1_TIMEOUT (3 << MCAN_TOCC_TOS_SHIFT) /* Timeout controlled by Receive FIFO 1 */ + +#define MCAN_TOCC_TOP_SHIFT (16) /* Bits 16-31: Timeout Period */ +#define MCAN_TOCC_TOP_MASK (0xffff << MCAN_TOCC_TOP_SHIFT) +# define MCAN_TOCC_TOP(n) ((uint32_t)(n) << MCAN_TOCC_TOP_SHIFT) + +/* Timeout Counter Value Register */ + +#define MCAN_TOCV_MASK 0x0000ffff /* Timeout counter mask */ + +/* Error Counter Register */ + +#define MCAN_ECR_TEC_SHIFT (0) /* Bits 0-7: Transmit Error Counter */ +#define MCAN_ECR_TEC_MASK (0xff << MCAN_ECR_TEC_SHIFT) +# define MCAN_ECR_TEC(n) ((uint32_t)(n) << MCAN_ECR_TEC_SHIFT) +#define MCAN_ECR_REC_SHIFT (8) /* Bits 8-14: Receive Error Counter */ +#define MCAN_ECR_REC_MASK (0x7f << MCAN_ECR_REC_SHIFT) +# define MCAN_ECR_REC(n) ((uint32_t)(n) << MCAN_ECR_REC_SHIFT) +#define MCAN_ECR_RP (1 << 15) /* Bit 15: Receive Error Passive */ +#define MCAN_ECR_CEL_SHIFT (16) /* Bits 16-23: CAN Error Logging */ +#define MCAN_ECR_CEL_MASK (0xff << MCAN_ECR_CEL_SHIFT) +# define MCAN_ECR_CEL(n) ((uint32_t)(n) << MCAN_ECR_CEL_SHIFT) + +/* Protocol Status Register */ + +/* Error codes */ + +#define MCAN_PSR_EC_NO_ERROR (0) /* No error occurred since LEC has been reset */ +#define MCAN_PSR_EC_STUFF_ERROR (1) /* More than 5 equal bits in a sequence */ +#define MCAN_PSR_EC_FORM_ERROR (2) /* Part of a received frame has wrong format */ +#define MCAN_PSR_EC_ACK_ERROR (3) /* Message not acknowledged by another node */ +#define MCAN_PSR_EC_BIT1_ERROR (4) /* Send with recessive level, but bus value was dominant */ +#define MCAN_PSR_EC_BIT0_ERROR (5) /* Send with dominant level, but bus value was recessive */ +#define MCAN_PSR_EC_CRC_ERROR (6) /* CRC received message incorrect */ +#define MCAN_PSR_EC_NO_CHANGE (7) /* No CAN bus event was detected since last read */ + +#define MCAN_PSR_LEC_SHIFT (0) /* Bits 0-2: Last Error Code */ +#define MCAN_PSR_LEC_MASK (7 << MCAN_PSR_LEC_SHIFT) +# define MCAN_PSR_LEC(n) ((uint32_t)(n) << MCAN_PSR_LEC_SHIFT) /* See error codes above */ + +#define MCAN_PSR_ACT_SHIFT (3) /* Bits 3-4: Activity */ +#define MCAN_PSR_ACT_MASK (3 << MCAN_PSR_ACT_SHIFT) +# define MCAN_PSR_ACT_SYNCHING (0 << MCAN_PSR_ACT_SHIFT) /* Node is synchronizing on CAN communication */ +# define MCAN_PSR_ACT_IDLE (1 << MCAN_PSR_ACT_SHIFT) /* Node is neither receiver nor transmitter */ +# define MCAN_PSR_ACT_RECEIVER (2 << MCAN_PSR_ACT_SHIFT) /* Node is operating as receiver */ +# define MCAN_PSR_ACT_TRANSMITTER (3 << MCAN_PSR_ACT_SHIFT) /* Node is operating as transmitter */ + +#define MCAN_PSR_EP (1 << 5) /* Bit 5: Error Passive */ +#define MCAN_PSR_EW (1 << 6) /* Bit 6: Warning Status */ +#define MCAN_PSR_BO (1 << 7) /* Bit 7: Bus_Off Status */ +#define MCAN_PSR_FLEC_SHIFT (8) /* Bits 8-10: Fast Last Error Code */ +#define MCAN_PSR_FLEC_MASK (7 << MCAN_PSR_FLEC_SHIFT) +# define MCAN_PSR_FLEC(n) ((uint32_t)(n) << MCAN_PSR_FLEC_SHIFT) /* See error codes above */ + +#define MCAN_PSR_RESI (1 << 11) /* Bit 11: ESI Flag of Last Received CAN FD Message */ +#define MCAN_PSR_RBRS (1 << 12) /* Bit 12: BRS Flag of Last Received CAN FD Message */ +#define MCAN_PSR_REDL (1 << 13) /* Bit 13: Received a CAN FD Message */ + +/* Common bit definitions for Interrupt Register, Interrupt Enable Register, + * Interrupt Line Select Register + */ + +#define MCAN_INT_RF0N (1 << 0) /* Bit 0: Receive FIFO 0 New Message */ +#define MCAN_INT_RF0W (1 << 1) /* Bit 1: Receive FIFO 0 Watermark Reached */ +#define MCAN_INT_RF0F (1 << 2) /* Bit 2: Receive FIFO 0 Full */ +#define MCAN_INT_RF0L (1 << 3) /* Bit 3: Receive FIFO 0 Message Lost */ +#define MCAN_INT_RF1N (1 << 4) /* Bit 4: Receive FIFO 1 New Message */ +#define MCAN_INT_RF1W (1 << 5) /* Bit 5: Receive FIFO 1 Watermark Reached */ +#define MCAN_INT_RF1F (1 << 6) /* Bit 6: Receive FIFO 1 Full */ +#define MCAN_INT_RF1L (1 << 7) /* Bit 7: Receive FIFO 1 Message Lost */ +#define MCAN_INT_HPM (1 << 8) /* Bit 8: High Priority Message Received */ +#define MCAN_INT_TC (1 << 9) /* Bit 9: Transmission Completed */ +#define MCAN_INT_TCF (1 << 10) /* Bit 10: Transmission Cancellation Finished */ +#define MCAN_INT_TFE (1 << 11) /* Bit 11: Tx FIFO Empty */ +#define MCAN_INT_TEFN (1 << 12) /* Bit 12: Tx Event FIFO New Entry */ +#define MCAN_INT_TEFW (1 << 13) /* Bit 13: Tx Event FIFO Watermark Reached */ +#define MCAN_INT_TEFF (1 << 14) /* Bit 14: Tx Event FIFO Full */ +#define MCAN_INT_TEFL (1 << 15) /* Bit 15: Tx Event FIFO Element Lost */ +#define MCAN_INT_TSW (1 << 16) /* Bit 16: Timestamp Wraparound */ +#define MCAN_INT_MRAF (1 << 17) /* Bit 17: Message RAM Access Failure */ +#define MCAN_INT_TOO (1 << 18) /* Bit 18: Timeout Occurred */ +#define MCAN_INT_DRX (1 << 19) /* Bit 19: Message stored to Dedicated Receive Buffer */ +#define MCAN_INT_ELO (1 << 22) /* Bit 22: Error Logging Overflow */ +#define MCAN_INT_EP (1 << 23) /* Bit 23: Error Passive */ +#define MCAN_INT_EW (1 << 24) /* Bit 24: Warning Status */ +#define MCAN_INT_BO (1 << 25) /* Bit 25: Bus_Off Status */ +#define MCAN_INT_WDI (1 << 26) /* Bit 26: Watchdog Interrupt */ +#define MCAN_INT_CRCE (1 << 27) /* Bit 27: Receive CRC Error */ +#define MCAN_INT_BE (1 << 28) /* Bit 28: Bit Error */ +#define MCAN_INT_ACKE (1 << 29) /* Bit 29: Acknowledge Error */ +#define MCAN_INT_FOE (1 << 30) /* Bit 30: Format Error */ +#define MCAN_INT_STE (1 << 31) /* Bit 31: Stuff Error */ + +#define MCAN_INT_ALL (0xffcfffff) + +/* Interrupt Line Enable Register */ + +#define MCAN_ILE_EINT0 (1 << 0) /* Bit 0: Enable Interrupt Line 0 */ +#define MCAN_ILE_EINT1 (1 << 1) /* Bit 1: Enable Interrupt Line 1 */ + +/* Global Filter Configuration Register */ + +#define MCAN_GFC_RRFE (1 << 0) /* Bit 0: Reject Remote Frames Extended */ +#define MCAN_GFC_RRFS (1 << 1) /* Bit 1: Reject Remote Frames Standard */ +#define MCAN_GFC_ANFE_SHIFT (2) /* Bits 2-3: Accept Non-matching Frames Extended */ +#define MCAN_GFC_ANFE_MASK (3 << MCAN_GFC_ANFE_SHIFT) +# define MCAN_GFC_ANFE_RX_FIFO0 (0 << MCAN_GFC_ANFE_SHIFT) /* Message stored in Receive FIFO 0 */ +# define MCAN_GFC_ANFE_RX_FIFO1 (1 << MCAN_GFC_ANFE_SHIFT) /* Message stored in Receive FIFO 1 */ +# define MCAN_GFC_ANFE_REJECTED (2 << MCAN_GFC_ANFE_SHIFT) /* 2-3 Message rejected */ + +#define MCAN_GFC_ANFS_SHIFT (4) /* Bits 4-5: Accept Non-matching Frames Standard */ +#define MCAN_GFC_ANFS_MASK (3 << MCAN_GFC_ANFS_SHIFT) +# define MCAN_GFC_ANFS_RX_FIFO0 (0 << MCAN_GFC_ANFS_SHIFT) /* Message stored in Receive FIFO 0 */ +# define MCAN_GFC_ANFS_RX_FIFO1 (1 << MCAN_GFC_ANFS_SHIFT) /* Message stored in Receive FIFO 1 */ +# define MCAN_GFC_ANFS_REJECTED (2 << MCAN_GFC_ANFS_SHIFT) /* 2-3 Message rejected */ + +/* Standard ID Filter Configuration Register */ + +#define MCAN_SIDFC_FLSSA_SHIFT (2) /* Bits 2-15: Filter List Standard Start Address */ +#define MCAN_SIDFC_FLSSA_MASK (0x3fff << MCAN_SIDFC_FLSSA_SHIFT) +# define MCAN_SIDFC_FLSSA(n) ((uint32_t)(n) << MCAN_SIDFC_FLSSA_SHIFT) +#define MCAN_SIDFC_LSS_SHIFT (16) /* Bits 16-23: List Size Standard */ +#define MCAN_SIDFC_LSS_MASK (0xff << MCAN_SIDFC_LSS_SHIFT) +# define MCAN_SIDFC_LSS(n) ((uint32_t)(n) << MCAN_SIDFC_LSS_SHIFT) + +/* Extended ID Filter Configuration Register */ + +#define MCAN_XIDFC_FLESA_SHIFT (2) /* Bits 2-15: Filter List Extended Start Address */ +#define MCAN_XIDFC_FLESA_MASK (0x3fff << MCAN_XIDFC_FLESA_SHIFT) +# define MCAN_XIDFC_FLESA(n) ((uint32_t)(n) << MCAN_XIDFC_FLESA_SHIFT) +#define MCAN_XIDFC_LSE_SHIFT (16) /* Bits 16-22: List Size Extended */ +#define MCAN_XIDFC_LSE_MASK (0x7f << MCAN_XIDFC_LSE_SHIFT) +# define MCAN_XIDFC_LSE(n) ((uint32_t)(n) << MCAN_XIDFC_LSE_SHIFT) + +/* Extended ID AND Mask Register */ + +#define MCAN_XIDAM_MASK 0x1fffffff /* Extended ID mask */ + +/* High Priority Message Status Register */ + +#define MCAN_HPMS_BIDX_SHIFT (0) /* Bits 0-5: Buffer Index */ +#define MCAN_HPMS_BIDX_MASK (0x3f << MCAN_HPMS_BIDX_SHIFT) +# define MCAN_HPMS_BIDX(n) ((uint32_t)(n) << MCAN_HPMS_BIDX_SHIFT) +#define MCAN_HPMS_MSI_SHIFT (6) /* Bits 6-7: Message Storage Indicator */ +#define MCAN_HPMS_MSI_MASK (3 << MCAN_HPMS_MSI_SHIFT) +# define MCAN_HPMS_MSI_NOFIFO (0 << MCAN_HPMS_MSI_SHIFT) /* No FIFO selected. */ +# define MCAN_HPMS_MSI_LOST (1 << MCAN_HPMS_MSI_SHIFT) /* FIFO message. */ +# define MCAN_HPMS_MSI_FIFO0 (2 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 0. */ +# define MCAN_HPMS_MSI_FIFO1 (3 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 1. */ + +#define MCAN_HPMS_FIDX_SHIFT (8) /* Bits 8-14: Filter Index */ +#define MCAN_HPMS_FIDX_MASK (0x7f << MCAN_HPMS_FIDX_SHIFT) +# define MCAN_HPMS_FIDX(n) ((uint32_t)(n) << MCAN_HPMS_FIDX_SHIFT) +#define MCAN_HPMS_FLST (1 << 15) /* Bit 15: Filter List */ + +/* New Data 1 Register */ + +#define MCAN_NDAT1(n) (1 << (n)) /* New data for buffer n, n=0-31 */ + +/* New Data 2 Register */ + +#define MCAN_NDAT2(n) (1 << ((n)-32)) /* New data for buffer n, n=32-63 */ + +/* Receive FIFO 0 Configuration Register */ + +#define MCAN_RXF0C_F0SA_SHIFT (2) /* Bits 2-15: Receive FIFO 0 Start Address */ +#define MCAN_RXF0C_F0SA_MASK (0x3fff << MCAN_RXF0C_F0SA_SHIFT) +# define MCAN_RXF0C_F0SA(n) ((uint32_t)(n) << MCAN_RXF0C_F0SA_SHIFT) +#define MCAN_RXF0C_F0S_SHIFT (16) /* Bits 16-22: Receive FIFO 0 Size */ +#define MCAN_RXF0C_F0S_MASK (0x7f << MCAN_RXF0C_F0S_SHIFT) +# define MCAN_RXF0C_F0S(n) ((uint32_t)(n) << MCAN_RXF0C_F0S_SHIFT) +#define MCAN_RXF0C_F0WM_SHIFT (24) /* Bits 24-30: Receive FIFO 0 Watermark */ +#define MCAN_RXF0C_F0WM_MASK (0x7f << MCAN_RXF0C_F0WM_SHIFT) +# define MCAN_RXF0C_F0WM(n) ((uint32_t)(n) << MCAN_RXF0C_F0WM_SHIFT) +#define MCAN_RXF0C_F0OM (1 << 31) /* Bit 31: FIFO 0 Operation Mode */ + +/* Receive FIFO 0 Status Register */ + +#define MCAN_RXF0S_F0FL_SHIFT (0) /* Bits 0-6: Receive FIFO 0 Fill Level */ +#define MCAN_RXF0S_F0FL_MASK (0x7f << MCAN_RXF0S_F0FL_SHIFT) +# define MCAN_RXF0S_F0FL(n) ((uint32_t)(n) << MCAN_RXF0S_F0FL_SHIFT) +#define MCAN_RXF0S_F0GI_SHIFT (8) /* Bits 8-13: Receive FIFO 0 Get Index */ +#define MCAN_RXF0S_F0GI_MASK (0x3f << MCAN_RXF0S_F0GI_SHIFT) +# define MCAN_RXF0S_F0GI(n) ((uint32_t)(n) << MCAN_RXF0S_F0GI_SHIFT) +#define MCAN_RXF0S_F0PI_SHIFT (16) /* Bits 16-21: Receive FIFO 0 Put Index */ +#define MCAN_RXF0S_F0PI_MASK (0x3f << MCAN_RXF0S_F0PI_SHIFT) +# define MCAN_RXF0S_F0PI(n) ((uint32_t)(n) << MCAN_RXF0S_F0PI_SHIFT) +#define MCAN_RXF0S_F0F (1 << 24) /* Bit 24: Receive FIFO 0 Full */ +#define MCAN_RXF0S_RF0L (1 << 25) /* Bit 25: Receive FIFO 0 Message Lost */ + +/* Receive FIFO 0 Acknowledge Register */ + +#define MCAN_RXF0A_MASK 0x0000003f /* Receive FIFO 0 acknowledge index mask */ + +/* Receive Rx Buffer Configuration Register */ + +#define MCAN_RXBC_MASK 0x0000fffc /* Receive buffer start address mask */ + +/* Receive FIFO 1 Configuration Register */ + +#define MCAN_RXF1C_F1SA_SHIFT (2) /* Bits 2-15: Receive FIFO 1 Start Address */ +#define MCAN_RXF1C_F1SA_MASK (0x3fff << MCAN_RXF1C_F1SA_SHIFT) +# define MCAN_RXF1C_F1SA(n) ((uint32_t)(n) << MCAN_RXF1C_F1SA_SHIFT) +#define MCAN_RXF1C_F1S_SHIFT (16) /* Bits 16-22: Receive FIFO 1 Size */ +#define MCAN_RXF1C_F1S_MASK (0x7f << MCAN_RXF1C_F1S_SHIFT) +# define MCAN_RXF1C_F1S(n) ((uint32_t)(n) << MCAN_RXF1C_F1S_SHIFT) +#define MCAN_RXF1C_F1WM_SHIFT (24) /* Bits 24-30: Receive FIFO 1 Watermark */ +#define MCAN_RXF1C_F1WM_MASK (0x7f << MCAN_RXF1C_F1WM_SHIFT) +# define MCAN_RXF1C_F1WM(n) ((uint32_t)(n) << MCAN_RXF1C_F1WM_SHIFT) +#define MCAN_RXF1C_F1OM (1 << 31) /* Bit 31: FIFO 1 Operation Mode */ + +/* Receive FIFO 1 Status Register */ + +#define MCAN_RXF1S_F1FL_SHIFT (0) /* Bits 0-6: Receive FIFO 1 Fill Level */ +#define MCAN_RXF1S_F1FL_MASK (0x7f << MCAN_RXF1S_F1FL_SHIFT) +# define MCAN_RXF1S_F1FL(n) ((uint32_t)(n) << MCAN_RXF1S_F1FL_SHIFT) +#define MCAN_RXF1S_F1GI_SHIFT (8) /* Bits 8-13: Receive FIFO 1 Get Index */ +#define MCAN_RXF1S_F1GI_MASK (0x3f << MCAN_RXF1S_F1GI_SHIFT) +# define MCAN_RXF1S_F1GI(n) ((uint32_t)(n) << MCAN_RXF1S_F1GI_SHIFT) +#define MCAN_RXF1S_F1PI_SHIFT (16) /* Bits 16-21: Receive FIFO 1 Put Index */ +#define MCAN_RXF1S_F1PI_MASK (0x3f << MCAN_RXF1S_F1PI_SHIFT) +# define MCAN_RXF1S_F1PI(n) ((uint32_t)(n) << MCAN_RXF1S_F1PI_SHIFT) +#define MCAN_RXF1S_F1F (1 << 24) /* Bit 24: Receive FIFO 1 Full */ +#define MCAN_RXF1S_RF1L (1 << 25) /* Bit 25: Receive FIFO 1 Message Lost */ +#define MCAN_RXF1S_DMS_SHIFT (30) /* Bits 30-31: Debug Message Status */ +#define MCAN_RXF1S_DMS_MASK (3 << MCAN_RXF1S_DMS_SHIFT) +# define MCAN_RXF1S_DMS_IDLE (0 << MCAN_RXF1S_DMS_SHIFT) /* Idle state */ +# define MCAN_RXF1S_DMS_MSG_A (1 << MCAN_RXF1S_DMS_SHIFT) /* Debug message A received. */ +# define MCAN_RXF1S_DMS_MSG_AB (2 << MCAN_RXF1S_DMS_SHIFT) /* Debug messages A, B received. */ +# define MCAN_RXF1S_DMS_MSG_ABC (3 << MCAN_RXF1S_DMS_SHIFT) /* Debug messages A, B, C received, DMA request is set. */ + +/* Receive FIFO 1 Acknowledge Register */ + +#define MCAN_RXF1A_MASK 0x0000003f /* Receive FIFO 1 acknowledge index mask */ + +/* Receive Buffer / FIFO Element Size Configuration Register */ + +#define MCAN_RXESC_F0DS_SHIFT (0) /* Bits 0-2: Receive FIFO 0 Data Field Size */ +#define MCAN_RXESC_F0DS_MASK (7 << MCAN_RXESC_F0DS_SHIFT) +# define MCAN_RXESC_F0DS(n) ((uint32_t)(n) << MCAN_RXESC_F0DS_SHIFT) +# define MCAN_RXESC_F0DS_8B (0 << MCAN_RXESC_F0DS_SHIFT) /* 8-byte data field */ +# define MCAN_RXESC_F0DS_12B (1 << MCAN_RXESC_F0DS_SHIFT) /* 12-byte data field */ +# define MCAN_RXESC_F0DS_16B (2 << MCAN_RXESC_F0DS_SHIFT) /* 16-byte data field */ +# define MCAN_RXESC_F0DS_20B (3 << MCAN_RXESC_F0DS_SHIFT) /* 20-byte data field */ +# define MCAN_RXESC_F0DS_24B (4 << MCAN_RXESC_F0DS_SHIFT) /* 24-byte data field */ +# define MCAN_RXESC_F0DS_32B (5 << MCAN_RXESC_F0DS_SHIFT) /* 32-byte data field */ +# define MCAN_RXESC_F0DS_48B (6 << MCAN_RXESC_F0DS_SHIFT) /* 48-byte data field */ +# define MCAN_RXESC_F0DS_64B (7 << MCAN_RXESC_F0DS_SHIFT) /* 64-byte data field */ + +#define MCAN_RXESC_F1DS_SHIFT (4) /* Bits 4-6: Receive FIFO 1 Data Field Size */ +#define MCAN_RXESC_F1DS_MASK (7 << MCAN_RXESC_F1DS_SHIFT) +# define MCAN_RXESC_F1DS(n) ((uint32_t)(n) << MCAN_RXESC_F1DS_SHIFT) +# define MCAN_RXESC_F1DS_8B (0 << MCAN_RXESC_F1DS_SHIFT) /* 8-byte data field */ +# define MCAN_RXESC_F1DS_12B (1 << MCAN_RXESC_F1DS_SHIFT) /* 12-byte data field */ +# define MCAN_RXESC_F1DS_16B (2 << MCAN_RXESC_F1DS_SHIFT) /* 16-byte data field */ +# define MCAN_RXESC_F1DS_20B (3 << MCAN_RXESC_F1DS_SHIFT) /* 20-byte data field */ +# define MCAN_RXESC_F1DS_24B (4 << MCAN_RXESC_F1DS_SHIFT) /* 24-byte data field */ +# define MCAN_RXESC_F1DS_32B (5 << MCAN_RXESC_F1DS_SHIFT) /* 32-byte data field */ +# define MCAN_RXESC_F1DS_48B (6 << MCAN_RXESC_F1DS_SHIFT) /* 48-byte data field */ +# define MCAN_RXESC_F1DS_64B (7 << MCAN_RXESC_F1DS_SHIFT) /* 64-byte data field */ + +#define MCAN_RXESC_RBDS_SHIFT (8) /* Bits 8-10: Receive Buffer Data Field Size */ +#define MCAN_RXESC_RBDS_MASK (7 << MCAN_RXESC_RBDS_SHIFT) +# define MCAN_RXESC_RBDS(n) ((uint32_t)(n) << MCAN_RXESC_RBDS_SHIFT) +# define MCAN_RXESC_RBDS_8B (0 << MCAN_RXESC_RBDS_SHIFT) /* 8-byte data field */ +# define MCAN_RXESC_RBDS_12B (1 << MCAN_RXESC_RBDS_SHIFT) /* 12-byte data field */ +# define MCAN_RXESC_RBDS_16B (2 << MCAN_RXESC_RBDS_SHIFT) /* 16-byte data field */ +# define MCAN_RXESC_RBDS_20B (3 << MCAN_RXESC_RBDS_SHIFT) /* 20-byte data field */ +# define MCAN_RXESC_RBDS_24B (4 << MCAN_RXESC_RBDS_SHIFT) /* 24-byte data field */ +# define MCAN_RXESC_RBDS_32B (5 << MCAN_RXESC_RBDS_SHIFT) /* 32-byte data field */ +# define MCAN_RXESC_RBDS_48B (6 << MCAN_RXESC_RBDS_SHIFT) /* 48-byte data field */ +# define MCAN_RXESC_RBDS_64B (7 << MCAN_RXESC_RBDS_SHIFT) /* 64-byte data field */ + +/* Transmit Buffer Configuration Register */ + +#define MCAN_TXBC_TBSA_SHIFT (2) /* Bits 2-15: Tx Buffers Start Address */ +#define MCAN_TXBC_TBSA_MASK (0x3fff << MCAN_TXBC_TBSA_SHIFT) +# define MCAN_TXBC_TBSA(n) ((uint32_t)(n) << MCAN_TXBC_TBSA_SHIFT) +#define MCAN_TXBC_NDTB_SHIFT (16) /* Bits 16-21: Number of Dedicated Transmit Buffers */ +#define MCAN_TXBC_NDTB_MASK (0x3f << MCAN_TXBC_NDTB_SHIFT) +# define MCAN_TXBC_NDTB(n) ((uint32_t)(n) << MCAN_TXBC_NDTB_SHIFT) +#define MCAN_TXBC_TFQS_SHIFT (24) /* Bits 24-29: Transmit FIFO/Queue Size */ +#define MCAN_TXBC_TFQS_MASK (0x3f << MCAN_TXBC_TFQS_SHIFT) +# define MCAN_TXBC_TFQS(n) ((uint32_t)(n) << MCAN_TXBC_TFQS_SHIFT) +#define MCAN_TXBC_TFQM (1 << 30) /* Bit 30: Tx FIFO/Queue Mode */ + +/* Transmit FIFO/Queue Status Register */ + +#define MCAN_TXFQS_TFFL_SHIFT (0) /* Bits 0-5: Tx FIFO Free Level */ +#define MCAN_TXFQS_TFFL_MASK (0x3f << MCAN_TXFQS_TFFL_SHIFT) +# define MCAN_TXFQS_TFFL(n) ((uint32_t)(n) << MCAN_TXFQS_TFFL_SHIFT) +#define MCAN_TXFQS_TFGI_SHIFT (8) /* Bits 8-12: Tx FIFO Get Index */ +#define MCAN_TXFQS_TFGI_MASK (0x1f << MCAN_TXFQS_TFGI_SHIFT) +# define MCAN_TXFQS_TFGI(n) ((uint32_t)(n) << MCAN_TXFQS_TFGI_SHIFT) +#define MCAN_TXFQS_TFQPI_SHIFT (16) /* Bits 16-20: Tx FIFO/Queue Put Index */ +#define MCAN_TXFQS_TFQPI_MASK (0x1f << MCAN_TXFQS_TFQPI_SHIFT) +# define MCAN_TXFQS_TFQPI(n) ((uint32_t)(n) << MCAN_TXFQS_TFQPI_SHIFT) +#define MCAN_TXFQS_TFQF (1 << 21) /* Bit 21: Tx FIFO/Queue Full */ + +/* Transmit Buffer Element Size Configuration Register */ + +#define MCAN_TXESC_TBDS_SHIFT (0) /* Bits 0-2: Tx Buffer Data Field Size */ +#define MCAN_TXESC_TBDS_MASK (7 << MCAN_TXESC_TBDS_SHIFT) +# define MCAN_TXESC_TBDS(n) ((uint32_t)(n) << MCAN_TXESC_TBDS_SHIFT) +# define MCAN_TXESC_TBDS_8B (0 << MCAN_TXESC_TBDS_SHIFT) /* 8-byte data field */ +# define MCAN_TXESC_TBDS_12B (1 << MCAN_TXESC_TBDS_SHIFT) /* 12-byte data field */ +# define MCAN_TXESC_TBDS_16B (2 << MCAN_TXESC_TBDS_SHIFT) /* 16-byte data field */ +# define MCAN_TXESC_TBDS_20B (3 << MCAN_TXESC_TBDS_SHIFT) /* 20-byte data field */ +# define MCAN_TXESC_TBDS_24B (4 << MCAN_TXESC_TBDS_SHIFT) /* 24-byte data field */ +# define MCAN_TXESC_TBDS_32B (5 << MCAN_TXESC_TBDS_SHIFT) /* 32-byte data field */ +# define MCAN_TXESC_TBDS_48B (6 << MCAN_TXESC_TBDS_SHIFT) /* 48-byte data field */ +# define MCAN_TXESC_TBDS_64B (7 << MCAN_TXESC_TBDS_SHIFT) /* 64-byte data field */ + +/* Transmit Buffer Request Pending Register */ + +#define MCAN_TXBRP(n) (1 << (n)) /* Transmission request pending for buffer n, n=0-31 */ + +/* Transmit Buffer Add Request Register */ + +#define MCAN_TXBAR(n) (1 << (n)) /* Add request for transmit buffer n, n=0-31 */ + +/* Transmit Buffer Cancellation Request Register */ + +#define MCAN_TXBCR(n) (1 << (n)) /* Cancellation request for transmit buffer n, n=0-31 */ + +/* Transmit Buffer Transmission Occurred Register */ + +#define MCAN_TXBTO(n) (1 << (n)) /* Transmission occurred for buffer n, n=0-31 */ + +/* Transmit Buffer Cancellation Finished Register */ + +#define MCAN_TXBCF(n) (1 << (n)) /* Cancellation finished for transmit buffer n, n=0-31 */ + +/* Transmit Buffer Transmission Interrupt Enable Register */ + +#define MCAN_TXBTIE(n) (1 << (n)) /* Transmission interrupt enable for buffer n, n=0-31 */ + +/* Transmit Buffer Cancellation Finished Interrupt Enable Register */ + +#define MCAN_TXBTIE(n) (1 << (n)) /* Cancellation finished interrupt enable for transmit buffer n, n=0-31 */ + +/* Transmit Event FIFO Configuration Register */ + +#define MCAN_TXEFC_EFSA_SHIFT (2) /* Bits 2-15: Event FIFO Start Address */ +#define MCAN_TXEFC_EFSA_MASK (0x3fff << MCAN_TXEFC_EFSA_SHIFT) +# define MCAN_TXEFC_EFSA(n) ((uint32_t)(n) << MCAN_TXEFC_EFSA_SHIFT) +#define MCAN_TXEFC_EFS_SHIFT (16) /* Bits 16-21: Event FIFO Size */ +#define MCAN_TXEFC_EFS_MASK (0x3f << MCAN_TXEFC_EFS_SHIFT) +# define MCAN_TXEFC_EFS(n) ((uint32_t)(n) << MCAN_TXEFC_EFS_SHIFT) +#define MCAN_TXEFC_EFWM_SHIFT (24) /* Bits 24-29: Event FIFO Watermark */ +#define MCAN_TXEFC_EFWM_MASK (0x3f << MCAN_TXEFC_EFWM_SHIFT) +# define MCAN_TXEFC_EFWM(n) ((uint32_t)(n) << MCAN_TXEFC_EFWM_SHIFT) + +/* Transmit Event FIFO Status Register */ + +#define MCAN_TXEFS_EFFL_SHIFT (0) /* Bits 0-5: Event FIFO Fill Level */ +#define MCAN_TXEFS_EFFL_MASK (0x3f << MCAN_TXEFS_EFFL_SHIFT) +# define MCAN_TXEFS_EFFL(n) ((uint32_t)(n) << MCAN_TXEFS_EFFL_SHIFT) +#define MCAN_TXEFS_EFGI_SHIFT (8) /* Bits 8-12: Event FIFO Get Index */ +#define MCAN_TXEFS_EFGI_MASK (0x1f << MCAN_TXEFS_EFGI_SHIFT) +# define MCAN_TXEFS_EFGI(n) ((uint32_t)(n) << MCAN_TXEFS_EFGI_SHIFT) +#define MCAN_TXEFS_EFPI_SHIFT (16) /* Bits 16-20: Event FIFO Put Index */ +#define MCAN_TXEFS_EFPI_MASK (0x1f << MCAN_TXEFS_EFPI_SHIFT) +# define MCAN_TXEFS_EFPI(n) ((uint32_t)(n) << MCAN_TXEFS_EFPI_SHIFT) +#define MCAN_TXEFS_EFF (1 << 24) /* Bit 24: Event FIFO Full */ +#define MCAN_TXEFS_TEFL (1 << 25) /* Bit 25: Tx Event FIFO Element Lost */ + +/* Transmit Event FIFO Acknowledge Register */ + +#define MCAN_TXEFA_MASK 0x0000001f /* Event fifo acknowledge index mask */ + +/* Message RAM Definitions **************************************************/ + +/* Common Buffer and FIFO element bit definitions: + * + * --------------- ------------------- -------------------------------- + * RESOURCE R0 R1 + * --------------- ------------------- -------------------------------- + * RX Buffer: ESI, XTD, RTR, ID, ANMF, FIDX, EDL, BRS, DLC, RXTS + * RX FIFO: ESI, XTD, RTR, ID, ANMF, FIDX, EDL, BRS, DLC, RXTS + * TX buffer: XTD, RTR, ID, MM, EFC, DLC + * TX Event FIFO: ESI, XTD, RTR, ID, MM, ET, EDL, BRS, DLC, TXTS + * --------------- ------------------- -------------------------------- + */ + +/* Common */ + +#define BUFFER_R0_EXTID_SHIFT (0) /* Bits 0-28: Extended identifier */ +#define BUFFER_R0_EXTID_MASK (0x1fffffff << BUFFER_R0_EXTID_SHIFT) +# define BUFFER_R0_EXTID(n) ((uint32_t)(n) << BUFFER_R0_EXTID_SHIFT) +#define BUFFER_R0_STDID_SHIFT (18) /* Bits 18-28: Standard identifier */ +#define BUFFER_R0_STDID_MASK (0x7ff << BUFFER_R0_STDID_SHIFT) +# define BUFFER_R0_STDID(n) ((uint32_t)(n) << BUFFER_R0_STDID_SHIFT) +#define BUFFER_R0_RTR (1 << 29) /* Bit 29: Remote Transmission Request */ +#define BUFFER_R0_XTD (1 << 30) /* Bit 30: Extended Identifier */ +#define BUFFER_R0_ESI (1 << 31) /* Bit 31: Error State Indicator */ + +/* Common */ + +#define BUFFER_R1_DLC_SHIFT (16) /* Bits 16-19: Date length code */ +#define BUFFER_R1_DLC_MASK (15 << BUFFER_R1_DLC_SHIFT) +# define BUFFER_R1_DLC(n) ((uint32_t)(n) << BUFFER_R1_DLC_SHIFT) +#define BUFFER_R1_BRS (1 << 20) /* Bit 20: Bit Rate Switch */ +#define BUFFER_R1_EDL (1 << 21) /* Bit 21: Extended Data Length */ + +/* RX buffer/RX FIFOs */ + +#define BUFFER_R1_RXTS_SHIFT (0) /* Bits 0-15: RX Timestamp */ +#define BUFFER_R1_RXTS_MASK (0xffff << BUFFER_R1_RXTS_SHIFT) +# define BUFFER_R1_RXTS(n) ((uint32_t)(n) << BUFFER_R1_RXTS_SHIFT) +#define BUFFER_R1_FIDX_SHIFT (24) /* Bits 24-30: Filter index */ +#define BUFFER_R1_FIDX_MASK (0x7f << BUFFER_R1_FIDX_SHIFT) +# define BUFFER_R1_FIDX(n) ((uint32_t)(n) << BUFFER_R1_FIDX_SHIFT) +#define BUFFER_R1_ANMF (1 << 31) /* Bit 31: Accepted Non-matching Frame */ + +/* TX buffer/TX Event FIFO */ + +#define BUFFER_R1_MM_SHIFT (24) /* Bits 24-31: Message Marker */ +#define BUFFER_R1_MM_MASK (0xffff << BUFFER_R1_MM_SHIFT) +# define BUFFER_R1_MM(n) ((uint32_t)(n) << BUFFER_R1_MM_SHIFT) + +/* TX buffer */ + +#define BUFFER_R1_EFC (1 << 23) /* Bit 23: Event FIFO Control */ + +/* TX Event FIFO */ + +#define BUFFER_R1_TXTS_SHIFT (0) /* Bits 0-15: TX Timestamp */ +#define BUFFER_R1_TXTS_MASK (0xffff << BUFFER_R1_TXTS_SHIFT) +# define BUFFER_R1_TXTS(n) ((uint32_t)(n) << BUFFER_R1_TXTS_SHIFT) +#define BUFFER_R1_ET_SHIFT (22) /* Bits 22-23: Event Type */ +#define BUFFER_R1_ET_MASK (15 << BUFFER_R1_ET_SHIFT) +# define BUFFER_R1_ET_TXEVENT (1 << BUFFER_R1_ET_SHIFT) /* Tx event */ +# define BUFFER_R1_ET_TXCANCEL (2 << BUFFER_R1_ET_SHIFT) /* Transmission despite cancellation */ + +/* Standard Message ID Filter Element */ + +#define STDFILTER_S0_SFID2_SHIFT (0) /* Bits 0-10: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID2_MASK (0x3ff << STDFILTER_S0_SFID2_SHIFT) +# define STDFILTER_S0_SFID2(n) ((uint32_t)(n) << STDFILTER_S0_SFID2_SHIFT) +#define STDFILTER_S0_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define STDFILTER_S0_BUFFER_MASK (0x3f << STDFILTER_S0_BUFFER_SHIFT) +# define STDFILTER_S0_BUFFER(n) ((uint32_t)(n) << STDFILTER_S0_BUFFER_SHIFT) +#define STDFILTER_S0_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define STDFILTER_S0_ACTION_MASK (3 << STDFILTER_S0_ACTION_SHIFT) +# define STDFILTER_S0_RXBUFFER (0 << STDFILTER_S0_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define STDFILTER_S0_DEBUGA (1 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message A */ +# define STDFILTER_S0_DEBUGB (2 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message B */ +# define STDFILTER_S0_DEBUGC (3 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message C */ + +#define STDFILTER_S0_SFID1_SHIFT (16) /* Bits 16-26: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID1_MASK (0x3ff << STDFILTER_S0_SFID1_SHIFT) +# define STDFILTER_S0_SFID1(n) ((uint32_t)(n) << STDFILTER_S0_SFID1_SHIFT) +#define STDFILTER_S0_SFEC_SHIFT (27) /* Bits 27-29: Standard Filter Element Configuration */ +#define STDFILTER_S0_SFEC_MASK (7 << STDFILTER_S0_SFEC_SHIFT) +# define STDFILTER_S0_SFEC_DISABLE (0 << STDFILTER_S0_SFEC_SHIFT) /* Disable filter element */ +# define STDFILTER_S0_SFEC_FIFO0 (1 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define STDFILTER_S0_SFEC_FIFO1 (2 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define STDFILTER_S0_SFEC_REJECT (3 << STDFILTER_S0_SFEC_SHIFT) /* Reject ID on match */ +# define STDFILTER_S0_SFEC_PRIORITY (4 << STDFILTER_S0_SFEC_SHIFT) /* Set priority ion match */ +# define STDFILTER_S0_SFEC_PRIOFIFO0 (5 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define STDFILTER_S0_SFEC_PRIOFIFO1 (6 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define STDFILTER_S0_SFEC_BUFFER (7 << STDFILTER_S0_SFEC_SHIFT) /* Store into Rx Buffer or as debug message */ + +#define STDFILTER_S0_SFT_SHIFT (30) /* Bits 30-31: Standard Filter Type */ +#define STDFILTER_S0_SFT_MASK (3 << STDFILTER_S0_SFT_SHIFT) +# define STDFILTER_S0_SFT_RANGE (0 << STDFILTER_S0_SFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define STDFILTER_S0_SFT_DUAL (1 << STDFILTER_S0_SFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define STDFILTER_S0_SFT_CLASSIC (2 << STDFILTER_S0_SFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ + +/* Extended Message ID Filter Element */ + +#define EXTFILTER_F0_EFID1_SHIFT (0) /* Bits 0-28: Extended Filter ID 1 */ +#define EXTFILTER_F0_EFID1_MASK (0x1fffffff << EXTFILTER_F0_EFID1_SHIFT) +# define EXTFILTER_F0_EFID1(n) ((uint32_t)(n) << EXTFILTER_F0_EFID1_SHIFT) +#define EXTFILTER_F0_EFEC_SHIFT (29) /* Bits 29-31: Extended Filter Element Configuration */ +#define EXTFILTER_F0_EFEC_MASK (7 << EXTFILTER_F0_EFEC_SHIFT) +# define EXTFILTER_F0_EFEC_DISABLE (0 << EXTFILTER_F0_EFEC_SHIFT) /* Disable filter element */ +# define EXTFILTER_F0_EFEC_FIFO0 (1 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_FIFO1 (2 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_REJECT (3 << EXTFILTER_F0_EFEC_SHIFT) /* Reject ID on match */ +# define EXTFILTER_F0_EFEC_PRIORITY (4 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO0 (5 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO1 (6 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_BUFFER (7 << EXTFILTER_F0_EFEC_SHIFT) /* Store into Rx Buffer or as debug message */ + +#define EXTFILTER_F1_EFID2_SHIFT (0) /* Bits 0-28: Extended Filter ID 2 */ +#define EXTFILTER_F1_EFID2_MASK (0x1fffffff << EXTFILTER_F1_EFID2_SHIFT) +# define EXTFILTER_F1_EFID2(n) ((uint32_t)(n) << EXTFILTER_F1_EFID2_SHIFT) +#define EXTFILTER_F1_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define EXTFILTER_F1_BUFFER_MASK (0x3f << EXTFILTER_F1_BUFFER_SHIFT) +# define EXTFILTER_F1_BUFFER(n) ((uint32_t)(n) << EXTFILTER_F1_BUFFER_SHIFT) +#define EXTFILTER_F1_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define EXTFILTER_F1_ACTION_MASK (3 << EXTFILTER_F1_ACTION_SHIFT) +# define EXTFILTER_F1_RXBUFFER (0 << EXTFILTER_F1_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define EXTFILTER_F1_DEBUGA (1 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message A */ +# define EXTFILTER_F1_DEBUGB (2 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message B */ +# define EXTFILTER_F1_DEBUGC (3 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message C */ + +#define EXTFILTER_F1_EFT_SHIFT (30) /* Bits 30-31: Extended Filter Type */ +#define EXTFILTER_F1_EFT_MASK (3 << EXTFILTER_F1_EFT_SHIFT) +# define EXTFILTER_F1_EFT_RANGE (0 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define EXTFILTER_F1_EFT_DUAL (1 << EXTFILTER_F1_EFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define EXTFILTER_F1_EFT_CLASSIC (2 << EXTFILTER_F1_EFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ +# define EXTFILTER_F1_EFT_NOXIDAM (2 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from EF1ID to EF2ID, no XIDAM */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_SAMA5_HARDWARE_SAM_MCAN_H */ diff --git a/arch/arm/src/sama5/sam_mcan.c b/arch/arm/src/sama5/sam_mcan.c new file mode 100644 index 0000000000..a11b4989b9 --- /dev/null +++ b/arch/arm/src/sama5/sam_mcan.c @@ -0,0 +1,4202 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_mcan.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* References: + * SAMA5D2 Series Data Sheet + * Atmel sample code + * Based on pre-existing SAMV71 NuttX mcan driver + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "arm_internal.h" + +#include "hardware/sam_sfr.h" +#include "hardware/sam_pinmap.h" +#include "sam_periphclks.h" +#include "sam_pio.h" +#include "sam_mcan.h" + +#if defined(CONFIG_CAN) && (defined(CONFIG_SAMA5_MCAN0) || \ + defined(CONFIG_SAMA5_MCAN1)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Common definitions */ + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* dedicated RS and TX buffers are not supported */ + +#define DEDICATED_BUFFERS_NOT_USED + +/* Clock source */ + +/* PCK5 is the programmable clock source, common to all MCAN controllers */ + +#if defined(CONFIG_SAMA5_MCAN_CLKSRC_SLOW) +# define SAMA5_MCAN_CLKSRC PMC_PCR_GCKCSS_SLOW +# define SAMA5_MCAN_CLKSRC_FREQUENCY BOARD_SLOWCLK_FREQUENCY +#elif defined(CONFIG_SAMA5_MCAN_CLKSRC_PLLA) +# define SAMA5_MCAN_CLKSRC PMC_PCR_GCKCSS_PLLA +# define SAMA5_MCAN_CLKSRC_FREQUENCY BOARD_PLLA_FREQUENCY +#elif defined(CONFIG_SAMA5_MCAN_CLKSRC_UPLL) +# define SAMA5_MCAN_CLKSRC PMC_PCR_GCKCSS_UPLL +# define SAMA5_MCAN_CLKSRC_FREQUENCY BOARD_UPLL_FREQUENCY +#elif defined(CONFIG_SAMA5_MCAN_CLKSRC_MCK) +# define SAMA5_MCAN_CLKSRC PMC_PCR_GCKCSS_MCK +# define SAMA5_MCAN_CLKSRC_FREQUENCY BOARD_MCK_FREQUENCY +#elif defined(CONFIG_SAMA5_MCAN_CLKSRC_MAIN) +# define SAMA5_MCAN_CLKSRC PMC_PCR_GCKCSS_MAIN +# define SAMA5_MCAN_CLKSRC_FREQUENCY BOARD_MAINOSC_FREQUENCY +#else +# error no mcan clock defined! +#endif + +#ifndef CONFIG_SAMA5_MCAN_CLKSRC_PRESCALER +# define CONFIG_SAMA5_MCAN_CLKSRC_PRESCALER 1 +#endif + +#define SAMA5_MCANCLK_FREQUENCY \ + (SAMA5_MCAN_CLKSRC_FREQUENCY / CONFIG_SAMA5_MCAN_CLKSRC_PRESCALER) + +/* Buffer Alignment. + * + * The MCAN peripheral does not require any data be aligned. However, if + * the data cache is enabled then alignment is required. That is because + * the data will need to be invalidated and that cache invalidation will + * occur in multiples of full change lines. + */ + +#ifdef CONFIG_ARCH_DCACHE +# define MCAN_ALIGN ARMV7A_DCACHE_LINESIZE +# define MCAN_ALIGN_MASK (MCAN_ALIGN-1) +# define MCAN_ALIGN_UP(n) (((n) + MCAN_ALIGN_MASK) & ~MCAN_ALIGN_MASK) +# define SAM_MCAN_SFR_SHIFT 16 +# define SAM_MCAN0_SFR_MASK 0xffff0000 +# define SAM_MCAN1_SFR_MASK 0x0000ffff +# define SAM_MCAN_SFR_MSB_MASK 0xffff0000 +# define SAM_MCAN_SFR_GET_MSB(n) (( (uint32_t)(n) & (SAM_MCAN_SFR_MSB_MASK)) >> SAM_MCAN_SFR_SHIFT) +#else +# define MCAN_ALIGN (0) +# define MCAN_ALIGN_MASK (0) +# define MCAN_ALIGN_UP(n) (n) +#endif + +/* General Configuration */ + +#ifndef CONFIG_CAN_TXREADY +# warning WARNING!!! CONFIG_CAN_TXREADY is required by this driver +#endif + +/* MCAN0 Configuration */ + +#ifdef CONFIG_SAMA5_MCAN0 + +/* Bit timing */ + +# define MCAN0_TSEG1 (CONFIG_SAMA5_MCAN0_PROPSEG + CONFIG_SAMA5_MCAN0_PHASESEG1 - 1) +# define MCAN0_TSEG2 (CONFIG_SAMA5_MCAN0_PHASESEG2 - 1) +# define MCAN0_BRP ((uint32_t)(((float)SAMA5_MCANCLK_FREQUENCY / \ + ((float)(MCAN0_TSEG1 + MCAN0_TSEG2 + 3) * \ + (float)CONFIG_SAMA5_MCAN0_BITRATE)) - 1)) + +# define MCAN0_SJW (CONFIG_SAMA5_MCAN0_FSJW - 1) + +/* NB: errata sheet states TSEG1 must not be programmed as 0 */ + +# if ((MCAN0_TSEG1 > 256) || (MCAN0_TSEG1 < 2)) +# error Invalid MCAN0 TSEG1 +# endif +# if MCAN0_TSEG2 > 128 +# error Invalid MCAN0 TSEG2 +# endif +# if MCAN0_SJW > 128 +# error Invalid MCAN0 SJW +# endif + +# define MCAN0_FTSEG1 (CONFIG_SAMA5_MCAN0_FPROPSEG + CONFIG_SAMA5_MCAN0_FPHASESEG1 - 1) +# define MCAN0_FTSEG2 (CONFIG_SAMA5_MCAN0_FPHASESEG2 - 1) +# define MCAN0_FBRP ((uint32_t)(((float)SAMA5_MCANCLK_FREQUENCY / \ + ((float)(MCAN0_FTSEG1 + MCAN0_FTSEG2 + 3) * \ + (float)CONFIG_SAMA5_MCAN0_FBITRATE)) - 1)) +# define MCAN0_FSJW (CONFIG_SAMA5_MCAN0_FFSJW - 1) + +/* NB: errata sheet states TSEG1 must not be programmed as 0 */ + +# if ((MCAN0_FTSEG1 > 32) || (MCAN0_FTSEG1 < 2)) +# error Invalid MCAN0 FTSEG1 +# endif +# if MCAN0_FTSEG2 > 17 +# error Invalid MCAN0 FTSEG2 +# endif +# if MCAN0_FSJW > 8 +# error Invalid MCAN0 FSJW +# endif + +/* MCAN0 RX FIFO0 element size */ + +# if defined(CONFIG_SAMA5_MCAN0_RXFIFO0_8BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 8 +# define MCAN0_RXFIFO0_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_12BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 12 +# define MCAN0_RXFIFO0_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_16BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 16 +# define MCAN0_RXFIFO0_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_20BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 20 +# define MCAN0_RXFIFO0_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_24BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 24 +# define MCAN0_RXFIFO0_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_32BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 32 +# define MCAN0_RXFIFO0_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_48BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 48 +# define MCAN0_RXFIFO0_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO0_64BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 64 +# define MCAN0_RXFIFO0_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX FIFO0 element size +# endif + +# ifndef CONFIG_SAMA5_MCAN0_RXFIFO0_SIZE +# define CONFIG_SAMA5_MCAN0_RXFIFO0_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN0_RXFIFO0_SIZE > 64 +# error Invalid MCAN0 number of RX FIFO0 elements +# endif + +# define MCAN0_RXFIFO0_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_RXFIFO0_SIZE * \ + MCAN0_RXFIFO0_ELEMENT_SIZE + 8) +# define MCAN0_RXFIFO0_WORDS (MCAN0_RXFIFO0_BYTES >> 2) + +/* MCAN0 RX FIFO1 element size */ + +# if defined(CONFIG_SAMA5_MCAN0_RXFIFO1_8BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 8 +# define MCAN0_RXFIFO1_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_12BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 12 +# define MCAN0_RXFIFO1_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_16BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 16 +# define MCAN0_RXFIFO1_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_20BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 20 +# define MCAN0_RXFIFO1_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_24BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 24 +# define MCAN0_RXFIFO1_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_32BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 32 +# define MCAN0_RXFIFO1_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_48BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 48 +# define MCAN0_RXFIFO1_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN0_RXFIFO1_64BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 64 +# define MCAN0_RXFIFO1_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX FIFO1 element size +# endif + +# ifndef CONFIG_SAMA5_MCAN0_RXFIFO1_SIZE +# define CONFIG_SAMA5_MCAN0_RXFIFO1_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN0_RXFIFO1_SIZE > 64 +# error Invalid MCAN0 number of RX FIFO1 elements +# endif + +# define MCAN0_RXFIFO1_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_RXFIFO1_SIZE * \ + MCAN0_RXFIFO1_ELEMENT_SIZE + 8) +# define MCAN0_RXFIFO1_WORDS (MCAN0_RXFIFO1_BYTES >> 2) + +/* MCAN0 Filters */ + +# ifndef CONFIG_SAMA5_MCAN0_NSTDFILTERS +# define CONFIG_SAMA5_MCAN0_NSTDFILTERS 0 +# endif + +# if (CONFIG_SAMA5_MCAN0_NSTDFILTERS > 128) +# error Invalid MCAN0 number of Standard Filters +# endif + +# ifndef CONFIG_SAMA5_MCAN0_NEXTFILTERS +# define CONFIG_SAMA5_MCAN0_NEXTFILTERS 0 +# endif + +# if (CONFIG_SAMA5_MCAN0_NEXTFILTERS > 64) +# error Invalid MCAN0 number of Extended Filters +# endif + +# define MCAN0_STDFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_NSTDFILTERS << 2) +# define MCAN0_STDFILTER_WORDS (MCAN0_STDFILTER_BYTES >> 2) + +# define MCAN0_EXTFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_NEXTFILTERS << 3) +# define MCAN0_EXTFILTER_WORDS (MCAN0_EXTFILTER_BYTES >> 2) + +/* MCAN0 RX buffer element size */ + +# if defined(CONFIG_SAMA5_MCAN0_RXBUFFER_8BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 8 +# define MCAN0_RXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_12BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 12 +# define MCAN0_RXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_16BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 16 +# define MCAN0_RXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_20BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 20 +# define MCAN0_RXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_24BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 24 +# define MCAN0_RXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_32BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 32 +# define MCAN0_RXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_48BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 48 +# define MCAN0_RXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN0_RXBUFFER_64BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 64 +# define MCAN0_RXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX buffer element size +# endif + +# ifndef CONFIG_SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE +# define CONFIG_SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE > 64 +# error Invalid MCAN0 number of RX BUFFER elements +# endif + +# define MCAN0_DEDICATED_RXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE * \ + MCAN0_RXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_DEDICATED_RXBUFFER_WORDS \ + (MCAN0_DEDICATED_RXBUFFER_BYTES >> 2) + +/* MCAN0 TX buffer element size */ + +# if defined(CONFIG_SAMA5_MCAN0_TXBUFFER_8BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 8 +# define MCAN0_TXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_12BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 12 +# define MCAN0_TXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_16BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 16 +# define MCAN0_TXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_20BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 20 +# define MCAN0_TXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_24BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 24 +# define MCAN0_TXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_32BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 32 +# define MCAN0_TXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_48BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 48 +# define MCAN0_TXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN0_TXBUFFER_64BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 64 +# define MCAN0_TXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 TX buffer element size +# endif + +# ifndef CONFIG_SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE +# define CONFIG_SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE 0 +# endif + +# define MCAN0_DEDICATED_TXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE * \ + MCAN0_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_DEDICATED_TXBUFFER_WORDS \ + (MCAN0_DEDICATED_TXBUFFER_BYTES >> 2) + +/* MCAN0 TX FIFOs */ + +# ifndef CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE +# define CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE 0 +# endif + +# if (CONFIG_SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE + \ + CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE) > 32 +# error Invalid MCAN0 number of TX BUFFER elements +# endif + +# ifndef CONFIG_SAMA5_MCAN0_TXEVENTFIFO_SIZE +# define CONFIG_SAMA5_MCAN0_TXEVENTFIFO_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN0_TXEVENTFIFO_SIZE > 32 +# error Invalid MCAN0 number of TX EVENT FIFO elements +# endif + +# define MCAN0_TXEVENTFIFO_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_TXEVENTFIFO_SIZE << 3) +# define MCAN0_TXEVENTFIFO_WORDS \ + (MCAN0_TXEVENTFIFO_BYTES >> 2) + +# define MCAN0_TXFIFIOQ_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE * \ + MCAN0_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_TXFIFIOQ_WORDS (MCAN0_TXFIFIOQ_BYTES >> 2) + +/* MCAN0 Message RAM */ + +# define MCAN0_STDFILTER_INDEX 0 +# define MCAN0_EXTFILTERS_INDEX (MCAN0_STDFILTER_INDEX + MCAN0_STDFILTER_WORDS) +# define MCAN0_RXFIFO0_INDEX (MCAN0_EXTFILTERS_INDEX + MCAN0_EXTFILTER_WORDS) +# define MCAN0_RXFIFO1_INDEX (MCAN0_RXFIFO0_INDEX + MCAN0_RXFIFO0_WORDS) +# define MCAN0_RXDEDICATED_INDEX (MCAN0_RXFIFO1_INDEX + MCAN0_RXFIFO1_WORDS) +# define MCAN0_TXEVENTFIFO_INDEX (MCAN0_RXDEDICATED_INDEX + MCAN0_DEDICATED_RXBUFFER_WORDS) +# define MCAN0_TXDEDICATED_INDEX (MCAN0_TXEVENTFIFO_INDEX + MCAN0_TXEVENTFIFO_WORDS) +# define MCAN0_TXFIFOQ_INDEX (MCAN0_TXDEDICATED_INDEX + MCAN0_DEDICATED_TXBUFFER_WORDS) +# define MCAN0_MSGRAM_WORDS (MCAN0_TXFIFOQ_INDEX + MCAN0_TXFIFIOQ_WORDS) + +#endif /* CONFIG_SAMA5_MCAN0 */ + +/* Loopback mode */ + +#undef SAMA5_MCAN_LOOPBACK +#if defined(CONFIG_SAMA5_MCAN0_LOOPBACK) || defined(CONFIG_SAMA5_MCAN1_LOOPBACK) +# define SAMA5_MCAN_LOOPBACK 1 +#endif + +/* MCAN1 Configuration */ + +#ifdef CONFIG_SAMA5_MCAN1 + /* Bit timing */ + +# define MCAN1_TSEG1 (CONFIG_SAMA5_MCAN1_PROPSEG + CONFIG_SAMA5_MCAN1_PHASESEG1) +# define MCAN1_TSEG2 CONFIG_SAMA5_MCAN1_PHASESEG2 +# define MCAN1_BRP ((uint32_t)(((float)SAMA5_MCANCLK_FREQUENCY / \ + ((float)(MCAN1_TSEG1 + MCAN1_TSEG2 + 3) * \ + (float)CONFIG_SAMA5_MCAN1_BITRATE)) - 1)) +# define MCAN1_SJW (CONFIG_SAMA5_MCAN1_FSJW - 1) + +# if MCAN1_TSEG1 > 63 +# error Invalid MCAN1 TSEG1 +# endif +# if MCAN1_TSEG2 > 15 +# error Invalid MCAN1 TSEG2 +# endif +# if MCAN1_SJW > 15 +# error Invalid MCAN1 SJW +# endif + +# define MCAN1_FTSEG1 (CONFIG_SAMA5_MCAN1_FPROPSEG + CONFIG_SAMA5_MCAN1_FPHASESEG1) +# define MCAN1_FTSEG2 (CONFIG_SAMA5_MCAN1_FPHASESEG2) +# define MCAN1_FBRP ((uint32_t)(((float)SAMA5_MCANCLK_FREQUENCY / \ + ((float)(MCAN1_FTSEG1 + MCAN1_FTSEG2 + 3) * \ + (float)CONFIG_SAMA5_MCAN1_FBITRATE)) - 1)) +# define MCAN1_FSJW (CONFIG_SAMA5_MCAN1_FFSJW - 1) + +#if MCAN1_FTSEG1 > 15 +# error Invalid MCAN1 FTSEG1 +#endif +#if MCAN1_FTSEG2 > 7 +# error Invalid MCAN1 FTSEG2 +#endif +#if MCAN1_FSJW > 3 +# error Invalid MCAN1 FSJW +#endif + +/* MCAN1 RX FIFO0 element size */ + +# if defined(CONFIG_SAMA5_MCAN1_RXFIFO0_8BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 8 +# define MCAN1_RXFIFO0_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_12BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 12 +# define MCAN1_RXFIFO0_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_16BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 16 +# define MCAN1_RXFIFO0_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_20BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 20 +# define MCAN1_RXFIFO0_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_24BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 24 +# define MCAN1_RXFIFO0_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_32BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 32 +# define MCAN1_RXFIFO0_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_48BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 48 +# define MCAN1_RXFIFO0_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO0_64BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 64 +# define MCAN1_RXFIFO0_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX FIFO0 element size +# endif + +# ifndef CONFIG_SAMA5_MCAN1_RXFIFO0_SIZE +# define CONFIG_SAMA5_MCAN1_RXFIFO0_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN1_RXFIFO0_SIZE > 64 +# error Invalid MCAN1 number of RX FIFO 0 elements +# endif + +# define MCAN1_RXFIFO0_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_RXFIFO0_SIZE * \ + MCAN1_RXFIFO0_ELEMENT_SIZE + 8) +# define MCAN1_RXFIFO0_WORDS (MCAN1_RXFIFO0_BYTES >> 2) + +/* MCAN1 RX FIFO1 element size */ + +# if defined(CONFIG_SAMA5_MCAN1_RXFIFO1_8BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 8 +# define MCAN1_RXFIFO1_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_12BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 12 +# define MCAN1_RXFIFO1_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_16BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 16 +# define MCAN1_RXFIFO1_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_20BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 20 +# define MCAN1_RXFIFO1_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_24BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 24 +# define MCAN1_RXFIFO1_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_32BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 32 +# define MCAN1_RXFIFO1_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_48BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 48 +# define MCAN1_RXFIFO1_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN1_RXFIFO1_64BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 64 +# define MCAN1_RXFIFO1_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX FIFO1 element size +# endif + +# ifndef CONFIG_SAMA5_MCAN1_RXFIFO1_SIZE +# define CONFIG_SAMA5_MCAN1_RXFIFO1_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN1_RXFIFO1_SIZE > 64 +# error Invalid MCAN1 number of RX FIFO 0 elements +# endif + +# define MCAN1_RXFIFO1_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_RXFIFO1_SIZE * \ + MCAN1_RXFIFO1_ELEMENT_SIZE + 8) +# define MCAN1_RXFIFO1_WORDS (MCAN1_RXFIFO1_BYTES >> 2) + +/* MCAN1 Filters */ + +# ifndef CONFIG_SAMA5_MCAN1_NSTDFILTERS +# define CONFIG_SAMA5_MCAN1_NSTDFILTERS 0 +# endif + +# if CONFIG_SAMA5_MCAN1_NSTDFILTERS > 128 +# error Invalid MCAN1 number of Standard Filters +# endif + +# ifndef CONFIG_SAMA5_MCAN1_NEXTFILTERS +# define CONFIG_SAMA5_MCAN1_NEXTFILTERS 0 +# endif + +# if CONFIG_SAMA5_MCAN1_NEXTFILTERS > 64 +# error Invalid MCAN1 number of Extended Filters +# endif + +# define MCAN1_STDFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_NSTDFILTERS << 2) +# define MCAN1_STDFILTER_WORDS (MCAN1_STDFILTER_BYTES >> 2) + +# define MCAN1_EXTFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_NEXTFILTERS << 3) +# define MCAN1_EXTFILTER_WORDS (MCAN1_EXTFILTER_BYTES >> 2) + +/* MCAN1 RX buffer element size */ + +# if defined(CONFIG_SAMA5_MCAN1_RXBUFFER_8BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 8 +# define MCAN1_RXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_12BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 12 +# define MCAN1_RXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_16BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 16 +# define MCAN1_RXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_20BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 20 +# define MCAN1_RXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_24BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 24 +# define MCAN1_RXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_32BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 32 +# define MCAN1_RXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_48BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 48 +# define MCAN1_RXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN1_RXBUFFER_64BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 64 +# define MCAN1_RXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX buffer element size +# endif + +# ifndef CONFIG_SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE +# define CONFIG_SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE > 64 +# error Invalid MCAN1 number of RX BUFFER elements +# endif + +# define MCAN1_DEDICATED_RXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE * \ + MCAN1_RXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_DEDICATED_RXBUFFER_WORDS \ + (MCAN1_DEDICATED_RXBUFFER_BYTES >> 2) + +/* MCAN1 TX buffer element size */ + +# if defined(CONFIG_SAMA5_MCAN1_TXBUFFER_8BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 8 +# define MCAN1_TXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_12BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 12 +# define MCAN1_TXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_16BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 16 +# define MCAN1_TXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_20BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 20 +# define MCAN1_TXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_24BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 24 +# define MCAN1_TXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_32BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 32 +# define MCAN1_TXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_48BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 48 +# define MCAN1_TXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMA5_MCAN1_TXBUFFER_64BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 64 +# define MCAN1_TXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 TX buffer element size +# endif + +# ifndef CONFIG_SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE +# define CONFIG_SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE 0 +# endif + +# define MCAN1_DEDICATED_TXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE * \ + MCAN1_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_DEDICATED_TXBUFFER_WORDS \ + (MCAN1_DEDICATED_TXBUFFER_BYTES >> 2) + +/* MCAN1 TX FIFOs */ + +# ifndef CONFIG_SAMA5_MCAN1_TXFIFOQ_SIZE +# define CONFIG_SAMA5_MCAN1_TXFIFOQ_SIZE 0 +# endif + +# if (CONFIG_SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE + \ + CONFIG_SAMA5_MCAN1_TXFIFOQ_SIZE) > 32 +# error Invalid MCAN1 number of TX BUFFER elements +# endif + +# ifndef CONFIG_SAMA5_MCAN1_TXEVENTFIFO_SIZE +# define CONFIG_SAMA5_MCAN1_TXEVENTFIFO_SIZE 0 +# endif + +# if CONFIG_SAMA5_MCAN1_TXEVENTFIFO_SIZE > 32 +# error Invalid MCAN1 number of TX EVENT FIFO elements +# endif + +# define MCAN1_TXEVENTFIFO_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_TXEVENTFIFO_SIZE << 3) +# define MCAN1_TXEVENTFIFO_WORDS \ + (MCAN1_TXEVENTFIFO_BYTES >> 2) + +# define MCAN1_TXFIFIOQ_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMA5_MCAN1_TXFIFOQ_SIZE * \ + MCAN1_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_TXFIFIOQ_WORDS (MCAN1_TXFIFIOQ_BYTES >> 2) + +/* MCAN1 Message RAM */ + +# define MCAN1_STDFILTER_INDEX 0 +# define MCAN1_EXTFILTERS_INDEX (MCAN1_STDFILTER_INDEX + MCAN1_STDFILTER_WORDS) +# define MCAN1_RXFIFO0_INDEX (MCAN1_EXTFILTERS_INDEX + MCAN1_EXTFILTER_WORDS) +# define MCAN1_RXFIFO1_INDEX (MCAN1_RXFIFO0_INDEX + MCAN1_RXFIFO0_WORDS) +# define MCAN1_RXDEDICATED_INDEX (MCAN1_RXFIFO1_INDEX + MCAN1_RXFIFO1_WORDS) +# define MCAN1_TXEVENTFIFO_INDEX (MCAN1_RXDEDICATED_INDEX + MCAN1_DEDICATED_RXBUFFER_WORDS) +# define MCAN1_TXDEDICATED_INDEX (MCAN1_TXEVENTFIFO_INDEX + MCAN1_TXEVENTFIFO_WORDS) +# define MCAN1_TXFIFOQ_INDEX (MCAN1_TXDEDICATED_INDEX + MCAN1_DEDICATED_TXBUFFER_WORDS) +# define MCAN1_MSGRAM_WORDS (MCAN1_TXFIFOQ_INDEX + MCAN1_TXFIFIOQ_WORDS) + +#endif /* CONFIG_SAMA5_MCAN1 */ + +/* MCAN helpers */ + +#define MAILBOX_ADDRESS(a) ((uint32_t)(a) & 0x0000fffc) + +/* Interrupts */ + +/* Common interrupts + * + * MCAN_INT_TSW - Timestamp Wraparound + * MCAN_INT_MRAF - Message RAM Access Failure + * MCAN_INT_TOO - Timeout Occurred + * MCAN_INT_ELO - Error Logging Overflow + * MCAN_INT_EP - Error Passive + * MCAN_INT_EW - Warning Status + * MCAN_INT_BO - Bus_Off Status + * MCAN_INT_WDI - Watchdog Interrupt + */ + +#define MCAN_CMNERR_INTS (MCAN_INT_MRAF | MCAN_INT_TOO | MCAN_INT_EP | \ + MCAN_INT_BO | MCAN_INT_WDI) +#define MCAN_COMMON_INTS MCAN_CMNERR_INTS + +/* RXFIFO mode interrupts + * + * MCAN_INT_RF0N - Receive FIFO 0 New Message + * MCAN_INT_RF0W - Receive FIFO 0 Watermark Reached + * MCAN_INT_RF0F - Receive FIFO 0 Full + * MCAN_INT_RF0L - Receive FIFO 0 Message Lost + * MCAN_INT_RF1N - Receive FIFO 1 New Message + * MCAN_INT_RF1W - Receive FIFO 1 Watermark Reached + * MCAN_INT_RF1F - Receive FIFO 1 Full + * MCAN_INT_RF1L - Receive FIFO 1 Message Lost + * MCAN_INT_HPM - High Priority Message Received + * + * Dedicated RX Buffer mode interrupts + * + * MCAN_INT_DRX - Message stored to Dedicated Receive Buffer + * + * Mode-independent RX-related interrupts + * + * MCAN_INT_CRCE - Receive CRC Error + * MCAN_INT_FOE - Format Error + * MCAN_INT_STE - Stuff Error + */ + +#define MCAN_RXCOMMON_INTS (MCAN_INT_CRCE | MCAN_INT_FOE | MCAN_INT_STE) +#define MCAN_RXFIFO0_INTS (MCAN_INT_RF0N | MCAN_INT_RF0W | MCAN_INT_RF0L) +#define MCAN_RXFIFO1_INTS (MCAN_INT_RF1N | MCAN_INT_RF1W | MCAN_INT_RF1L) +#define MCAN_RXFIFO_INTS (MCAN_RXFIFO0_INTS | MCAN_RXFIFO1_INTS | \ + MCAN_INT_HPM | MCAN_RXCOMMON_INTS) +#define MCAN_RXDEDBUF_INTS (MCAN_INT_DRX | MCAN_RXCOMMON_INTS) + +#define MCAN_RXERR_INTS (MCAN_INT_RF0L | MCAN_INT_RF1L | MCAN_INT_CRCE | \ + MCAN_INT_FOE | MCAN_INT_STE) + +/* TX FIFOQ mode interrupts + * + * MCAN_INT_TFE - Tx FIFO Empty + * + * TX Event FIFO interrupts + * + * MCAN_INT_TEFN - Tx Event FIFO New Entry + * MCAN_INT_TEFW - Tx Event FIFO Watermark Reached + * MCAN_INT_TEFF - Tx Event FIFO Full + * MCAN_INT_TEFL - Tx Event FIFO Element Lost + * + * Mode-independent TX-related interrupts + * + * MCAN_INT_TC - Transmission Completed + * MCAN_INT_TCF - Transmission Cancellation Finished + * MCAN_INT_BE - Bit Error + * MCAN_INT_ACKE - Acknowledge Error + */ + +#define MCAN_TXCOMMON_INTS (MCAN_INT_TC | MCAN_INT_TCF | MCAN_INT_BE | \ + MCAN_INT_ACKE) +#define MCAN_TXFIFOQ_INTS (MCAN_INT_TFE | MCAN_TXCOMMON_INTS) +#define MCAN_TXEVFIFO_INTS (MCAN_INT_TEFN | MCAN_INT_TEFW | MCAN_INT_TEFF | \ + MCAN_INT_TEFL) +#define MCAN_TXDEDBUF_INTS MCAN_TXCOMMON_INTS + +#define MCAN_TXERR_INTS (MCAN_INT_TEFL | MCAN_INT_BE | MCAN_INT_ACKE) + +/* Common-, TX- and RX-Error-Mask */ + +#define MCAN_ANYERR_INTS (MCAN_CMNERR_INTS | MCAN_RXERR_INTS | MCAN_TXERR_INTS) + +/* Debug */ + +/* Debug configurations that may be enabled just for testing MCAN */ + +#ifndef CONFIG_DEBUG_CAN_INFO +# undef CONFIG_SAMA5_MCAN_REGDEBUG +#endif + +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG +# define reginfo caninfo +#else +# define reginfo(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CAN mode of operation */ + +enum sam_canmode_e +{ + MCAN_ISO11898_1_MODE = 0, /* CAN operation according to ISO11898-1 */ + MCAN_FD_MODE = 1, /* CAN FD operation */ + MCAN_FD_BSW_MODE = 2 /* CAN FD operation with bit rate switching */ +}; + +/* CAN driver state */ + +enum can_state_s +{ + MCAN_STATE_UNINIT = 0, /* Not yet initialized */ + MCAN_STATE_RESET, /* Initialized, reset state */ + MCAN_STATE_SETUP, /* can_setup() has been called */ +}; + +/* This structure describes the MCAN message RAM layout */ + +struct sam_msgram_s +{ + uint32_t *stdfilters; /* Standard filters */ + uint32_t *extfilters; /* Extended filters */ + uint32_t *rxfifo0; /* RX FIFO0 */ + uint32_t *rxfifo1; /* RX FIFO1 */ + uint32_t *rxdedicated; /* RX dedicated buffers */ + uint32_t *txeventfifo; /* TX event FIFO */ + uint32_t *txdedicated; /* TX dedicated buffers */ + uint32_t *txfifoq; /* TX FIFO queue */ +}; + +/* This structure provides the constant configuration of a MCAN peripheral */ + +struct sam_config_s +{ + uint32_t rxpinset; /* RX pin configuration */ + uint32_t txpinset; /* TX pin configuration */ + uintptr_t base; /* Base address of the MCAN registers */ + uint32_t baud; /* Configured baud */ + uint32_t btp; /* Bit timing/prescaler register setting */ + uint32_t fbtp; /* Fast bit timing/prescaler register setting */ + uint8_t port; /* MCAN port number (1 or 2) */ + uint8_t pid; /* MCAN peripheral ID */ + uint8_t irq0; /* MCAN peripheral IRQ number for int. line 0 */ + uint8_t irq1; /* MCAN peripheral IRQ number for int. line 1 */ + uint8_t mode; /* See enum sam_canmode_e */ + uint8_t nstdfilters; /* Number of standard filters (up to 128) */ + uint8_t nextfilters; /* Number of extended filters (up to 64) */ + uint8_t nrxfifo0; /* Number of RX FIFO0 elements (up to 64) */ + uint8_t nrxfifo1; /* Number of RX FIFO1 elements (up to 64) */ + uint8_t nrxdedicated; /* Number of dedicated RX buffers (up to 64) */ + uint8_t ntxeventfifo; /* Number of TXevent FIFO elements (up to 32) */ + uint8_t ntxdedicated; /* Number of dedicated TX buffers (up to 64) */ + uint8_t ntxfifoq; /* Number of TX FIFO queue elements (up to 32) */ + uint8_t rxfifo0ecode; /* Encoded RX FIFO0 element size */ + uint8_t rxfifo0esize; /* RX FIFO0 element size (words) */ + uint8_t rxfifo1ecode; /* Encoded RX FIFO1 element size */ + uint8_t rxfifo1esize; /* RX FIFO1 element size (words) */ + uint8_t rxbufferecode; /* Encoded RX buffer element size */ + uint8_t rxbufferesize; /* RX buffer element size (words) */ + uint8_t txbufferecode; /* Encoded TX buffer element size */ + uint8_t txbufferesize; /* TX buffer element size (words) */ +#ifdef SAMA5_MCAN_LOOPBACK + bool loopback; /* True: Loopback mode */ +#endif + + /* MCAN message RAM layout */ + + struct sam_msgram_s msgram; +}; + +/* This structure provides the current state of a MCAN peripheral */ + +struct sam_mcan_s +{ + /* The constant configuration */ + + const struct sam_config_s *config; + + enum can_state_s state; /* See enum can_state_s */ +#ifdef CONFIG_CAN_EXTID + uint8_t nextalloc; /* Number of allocated extended filters */ +#endif + uint8_t nstdalloc; /* Number of allocated standard filters */ + mutex_t lock; /* Enforces mutually exclusive access */ + sem_t txfsem; /* Used to wait for TX FIFO availability */ + uint32_t btp; /* Current bit timing */ + uint32_t fbtp; /* Current fast bit timing */ + uint32_t rxints; /* Configured RX interrupts */ + uint32_t txints; /* Configured TX interrupts */ + +#ifdef CONFIG_CAN_EXTID + uint32_t extfilters[2]; /* Extended filter bit allocator. 2*32=64 */ +#endif + uint32_t stdfilters[4]; /* Standard filter bit allocator. 4*32=128 */ + +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG + uintptr_t regaddr; /* Last register address read */ + uint32_t regval; /* Last value read from the register */ + unsigned int count; /* Number of times that the value was read */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* MCAN Register access */ + +static uint32_t mcan_getreg(struct sam_mcan_s *priv, int offset); +static void mcan_putreg(struct sam_mcan_s *priv, int offset, + uint32_t regval); +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG +static void mcan_dumpregs(struct sam_mcan_s *priv, const char *msg); +#else +# define mcan_dumpregs(priv,msg) +#endif + +static void mcan_buffer_reserve(struct sam_mcan_s *priv); +static void mcan_buffer_release(struct sam_mcan_s *priv); + +/* MCAN helpers */ + +static uint8_t mcan_dlc2bytes(struct sam_mcan_s *priv, uint8_t dlc); +#if 0 /* Not used */ +static uint8_t mcan_bytes2dlc(struct sam_mcan_s *priv, uint8_t nbytes); +#endif + +#ifdef CONFIG_CAN_EXTID +static int mcan_add_extfilter(struct sam_mcan_s *priv, + struct canioc_extfilter_s *extconfig); +static int mcan_del_extfilter(struct sam_mcan_s *priv, int ndx); +#endif +static int mcan_add_stdfilter(struct sam_mcan_s *priv, + struct canioc_stdfilter_s *stdconfig); +static int mcan_del_stdfilter(struct sam_mcan_s *priv, int ndx); + +/* CAN driver methods */ + +static void mcan_reset(struct can_dev_s *dev); +static int mcan_setup(struct can_dev_s *dev); +static void mcan_shutdown(struct can_dev_s *dev); +static void mcan_rxint(struct can_dev_s *dev, bool enable); +static void mcan_txint(struct can_dev_s *dev, bool enable); +static int mcan_ioctl(struct can_dev_s *dev, int cmd, + unsigned long arg); +static int mcan_remoterequest(struct can_dev_s *dev, uint16_t id); +static int mcan_send(struct can_dev_s *dev, struct can_msg_s *msg); +static bool mcan_txready(struct can_dev_s *dev); +static bool mcan_txempty(struct can_dev_s *dev); + +/* MCAN interrupt handling */ + +#ifndef DEDICATED_BUFFERS_NOT_USED +static bool mcan_dedicated_rxbuffer_available(struct sam_mcan_s *priv, + int bufndx); +#endif +#ifdef CONFIG_CAN_ERRORS +static void mcan_error(struct can_dev_s *dev, uint32_t status); +#endif +static void mcan_receive(struct can_dev_s *dev, + uint32_t *rxbuffer, unsigned long nwords); +static int mcan_interrupt(int irq, void *context, void *arg); + +/* Hardware initialization */ + +static int mcan_hw_initialize(struct sam_mcan_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct can_ops_s g_mcanops = +{ + .co_reset = mcan_reset, + .co_setup = mcan_setup, + .co_shutdown = mcan_shutdown, + .co_rxint = mcan_rxint, + .co_txint = mcan_txint, + .co_ioctl = mcan_ioctl, + .co_remoterequest = mcan_remoterequest, + .co_send = mcan_send, + .co_txready = mcan_txready, + .co_txempty = mcan_txempty, +}; + +static uint32_t g_mcan0_msgram[MCAN0_MSGRAM_WORDS] aligned_data(MCAN_ALIGN) +#ifdef CONFIG_ARCH_DCACHE + __attribute__((aligned(MCAN_ALIGN))); +#else + ; +#endif + +/* Constant configuration */ + +#ifdef CONFIG_SAMA5_MCAN0 + +static const struct sam_config_s g_mcan0const = +{ + .rxpinset = PIO_CAN0_RX, + .txpinset = PIO_CAN0_TX, + .base = SAM_MCAN0_VBASE, + .baud = CONFIG_SAMA5_MCAN0_BITRATE, + .btp = MCAN_BTP_BRP(MCAN0_BRP) | + MCAN_BTP_TSEG1(MCAN0_TSEG1) | + MCAN_BTP_TSEG2(MCAN0_TSEG2) | + MCAN_BTP_SJW(MCAN0_SJW), + .fbtp = MCAN_FBTP_FBRP(MCAN0_FBRP) | + MCAN_FBTP_FTSEG1(MCAN0_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN0_FTSEG2) | + MCAN_FBTP_FSJW(MCAN0_FSJW), + .port = 0, + .pid = SAM_PID_MCAN00, + .irq0 = SAM_IRQ_MCAN00, + .irq1 = SAM_IRQ_MCAN01, +#if defined(CONFIG_SAMA5_MCAN0_ISO11898_1) + .mode = MCAN_ISO11898_1_MODE, +#elif defined(CONFIG_SAMA5_MCAN0_FD) + .mode = MCAN_FD_MODE, +#else /* if defined(CONFIG_SAMA5_MCAN0_FD_BSW) */ + .mode = MCAN_FD_BSW_MODE, +#endif + .nstdfilters = CONFIG_SAMA5_MCAN0_NSTDFILTERS, + .nextfilters = CONFIG_SAMA5_MCAN0_NEXTFILTERS, + .nrxfifo0 = CONFIG_SAMA5_MCAN0_RXFIFO0_SIZE, + .nrxfifo1 = CONFIG_SAMA5_MCAN0_RXFIFO1_SIZE, + .nrxdedicated = CONFIG_SAMA5_MCAN0_DEDICATED_RXBUFFER_SIZE, + .ntxeventfifo = CONFIG_SAMA5_MCAN0_TXEVENTFIFO_SIZE, + .ntxdedicated = CONFIG_SAMA5_MCAN0_DEDICATED_TXBUFFER_SIZE, + .ntxfifoq = CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE, + .rxfifo0ecode = MCAN0_RXFIFO0_ENCODED_SIZE, + .rxfifo0esize = (MCAN0_RXFIFO0_ELEMENT_SIZE / 4) + 2, + .rxfifo1ecode = MCAN0_RXFIFO1_ENCODED_SIZE, + .rxfifo1esize = (MCAN0_RXFIFO1_ELEMENT_SIZE / 4) + 2, + .rxbufferecode = MCAN0_RXBUFFER_ENCODED_SIZE, + .rxbufferesize = (MCAN0_RXBUFFER_ELEMENT_SIZE / 4) + 2, + .txbufferecode = MCAN0_TXBUFFER_ENCODED_SIZE, + .txbufferesize = (MCAN0_TXBUFFER_ELEMENT_SIZE / 4) + 2, + +#ifdef CONFIG_SAMA5_MCAN0_LOOPBACK + .loopback = true, +#endif + + /* MCAN0 Message RAM */ + + .msgram = + { + &g_mcan0_msgram[MCAN0_STDFILTER_INDEX], + &g_mcan0_msgram[MCAN0_EXTFILTERS_INDEX], + &g_mcan0_msgram[MCAN0_RXFIFO0_INDEX], + &g_mcan0_msgram[MCAN0_RXFIFO1_INDEX], + &g_mcan0_msgram[MCAN0_RXDEDICATED_INDEX], + &g_mcan0_msgram[MCAN0_TXEVENTFIFO_INDEX], + &g_mcan0_msgram[MCAN0_TXDEDICATED_INDEX], + &g_mcan0_msgram[MCAN0_TXFIFOQ_INDEX] + } +}; + +/* MCAN0 variable driver state */ + +static struct sam_mcan_s g_mcan0priv = +{ + .config = &g_mcan0const, + .lock = NXMUTEX_INITIALIZER, + .txfsem = SEM_INITIALIZER(CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE), +}; + +static struct can_dev_s g_mcan0dev = +{ + .cd_ops = &g_mcanops, + .cd_priv = &g_mcan0priv, +}; + +#endif /* CONFIG_SAMA5_MCAN0 */ + +#ifdef CONFIG_SAMA5_MCAN1 + +/* MCAN1 message RAM allocation */ + +static uint32_t g_mcan1_msgram[MCAN1_MSGRAM_WORDS] aligned_data(MCAN_ALIGN) +#ifdef CONFIG_ARCH_DCACHE + __attribute__((aligned(MCAN_ALIGN))); +#else + ; +#endif + +/* MCAN1 constant configuration */ + +static const struct sam_config_s g_mcan1const = +{ + .rxpinset = PIO_CAN1_RX, + .txpinset = PIO_CAN1_TX, + .base = SAM_MCAN1_VBASE, + .baud = CONFIG_SAMA5_MCAN1_BITRATE, + .btp = MCAN_BTP_BRP(MCAN1_BRP) | + MCAN_BTP_TSEG1(MCAN1_TSEG1) | + MCAN_BTP_TSEG2(MCAN1_TSEG2) | + MCAN_BTP_SJW(MCAN1_SJW), + .fbtp = MCAN_FBTP_FBRP(MCAN1_FBRP) | + MCAN_FBTP_FTSEG1(MCAN1_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN1_FTSEG2) | + MCAN_FBTP_FSJW(MCAN1_FSJW), + .port = 1, + .pid = SAM_PID_MCAN10, + .irq0 = SAM_IRQ_MCAN10, + .irq1 = SAM_IRQ_MCAN11, +#if defined(CONFIG_SAMA5_MCAN1_ISO11898_1) + .mode = MCAN_ISO11898_1_MODE, +#elif defined(CONFIG_SAMA5_MCAN1_FD) + .mode = MCAN_FD_MODE, +#else /* if defined(CONFIG_SAMA5_MCAN1_FD_BSW) */ + .mode = MCAN_FD_BSW_MODE, +#endif + .nstdfilters = CONFIG_SAMA5_MCAN1_NSTDFILTERS, + .nextfilters = CONFIG_SAMA5_MCAN1_NEXTFILTERS, + .nrxfifo0 = CONFIG_SAMA5_MCAN1_RXFIFO0_SIZE, + .nrxfifo1 = CONFIG_SAMA5_MCAN1_RXFIFO1_SIZE, + .nrxdedicated = CONFIG_SAMA5_MCAN1_DEDICATED_RXBUFFER_SIZE, + .ntxeventfifo = CONFIG_SAMA5_MCAN1_TXEVENTFIFO_SIZE, + .ntxdedicated = CONFIG_SAMA5_MCAN1_DEDICATED_TXBUFFER_SIZE, + .ntxfifoq = CONFIG_SAMA5_MCAN1_TXFIFOQ_SIZE, + .rxfifo0ecode = MCAN1_RXFIFO0_ENCODED_SIZE, + .rxfifo0esize = (MCAN1_RXFIFO0_ELEMENT_SIZE / 4) + 2, + .rxfifo1ecode = MCAN1_RXFIFO1_ENCODED_SIZE, + .rxfifo1esize = (MCAN1_RXFIFO1_ELEMENT_SIZE / 4) + 2, + .rxbufferecode = MCAN1_RXBUFFER_ENCODED_SIZE, + .rxbufferesize = (MCAN1_RXBUFFER_ELEMENT_SIZE / 4) + 2, + .txbufferecode = MCAN1_TXBUFFER_ENCODED_SIZE, + .txbufferesize = (MCAN1_TXBUFFER_ELEMENT_SIZE / 4) + 2, + +#ifdef CONFIG_SAMA5_MCAN1_LOOPBACK + .loopback = true, +#endif + /* MCAN1 Message RAM */ + + .msgram = + { + &g_mcan1_msgram[MCAN1_STDFILTER_INDEX], + &g_mcan1_msgram[MCAN1_EXTFILTERS_INDEX], + &g_mcan1_msgram[MCAN1_RXFIFO0_INDEX], + &g_mcan1_msgram[MCAN1_RXFIFO1_INDEX], + &g_mcan1_msgram[MCAN1_RXDEDICATED_INDEX], + &g_mcan1_msgram[MCAN1_TXEVENTFIFO_INDEX], + &g_mcan1_msgram[MCAN1_TXDEDICATED_INDEX], + &g_mcan1_msgram[MCAN1_TXFIFOQ_INDEX] + } +}; + +/* MCAN1 variable driver state */ + +static struct sam_mcan_s g_mcan1priv = +{ + .config = &g_mcan1const, + .lock = NXMUTEX_INITIALIZER, + .txfsem = SEM_INITIALIZER(CONFIG_SAMA5_MCAN0_TXFIFOQ_SIZE), +}; + +static struct can_dev_s g_mcan1dev = +{ + .cd_ops = &g_mcanops, + .cd_priv = &g_mcan1priv, +}; + +#endif /* CONFIG_SAMA5_MCAN1 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mcan_getreg + * + * Description: + * Read the value of a MCAN register. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * offset - The offset to the register to read + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG +static uint32_t mcan_getreg(struct sam_mcan_s *priv, int offset) +{ + const struct sam_config_s *config = priv->config; + uintptr_t regaddr; + uint32_t regval; + + /* Read the value from the register */ + + regaddr = config->base + offset; + regval = getreg32(regaddr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (regaddr == priv->regaddr && regval == priv->regval) + { + if (priv->count == 0xffffffff || ++priv->count > 3) + { + if (priv->count == 4) + { + caninfo("...\n"); + } + + return regval; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (priv->count > 3) + { + /* Yes.. then show how many times the value repeated */ + + caninfo("[repeats %d more times]\n", priv->count - 3); + } + + /* Save the new address, value, and count */ + + priv->regaddr = regaddr; + priv->regval = regval; + priv->count = 1; + } + + /* Show the register value read */ + + caninfo("%08" PRIx32 "->%08" PRIx32 "\n", regaddr, regval); + return regval; +} + +#else +static uint32_t mcan_getreg(struct sam_mcan_s *priv, int offset) +{ + const struct sam_config_s *config = priv->config; + return getreg32(config->base + offset); +} + +#endif /* CONFIG_SAMA5_MCAN_REGDEBUG */ + +/**************************************************************************** + * Name: mcan_putreg + * + * Description: + * Set the value of a MCAN register. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * offset - The offset to the register to write + * regval - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG +static void mcan_putreg(struct sam_mcan_s *priv, int offset, + uint32_t regval) +{ + const struct sam_config_s *config = priv->config; + uintptr_t regaddr = config->base + offset; + + /* Show the register value being written */ + + caninfo("%08" PRIx32 "<-%08" PRIx32 "\n", regaddr, regval); + + /* Write the value */ + + putreg32(regval, regaddr); +} + +#else +static void mcan_putreg(struct sam_mcan_s *priv, int offset, + uint32_t regval) +{ + const struct sam_config_s *config = priv->config; + + putreg32(regval, config->base + offset); +} + +#endif + +/**************************************************************************** + * Name: mcan_dumpregs + * + * Description: + * Dump the contents of all MCAN control registers + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_MCAN_REGDEBUG +static void mcan_dumpregs(struct sam_mcan_s *priv, const char *msg) +{ + const struct sam_config_s *config = priv->config; + + caninfo("MCAN%d Registers: %s\n", config->port, msg); + caninfo(" Base: %08x\n", config->base); + + caninfo ("UTMI ref clk=%d\n", getreg32(SAM_SFR_VBASE + + SAM_SFR_UTMICKTRIM_OFFSET) & + 0x03); + + putreg32(PMC_PCR_PID(SAM_PID_MCAN0), SAM_PMC_PCR); + caninfo(" MCREL: %08x ENDN: %08x PMC_PCR %08x\n", + getreg32(config->base + SAM_MCAN_CREL_OFFSET), + getreg32(config->base + SAM_MCAN_ENDN_OFFSET), + getreg32(SAM_PMC_PCR)); + + caninfo(" CUST: %08x FBTP: %08x TEST: %08x RWD: %08x\n", + getreg32(config->base + SAM_MCAN_CUST_OFFSET), + getreg32(config->base + SAM_MCAN_FBTP_OFFSET), + getreg32(config->base + SAM_MCAN_TEST_OFFSET), + getreg32(config->base + SAM_MCAN_RWD_OFFSET)); + + caninfo(" CCCR: %08x NBTP: %08x TSCC: %08x TSCV: %08x\n", + getreg32(config->base + SAM_MCAN_CCCR_OFFSET), + getreg32(config->base + SAM_MCAN_BTP_OFFSET), + getreg32(config->base + SAM_MCAN_TSCC_OFFSET), + getreg32(config->base + SAM_MCAN_TSCV_OFFSET)); + + caninfo(" TOCC: %08x TOCV: %08x ECR: %08x PSR: %08x\n", + getreg32(config->base + SAM_MCAN_TOCC_OFFSET), + getreg32(config->base + SAM_MCAN_TOCV_OFFSET), + getreg32(config->base + SAM_MCAN_ECR_OFFSET), + getreg32(config->base + SAM_MCAN_PSR_OFFSET)); + + caninfo(" IR: %08x IE: %08x ILS: %08x ILE: %08x\n", + getreg32(config->base + SAM_MCAN_IR_OFFSET), + getreg32(config->base + SAM_MCAN_IE_OFFSET), + getreg32(config->base + SAM_MCAN_ILS_OFFSET), + getreg32(config->base + SAM_MCAN_ILE_OFFSET)); + + caninfo(" GFC: %08x SIDFC: %08x XIDFC: %08x XIDAM: %08x\n", + getreg32(config->base + SAM_MCAN_GFC_OFFSET), + getreg32(config->base + SAM_MCAN_SIDFC_OFFSET), + getreg32(config->base + SAM_MCAN_XIDFC_OFFSET), + getreg32(config->base + SAM_MCAN_XIDAM_OFFSET)); + + caninfo(" HPMS: %08x NDAT1: %08x NDAT2: %08x RXF0C: %08x\n", + getreg32(config->base + SAM_MCAN_HPMS_OFFSET), + getreg32(config->base + SAM_MCAN_NDAT1_OFFSET), + getreg32(config->base + SAM_MCAN_NDAT2_OFFSET), + getreg32(config->base + SAM_MCAN_RXF0C_OFFSET)); + + caninfo(" RXF0S: %08x FXF0A: %08x RXBC: %08x RXF1C: %08x\n", + getreg32(config->base + SAM_MCAN_RXF0S_OFFSET), + getreg32(config->base + SAM_MCAN_RXF0A_OFFSET), + getreg32(config->base + SAM_MCAN_RXBC_OFFSET), + getreg32(config->base + SAM_MCAN_RXF1C_OFFSET)); + + caninfo(" RXF1S: %08x FXF1A: %08x RXESC: %08x TXBC: %08x\n", + getreg32(config->base + SAM_MCAN_RXF1S_OFFSET), + getreg32(config->base + SAM_MCAN_RXF1A_OFFSET), + getreg32(config->base + SAM_MCAN_RXESC_OFFSET), + getreg32(config->base + SAM_MCAN_TXBC_OFFSET)); + + caninfo(" TXFQS: %08x TXESC: %08x TXBRP: %08x TXBAR: %08x\n", + getreg32(config->base + SAM_MCAN_TXFQS_OFFSET), + getreg32(config->base + SAM_MCAN_TXESC_OFFSET), + getreg32(config->base + SAM_MCAN_TXBRP_OFFSET), + getreg32(config->base + SAM_MCAN_TXBAR_OFFSET)); + + caninfo(" TXBCR: %08x TXBTO: %08x TXBCF: %08x TXBTIE: %08x\n", + getreg32(config->base + SAM_MCAN_TXBCR_OFFSET), + getreg32(config->base + SAM_MCAN_TXBTO_OFFSET), + getreg32(config->base + SAM_MCAN_TXBCF_OFFSET), + getreg32(config->base + SAM_MCAN_TXBTIE_OFFSET)); + + caninfo("TXBCIE: %08x TXEFC: %08x TXEFS: %08x TXEFA: %08x\n", + getreg32(config->base + SAM_MCAN_TXBCIE_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFC_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFS_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFA_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: mcan_buffer_reserve + * + * Description: + * Take the semaphore, decrementing the semaphore count to indicate that + * one fewer TX FIFOQ buffer is available. Handles any exceptional + * conditions. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + * Assumptions: + * Called only non-interrupt logic via mcan_write(). We do not have + * exclusive access to the MCAN hardware and interrupts are not disabled. + * mcan_write() does lock the scheduler for reasons noted below. + * + ****************************************************************************/ + +static void mcan_buffer_reserve(struct sam_mcan_s *priv) +{ + irqstate_t flags; + uint32_t txfqs1; + uint32_t txfqs2; +#ifndef CONFIG_SAMA5_MCAN_QUEUE_MODE + int tffl; +#endif + int sval; + int ret; + + /* Wait until we successfully get the semaphore. EINTR is the only + * expected 'failure' (meaning that the wait for the semaphore was + * interrupted by a signal. + */ + + do + { + /* We take some extra precautions here because it is possible that on + * certain error conditions, the semaphore count could get out of + * phase with the actual count of elements in the TX FIFO (I have + * never seen this happen, however. My paranoia). + * + * An missed TX interrupt could cause the semaphore count to fail to + * be incremented and, hence, to be too low. + */ + + for (; ; ) + { + /* Get the current queue status and semaphore count. */ + + flags = enter_critical_section(); + txfqs1 = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + nxsem_get_value(&priv->txfsem, &sval); + txfqs2 = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + + /* If the semaphore count and the TXFQS samples are in + * sync, then break out of the look with interrupts + * disabled. + */ + + if (txfqs1 == txfqs2) + { + break; + } + + /* Otherwise, re-enable interrupts to interrupts that may + * resynchronize, the semaphore count and try again. + */ + + leave_critical_section(flags); + } + +#ifdef CONFIG_SAMA5_MCAN_QUEUE_MODE + /* We only have one useful bit of information in the TXFQS: + * Is the TX FIFOQ full or not? We can only do limited checks + * with that single bit of information. + */ + + if ((txfqs1 & MCAN_TXFQS_TFQF) != 0) + { + /* The TX FIFOQ is full. The semaphore count should then be + * less than or equal to zero. If it is greater than zero, + * then reinitialize it to 0. + */ + + if (sval > 0) + { + canerr("ERROR: TX FIFOQ full but txfsem is %d\n", sval); + nxsem_reset(&priv->txfsem, 0); + } + } + + /* The FIFO is not full so the semaphore count should be greater + * than zero. If it is not, then we have missed a call to + * mcan_buffer_release(0). + * + * NOTE: Since there is no mutual exclusion, it might be possible + * that mcan_write() could be re-entered AFTER taking the semaphore + * and dropping the count to zero, but BEFORE adding the message + * to the TX FIFOQ. That corner case is handled in mcan_write() by + * locking the scheduler. + */ + + else if (sval <= 0) + { + canerr("ERROR: TX FIFOQ not full but txfsem is %d\n", sval); + + /* Less than zero means that another thread is waiting */ + + if (sval < 0) + { + /* Bump up the count by one and try again */ + + nxsem_post(&priv->txfsem); + leave_critical_section(flags); + continue; + } + + /* Exactly zero but the FIFO is not full. Just return without + * decrementing the count. + */ + + leave_critical_section(flags); + return; + } +#else + /* Tx FIFO Free Level */ + + tffl = (txfqs1 & MCAN_TXFQS_TFFL_MASK) >> MCAN_TXFQS_TFFL_SHIFT; + + /* Check if the configured number is less than the number of buffers + * in the chip + */ + + if (tffl > priv->config->ntxfifoq) + { + canerr("ERROR: TX FIFO reports %d but max is %d\n", + tffl, priv->config->ntxfifoq); + tffl = priv->config->ntxfifoq; + } + + /* REVISIT: There may be issues with this logic in a multi-thread + * environment. If there is only a single thread, then certainly + * sval and tff1 should match, but that may not be true in any multi- + * threaded use of this driver. + */ + + if (sval != tffl) + { + canerr("ERROR: TX FIFO reports %d but txfsem is %d\n", tffl, sval); + + /* Reset the semaphore count to the Tx FIFO free level. */ + + nxsem_reset(&priv->txfsem, tffl); + } +#endif + + /* The semaphore value is reasonable. Wait for the next TX interrupt. */ + + ret = nxsem_wait(&priv->txfsem); + leave_critical_section(flags); + } + while (ret < 0); +} + +/**************************************************************************** + * Name: mcan_buffer_release + * + * Description: + * Release the semaphore, increment the semaphore count to indicate that + * one more TX FIFOQ buffer is available. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + * Assumptions: + * This function is called only from the interrupt level in response to the + * complete of a transmission. + * + ****************************************************************************/ + +static void mcan_buffer_release(struct sam_mcan_s *priv) +{ + int sval; + + /* We take some extra precautions here because it is possible that on + * certain error conditions, the semaphore count could get out of phase + * with the actual count of elements in the TX FIFO (I have never seen + * this happen, however. My paranoia). + * + * An extra TC interrupt could cause the count to be incremented too + * many times. + */ + + nxsem_get_value(&priv->txfsem, &sval); + if (sval < priv->config->ntxfifoq) + { + nxsem_post(&priv->txfsem); + } + else + { + canerr("ERROR: txfsem would increment beyond %d\n", + priv->config->ntxfifoq); + } +} + +/**************************************************************************** + * Name: mcan_dlc2bytes + * + * Description: + * In the CAN FD format, the coding of the DLC differs from the standard + * CAN format. The DLC codes 0 to 8 have the same coding as in standard + * CAN. But the codes 9 to 15 all imply a data field of 8 bytes with + * standard CAN. In CAN FD mode, the values 9 to 15 are encoded to values + * in the range 12 to 64. + * + * Input Parameters: + * dlc - the DLC value to convert to a byte count + * + * Returned Value: + * The number of bytes corresponding to the DLC value. + * + ****************************************************************************/ + +static uint8_t mcan_dlc2bytes(struct sam_mcan_s *priv, uint8_t dlc) +{ + if (dlc > 8) + { +#ifdef CONFIG_CAN_FD + if (priv->config->mode == MCAN_ISO11898_1_MODE) + { + return 8; + } + else + { + switch (dlc) + { + case 9: + return 12; + case 10: + return 16; + case 11: + return 20; + case 12: + return 24; + case 13: + return 32; + case 14: + return 48; + default: + case 15: + return 64; + } + } +#else + return 8; +#endif + } + + return dlc; +} + +/**************************************************************************** + * Name: mcan_bytes2dlc + * + * Description: + * In the CAN FD format, the coding of the DLC differs from the standard + * CAN format. The DLC codes 0 to 8 have the same coding as in standard + * CAN. But the codes 9 to 15 all imply a data field of 8 bytes with + * standard CAN. In CAN FD mode, the values 9 to 15 are encoded to values + * in the range 12 to 64. + * + * Input Parameters: + * nbytes - the byte count to convert to a DLC value + * + * Returned Value: + * The encoded DLC value corresponding to at least that number of bytes. + * + ****************************************************************************/ + +#if 0 /* Not used */ +static uint8_t mcan_bytes2dlc(struct sam_mcan_s *priv, uint8_t nbytes) +{ + if (nbytes <= 8) + { + return nbytes; + } +#ifdef CONFIG_CAN_FD + else if (priv->mode == MCAN_ISO11898_1_MODE) + { + return 8; + } + else if (nbytes <= 12) + { + return 9; + } + else if (nbytes <= 16) + { + return 10; + } + else if (nbytes <= 20) + { + return 11; + } + else if (nbytes <= 24) + { + return 12; + } + else if (nbytes <= 32) + { + return 13; + } + else if (nbytes <= 48) + { + return 14; + } + else /* if (nbytes <= 64) */ + { + return 15; + } +#else + else + { + return 8; + } +#endif +} +#endif + +/**************************************************************************** + * Name: mcan_add_extfilter + * + * Description: + * Add an address filter for a extended 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * extconfig - The configuration of the extended filter + * + * Returned Value: + * A non-negative filter ID is returned on success. Otherwise a negated + * errno value is returned to indicate the nature of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int mcan_add_extfilter(struct sam_mcan_s *priv, + struct canioc_extfilter_s *extconfig) +{ + const struct sam_config_s *config; + uint32_t *extfilter; + uint32_t regval; + int word; + int bit; + int ndx; + int ret; + + DEBUGASSERT(priv != NULL && priv->config != NULL && extconfig != NULL); + config = priv->config; + + /* Get exclusive excess to the MCAN hardware */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Find an unused standard filter */ + + for (ndx = 0; ndx < config->nextfilters; ndx++) + { + /* Is this filter assigned? */ + + word = ndx >> 5; + bit = ndx & 0x1f; + + if ((priv->extfilters[word] & (1 << bit)) == 0) + { + /* No, assign the filter */ + + DEBUGASSERT(priv->nextalloc < priv->config->nstdfilters); + priv->extfilters[word] |= (1 << bit); + priv->nextalloc++; + + extfilter = config->msgram.extfilters + (ndx << 1); + + /* Format and write filter word F0 */ + + DEBUGASSERT(extconfig->xf_id1 <= CAN_MAX_EXTMSGID); + regval = EXTFILTER_F0_EFID1(extconfig->xf_id1); + + if (extconfig->xf_prio == 0) + { + regval |= EXTFILTER_F0_EFEC_FIFO0; + } + else + { + regval |= EXTFILTER_F0_EFEC_FIFO0; + } + + extfilter[0] = regval; + + /* Format and write filter word F1 */ + + DEBUGASSERT(extconfig->xf_id2 <= CAN_MAX_EXTMSGID); + regval = EXTFILTER_F1_EFID2(extconfig->xf_id2); + + switch (extconfig->xf_type) + { + default: + case CAN_FILTER_DUAL: + regval |= EXTFILTER_F1_EFT_DUAL; + break; + + case CAN_FILTER_MASK: + regval |= EXTFILTER_F1_EFT_CLASSIC; + break; + case CAN_FILTER_RANGE: + regval |= EXTFILTER_F1_EFT_RANGE; + break; + } + + extfilter[1] = regval; + + /* Flush the filter entry into physical RAM */ + + up_clean_dcache((uintptr_t)extfilter, (uintptr_t)extfilter + 8); + + /* Is this the first extended filter? */ + + if (priv->nextalloc == 1) + { + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & + MCAN_CCCR_INIT) == 0) + { + } + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFE=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Disable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + } + + nxmutex_unlock(&priv->lock); + return ndx; + } + } + + DEBUGASSERT(priv->nextalloc == priv->config->nextfilters); + nxmutex_unlock(&priv->lock); + return -EAGAIN; +} +#endif + +/**************************************************************************** + * Name: mcan_del_extfilter + * + * Description: + * Remove an address filter for a standard 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * ndx - The filter index previously returned by the mcan_add_extfilter(). + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int mcan_del_extfilter(struct sam_mcan_s *priv, int ndx) +{ + const struct sam_config_s *config; + uint32_t *extfilter; + uint32_t regval; + int word; + int bit; + int ret; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + + /* Check user Parameters */ + + DEBUGASSERT(ndx >= 0 || ndx < config->nextfilters); + + if (ndx < 0 || ndx >= config->nextfilters) + { + return -EINVAL; + } + + /* Get exclusive excess to the MCAN hardware */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + word = ndx >> 5; + bit = ndx & 0x1f; + + /* Check if this filter is really assigned */ + + if ((priv->extfilters[word] & (1 << bit)) == 0) + { + /* No, error out */ + + nxmutex_unlock(&priv->lock); + return -ENOENT; + } + + /* Release the filter */ + + priv->extfilters[word] &= ~(1 << bit); + + DEBUGASSERT(priv->nextalloc > 0); + priv->nextalloc--; + + /* Was that the last extended filter? */ + + if (priv->nextalloc == 0) + { + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & + MCAN_CCCR_INIT) == 0) + { + } + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* If there are no extended filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFE=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Disable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + extfilter = config->msgram.extfilters + (ndx << 1); + *extfilter++ = 0; + *extfilter = 0; + + nxmutex_unlock(&priv->lock); + return OK; +} +#endif + +/**************************************************************************** + * Name: mcan_add_stdfilter + * + * Description: + * Add an address filter for a standard 11 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * stdconfig - The configuration of the standard filter + * + * Returned Value: + * A non-negative filter ID is returned on success. Otherwise a negated + * errno value is returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_add_stdfilter(struct sam_mcan_s *priv, + struct canioc_stdfilter_s *stdconfig) +{ + const struct sam_config_s *config; + uint32_t *stdfilter; + uint32_t regval; + int word; + int bit; + int ndx; + int ret; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + + /* Get exclusive excess to the MCAN hardware */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Find an unused standard filter */ + + for (ndx = 0; ndx < config->nstdfilters; ndx++) + { + /* Is this filter assigned? */ + + word = ndx >> 5; + bit = ndx & 0x1f; + + if ((priv->stdfilters[word] & (1 << bit)) == 0) + { + /* No, assign the filter */ + + DEBUGASSERT(priv->nstdalloc < priv->config->nstdfilters); + priv->stdfilters[word] |= (1 << bit); + priv->nstdalloc++; + + /* Format and write filter word S0 */ + + stdfilter = config->msgram.stdfilters + ndx; + + DEBUGASSERT(stdconfig->sf_id1 <= CAN_MAX_STDMSGID); + regval = STDFILTER_S0_SFID1(stdconfig->sf_id1); + + DEBUGASSERT(stdconfig->sf_id2 <= CAN_MAX_STDMSGID); + regval |= STDFILTER_S0_SFID2(stdconfig->sf_id2); + + if (stdconfig->sf_prio == 0) + { + regval |= STDFILTER_S0_SFEC_FIFO0; + } + else + { + regval |= STDFILTER_S0_SFEC_FIFO1; + } + + switch (stdconfig->sf_type) + { + default: + case CAN_FILTER_DUAL: + regval |= STDFILTER_S0_SFT_DUAL; + break; + + case CAN_FILTER_MASK: + regval |= STDFILTER_S0_SFT_CLASSIC; + break; + case CAN_FILTER_RANGE: + regval |= STDFILTER_S0_SFT_RANGE; + break; + } + + *stdfilter = regval; + + /* Flush the filter entry into physical RAM */ + + up_clean_dcache((uintptr_t)stdfilter, (uintptr_t)stdfilter + 4); + + /* Is this the first standard filter? */ + + if (priv->nstdalloc == 1) + { + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & + MCAN_CCCR_INIT) == 0) + { + } + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFS=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Disable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + } + + nxmutex_unlock(&priv->lock); + return ndx; + } + } + + DEBUGASSERT(priv->nstdalloc == priv->config->nstdfilters); + nxmutex_unlock(&priv->lock); + return -EAGAIN; +} + +/**************************************************************************** + * Name: mcan_del_stdfilter + * + * Description: + * Remove an address filter for a standard 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * ndx - The filter index previously returned by the mcan_add_stdfilter(). + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_del_stdfilter(struct sam_mcan_s *priv, int ndx) +{ + const struct sam_config_s *config; + uint32_t *stdfilter; + uint32_t regval; + int word; + int bit; + int ret; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + + /* Check Userspace Parameters */ + + DEBUGASSERT(ndx >= 0 || ndx < config->nstdfilters); + + if (ndx < 0 || ndx >= config->nstdfilters) + { + return -EINVAL; + } + + /* Get exclusive excess to the MCAN hardware */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + word = ndx >> 5; + bit = ndx & 0x1f; + + /* Check if this filter is really assigned */ + + if ((priv->stdfilters[word] & (1 << bit)) == 0) + { + /* No, error out */ + + nxmutex_unlock(&priv->lock); + return -ENOENT; + } + + /* Release the filter */ + + priv->stdfilters[word] &= ~(1 << bit); + + DEBUGASSERT(priv->nstdalloc > 0); + priv->nstdalloc--; + + /* Was that the last standard filter? */ + + if (priv->nstdalloc == 0) + { + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & + MCAN_CCCR_INIT) == 0) + { + } + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* If there are no standard filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Disable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + stdfilter = config->msgram.stdfilters + ndx; + *stdfilter = 0; + + nxmutex_unlock(&priv->lock); + return OK; +} + +/**************************************************************************** + * Name: mcan_start_busoff_recovery_sequence + * + * Description: + * This function initiates the BUS-OFF recovery sequence. + * CAN Specification Rev. 2.0 or ISO11898-1:2015 + * According the SAMV71 datasheet: + * + * "If the device goes Bus_Off, it will set MCAN_CCCR.INIT of its own + * accord, stopping all bus activities. Once MCAN_CCCR.INIT has been + * cleared by the processor (application), the device will then wait for + * 129 occurrences of Bus Idle (129 * 11 consecutive recessive bits) + * before resuming normal operation. At the end of the Bus_Off recovery + * sequence, the Error Management Counters will be reset. During the + * waiting time after the resetting of MCAN_CCCR.INIT, each time a + * sequence of 11 recessive bits has been monitored, a Bit0 Error code is + * written to MCAN_PSR.LEC, enabling the processor to readily check up + * whether the CAN bus is stuck at dominant or continuously disturbed and + * to monitor the Bus_Off recovery sequence. MCAN_ECR.REC is used to + * count these sequences." + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_start_busoff_recovery_sequence(struct sam_mcan_s *priv) +{ + uint32_t regval; + int ret; + + DEBUGASSERT(priv); + + /* Get exclusive access to the MCAN peripheral */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* only start BUS-OFF recovery if we are in BUS-OFF state */ + + regval = mcan_getreg(priv, SAM_MCAN_PSR_OFFSET); + if (!(regval & MCAN_PSR_BO)) + { + nxmutex_unlock(&priv->lock); + return -EPERM; + } + + /* Disable initialization mode to issue the recovery sequence */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + nxmutex_unlock(&priv->lock); + return OK; +} + +/**************************************************************************** + * Name: mcan_reset + * + * Description: + * Reset the MCAN device. Called early to initialize the hardware. This + * function is called, before mcan_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_reset(struct can_dev_s *dev) +{ + struct sam_mcan_s *priv; + const struct sam_config_s *config; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("MCAN%d\n", config->port); + UNUSED(config); + + /* Get exclusive access to the MCAN peripheral */ + + nxmutex_lock(&priv->lock); + + /* Disable all interrupts */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* Make sure that all buffers are released. + * + * REVISIT: What if a thread is waiting for a buffer? The following + * will not wake up any waiting threads. + */ + + nxsem_reset(&priv->txfsem, config->ntxfifoq); + + /* Disable peripheral clocking to the MCAN controller */ + + sam_disableperiph1(priv->config->pid); + priv->state = MCAN_STATE_RESET; + nxmutex_unlock(&priv->lock); +} + +/**************************************************************************** + * Name: mcan_setup + * + * Description: + * Configure the MCAN. This method is called the first time that the MCAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching MCAN interrupts. + * All MCAN interrupts are disabled upon return. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_setup(struct can_dev_s *dev) +{ + struct sam_mcan_s *priv; + const struct sam_config_s *config; + int ret; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("MCAN%d pid: %d\n", config->port, config->pid); + + /* Get exclusive access to the MCAN peripheral */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* MCAN hardware initialization */ + + ret = mcan_hw_initialize(priv); + if (ret < 0) + { + canerr("ERROR: MCAN%d H/W initialization failed: %d\n", + config->port, ret); + return ret; + } + + mcan_dumpregs(priv, "After hardware initialization"); + + /* Attach the MCAN interrupt handlers */ + + ret = irq_attach(config->irq0, mcan_interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach MCAN%d line 0 IRQ (%d)", + config->port, config->irq0); + return ret; + } + + ret = irq_attach(config->irq1, mcan_interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach MCAN%d line 1 IRQ (%d)", + config->port, config->irq1); + return ret; + } + + /* Enable receive interrupts */ + + priv->state = MCAN_STATE_SETUP; + mcan_rxint(dev, true); + + mcan_dumpregs(priv, "After receive setup"); + + /* Enable the interrupts at the NVIC (they are still disabled at the MCAN + * peripheral). + */ + + up_enable_irq(config->irq0); + up_enable_irq(config->irq1); + nxmutex_unlock(&priv->lock); + return OK; +} + +/**************************************************************************** + * Name: mcan_shutdown + * + * Description: + * Disable the MCAN. This method is called when the MCAN device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_shutdown(struct can_dev_s *dev) +{ + struct sam_mcan_s *priv; + const struct sam_config_s *config; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("MCAN%d\n", config->port); + + /* Get exclusive access to the MCAN peripheral */ + + nxmutex_lock(&priv->lock); + + /* Disable MCAN interrupts at the NVIC */ + + up_disable_irq(config->irq0); + up_disable_irq(config->irq1); + + /* Disable all interrupts from the MCAN peripheral */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* Detach the MCAN interrupt handler */ + + irq_detach(config->irq0); + irq_detach(config->irq1); + + /* Disable peripheral clocking to the MCAN controller */ + + sam_disableperiph1(priv->config->pid); + nxmutex_unlock(&priv->lock); +} + +/**************************************************************************** + * Name: mcan_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_rxint(struct can_dev_s *dev, bool enable) +{ + struct sam_mcan_s *priv = dev->cd_priv; + irqstate_t flags; + uint32_t regval; + + DEBUGASSERT(priv && priv->config); + + caninfo("MCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + flags = enter_critical_section(); + regval = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->rxints | MCAN_COMMON_INTS; + } + else + { + regval &= ~priv->rxints; + } + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, regval); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: mcan_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_txint(struct can_dev_s *dev, bool enable) +{ + struct sam_mcan_s *priv = dev->cd_priv; + irqstate_t flags; + uint32_t regval; + + DEBUGASSERT(priv && priv->config); + + caninfo("MCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + flags = enter_critical_section(); + regval = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->txints | MCAN_COMMON_INTS; + } + else + { + regval &= ~priv->txints; + } + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, regval); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: mcan_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg) +{ + struct sam_mcan_s *priv; + int ret = -ENOTTY; + + caninfo("cmd=%04x arg=%lu\n", cmd, arg); + + DEBUGASSERT(dev && dev->cd_priv); + priv = dev->cd_priv; + + /* Handle the command */ + + switch (cmd) + { + /* CANIOC_GET_BITTIMING: + * Description: Return the current bit timing settings + * Argument: A pointer to a write-able instance of struct + * canioc_bittiming_s in which current bit timing + * values will be returned. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies: None + */ + + case CANIOC_GET_BITTIMING: + { + struct canioc_bittiming_s *bt = + (struct canioc_bittiming_s *)arg; + uint32_t regval; + uint32_t brp; + + DEBUGASSERT(bt != NULL); + + regval = mcan_getreg(priv, SAM_MCAN_BTP_OFFSET); + bt->bt_sjw = ((regval & MCAN_BTP_SJW_MASK) >> + MCAN_BTP_SJW_SHIFT) + 1; + bt->bt_tseg1 = ((regval & MCAN_BTP_TSEG1_MASK) >> + MCAN_BTP_TSEG1_SHIFT) + 1; + bt->bt_tseg2 = ((regval & MCAN_BTP_TSEG2_MASK) >> + MCAN_BTP_TSEG2_SHIFT) + 1; + + brp = ((regval & MCAN_BTP_BRP_MASK) >> + MCAN_BTP_BRP_SHIFT) + 1; + bt->bt_baud = SAMA5_MCANCLK_FREQUENCY / brp / + (bt->bt_tseg1 + bt->bt_tseg2 + 1); + ret = OK; + } + break; + + /* CANIOC_SET_BITTIMING: + * Description: Set new current bit timing values + * Argument: A pointer to a read-able instance of struct + * canioc_bittiming_s in which the new bit timing + * values are provided. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies: None + * + * REVISIT: There is probably a limitation here: If there are + * multiple threads trying to send CAN packets, when one of these + * threads reconfigures the bitrate, the MCAN hardware will be reset + * and the context of operation will be lost. Hence, this IOCTL can + * only safely be executed in quiescent time periods. + */ + + case CANIOC_SET_BITTIMING: + { + const struct canioc_bittiming_s *bt = + (const struct canioc_bittiming_s *)arg; + irqstate_t flags; + uint32_t brp; + uint32_t tseg1; + uint32_t tseg2; + uint32_t sjw; + uint32_t ie; + uint8_t state; + + DEBUGASSERT(bt != NULL); + DEBUGASSERT(bt->bt_baud < SAMA5_MCANCLK_FREQUENCY); + DEBUGASSERT(bt->bt_sjw > 0 && bt->bt_sjw <= 16); + DEBUGASSERT(bt->bt_tseg1 > 1 && bt->bt_tseg1 <= 64); + DEBUGASSERT(bt->bt_tseg2 > 0 && bt->bt_tseg2 <= 16); + + /* Extract bit timing data */ + + tseg1 = bt->bt_tseg1 - 1; + tseg2 = bt->bt_tseg2 - 1; + sjw = bt->bt_sjw - 1; + + brp = (uint32_t) + (((float) SAMA5_MCANCLK_FREQUENCY / + ((float)(tseg1 + tseg2 + 3) * (float)bt->bt_baud)) - 1); + + /* Save the value of the new bit timing register */ + + flags = enter_critical_section(); + priv->btp = MCAN_BTP_BRP(brp) | MCAN_BTP_TSEG1(tseg1) | + MCAN_BTP_TSEG2(tseg2) | MCAN_BTP_SJW(sjw); + + /* We need to reset to instantiate the new timing. Save + * current state information so that recover to this + * state. + */ + + ie = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + state = priv->state; + + /* Reset the MCAN */ + + mcan_reset(dev); + ret = OK; + + /* If we have previously been setup, then setup again */ + + if (state == MCAN_STATE_SETUP) + { + ret = mcan_setup(dev); + } + + /* We we have successfully re-initialized, then restore the + * interrupt state. + * + * REVISIT: Since the hardware was reset, any pending TX + * activity was lost. Should we disable TX interrupts? + */ + + if (ret == OK) + { + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie & ~priv->txints); + } + + leave_critical_section(flags); + } + break; + +#ifdef CONFIG_CAN_EXTID + /* CANIOC_ADD_EXTFILTER: + * Description: Add an address filter for a extended 29 bit + * address. + * Argument: A reference to struct canioc_extfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_EXTFILTER: + { + DEBUGASSERT(arg != 0); + + ret = mcan_add_extfilter(priv, + (struct canioc_extfilter_s *)arg); + } + break; + + /* CANIOC_DEL_EXTFILTER: + * Description: Remove an address filter for a standard 29 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_EXTFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + */ + + case CANIOC_DEL_EXTFILTER: + { + DEBUGASSERT(arg <= priv->config->nextfilters); + ret = mcan_del_extfilter(priv, (int)arg); + } + break; +#endif + + /* CANIOC_ADD_STDFILTER: + * Description: Add an address filter for a standard 11 bit + * address. + * Argument: A reference to struct canioc_stdfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_STDFILTER: + { + DEBUGASSERT(arg != 0); + + ret = mcan_add_stdfilter(priv, + (struct canioc_stdfilter_s *)arg); + } + break; + + /* CANIOC_DEL_STDFILTER: + * Description: Remove an address filter for a standard 11 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_STDFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + */ + + case CANIOC_DEL_STDFILTER: + { + DEBUGASSERT(arg <= priv->config->nstdfilters); + ret = mcan_del_stdfilter(priv, (int)arg); + } + break; + + /* CANIOC_BUSOFF_RECOVERY: + * Description : Initiates the BUS - OFF recovery sequence + * Argument : None + * Returned Value : Zero (OK) is returned on success. Otherwise -1 + * (ERROR) is returned with the errno variable set + * to indicate the nature of the error. + * Dependencies : None + */ + + case CANIOC_BUSOFF_RECOVERY: + { + ret = mcan_start_busoff_recovery_sequence(priv); + } + break; + + /* Unsupported/unrecognized command */ + + default: + canerr("ERROR: Unrecognized command: %04x\n", cmd); + break; + } + + return ret; +} + +/**************************************************************************** + * Name: mcan_remoterequest + * + * Description: + * Send a remote request + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_remoterequest(struct can_dev_s *dev, uint16_t id) +{ + /* REVISIT: Remote request not implemented */ + + return -ENOSYS; +} + +/**************************************************************************** + * Name: mcan_send + * + * Description: + * Send one can message. + * + * One CAN-message consists of a maximum of 10 bytes. A message is + * composed of at least the first 2 bytes (when there are no data bytes). + * + * Byte 0: Bits 0-7: Bits 3-10 of the 11-bit CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Transmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_send(struct can_dev_s *dev, struct can_msg_s *msg) +{ + struct sam_mcan_s *priv; + const struct sam_config_s *config; + uint32_t *txbuffer = 0; + const uint8_t *src; + uint8_t *dest; + uint32_t regval; + unsigned int msglen; + unsigned int ndx; + unsigned int nbytes; + unsigned int i; + int ret; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv && priv->config); + config = priv->config; + + caninfo("MCAN%d\n", config->port); + caninfo("MCAN%d ID: %" PRIu32 " DLC: %u\n", + config->port, (uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + + /* That that FIFO elements were configured. + * + * REVISIT: Dedicated TX buffers are not used by this driver. + */ + + DEBUGASSERT(config->ntxfifoq > 0); + + /* Reserve a buffer for the transmission, waiting if necessary. When + * mcan_buffer_reserve() returns, we are guaranteed that the TX FIFOQ is + * not full and cannot become full at least until we add our packet to + * the FIFO. + * + * We can't get exclusive access to MCAN resources here because that + * lock the MCAN while we wait for a free buffer. Instead, the + * scheduler is locked here momentarily. See discussion in + * mcan_buffer_reserve() for an explanation. + * + * REVISIT: This needs to be extended in order to handler case where + * the MCAN device was opened O_NONBLOCK. + */ + + sched_lock(); + mcan_buffer_reserve(priv); + + /* Get exclusive access to the MCAN peripheral */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + mcan_buffer_release(priv); + sched_unlock(); + return ret; + } + + sched_unlock(); + + /* Get our reserved Tx FIFO/queue put index */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + DEBUGASSERT((regval & MCAN_TXFQS_TFQF) == 0); + + ndx = (regval & MCAN_TXFQS_TFQPI_MASK) >> MCAN_TXFQS_TFQPI_SHIFT; + + /* And the TX buffer corresponding to this index */ + + txbuffer = config->msgram.txdedicated + ndx * config->txbufferesize; + + /* Format the TX FIFOQ entry + * + * Format word T1: + * Transfer message ID (ID) - Value from message structure + * Remote Transmission Request (RTR) - Value from message structure + * Extended Identifier (XTD) - Depends on configuration. + */ + +#ifdef CONFIG_CAN_EXTID + if (msg->cm_hdr.ch_extid) + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_EXTMSGID); + + regval = BUFFER_R0_EXTID(msg->cm_hdr.ch_id) | BUFFER_R0_XTD; + } + else +#endif + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_STDMSGID); + + regval = BUFFER_R0_STDID(msg->cm_hdr.ch_id); + } + + if (msg->cm_hdr.ch_rtr) + { + regval |= BUFFER_R0_RTR; + } + + txbuffer[0] = regval; + reginfo("T0: %08" PRIx32 "\n", regval); + + /* Format word T1: + * Data Length Code (DLC) - Value from message structure + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero + */ + + txbuffer[1] = BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); + reginfo("T1: %08" PRIx32 "\n", txbuffer[1]); + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + dest = (uint8_t *)&txbuffer[2]; + src = msg->cm_data; + nbytes = mcan_dlc2bytes(priv, msg->cm_hdr.ch_dlc); + + for (i = 0; i < nbytes; i++) + { + /* Little endian is assumed */ + + *dest++ = *src++; + } + + /* Flush the D-Cache to memory before initiating the transfer */ + + msglen = 2 * sizeof(uint32_t) + nbytes; + up_clean_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + msglen); + UNUSED(msglen); + + /* Enable transmit interrupts from the TX FIFOQ buffer by setting TC + * interrupt bit in IR (also requires that the TC interrupt is enabled) + */ + + mcan_dumpregs(priv, "before tx req"); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, (1 << ndx)); + + /* And request to send the packet */ + + mcan_putreg(priv, SAM_MCAN_TXBAR_OFFSET, (1 << ndx)); + mcan_dumpregs(priv, "After tx done"); + nxmutex_unlock(&priv->lock); + + /* Report that the TX transfer is complete to the upper half logic. Of + * course, the transfer is not complete, but this early notification + * allows the upper half logic to free resources sooner. + * + * REVISIT: Should we disable interrupts? can_txdone() was designed to + * be called from an interrupt handler and, hence, may be unsafe when + * called from the tasking level. + */ + + can_txdone(dev); + return OK; +} + +/**************************************************************************** + * Name: mcan_txready + * + * Description: + * Return true if the MCAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the MCAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool mcan_txready(struct can_dev_s *dev) +{ + struct sam_mcan_s *priv = dev->cd_priv; + uint32_t regval; + bool notfull; +#ifdef CONFIG_DEBUG_FEATURES + int sval; +#endif + int ret; + + /* Get exclusive access to the MCAN peripheral */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return false; + } + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * not full. + * + * REVISIT: Dedicated TX buffers are not supported. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + notfull = ((regval & MCAN_TXFQS_TFQF) == 0); + +#ifdef CONFIG_DEBUG_FEATURES + /* As a sanity check, the txfsem should also track the number of elements + * the TX FIFO/queue. Make sure that they are consistent. + */ + + nxsem_get_value(&priv->txfsem, &sval); + DEBUGASSERT(((notfull && sval > 0) || (!notfull && sval <= 0)) && + (sval <= priv->config->ntxfifoq)); +#endif + + nxmutex_unlock(&priv->lock); + return notfull; +} + +/**************************************************************************** + * Name: mcan_txempty + * + * Description: + * Return true if all message have been sent. If for example, the MCAN + * hardware implements FIFOs, then this would mean the transmit FIFO is + * empty. This method is called when the driver needs to make sure that + * all characters are "drained" from the TX hardware before calling + * co_shutdown(). + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if there are no pending TX transfers in the MCAN hardware. + * + ****************************************************************************/ + +static bool mcan_txempty(struct can_dev_s *dev) +{ + struct sam_mcan_s *priv = dev->cd_priv; + uint32_t regval; +#ifdef CONFIG_SAMA5_MCAN_QUEUE_MODE + int sval; +#else + int tffl; +#endif + bool empty; + int ret; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + + /* Get exclusive access to the MCAN peripheral */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return false; + } + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * empty. We don't have a reliable indication that the FIFO is empty, so + * we have to use some heuristics. + * + * REVISIT: Dedicated TX buffers are not supported. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + if ((regval & MCAN_TXFQS_TFQF) != 0) + { + nxmutex_unlock(&priv->lock); + return false; + } + +#ifdef CONFIG_SAMA5_MCAN_QUEUE_MODE + /* The TX FIFO/Queue is not full, but is it empty? The txfsem should + * track the number of elements the TX FIFO/queue in use. + * + * Since the FIFO is not full, the semaphore count should be greater + * than zero. If it is equal to the full count of TX FIFO/Queue + * elements, then there is no transfer in progress. + */ + + nxsem_get_value(&priv->txfsem, &sval); + DEBUGASSERT(sval > 0 && sval <= priv->config->ntxfifoq); + + empty = (sval == priv->config->ntxfifoq); +#else + /* Tx FIFO Free Level */ + + tffl = (regval & MCAN_TXFQS_TFFL_MASK) >> MCAN_TXFQS_TFFL_SHIFT; + empty = (tffl >= priv->config->ntxfifoq); +#endif + + nxmutex_unlock(&priv->lock); + return empty; +} + +/**************************************************************************** + * Name: mcan_dedicated_rxbuffer_available + * + * Description: + * Check if data is available in a dedicated RX buffer. + * + * Input Parameters: + * priv - MCAN-specific private data + * bufndx - Buffer index + * + * None + * Returned Value: + * True: Data is available + * + ****************************************************************************/ + +#ifndef DEDICATED_BUFFERS_NOT_USED +bool mcan_dedicated_rxbuffer_available(struct sam_mcan_s *priv, + int bufndx) +{ + if (bufndx < 32) + { + return (bool)(mcan->MCAN_NDAT1 & (1 << bufndx)); + } + else if (bufndx < 64) + { + return (bool)(mcan->MCAN_NDAT1 & (1 << (bufndx - 32))); + } + else + { + return false; + } +} +#endif + +/**************************************************************************** + * Name: mcan_error + * + * Description: + * Report a CAN error + * + * Input Parameters: + * dev - CAN-common state data + * status - Interrupt status with error bits set + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_ERRORS +static void mcan_error(struct can_dev_s *dev, uint32_t status) +{ + struct sam_mcan_s *priv = dev->cd_priv; + struct can_hdr_s hdr; + uint32_t psr; + uint16_t errbits; + uint8_t data[CAN_ERROR_DLC]; + int ret; + + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Always fill in "static" error conditions, but set the signaling bit + * only if the condition has changed (see IRQ-Flags below) + * They have to be filled in every time CAN_ERROR_CONTROLLER is set. + */ + + psr = mcan_getreg(priv, SAM_MCAN_PSR_OFFSET); + if ((psr & MCAN_PSR_EP) != 0) + { + data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE); + } + + if (psr & MCAN_PSR_EW) + { + data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING); + } + + if ((status & (MCAN_INT_EP | MCAN_INT_EW)) != 0) + { + /* "Error Passive" or "Error Warning" status changed */ + + errbits |= CAN_ERROR_CONTROLLER; + } + + if ((status & MCAN_INT_BO) != 0) + { + /* Bus_Off Status changed */ + + if ((psr & MCAN_PSR_BO) != 0) + { + errbits |= CAN_ERROR_BUSOFF; + } + else + { + errbits |= CAN_ERROR_RESTARTED; + } + } + + if ((status & (MCAN_INT_RF0L | MCAN_INT_RF1L)) != 0) + { + /* Receive FIFO 0/1 Message Lost + * Receive FIFO 1 Message Lost + */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_RXOVERFLOW; + } + + if ((status & MCAN_INT_TEFL) != 0) + { + /* Tx Event FIFO Element Lost */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_TXOVERFLOW; + } + + if ((status & MCAN_INT_TOO) != 0) + { + /* Timeout Occurred */ + + errbits |= CAN_ERROR_TXTIMEOUT; + } + + if ((status & (MCAN_INT_MRAF | MCAN_INT_ELO)) != 0) + { + /* Message RAM Access Failure + * Error Logging Overflow + */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_UNSPEC; + } + + if ((status & MCAN_INT_CRCE) != 0) + { + /* Receive CRC Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[3] |= (CAN_ERROR3_CRCSEQ | CAN_ERROR3_CRCDEL); + } + + if ((status & MCAN_INT_BE) != 0) + { + /* Bit Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT; + } + + if ((status & MCAN_INT_ACKE) != 0) + { + /* Acknowledge Error */ + + errbits |= CAN_ERROR_NOACK; + } + + if ((status & MCAN_INT_FOE) != 0) + { + /* Format Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_FORM; + } + + if ((status & MCAN_INT_STE) != 0) + { + /* Stuff Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_STUFF; + } + + if (errbits != 0) + { + /* Format the CAN header for the error report. */ + + hdr.ch_id = errbits; + hdr.ch_dlc = CAN_ERROR_DLC; + hdr.ch_rtr = 0; + hdr.ch_error = 1; +#ifdef CONFIG_CAN_EXTID + hdr.ch_extid = 0; +#endif + hdr.ch_unused = 0; + + /* And provide the error report to the upper half logic */ + + ret = can_receive(dev, &hdr, data); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } + } +} +#endif /* CONFIG_CAN_ERRORS */ + +/**************************************************************************** + * Name: mcan_receive + * + * Description: + * Receive an MCAN messages + * + * Input Parameters: + * dev - CAN-common state data + * rxbuffer - The RX buffer containing the received messages + * nwords - The length of the RX buffer (element size in words). + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_receive(struct can_dev_s *dev, uint32_t *rxbuffer, + unsigned long nwords) +{ + struct can_hdr_s hdr; + uint32_t regval; + unsigned int nbytes; + int ret; + + /* Invalidate the D-Cache to ensure + * that we reread the RX buffer data from memory. + */ + + nbytes = (nwords << 2); + up_invalidate_dcache((uintptr_t)rxbuffer, (uintptr_t)rxbuffer + nbytes); + + /* Format the CAN header */ + + /* Word R0 contains the CAN ID */ + + regval = *rxbuffer++; + reginfo("R0: %08" PRIx32 "\n", regval); + +#ifdef CONFIG_CAN_ERRORS + hdr.ch_error = 0; +#endif + hdr.ch_unused = 0; + + if ((regval & BUFFER_R0_RTR) != 0) + { + hdr.ch_rtr = true; + } + else + { + hdr.ch_rtr = false; + } + +#ifdef CONFIG_CAN_EXTID + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_EXTID_MASK) >> + BUFFER_R0_EXTID_SHIFT; + hdr.ch_extid = true; + } + else + { + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT; + hdr.ch_extid = false; + } + +#else + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ + + return; + } + + /* Save the standard ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; +#endif + + /* Word R1 contains the DLC and timestamp */ + + regval = *rxbuffer++; + reginfo("R1: %08" PRIx32 "\n", regval); + + hdr.ch_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + + /* And provide the CAN message to the upper half logic */ + + ret = can_receive(dev, &hdr, (uint8_t *)rxbuffer); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: mcan_interrupt + * + * Description: + * Common MCAN interrupt handler + * + * Input Parameters: + * dev - CAN-common state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int mcan_interrupt(int irq, void *context, void *arg) +{ + struct can_dev_s *dev = (struct can_dev_s *)arg; + struct sam_mcan_s *priv; + uint32_t ir; + uint32_t ie; + uint32_t pending; + uint32_t regval; + unsigned int nelem; + unsigned int ndx; + bool handled; + + DEBUGASSERT(dev != NULL); + priv = dev->cd_priv; + DEBUGASSERT(priv && priv->config); + + /* Loop while there are pending interrupt events */ + + do + { + /* Get the set of pending interrupts. */ + + ir = mcan_getreg(priv, SAM_MCAN_IR_OFFSET); + ie = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + pending = (ir & ie); + handled = false; + + /* Check for any errors */ + + if ((pending & MCAN_ANYERR_INTS) != 0) + { + /* Check for common errors */ + + if ((pending & MCAN_CMNERR_INTS) != 0) + { + canerr("ERROR: Common %08" PRIx32 "\n", + pending & MCAN_CMNERR_INTS); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_CMNERR_INTS); + } + + /* Check for transmission errors */ + + if ((pending & MCAN_TXERR_INTS) != 0) + { + canerr("ERROR: TX %08" PRIx32 "\n", pending & MCAN_TXERR_INTS); + + /* An Acknowledge-Error will occur if for example the device + * is not connected to the bus. + * + * The CAN-Standard states that the Chip has to retry the + * message forever, which will produce an ACKE every time. + * To prevent this Interrupt-Flooding and the high CPU-Load + * we disable the ACKE here as long we didn't transfer at + * least one message successfully (see MCAN_INT_TC below). + */ + + ie &= ~MCAN_INT_ACKE; + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_TXERR_INTS); + + /* REVISIT: Will MCAN_INT_TC also be set in the event of + * a transmission error? Each write must conclude with a + * call to man_buffer_release(), whether or not the write + * was successful. + * + * We assume that MCAN_INT_TC will be called for each + * message buffer. Except the transfer is cancelled. + * TODO: add handling for MCAN_INT_TCF + */ + } + + /* Check for reception errors */ + + if ((pending & MCAN_RXERR_INTS) != 0) + { + canerr("ERROR: RX %08" PRIx32 "\n", pending & MCAN_RXERR_INTS); + + /* To prevent Interrupt-Flooding the current active + * RX error interrupts are disabled. After successfully + * receiving at least one CAN packet all RX error interrupts + * are turned back on. + * + * The Interrupt-Flooding can for example occur if the + * configured CAN speed does not match the speed of the other + * CAN nodes in the network. + */ + + ie &= ~(pending & MCAN_RXERR_INTS); + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_RXERR_INTS); + } + +#ifdef CONFIG_CAN_ERRORS + /* Report errors */ + + mcan_error(dev, pending & MCAN_ANYERR_INTS); +#endif + handled = true; + } + + /* Check for successful completion of a transmission */ + + if ((pending & MCAN_INT_TC) != 0) + { + /* Check if we have disabled the ACKE in the error-handling above + * (see MCAN_TXERR_INTS) to prevent Interrupt-Flooding and + * re-enable the error interrupt here again. + */ + + if ((ie & MCAN_INT_ACKE) == 0) + { + ie |= MCAN_INT_ACKE; + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie); + } + + /* Clear the pending TX completion interrupt (and all + * other TX-related interrupts) + */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->txints); + + /* Indicate that there is one more buffer free in the TX FIFOQ by + * "releasing" it. This may have the effect of waking up a thread + * that has been waiting for a free TX FIFOQ buffer. + * + * REVISIT: TX dedicated buffers are not supported. + */ + + mcan_buffer_release(priv); + handled = true; + +#ifdef CONFIG_CAN_TXREADY + /* Inform the upper half driver that we are again ready to accept + * data in mcan_send(). + */ + + can_txready(dev); +#endif + } + else if ((pending & priv->txints) != 0) + { + /* Clear unhandled TX events */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->txints); + handled = true; + } + +#ifndef DEDICATED_BUFFERS_NOT_USED + /* Check if a message has been saved to the dedicated RX buffer (DRX) */ + + if ((pending & MCAN_INT_DRX) != 0) + { + int i; + + /* Clear the pending DRX interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_DRX); + + /* Process each dedicated RX buffer */ + + for (i = 0; i < priv->config->nrxdedicated; i++) + { + uint32_t *rxdedicated = &priv->config->rxdedicated[i]; + + /* Check if data is available in this dedicated RX buffer */ + + if (mcan_dedicated_rxbuffer_available(priv, i)) + { + /* Yes.. Invalidate the D-Cache to that data will be re- + * fetched from RAM. + * + * REVISIT: This will require 32-byte alignment. + */ + + arch_invalidata_dcache(); + mcan_receive(priv, rxdedicated, + priv->config->rxbufferesize); + + /* Clear the new data flag for the buffer */ + + if (i < 32) + { + sam_putreg(priv, SAM_MCAN_NDAT1_OFFSET, + (1 << i); + } + else + { + sam_putreg(priv, SAM_MCAN_NDAT1_OFFSET, + (1 << (i - 32)); + } + } + } + + handled = true; + } +#endif + + /* Clear the RX FIFO1 new message interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_RF1N); + pending &= ~MCAN_INT_RF1N; + + /* We treat RX FIFO1 as the "high priority" queue: We will process + * all messages in RX FIFO1 before processing any message from RX + * FIFO0. + */ + + for (; ; ) + { + /* Check if there is anything in RX FIFO1 */ + + regval = mcan_getreg(priv, SAM_MCAN_RXF1S_OFFSET); + nelem = (regval & MCAN_RXF0S_F0FL_MASK) >> MCAN_RXF0S_F0FL_SHIFT; + if (nelem == 0) + { + /* Break out of the loop if RX FIFO1 is empty */ + + break; + } + + /* Clear the RX FIFO1 interrupt (and all other FIFO1-related + * interrupts) + */ + + /* Handle the newly received message in FIFO1 */ + + ndx = (regval & MCAN_RXF1S_F1GI_MASK) >> MCAN_RXF1S_F1GI_SHIFT; + + if ((regval & MCAN_RXF0S_RF0L) != 0) + { + canerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + mcan_receive(dev, + priv->config->msgram.rxfifo1 + + (ndx * priv->config->rxfifo1esize), + priv->config->rxfifo1esize); + + /* Turning back on all configured RX error interrupts */ + + ie |= (priv->rxints & MCAN_RXERR_INTS); + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie); + } + + /* Acknowledge reading the FIFO entry */ + + mcan_putreg(priv, SAM_MCAN_RXF1A_OFFSET, ndx); + handled = true; + } + + /* Check for successful reception of a new message in RX FIFO0 */ + + /* Clear the RX FIFO0 new message interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_RF0N); + pending &= ~MCAN_INT_RF0N; + + /* Check if there is anything in RX FIFO0 */ + + regval = mcan_getreg(priv, SAM_MCAN_RXF0S_OFFSET); + nelem = (regval & MCAN_RXF0S_F0FL_MASK) >> MCAN_RXF0S_F0FL_SHIFT; + if (nelem > 0) + { + /* Handle the newly received message in FIFO0 */ + + ndx = (regval & MCAN_RXF0S_F0GI_MASK) >> MCAN_RXF0S_F0GI_SHIFT; + + if ((regval & MCAN_RXF0S_RF0L) != 0) + { + canerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + mcan_receive(dev, + priv->config->msgram.rxfifo0 + + (ndx * priv->config->rxfifo0esize), + priv->config->rxfifo0esize); + + /* Turning back on all configured RX error interrupts */ + + ie |= (priv->rxints & MCAN_RXERR_INTS); + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie); + } + + /* Acknowledge reading the FIFO entry */ + + mcan_putreg(priv, SAM_MCAN_RXF0A_OFFSET, ndx); + handled = true; + } + + /* Clear unhandled RX interrupts */ + + if ((pending & priv->rxints) != 0) + { + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->rxints); + } + } + while (handled); + + return OK; +} + +/**************************************************************************** + * Name: mcan_hw_initialize + * + * Description: + * MCAN hardware initialization + * + * Input Parameters: + * priv - A pointer to the private data structure for this MCAN peripheral + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int mcan_hw_initialize(struct sam_mcan_s *priv) +{ + const struct sam_config_s *config = priv->config; + uint32_t *msgram; + uint32_t regval; + uint32_t cntr; + uint32_t cmr; + + caninfo("MCAN%d\n", config->port); + caninfo("mcan%d_msgram is at %" PRIx32 "\n", config->port, + (uint32_t) &config->msgram); + + /* Configure MCAN pins */ + + sam_configpio(config->rxpinset); + sam_configpio(config->txpinset); + + /* Enable peripheral clocking */ + + sam_enableperiph1(config->pid); + + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & MCAN_CCCR_INIT) == 0); + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Global Filter Configuration: + * + * ANFS=0: Store all non matching standard frame in RX FIFO0 + * ANFE=0: Store all non matching extended frame in RX FIFO0 + */ + + regval = MCAN_GFC_ANFE_RX_FIFO0 | MCAN_GFC_ANFS_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Extended ID Filter AND mask */ + + mcan_putreg(priv, SAM_MCAN_XIDAM_OFFSET, 0x1fffffff); + + /* Disable all interrupts */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* All interrupts directed to Line 0. But disable both interrupt lines 0 + * and 1 for now. + * + * REVISIT: Only interrupt line 0 is used by this driver. + */ + + mcan_putreg(priv, SAM_MCAN_ILS_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_ILE_OFFSET, 0); + + /* Clear all pending interrupts. */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_ALL); + + /* Configure MCAN bit timing */ + + mcan_putreg(priv, SAM_MCAN_BTP_OFFSET, priv->btp); + mcan_putreg(priv, SAM_MCAN_FBTP_OFFSET, priv->fbtp); + + /* Configure message RAM starting addresses and sizes. */ + + regval = MAILBOX_ADDRESS(config->msgram.stdfilters) | + MCAN_SIDFC_LSS(config->nstdfilters); + mcan_putreg(priv, SAM_MCAN_SIDFC_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.extfilters) | + MCAN_XIDFC_LSE(config->nextfilters); + mcan_putreg(priv, SAM_MCAN_XIDFC_OFFSET, regval); + + /* Configure RX FIFOs */ + + regval = MAILBOX_ADDRESS(config->msgram.rxfifo0) | + MCAN_RXF0C_F0S(config->nrxfifo0); + mcan_putreg(priv, SAM_MCAN_RXF0C_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.rxfifo1) | + MCAN_RXF1C_F1S(config->nrxfifo1); + mcan_putreg(priv, SAM_MCAN_RXF1C_OFFSET, regval); + + /* Watermark interrupt off, blocking mode */ + + regval = MAILBOX_ADDRESS(config->msgram.rxdedicated); + mcan_putreg(priv, SAM_MCAN_RXBC_OFFSET, regval); + + regval = MCAN_RXESC_RBDS(config->rxbufferecode) | + MCAN_RXESC_F1DS(config->rxfifo1ecode) | + MCAN_RXESC_F0DS(config->rxfifo0ecode); + mcan_putreg(priv, SAM_MCAN_RXESC_OFFSET, regval); + + /* Configure TX FIFOs */ + + regval = MAILBOX_ADDRESS(config->msgram.txeventfifo) | + MCAN_TXEFC_EFS(config->ntxeventfifo); + mcan_putreg(priv, SAM_MCAN_TXEFC_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.txdedicated) | + MCAN_TXBC_NDTB(config->ntxdedicated) | + MCAN_TXBC_TFQS(config->ntxfifoq); + mcan_putreg(priv, SAM_MCAN_TXBC_OFFSET, regval); + + regval = MCAN_TXESC_TBDS(config->txbufferecode); + mcan_putreg(priv, SAM_MCAN_TXESC_OFFSET, regval); + + /* Configure Message Filters */ + + /* Disable all standard filters */ + + msgram = config->msgram.stdfilters; + cntr = config->nstdfilters; + while (cntr > 0) + { + *msgram++ = STDFILTER_S0_SFEC_DISABLE; + cntr--; + } + + /* Disable all extended filters */ + + msgram = config->msgram.extfilters; + cntr = config->nextfilters; + while (cntr > 0) + { + *msgram = EXTFILTER_F0_EFEC_DISABLE; + msgram = msgram + 2; + cntr--; + } + + /* Clear new RX data flags */ + + mcan_putreg(priv, SAM_MCAN_NDAT1_OFFSET, 0xffffffff); + mcan_putreg(priv, SAM_MCAN_NDAT2_OFFSET, 0xffffffff); + + /* Select ISO11898-1 mode or FD mode with or without fast bit rate + * switching + */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_CME_MASK | MCAN_CCCR_CMR_MASK); + + switch (config->mode) + { + default: + case MCAN_ISO11898_1_MODE: + regval |= MCAN_CCCR_CME_ISO11898_1; + cmr = MCAN_CCCR_CMR_ISO11898_1; + break; + +#ifdef CONFIG_CAN_FD + case MCAN_FD_MODE: + regval |= MCAN_CCCR_CME_FD; + cmr = MCAN_CCCR_CMR_FD; + break; + + case MCAN_FD_BSW_MODE: + regval |= MCAN_CCCR_CME_FD_BSW; + cmr = MCAN_CCCR_CMR_FD_BSW; + break; +#endif + } + + /* Set the initial CAN mode */ + + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Request the mode change */ + + regval |= cmr; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for the mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & + (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) != 0); + + /* Enable FIFO/Queue mode + * + * REVISIT: Dedicated TX buffers are not used. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXBC_OFFSET); +#ifdef CONFIG_SAMA5_MCAN_QUEUE_MODE + regval |= MCAN_TXBC_TFQM; +#else + regval &= ~MCAN_TXBC_TFQM; +#endif + mcan_putreg(priv, SAM_MCAN_TXBC_OFFSET, regval); + +#ifdef SAMA5_MCAN_LOOPBACK + /* Is loopback mode selected for this peripheral? */ + + if (config->loopback) + { + /* MCAN_CCCR_TEST - Test mode enable + * MCAN_CCCR_MON - Bus monitoring mode (for internal loopback) + * MCAN_TEST_LBCK - Loopback mode + */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_TEST | MCAN_CCCR_MON); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + regval = mcan_getreg(priv, SAM_MCAN_TEST_OFFSET); + regval |= MCAN_TEST_LBCK; + mcan_putreg(priv, SAM_MCAN_TEST_OFFSET, regval); + } +#endif + + /* Configure interrupt lines */ + + /* Select RX-related interrupts */ + +#ifndef DEDICATED_BUFFERS_NOT_USED + priv->rxints = MCAN_RXDEDBUF_INTS; +#else + priv->rxints = MCAN_RXFIFO_INTS; +#endif + + /* Select TX-related interrupts */ + +#ifndef DEDICATED_BUFFERS_NOT_USED + priv->txints = MCAN_TXDEDBUF_INTS; +#else + priv->txints = MCAN_TXFIFOQ_INTS; +#endif + + /* Direct all interrupts to Line 0. + * + * Bits in the ILS register correspond to each MCAN interrupt; A bit + * set to '1' is directed to interrupt line 1; a bit cleared to '0' + * is directed interrupt line 0. + * + * REVISIT: Nothing is done here. Only interrupt line 0 is used by + * this driver and ILS was already cleared above. + */ + + /* Enable only interrupt line 0. */ + + mcan_putreg(priv, SAM_MCAN_ILE_OFFSET, MCAN_ILE_EINT0); + + /* Disable initialization mode to enable normal operation */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_mcan_initialize + * + * Description: + * Initialize the selected MCAN port + * + * Input Parameters: + * port - Port number (for hardware that has multiple MCAN interfaces), + * 0=MCAN0, 1=MCAN1 + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s *sam_mcan_initialize(int port) +{ + struct can_dev_s *dev; + struct sam_mcan_s *priv; + const struct sam_config_s *config; + uint32_t regval; + + caninfo("MCAN%d, clk freq=%d\n", port, SAMA5_MCANCLK_FREQUENCY); + + /* Select clock source and pre-scaler value. */ + + regval = PMC_PCR_GCKEN | PMC_PCR_CMD | PMC_PCR_EN | + PMC_PCR_GCKDIV(CONFIG_SAMA5_MCAN_CLKSRC_PRESCALER - 1) | + SAMA5_MCAN_CLKSRC; + + switch (port) + { +#ifdef CONFIG_SAMA5_MCAN0 + case MCAN0: + + /* Enable CLK */ + + regval |= PMC_PCR_PID(SAM_PID_MCAN0); + putreg32(regval, SAM_PMC_PCR); + sam_mcan0_enableclk(); + + /* Select the MCAN0 device structure */ + + dev = &g_mcan0dev; + priv = &g_mcan0priv; + config = &g_mcan0const; + + /* Configure MCAN0 Message RAM Base Address */ + + regval = getreg32(SAM_SFR_VBASE + SAM_SFR_CAN_OFFSET) & + SAM_MCAN0_SFR_MASK; + regval |= SAM_MCAN_SFR_GET_MSB(config->msgram.stdfilters); + + putreg32(regval, SAM_SFR_VBASE + SAM_SFR_CAN_OFFSET); + break; +#endif +#ifdef CONFIG_SAMA5_MCAN1 + case MCAN1: + + /* Enable CLK */ + + regval |= PMC_PCR_PID(SAM_PID_MCAN1); + putreg32(regval, SAM_PMC_PCR); + sam_mcan1_enableclk(); + + /* Select the MCAN1 device structure */ + + dev = &g_mcan1dev; + priv = &g_mcan1priv; + config = &g_mcan1const; + + /* Configure MCAN1 Message RAM Base Address */ + + regval = getreg32(SAM_SFR_VBASE + SAM_SFR_CAN_OFFSET) & + SAM_MCAN1_SFR_MASK; + regval |= SAM_MCAN_SFR_GET_MSB(config->msgram.stdfilters) << + SAM_MCAN_SFR_SHIFT; + + putreg32(regval, SAM_SFR_VBASE + SAM_SFR_CAN_OFFSET); + break; +#endif + default: + canerr("ERROR: Unsupported mcan port %d\n", port); + return NULL; + break; + } + + /* Is this the first time that we have handed out this device? */ + + if (priv->state == MCAN_STATE_UNINIT) + { + /* Yes, then perform one time data initialization */ + + /* Set the initial bit timing. This might change subsequently + * due to IOCTL command processing. + */ + + priv->btp = priv->config->btp; + priv->fbtp = priv->config->fbtp; + + /* And put the hardware in the initial state */ + + mcan_reset(dev); + } + + return dev; +} + +#endif /* CONFIG_CAN && CONFIG_SAMA5_MCAN */ diff --git a/arch/arm/src/sama5/sam_mcan.h b/arch/arm/src/sama5/sam_mcan.h new file mode 100644 index 0000000000..62b84969df --- /dev/null +++ b/arch/arm/src/sama5/sam_mcan.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_mcan.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMA5_SAM_MCAN_H +#define __ARCH_ARM_SRC_SAMA5_SAM_MCAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/sam_mcan.h" + +#include + +#if defined(CONFIG_CAN) && (defined(CONFIG_SAMA5_MCAN0) || \ + defined(CONFIG_SAMA5_MCAN1)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Port numbers for use with sam_mcan_initialize() */ + +#define MCAN0 0 +#define MCAN1 1 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_mcan_initialize + * + * Description: + * Initialize the selected MCAN port + * + * Input Parameters: + * port - Port number (for hardware that has multiple CAN interfaces), + * 0=MCAN0, 1=NCAN1 + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s; +struct can_dev_s *sam_mcan_initialize(int port); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_CAN && (CONFIG_SAMA5_MCAN0 || CONFIG_SAMA5_MCAN1) */ +#endif /* __ARCH_ARM_SRC_SAMA5_SAM_MCAN_H */