1db3e6379SDeniz Eren /* 2db3e6379SDeniz Eren * MIOe-3680 PCI CAN device (SJA1000 based) emulation 3db3e6379SDeniz Eren * 4db3e6379SDeniz Eren * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com) 5db3e6379SDeniz Eren * 6db3e6379SDeniz Eren * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by 7db3e6379SDeniz Eren * Jin Yang and Pavel Pisa 8db3e6379SDeniz Eren * 9db3e6379SDeniz Eren * Permission is hereby granted, free of charge, to any person obtaining a copy 10db3e6379SDeniz Eren * of this software and associated documentation files (the "Software"), to deal 11db3e6379SDeniz Eren * in the Software without restriction, including without limitation the rights 12db3e6379SDeniz Eren * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13db3e6379SDeniz Eren * copies of the Software, and to permit persons to whom the Software is 14db3e6379SDeniz Eren * furnished to do so, subject to the following conditions: 15db3e6379SDeniz Eren * 16db3e6379SDeniz Eren * The above copyright notice and this permission notice shall be included in 17db3e6379SDeniz Eren * all copies or substantial portions of the Software. 18db3e6379SDeniz Eren * 19db3e6379SDeniz Eren * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20db3e6379SDeniz Eren * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21db3e6379SDeniz Eren * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22db3e6379SDeniz Eren * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23db3e6379SDeniz Eren * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24db3e6379SDeniz Eren * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25db3e6379SDeniz Eren * THE SOFTWARE. 26db3e6379SDeniz Eren */ 27db3e6379SDeniz Eren 28db3e6379SDeniz Eren #include "qemu/osdep.h" 290b8fa32fSMarkus Armbruster #include "qemu/module.h" 30db3e6379SDeniz Eren #include "qapi/error.h" 3164552b6bSMarkus Armbruster #include "hw/irq.h" 32edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h" 33a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 34d6454270SMarkus Armbruster #include "migration/vmstate.h" 35db3e6379SDeniz Eren #include "net/can_emu.h" 36db3e6379SDeniz Eren 37db3e6379SDeniz Eren #include "can_sja1000.h" 38db1015e9SEduardo Habkost #include "qom/object.h" 39db3e6379SDeniz Eren 40db3e6379SDeniz Eren #define TYPE_CAN_PCI_DEV "mioe3680_pci" 41db3e6379SDeniz Eren 42db1015e9SEduardo Habkost typedef struct Mioe3680PCIState Mioe3680PCIState; 438110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(Mioe3680PCIState, MIOe3680_PCI_DEV, 448110fa1dSEduardo Habkost TYPE_CAN_PCI_DEV) 45db3e6379SDeniz Eren 46db3e6379SDeniz Eren /* the PCI device and vendor IDs */ 47db3e6379SDeniz Eren #ifndef MIOe3680_PCI_VENDOR_ID1 48db3e6379SDeniz Eren #define MIOe3680_PCI_VENDOR_ID1 0x13fe 49db3e6379SDeniz Eren #endif 50db3e6379SDeniz Eren 51db3e6379SDeniz Eren #ifndef MIOe3680_PCI_DEVICE_ID1 52db3e6379SDeniz Eren #define MIOe3680_PCI_DEVICE_ID1 0xc302 53db3e6379SDeniz Eren #endif 54db3e6379SDeniz Eren 55db3e6379SDeniz Eren #define MIOe3680_PCI_SJA_COUNT 2 56db3e6379SDeniz Eren #define MIOe3680_PCI_SJA_RANGE 0x400 57db3e6379SDeniz Eren 58db3e6379SDeniz Eren #define MIOe3680_PCI_BYTES_PER_SJA 0x80 59db3e6379SDeniz Eren 60db1015e9SEduardo Habkost struct Mioe3680PCIState { 61db3e6379SDeniz Eren /*< private >*/ 62db3e6379SDeniz Eren PCIDevice dev; 63db3e6379SDeniz Eren /*< public >*/ 64db3e6379SDeniz Eren MemoryRegion sja_io[MIOe3680_PCI_SJA_COUNT]; 65db3e6379SDeniz Eren 66db3e6379SDeniz Eren CanSJA1000State sja_state[MIOe3680_PCI_SJA_COUNT]; 67db3e6379SDeniz Eren qemu_irq irq; 68db3e6379SDeniz Eren 69db3e6379SDeniz Eren char *model; /* The model that support, only SJA1000 now. */ 70db3e6379SDeniz Eren CanBusState *canbus[MIOe3680_PCI_SJA_COUNT]; 71db1015e9SEduardo Habkost }; 72db3e6379SDeniz Eren 73db3e6379SDeniz Eren static void mioe3680_pci_reset(DeviceState *dev) 74db3e6379SDeniz Eren { 75db3e6379SDeniz Eren Mioe3680PCIState *d = MIOe3680_PCI_DEV(dev); 76db3e6379SDeniz Eren int i; 77db3e6379SDeniz Eren 78db3e6379SDeniz Eren for (i = 0 ; i < MIOe3680_PCI_SJA_COUNT; i++) { 79db3e6379SDeniz Eren can_sja_hardware_reset(&d->sja_state[i]); 80db3e6379SDeniz Eren } 81db3e6379SDeniz Eren } 82db3e6379SDeniz Eren 83db3e6379SDeniz Eren static uint64_t mioe3680_pci_sja1_io_read(void *opaque, hwaddr addr, 84db3e6379SDeniz Eren unsigned size) 85db3e6379SDeniz Eren { 86db3e6379SDeniz Eren Mioe3680PCIState *d = opaque; 87db3e6379SDeniz Eren CanSJA1000State *s = &d->sja_state[0]; 88db3e6379SDeniz Eren 89db3e6379SDeniz Eren if (addr >= MIOe3680_PCI_BYTES_PER_SJA) { 90db3e6379SDeniz Eren return 0; 91db3e6379SDeniz Eren } 92db3e6379SDeniz Eren 93db3e6379SDeniz Eren return can_sja_mem_read(s, addr >> 2, size); 94db3e6379SDeniz Eren } 95db3e6379SDeniz Eren 96db3e6379SDeniz Eren static void mioe3680_pci_sja1_io_write(void *opaque, hwaddr addr, uint64_t data, 97db3e6379SDeniz Eren unsigned size) 98db3e6379SDeniz Eren { 99db3e6379SDeniz Eren Mioe3680PCIState *d = opaque; 100db3e6379SDeniz Eren CanSJA1000State *s = &d->sja_state[0]; 101db3e6379SDeniz Eren 102db3e6379SDeniz Eren if (addr >= MIOe3680_PCI_BYTES_PER_SJA) { 103db3e6379SDeniz Eren return; 104db3e6379SDeniz Eren } 105db3e6379SDeniz Eren 106db3e6379SDeniz Eren can_sja_mem_write(s, addr >> 2, data, size); 107db3e6379SDeniz Eren } 108db3e6379SDeniz Eren 109db3e6379SDeniz Eren static uint64_t mioe3680_pci_sja2_io_read(void *opaque, hwaddr addr, 110db3e6379SDeniz Eren unsigned size) 111db3e6379SDeniz Eren { 112db3e6379SDeniz Eren Mioe3680PCIState *d = opaque; 113db3e6379SDeniz Eren CanSJA1000State *s = &d->sja_state[1]; 114db3e6379SDeniz Eren 115db3e6379SDeniz Eren if (addr >= MIOe3680_PCI_BYTES_PER_SJA) { 116db3e6379SDeniz Eren return 0; 117db3e6379SDeniz Eren } 118db3e6379SDeniz Eren 119db3e6379SDeniz Eren return can_sja_mem_read(s, addr >> 2, size); 120db3e6379SDeniz Eren } 121db3e6379SDeniz Eren 122db3e6379SDeniz Eren static void mioe3680_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data, 123db3e6379SDeniz Eren unsigned size) 124db3e6379SDeniz Eren { 125db3e6379SDeniz Eren Mioe3680PCIState *d = opaque; 126db3e6379SDeniz Eren CanSJA1000State *s = &d->sja_state[1]; 127db3e6379SDeniz Eren 128db3e6379SDeniz Eren if (addr >= MIOe3680_PCI_BYTES_PER_SJA) { 129db3e6379SDeniz Eren return; 130db3e6379SDeniz Eren } 131db3e6379SDeniz Eren 132db3e6379SDeniz Eren can_sja_mem_write(s, addr >> 2, data, size); 133db3e6379SDeniz Eren } 134db3e6379SDeniz Eren 135db3e6379SDeniz Eren static const MemoryRegionOps mioe3680_pci_sja1_io_ops = { 136db3e6379SDeniz Eren .read = mioe3680_pci_sja1_io_read, 137db3e6379SDeniz Eren .write = mioe3680_pci_sja1_io_write, 138db3e6379SDeniz Eren .endianness = DEVICE_LITTLE_ENDIAN, 139db3e6379SDeniz Eren .impl = { 140db3e6379SDeniz Eren .max_access_size = 1, 141db3e6379SDeniz Eren }, 142db3e6379SDeniz Eren }; 143db3e6379SDeniz Eren 144db3e6379SDeniz Eren static const MemoryRegionOps mioe3680_pci_sja2_io_ops = { 145db3e6379SDeniz Eren .read = mioe3680_pci_sja2_io_read, 146db3e6379SDeniz Eren .write = mioe3680_pci_sja2_io_write, 147db3e6379SDeniz Eren .endianness = DEVICE_LITTLE_ENDIAN, 148db3e6379SDeniz Eren .impl = { 149db3e6379SDeniz Eren .max_access_size = 1, 150db3e6379SDeniz Eren }, 151db3e6379SDeniz Eren }; 152db3e6379SDeniz Eren 153db3e6379SDeniz Eren static void mioe3680_pci_realize(PCIDevice *pci_dev, Error **errp) 154db3e6379SDeniz Eren { 155db3e6379SDeniz Eren Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev); 156db3e6379SDeniz Eren uint8_t *pci_conf; 157db3e6379SDeniz Eren int i; 158db3e6379SDeniz Eren 159db3e6379SDeniz Eren pci_conf = pci_dev->config; 160db3e6379SDeniz Eren pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ 161db3e6379SDeniz Eren 162db3e6379SDeniz Eren d->irq = pci_allocate_irq(&d->dev); 163db3e6379SDeniz Eren 164db3e6379SDeniz Eren for (i = 0 ; i < MIOe3680_PCI_SJA_COUNT; i++) { 165db3e6379SDeniz Eren can_sja_init(&d->sja_state[i], d->irq); 166db3e6379SDeniz Eren } 167db3e6379SDeniz Eren 168db3e6379SDeniz Eren for (i = 0 ; i < MIOe3680_PCI_SJA_COUNT; i++) { 169db3e6379SDeniz Eren if (can_sja_connect_to_bus(&d->sja_state[i], d->canbus[i]) < 0) { 170db3e6379SDeniz Eren error_setg(errp, "can_sja_connect_to_bus failed"); 171db3e6379SDeniz Eren return; 172db3e6379SDeniz Eren } 173db3e6379SDeniz Eren } 174db3e6379SDeniz Eren 175db3e6379SDeniz Eren memory_region_init_io(&d->sja_io[0], OBJECT(d), &mioe3680_pci_sja1_io_ops, 176db3e6379SDeniz Eren d, "mioe3680_pci-sja1", MIOe3680_PCI_SJA_RANGE); 177db3e6379SDeniz Eren memory_region_init_io(&d->sja_io[1], OBJECT(d), &mioe3680_pci_sja2_io_ops, 178db3e6379SDeniz Eren d, "mioe3680_pci-sja2", MIOe3680_PCI_SJA_RANGE); 179db3e6379SDeniz Eren 180db3e6379SDeniz Eren for (i = 0 ; i < MIOe3680_PCI_SJA_COUNT; i++) { 181db3e6379SDeniz Eren pci_register_bar(&d->dev, /*BAR*/ i, PCI_BASE_ADDRESS_SPACE_IO, 182db3e6379SDeniz Eren &d->sja_io[i]); 183db3e6379SDeniz Eren } 184db3e6379SDeniz Eren } 185db3e6379SDeniz Eren 186db3e6379SDeniz Eren static void mioe3680_pci_exit(PCIDevice *pci_dev) 187db3e6379SDeniz Eren { 188db3e6379SDeniz Eren Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev); 189db3e6379SDeniz Eren int i; 190db3e6379SDeniz Eren 191db3e6379SDeniz Eren for (i = 0 ; i < MIOe3680_PCI_SJA_COUNT; i++) { 192db3e6379SDeniz Eren can_sja_disconnect(&d->sja_state[i]); 193db3e6379SDeniz Eren } 194db3e6379SDeniz Eren 195db3e6379SDeniz Eren qemu_free_irq(d->irq); 196db3e6379SDeniz Eren } 197db3e6379SDeniz Eren 198db3e6379SDeniz Eren static const VMStateDescription vmstate_mioe3680_pci = { 199db3e6379SDeniz Eren .name = "mioe3680_pci", 200db3e6379SDeniz Eren .version_id = 1, 201db3e6379SDeniz Eren .minimum_version_id = 1, 2021de81b42SRichard Henderson .fields = (const VMStateField[]) { 203db3e6379SDeniz Eren VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState), 204db3e6379SDeniz Eren VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja, 205db3e6379SDeniz Eren CanSJA1000State), 206db3e6379SDeniz Eren VMSTATE_STRUCT(sja_state[1], Mioe3680PCIState, 0, vmstate_can_sja, 207db3e6379SDeniz Eren CanSJA1000State), 208db3e6379SDeniz Eren VMSTATE_END_OF_LIST() 209db3e6379SDeniz Eren } 210db3e6379SDeniz Eren }; 211db3e6379SDeniz Eren 212db3e6379SDeniz Eren static void mioe3680_pci_instance_init(Object *obj) 213db3e6379SDeniz Eren { 214db3e6379SDeniz Eren Mioe3680PCIState *d = MIOe3680_PCI_DEV(obj); 215db3e6379SDeniz Eren 216db3e6379SDeniz Eren object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, 217db3e6379SDeniz Eren (Object **)&d->canbus[0], 218db3e6379SDeniz Eren qdev_prop_allow_set_link_before_realize, 219d2623129SMarkus Armbruster 0); 220db3e6379SDeniz Eren object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, 221db3e6379SDeniz Eren (Object **)&d->canbus[1], 222db3e6379SDeniz Eren qdev_prop_allow_set_link_before_realize, 223d2623129SMarkus Armbruster 0); 224db3e6379SDeniz Eren } 225db3e6379SDeniz Eren 226*12d1a768SPhilippe Mathieu-Daudé static void mioe3680_pci_class_init(ObjectClass *klass, const void *data) 227db3e6379SDeniz Eren { 228db3e6379SDeniz Eren DeviceClass *dc = DEVICE_CLASS(klass); 229db3e6379SDeniz Eren PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 230db3e6379SDeniz Eren 231db3e6379SDeniz Eren k->realize = mioe3680_pci_realize; 232db3e6379SDeniz Eren k->exit = mioe3680_pci_exit; 233db3e6379SDeniz Eren k->vendor_id = MIOe3680_PCI_VENDOR_ID1; 234db3e6379SDeniz Eren k->device_id = MIOe3680_PCI_DEVICE_ID1; 235db3e6379SDeniz Eren k->revision = 0x00; 236db3e6379SDeniz Eren k->class_id = 0x000c09; 237db3e6379SDeniz Eren k->subsystem_vendor_id = MIOe3680_PCI_VENDOR_ID1; 238db3e6379SDeniz Eren k->subsystem_id = MIOe3680_PCI_DEVICE_ID1; 239db3e6379SDeniz Eren dc->desc = "Mioe3680 PCICANx"; 240db3e6379SDeniz Eren dc->vmsd = &vmstate_mioe3680_pci; 241db3e6379SDeniz Eren set_bit(DEVICE_CATEGORY_MISC, dc->categories); 242e3d08143SPeter Maydell device_class_set_legacy_reset(dc, mioe3680_pci_reset); 243db3e6379SDeniz Eren } 244db3e6379SDeniz Eren 245db3e6379SDeniz Eren static const TypeInfo mioe3680_pci_info = { 246db3e6379SDeniz Eren .name = TYPE_CAN_PCI_DEV, 247db3e6379SDeniz Eren .parent = TYPE_PCI_DEVICE, 248db3e6379SDeniz Eren .instance_size = sizeof(Mioe3680PCIState), 249db3e6379SDeniz Eren .class_init = mioe3680_pci_class_init, 250db3e6379SDeniz Eren .instance_init = mioe3680_pci_instance_init, 251db3e6379SDeniz Eren .interfaces = (InterfaceInfo[]) { 252db3e6379SDeniz Eren { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 253db3e6379SDeniz Eren { }, 254db3e6379SDeniz Eren }, 255db3e6379SDeniz Eren }; 256db3e6379SDeniz Eren 257db3e6379SDeniz Eren static void mioe3680_pci_register_types(void) 258db3e6379SDeniz Eren { 259db3e6379SDeniz Eren type_register_static(&mioe3680_pci_info); 260db3e6379SDeniz Eren } 261db3e6379SDeniz Eren 262db3e6379SDeniz Eren type_init(mioe3680_pci_register_types) 263