1 /*
2 * Copyright (C) 2004-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: VR41xx (VR4122 and VR4131) misc functions
29 *
30 * This is just a big hack.
31 *
32 * TODO: Implement more functionality some day.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "console.h"
40 #include "cpu.h"
41 #include "device.h"
42 #include "devices.h"
43 #include "interrupt.h"
44 #include "machine.h"
45 #include "memory.h"
46 #include "misc.h"
47 #include "timer.h"
48
49 #include "thirdparty/bcureg.h"
50 #include "thirdparty/vripreg.h"
51 #include "thirdparty/vrkiureg.h"
52 #include "thirdparty/vr_rtcreg.h"
53
54
55 /* #define debug fatal */
56
57 #define DEV_VR41XX_TICKSHIFT 14
58
59 #define DEV_VR41XX_LENGTH 0x800 /* TODO? */
60 struct vr41xx_data {
61 struct interrupt cpu_irq; /* Connected to MIPS irq 2 */
62 int cpumodel; /* Model nr, e.g. 4121 */
63
64 /* KIU: */
65 int kiu_console_handle;
66 uint32_t kiu_offset;
67 struct interrupt kiu_irq;
68 int kiu_int_assert;
69 int old_kiu_int_assert;
70
71 int d0, d1, d2, d3, d4, d5;
72 int dont_clear_next;
73 int escape_state;
74
75 /* Timer: */
76 int pending_timer_interrupts;
77 struct interrupt timer_irq;
78 struct timer *timer;
79
80 /* See icureg.h in NetBSD for more info. */
81 uint16_t sysint1;
82 uint16_t msysint1;
83 uint16_t giuint;
84 uint16_t giumask;
85 uint16_t sysint2;
86 uint16_t msysint2;
87 struct interrupt giu_irq;
88 };
89
90
91 /*
92 * vr41xx_vrip_interrupt_assert():
93 * vr41xx_vrip_interrupt_deassert():
94 */
vr41xx_vrip_interrupt_assert(struct interrupt * interrupt)95 void vr41xx_vrip_interrupt_assert(struct interrupt *interrupt)
96 {
97 struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra;
98 int line = interrupt->line;
99 if (line < 16)
100 d->sysint1 |= (1 << line);
101 else
102 d->sysint2 |= (1 << (line-16));
103 if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2))
104 INTERRUPT_ASSERT(d->cpu_irq);
105 }
vr41xx_vrip_interrupt_deassert(struct interrupt * interrupt)106 void vr41xx_vrip_interrupt_deassert(struct interrupt *interrupt)
107 {
108 struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra;
109 int line = interrupt->line;
110 if (line < 16)
111 d->sysint1 &= ~(1 << line);
112 else
113 d->sysint2 &= ~(1 << (line-16));
114 if (!(d->sysint1 & d->msysint1) && !(d->sysint2 & d->msysint2))
115 INTERRUPT_DEASSERT(d->cpu_irq);
116 }
117
118
119 /*
120 * vr41xx_giu_interrupt_assert():
121 * vr41xx_giu_interrupt_deassert():
122 */
vr41xx_giu_interrupt_assert(struct interrupt * interrupt)123 void vr41xx_giu_interrupt_assert(struct interrupt *interrupt)
124 {
125 struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra;
126 int line = interrupt->line;
127 d->giuint |= (1 << line);
128 if (d->giuint & d->giumask)
129 INTERRUPT_ASSERT(d->giu_irq);
130 }
vr41xx_giu_interrupt_deassert(struct interrupt * interrupt)131 void vr41xx_giu_interrupt_deassert(struct interrupt *interrupt)
132 {
133 struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra;
134 int line = interrupt->line;
135 d->giuint &= ~(1 << line);
136 if (!(d->giuint & d->giumask))
137 INTERRUPT_DEASSERT(d->giu_irq);
138 }
139
140
recalc_kiu_int_assert(struct cpu * cpu,struct vr41xx_data * d)141 static void recalc_kiu_int_assert(struct cpu *cpu, struct vr41xx_data *d)
142 {
143 if (d->kiu_int_assert != d->old_kiu_int_assert) {
144 d->old_kiu_int_assert = d->kiu_int_assert;
145 if (d->kiu_int_assert != 0)
146 INTERRUPT_ASSERT(d->kiu_irq);
147 else
148 INTERRUPT_DEASSERT(d->kiu_irq);
149 }
150 }
151
152
153 /*
154 * vr41xx_keytick():
155 */
vr41xx_keytick(struct cpu * cpu,struct vr41xx_data * d)156 static void vr41xx_keytick(struct cpu *cpu, struct vr41xx_data *d)
157 {
158 int keychange = 0;
159
160 /*
161 * Keyboard input:
162 *
163 * Hardcoded for MobilePro. (See NetBSD's hpckbdkeymap.h for
164 * info on other keyboard layouts. mobilepro780_keytrans is the
165 * one used here.)
166 *
167 * TODO: Make this work with "any" keyboard layout.
168 *
169 * ofs 0:
170 * 8000='o' 4000='.' 2000=DOWN 1000=UP
171 * 800=';' 400=''' 200='[' 100=?
172 * 80='l' 40=CR 20=RIGHT 10=LEFT
173 * 8='/' 4='\' 2=']' 1=SPACE
174 * ofs 2:
175 * 8000='a' 4000='s' 2000='d' 1000='f'
176 * 800='`' 400='-' 200='=' 100=?
177 * 80='z' 40='x' 20='c' 10='v'
178 * 8=? 4=? 2=?
179 * ofs 4:
180 * 8000='9' 4000='0' 2000=? 1000=?
181 * 800='b' 400='n' 200='m' 100=','
182 * 80='q' 40='w' 20='e' 10='r'
183 * 8='5' 4='6' 2='7' 1='8'
184 * ofs 6:
185 * 8000=ESC 4000=DEL 2000=CAPS 1000=?
186 * 800='t' 400='y' 200='u' 100='i'
187 * 80='1' 40='2' 20='3' 10='4'
188 * 8='g' 4='h' 2='j' 1='k'
189 * ofs 8:
190 * 200=ALT_L
191 * 80= 40=TAB 20='p' 10=BS
192 * 8= 4= 2= 1=ALT_R
193 * ofs a:
194 * 800=SHIFT 4=CTRL
195 *
196 *
197 * The following are for the IBM WorkPad Z50:
198 * (Not yet implemented, TODO)
199 *
200 * 00 f1 f3 f5 f7 f9 - - f11
201 * 08 f2 f4 f6 f8 f10 - - f12
202 * 10 ' [ - 0 p ; up /
203 * 18 - - - 9 o l . -
204 * 20 left ] = 8 i k , -
205 * 28 h y 6 7 u j m n
206 * 30 - bs num del - \ ent sp
207 * 38 g t 5 4 r f v b
208 * 40 - - - 3 e d c right
209 * 48 - - - 2 w s x down
210 * 50 esc tab ~ 1 q a z -
211 * 58 menu Ls Lc Rc La Ra Rs -
212 */
213
214 if (d->d0 != 0 || d->d1 != 0 || d->d2 != 0 ||
215 d->d3 != 0 || d->d4 != 0 || d->d5 != 0)
216 keychange = 1;
217
218 /* Release all keys: */
219 if (!d->dont_clear_next) {
220 d->d0 = d->d1 = d->d2 = d->d3 = d->d4 = d->d5 = 0;
221 } else
222 d->dont_clear_next = 0;
223
224 if (console_charavail(d->kiu_console_handle)) {
225 char ch = console_readchar(d->kiu_console_handle);
226
227 if (d->escape_state > 0) {
228 switch (d->escape_state) {
229 case 1: /* expecting a [ */
230 d->escape_state = 0;
231 if (ch == '[')
232 d->escape_state = 2;
233 break;
234 case 2: /* cursor keys etc: */
235 /* Ugly hack for Mobilepro770: */
236 if (cpu->machine->machine_subtype ==
237 MACHINE_HPCMIPS_NEC_MOBILEPRO_770) {
238 switch (ch) {
239 case 'A': d->d0 = 0x2000; break;
240 case 'B': d->d0 = 0x20; break;
241 case 'C': d->d0 = 0x1000; break;
242 case 'D': d->d0 = 0x10; break;
243 default: fatal("[ vr41xx kiu: unimpl"
244 "emented escape 0x%02 ]\n", ch);
245 }
246 } else {
247 switch (ch) {
248 case 'A': d->d0 = 0x1000; break;
249 case 'B': d->d0 = 0x2000; break;
250 case 'C': d->d0 = 0x20; break;
251 case 'D': d->d0 = 0x10; break;
252 default: fatal("[ vr41xx kiu: unimpl"
253 "emented escape 0x%02 ]\n", ch);
254 }
255 }
256 d->escape_state = 0;
257 }
258 } else switch (ch) {
259 case '+': console_makeavail(d->kiu_console_handle, '=');
260 d->d5 = 0x800; break;
261 case '_': console_makeavail(d->kiu_console_handle, '-');
262 d->d5 = 0x800; break;
263 case '<': console_makeavail(d->kiu_console_handle, ',');
264 d->d5 = 0x800; break;
265 case '>': console_makeavail(d->kiu_console_handle, '.');
266 d->d5 = 0x800; break;
267 case '{': console_makeavail(d->kiu_console_handle, '[');
268 d->d5 = 0x800; break;
269 case '}': console_makeavail(d->kiu_console_handle, ']');
270 d->d5 = 0x800; break;
271 case ':': console_makeavail(d->kiu_console_handle, ';');
272 d->d5 = 0x800; break;
273 case '"': console_makeavail(d->kiu_console_handle, '\'');
274 d->d5 = 0x800; break;
275 case '|': console_makeavail(d->kiu_console_handle, '\\');
276 d->d5 = 0x800; break;
277 case '?': console_makeavail(d->kiu_console_handle, '/');
278 d->d5 = 0x800; break;
279
280 case '!': console_makeavail(d->kiu_console_handle, '1');
281 d->d5 = 0x800; break;
282 case '@': console_makeavail(d->kiu_console_handle, '2');
283 d->d5 = 0x800; break;
284 case '#': console_makeavail(d->kiu_console_handle, '3');
285 d->d5 = 0x800; break;
286 case '$': console_makeavail(d->kiu_console_handle, '4');
287 d->d5 = 0x800; break;
288 case '%': console_makeavail(d->kiu_console_handle, '5');
289 d->d5 = 0x800; break;
290 case '^': console_makeavail(d->kiu_console_handle, '6');
291 d->d5 = 0x800; break;
292 case '&': console_makeavail(d->kiu_console_handle, '7');
293 d->d5 = 0x800; break;
294 case '*': console_makeavail(d->kiu_console_handle, '8');
295 d->d5 = 0x800; break;
296 case '(': console_makeavail(d->kiu_console_handle, '9');
297 d->d5 = 0x800; break;
298 case ')': console_makeavail(d->kiu_console_handle, '0');
299 d->d5 = 0x800; break;
300
301 case '1': d->d3 = 0x80; break;
302 case '2': d->d3 = 0x40; break;
303 case '3': d->d3 = 0x20; break;
304 case '4': d->d3 = 0x10; break;
305 case '5': d->d2 = 0x08; break;
306 case '6': d->d2 = 0x04; break;
307 case '7': d->d2 = 0x02; break;
308 case '8': d->d2 = 0x01; break;
309 case '9': d->d2 = 0x8000; break;
310 case '0': d->d2 = 0x4000; break;
311
312 case ';': d->d0 = 0x800; break;
313 case '\'': d->d0 = 0x400; break;
314 case '[': d->d0 = 0x200; break;
315 case '/': d->d0 = 0x8; break;
316 case '\\': d->d0 = 0x4; break;
317 case ']': d->d0 = 0x2; break;
318
319 case 'a': d->d1 = 0x8000; break;
320 case 'b': d->d2 = 0x800; break;
321 case 'c': d->d1 = 0x20; break;
322 case 'd': d->d1 = 0x2000; break;
323 case 'e': d->d2 = 0x20; break;
324 case 'f': d->d1 = 0x1000; break;
325 case 'g': d->d3 = 0x8; break;
326 case 'h': d->d3 = 0x4; break;
327 case 'i': d->d3 = 0x100; break;
328 case 'j': d->d3 = 0x2; break;
329 case 'k': d->d3 = 0x1; break;
330 case 'l': d->d0 = 0x80; break;
331 case 'm': d->d2 = 0x200; break;
332 case 'n': d->d2 = 0x400; break;
333 case 'o': d->d0 = 0x8000; break;
334 case 'p': d->d4 = 0x20; break;
335 case 'q': d->d2 = 0x80; break;
336 case 'r': d->d2 = 0x10; break;
337 case 's': d->d1 = 0x4000; break;
338 case 't': d->d3 = 0x800; break;
339 case 'u': d->d3 = 0x200; break;
340 case 'v': d->d1 = 0x10; break;
341 case 'w': d->d2 = 0x40; break;
342 case 'x': d->d1 = 0x40; break;
343 case 'y': d->d3 = 0x400; break;
344 case 'z': d->d1 = 0x80; break;
345
346 case ',': d->d2 = 0x100; break;
347 case '.': d->d0 = 0x4000; break;
348 case '-': d->d1 = 0x400; break;
349 case '=': d->d1 = 0x200; break;
350
351 case '\r':
352 case '\n': d->d0 = 0x40; break;
353 case ' ': d->d0 = 0x01; break;
354 case '\b': d->d4 = 0x10; break;
355
356 case 27: d->escape_state = 1; break;
357
358 default:
359 /* Shifted: */
360 if (ch >= 'A' && ch <= 'Z') {
361 console_makeavail(d->kiu_console_handle,
362 ch + 32);
363 d->d5 = 0x800;
364 d->dont_clear_next = 1;
365 break;
366 }
367
368 /* CTRLed: */
369 if (ch >= 1 && ch <= 26) {
370 console_makeavail(d->kiu_console_handle,
371 ch + 96);
372 d->d5 = 0x4;
373 d->dont_clear_next = 1;
374 break;
375 }
376 }
377
378 if (d->escape_state == 0)
379 keychange = 1;
380 }
381
382 if (keychange) {
383 /* 4=lost data, 2=data complete, 1=key input detected */
384 d->kiu_int_assert |= 3;
385 recalc_kiu_int_assert(cpu, d);
386 }
387 }
388
389
390 /*
391 * timer_tick():
392 */
timer_tick(struct timer * timer,void * extra)393 static void timer_tick(struct timer *timer, void *extra)
394 {
395 struct vr41xx_data *d = (struct vr41xx_data *) extra;
396 d->pending_timer_interrupts ++;
397 }
398
399
DEVICE_TICK(vr41xx)400 DEVICE_TICK(vr41xx)
401 {
402 struct vr41xx_data *d = (struct vr41xx_data *) extra;
403
404 if (d->pending_timer_interrupts > 0)
405 INTERRUPT_ASSERT(d->timer_irq);
406
407 if (cpu->machine->x11_md.in_use)
408 vr41xx_keytick(cpu, d);
409 }
410
411
412 /*
413 * vr41xx_kiu():
414 *
415 * Keyboard Interface Unit. Return value is "odata".
416 * (See NetBSD's vrkiu.c for more info.)
417 */
vr41xx_kiu(struct cpu * cpu,int ofs,uint64_t idata,int writeflag,struct vr41xx_data * d)418 static uint64_t vr41xx_kiu(struct cpu *cpu, int ofs, uint64_t idata,
419 int writeflag, struct vr41xx_data *d)
420 {
421 uint64_t odata = 0;
422
423 switch (ofs) {
424 case KIUDAT0:
425 odata = d->d0; break;
426 case KIUDAT1:
427 odata = d->d1; break;
428 case KIUDAT2:
429 odata = d->d2; break;
430 case KIUDAT3:
431 odata = d->d3; break;
432 case KIUDAT4:
433 odata = d->d4; break;
434 case KIUDAT5:
435 odata = d->d5; break;
436 case KIUSCANREP:
437 if (writeflag == MEM_WRITE) {
438 debug("[ vr41xx KIU: setting KIUSCANREP to 0x%04x ]\n",
439 (int)idata);
440 /* TODO */
441 } else
442 fatal("[ vr41xx KIU: unimplemented read from "
443 "KIUSCANREP ]\n");
444 break;
445 case KIUSCANS:
446 if (writeflag == MEM_WRITE) {
447 debug("[ vr41xx KIU: write to KIUSCANS: 0x%04x: TODO"
448 " ]\n", (int)idata);
449 /* TODO */
450 } else
451 debug("[ vr41xx KIU: unimplemented read from "
452 "KIUSCANS ]\n");
453 break;
454 case KIUINT:
455 /* Interrupt. A wild guess: zero-on-write */
456 if (writeflag == MEM_WRITE) {
457 d->kiu_int_assert &= ~idata;
458 } else {
459 odata = d->kiu_int_assert;
460 }
461 recalc_kiu_int_assert(cpu, d);
462 break;
463 case KIURST:
464 /* Reset. */
465 break;
466 default:
467 if (writeflag == MEM_WRITE)
468 debug("[ vr41xx KIU: unimplemented write to offset "
469 "0x%x, data=0x%016" PRIx64" ]\n", ofs,
470 (uint64_t) idata);
471 else
472 debug("[ vr41xx KIU: unimplemented read from offset "
473 "0x%x ]\n", ofs);
474 }
475
476 return odata;
477 }
478
479
DEVICE_ACCESS(vr41xx)480 DEVICE_ACCESS(vr41xx)
481 {
482 struct vr41xx_data *d = (struct vr41xx_data *) extra;
483 uint64_t idata = 0, odata = 0;
484 int revision = 0;
485
486 if (writeflag == MEM_WRITE)
487 idata = memory_readmax64(cpu, data, len);
488
489 // int regnr = relative_addr / sizeof(uint64_t);
490
491 /* KIU ("Keyboard Interface Unit") is handled separately. */
492 if (relative_addr >= d->kiu_offset &&
493 relative_addr < d->kiu_offset + 0x20) {
494 odata = vr41xx_kiu(cpu, relative_addr - d->kiu_offset,
495 idata, writeflag, d);
496 goto ret;
497 }
498
499 /* TODO: Maybe these should be handled separately as well? */
500
501 switch (relative_addr) {
502
503 /* BCU: 0x00 .. 0x1c */
504 case BCUREVID_REG_W: /* 0x010 */
505 case BCU81REVID_REG_W: /* 0x014 */
506 /*
507 * TODO? Linux seems to read 0x14. The lowest bits are
508 * a divisor for PClock, bits 8 and up seem to be a
509 * divisor for VTClock (relative to PClock?)...
510 */
511 switch (d->cpumodel) {
512 case 4131: revision = BCUREVID_RID_4131; break;
513 case 4122: revision = BCUREVID_RID_4122; break;
514 case 4121: revision = BCUREVID_RID_4121; break;
515 case 4111: revision = BCUREVID_RID_4111; break;
516 case 4102: revision = BCUREVID_RID_4102; break;
517 case 4101: revision = BCUREVID_RID_4101; break;
518 case 4181: revision = BCUREVID_RID_4181; break;
519 }
520 odata = (revision << BCUREVID_RIDSHFT) | 0x020c;
521 break;
522 case BCU81CLKSPEED_REG_W: /* 0x018 */
523 /*
524 * TODO: Implement this for ALL cpu types:
525 */
526 odata = BCUCLKSPEED_DIVT4 << BCUCLKSPEED_DIVTSHFT;
527 break;
528
529 /* DMAAU: 0x20 .. 0x3c */
530
531 /* DCU: 0x40 .. 0x5c */
532
533 /* CMU: 0x60 .. 0x7c */
534
535 /* ICU: 0x80 .. 0xbc */
536 case 0x80: /* Level 1 system interrupt reg 1... */
537 if (writeflag == MEM_READ)
538 odata = d->sysint1;
539 else {
540 /* TODO: clear-on-write-one? */
541 d->sysint1 &= ~idata;
542 d->sysint1 &= 0xffff;
543 }
544 break;
545 case 0x88:
546 if (writeflag == MEM_READ)
547 odata = d->giuint;
548 else
549 d->giuint &= ~idata;
550 break;
551 case 0x8c:
552 if (writeflag == MEM_READ)
553 odata = d->msysint1;
554 else
555 d->msysint1 = idata;
556 break;
557 case 0x94:
558 if (writeflag == MEM_READ)
559 odata = d->giumask;
560 else
561 d->giumask = idata;
562 break;
563 case 0xa0: /* Level 1 system interrupt reg 2... */
564 if (writeflag == MEM_READ)
565 odata = d->sysint2;
566 else {
567 /* TODO: clear-on-write-one? */
568 d->sysint2 &= ~idata;
569 d->sysint2 &= 0xffff;
570 }
571 break;
572 case 0xa6:
573 if (writeflag == MEM_READ)
574 odata = d->msysint2;
575 else
576 d->msysint2 = idata;
577 break;
578
579 /* RTC: */
580 case 0xc0:
581 case 0xc2:
582 case 0xc4:
583 {
584 struct timeval tv;
585 gettimeofday(&tv, NULL);
586 /* Adjust time by 120 years and 29 days. */
587 tv.tv_sec += (int64_t) (120*365 + 29) * 24*60*60;
588
589 switch (relative_addr) {
590 case 0xc0:
591 odata = (tv.tv_sec & 1) << 15;
592 odata += (uint64_t)tv.tv_usec * 32768 / 1000000;
593 break;
594 case 0xc2:
595 odata = (tv.tv_sec >> 1) & 0xffff;
596 break;
597 case 0xc4:
598 odata = (tv.tv_sec >> 17) & 0xffff;
599 break;
600 }
601 }
602 break;
603
604 case 0xd0: /* RTCL1_L_REG_W */
605 if (writeflag == MEM_WRITE && idata != 0) {
606 int hz = RTCL1_L_HZ / idata;
607 debug("[ vr41xx: rtc interrupts at %i Hz ]\n", hz);
608 if (d->timer == NULL)
609 d->timer = timer_add(hz, timer_tick, d);
610 else
611 timer_update_frequency(d->timer, hz);
612 }
613 break;
614 case 0xd2: /* RTCL1_H_REG_W */
615 break;
616
617 case 0x108:
618 if (writeflag == MEM_READ)
619 odata = d->giuint;
620 else
621 d->giuint &= ~idata;
622 break;
623 /* case 0x10a:
624 "High" part of GIU?
625 break;
626 */
627
628 case 0x13e: /* on 4181? */
629 case 0x1de: /* on 4121? */
630 /* RTC interrupt register... */
631 /* Ack. timer interrupts? */
632 INTERRUPT_DEASSERT(d->timer_irq);
633 if (d->pending_timer_interrupts > 0)
634 d->pending_timer_interrupts --;
635 break;
636
637 default:
638 if (writeflag == MEM_WRITE)
639 debug("[ vr41xx: unimplemented write to address "
640 "0x%" PRIx64", data=0x%016" PRIx64" ]\n",
641 (uint64_t) relative_addr, (uint64_t) idata);
642 else
643 debug("[ vr41xx: unimplemented read from address "
644 "0x%" PRIx64" ]\n", (uint64_t) relative_addr);
645 }
646
647 ret:
648 /*
649 * Recalculate interrupt assertions:
650 */
651 if (d->giuint & d->giumask)
652 INTERRUPT_ASSERT(d->giu_irq);
653 else
654 INTERRUPT_DEASSERT(d->giu_irq);
655 if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2))
656 INTERRUPT_ASSERT(d->cpu_irq);
657 else
658 INTERRUPT_DEASSERT(d->cpu_irq);
659
660 if (writeflag == MEM_READ)
661 memory_writemax64(cpu, data, len, odata);
662
663 return 1;
664 }
665
666
667 /*
668 * dev_vr41xx_init():
669 *
670 * machine->path is something like "machine[0]".
671 */
dev_vr41xx_init(struct machine * machine,struct memory * mem,int cpumodel)672 struct vr41xx_data *dev_vr41xx_init(struct machine *machine,
673 struct memory *mem, int cpumodel)
674 {
675 struct vr41xx_data *d;
676 uint64_t baseaddr = 0;
677 char tmps[300];
678 int i;
679
680 CHECK_ALLOCATION(d = (struct vr41xx_data *) malloc(sizeof(struct vr41xx_data)));
681 memset(d, 0, sizeof(struct vr41xx_data));
682
683 /* Connect to MIPS irq 2: */
684 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].2",
685 machine->path, machine->bootstrap_cpu);
686 INTERRUPT_CONNECT(tmps, d->cpu_irq);
687
688 /*
689 * Register VRIP interrupt lines 0..25:
690 */
691 for (i=0; i<=25; i++) {
692 struct interrupt templ;
693 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
694 machine->path, machine->bootstrap_cpu, i);
695 memset(&templ, 0, sizeof(templ));
696 templ.line = i;
697 templ.name = tmps;
698 templ.extra = d;
699 templ.interrupt_assert = vr41xx_vrip_interrupt_assert;
700 templ.interrupt_deassert = vr41xx_vrip_interrupt_deassert;
701 interrupt_handler_register(&templ);
702 }
703
704 /*
705 * Register GIU interrupt lines 0..31:
706 */
707 for (i=0; i<32; i++) {
708 struct interrupt templ;
709 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i.giu.%i",
710 machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU, i);
711 memset(&templ, 0, sizeof(templ));
712 templ.line = i;
713 templ.name = tmps;
714 templ.extra = d;
715 templ.interrupt_assert = vr41xx_giu_interrupt_assert;
716 templ.interrupt_deassert = vr41xx_giu_interrupt_deassert;
717 interrupt_handler_register(&templ);
718 }
719
720 d->cpumodel = cpumodel;
721
722 /* TODO: VRC4173 has the KIU at offset 0x100? */
723 d->kiu_offset = 0x180;
724 d->kiu_console_handle = -1;
725 if (machine->x11_md.in_use)
726 d->kiu_console_handle = console_start_slave_inputonly(
727 machine, "kiu", 1);
728
729 /* Connect to the KIU and GIU interrupts: */
730 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
731 machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU);
732 INTERRUPT_CONNECT(tmps, d->giu_irq);
733 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
734 machine->path, machine->bootstrap_cpu, VRIP_INTR_KIU);
735 INTERRUPT_CONNECT(tmps, d->kiu_irq);
736
737 if (machine->x11_md.in_use)
738 machine->main_console_handle = d->kiu_console_handle;
739
740 switch (cpumodel) {
741 case 4101:
742 case 4102:
743 case 4111:
744 case 4121:
745 baseaddr = 0xb000000;
746 break;
747 case 4181:
748 baseaddr = 0xa000000;
749 dev_ram_init(machine, 0xb000000, 0x1000000, DEV_RAM_MIRROR,
750 0xa000000);
751 break;
752 case 4122:
753 case 4131:
754 baseaddr = 0xf000000;
755 break;
756 default:
757 printf("Unimplemented VR cpu model\n");
758 exit(1);
759 }
760
761 if (d->cpumodel == 4121 || d->cpumodel == 4181)
762 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].3",
763 machine->path, machine->bootstrap_cpu);
764 else
765 snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i",
766 machine->path, machine->bootstrap_cpu, VRIP_INTR_ETIMER);
767 INTERRUPT_CONNECT(tmps, d->timer_irq);
768
769 memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH,
770 dev_vr41xx_access, (void *)d, DM_DEFAULT, NULL);
771
772 /*
773 * TODO: Find out which controllers are at which addresses on
774 * which chips.
775 */
776 if (cpumodel == 4131) {
777 snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i].vrip.%i "
778 "addr=0x%" PRIx64" name2=siu", machine->path,
779 machine->bootstrap_cpu, VRIP_INTR_SIU,
780 (uint64_t) (baseaddr+0x800));
781 device_add(machine, tmps);
782 } else {
783 /* This is used by Linux and NetBSD: */
784 snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i]."
785 "vrip.%i addr=0x%x name2=serial", machine->path,
786 machine->bootstrap_cpu, VRIP_INTR_SIU, 0xc000000);
787 device_add(machine, tmps);
788 }
789
790 /* Hm... maybe this should not be here. TODO */
791 snprintf(tmps, sizeof(tmps), "pcic irq=%s.cpu[%i].vrip.%i addr="
792 "0x140003e0", machine->path, machine->bootstrap_cpu,
793 VRIP_INTR_GIU);
794 device_add(machine, tmps);
795
796 machine_add_tickfunction(machine, dev_vr41xx_tick, d,
797 DEV_VR41XX_TICKSHIFT);
798
799 /* Some machines (?) use ISA space at 0x15000000 instead of
800 0x14000000, eg IBM WorkPad Z50. */
801 dev_ram_init(machine, 0x15000000, 0x1000000, DEV_RAM_MIRROR,
802 0x14000000);
803
804 return d;
805 }
806
807