1aa406e8bSJan Charvat /* 2aa406e8bSJan Charvat * CTU CAN FD PCI device emulation 3aa406e8bSJan Charvat * http://canbus.pages.fel.cvut.cz/ 4aa406e8bSJan Charvat * 5aa406e8bSJan Charvat * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com) 6aa406e8bSJan Charvat * 7aa406e8bSJan Charvat * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by 8aa406e8bSJan Charvat * Jin Yang and Pavel Pisa 9aa406e8bSJan Charvat * 10aa406e8bSJan Charvat * Permission is hereby granted, free of charge, to any person obtaining a copy 11aa406e8bSJan Charvat * of this software and associated documentation files (the "Software"), to deal 12aa406e8bSJan Charvat * in the Software without restriction, including without limitation the rights 13aa406e8bSJan Charvat * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14aa406e8bSJan Charvat * copies of the Software, and to permit persons to whom the Software is 15aa406e8bSJan Charvat * furnished to do so, subject to the following conditions: 16aa406e8bSJan Charvat * 17aa406e8bSJan Charvat * The above copyright notice and this permission notice shall be included in 18aa406e8bSJan Charvat * all copies or substantial portions of the Software. 19aa406e8bSJan Charvat * 20aa406e8bSJan Charvat * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21aa406e8bSJan Charvat * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22aa406e8bSJan Charvat * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23aa406e8bSJan Charvat * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24aa406e8bSJan Charvat * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25aa406e8bSJan Charvat * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26aa406e8bSJan Charvat * THE SOFTWARE. 27aa406e8bSJan Charvat */ 28aa406e8bSJan Charvat 29aa406e8bSJan Charvat #include "qemu/osdep.h" 30aa406e8bSJan Charvat #include "qemu/log.h" 31*b7bd67fbSAlex Bennée #include "qemu/bswap.h" 32*b7bd67fbSAlex Bennée #include "qemu/bitops.h" 33aa406e8bSJan Charvat #include "hw/irq.h" 34aa406e8bSJan Charvat #include "migration/vmstate.h" 35aa406e8bSJan Charvat #include "net/can_emu.h" 36aa406e8bSJan Charvat 37aa406e8bSJan Charvat #include "ctucan_core.h" 38aa406e8bSJan Charvat 39aa406e8bSJan Charvat #ifndef DEBUG_CAN 40aa406e8bSJan Charvat #define DEBUG_CAN 0 41aa406e8bSJan Charvat #endif /*DEBUG_CAN*/ 42aa406e8bSJan Charvat 43aa406e8bSJan Charvat #define DPRINTF(fmt, ...) \ 44aa406e8bSJan Charvat do { \ 45aa406e8bSJan Charvat if (DEBUG_CAN) { \ 46aa406e8bSJan Charvat qemu_log("[ctucan]: " fmt , ## __VA_ARGS__); \ 47aa406e8bSJan Charvat } \ 48aa406e8bSJan Charvat } while (0) 49aa406e8bSJan Charvat 50aa406e8bSJan Charvat static void ctucan_buff2frame(const uint8_t *buff, qemu_can_frame *frame) 51aa406e8bSJan Charvat { 52aa406e8bSJan Charvat frame->can_id = 0; 53aa406e8bSJan Charvat frame->can_dlc = 0; 54aa406e8bSJan Charvat frame->flags = 0; 55aa406e8bSJan Charvat 56aa406e8bSJan Charvat if (buff == NULL) { 57aa406e8bSJan Charvat return; 58aa406e8bSJan Charvat } 59aa406e8bSJan Charvat { 60aa406e8bSJan Charvat union ctu_can_fd_frame_form_w frame_form_w; 61aa406e8bSJan Charvat union ctu_can_fd_identifier_w identifier_w; 62aa406e8bSJan Charvat unsigned int ide; 63aa406e8bSJan Charvat uint32_t w; 64aa406e8bSJan Charvat 65aa406e8bSJan Charvat w = le32_to_cpu(*(uint32_t *)buff); 66aa406e8bSJan Charvat frame_form_w = (union ctu_can_fd_frame_form_w)w; 67aa406e8bSJan Charvat frame->can_dlc = can_dlc2len(frame_form_w.s.dlc); 68aa406e8bSJan Charvat 69aa406e8bSJan Charvat w = le32_to_cpu(*(uint32_t *)(buff + 4)); 70aa406e8bSJan Charvat identifier_w = (union ctu_can_fd_identifier_w)w; 71aa406e8bSJan Charvat 72aa406e8bSJan Charvat ide = frame_form_w.s.ide; 73aa406e8bSJan Charvat if (ide) { 74aa406e8bSJan Charvat frame->can_id = (identifier_w.s.identifier_base << 18) | 75aa406e8bSJan Charvat identifier_w.s.identifier_ext; 76aa406e8bSJan Charvat frame->can_id |= QEMU_CAN_EFF_FLAG; 77aa406e8bSJan Charvat } else { 78aa406e8bSJan Charvat frame->can_id = identifier_w.s.identifier_base; 79aa406e8bSJan Charvat } 80aa406e8bSJan Charvat 81aa406e8bSJan Charvat if (frame_form_w.s.esi_rsv) { 82aa406e8bSJan Charvat frame->flags |= QEMU_CAN_FRMF_ESI; 83aa406e8bSJan Charvat } 84aa406e8bSJan Charvat 85aa406e8bSJan Charvat if (frame_form_w.s.rtr) { 86aa406e8bSJan Charvat frame->can_id |= QEMU_CAN_RTR_FLAG; 87aa406e8bSJan Charvat } 88aa406e8bSJan Charvat 89aa406e8bSJan Charvat if (frame_form_w.s.fdf) { /*CAN FD*/ 90aa406e8bSJan Charvat frame->flags |= QEMU_CAN_FRMF_TYPE_FD; 91aa406e8bSJan Charvat if (frame_form_w.s.brs) { 92aa406e8bSJan Charvat frame->flags |= QEMU_CAN_FRMF_BRS; 93aa406e8bSJan Charvat } 94aa406e8bSJan Charvat } 95aa406e8bSJan Charvat } 96aa406e8bSJan Charvat 97aa406e8bSJan Charvat memcpy(frame->data, buff + 0x10, 0x40); 98aa406e8bSJan Charvat } 99aa406e8bSJan Charvat 100aa406e8bSJan Charvat 101aa406e8bSJan Charvat static int ctucan_frame2buff(const qemu_can_frame *frame, uint8_t *buff) 102aa406e8bSJan Charvat { 103aa406e8bSJan Charvat unsigned int bytes_cnt = -1; 104aa406e8bSJan Charvat memset(buff, 0, CTUCAN_MSG_MAX_LEN * sizeof(*buff)); 105aa406e8bSJan Charvat 106aa406e8bSJan Charvat if (frame == NULL) { 107aa406e8bSJan Charvat return bytes_cnt; 108aa406e8bSJan Charvat } 109aa406e8bSJan Charvat { 110aa406e8bSJan Charvat union ctu_can_fd_frame_form_w frame_form_w; 111aa406e8bSJan Charvat union ctu_can_fd_identifier_w identifier_w; 112aa406e8bSJan Charvat 113aa406e8bSJan Charvat frame_form_w.u32 = 0; 114aa406e8bSJan Charvat identifier_w.u32 = 0; 115aa406e8bSJan Charvat 116aa406e8bSJan Charvat bytes_cnt = frame->can_dlc; 117aa406e8bSJan Charvat bytes_cnt = (bytes_cnt + 3) & ~3; 118aa406e8bSJan Charvat bytes_cnt += 16; 119aa406e8bSJan Charvat frame_form_w.s.rwcnt = (bytes_cnt >> 2) - 1; 120aa406e8bSJan Charvat 121aa406e8bSJan Charvat frame_form_w.s.dlc = can_len2dlc(frame->can_dlc); 122aa406e8bSJan Charvat 123aa406e8bSJan Charvat if (frame->can_id & QEMU_CAN_EFF_FLAG) { 124aa406e8bSJan Charvat frame_form_w.s.ide = 1; 125aa406e8bSJan Charvat identifier_w.s.identifier_base = 126aa406e8bSJan Charvat (frame->can_id & 0x1FFC0000) >> 18; 127aa406e8bSJan Charvat identifier_w.s.identifier_ext = frame->can_id & 0x3FFFF; 128aa406e8bSJan Charvat } else { 129aa406e8bSJan Charvat identifier_w.s.identifier_base = frame->can_id & 0x7FF; 130aa406e8bSJan Charvat } 131aa406e8bSJan Charvat 132aa406e8bSJan Charvat if (frame->flags & QEMU_CAN_FRMF_ESI) { 133aa406e8bSJan Charvat frame_form_w.s.esi_rsv = 1; 134aa406e8bSJan Charvat } 135aa406e8bSJan Charvat 136aa406e8bSJan Charvat if (frame->can_id & QEMU_CAN_RTR_FLAG) { 137aa406e8bSJan Charvat frame_form_w.s.rtr = 1; 138aa406e8bSJan Charvat } 139aa406e8bSJan Charvat 140aa406e8bSJan Charvat if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { /*CAN FD*/ 141aa406e8bSJan Charvat frame_form_w.s.fdf = 1; 142aa406e8bSJan Charvat if (frame->flags & QEMU_CAN_FRMF_BRS) { 143aa406e8bSJan Charvat frame_form_w.s.brs = 1; 144aa406e8bSJan Charvat } 145aa406e8bSJan Charvat } 146aa406e8bSJan Charvat *(uint32_t *)buff = cpu_to_le32(frame_form_w.u32); 147aa406e8bSJan Charvat *(uint32_t *)(buff + 4) = cpu_to_le32(identifier_w.u32); 148aa406e8bSJan Charvat } 149aa406e8bSJan Charvat 150aa406e8bSJan Charvat memcpy(buff + 0x10, frame->data, 0x40); 151aa406e8bSJan Charvat 152aa406e8bSJan Charvat return bytes_cnt; 153aa406e8bSJan Charvat } 154aa406e8bSJan Charvat 155aa406e8bSJan Charvat static void ctucan_update_irq(CtuCanCoreState *s) 156aa406e8bSJan Charvat { 157aa406e8bSJan Charvat union ctu_can_fd_int_stat int_rq; 158aa406e8bSJan Charvat 159aa406e8bSJan Charvat int_rq.u32 = 0; 160aa406e8bSJan Charvat 161aa406e8bSJan Charvat if (s->rx_status_rx_settings.s.rxfrc) { 162aa406e8bSJan Charvat int_rq.s.rbnei = 1; 163aa406e8bSJan Charvat } 164aa406e8bSJan Charvat 165aa406e8bSJan Charvat int_rq.u32 &= ~s->int_mask.u32; 166aa406e8bSJan Charvat s->int_stat.u32 |= int_rq.u32; 167aa406e8bSJan Charvat if (s->int_stat.u32 & s->int_ena.u32) { 168aa406e8bSJan Charvat qemu_irq_raise(s->irq); 169aa406e8bSJan Charvat } else { 170aa406e8bSJan Charvat qemu_irq_lower(s->irq); 171aa406e8bSJan Charvat } 172aa406e8bSJan Charvat } 173aa406e8bSJan Charvat 174aa406e8bSJan Charvat static void ctucan_update_txnf(CtuCanCoreState *s) 175aa406e8bSJan Charvat { 176aa406e8bSJan Charvat int i; 177aa406e8bSJan Charvat int txnf; 178aa406e8bSJan Charvat unsigned int buff_st; 179aa406e8bSJan Charvat 180aa406e8bSJan Charvat txnf = 0; 181aa406e8bSJan Charvat 182aa406e8bSJan Charvat for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { 183aa406e8bSJan Charvat buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf; 184aa406e8bSJan Charvat if (buff_st == TXT_ETY) { 185aa406e8bSJan Charvat txnf = 1; 186aa406e8bSJan Charvat } 187aa406e8bSJan Charvat } 188aa406e8bSJan Charvat s->status.s.txnf = txnf; 189aa406e8bSJan Charvat } 190aa406e8bSJan Charvat 191aa406e8bSJan Charvat void ctucan_hardware_reset(CtuCanCoreState *s) 192aa406e8bSJan Charvat { 193aa406e8bSJan Charvat DPRINTF("Hardware reset in progress!!!\n"); 194aa406e8bSJan Charvat int i; 195aa406e8bSJan Charvat unsigned int buff_st; 196aa406e8bSJan Charvat uint32_t buff_st_mask; 197aa406e8bSJan Charvat 198aa406e8bSJan Charvat s->tx_status.u32 = 0; 199aa406e8bSJan Charvat for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { 200aa406e8bSJan Charvat buff_st_mask = 0xf << (i * 4); 201aa406e8bSJan Charvat buff_st = TXT_ETY; 202aa406e8bSJan Charvat s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) | 203aa406e8bSJan Charvat (buff_st << (i * 4)); 204aa406e8bSJan Charvat } 205aa406e8bSJan Charvat s->status.s.idle = 1; 206aa406e8bSJan Charvat 207aa406e8bSJan Charvat ctucan_update_txnf(s); 208aa406e8bSJan Charvat 209aa406e8bSJan Charvat s->rx_status_rx_settings.u32 = 0; 210aa406e8bSJan Charvat s->rx_tail_pos = 0; 211aa406e8bSJan Charvat s->rx_cnt = 0; 212aa406e8bSJan Charvat s->rx_frame_rem = 0; 213aa406e8bSJan Charvat 214aa406e8bSJan Charvat /* Flush RX buffer */ 215aa406e8bSJan Charvat s->rx_tail_pos = 0; 216aa406e8bSJan Charvat s->rx_cnt = 0; 217aa406e8bSJan Charvat s->rx_frame_rem = 0; 218aa406e8bSJan Charvat 219aa406e8bSJan Charvat /* Set on progdokum reset value */ 220aa406e8bSJan Charvat s->mode_settings.u32 = 0; 221aa406e8bSJan Charvat s->mode_settings.s.fde = 1; 222aa406e8bSJan Charvat 223aa406e8bSJan Charvat s->int_stat.u32 = 0; 224aa406e8bSJan Charvat s->int_ena.u32 = 0; 225aa406e8bSJan Charvat s->int_mask.u32 = 0; 226aa406e8bSJan Charvat 227aa406e8bSJan Charvat s->rx_status_rx_settings.u32 = 0; 228aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxe = 0; 229aa406e8bSJan Charvat 230aa406e8bSJan Charvat s->rx_fr_ctr.u32 = 0; 231aa406e8bSJan Charvat s->tx_fr_ctr.u32 = 0; 232aa406e8bSJan Charvat 233aa406e8bSJan Charvat s->yolo_reg.s.yolo_val = 3735928559; 234aa406e8bSJan Charvat 235aa406e8bSJan Charvat qemu_irq_lower(s->irq); 236aa406e8bSJan Charvat } 237aa406e8bSJan Charvat 238aa406e8bSJan Charvat static void ctucan_send_ready_buffers(CtuCanCoreState *s) 239aa406e8bSJan Charvat { 240aa406e8bSJan Charvat qemu_can_frame frame; 241aa406e8bSJan Charvat uint8_t *pf; 242aa406e8bSJan Charvat int buff2tx_idx; 243aa406e8bSJan Charvat uint32_t tx_prio_max; 244aa406e8bSJan Charvat 245aa406e8bSJan Charvat if (!s->mode_settings.s.ena) { 246aa406e8bSJan Charvat return; 247aa406e8bSJan Charvat } 248aa406e8bSJan Charvat 249aa406e8bSJan Charvat do { 250aa406e8bSJan Charvat union ctu_can_fd_int_stat int_stat; 251aa406e8bSJan Charvat int i; 252aa406e8bSJan Charvat buff2tx_idx = -1; 253aa406e8bSJan Charvat tx_prio_max = 0; 254aa406e8bSJan Charvat 255aa406e8bSJan Charvat for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { 256aa406e8bSJan Charvat uint32_t prio; 257aa406e8bSJan Charvat 258e0784d83SPeter Maydell if (extract32(s->tx_status.u32, i * 4, 4) != TXT_RDY) { 259aa406e8bSJan Charvat continue; 260aa406e8bSJan Charvat } 261aa406e8bSJan Charvat prio = (s->tx_priority.u32 >> (i * 4)) & 0x7; 262aa406e8bSJan Charvat if (tx_prio_max < prio) { 263aa406e8bSJan Charvat tx_prio_max = prio; 264aa406e8bSJan Charvat buff2tx_idx = i; 265aa406e8bSJan Charvat } 266aa406e8bSJan Charvat } 267aa406e8bSJan Charvat if (buff2tx_idx == -1) { 268aa406e8bSJan Charvat break; 269aa406e8bSJan Charvat } 270aa406e8bSJan Charvat int_stat.u32 = 0; 271aa406e8bSJan Charvat pf = s->tx_buffer[buff2tx_idx].data; 272aa406e8bSJan Charvat ctucan_buff2frame(pf, &frame); 273aa406e8bSJan Charvat s->status.s.idle = 0; 274aa406e8bSJan Charvat s->status.s.txs = 1; 275aa406e8bSJan Charvat can_bus_client_send(&s->bus_client, &frame, 1); 276aa406e8bSJan Charvat s->status.s.idle = 1; 277aa406e8bSJan Charvat s->status.s.txs = 0; 278aa406e8bSJan Charvat s->tx_fr_ctr.s.tx_fr_ctr_val++; 279aa406e8bSJan Charvat int_stat.s.txi = 1; 280aa406e8bSJan Charvat int_stat.s.txbhci = 1; 281aa406e8bSJan Charvat s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; 282e0784d83SPeter Maydell s->tx_status.u32 = deposit32(s->tx_status.u32, 283e0784d83SPeter Maydell buff2tx_idx * 4, 4, TXT_TOK); 284aa406e8bSJan Charvat } while (1); 285aa406e8bSJan Charvat } 286aa406e8bSJan Charvat 287aa406e8bSJan Charvat #define CTUCAN_CORE_TXBUFF_SPAN \ 288aa406e8bSJan Charvat (CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1) 289aa406e8bSJan Charvat 290aa406e8bSJan Charvat void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val, 291aa406e8bSJan Charvat unsigned size) 292aa406e8bSJan Charvat { 293aa406e8bSJan Charvat int i; 294aa406e8bSJan Charvat 295aa406e8bSJan Charvat DPRINTF("write 0x%02llx addr 0x%02x\n", 296aa406e8bSJan Charvat (unsigned long long)val, (unsigned int)addr); 297aa406e8bSJan Charvat 2985e73953aSPeter Maydell if (addr >= CTUCAN_CORE_MEM_SIZE) { 299aa406e8bSJan Charvat return; 300aa406e8bSJan Charvat } 301aa406e8bSJan Charvat 302aa406e8bSJan Charvat if (addr >= CTU_CAN_FD_TXTB1_DATA_1) { 303aa406e8bSJan Charvat int buff_num; 304aa406e8bSJan Charvat addr -= CTU_CAN_FD_TXTB1_DATA_1; 305aa406e8bSJan Charvat buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN; 306aa406e8bSJan Charvat addr %= CTUCAN_CORE_TXBUFF_SPAN; 3075e73953aSPeter Maydell if ((buff_num < CTUCAN_CORE_TXBUF_NUM) && 30871182187SPeter Maydell ((addr + size) <= sizeof(s->tx_buffer[buff_num].data))) { 30971182187SPeter Maydell stn_le_p(s->tx_buffer[buff_num].data + addr, size, val); 310aa406e8bSJan Charvat } 311aa406e8bSJan Charvat } else { 312aa406e8bSJan Charvat switch (addr & ~3) { 313aa406e8bSJan Charvat case CTU_CAN_FD_MODE: 314aa406e8bSJan Charvat s->mode_settings.u32 = (uint32_t)val; 315aa406e8bSJan Charvat if (s->mode_settings.s.rst) { 316aa406e8bSJan Charvat ctucan_hardware_reset(s); 317aa406e8bSJan Charvat s->mode_settings.s.rst = 0; 318aa406e8bSJan Charvat } 319aa406e8bSJan Charvat break; 320aa406e8bSJan Charvat case CTU_CAN_FD_COMMAND: 321aa406e8bSJan Charvat { 322aa406e8bSJan Charvat union ctu_can_fd_command command; 323aa406e8bSJan Charvat command.u32 = (uint32_t)val; 324aa406e8bSJan Charvat if (command.s.cdo) { 325aa406e8bSJan Charvat s->status.s.dor = 0; 326aa406e8bSJan Charvat } 327aa406e8bSJan Charvat if (command.s.rrb) { 328aa406e8bSJan Charvat s->rx_tail_pos = 0; 329aa406e8bSJan Charvat s->rx_cnt = 0; 330aa406e8bSJan Charvat s->rx_frame_rem = 0; 331aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxfrc = 0; 332aa406e8bSJan Charvat } 333aa406e8bSJan Charvat if (command.s.txfcrst) { 334aa406e8bSJan Charvat s->tx_fr_ctr.s.tx_fr_ctr_val = 0; 335aa406e8bSJan Charvat } 336aa406e8bSJan Charvat if (command.s.rxfcrst) { 337aa406e8bSJan Charvat s->rx_fr_ctr.s.rx_fr_ctr_val = 0; 338aa406e8bSJan Charvat } 339aa406e8bSJan Charvat break; 340aa406e8bSJan Charvat } 341aa406e8bSJan Charvat case CTU_CAN_FD_INT_STAT: 342aa406e8bSJan Charvat s->int_stat.u32 &= ~(uint32_t)val; 343aa406e8bSJan Charvat break; 344aa406e8bSJan Charvat case CTU_CAN_FD_INT_ENA_SET: 345aa406e8bSJan Charvat s->int_ena.u32 |= (uint32_t)val; 346aa406e8bSJan Charvat break; 347aa406e8bSJan Charvat case CTU_CAN_FD_INT_ENA_CLR: 348aa406e8bSJan Charvat s->int_ena.u32 &= ~(uint32_t)val; 349aa406e8bSJan Charvat break; 350aa406e8bSJan Charvat case CTU_CAN_FD_INT_MASK_SET: 351aa406e8bSJan Charvat s->int_mask.u32 |= (uint32_t)val; 352aa406e8bSJan Charvat break; 353aa406e8bSJan Charvat case CTU_CAN_FD_INT_MASK_CLR: 354aa406e8bSJan Charvat s->int_mask.u32 &= ~(uint32_t)val; 355aa406e8bSJan Charvat break; 356aa406e8bSJan Charvat case CTU_CAN_FD_TX_COMMAND: 357aa406e8bSJan Charvat if (s->mode_settings.s.ena) { 358aa406e8bSJan Charvat union ctu_can_fd_tx_command tx_command; 359aa406e8bSJan Charvat union ctu_can_fd_tx_command mask; 360aa406e8bSJan Charvat unsigned int buff_st; 361aa406e8bSJan Charvat uint32_t buff_st_mask; 362aa406e8bSJan Charvat 363aa406e8bSJan Charvat tx_command.u32 = (uint32_t)val; 364aa406e8bSJan Charvat mask.u32 = 0; 365aa406e8bSJan Charvat mask.s.txb1 = 1; 366aa406e8bSJan Charvat 367aa406e8bSJan Charvat for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { 368aa406e8bSJan Charvat if (!(tx_command.u32 & (mask.u32 << i))) { 369aa406e8bSJan Charvat continue; 370aa406e8bSJan Charvat } 371aa406e8bSJan Charvat buff_st_mask = 0xf << (i * 4); 372aa406e8bSJan Charvat buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf; 373aa406e8bSJan Charvat if (tx_command.s.txca) { 374aa406e8bSJan Charvat if (buff_st == TXT_RDY) { 375aa406e8bSJan Charvat buff_st = TXT_ABT; 376aa406e8bSJan Charvat } 377aa406e8bSJan Charvat } 378aa406e8bSJan Charvat if (tx_command.s.txcr) { 379aa406e8bSJan Charvat if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) || 380aa406e8bSJan Charvat (buff_st == TXT_ABT) || (buff_st == TXT_ETY)) 381aa406e8bSJan Charvat buff_st = TXT_RDY; 382aa406e8bSJan Charvat } 383aa406e8bSJan Charvat if (tx_command.s.txce) { 384aa406e8bSJan Charvat if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) || 385aa406e8bSJan Charvat (buff_st == TXT_ABT)) 386aa406e8bSJan Charvat buff_st = TXT_ETY; 387aa406e8bSJan Charvat } 388aa406e8bSJan Charvat s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) | 389aa406e8bSJan Charvat (buff_st << (i * 4)); 390aa406e8bSJan Charvat } 391aa406e8bSJan Charvat 392aa406e8bSJan Charvat ctucan_send_ready_buffers(s); 393aa406e8bSJan Charvat ctucan_update_txnf(s); 394aa406e8bSJan Charvat } 395aa406e8bSJan Charvat break; 396aa406e8bSJan Charvat case CTU_CAN_FD_TX_PRIORITY: 397aa406e8bSJan Charvat s->tx_priority.u32 = (uint32_t)val; 398aa406e8bSJan Charvat break; 399aa406e8bSJan Charvat } 400aa406e8bSJan Charvat 401aa406e8bSJan Charvat ctucan_update_irq(s); 402aa406e8bSJan Charvat } 403aa406e8bSJan Charvat 404aa406e8bSJan Charvat return; 405aa406e8bSJan Charvat } 406aa406e8bSJan Charvat 407aa406e8bSJan Charvat uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size) 408aa406e8bSJan Charvat { 409aa406e8bSJan Charvat uint32_t val = 0; 410aa406e8bSJan Charvat 411aa406e8bSJan Charvat DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr); 412aa406e8bSJan Charvat 413aa406e8bSJan Charvat if (addr > CTUCAN_CORE_MEM_SIZE) { 414aa406e8bSJan Charvat return 0; 415aa406e8bSJan Charvat } 416aa406e8bSJan Charvat 417aa406e8bSJan Charvat switch (addr & ~3) { 418aa406e8bSJan Charvat case CTU_CAN_FD_DEVICE_ID: 419aa406e8bSJan Charvat { 420aa406e8bSJan Charvat union ctu_can_fd_device_id_version idver; 421aa406e8bSJan Charvat idver.u32 = 0; 422aa406e8bSJan Charvat idver.s.device_id = CTU_CAN_FD_ID; 423aa406e8bSJan Charvat idver.s.ver_major = 2; 424aa406e8bSJan Charvat idver.s.ver_minor = 2; 425aa406e8bSJan Charvat val = idver.u32; 426aa406e8bSJan Charvat } 427aa406e8bSJan Charvat break; 428aa406e8bSJan Charvat case CTU_CAN_FD_MODE: 429aa406e8bSJan Charvat val = s->mode_settings.u32; 430aa406e8bSJan Charvat break; 431aa406e8bSJan Charvat case CTU_CAN_FD_STATUS: 432aa406e8bSJan Charvat val = s->status.u32; 433aa406e8bSJan Charvat break; 434aa406e8bSJan Charvat case CTU_CAN_FD_INT_STAT: 435aa406e8bSJan Charvat val = s->int_stat.u32; 436aa406e8bSJan Charvat break; 437aa406e8bSJan Charvat case CTU_CAN_FD_INT_ENA_SET: 438aa406e8bSJan Charvat case CTU_CAN_FD_INT_ENA_CLR: 439aa406e8bSJan Charvat val = s->int_ena.u32; 440aa406e8bSJan Charvat break; 441aa406e8bSJan Charvat case CTU_CAN_FD_INT_MASK_SET: 442aa406e8bSJan Charvat case CTU_CAN_FD_INT_MASK_CLR: 443aa406e8bSJan Charvat val = s->int_mask.u32; 444aa406e8bSJan Charvat break; 445aa406e8bSJan Charvat case CTU_CAN_FD_RX_MEM_INFO: 446aa406e8bSJan Charvat s->rx_mem_info.u32 = 0; 447aa406e8bSJan Charvat s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2; 448aa406e8bSJan Charvat s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN - 449aa406e8bSJan Charvat s->rx_cnt) >> 2; 450aa406e8bSJan Charvat val = s->rx_mem_info.u32; 451aa406e8bSJan Charvat break; 452aa406e8bSJan Charvat case CTU_CAN_FD_RX_POINTERS: 453aa406e8bSJan Charvat { 454aa406e8bSJan Charvat uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt; 455aa406e8bSJan Charvat rx_head_pos %= CTUCAN_RCV_BUF_LEN; 456aa406e8bSJan Charvat s->rx_pointers.s.rx_wpp = rx_head_pos; 457aa406e8bSJan Charvat s->rx_pointers.s.rx_rpp = s->rx_tail_pos; 458aa406e8bSJan Charvat val = s->rx_pointers.u32; 459aa406e8bSJan Charvat break; 460aa406e8bSJan Charvat } 461aa406e8bSJan Charvat case CTU_CAN_FD_RX_STATUS: 462aa406e8bSJan Charvat case CTU_CAN_FD_RX_SETTINGS: 463aa406e8bSJan Charvat if (!s->rx_status_rx_settings.s.rxfrc) { 464aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxe = 1; 465aa406e8bSJan Charvat } else { 466aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxe = 0; 467aa406e8bSJan Charvat } 468aa406e8bSJan Charvat if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) { 469aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxf = 1; 470aa406e8bSJan Charvat } else { 471aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxf = 0; 472aa406e8bSJan Charvat } 473aa406e8bSJan Charvat val = s->rx_status_rx_settings.u32; 474aa406e8bSJan Charvat break; 475aa406e8bSJan Charvat case CTU_CAN_FD_RX_DATA: 476aa406e8bSJan Charvat if (s->rx_cnt) { 477aa406e8bSJan Charvat memcpy(&val, s->rx_buff + s->rx_tail_pos, 4); 478aa406e8bSJan Charvat val = le32_to_cpu(val); 479aa406e8bSJan Charvat if (!s->rx_frame_rem) { 480aa406e8bSJan Charvat union ctu_can_fd_frame_form_w frame_form_w; 481aa406e8bSJan Charvat frame_form_w.u32 = val; 482aa406e8bSJan Charvat s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4; 483aa406e8bSJan Charvat } 484aa406e8bSJan Charvat s->rx_cnt -= 4; 485aa406e8bSJan Charvat s->rx_frame_rem -= 4; 486aa406e8bSJan Charvat if (!s->rx_frame_rem) { 487aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxfrc--; 488aa406e8bSJan Charvat if (!s->rx_status_rx_settings.s.rxfrc) { 489aa406e8bSJan Charvat s->status.s.rxne = 0; 490aa406e8bSJan Charvat s->status.s.idle = 1; 491aa406e8bSJan Charvat s->status.s.rxs = 0; 492aa406e8bSJan Charvat } 493aa406e8bSJan Charvat } 494aa406e8bSJan Charvat s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN; 495aa406e8bSJan Charvat } else { 496aa406e8bSJan Charvat val = 0; 497aa406e8bSJan Charvat } 498aa406e8bSJan Charvat break; 499aa406e8bSJan Charvat case CTU_CAN_FD_TX_STATUS: 500aa406e8bSJan Charvat val = s->tx_status.u32; 501aa406e8bSJan Charvat break; 502aa406e8bSJan Charvat case CTU_CAN_FD_TX_PRIORITY: 503aa406e8bSJan Charvat val = s->tx_priority.u32; 504aa406e8bSJan Charvat break; 505aa406e8bSJan Charvat case CTU_CAN_FD_RX_FR_CTR: 506aa406e8bSJan Charvat val = s->rx_fr_ctr.s.rx_fr_ctr_val; 507aa406e8bSJan Charvat break; 508aa406e8bSJan Charvat case CTU_CAN_FD_TX_FR_CTR: 509aa406e8bSJan Charvat val = s->tx_fr_ctr.s.tx_fr_ctr_val; 510aa406e8bSJan Charvat break; 511aa406e8bSJan Charvat case CTU_CAN_FD_YOLO_REG: 512aa406e8bSJan Charvat val = s->yolo_reg.s.yolo_val; 513aa406e8bSJan Charvat break; 514aa406e8bSJan Charvat } 515aa406e8bSJan Charvat 516aa406e8bSJan Charvat val >>= ((addr & 3) << 3); 517aa406e8bSJan Charvat if (size < 8) { 518aa406e8bSJan Charvat val &= ((uint64_t)1 << (size << 3)) - 1; 519aa406e8bSJan Charvat } 520aa406e8bSJan Charvat 521aa406e8bSJan Charvat return val; 522aa406e8bSJan Charvat } 523aa406e8bSJan Charvat 524aa406e8bSJan Charvat bool ctucan_can_receive(CanBusClientState *client) 525aa406e8bSJan Charvat { 526aa406e8bSJan Charvat CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client); 527aa406e8bSJan Charvat 528aa406e8bSJan Charvat if (!s->mode_settings.s.ena) { 529aa406e8bSJan Charvat return false; 530aa406e8bSJan Charvat } 531aa406e8bSJan Charvat 532aa406e8bSJan Charvat return true; /* always return true, when operation mode */ 533aa406e8bSJan Charvat } 534aa406e8bSJan Charvat 535aa406e8bSJan Charvat ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames, 536aa406e8bSJan Charvat size_t frames_cnt) 537aa406e8bSJan Charvat { 538aa406e8bSJan Charvat CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client); 539aa406e8bSJan Charvat static uint8_t rcv[CTUCAN_MSG_MAX_LEN]; 540aa406e8bSJan Charvat int i; 541aa406e8bSJan Charvat int ret = -1; 542aa406e8bSJan Charvat const qemu_can_frame *frame = frames; 543aa406e8bSJan Charvat union ctu_can_fd_int_stat int_stat; 544aa406e8bSJan Charvat int_stat.u32 = 0; 545aa406e8bSJan Charvat 546aa406e8bSJan Charvat if (frames_cnt <= 0) { 547aa406e8bSJan Charvat return 0; 548aa406e8bSJan Charvat } 549aa406e8bSJan Charvat 550aa406e8bSJan Charvat ret = ctucan_frame2buff(frame, rcv); 551aa406e8bSJan Charvat 552aa406e8bSJan Charvat if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */ 553aa406e8bSJan Charvat s->status.s.dor = 1; 554aa406e8bSJan Charvat int_stat.s.doi = 1; 555aa406e8bSJan Charvat s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; 556aa406e8bSJan Charvat ctucan_update_irq(s); 557aa406e8bSJan Charvat DPRINTF("Receive FIFO overrun\n"); 558aa406e8bSJan Charvat return ret; 559aa406e8bSJan Charvat } 560aa406e8bSJan Charvat s->status.s.idle = 0; 561aa406e8bSJan Charvat s->status.s.rxs = 1; 562aa406e8bSJan Charvat int_stat.s.rxi = 1; 563aa406e8bSJan Charvat if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) { 564aa406e8bSJan Charvat int_stat.s.rxfi = 1; 565aa406e8bSJan Charvat } 566aa406e8bSJan Charvat s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; 567aa406e8bSJan Charvat s->rx_fr_ctr.s.rx_fr_ctr_val++; 568aa406e8bSJan Charvat s->rx_status_rx_settings.s.rxfrc++; 569aa406e8bSJan Charvat for (i = 0; i < ret; i++) { 570aa406e8bSJan Charvat s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i]; 571aa406e8bSJan Charvat s->rx_cnt++; 572aa406e8bSJan Charvat } 573aa406e8bSJan Charvat s->status.s.rxne = 1; 574aa406e8bSJan Charvat 575aa406e8bSJan Charvat ctucan_update_irq(s); 576aa406e8bSJan Charvat 577aa406e8bSJan Charvat return 1; 578aa406e8bSJan Charvat } 579aa406e8bSJan Charvat 580aa406e8bSJan Charvat static CanBusClientInfo ctucan_bus_client_info = { 581aa406e8bSJan Charvat .can_receive = ctucan_can_receive, 582aa406e8bSJan Charvat .receive = ctucan_receive, 583aa406e8bSJan Charvat }; 584aa406e8bSJan Charvat 585aa406e8bSJan Charvat 586aa406e8bSJan Charvat int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus) 587aa406e8bSJan Charvat { 588aa406e8bSJan Charvat s->bus_client.info = &ctucan_bus_client_info; 589aa406e8bSJan Charvat 590aa406e8bSJan Charvat if (!bus) { 591aa406e8bSJan Charvat return -EINVAL; 592aa406e8bSJan Charvat } 593aa406e8bSJan Charvat 594aa406e8bSJan Charvat if (can_bus_insert_client(bus, &s->bus_client) < 0) { 595aa406e8bSJan Charvat return -1; 596aa406e8bSJan Charvat } 597aa406e8bSJan Charvat 598aa406e8bSJan Charvat return 0; 599aa406e8bSJan Charvat } 600aa406e8bSJan Charvat 601aa406e8bSJan Charvat void ctucan_disconnect(CtuCanCoreState *s) 602aa406e8bSJan Charvat { 603aa406e8bSJan Charvat can_bus_remove_client(&s->bus_client); 604aa406e8bSJan Charvat } 605aa406e8bSJan Charvat 606aa406e8bSJan Charvat int ctucan_init(CtuCanCoreState *s, qemu_irq irq) 607aa406e8bSJan Charvat { 608aa406e8bSJan Charvat s->irq = irq; 609aa406e8bSJan Charvat 610aa406e8bSJan Charvat qemu_irq_lower(s->irq); 611aa406e8bSJan Charvat 612aa406e8bSJan Charvat ctucan_hardware_reset(s); 613aa406e8bSJan Charvat 614aa406e8bSJan Charvat return 0; 615aa406e8bSJan Charvat } 616aa406e8bSJan Charvat 617aa406e8bSJan Charvat const VMStateDescription vmstate_qemu_ctucan_tx_buffer = { 618aa406e8bSJan Charvat .name = "qemu_ctucan_tx_buffer", 619aa406e8bSJan Charvat .version_id = 1, 620aa406e8bSJan Charvat .minimum_version_id = 1, 6211de81b42SRichard Henderson .fields = (const VMStateField[]) { 622aa406e8bSJan Charvat VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN), 623aa406e8bSJan Charvat VMSTATE_END_OF_LIST() 624aa406e8bSJan Charvat } 625aa406e8bSJan Charvat }; 626aa406e8bSJan Charvat 627aa406e8bSJan Charvat static int ctucan_post_load(void *opaque, int version_id) 628aa406e8bSJan Charvat { 629aa406e8bSJan Charvat CtuCanCoreState *s = opaque; 630aa406e8bSJan Charvat ctucan_update_irq(s); 631aa406e8bSJan Charvat return 0; 632aa406e8bSJan Charvat } 633aa406e8bSJan Charvat 634aa406e8bSJan Charvat /* VMState is needed for live migration of QEMU images */ 635aa406e8bSJan Charvat const VMStateDescription vmstate_ctucan = { 636aa406e8bSJan Charvat .name = "ctucan", 637aa406e8bSJan Charvat .version_id = 1, 638aa406e8bSJan Charvat .minimum_version_id = 1, 639aa406e8bSJan Charvat .post_load = ctucan_post_load, 6401de81b42SRichard Henderson .fields = (const VMStateField[]) { 641aa406e8bSJan Charvat VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState), 642aa406e8bSJan Charvat VMSTATE_UINT32(status.u32, CtuCanCoreState), 643aa406e8bSJan Charvat VMSTATE_UINT32(int_stat.u32, CtuCanCoreState), 644aa406e8bSJan Charvat VMSTATE_UINT32(int_ena.u32, CtuCanCoreState), 645aa406e8bSJan Charvat VMSTATE_UINT32(int_mask.u32, CtuCanCoreState), 646aa406e8bSJan Charvat VMSTATE_UINT32(brt.u32, CtuCanCoreState), 647aa406e8bSJan Charvat VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState), 648aa406e8bSJan Charvat VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState), 649aa406e8bSJan Charvat VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState), 650aa406e8bSJan Charvat VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState), 651aa406e8bSJan Charvat VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState), 652aa406e8bSJan Charvat VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState), 653aa406e8bSJan Charvat VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState), 654aa406e8bSJan Charvat VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState), 655aa406e8bSJan Charvat VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState), 656aa406e8bSJan Charvat VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState), 657aa406e8bSJan Charvat VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState), 658aa406e8bSJan Charvat VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState), 659aa406e8bSJan Charvat VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState), 660aa406e8bSJan Charvat VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState), 661aa406e8bSJan Charvat VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState), 662aa406e8bSJan Charvat VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState), 663aa406e8bSJan Charvat VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState), 664aa406e8bSJan Charvat VMSTATE_UINT32(tx_status.u32, CtuCanCoreState), 665aa406e8bSJan Charvat VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState), 666aa406e8bSJan Charvat VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState), 667aa406e8bSJan Charvat VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState), 668aa406e8bSJan Charvat VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState), 669aa406e8bSJan Charvat VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState), 670aa406e8bSJan Charvat VMSTATE_UINT32(debug_register.u32, CtuCanCoreState), 671aa406e8bSJan Charvat VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState), 672aa406e8bSJan Charvat VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState), 673aa406e8bSJan Charvat VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState), 674aa406e8bSJan Charvat 675aa406e8bSJan Charvat VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState, 676aa406e8bSJan Charvat CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer, 677aa406e8bSJan Charvat CtuCanCoreMsgBuffer), 678aa406e8bSJan Charvat 679aa406e8bSJan Charvat VMSTATE_BUFFER(rx_buff, CtuCanCoreState), 680aa406e8bSJan Charvat VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState), 681aa406e8bSJan Charvat VMSTATE_UINT32(rx_cnt, CtuCanCoreState), 682aa406e8bSJan Charvat VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState), 683aa406e8bSJan Charvat 684aa406e8bSJan Charvat VMSTATE_END_OF_LIST() 685aa406e8bSJan Charvat } 686aa406e8bSJan Charvat }; 687