1*aa406e8bSJan Charvat /* 2*aa406e8bSJan Charvat * CTU CAN FD PCI device emulation 3*aa406e8bSJan Charvat * http://canbus.pages.fel.cvut.cz/ 4*aa406e8bSJan Charvat * 5*aa406e8bSJan Charvat * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com) 6*aa406e8bSJan Charvat * 7*aa406e8bSJan Charvat * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by 8*aa406e8bSJan Charvat * Jin Yang and Pavel Pisa 9*aa406e8bSJan Charvat * 10*aa406e8bSJan Charvat * Permission is hereby granted, free of charge, to any person obtaining a copy 11*aa406e8bSJan Charvat * of this software and associated documentation files (the "Software"), to deal 12*aa406e8bSJan Charvat * in the Software without restriction, including without limitation the rights 13*aa406e8bSJan Charvat * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14*aa406e8bSJan Charvat * copies of the Software, and to permit persons to whom the Software is 15*aa406e8bSJan Charvat * furnished to do so, subject to the following conditions: 16*aa406e8bSJan Charvat * 17*aa406e8bSJan Charvat * The above copyright notice and this permission notice shall be included in 18*aa406e8bSJan Charvat * all copies or substantial portions of the Software. 19*aa406e8bSJan Charvat * 20*aa406e8bSJan Charvat * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21*aa406e8bSJan Charvat * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22*aa406e8bSJan Charvat * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23*aa406e8bSJan Charvat * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24*aa406e8bSJan Charvat * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25*aa406e8bSJan Charvat * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26*aa406e8bSJan Charvat * THE SOFTWARE. 27*aa406e8bSJan Charvat */ 28*aa406e8bSJan Charvat 29*aa406e8bSJan Charvat #include "qemu/osdep.h" 30*aa406e8bSJan Charvat #include "qemu/event_notifier.h" 31*aa406e8bSJan Charvat #include "qemu/module.h" 32*aa406e8bSJan Charvat #include "qemu/thread.h" 33*aa406e8bSJan Charvat #include "qemu/sockets.h" 34*aa406e8bSJan Charvat #include "qapi/error.h" 35*aa406e8bSJan Charvat #include "chardev/char.h" 36*aa406e8bSJan Charvat #include "hw/irq.h" 37*aa406e8bSJan Charvat #include "hw/pci/pci.h" 38*aa406e8bSJan Charvat #include "hw/qdev-properties.h" 39*aa406e8bSJan Charvat #include "migration/vmstate.h" 40*aa406e8bSJan Charvat #include "net/can_emu.h" 41*aa406e8bSJan Charvat 42*aa406e8bSJan Charvat #include "ctucan_core.h" 43*aa406e8bSJan Charvat 44*aa406e8bSJan Charvat #define TYPE_CTUCAN_PCI_DEV "ctucan_pci" 45*aa406e8bSJan Charvat 46*aa406e8bSJan Charvat typedef struct CtuCanPCIState CtuCanPCIState; 47*aa406e8bSJan Charvat DECLARE_INSTANCE_CHECKER(CtuCanPCIState, CTUCAN_PCI_DEV, 48*aa406e8bSJan Charvat TYPE_CTUCAN_PCI_DEV) 49*aa406e8bSJan Charvat 50*aa406e8bSJan Charvat #define CTUCAN_PCI_CORE_COUNT 2 51*aa406e8bSJan Charvat #define CTUCAN_PCI_CORE_RANGE 0x10000 52*aa406e8bSJan Charvat 53*aa406e8bSJan Charvat #define CTUCAN_PCI_BAR_COUNT 2 54*aa406e8bSJan Charvat 55*aa406e8bSJan Charvat #define CTUCAN_PCI_BYTES_PER_CORE 0x4000 56*aa406e8bSJan Charvat 57*aa406e8bSJan Charvat #ifndef PCI_VENDOR_ID_TEDIA 58*aa406e8bSJan Charvat #define PCI_VENDOR_ID_TEDIA 0x1760 59*aa406e8bSJan Charvat #endif 60*aa406e8bSJan Charvat 61*aa406e8bSJan Charvat #define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00 62*aa406e8bSJan Charvat 63*aa406e8bSJan Charvat #define CTUCAN_BAR0_RANGE 0x8000 64*aa406e8bSJan Charvat #define CTUCAN_BAR0_CTUCAN_ID 0x0000 65*aa406e8bSJan Charvat #define CTUCAN_BAR0_CRA_BASE 0x4000 66*aa406e8bSJan Charvat #define CYCLONE_IV_CRA_A2P_IE (0x0050) 67*aa406e8bSJan Charvat 68*aa406e8bSJan Charvat #define CTUCAN_WITHOUT_CTUCAN_ID 0 69*aa406e8bSJan Charvat #define CTUCAN_WITH_CTUCAN_ID 1 70*aa406e8bSJan Charvat 71*aa406e8bSJan Charvat struct CtuCanPCIState { 72*aa406e8bSJan Charvat /*< private >*/ 73*aa406e8bSJan Charvat PCIDevice dev; 74*aa406e8bSJan Charvat /*< public >*/ 75*aa406e8bSJan Charvat MemoryRegion ctucan_io[CTUCAN_PCI_BAR_COUNT]; 76*aa406e8bSJan Charvat 77*aa406e8bSJan Charvat CtuCanCoreState ctucan_state[CTUCAN_PCI_CORE_COUNT]; 78*aa406e8bSJan Charvat qemu_irq irq; 79*aa406e8bSJan Charvat 80*aa406e8bSJan Charvat char *model; /* The model that support, only SJA1000 now. */ 81*aa406e8bSJan Charvat CanBusState *canbus[CTUCAN_PCI_CORE_COUNT]; 82*aa406e8bSJan Charvat }; 83*aa406e8bSJan Charvat 84*aa406e8bSJan Charvat static void ctucan_pci_reset(DeviceState *dev) 85*aa406e8bSJan Charvat { 86*aa406e8bSJan Charvat CtuCanPCIState *d = CTUCAN_PCI_DEV(dev); 87*aa406e8bSJan Charvat int i; 88*aa406e8bSJan Charvat 89*aa406e8bSJan Charvat for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { 90*aa406e8bSJan Charvat ctucan_hardware_reset(&d->ctucan_state[i]); 91*aa406e8bSJan Charvat } 92*aa406e8bSJan Charvat } 93*aa406e8bSJan Charvat 94*aa406e8bSJan Charvat static uint64_t ctucan_pci_id_cra_io_read(void *opaque, hwaddr addr, 95*aa406e8bSJan Charvat unsigned size) 96*aa406e8bSJan Charvat { 97*aa406e8bSJan Charvat if (addr >= 4) { 98*aa406e8bSJan Charvat return 0; 99*aa406e8bSJan Charvat } 100*aa406e8bSJan Charvat 101*aa406e8bSJan Charvat uint64_t tmp = 0xC0000000 + CTUCAN_PCI_CORE_COUNT; 102*aa406e8bSJan Charvat tmp >>= ((addr & 3) << 3); 103*aa406e8bSJan Charvat if (size < 8) { 104*aa406e8bSJan Charvat tmp &= ((uint64_t)1 << (size << 3)) - 1; 105*aa406e8bSJan Charvat } 106*aa406e8bSJan Charvat return tmp; 107*aa406e8bSJan Charvat } 108*aa406e8bSJan Charvat 109*aa406e8bSJan Charvat static void ctucan_pci_id_cra_io_write(void *opaque, hwaddr addr, uint64_t data, 110*aa406e8bSJan Charvat unsigned size) 111*aa406e8bSJan Charvat { 112*aa406e8bSJan Charvat 113*aa406e8bSJan Charvat } 114*aa406e8bSJan Charvat 115*aa406e8bSJan Charvat static uint64_t ctucan_pci_cores_io_read(void *opaque, hwaddr addr, 116*aa406e8bSJan Charvat unsigned size) 117*aa406e8bSJan Charvat { 118*aa406e8bSJan Charvat CtuCanPCIState *d = opaque; 119*aa406e8bSJan Charvat CtuCanCoreState *s; 120*aa406e8bSJan Charvat hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE; 121*aa406e8bSJan Charvat 122*aa406e8bSJan Charvat if (core_num >= CTUCAN_PCI_CORE_COUNT) { 123*aa406e8bSJan Charvat return 0; 124*aa406e8bSJan Charvat } 125*aa406e8bSJan Charvat 126*aa406e8bSJan Charvat s = &d->ctucan_state[core_num]; 127*aa406e8bSJan Charvat 128*aa406e8bSJan Charvat return ctucan_mem_read(s, addr % CTUCAN_PCI_BYTES_PER_CORE, size); 129*aa406e8bSJan Charvat } 130*aa406e8bSJan Charvat 131*aa406e8bSJan Charvat static void ctucan_pci_cores_io_write(void *opaque, hwaddr addr, uint64_t data, 132*aa406e8bSJan Charvat unsigned size) 133*aa406e8bSJan Charvat { 134*aa406e8bSJan Charvat CtuCanPCIState *d = opaque; 135*aa406e8bSJan Charvat CtuCanCoreState *s; 136*aa406e8bSJan Charvat hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE; 137*aa406e8bSJan Charvat 138*aa406e8bSJan Charvat if (core_num >= CTUCAN_PCI_CORE_COUNT) { 139*aa406e8bSJan Charvat return; 140*aa406e8bSJan Charvat } 141*aa406e8bSJan Charvat 142*aa406e8bSJan Charvat s = &d->ctucan_state[core_num]; 143*aa406e8bSJan Charvat 144*aa406e8bSJan Charvat return ctucan_mem_write(s, addr % CTUCAN_PCI_BYTES_PER_CORE, data, size); 145*aa406e8bSJan Charvat } 146*aa406e8bSJan Charvat 147*aa406e8bSJan Charvat static const MemoryRegionOps ctucan_pci_id_cra_io_ops = { 148*aa406e8bSJan Charvat .read = ctucan_pci_id_cra_io_read, 149*aa406e8bSJan Charvat .write = ctucan_pci_id_cra_io_write, 150*aa406e8bSJan Charvat .endianness = DEVICE_LITTLE_ENDIAN, 151*aa406e8bSJan Charvat .impl.min_access_size = 1, 152*aa406e8bSJan Charvat .impl.max_access_size = 4, 153*aa406e8bSJan Charvat .valid.min_access_size = 1, 154*aa406e8bSJan Charvat .valid.max_access_size = 4, 155*aa406e8bSJan Charvat }; 156*aa406e8bSJan Charvat 157*aa406e8bSJan Charvat static const MemoryRegionOps ctucan_pci_cores_io_ops = { 158*aa406e8bSJan Charvat .read = ctucan_pci_cores_io_read, 159*aa406e8bSJan Charvat .write = ctucan_pci_cores_io_write, 160*aa406e8bSJan Charvat .endianness = DEVICE_LITTLE_ENDIAN, 161*aa406e8bSJan Charvat .impl.min_access_size = 1, 162*aa406e8bSJan Charvat .impl.max_access_size = 4, 163*aa406e8bSJan Charvat .valid.min_access_size = 1, 164*aa406e8bSJan Charvat .valid.max_access_size = 4, 165*aa406e8bSJan Charvat }; 166*aa406e8bSJan Charvat 167*aa406e8bSJan Charvat static void ctucan_pci_realize(PCIDevice *pci_dev, Error **errp) 168*aa406e8bSJan Charvat { 169*aa406e8bSJan Charvat CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev); 170*aa406e8bSJan Charvat uint8_t *pci_conf; 171*aa406e8bSJan Charvat int i; 172*aa406e8bSJan Charvat 173*aa406e8bSJan Charvat pci_conf = pci_dev->config; 174*aa406e8bSJan Charvat pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ 175*aa406e8bSJan Charvat 176*aa406e8bSJan Charvat d->irq = pci_allocate_irq(&d->dev); 177*aa406e8bSJan Charvat 178*aa406e8bSJan Charvat for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { 179*aa406e8bSJan Charvat ctucan_init(&d->ctucan_state[i], d->irq); 180*aa406e8bSJan Charvat } 181*aa406e8bSJan Charvat 182*aa406e8bSJan Charvat for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { 183*aa406e8bSJan Charvat if (ctucan_connect_to_bus(&d->ctucan_state[i], d->canbus[i]) < 0) { 184*aa406e8bSJan Charvat error_setg(errp, "ctucan_connect_to_bus failed"); 185*aa406e8bSJan Charvat return; 186*aa406e8bSJan Charvat } 187*aa406e8bSJan Charvat } 188*aa406e8bSJan Charvat 189*aa406e8bSJan Charvat memory_region_init_io(&d->ctucan_io[0], OBJECT(d), 190*aa406e8bSJan Charvat &ctucan_pci_id_cra_io_ops, d, 191*aa406e8bSJan Charvat "ctucan_pci-core0", CTUCAN_BAR0_RANGE); 192*aa406e8bSJan Charvat memory_region_init_io(&d->ctucan_io[1], OBJECT(d), 193*aa406e8bSJan Charvat &ctucan_pci_cores_io_ops, d, 194*aa406e8bSJan Charvat "ctucan_pci-core1", CTUCAN_PCI_CORE_RANGE); 195*aa406e8bSJan Charvat 196*aa406e8bSJan Charvat for (i = 0 ; i < CTUCAN_PCI_BAR_COUNT; i++) { 197*aa406e8bSJan Charvat pci_register_bar(&d->dev, i, PCI_BASE_ADDRESS_MEM_MASK & 0, 198*aa406e8bSJan Charvat &d->ctucan_io[i]); 199*aa406e8bSJan Charvat } 200*aa406e8bSJan Charvat } 201*aa406e8bSJan Charvat 202*aa406e8bSJan Charvat static void ctucan_pci_exit(PCIDevice *pci_dev) 203*aa406e8bSJan Charvat { 204*aa406e8bSJan Charvat CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev); 205*aa406e8bSJan Charvat int i; 206*aa406e8bSJan Charvat 207*aa406e8bSJan Charvat for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { 208*aa406e8bSJan Charvat ctucan_disconnect(&d->ctucan_state[i]); 209*aa406e8bSJan Charvat } 210*aa406e8bSJan Charvat 211*aa406e8bSJan Charvat qemu_free_irq(d->irq); 212*aa406e8bSJan Charvat } 213*aa406e8bSJan Charvat 214*aa406e8bSJan Charvat static const VMStateDescription vmstate_ctucan_pci = { 215*aa406e8bSJan Charvat .name = "ctucan_pci", 216*aa406e8bSJan Charvat .version_id = 1, 217*aa406e8bSJan Charvat .minimum_version_id = 1, 218*aa406e8bSJan Charvat .minimum_version_id_old = 1, 219*aa406e8bSJan Charvat .fields = (VMStateField[]) { 220*aa406e8bSJan Charvat VMSTATE_PCI_DEVICE(dev, CtuCanPCIState), 221*aa406e8bSJan Charvat VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan, 222*aa406e8bSJan Charvat CtuCanCoreState), 223*aa406e8bSJan Charvat #if CTUCAN_PCI_CORE_COUNT >= 2 224*aa406e8bSJan Charvat VMSTATE_STRUCT(ctucan_state[1], CtuCanPCIState, 0, vmstate_ctucan, 225*aa406e8bSJan Charvat CtuCanCoreState), 226*aa406e8bSJan Charvat #endif 227*aa406e8bSJan Charvat VMSTATE_END_OF_LIST() 228*aa406e8bSJan Charvat } 229*aa406e8bSJan Charvat }; 230*aa406e8bSJan Charvat 231*aa406e8bSJan Charvat static void ctucan_pci_instance_init(Object *obj) 232*aa406e8bSJan Charvat { 233*aa406e8bSJan Charvat CtuCanPCIState *d = CTUCAN_PCI_DEV(obj); 234*aa406e8bSJan Charvat 235*aa406e8bSJan Charvat object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, 236*aa406e8bSJan Charvat (Object **)&d->canbus[0], 237*aa406e8bSJan Charvat qdev_prop_allow_set_link_before_realize, 0); 238*aa406e8bSJan Charvat #if CTUCAN_PCI_CORE_COUNT >= 2 239*aa406e8bSJan Charvat object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, 240*aa406e8bSJan Charvat (Object **)&d->canbus[1], 241*aa406e8bSJan Charvat qdev_prop_allow_set_link_before_realize, 0); 242*aa406e8bSJan Charvat #endif 243*aa406e8bSJan Charvat } 244*aa406e8bSJan Charvat 245*aa406e8bSJan Charvat static void ctucan_pci_class_init(ObjectClass *klass, void *data) 246*aa406e8bSJan Charvat { 247*aa406e8bSJan Charvat DeviceClass *dc = DEVICE_CLASS(klass); 248*aa406e8bSJan Charvat PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 249*aa406e8bSJan Charvat 250*aa406e8bSJan Charvat k->realize = ctucan_pci_realize; 251*aa406e8bSJan Charvat k->exit = ctucan_pci_exit; 252*aa406e8bSJan Charvat k->vendor_id = PCI_VENDOR_ID_TEDIA; 253*aa406e8bSJan Charvat k->device_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21; 254*aa406e8bSJan Charvat k->revision = 0x00; 255*aa406e8bSJan Charvat k->class_id = 0x000c09; 256*aa406e8bSJan Charvat k->subsystem_vendor_id = PCI_VENDOR_ID_TEDIA; 257*aa406e8bSJan Charvat k->subsystem_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21; 258*aa406e8bSJan Charvat dc->desc = "CTU CAN PCI"; 259*aa406e8bSJan Charvat dc->vmsd = &vmstate_ctucan_pci; 260*aa406e8bSJan Charvat set_bit(DEVICE_CATEGORY_MISC, dc->categories); 261*aa406e8bSJan Charvat dc->reset = ctucan_pci_reset; 262*aa406e8bSJan Charvat } 263*aa406e8bSJan Charvat 264*aa406e8bSJan Charvat static const TypeInfo ctucan_pci_info = { 265*aa406e8bSJan Charvat .name = TYPE_CTUCAN_PCI_DEV, 266*aa406e8bSJan Charvat .parent = TYPE_PCI_DEVICE, 267*aa406e8bSJan Charvat .instance_size = sizeof(CtuCanPCIState), 268*aa406e8bSJan Charvat .class_init = ctucan_pci_class_init, 269*aa406e8bSJan Charvat .instance_init = ctucan_pci_instance_init, 270*aa406e8bSJan Charvat .interfaces = (InterfaceInfo[]) { 271*aa406e8bSJan Charvat { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 272*aa406e8bSJan Charvat { }, 273*aa406e8bSJan Charvat }, 274*aa406e8bSJan Charvat }; 275*aa406e8bSJan Charvat 276*aa406e8bSJan Charvat static void ctucan_pci_register_types(void) 277*aa406e8bSJan Charvat { 278*aa406e8bSJan Charvat type_register_static(&ctucan_pci_info); 279*aa406e8bSJan Charvat } 280*aa406e8bSJan Charvat 281*aa406e8bSJan Charvat type_init(ctucan_pci_register_types) 282