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