| 1 | /* |
| 2 | * QEMU model of the NXP FLEXCAN device. |
| 3 | * |
| 4 | * Copyright (c) 2025 Matyas Bobek <matyas.bobek@gmail.com> |
| 5 | * |
| 6 | * Based on CTU CAN FD emulation implemented by Jan Charvat. |
| 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 9 | */ |
| 10 | |
| 11 | #ifndef HW_CAN_FLEXCAN_H |
| 12 | #define HW_CAN_FLEXCAN_H |
| 13 | |
| 14 | #include "net/can_emu.h" |
| 15 | #include "qom/object.h" |
| 16 | #include "hw/misc/imx_ccm.h" |
| 17 | |
| 18 | #define FLEXCAN_FIFO_DEPTH 6 |
| 19 | #define FLEXCAN_MAILBOX_COUNT 64 |
| 20 | |
| 21 | /** |
| 22 | * Definitions of structs FlexcanRegs and FlexcanRegsMessageBuffer were |
| 23 | * originally written for the Linux kernel by: |
| 24 | * Andrey Volkov <andrey@volkov.fr> |
| 25 | * Sascha Hauer <s.hauer@pengutronix.de> |
| 26 | * Marc Kleine-Budde <mkl@pengutronix.de> |
| 27 | * David Jander <david@protonic.nl> |
| 28 | * and they have agreed to license them under GPL-2.0-or-later. |
| 29 | */ |
| 30 | |
| 31 | /* view of single message buffer registers */ |
| 32 | typedef struct FlexcanRegsMessageBuffer { |
| 33 | uint32_t can_ctrl; |
| 34 | uint32_t can_id; |
| 35 | uint32_t data[2]; |
| 36 | } FlexcanRegsMessageBuffer; |
| 37 | |
| 38 | /* FlexCAN register in hw layout */ |
| 39 | typedef struct FlexcanRegs { |
| 40 | uint32_t mcr; /* 0x00 */ |
| 41 | uint32_t ctrl; /* 0x04 - not affected by soft reset */ |
| 42 | uint32_t timer; /* 0x08 */ |
| 43 | uint32_t tcr; /* 0x0C */ |
| 44 | uint32_t rxmgmask; /* 0x10 - not affected by soft reset */ |
| 45 | uint32_t rx14mask; /* 0x14 - not affected by soft reset */ |
| 46 | uint32_t rx15mask; /* 0x18 - not affected by soft reset */ |
| 47 | uint32_t ecr; /* 0x1C */ |
| 48 | uint32_t esr; /* 0x20 */ |
| 49 | uint32_t imask2; /* 0x24 */ |
| 50 | uint32_t imask1; /* 0x28 */ |
| 51 | uint32_t iflag2; /* 0x2C */ |
| 52 | uint32_t iflag1; /* 0x30 */ |
| 53 | union { /* 0x34 */ |
| 54 | uint32_t gfwr_mx28; /* MX28, MX53 */ |
| 55 | uint32_t ctrl2; /* MX6, VF610 - not affected by soft reset */ |
| 56 | }; |
| 57 | uint32_t esr2; /* 0x38 */ |
| 58 | uint32_t imeur; /* 0x3C, unused */ |
| 59 | uint32_t lrfr; /* 0x40, unused */ |
| 60 | uint32_t crcr; /* 0x44 */ |
| 61 | uint32_t rxfgmask; /* 0x48 */ |
| 62 | uint32_t rxfir; /* 0x4C - not affected by soft reset */ |
| 63 | uint32_t cbt; /* 0x50, unused - not affected by soft reset */ |
| 64 | uint32_t _reserved2; /* 0x54 */ |
| 65 | uint32_t dbg1; /* 0x58, unused */ |
| 66 | uint32_t dbg2; /* 0x5C, unused */ |
| 67 | uint32_t _reserved3[8]; /* 0x60 */ |
| 68 | /* 0x80 - not affected by soft reset */ |
| 69 | FlexcanRegsMessageBuffer mbs[FLEXCAN_MAILBOX_COUNT]; |
| 70 | uint32_t _reserved4[256]; /* 0x480 */ |
| 71 | uint32_t rximr[64]; /* 0x880 - not affected by soft reset */ |
| 72 | uint32_t _reserved5[24]; /* 0x980 */ |
| 73 | uint32_t gfwr_mx6; /* 0x9E0 - MX6 */ |
| 74 | |
| 75 | /* the rest is unused except for SMB */ |
| 76 | uint32_t _reserved6[39]; /* 0x9E4 */ |
| 77 | uint32_t _rxfir[6]; /* 0xA80 */ |
| 78 | uint32_t _reserved8[2]; /* 0xA98 */ |
| 79 | uint32_t _rxmgmask; /* 0xAA0 */ |
| 80 | uint32_t _rxfgmask; /* 0xAA4 */ |
| 81 | uint32_t _rx14mask; /* 0xAA8 */ |
| 82 | uint32_t _rx15mask; /* 0xAAC */ |
| 83 | uint32_t tx_smb[4]; /* 0xAB0 */ |
| 84 | FlexcanRegsMessageBuffer rx_smb0; /* 0xAC0, used for SMB emulation */ |
| 85 | uint32_t rx_smb1[4]; /* 0xAD0 */ |
| 86 | uint32_t mecr; /* 0xAE0 */ |
| 87 | uint32_t erriar; /* 0xAE4 */ |
| 88 | uint32_t erridpr; /* 0xAE8 */ |
| 89 | uint32_t errippr; /* 0xAEC */ |
| 90 | uint32_t rerrar; /* 0xAF0 */ |
| 91 | uint32_t rerrdr; /* 0xAF4 */ |
| 92 | uint32_t rerrsynr; /* 0xAF8 */ |
| 93 | uint32_t errsr; /* 0xAFC */ |
| 94 | uint32_t _reserved7[64]; /* 0xB00 */ |
| 95 | uint32_t fdctrl; /* 0xC00 - not affected by soft reset */ |
| 96 | uint32_t fdcbt; /* 0xC04 - not affected by soft reset */ |
| 97 | uint32_t fdcrc; /* 0xC08 */ |
| 98 | uint32_t _reserved9[199]; /* 0xC0C */ |
| 99 | uint32_t tx_smb_fd[18]; /* 0xF28 */ |
| 100 | uint32_t rx_smb0_fd[18]; /* 0xF70 */ |
| 101 | uint32_t rx_smb1_fd[18]; /* 0xFB8 */ |
| 102 | } FlexcanRegs; |
| 103 | |
| 104 | typedef struct FlexcanState { |
| 105 | SysBusDevice parent_obj; |
| 106 | |
| 107 | MemoryRegion iomem; |
| 108 | IMXCCMState *ccm; |
| 109 | qemu_irq irq; |
| 110 | |
| 111 | CanBusState *canbus; |
| 112 | CanBusClientState bus_client; |
| 113 | |
| 114 | union { |
| 115 | FlexcanRegs regs; |
| 116 | uint32_t regs_raw[sizeof(FlexcanRegs) / 4]; |
| 117 | }; |
| 118 | int64_t timer_start; |
| 119 | uint64_t last_rx_timer_cycles; |
| 120 | int32_t locked_mbidx; |
| 121 | int32_t smb_target_mbidx; |
| 122 | uint32_t timer_freq; |
| 123 | } FlexcanState; |
| 124 | |
| 125 | #define TYPE_CAN_FLEXCAN "flexcan" |
| 126 | OBJECT_DECLARE_SIMPLE_TYPE(FlexcanState, CAN_FLEXCAN); |
| 127 | |
| 128 | #define TYPE_CAN_FLEXCAN2 "flexcan2" |
| 129 | #define TYPE_CAN_FLEXCAN3 "flexcan3" |
| 130 | |
| 131 | #endif |