2 * CTU CAN FD PCI device emulation
3 * http://canbus.pages.fel.cvut.cz/
5 * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com)
7 * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
8 * Jin Yang and Pavel Pisa
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include "qemu/osdep.h"
30 #include "qemu/event_notifier.h"
31 #include "qemu/module.h"
32 #include "qemu/thread.h"
33 #include "qemu/sockets.h"
34 #include "qapi/error.h"
35 #include "chardev/char.h"
37 #include "hw/pci/pci_device.h"
38 #include "hw/qdev-properties.h"
39 #include "migration/vmstate.h"
40 #include "net/can_emu.h"
42 #include "ctucan_core.h"
44 #define TYPE_CTUCAN_PCI_DEV "ctucan_pci"
46 typedef struct CtuCanPCIState CtuCanPCIState
;
47 DECLARE_INSTANCE_CHECKER(CtuCanPCIState
, CTUCAN_PCI_DEV
,
50 #define CTUCAN_PCI_CORE_COUNT 2
51 #define CTUCAN_PCI_CORE_RANGE 0x10000
53 #define CTUCAN_PCI_BAR_COUNT 2
55 #define CTUCAN_PCI_BYTES_PER_CORE 0x4000
57 #ifndef PCI_VENDOR_ID_TEDIA
58 #define PCI_VENDOR_ID_TEDIA 0x1760
61 #define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
63 #define CTUCAN_BAR0_RANGE 0x8000
64 #define CTUCAN_BAR0_CTUCAN_ID 0x0000
65 #define CTUCAN_BAR0_CRA_BASE 0x4000
66 #define CYCLONE_IV_CRA_A2P_IE (0x0050)
68 #define CTUCAN_WITHOUT_CTUCAN_ID 0
69 #define CTUCAN_WITH_CTUCAN_ID 1
71 struct CtuCanPCIState
{
75 MemoryRegion ctucan_io
[CTUCAN_PCI_BAR_COUNT
];
77 CtuCanCoreState ctucan_state
[CTUCAN_PCI_CORE_COUNT
];
80 char *model
; /* The model that support, only SJA1000 now. */
81 CanBusState
*canbus
[CTUCAN_PCI_CORE_COUNT
];
84 static void ctucan_pci_reset(DeviceState
*dev
)
86 CtuCanPCIState
*d
= CTUCAN_PCI_DEV(dev
);
89 for (i
= 0 ; i
< CTUCAN_PCI_CORE_COUNT
; i
++) {
90 ctucan_hardware_reset(&d
->ctucan_state
[i
]);
94 static uint64_t ctucan_pci_id_cra_io_read(void *opaque
, hwaddr addr
,
101 uint64_t tmp
= 0xC0000000 + CTUCAN_PCI_CORE_COUNT
;
102 tmp
>>= ((addr
& 3) << 3);
104 tmp
&= ((uint64_t)1 << (size
<< 3)) - 1;
109 static void ctucan_pci_id_cra_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
115 static uint64_t ctucan_pci_cores_io_read(void *opaque
, hwaddr addr
,
118 CtuCanPCIState
*d
= opaque
;
120 hwaddr core_num
= addr
/ CTUCAN_PCI_BYTES_PER_CORE
;
122 if (core_num
>= CTUCAN_PCI_CORE_COUNT
) {
126 s
= &d
->ctucan_state
[core_num
];
128 return ctucan_mem_read(s
, addr
% CTUCAN_PCI_BYTES_PER_CORE
, size
);
131 static void ctucan_pci_cores_io_write(void *opaque
, hwaddr addr
, uint64_t data
,
134 CtuCanPCIState
*d
= opaque
;
136 hwaddr core_num
= addr
/ CTUCAN_PCI_BYTES_PER_CORE
;
138 if (core_num
>= CTUCAN_PCI_CORE_COUNT
) {
142 s
= &d
->ctucan_state
[core_num
];
144 return ctucan_mem_write(s
, addr
% CTUCAN_PCI_BYTES_PER_CORE
, data
, size
);
147 static const MemoryRegionOps ctucan_pci_id_cra_io_ops
= {
148 .read
= ctucan_pci_id_cra_io_read
,
149 .write
= ctucan_pci_id_cra_io_write
,
150 .endianness
= DEVICE_LITTLE_ENDIAN
,
151 .impl
.min_access_size
= 1,
152 .impl
.max_access_size
= 4,
153 .valid
.min_access_size
= 1,
154 .valid
.max_access_size
= 4,
157 static const MemoryRegionOps ctucan_pci_cores_io_ops
= {
158 .read
= ctucan_pci_cores_io_read
,
159 .write
= ctucan_pci_cores_io_write
,
160 .endianness
= DEVICE_LITTLE_ENDIAN
,
161 .impl
.min_access_size
= 1,
162 .impl
.max_access_size
= 4,
163 .valid
.min_access_size
= 1,
164 .valid
.max_access_size
= 4,
167 static void ctucan_pci_realize(PCIDevice
*pci_dev
, Error
**errp
)
169 CtuCanPCIState
*d
= CTUCAN_PCI_DEV(pci_dev
);
173 pci_conf
= pci_dev
->config
;
174 pci_conf
[PCI_INTERRUPT_PIN
] = 0x01; /* interrupt pin A */
176 d
->irq
= pci_allocate_irq(&d
->dev
);
178 for (i
= 0 ; i
< CTUCAN_PCI_CORE_COUNT
; i
++) {
179 ctucan_init(&d
->ctucan_state
[i
], d
->irq
);
182 for (i
= 0 ; i
< CTUCAN_PCI_CORE_COUNT
; i
++) {
183 if (ctucan_connect_to_bus(&d
->ctucan_state
[i
], d
->canbus
[i
]) < 0) {
184 error_setg(errp
, "ctucan_connect_to_bus failed");
189 memory_region_init_io(&d
->ctucan_io
[0], OBJECT(d
),
190 &ctucan_pci_id_cra_io_ops
, d
,
191 "ctucan_pci-core0", CTUCAN_BAR0_RANGE
);
192 memory_region_init_io(&d
->ctucan_io
[1], OBJECT(d
),
193 &ctucan_pci_cores_io_ops
, d
,
194 "ctucan_pci-core1", CTUCAN_PCI_CORE_RANGE
);
196 for (i
= 0 ; i
< CTUCAN_PCI_BAR_COUNT
; i
++) {
197 pci_register_bar(&d
->dev
, i
, PCI_BASE_ADDRESS_MEM_MASK
& 0,
202 static void ctucan_pci_exit(PCIDevice
*pci_dev
)
204 CtuCanPCIState
*d
= CTUCAN_PCI_DEV(pci_dev
);
207 for (i
= 0 ; i
< CTUCAN_PCI_CORE_COUNT
; i
++) {
208 ctucan_disconnect(&d
->ctucan_state
[i
]);
211 qemu_free_irq(d
->irq
);
214 static const VMStateDescription vmstate_ctucan_pci
= {
215 .name
= "ctucan_pci",
217 .minimum_version_id
= 1,
218 .fields
= (const VMStateField
[]) {
219 VMSTATE_PCI_DEVICE(dev
, CtuCanPCIState
),
220 VMSTATE_STRUCT(ctucan_state
[0], CtuCanPCIState
, 0, vmstate_ctucan
,
222 #if CTUCAN_PCI_CORE_COUNT >= 2
223 VMSTATE_STRUCT(ctucan_state
[1], CtuCanPCIState
, 0, vmstate_ctucan
,
226 VMSTATE_END_OF_LIST()
230 static void ctucan_pci_instance_init(Object
*obj
)
232 CtuCanPCIState
*d
= CTUCAN_PCI_DEV(obj
);
234 object_property_add_link(obj
, "canbus0", TYPE_CAN_BUS
,
235 (Object
**)&d
->canbus
[0],
236 qdev_prop_allow_set_link_before_realize
, 0);
237 #if CTUCAN_PCI_CORE_COUNT >= 2
238 object_property_add_link(obj
, "canbus1", TYPE_CAN_BUS
,
239 (Object
**)&d
->canbus
[1],
240 qdev_prop_allow_set_link_before_realize
, 0);
244 static void ctucan_pci_class_init(ObjectClass
*klass
, void *data
)
246 DeviceClass
*dc
= DEVICE_CLASS(klass
);
247 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
249 k
->realize
= ctucan_pci_realize
;
250 k
->exit
= ctucan_pci_exit
;
251 k
->vendor_id
= PCI_VENDOR_ID_TEDIA
;
252 k
->device_id
= PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
;
254 k
->class_id
= 0x000c09;
255 k
->subsystem_vendor_id
= PCI_VENDOR_ID_TEDIA
;
256 k
->subsystem_id
= PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
;
257 dc
->desc
= "CTU CAN PCI";
258 dc
->vmsd
= &vmstate_ctucan_pci
;
259 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
260 device_class_set_legacy_reset(dc
, ctucan_pci_reset
);
263 static const TypeInfo ctucan_pci_info
= {
264 .name
= TYPE_CTUCAN_PCI_DEV
,
265 .parent
= TYPE_PCI_DEVICE
,
266 .instance_size
= sizeof(CtuCanPCIState
),
267 .class_init
= ctucan_pci_class_init
,
268 .instance_init
= ctucan_pci_instance_init
,
269 .interfaces
= (InterfaceInfo
[]) {
270 { INTERFACE_CONVENTIONAL_PCI_DEVICE
},
275 static void ctucan_pci_register_types(void)
277 type_register_static(&ctucan_pci_info
);
280 type_init(ctucan_pci_register_types
)