xref: /openbmc/qemu/hw/net/can/can_kvaser_pci.c (revision 6c3a9247)
1 /*
2  * Kvaser PCI CAN device (SJA1000 based) emulation
3  *
4  * Copyright (c) 2013-2014 Jin Yang
5  * Copyright (c) 2014-2018 Pavel Pisa
6  *
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
10  *
11  * Initial development supported by Google GSoC 2013 from RTEMS project slot
12  *
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:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
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
29  * THE SOFTWARE.
30  */
31 
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"
39 #include "hw/irq.h"
40 #include "hw/pci/pci.h"
41 #include "hw/qdev-properties.h"
42 #include "migration/vmstate.h"
43 #include "net/can_emu.h"
44 
45 #include "can_sja1000.h"
46 #include "qom/object.h"
47 
48 #define TYPE_CAN_PCI_DEV "kvaser_pci"
49 
50 typedef struct KvaserPCIState KvaserPCIState;
51 DECLARE_INSTANCE_CHECKER(KvaserPCIState, KVASER_PCI_DEV,
52                          TYPE_CAN_PCI_DEV)
53 
54 #ifndef KVASER_PCI_VENDOR_ID1
55 #define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
56 #endif
57 
58 #ifndef KVASER_PCI_DEVICE_ID1
59 #define KVASER_PCI_DEVICE_ID1     0x8406
60 #endif
61 
62 #define KVASER_PCI_S5920_RANGE    0x80
63 #define KVASER_PCI_SJA_RANGE      0x80
64 #define KVASER_PCI_XILINX_RANGE   0x8
65 
66 #define KVASER_PCI_BYTES_PER_SJA  0x20
67 
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
74 
75 #define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
76 #define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
77 
78 #define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
79                                          high nibble version number. */
80 
81 #define KVASER_PCI_XILINX_VERSION_NUMBER 13
82 
83 struct KvaserPCIState {
84     /*< private >*/
85     PCIDevice       dev;
86     /*< public >*/
87     MemoryRegion    s5920_io;
88     MemoryRegion    sja_io;
89     MemoryRegion    xilinx_io;
90 
91     CanSJA1000State sja_state;
92     qemu_irq        irq;
93 
94     uint32_t        s5920_intcsr;
95     uint32_t        s5920_irqstate;
96 
97     CanBusState     *canbus;
98 };
99 
100 static void kvaser_pci_irq_handler(void *opaque, int irq_num, int level)
101 {
102     KvaserPCIState *d = (KvaserPCIState *)opaque;
103 
104     d->s5920_irqstate = level;
105     if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M) {
106         pci_set_irq(&d->dev, level);
107     }
108 }
109 
110 static void kvaser_pci_reset(DeviceState *dev)
111 {
112     KvaserPCIState *d = KVASER_PCI_DEV(dev);
113     CanSJA1000State *s = &d->sja_state;
114 
115     can_sja_hardware_reset(s);
116 }
117 
118 static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr,
119                                          unsigned size)
120 {
121     KvaserPCIState *d = opaque;
122     uint64_t val;
123 
124     switch (addr) {
125     case S5920_INTCSR:
126         val = d->s5920_intcsr;
127         val &= ~S5920_INTCSR_INTERRUPT_ASSERTED_M;
128         if (d->s5920_irqstate) {
129             val |= S5920_INTCSR_INTERRUPT_ASSERTED_M;
130         }
131         return val;
132     }
133     return 0;
134 }
135 
136 static void kvaser_pci_s5920_io_write(void *opaque, hwaddr addr, uint64_t data,
137                                       unsigned size)
138 {
139     KvaserPCIState *d = opaque;
140 
141     switch (addr) {
142     case S5920_INTCSR:
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));
146         }
147         d->s5920_intcsr = data;
148         break;
149     }
150 }
151 
152 static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
153 {
154     KvaserPCIState *d = opaque;
155     CanSJA1000State *s = &d->sja_state;
156 
157     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
158         return 0;
159     }
160 
161     return can_sja_mem_read(s, addr, size);
162 }
163 
164 static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
165                                     unsigned size)
166 {
167     KvaserPCIState *d = opaque;
168     CanSJA1000State *s = &d->sja_state;
169 
170     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
171         return;
172     }
173 
174     can_sja_mem_write(s, addr, data, size);
175 }
176 
177 static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr,
178                                           unsigned size)
179 {
180     switch (addr) {
181     case KVASER_PCI_XILINX_VERINT:
182         return (KVASER_PCI_XILINX_VERSION_NUMBER << 4) | 0;
183     }
184 
185     return 0;
186 }
187 
188 static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
189                              unsigned size)
190 {
191 
192 }
193 
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,
198     .impl = {
199         .min_access_size = 4,
200         .max_access_size = 4,
201     },
202 };
203 
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,
208     .impl = {
209         .max_access_size = 1,
210     },
211 };
212 
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,
217     .impl = {
218         .max_access_size = 1,
219     },
220 };
221 
222 static void kvaser_pci_realize(PCIDevice *pci_dev, Error **errp)
223 {
224     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
225     CanSJA1000State *s = &d->sja_state;
226     uint8_t *pci_conf;
227 
228     pci_conf = pci_dev->config;
229     pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
230 
231     d->irq = qemu_allocate_irq(kvaser_pci_irq_handler, d, 0);
232 
233     can_sja_init(s, d->irq);
234 
235     if (can_sja_connect_to_bus(s, d->canbus) < 0) {
236         error_setg(errp, "can_sja_connect_to_bus failed");
237         return;
238     }
239 
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);
246 
247     pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
248                                             &d->s5920_io);
249     pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
250                                             &d->sja_io);
251     pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO,
252                                             &d->xilinx_io);
253 }
254 
255 static void kvaser_pci_exit(PCIDevice *pci_dev)
256 {
257     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
258     CanSJA1000State *s = &d->sja_state;
259 
260     can_sja_disconnect(s);
261 
262     qemu_free_irq(d->irq);
263 }
264 
265 static const VMStateDescription vmstate_kvaser_pci = {
266     .name = "kvaser_pci",
267     .version_id = 1,
268     .minimum_version_id = 1,
269     .fields = (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,
274                        CanSJA1000State),
275         VMSTATE_END_OF_LIST()
276     }
277 };
278 
279 static void kvaser_pci_instance_init(Object *obj)
280 {
281     KvaserPCIState *d = KVASER_PCI_DEV(obj);
282 
283     object_property_add_link(obj, "canbus", TYPE_CAN_BUS,
284                              (Object **)&d->canbus,
285                              qdev_prop_allow_set_link_before_realize,
286                              0);
287 }
288 
289 static void kvaser_pci_class_init(ObjectClass *klass, void *data)
290 {
291     DeviceClass *dc = DEVICE_CLASS(klass);
292     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
293 
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;
298     k->revision = 0x00;
299     k->class_id = 0x00ff00;
300     dc->desc = "Kvaser PCICANx";
301     dc->vmsd = &vmstate_kvaser_pci;
302     dc->reset = kvaser_pci_reset;
303     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
304 }
305 
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 },
314         { },
315     },
316 };
317 
318 static void kvaser_pci_register_types(void)
319 {
320     type_register_static(&kvaser_pci_info);
321 }
322 
323 type_init(kvaser_pci_register_types)
324