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_device.h"
41 #include "hw/qdev-properties.h"
42 #include "migration/vmstate.h"
43 #include "net/can_emu.h"
45 #include "can_sja1000.h"
46 #include "qom/object.h"
48 #define TYPE_CAN_PCI_DEV "kvaser_pci"
50 typedef struct KvaserPCIState KvaserPCIState
;
51 DECLARE_INSTANCE_CHECKER(KvaserPCIState
, KVASER_PCI_DEV
,
54 #ifndef KVASER_PCI_VENDOR_ID1
55 #define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */
58 #ifndef KVASER_PCI_DEVICE_ID1
59 #define KVASER_PCI_DEVICE_ID1 0x8406
62 #define KVASER_PCI_S5920_RANGE 0x80
63 #define KVASER_PCI_SJA_RANGE 0x80
64 #define KVASER_PCI_XILINX_RANGE 0x8
66 #define KVASER_PCI_BYTES_PER_SJA 0x20
68 #define S5920_OMB 0x0C
69 #define S5920_IMB 0x1C
70 #define S5920_MBEF 0x34
71 #define S5920_INTCSR 0x38
72 #define S5920_RCR 0x3C
73 #define S5920_PTCR 0x60
75 #define S5920_INTCSR_ADDON_INTENABLE_M 0x2000
76 #define S5920_INTCSR_INTERRUPT_ASSERTED_M 0x800000
78 #define KVASER_PCI_XILINX_VERINT 7 /* Lower nibble simulate interrupts,
79 high nibble version number. */
81 #define KVASER_PCI_XILINX_VERSION_NUMBER 13
83 struct KvaserPCIState
{
87 MemoryRegion s5920_io
;
89 MemoryRegion xilinx_io
;
91 CanSJA1000State sja_state
;
94 uint32_t s5920_intcsr
;
95 uint32_t s5920_irqstate
;
100 static void kvaser_pci_irq_handler(void *opaque
, int irq_num
, int level
)
102 KvaserPCIState
*d
= (KvaserPCIState
*)opaque
;
104 d
->s5920_irqstate
= level
;
105 if (d
->s5920_intcsr
& S5920_INTCSR_ADDON_INTENABLE_M
) {
106 pci_set_irq(&d
->dev
, level
);
110 static void kvaser_pci_reset(DeviceState
*dev
)
112 KvaserPCIState
*d
= KVASER_PCI_DEV(dev
);
113 CanSJA1000State
*s
= &d
->sja_state
;
115 can_sja_hardware_reset(s
);
118 static uint64_t kvaser_pci_s5920_io_read(void *opaque
, hwaddr addr
,
121 KvaserPCIState
*d
= opaque
;
126 val
= d
->s5920_intcsr
;
127 val
&= ~S5920_INTCSR_INTERRUPT_ASSERTED_M
;
128 if (d
->s5920_irqstate
) {
129 val
|= S5920_INTCSR_INTERRUPT_ASSERTED_M
;
136 static void kvaser_pci_s5920_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
139 KvaserPCIState
*d
= opaque
;
143 if (d
->s5920_irqstate
&&
144 ((d
->s5920_intcsr
^ data
) & S5920_INTCSR_ADDON_INTENABLE_M
)) {
145 pci_set_irq(&d
->dev
, !!(data
& S5920_INTCSR_ADDON_INTENABLE_M
));
147 d
->s5920_intcsr
= data
;
152 static uint64_t kvaser_pci_sja_io_read(void *opaque
, hwaddr addr
, unsigned size
)
154 KvaserPCIState
*d
= opaque
;
155 CanSJA1000State
*s
= &d
->sja_state
;
157 if (addr
>= KVASER_PCI_BYTES_PER_SJA
) {
161 return can_sja_mem_read(s
, addr
, size
);
164 static void kvaser_pci_sja_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
167 KvaserPCIState
*d
= opaque
;
168 CanSJA1000State
*s
= &d
->sja_state
;
170 if (addr
>= KVASER_PCI_BYTES_PER_SJA
) {
174 can_sja_mem_write(s
, addr
, data
, size
);
177 static uint64_t kvaser_pci_xilinx_io_read(void *opaque
, hwaddr addr
,
181 case KVASER_PCI_XILINX_VERINT
:
182 return (KVASER_PCI_XILINX_VERSION_NUMBER
<< 4) | 0;
188 static void kvaser_pci_xilinx_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
194 static const MemoryRegionOps kvaser_pci_s5920_io_ops
= {
195 .read
= kvaser_pci_s5920_io_read
,
196 .write
= kvaser_pci_s5920_io_write
,
197 .endianness
= DEVICE_LITTLE_ENDIAN
,
199 .min_access_size
= 4,
200 .max_access_size
= 4,
204 static const MemoryRegionOps kvaser_pci_sja_io_ops
= {
205 .read
= kvaser_pci_sja_io_read
,
206 .write
= kvaser_pci_sja_io_write
,
207 .endianness
= DEVICE_LITTLE_ENDIAN
,
209 .max_access_size
= 1,
213 static const MemoryRegionOps kvaser_pci_xilinx_io_ops
= {
214 .read
= kvaser_pci_xilinx_io_read
,
215 .write
= kvaser_pci_xilinx_io_write
,
216 .endianness
= DEVICE_LITTLE_ENDIAN
,
218 .max_access_size
= 1,
222 static void kvaser_pci_realize(PCIDevice
*pci_dev
, Error
**errp
)
224 KvaserPCIState
*d
= KVASER_PCI_DEV(pci_dev
);
225 CanSJA1000State
*s
= &d
->sja_state
;
228 pci_conf
= pci_dev
->config
;
229 pci_conf
[PCI_INTERRUPT_PIN
] = 0x01; /* interrupt pin A */
231 d
->irq
= qemu_allocate_irq(kvaser_pci_irq_handler
, d
, 0);
233 can_sja_init(s
, d
->irq
);
235 if (can_sja_connect_to_bus(s
, d
->canbus
) < 0) {
236 error_setg(errp
, "can_sja_connect_to_bus failed");
240 memory_region_init_io(&d
->s5920_io
, OBJECT(d
), &kvaser_pci_s5920_io_ops
,
241 d
, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE
);
242 memory_region_init_io(&d
->sja_io
, OBJECT(d
), &kvaser_pci_sja_io_ops
,
243 d
, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE
);
244 memory_region_init_io(&d
->xilinx_io
, OBJECT(d
), &kvaser_pci_xilinx_io_ops
,
245 d
, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE
);
247 pci_register_bar(&d
->dev
, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO
,
249 pci_register_bar(&d
->dev
, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO
,
251 pci_register_bar(&d
->dev
, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO
,
255 static void kvaser_pci_exit(PCIDevice
*pci_dev
)
257 KvaserPCIState
*d
= KVASER_PCI_DEV(pci_dev
);
258 CanSJA1000State
*s
= &d
->sja_state
;
260 can_sja_disconnect(s
);
262 qemu_free_irq(d
->irq
);
265 static const VMStateDescription vmstate_kvaser_pci
= {
266 .name
= "kvaser_pci",
268 .minimum_version_id
= 1,
269 .fields
= (const VMStateField
[]) {
270 VMSTATE_PCI_DEVICE(dev
, KvaserPCIState
),
271 /* Load this before sja_state. */
272 VMSTATE_UINT32(s5920_intcsr
, KvaserPCIState
),
273 VMSTATE_STRUCT(sja_state
, KvaserPCIState
, 0, vmstate_can_sja
,
275 VMSTATE_END_OF_LIST()
279 static void kvaser_pci_instance_init(Object
*obj
)
281 KvaserPCIState
*d
= KVASER_PCI_DEV(obj
);
283 object_property_add_link(obj
, "canbus", TYPE_CAN_BUS
,
284 (Object
**)&d
->canbus
,
285 qdev_prop_allow_set_link_before_realize
,
289 static void kvaser_pci_class_init(ObjectClass
*klass
, void *data
)
291 DeviceClass
*dc
= DEVICE_CLASS(klass
);
292 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
294 k
->realize
= kvaser_pci_realize
;
295 k
->exit
= kvaser_pci_exit
;
296 k
->vendor_id
= KVASER_PCI_VENDOR_ID1
;
297 k
->device_id
= KVASER_PCI_DEVICE_ID1
;
299 k
->class_id
= 0x00ff00;
300 dc
->desc
= "Kvaser PCICANx";
301 dc
->vmsd
= &vmstate_kvaser_pci
;
302 device_class_set_legacy_reset(dc
, kvaser_pci_reset
);
303 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
306 static const TypeInfo kvaser_pci_info
= {
307 .name
= TYPE_CAN_PCI_DEV
,
308 .parent
= TYPE_PCI_DEVICE
,
309 .instance_size
= sizeof(KvaserPCIState
),
310 .class_init
= kvaser_pci_class_init
,
311 .instance_init
= kvaser_pci_instance_init
,
312 .interfaces
= (InterfaceInfo
[]) {
313 { INTERFACE_CONVENTIONAL_PCI_DEVICE
},
318 static void kvaser_pci_register_types(void)
320 type_register_static(&kvaser_pci_info
);
323 type_init(kvaser_pci_register_types
)