]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - hw/can/can_kvaser_pci.c
CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
[lisovros/qemu_apohw.git] / hw / can / can_kvaser_pci.c
1 /*
2  * Kvaser PCI CAN device (SJA1000 based) emulation
3  *
4  * Copyright (c) 2013-2014 Jin Yang
5  * Copyright (c) 2014 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 "hw/hw.h"
33 #include "hw/pci/pci.h"
34 #include "qemu/event_notifier.h"
35 #include "qemu/osdep.h"
36 #include "qemu/thread.h"
37 #include "qemu/sockets.h"
38 #include "sysemu/char.h"
39 #include "can/can_emu.h"
40
41 #include "can_sja1000.h"
42
43 #define TYPE_CAN_PCI_DEV "kvaser_pci"
44
45 #define KVASER_PCI_DEV(obj) \
46     OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
47
48 #ifndef KVASER_PCI_VENDOR_ID1
49 #define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
50 #endif
51
52 #ifndef KVASER_PCI_DEVICE_ID1
53 #define KVASER_PCI_DEVICE_ID1     0x8406
54 #endif
55
56 #define KVASER_PCI_S5920_RANGE    0x80
57 #define KVASER_PCI_SJA_RANGE      0x80
58 #define KVASER_PCI_XILINX_RANGE   0x8
59
60 #define KVASER_PCI_BYTES_PER_SJA  0x20
61
62 #define S5920_OMB                 0x0C
63 #define S5920_IMB                 0x1C
64 #define S5920_MBEF                0x34
65 #define S5920_INTCSR              0x38
66 #define S5920_RCR                 0x3C
67 #define S5920_PTCR                0x60
68
69 #define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
70 #define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
71
72 #define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
73                                          high nibble version number. */
74
75 typedef struct KvaserPCIState {
76     /*< private >*/
77     PCIDevice       dev;
78     /*< public >*/
79     MemoryRegion    s5920_io;
80     MemoryRegion    sja_io;
81     MemoryRegion    xilinx_io;
82
83     CanSJA1000State sja_state;
84     qemu_irq        irq;
85
86     uint32_t        s5920_intcsr;
87     uint32_t        s5920_irqstate;
88
89     char            *model; /* The model that support, only SJA1000 now. */
90     char            *canbus;
91     char            *host;
92 } KvaserPCIState;
93
94 static void kvaser_pci_irq_raise(void *opaque)
95 {
96     KvaserPCIState *d = (KvaserPCIState *)opaque;
97     d->s5920_irqstate = 1;
98
99     if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M)
100         qemu_irq_raise(d->irq);
101 }
102
103 static void kvaser_pci_irq_lower(void *opaque)
104 {
105     KvaserPCIState *d = (KvaserPCIState *)opaque;
106     d->s5920_irqstate = 0;
107     qemu_irq_lower(d->irq);
108 }
109
110 static void
111 kvaser_pci_reset(void *opaque)
112 {
113     KvaserPCIState *d = (KvaserPCIState *)opaque;
114     CanSJA1000State *s = &d->sja_state;
115
116     can_sja_hardware_reset(s);
117 }
118
119 static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr, 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_intcsr & data & S5920_INTCSR_ADDON_INTENABLE_M) {
144             if (d->s5920_irqstate) {
145                 qemu_irq_raise(d->irq);
146             }
147         }
148         d->s5920_intcsr = data;
149         break;
150     }
151 }
152
153 static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
154 {
155     KvaserPCIState *d = opaque;
156     CanSJA1000State *s = &d->sja_state;
157
158     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
159         return 0;
160     }
161
162     return can_sja_mem_read(s, addr, size);
163 }
164
165 static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
166                              unsigned size)
167 {
168     KvaserPCIState *d = opaque;
169     CanSJA1000State *s = &d->sja_state;
170
171     if (addr >= KVASER_PCI_BYTES_PER_SJA) {
172         return;
173     }
174
175     can_sja_mem_write(s, addr, data, size);
176 }
177
178 static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr, unsigned size)
179 {
180     /*KvaserPCIState *d = opaque;*/
181
182     switch (addr) {
183     case KVASER_PCI_XILINX_VERINT:
184         return (13 << 4) | 0;
185     }
186
187     return 0;
188 }
189
190 static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
191                              unsigned size)
192 {
193     /*KvaserPCIState *d = opaque;*/
194 }
195
196 static const MemoryRegionOps kvaser_pci_s5920_io_ops = {
197     .read = kvaser_pci_s5920_io_read,
198     .write = kvaser_pci_s5920_io_write,
199     .endianness = DEVICE_LITTLE_ENDIAN,
200     .impl = {
201         .min_access_size = 4,
202         .max_access_size = 4,
203     },
204 };
205
206 static const MemoryRegionOps kvaser_pci_sja_io_ops = {
207     .read = kvaser_pci_sja_io_read,
208     .write = kvaser_pci_sja_io_write,
209     .endianness = DEVICE_LITTLE_ENDIAN,
210     .impl = {
211         .min_access_size = 1,
212         .max_access_size = 1,
213     },
214 };
215
216 static const MemoryRegionOps kvaser_pci_xilinx_io_ops = {
217     .read = kvaser_pci_xilinx_io_read,
218     .write = kvaser_pci_xilinx_io_write,
219     .endianness = DEVICE_LITTLE_ENDIAN,
220     .impl = {
221         .min_access_size = 1,
222         .max_access_size = 1,
223     },
224 };
225
226 static int kvaser_pci_init(PCIDevice *pci_dev)
227 {
228     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
229     CanSJA1000State *s = &d->sja_state;
230     uint8_t *pci_conf;
231     CanBusState *can_bus;
232
233     if (d->model) {
234         if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
235             qerror_report(ERROR_CLASS_GENERIC_ERROR,
236                 "Can't create CAN device, the model %s is not supported now.\n",
237                 d->model);
238             exit(1);
239         }
240     }
241
242     can_bus = can_bus_find_by_name(d->canbus, true);
243     if (can_bus == NULL) {
244         qerror_report(ERROR_CLASS_GENERIC_ERROR, "Cannot create can find/allocate CAN bus\n");
245         exit(1);
246
247     }
248
249     if (d->host != NULL) {
250         if (can_bus_connect_to_host_device(can_bus, d->host) < 0) {
251             qerror_report(ERROR_CLASS_GENERIC_ERROR, "Cannot connect CAN bus to host device \"%s\"\n", d->host);
252             exit(1);
253         }
254     }
255
256     pci_conf = pci_dev->config;
257     pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
258
259     d->irq = pci_allocate_irq(&d->dev);
260
261     can_sja_init(s, kvaser_pci_irq_raise, kvaser_pci_irq_lower, d);
262
263     qemu_register_reset(kvaser_pci_reset, d);
264
265     if (can_sja_connect_to_bus(s, can_bus) < 0) {
266         qerror_report(ERROR_CLASS_GENERIC_ERROR,
267               "can_sja_connect_to_bus failed\n");
268         exit(1);
269     }
270
271     memory_region_init_io(&d->s5920_io, OBJECT(d), &kvaser_pci_s5920_io_ops, d,
272                           "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE);
273     memory_region_init_io(&d->sja_io, OBJECT(d), &kvaser_pci_sja_io_ops, d,
274                           "kvaser_pci-sja", KVASER_PCI_SJA_RANGE);
275     memory_region_init_io(&d->xilinx_io, OBJECT(d), &kvaser_pci_xilinx_io_ops, d,
276                           "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE);
277
278     pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO, &d->s5920_io);
279     pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO, &d->sja_io);
280     pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO, &d->xilinx_io);
281
282     return 0;
283 }
284
285 static void kvaser_pci_exit(PCIDevice *pci_dev)
286 {
287     KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
288     CanSJA1000State *s = &d->sja_state;
289
290     can_sja_disconnect(s);
291
292     qemu_unregister_reset(kvaser_pci_reset, d);
293
294     /* 
295      * regions d->s5920_io, d->sja_io and d->xilinx_io
296      * are destroyed by QOM now
297      */
298     /* memory_region_destroy(&d->s5920_io); */
299     /* memory_region_destroy(&d->sja_io); */
300     /* memory_region_destroy(&d->xilinx_io); */
301
302     can_sja_exit(s);
303
304     qemu_free_irq(d->irq);
305 }
306
307 static const VMStateDescription vmstate_kvaser_pci = {
308     .name = "kvaser_pci",
309     .version_id = 1,
310     .minimum_version_id = 1,
311     .minimum_version_id_old = 1,
312     .fields = (VMStateField[]) {
313         VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
314         VMSTATE_STRUCT(sja_state, KvaserPCIState, 0, vmstate_can_sja, CanSJA1000State),
315         /*char *model,*/
316         VMSTATE_UINT32(s5920_intcsr, KvaserPCIState),
317         VMSTATE_UINT32(s5920_irqstate, KvaserPCIState),
318         VMSTATE_END_OF_LIST()
319     }
320 };
321
322 static void qdev_kvaser_pci_reset(DeviceState *dev)
323 {
324     KvaserPCIState *d = KVASER_PCI_DEV(dev);
325     kvaser_pci_reset(d);
326 }
327
328 static Property kvaser_pci_properties[] = {
329     DEFINE_PROP_STRING("canbus",   KvaserPCIState, canbus),
330     DEFINE_PROP_STRING("host",  KvaserPCIState, host),
331     DEFINE_PROP_STRING("model", KvaserPCIState, model),
332     DEFINE_PROP_END_OF_LIST(),
333 };
334
335 static void kvaser_pci_class_init(ObjectClass *klass, void *data)
336 {
337     DeviceClass *dc = DEVICE_CLASS(klass);
338     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
339
340     k->init = kvaser_pci_init;
341     k->exit = kvaser_pci_exit;
342     k->vendor_id = KVASER_PCI_VENDOR_ID1;
343     k->device_id = KVASER_PCI_DEVICE_ID1;
344     k->revision = 0x00;
345     k->class_id = 0x00ff00;
346     dc->desc = "Kvaser PCICANx";
347     dc->props = kvaser_pci_properties;
348     dc->vmsd = &vmstate_kvaser_pci;
349     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
350     dc->reset = qdev_kvaser_pci_reset;
351 }
352
353 static const TypeInfo kvaser_pci_info = {
354     .name          = TYPE_CAN_PCI_DEV,
355     .parent        = TYPE_PCI_DEVICE,
356     .instance_size = sizeof(KvaserPCIState),
357     .class_init    = kvaser_pci_class_init,
358 };
359
360 static void kvaser_pci_register_types(void)
361 {
362     type_register_static(&kvaser_pci_info);
363 }
364
365 type_init(kvaser_pci_register_types)