xref: /openbmc/qemu/hw/net/can/can_kvaser_pci.c (revision 6a0acfff)
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/hw.h"
40 #include "hw/irq.h"
41 #include "hw/pci/pci.h"
42 #include "net/can_emu.h"
43 
44 #include "can_sja1000.h"
45 
46 #define TYPE_CAN_PCI_DEV "kvaser_pci"
47 
48 #define KVASER_PCI_DEV(obj) \
49     OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
50 
51 #ifndef KVASER_PCI_VENDOR_ID1
52 #define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
53 #endif
54 
55 #ifndef KVASER_PCI_DEVICE_ID1
56 #define KVASER_PCI_DEVICE_ID1     0x8406
57 #endif
58 
59 #define KVASER_PCI_S5920_RANGE    0x80
60 #define KVASER_PCI_SJA_RANGE      0x80
61 #define KVASER_PCI_XILINX_RANGE   0x8
62 
63 #define KVASER_PCI_BYTES_PER_SJA  0x20
64 
65 #define S5920_OMB                 0x0C
66 #define S5920_IMB                 0x1C
67 #define S5920_MBEF                0x34
68 #define S5920_INTCSR              0x38
69 #define S5920_RCR                 0x3C
70 #define S5920_PTCR                0x60
71 
72 #define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
73 #define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
74 
75 #define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
76                                          high nibble version number. */
77 
78 #define KVASER_PCI_XILINX_VERSION_NUMBER 13
79 
80 typedef struct KvaserPCIState {
81     /*< private >*/
82     PCIDevice       dev;
83     /*< public >*/
84     MemoryRegion    s5920_io;
85     MemoryRegion    sja_io;
86     MemoryRegion    xilinx_io;
87 
88     CanSJA1000State sja_state;
89     qemu_irq        irq;
90 
91     uint32_t        s5920_intcsr;
92     uint32_t        s5920_irqstate;
93 
94     CanBusState     *canbus;
95 } KvaserPCIState;
96 
97 static void kvaser_pci_irq_handler(void *opaque, int irq_num, int level)
98 {
99     KvaserPCIState *d = (KvaserPCIState *)opaque;
100 
101     d->s5920_irqstate = level;
102     if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M) {
103         pci_set_irq(&d->dev, level);
104     }
105 }
106 
107 static void kvaser_pci_reset(DeviceState *dev)
108 {
109     KvaserPCIState *d = KVASER_PCI_DEV(dev);
110     CanSJA1000State *s = &d->sja_state;
111 
112     can_sja_hardware_reset(s);
113 }
114 
115 static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr,
116                                          unsigned size)
117 {
118     KvaserPCIState *d = opaque;
119     uint64_t val;
120 
121     switch (addr) {
122     case S5920_INTCSR:
123         val = d->s5920_intcsr;
124         val &= ~S5920_INTCSR_INTERRUPT_ASSERTED_M;
125         if (d->s5920_irqstate) {
126             val |= S5920_INTCSR_INTERRUPT_ASSERTED_M;
127         }
128         return val;
129     }
130     return 0;
131 }
132 
133 static void kvaser_pci_s5920_io_write(void *opaque, hwaddr addr, uint64_t data,
134                                       unsigned size)
135 {
136     KvaserPCIState *d = opaque;
137 
138     switch (addr) {
139     case S5920_INTCSR:
140         if (d->s5920_irqstate &&
141             ((d->s5920_intcsr ^ data) & S5920_INTCSR_ADDON_INTENABLE_M)) {
142             pci_set_irq(&d->dev, !!(data & S5920_INTCSR_ADDON_INTENABLE_M));
143         }
144         d->s5920_intcsr = data;
145         break;
146     }
147 }
148 
149 static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
150 {
151     KvaserPCIState *d = opaque;
152     CanSJA1000State *s = &d->sja_state;
153 
154     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
155         return 0;
156     }
157 
158     return can_sja_mem_read(s, addr, size);
159 }
160 
161 static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
162                                     unsigned size)
163 {
164     KvaserPCIState *d = opaque;
165     CanSJA1000State *s = &d->sja_state;
166 
167     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
168         return;
169     }
170 
171     can_sja_mem_write(s, addr, data, size);
172 }
173 
174 static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr,
175                                           unsigned size)
176 {
177     switch (addr) {
178     case KVASER_PCI_XILINX_VERINT:
179         return (KVASER_PCI_XILINX_VERSION_NUMBER << 4) | 0;
180     }
181 
182     return 0;
183 }
184 
185 static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
186                              unsigned size)
187 {
188 
189 }
190 
191 static const MemoryRegionOps kvaser_pci_s5920_io_ops = {
192     .read = kvaser_pci_s5920_io_read,
193     .write = kvaser_pci_s5920_io_write,
194     .endianness = DEVICE_LITTLE_ENDIAN,
195     .impl = {
196         .min_access_size = 4,
197         .max_access_size = 4,
198     },
199 };
200 
201 static const MemoryRegionOps kvaser_pci_sja_io_ops = {
202     .read = kvaser_pci_sja_io_read,
203     .write = kvaser_pci_sja_io_write,
204     .endianness = DEVICE_LITTLE_ENDIAN,
205     .impl = {
206         .max_access_size = 1,
207     },
208 };
209 
210 static const MemoryRegionOps kvaser_pci_xilinx_io_ops = {
211     .read = kvaser_pci_xilinx_io_read,
212     .write = kvaser_pci_xilinx_io_write,
213     .endianness = DEVICE_LITTLE_ENDIAN,
214     .impl = {
215         .max_access_size = 1,
216     },
217 };
218 
219 static void kvaser_pci_realize(PCIDevice *pci_dev, Error **errp)
220 {
221     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
222     CanSJA1000State *s = &d->sja_state;
223     uint8_t *pci_conf;
224 
225     pci_conf = pci_dev->config;
226     pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
227 
228     d->irq = qemu_allocate_irq(kvaser_pci_irq_handler, d, 0);
229 
230     can_sja_init(s, d->irq);
231 
232     if (can_sja_connect_to_bus(s, d->canbus) < 0) {
233         error_setg(errp, "can_sja_connect_to_bus failed");
234         return;
235     }
236 
237     memory_region_init_io(&d->s5920_io, OBJECT(d), &kvaser_pci_s5920_io_ops,
238                           d, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE);
239     memory_region_init_io(&d->sja_io, OBJECT(d), &kvaser_pci_sja_io_ops,
240                           d, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE);
241     memory_region_init_io(&d->xilinx_io, OBJECT(d), &kvaser_pci_xilinx_io_ops,
242                           d, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE);
243 
244     pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
245                                             &d->s5920_io);
246     pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
247                                             &d->sja_io);
248     pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO,
249                                             &d->xilinx_io);
250 }
251 
252 static void kvaser_pci_exit(PCIDevice *pci_dev)
253 {
254     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
255     CanSJA1000State *s = &d->sja_state;
256 
257     can_sja_disconnect(s);
258 
259     qemu_free_irq(d->irq);
260 }
261 
262 static const VMStateDescription vmstate_kvaser_pci = {
263     .name = "kvaser_pci",
264     .version_id = 1,
265     .minimum_version_id = 1,
266     .minimum_version_id_old = 1,
267     .fields = (VMStateField[]) {
268         VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
269         /* Load this before sja_state.  */
270         VMSTATE_UINT32(s5920_intcsr, KvaserPCIState),
271         VMSTATE_STRUCT(sja_state, KvaserPCIState, 0, vmstate_can_sja,
272                        CanSJA1000State),
273         VMSTATE_END_OF_LIST()
274     }
275 };
276 
277 static void kvaser_pci_instance_init(Object *obj)
278 {
279     KvaserPCIState *d = KVASER_PCI_DEV(obj);
280 
281     object_property_add_link(obj, "canbus", TYPE_CAN_BUS,
282                              (Object **)&d->canbus,
283                              qdev_prop_allow_set_link_before_realize,
284                              0, &error_abort);
285 }
286 
287 static void kvaser_pci_class_init(ObjectClass *klass, void *data)
288 {
289     DeviceClass *dc = DEVICE_CLASS(klass);
290     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
291 
292     k->realize = kvaser_pci_realize;
293     k->exit = kvaser_pci_exit;
294     k->vendor_id = KVASER_PCI_VENDOR_ID1;
295     k->device_id = KVASER_PCI_DEVICE_ID1;
296     k->revision = 0x00;
297     k->class_id = 0x00ff00;
298     dc->desc = "Kvaser PCICANx";
299     dc->vmsd = &vmstate_kvaser_pci;
300     dc->reset = kvaser_pci_reset;
301     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
302 }
303 
304 static const TypeInfo kvaser_pci_info = {
305     .name          = TYPE_CAN_PCI_DEV,
306     .parent        = TYPE_PCI_DEVICE,
307     .instance_size = sizeof(KvaserPCIState),
308     .class_init    = kvaser_pci_class_init,
309     .instance_init = kvaser_pci_instance_init,
310     .interfaces = (InterfaceInfo[]) {
311         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
312         { },
313     },
314 };
315 
316 static void kvaser_pci_register_types(void)
317 {
318     type_register_static(&kvaser_pci_info);
319 }
320 
321 type_init(kvaser_pci_register_types)
322