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