]>
Commit | Line | Data |
---|---|---|
733210e7 PP |
1 | /* |
2 | * CAN device - SJA1000 chip emulation for QEMU | |
3 | * | |
4 | * Copyright (c) 2013-2014 Jin Yang | |
5 | * Copyright (c) 2014-2018 Pavel Pisa | |
6 | * | |
7 | * Initial development supported by Google GSoC 2013 from RTEMS project slot | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
10 | * of this software and associated documentation files (the "Software"), to deal | |
11 | * in the Software without restriction, including without limitation the rights | |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
13 | * copies of the Software, and to permit persons to whom the Software is | |
14 | * furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice shall be included in | |
17 | * all copies or substantial portions of the Software. | |
18 | * | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
25 | * THE SOFTWARE. | |
26 | */ | |
64552b6b | 27 | |
733210e7 PP |
28 | #include "qemu/osdep.h" |
29 | #include "qemu/log.h" | |
30 | #include "chardev/char.h" | |
64552b6b | 31 | #include "hw/irq.h" |
d6454270 | 32 | #include "migration/vmstate.h" |
733210e7 PP |
33 | #include "net/can_emu.h" |
34 | ||
35 | #include "can_sja1000.h" | |
36 | ||
37 | #ifndef DEBUG_FILTER | |
38 | #define DEBUG_FILTER 0 | |
39 | #endif /*DEBUG_FILTER*/ | |
40 | ||
41 | #ifndef DEBUG_CAN | |
42 | #define DEBUG_CAN 0 | |
43 | #endif /*DEBUG_CAN*/ | |
44 | ||
45 | #define DPRINTF(fmt, ...) \ | |
46 | do { \ | |
47 | if (DEBUG_CAN) { \ | |
48 | qemu_log("[cansja]: " fmt , ## __VA_ARGS__); \ | |
49 | } \ | |
50 | } while (0) | |
51 | ||
52 | static void can_sja_software_reset(CanSJA1000State *s) | |
53 | { | |
54 | s->mode &= ~0x31; | |
55 | s->mode |= 0x01; | |
56 | s->status_pel &= ~0x37; | |
57 | s->status_pel |= 0x34; | |
58 | ||
59 | s->rxbuf_start = 0x00; | |
60 | s->rxmsg_cnt = 0x00; | |
61 | s->rx_cnt = 0x00; | |
62 | } | |
63 | ||
64 | void can_sja_hardware_reset(CanSJA1000State *s) | |
65 | { | |
66 | /* Reset by hardware, p10 */ | |
67 | s->mode = 0x01; | |
68 | s->status_pel = 0x3c; | |
69 | s->interrupt_pel = 0x00; | |
70 | s->clock = 0x00; | |
71 | s->rxbuf_start = 0x00; | |
72 | s->rxmsg_cnt = 0x00; | |
73 | s->rx_cnt = 0x00; | |
74 | ||
75 | s->control = 0x01; | |
76 | s->status_bas = 0x0c; | |
77 | s->interrupt_bas = 0x00; | |
78 | ||
79 | qemu_irq_lower(s->irq); | |
80 | } | |
81 | ||
82 | static | |
83 | void can_sja_single_filter(struct qemu_can_filter *filter, | |
84 | const uint8_t *acr, const uint8_t *amr, int extended) | |
85 | { | |
86 | if (extended) { | |
87 | filter->can_id = (uint32_t)acr[0] << 21; | |
88 | filter->can_id |= (uint32_t)acr[1] << 13; | |
89 | filter->can_id |= (uint32_t)acr[2] << 5; | |
90 | filter->can_id |= (uint32_t)acr[3] >> 3; | |
91 | if (acr[3] & 4) { | |
92 | filter->can_id |= QEMU_CAN_RTR_FLAG; | |
93 | } | |
94 | ||
95 | filter->can_mask = (uint32_t)amr[0] << 21; | |
96 | filter->can_mask |= (uint32_t)amr[1] << 13; | |
97 | filter->can_mask |= (uint32_t)amr[2] << 5; | |
98 | filter->can_mask |= (uint32_t)amr[3] >> 3; | |
99 | filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK; | |
100 | if (!(amr[3] & 4)) { | |
101 | filter->can_mask |= QEMU_CAN_RTR_FLAG; | |
102 | } | |
103 | } else { | |
104 | filter->can_id = (uint32_t)acr[0] << 3; | |
105 | filter->can_id |= (uint32_t)acr[1] >> 5; | |
106 | if (acr[1] & 0x10) { | |
107 | filter->can_id |= QEMU_CAN_RTR_FLAG; | |
108 | } | |
109 | ||
110 | filter->can_mask = (uint32_t)amr[0] << 3; | |
111 | filter->can_mask |= (uint32_t)amr[1] << 5; | |
112 | filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK; | |
113 | if (!(amr[1] & 0x10)) { | |
114 | filter->can_mask |= QEMU_CAN_RTR_FLAG; | |
115 | } | |
116 | } | |
117 | } | |
118 | ||
119 | static | |
120 | void can_sja_dual_filter(struct qemu_can_filter *filter, | |
121 | const uint8_t *acr, const uint8_t *amr, int extended) | |
122 | { | |
123 | if (extended) { | |
124 | filter->can_id = (uint32_t)acr[0] << 21; | |
125 | filter->can_id |= (uint32_t)acr[1] << 13; | |
126 | ||
127 | filter->can_mask = (uint32_t)amr[0] << 21; | |
128 | filter->can_mask |= (uint32_t)amr[1] << 13; | |
129 | filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK & ~0x1fff; | |
130 | } else { | |
131 | filter->can_id = (uint32_t)acr[0] << 3; | |
132 | filter->can_id |= (uint32_t)acr[1] >> 5; | |
133 | if (acr[1] & 0x10) { | |
134 | filter->can_id |= QEMU_CAN_RTR_FLAG; | |
135 | } | |
136 | ||
137 | filter->can_mask = (uint32_t)amr[0] << 3; | |
138 | filter->can_mask |= (uint32_t)amr[1] >> 5; | |
139 | filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK; | |
140 | if (!(amr[1] & 0x10)) { | |
141 | filter->can_mask |= QEMU_CAN_RTR_FLAG; | |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | /* Details in DS-p22, what we need to do here is to test the data. */ | |
147 | static | |
148 | int can_sja_accept_filter(CanSJA1000State *s, | |
149 | const qemu_can_frame *frame) | |
150 | { | |
151 | ||
152 | struct qemu_can_filter filter; | |
153 | ||
154 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
155 | if (s->mode & (1 << 3)) { /* Single mode. */ | |
156 | if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */ | |
157 | can_sja_single_filter(&filter, | |
158 | s->code_mask + 0, s->code_mask + 4, 1); | |
159 | ||
160 | if (!can_bus_filter_match(&filter, frame->can_id)) { | |
161 | return 0; | |
162 | } | |
163 | } else { /* SFF */ | |
164 | can_sja_single_filter(&filter, | |
165 | s->code_mask + 0, s->code_mask + 4, 0); | |
166 | ||
167 | if (!can_bus_filter_match(&filter, frame->can_id)) { | |
168 | return 0; | |
169 | } | |
170 | ||
171 | if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */ | |
172 | return 1; | |
173 | } | |
174 | ||
175 | if (frame->can_dlc == 0) { | |
176 | return 1; | |
177 | } | |
178 | ||
179 | if ((frame->data[0] & ~(s->code_mask[6])) != | |
180 | (s->code_mask[2] & ~(s->code_mask[6]))) { | |
181 | return 0; | |
182 | } | |
183 | ||
184 | if (frame->can_dlc < 2) { | |
185 | return 1; | |
186 | } | |
187 | ||
188 | if ((frame->data[1] & ~(s->code_mask[7])) == | |
189 | (s->code_mask[3] & ~(s->code_mask[7]))) { | |
190 | return 1; | |
191 | } | |
192 | ||
193 | return 0; | |
194 | } | |
195 | } else { /* Dual mode */ | |
196 | if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */ | |
197 | can_sja_dual_filter(&filter, | |
198 | s->code_mask + 0, s->code_mask + 4, 1); | |
199 | ||
200 | if (can_bus_filter_match(&filter, frame->can_id)) { | |
201 | return 1; | |
202 | } | |
203 | ||
204 | can_sja_dual_filter(&filter, | |
205 | s->code_mask + 2, s->code_mask + 6, 1); | |
206 | ||
207 | if (can_bus_filter_match(&filter, frame->can_id)) { | |
208 | return 1; | |
209 | } | |
210 | ||
211 | return 0; | |
212 | } else { | |
213 | can_sja_dual_filter(&filter, | |
214 | s->code_mask + 0, s->code_mask + 4, 0); | |
215 | ||
216 | if (can_bus_filter_match(&filter, frame->can_id)) { | |
217 | uint8_t expect; | |
218 | uint8_t mask; | |
219 | expect = s->code_mask[1] << 4; | |
220 | expect |= s->code_mask[3] & 0x0f; | |
221 | ||
222 | mask = s->code_mask[5] << 4; | |
223 | mask |= s->code_mask[7] & 0x0f; | |
224 | mask = ~mask & 0xff; | |
225 | ||
226 | if ((frame->data[0] & mask) == | |
227 | (expect & mask)) { | |
228 | return 1; | |
229 | } | |
230 | } | |
231 | ||
232 | can_sja_dual_filter(&filter, | |
233 | s->code_mask + 2, s->code_mask + 6, 0); | |
234 | ||
235 | if (can_bus_filter_match(&filter, frame->can_id)) { | |
236 | return 1; | |
237 | } | |
238 | ||
239 | return 0; | |
240 | } | |
241 | } | |
242 | } | |
243 | ||
244 | return 1; | |
245 | } | |
246 | ||
247 | static void can_display_msg(const char *prefix, const qemu_can_frame *msg) | |
248 | { | |
249 | int i; | |
fc59d2d8 | 250 | FILE *logfile = qemu_log_lock(); |
733210e7 | 251 | |
733210e7 PP |
252 | qemu_log("%s%03X [%01d] %s %s", |
253 | prefix, | |
254 | msg->can_id & QEMU_CAN_EFF_MASK, | |
255 | msg->can_dlc, | |
256 | msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF", | |
257 | msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT"); | |
258 | ||
259 | for (i = 0; i < msg->can_dlc; i++) { | |
260 | qemu_log(" %02X", msg->data[i]); | |
261 | } | |
262 | qemu_log("\n"); | |
263 | qemu_log_flush(); | |
fc59d2d8 | 264 | qemu_log_unlock(logfile); |
733210e7 PP |
265 | } |
266 | ||
267 | static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame) | |
268 | { | |
269 | uint8_t i; | |
270 | ||
271 | frame->can_id = 0; | |
272 | if (buff[0] & 0x40) { /* RTR */ | |
273 | frame->can_id = QEMU_CAN_RTR_FLAG; | |
274 | } | |
275 | frame->can_dlc = buff[0] & 0x0f; | |
276 | ||
277 | if (buff[0] & 0x80) { /* Extended */ | |
278 | frame->can_id |= QEMU_CAN_EFF_FLAG; | |
279 | frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */ | |
280 | frame->can_id |= buff[2] << 13; /* ID.20~ID.13 */ | |
281 | frame->can_id |= buff[3] << 5; | |
282 | frame->can_id |= buff[4] >> 3; | |
283 | for (i = 0; i < frame->can_dlc; i++) { | |
284 | frame->data[i] = buff[5 + i]; | |
285 | } | |
286 | for (; i < 8; i++) { | |
287 | frame->data[i] = 0; | |
288 | } | |
289 | } else { | |
290 | frame->can_id |= buff[1] << 3; | |
291 | frame->can_id |= buff[2] >> 5; | |
292 | for (i = 0; i < frame->can_dlc; i++) { | |
293 | frame->data[i] = buff[3 + i]; | |
294 | } | |
295 | for (; i < 8; i++) { | |
296 | frame->data[i] = 0; | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
301 | ||
302 | static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame) | |
303 | { | |
304 | uint8_t i; | |
305 | ||
306 | frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07); | |
307 | if (buff[1] & 0x10) { /* RTR */ | |
308 | frame->can_id = QEMU_CAN_RTR_FLAG; | |
309 | } | |
310 | frame->can_dlc = buff[1] & 0x0f; | |
311 | ||
312 | for (i = 0; i < frame->can_dlc; i++) { | |
313 | frame->data[i] = buff[2 + i]; | |
314 | } | |
315 | for (; i < 8; i++) { | |
316 | frame->data[i] = 0; | |
317 | } | |
318 | } | |
319 | ||
320 | ||
321 | static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff) | |
322 | { | |
323 | int i; | |
324 | ||
325 | if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */ | |
326 | return -1; | |
327 | } | |
328 | ||
329 | buff[0] = 0x0f & frame->can_dlc; /* DLC */ | |
330 | if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */ | |
331 | buff[0] |= (1 << 6); | |
332 | } | |
333 | if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */ | |
334 | buff[0] |= (1 << 7); | |
335 | buff[1] = extract32(frame->can_id, 21, 8); /* ID.28~ID.21 */ | |
336 | buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */ | |
337 | buff[3] = extract32(frame->can_id, 5, 8); /* ID.12~ID.05 */ | |
338 | buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,xxx */ | |
339 | for (i = 0; i < frame->can_dlc; i++) { | |
340 | buff[5 + i] = frame->data[i]; | |
341 | } | |
342 | return frame->can_dlc + 5; | |
343 | } else { /* SFF */ | |
344 | buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */ | |
345 | buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */ | |
346 | for (i = 0; i < frame->can_dlc; i++) { | |
347 | buff[3 + i] = frame->data[i]; | |
348 | } | |
349 | ||
350 | return frame->can_dlc + 3; | |
351 | } | |
352 | ||
353 | return -1; | |
354 | } | |
355 | ||
356 | static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff) | |
357 | { | |
358 | int i; | |
359 | ||
360 | /* | |
361 | * EFF, no support for BasicMode | |
362 | * No use for Error frames now, | |
363 | * they could be used in future to update SJA1000 error state | |
364 | */ | |
365 | if ((frame->can_id & QEMU_CAN_EFF_FLAG) || | |
366 | (frame->can_id & QEMU_CAN_ERR_FLAG)) { | |
367 | return -1; | |
368 | } | |
369 | ||
370 | buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */ | |
371 | buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */ | |
372 | if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */ | |
373 | buff[1] |= (1 << 4); | |
374 | } | |
375 | buff[1] |= frame->can_dlc & 0x0f; | |
376 | for (i = 0; i < frame->can_dlc; i++) { | |
377 | buff[2 + i] = frame->data[i]; | |
378 | } | |
379 | ||
380 | return frame->can_dlc + 2; | |
381 | } | |
382 | ||
a62ed5d1 PB |
383 | static void can_sja_update_pel_irq(CanSJA1000State *s) |
384 | { | |
385 | if (s->interrupt_en & s->interrupt_pel) { | |
386 | qemu_irq_raise(s->irq); | |
387 | } else { | |
388 | qemu_irq_lower(s->irq); | |
389 | } | |
390 | } | |
391 | ||
392 | static void can_sja_update_bas_irq(CanSJA1000State *s) | |
393 | { | |
394 | if ((s->control >> 1) & s->interrupt_bas) { | |
395 | qemu_irq_raise(s->irq); | |
396 | } else { | |
397 | qemu_irq_lower(s->irq); | |
398 | } | |
399 | } | |
400 | ||
733210e7 PP |
401 | void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val, |
402 | unsigned size) | |
403 | { | |
404 | qemu_can_frame frame; | |
405 | uint32_t tmp; | |
406 | uint8_t tmp8, count; | |
407 | ||
408 | ||
409 | DPRINTF("write 0x%02llx addr 0x%02x\n", | |
410 | (unsigned long long)val, (unsigned int)addr); | |
411 | ||
412 | if (addr > CAN_SJA_MEM_SIZE) { | |
413 | return ; | |
414 | } | |
415 | ||
416 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
417 | switch (addr) { | |
418 | case SJA_MOD: /* Mode register */ | |
419 | s->mode = 0x1f & val; | |
420 | if ((s->mode & 0x01) && ((val & 0x01) == 0)) { | |
421 | /* Go to operation mode from reset mode. */ | |
422 | if (s->mode & (1 << 3)) { /* Single mode. */ | |
423 | /* For EFF */ | |
424 | can_sja_single_filter(&s->filter[0], | |
425 | s->code_mask + 0, s->code_mask + 4, 1); | |
426 | ||
427 | /* For SFF */ | |
428 | can_sja_single_filter(&s->filter[1], | |
429 | s->code_mask + 0, s->code_mask + 4, 0); | |
430 | ||
431 | can_bus_client_set_filters(&s->bus_client, s->filter, 2); | |
432 | } else { /* Dual mode */ | |
433 | /* For EFF */ | |
434 | can_sja_dual_filter(&s->filter[0], | |
435 | s->code_mask + 0, s->code_mask + 4, 1); | |
436 | ||
437 | can_sja_dual_filter(&s->filter[1], | |
438 | s->code_mask + 2, s->code_mask + 6, 1); | |
439 | ||
440 | /* For SFF */ | |
441 | can_sja_dual_filter(&s->filter[2], | |
442 | s->code_mask + 0, s->code_mask + 4, 0); | |
443 | ||
444 | can_sja_dual_filter(&s->filter[3], | |
445 | s->code_mask + 2, s->code_mask + 6, 0); | |
446 | ||
447 | can_bus_client_set_filters(&s->bus_client, s->filter, 4); | |
448 | } | |
449 | ||
450 | s->rxmsg_cnt = 0; | |
451 | s->rx_cnt = 0; | |
452 | } | |
453 | break; | |
454 | ||
455 | case SJA_CMR: /* Command register. */ | |
456 | if (0x01 & val) { /* Send transmission request. */ | |
457 | buff2frame_pel(s->tx_buff, &frame); | |
458 | if (DEBUG_FILTER) { | |
459 | can_display_msg("[cansja]: Tx request " , &frame); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Clear transmission complete status, | |
464 | * and Transmit Buffer Status. | |
465 | * write to the backends. | |
466 | */ | |
467 | s->status_pel &= ~(3 << 2); | |
468 | ||
469 | can_bus_client_send(&s->bus_client, &frame, 1); | |
470 | ||
471 | /* | |
472 | * Set transmission complete status | |
473 | * and Transmit Buffer Status. | |
474 | */ | |
475 | s->status_pel |= (3 << 2); | |
476 | ||
477 | /* Clear transmit status. */ | |
478 | s->status_pel &= ~(1 << 5); | |
479 | s->interrupt_pel |= 0x02; | |
a62ed5d1 | 480 | can_sja_update_pel_irq(s); |
733210e7 PP |
481 | } |
482 | if (0x04 & val) { /* Release Receive Buffer */ | |
483 | if (s->rxmsg_cnt <= 0) { | |
484 | break; | |
485 | } | |
486 | ||
487 | tmp8 = s->rx_buff[s->rxbuf_start]; count = 0; | |
488 | if (tmp8 & (1 << 7)) { /* EFF */ | |
489 | count += 2; | |
490 | } | |
491 | count += 3; | |
492 | if (!(tmp8 & (1 << 6))) { /* DATA */ | |
493 | count += (tmp8 & 0x0f); | |
494 | } | |
495 | ||
496 | if (DEBUG_FILTER) { | |
497 | qemu_log("[cansja]: message released from " | |
498 | "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count); | |
499 | } | |
500 | ||
501 | s->rxbuf_start += count; | |
502 | s->rxbuf_start %= SJA_RCV_BUF_LEN; | |
503 | ||
504 | s->rx_cnt -= count; | |
505 | s->rxmsg_cnt--; | |
506 | if (s->rxmsg_cnt == 0) { | |
507 | s->status_pel &= ~(1 << 0); | |
508 | s->interrupt_pel &= ~(1 << 0); | |
a62ed5d1 | 509 | can_sja_update_pel_irq(s); |
733210e7 PP |
510 | } |
511 | } | |
512 | if (0x08 & val) { /* Clear data overrun */ | |
513 | s->status_pel &= ~(1 << 1); | |
514 | s->interrupt_pel &= ~(1 << 3); | |
a62ed5d1 | 515 | can_sja_update_pel_irq(s); |
733210e7 PP |
516 | } |
517 | break; | |
518 | case SJA_SR: /* Status register */ | |
519 | case SJA_IR: /* Interrupt register */ | |
520 | break; /* Do nothing */ | |
521 | case SJA_IER: /* Interrupt enable register */ | |
522 | s->interrupt_en = val; | |
523 | break; | |
524 | case 16: /* RX frame information addr16-28. */ | |
525 | s->status_pel |= (1 << 5); /* Set transmit status. */ | |
526 | case 17 ... 28: | |
527 | if (s->mode & 0x01) { /* Reset mode */ | |
528 | if (addr < 24) { | |
529 | s->code_mask[addr - 16] = val; | |
530 | } | |
531 | } else { /* Operation mode */ | |
532 | s->tx_buff[addr - 16] = val; /* Store to TX buffer directly. */ | |
533 | } | |
534 | break; | |
535 | case SJA_CDR: | |
536 | s->clock = val; | |
537 | break; | |
538 | } | |
539 | } else { /* Basic Mode */ | |
540 | switch (addr) { | |
541 | case SJA_BCAN_CTR: /* Control register, addr 0 */ | |
542 | if ((s->control & 0x01) && ((val & 0x01) == 0)) { | |
543 | /* Go to operation mode from reset mode. */ | |
544 | s->filter[0].can_id = (s->code << 3) & (0xff << 3); | |
545 | tmp = (~(s->mask << 3)) & (0xff << 3); | |
546 | tmp |= QEMU_CAN_EFF_FLAG; /* Only Basic CAN Frame. */ | |
547 | s->filter[0].can_mask = tmp; | |
548 | can_bus_client_set_filters(&s->bus_client, s->filter, 1); | |
549 | ||
550 | s->rxmsg_cnt = 0; | |
551 | s->rx_cnt = 0; | |
552 | } else if (!(s->control & 0x01) && !(val & 0x01)) { | |
553 | can_sja_software_reset(s); | |
554 | } | |
555 | ||
556 | s->control = 0x1f & val; | |
557 | break; | |
558 | case SJA_BCAN_CMR: /* Command register, addr 1 */ | |
559 | if (0x01 & val) { /* Send transmission request. */ | |
560 | buff2frame_bas(s->tx_buff, &frame); | |
561 | if (DEBUG_FILTER) { | |
562 | can_display_msg("[cansja]: Tx request " , &frame); | |
563 | } | |
564 | ||
565 | /* | |
566 | * Clear transmission complete status, | |
567 | * and Transmit Buffer Status. | |
568 | */ | |
569 | s->status_bas &= ~(3 << 2); | |
570 | ||
571 | /* write to the backends. */ | |
572 | can_bus_client_send(&s->bus_client, &frame, 1); | |
573 | ||
574 | /* | |
575 | * Set transmission complete status, | |
576 | * and Transmit Buffer Status. | |
577 | */ | |
578 | s->status_bas |= (3 << 2); | |
579 | ||
580 | /* Clear transmit status. */ | |
581 | s->status_bas &= ~(1 << 5); | |
582 | s->interrupt_bas |= 0x02; | |
a62ed5d1 | 583 | can_sja_update_bas_irq(s); |
733210e7 PP |
584 | } |
585 | if (0x04 & val) { /* Release Receive Buffer */ | |
586 | if (s->rxmsg_cnt <= 0) { | |
587 | break; | |
588 | } | |
589 | ||
590 | tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN]; | |
591 | count = 2 + (tmp8 & 0x0f); | |
592 | ||
593 | if (DEBUG_FILTER) { | |
594 | qemu_log("[cansja]: message released from " | |
595 | "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count); | |
596 | } | |
597 | ||
598 | s->rxbuf_start += count; | |
599 | s->rxbuf_start %= SJA_RCV_BUF_LEN; | |
600 | s->rx_cnt -= count; | |
601 | s->rxmsg_cnt--; | |
602 | ||
603 | if (s->rxmsg_cnt == 0) { | |
604 | s->status_bas &= ~(1 << 0); | |
605 | s->interrupt_bas &= ~(1 << 0); | |
a62ed5d1 | 606 | can_sja_update_bas_irq(s); |
733210e7 PP |
607 | } |
608 | } | |
609 | if (0x08 & val) { /* Clear data overrun */ | |
610 | s->status_bas &= ~(1 << 1); | |
611 | s->interrupt_bas &= ~(1 << 3); | |
a62ed5d1 | 612 | can_sja_update_bas_irq(s); |
733210e7 PP |
613 | } |
614 | break; | |
615 | case 4: | |
616 | s->code = val; | |
617 | break; | |
618 | case 5: | |
619 | s->mask = val; | |
620 | break; | |
621 | case 10: | |
622 | s->status_bas |= (1 << 5); /* Set transmit status. */ | |
623 | case 11 ... 19: | |
624 | if ((s->control & 0x01) == 0) { /* Operation mode */ | |
625 | s->tx_buff[addr - 10] = val; /* Store to TX buffer directly. */ | |
626 | } | |
627 | break; | |
628 | case SJA_CDR: | |
629 | s->clock = val; | |
630 | break; | |
631 | } | |
632 | } | |
633 | } | |
634 | ||
635 | uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size) | |
636 | { | |
637 | uint64_t temp = 0; | |
638 | ||
639 | DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr); | |
640 | ||
641 | if (addr > CAN_SJA_MEM_SIZE) { | |
642 | return 0; | |
643 | } | |
644 | ||
645 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
646 | switch (addr) { | |
647 | case SJA_MOD: /* Mode register, addr 0 */ | |
648 | temp = s->mode; | |
649 | break; | |
650 | case SJA_CMR: /* Command register, addr 1 */ | |
651 | temp = 0x00; /* Command register, cannot be read. */ | |
652 | break; | |
653 | case SJA_SR: /* Status register, addr 2 */ | |
654 | temp = s->status_pel; | |
655 | break; | |
656 | case SJA_IR: /* Interrupt register, addr 3 */ | |
657 | temp = s->interrupt_pel; | |
658 | s->interrupt_pel = 0; | |
659 | if (s->rxmsg_cnt) { | |
660 | s->interrupt_pel |= (1 << 0); /* Receive interrupt. */ | |
733210e7 | 661 | } |
a62ed5d1 | 662 | can_sja_update_pel_irq(s); |
733210e7 PP |
663 | break; |
664 | case SJA_IER: /* Interrupt enable register, addr 4 */ | |
665 | temp = s->interrupt_en; | |
666 | break; | |
667 | case 5: /* Reserved */ | |
668 | case 6: /* Bus timing 0, hardware related, not support now. */ | |
669 | case 7: /* Bus timing 1, hardware related, not support now. */ | |
670 | case 8: /* | |
671 | * Output control register, hardware related, | |
672 | * not supported for now. | |
673 | */ | |
674 | case 9: /* Test. */ | |
675 | case 10 ... 15: /* Reserved */ | |
676 | temp = 0x00; | |
677 | break; | |
678 | ||
679 | case 16 ... 28: | |
680 | if (s->mode & 0x01) { /* Reset mode */ | |
681 | if (addr < 24) { | |
682 | temp = s->code_mask[addr - 16]; | |
683 | } else { | |
684 | temp = 0x00; | |
685 | } | |
686 | } else { /* Operation mode */ | |
687 | temp = s->rx_buff[(s->rxbuf_start + addr - 16) % | |
688 | SJA_RCV_BUF_LEN]; | |
689 | } | |
690 | break; | |
691 | case SJA_CDR: | |
692 | temp = s->clock; | |
693 | break; | |
694 | default: | |
695 | temp = 0xff; | |
696 | } | |
697 | } else { /* Basic Mode */ | |
698 | switch (addr) { | |
699 | case SJA_BCAN_CTR: /* Control register, addr 0 */ | |
700 | temp = s->control; | |
701 | break; | |
702 | case SJA_BCAN_SR: /* Status register, addr 2 */ | |
703 | temp = s->status_bas; | |
704 | break; | |
705 | case SJA_BCAN_IR: /* Interrupt register, addr 3 */ | |
706 | temp = s->interrupt_bas; | |
707 | s->interrupt_bas = 0; | |
708 | if (s->rxmsg_cnt) { | |
709 | s->interrupt_bas |= (1 << 0); /* Receive interrupt. */ | |
733210e7 | 710 | } |
a62ed5d1 | 711 | can_sja_update_bas_irq(s); |
733210e7 PP |
712 | break; |
713 | case 4: | |
714 | temp = s->code; | |
715 | break; | |
716 | case 5: | |
717 | temp = s->mask; | |
718 | break; | |
719 | case 20 ... 29: | |
720 | temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN]; | |
721 | break; | |
722 | case 31: | |
723 | temp = s->clock; | |
724 | break; | |
725 | default: | |
726 | temp = 0xff; | |
727 | break; | |
728 | } | |
729 | } | |
730 | DPRINTF("read addr 0x%02x, %d bytes, content 0x%02lx\n", | |
731 | (int)addr, size, (long unsigned int)temp); | |
732 | ||
733 | return temp; | |
734 | } | |
735 | ||
736 | int can_sja_can_receive(CanBusClientState *client) | |
737 | { | |
738 | CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client); | |
739 | ||
740 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
741 | if (s->mode & 0x01) { /* reset mode. */ | |
742 | return 0; | |
743 | } | |
744 | } else { /* BasicCAN mode */ | |
745 | if (s->control & 0x01) { | |
746 | return 0; | |
747 | } | |
748 | } | |
749 | ||
750 | return 1; /* always return 1, when operation mode */ | |
751 | } | |
752 | ||
753 | ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames, | |
754 | size_t frames_cnt) | |
755 | { | |
756 | CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client); | |
757 | static uint8_t rcv[SJA_MSG_MAX_LEN]; | |
758 | int i; | |
759 | int ret = -1; | |
760 | const qemu_can_frame *frame = frames; | |
761 | ||
762 | if (frames_cnt <= 0) { | |
763 | return 0; | |
764 | } | |
765 | if (DEBUG_FILTER) { | |
766 | can_display_msg("[cansja]: receive ", frame); | |
767 | } | |
768 | ||
769 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
770 | ||
771 | /* the CAN controller is receiving a message */ | |
772 | s->status_pel |= (1 << 4); | |
773 | ||
774 | if (can_sja_accept_filter(s, frame) == 0) { | |
775 | s->status_pel &= ~(1 << 4); | |
776 | if (DEBUG_FILTER) { | |
777 | qemu_log("[cansja]: filter rejects message\n"); | |
778 | } | |
779 | return ret; | |
780 | } | |
781 | ||
782 | ret = frame2buff_pel(frame, rcv); | |
783 | if (ret < 0) { | |
784 | s->status_pel &= ~(1 << 4); | |
785 | if (DEBUG_FILTER) { | |
786 | qemu_log("[cansja]: message store failed\n"); | |
787 | } | |
788 | return ret; /* maybe not support now. */ | |
789 | } | |
790 | ||
791 | if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */ | |
792 | s->status_pel |= (1 << 1); /* Overrun status */ | |
793 | s->interrupt_pel |= (1 << 3); | |
733210e7 PP |
794 | s->status_pel &= ~(1 << 4); |
795 | if (DEBUG_FILTER) { | |
796 | qemu_log("[cansja]: receive FIFO overrun\n"); | |
797 | } | |
a62ed5d1 | 798 | can_sja_update_pel_irq(s); |
733210e7 PP |
799 | return ret; |
800 | } | |
801 | s->rx_cnt += ret; | |
802 | s->rxmsg_cnt++; | |
803 | if (DEBUG_FILTER) { | |
804 | qemu_log("[cansja]: message stored in receive FIFO\n"); | |
805 | } | |
806 | ||
807 | for (i = 0; i < ret; i++) { | |
808 | s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i]; | |
809 | } | |
810 | s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */ | |
811 | ||
812 | s->status_pel |= 0x01; /* Set the Receive Buffer Status. DS-p23 */ | |
813 | s->interrupt_pel |= 0x01; | |
814 | s->status_pel &= ~(1 << 4); | |
815 | s->status_pel |= (1 << 0); | |
a62ed5d1 | 816 | can_sja_update_pel_irq(s); |
733210e7 PP |
817 | } else { /* BasicCAN mode */ |
818 | ||
819 | /* the CAN controller is receiving a message */ | |
820 | s->status_bas |= (1 << 4); | |
821 | ||
822 | ret = frame2buff_bas(frame, rcv); | |
823 | if (ret < 0) { | |
824 | s->status_bas &= ~(1 << 4); | |
825 | if (DEBUG_FILTER) { | |
826 | qemu_log("[cansja]: message store failed\n"); | |
827 | } | |
828 | return ret; /* maybe not support now. */ | |
829 | } | |
830 | ||
831 | if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */ | |
832 | s->status_bas |= (1 << 1); /* Overrun status */ | |
833 | s->status_bas &= ~(1 << 4); | |
834 | s->interrupt_bas |= (1 << 3); | |
a62ed5d1 | 835 | can_sja_update_bas_irq(s); |
733210e7 PP |
836 | if (DEBUG_FILTER) { |
837 | qemu_log("[cansja]: receive FIFO overrun\n"); | |
838 | } | |
839 | return ret; | |
840 | } | |
841 | s->rx_cnt += ret; | |
842 | s->rxmsg_cnt++; | |
843 | ||
844 | if (DEBUG_FILTER) { | |
845 | qemu_log("[cansja]: message stored\n"); | |
846 | } | |
847 | ||
848 | for (i = 0; i < ret; i++) { | |
849 | s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i]; | |
850 | } | |
851 | s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */ | |
852 | ||
853 | s->status_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */ | |
854 | s->status_bas &= ~(1 << 4); | |
a62ed5d1 PB |
855 | s->interrupt_bas |= (1 << 0); |
856 | can_sja_update_bas_irq(s); | |
733210e7 PP |
857 | } |
858 | return 1; | |
859 | } | |
860 | ||
861 | static CanBusClientInfo can_sja_bus_client_info = { | |
862 | .can_receive = can_sja_can_receive, | |
863 | .receive = can_sja_receive, | |
864 | }; | |
865 | ||
866 | ||
867 | int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus) | |
868 | { | |
869 | s->bus_client.info = &can_sja_bus_client_info; | |
870 | ||
089eac81 TH |
871 | if (!bus) { |
872 | return -EINVAL; | |
873 | } | |
874 | ||
733210e7 PP |
875 | if (can_bus_insert_client(bus, &s->bus_client) < 0) { |
876 | return -1; | |
877 | } | |
878 | ||
879 | return 0; | |
880 | } | |
881 | ||
882 | void can_sja_disconnect(CanSJA1000State *s) | |
883 | { | |
884 | can_bus_remove_client(&s->bus_client); | |
885 | } | |
886 | ||
887 | int can_sja_init(CanSJA1000State *s, qemu_irq irq) | |
888 | { | |
889 | s->irq = irq; | |
890 | ||
891 | qemu_irq_lower(s->irq); | |
892 | ||
893 | can_sja_hardware_reset(s); | |
894 | ||
895 | return 0; | |
896 | } | |
897 | ||
898 | const VMStateDescription vmstate_qemu_can_filter = { | |
899 | .name = "qemu_can_filter", | |
900 | .version_id = 1, | |
901 | .minimum_version_id = 1, | |
902 | .minimum_version_id_old = 1, | |
903 | .fields = (VMStateField[]) { | |
904 | VMSTATE_UINT32(can_id, qemu_can_filter), | |
905 | VMSTATE_UINT32(can_mask, qemu_can_filter), | |
906 | VMSTATE_END_OF_LIST() | |
907 | } | |
908 | }; | |
909 | ||
a62ed5d1 PB |
910 | static int can_sja_post_load(void *opaque, int version_id) |
911 | { | |
912 | CanSJA1000State *s = opaque; | |
913 | if (s->clock & 0x80) { /* PeliCAN Mode */ | |
914 | can_sja_update_pel_irq(s); | |
915 | } else { | |
916 | can_sja_update_bas_irq(s); | |
917 | } | |
918 | return 0; | |
919 | } | |
920 | ||
733210e7 PP |
921 | /* VMState is needed for live migration of QEMU images */ |
922 | const VMStateDescription vmstate_can_sja = { | |
923 | .name = "can_sja", | |
924 | .version_id = 1, | |
925 | .minimum_version_id = 1, | |
926 | .minimum_version_id_old = 1, | |
a62ed5d1 | 927 | .post_load = can_sja_post_load, |
733210e7 PP |
928 | .fields = (VMStateField[]) { |
929 | VMSTATE_UINT8(mode, CanSJA1000State), | |
930 | ||
931 | VMSTATE_UINT8(status_pel, CanSJA1000State), | |
932 | VMSTATE_UINT8(interrupt_pel, CanSJA1000State), | |
933 | VMSTATE_UINT8(interrupt_en, CanSJA1000State), | |
934 | VMSTATE_UINT8(rxmsg_cnt, CanSJA1000State), | |
935 | VMSTATE_UINT8(rxbuf_start, CanSJA1000State), | |
936 | VMSTATE_UINT8(clock, CanSJA1000State), | |
937 | ||
938 | VMSTATE_BUFFER(code_mask, CanSJA1000State), | |
939 | VMSTATE_BUFFER(tx_buff, CanSJA1000State), | |
940 | ||
941 | VMSTATE_BUFFER(rx_buff, CanSJA1000State), | |
942 | ||
943 | VMSTATE_UINT32(rx_ptr, CanSJA1000State), | |
944 | VMSTATE_UINT32(rx_cnt, CanSJA1000State), | |
945 | ||
946 | VMSTATE_UINT8(control, CanSJA1000State), | |
947 | ||
948 | VMSTATE_UINT8(status_bas, CanSJA1000State), | |
949 | VMSTATE_UINT8(interrupt_bas, CanSJA1000State), | |
950 | VMSTATE_UINT8(code, CanSJA1000State), | |
951 | VMSTATE_UINT8(mask, CanSJA1000State), | |
952 | ||
953 | VMSTATE_STRUCT_ARRAY(filter, CanSJA1000State, 4, 0, | |
954 | vmstate_qemu_can_filter, qemu_can_filter), | |
955 | ||
956 | ||
957 | VMSTATE_END_OF_LIST() | |
958 | } | |
959 | }; |