2 * Kvaser PCI CAN device (SJA1000 based) emulation
4 * Copyright (c) 2013-2014 Jin Yang
5 * Copyright (c) 2014-2018 Pavel Pisa
7 * Partially based on educational PCIexpress APOHW hardware
8 * emulator used fro class A0B36APO at CTU FEE course by
9 * Rostislav Lisovy and Pavel Pisa
11 * Initial development supported by Google GSoC 2013 from RTEMS project slot
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the "Software"), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is
18 * furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 #include "qemu/osdep.h"
33 #include "qemu/event_notifier.h"
34 #include "qemu/module.h"
35 #include "qemu/thread.h"
36 #include "qemu/sockets.h"
37 #include "qapi/error.h"
38 #include "chardev/char.h"
40 #include "hw/pci/pci.h"
41 #include "hw/qdev-properties.h"
42 #include "migration/vmstate.h"
43 #include "net/can_emu.h"
45 #include "can_sja1000.h"
47 #define TYPE_CAN_PCI_DEV "kvaser_pci"
49 #define KVASER_PCI_DEV(obj) \
50 OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
52 #ifndef KVASER_PCI_VENDOR_ID1
53 #define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */
56 #ifndef KVASER_PCI_DEVICE_ID1
57 #define KVASER_PCI_DEVICE_ID1 0x8406
60 #define KVASER_PCI_S5920_RANGE 0x80
61 #define KVASER_PCI_SJA_RANGE 0x80
62 #define KVASER_PCI_XILINX_RANGE 0x8
64 #define KVASER_PCI_BYTES_PER_SJA 0x20
66 #define S5920_OMB 0x0C
67 #define S5920_IMB 0x1C
68 #define S5920_MBEF 0x34
69 #define S5920_INTCSR 0x38
70 #define S5920_RCR 0x3C
71 #define S5920_PTCR 0x60
73 #define S5920_INTCSR_ADDON_INTENABLE_M 0x2000
74 #define S5920_INTCSR_INTERRUPT_ASSERTED_M 0x800000
76 #define KVASER_PCI_XILINX_VERINT 7 /* Lower nibble simulate interrupts,
77 high nibble version number. */
79 #define KVASER_PCI_XILINX_VERSION_NUMBER 13
81 typedef struct KvaserPCIState
{
85 MemoryRegion s5920_io
;
87 MemoryRegion xilinx_io
;
89 CanSJA1000State sja_state
;
92 uint32_t s5920_intcsr
;
93 uint32_t s5920_irqstate
;
98 static void kvaser_pci_irq_handler(void *opaque
, int irq_num
, int level
)
100 KvaserPCIState
*d
= (KvaserPCIState
*)opaque
;
102 d
->s5920_irqstate
= level
;
103 if (d
->s5920_intcsr
& S5920_INTCSR_ADDON_INTENABLE_M
) {
104 pci_set_irq(&d
->dev
, level
);
108 static void kvaser_pci_reset(DeviceState
*dev
)
110 KvaserPCIState
*d
= KVASER_PCI_DEV(dev
);
111 CanSJA1000State
*s
= &d
->sja_state
;
113 can_sja_hardware_reset(s
);
116 static uint64_t kvaser_pci_s5920_io_read(void *opaque
, hwaddr addr
,
119 KvaserPCIState
*d
= opaque
;
124 val
= d
->s5920_intcsr
;
125 val
&= ~S5920_INTCSR_INTERRUPT_ASSERTED_M
;
126 if (d
->s5920_irqstate
) {
127 val
|= S5920_INTCSR_INTERRUPT_ASSERTED_M
;
134 static void kvaser_pci_s5920_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
137 KvaserPCIState
*d
= opaque
;
141 if (d
->s5920_irqstate
&&
142 ((d
->s5920_intcsr
^ data
) & S5920_INTCSR_ADDON_INTENABLE_M
)) {
143 pci_set_irq(&d
->dev
, !!(data
& S5920_INTCSR_ADDON_INTENABLE_M
));
145 d
->s5920_intcsr
= data
;
150 static uint64_t kvaser_pci_sja_io_read(void *opaque
, hwaddr addr
, unsigned size
)
152 KvaserPCIState
*d
= opaque
;
153 CanSJA1000State
*s
= &d
->sja_state
;
155 if (addr
>= KVASER_PCI_BYTES_PER_SJA
) {
159 return can_sja_mem_read(s
, addr
, size
);
162 static void kvaser_pci_sja_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
165 KvaserPCIState
*d
= opaque
;
166 CanSJA1000State
*s
= &d
->sja_state
;
168 if (addr
>= KVASER_PCI_BYTES_PER_SJA
) {
172 can_sja_mem_write(s
, addr
, data
, size
);
175 static uint64_t kvaser_pci_xilinx_io_read(void *opaque
, hwaddr addr
,
179 case KVASER_PCI_XILINX_VERINT
:
180 return (KVASER_PCI_XILINX_VERSION_NUMBER
<< 4) | 0;
186 static void kvaser_pci_xilinx_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
192 static const MemoryRegionOps kvaser_pci_s5920_io_ops
= {
193 .read
= kvaser_pci_s5920_io_read
,
194 .write
= kvaser_pci_s5920_io_write
,
195 .endianness
= DEVICE_LITTLE_ENDIAN
,
197 .min_access_size
= 4,
198 .max_access_size
= 4,
202 static const MemoryRegionOps kvaser_pci_sja_io_ops
= {
203 .read
= kvaser_pci_sja_io_read
,
204 .write
= kvaser_pci_sja_io_write
,
205 .endianness
= DEVICE_LITTLE_ENDIAN
,
207 .max_access_size
= 1,
211 static const MemoryRegionOps kvaser_pci_xilinx_io_ops
= {
212 .read
= kvaser_pci_xilinx_io_read
,
213 .write
= kvaser_pci_xilinx_io_write
,
214 .endianness
= DEVICE_LITTLE_ENDIAN
,
216 .max_access_size
= 1,
220 static void kvaser_pci_realize(PCIDevice
*pci_dev
, Error
**errp
)
222 KvaserPCIState
*d
= KVASER_PCI_DEV(pci_dev
);
223 CanSJA1000State
*s
= &d
->sja_state
;
226 pci_conf
= pci_dev
->config
;
227 pci_conf
[PCI_INTERRUPT_PIN
] = 0x01; /* interrupt pin A */
229 d
->irq
= qemu_allocate_irq(kvaser_pci_irq_handler
, d
, 0);
231 can_sja_init(s
, d
->irq
);
233 if (can_sja_connect_to_bus(s
, d
->canbus
) < 0) {
234 error_setg(errp
, "can_sja_connect_to_bus failed");
238 memory_region_init_io(&d
->s5920_io
, OBJECT(d
), &kvaser_pci_s5920_io_ops
,
239 d
, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE
);
240 memory_region_init_io(&d
->sja_io
, OBJECT(d
), &kvaser_pci_sja_io_ops
,
241 d
, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE
);
242 memory_region_init_io(&d
->xilinx_io
, OBJECT(d
), &kvaser_pci_xilinx_io_ops
,
243 d
, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE
);
245 pci_register_bar(&d
->dev
, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO
,
247 pci_register_bar(&d
->dev
, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO
,
249 pci_register_bar(&d
->dev
, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO
,
253 static void kvaser_pci_exit(PCIDevice
*pci_dev
)
255 KvaserPCIState
*d
= KVASER_PCI_DEV(pci_dev
);
256 CanSJA1000State
*s
= &d
->sja_state
;
258 can_sja_disconnect(s
);
260 qemu_free_irq(d
->irq
);
263 static const VMStateDescription vmstate_kvaser_pci
= {
264 .name
= "kvaser_pci",
266 .minimum_version_id
= 1,
267 .minimum_version_id_old
= 1,
268 .fields
= (VMStateField
[]) {
269 VMSTATE_PCI_DEVICE(dev
, KvaserPCIState
),
270 /* Load this before sja_state. */
271 VMSTATE_UINT32(s5920_intcsr
, KvaserPCIState
),
272 VMSTATE_STRUCT(sja_state
, KvaserPCIState
, 0, vmstate_can_sja
,
274 VMSTATE_END_OF_LIST()
278 static void kvaser_pci_instance_init(Object
*obj
)
280 KvaserPCIState
*d
= KVASER_PCI_DEV(obj
);
282 object_property_add_link(obj
, "canbus", TYPE_CAN_BUS
,
283 (Object
**)&d
->canbus
,
284 qdev_prop_allow_set_link_before_realize
,
288 static void kvaser_pci_class_init(ObjectClass
*klass
, void *data
)
290 DeviceClass
*dc
= DEVICE_CLASS(klass
);
291 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
293 k
->realize
= kvaser_pci_realize
;
294 k
->exit
= kvaser_pci_exit
;
295 k
->vendor_id
= KVASER_PCI_VENDOR_ID1
;
296 k
->device_id
= KVASER_PCI_DEVICE_ID1
;
298 k
->class_id
= 0x00ff00;
299 dc
->desc
= "Kvaser PCICANx";
300 dc
->vmsd
= &vmstate_kvaser_pci
;
301 dc
->reset
= kvaser_pci_reset
;
302 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
305 static const TypeInfo kvaser_pci_info
= {
306 .name
= TYPE_CAN_PCI_DEV
,
307 .parent
= TYPE_PCI_DEVICE
,
308 .instance_size
= sizeof(KvaserPCIState
),
309 .class_init
= kvaser_pci_class_init
,
310 .instance_init
= kvaser_pci_instance_init
,
311 .interfaces
= (InterfaceInfo
[]) {
312 { INTERFACE_CONVENTIONAL_PCI_DEVICE
},
317 static void kvaser_pci_register_types(void)
319 type_register_static(&kvaser_pci_info
);
322 type_init(kvaser_pci_register_types
)