1 |
/* |
/* |
2 |
* Copyright (C) 2004-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2004-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_vr41xx.c,v 1.30 2005/08/05 09:11:48 debug Exp $ |
* $Id: dev_vr41xx.c,v 1.41 2006/10/02 09:26:53 debug Exp $ |
29 |
* |
* |
30 |
* VR41xx (actually, VR4122 and VR4131) misc functions. |
* VR41xx (actually, VR4122 and VR4131) misc functions. |
31 |
* |
* |
43 |
#include "machine.h" |
#include "machine.h" |
44 |
#include "memory.h" |
#include "memory.h" |
45 |
#include "misc.h" |
#include "misc.h" |
46 |
|
#include "timer.h" |
47 |
|
|
48 |
#include "bcureg.h" |
#include "bcureg.h" |
49 |
#include "vripreg.h" |
#include "vripreg.h" |
50 |
#include "vrkiureg.h" |
#include "vrkiureg.h" |
51 |
|
#include "vr_rtcreg.h" |
52 |
|
|
53 |
|
|
54 |
#define DEV_VR41XX_TICKSHIFT 15 |
#define DEV_VR41XX_TICKSHIFT 14 |
55 |
|
|
56 |
/* #define debug fatal */ |
/* #define debug fatal */ |
57 |
|
|
75 |
/* |
/* |
76 |
* Keyboard input: |
* Keyboard input: |
77 |
* |
* |
78 |
* Hardcoded for MobilePro 780. (See NetBSD's hpckbdkeymap.h for |
* Hardcoded for MobilePro. (See NetBSD's hpckbdkeymap.h for |
79 |
* info on other keyboard layouts. mobilepro780_keytrans is the |
* info on other keyboard layouts. mobilepro780_keytrans is the |
80 |
* one used here.) |
* one used here.) |
81 |
* |
* |
82 |
* TODO: Make this work with "any" keyboard layout. |
* TODO: Make this work with "any" keyboard layout. |
83 |
* |
* |
|
* (Even MobilePro 770 seems to be different? Hm. TODO) |
|
|
* |
|
84 |
* ofs 0: |
* ofs 0: |
85 |
* 8000='o' 4000='.' 2000=DOWN 1000=UP |
* 8000='o' 4000='.' 2000=DOWN 1000=UP |
86 |
* 800=';' 400=''' 200='[' 100=? |
* 800=';' 400=''' 200='[' 100=? |
147 |
d->escape_state = 2; |
d->escape_state = 2; |
148 |
break; |
break; |
149 |
case 2: /* cursor keys etc: */ |
case 2: /* cursor keys etc: */ |
150 |
switch (ch) { |
/* Ugly hack for Mobilepro770: */ |
151 |
case 'A': d->d0 = 0x1000; break; |
if (cpu->machine->machine_subtype == |
152 |
case 'B': d->d0 = 0x2000; break; |
MACHINE_HPCMIPS_NEC_MOBILEPRO_770) { |
153 |
case 'C': d->d0 = 0x20; break; |
switch (ch) { |
154 |
case 'D': d->d0 = 0x10; break; |
case 'A': d->d0 = 0x2000; break; |
155 |
default: fatal("[ vr41xx kiu: " |
case 'B': d->d0 = 0x20; break; |
156 |
"unimplemented escape 0x%02 ]\n", ch); |
case 'C': d->d0 = 0x1000; break; |
157 |
|
case 'D': d->d0 = 0x10; break; |
158 |
|
default: fatal("[ vr41xx kiu: unimpl" |
159 |
|
"emented escape 0x%02 ]\n", ch); |
160 |
|
} |
161 |
|
} else { |
162 |
|
switch (ch) { |
163 |
|
case 'A': d->d0 = 0x1000; break; |
164 |
|
case 'B': d->d0 = 0x2000; break; |
165 |
|
case 'C': d->d0 = 0x20; break; |
166 |
|
case 'D': d->d0 = 0x10; break; |
167 |
|
default: fatal("[ vr41xx kiu: unimpl" |
168 |
|
"emented escape 0x%02 ]\n", ch); |
169 |
|
} |
170 |
} |
} |
171 |
d->escape_state = 0; |
d->escape_state = 0; |
172 |
} |
} |
303 |
|
|
304 |
|
|
305 |
/* |
/* |
306 |
* dev_vr41xx_tick(): |
* timer_tick(): |
307 |
*/ |
*/ |
308 |
void dev_vr41xx_tick(struct cpu *cpu, void *extra) |
static void timer_tick(struct timer *timer, void *extra) |
309 |
|
{ |
310 |
|
struct vr41xx_data *d = (struct vr41xx_data *) extra; |
311 |
|
d->pending_timer_interrupts ++; |
312 |
|
} |
313 |
|
|
314 |
|
|
315 |
|
DEVICE_TICK(vr41xx) |
316 |
{ |
{ |
317 |
struct vr41xx_data *d = extra; |
struct vr41xx_data *d = extra; |
318 |
|
|
319 |
/* |
if (d->pending_timer_interrupts > 0) { |
320 |
* UGLY! TODO: fix this. |
if (d->cpumodel == 4121 || d->cpumodel == 4181) |
321 |
* |
cpu_interrupt(cpu, 3); |
322 |
* Interrupts should be triggered if the corresponding unit (for |
else |
323 |
* example the RTC unit) is activated. |
cpu_interrupt(cpu, 8 + VRIP_INTR_ETIMER); |
|
*/ |
|
|
{ |
|
|
static unsigned int x = 0; |
|
|
x++; |
|
|
|
|
|
if (x > 100 && (x&3)==0) { |
|
|
if (d->cpumodel == 4121 || d->cpumodel == 4181) |
|
|
cpu_interrupt(cpu, 3); |
|
|
else |
|
|
cpu_interrupt(cpu, 8 + VRIP_INTR_ETIMER); |
|
|
} |
|
324 |
} |
} |
325 |
|
|
326 |
if (cpu->machine->use_x11) |
if (cpu->machine->use_x11) |
385 |
default: |
default: |
386 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
387 |
debug("[ vr41xx KIU: unimplemented write to offset " |
debug("[ vr41xx KIU: unimplemented write to offset " |
388 |
"0x%x, data=0x%016llx ]\n", ofs, (long long)idata); |
"0x%x, data=0x%016"PRIx64" ]\n", ofs, |
389 |
|
(uint64_t) idata); |
390 |
else |
else |
391 |
debug("[ vr41xx KIU: unimplemented read from offset " |
debug("[ vr41xx KIU: unimplemented read from offset " |
392 |
"0x%x ]\n", ofs); |
"0x%x ]\n", ofs); |
396 |
} |
} |
397 |
|
|
398 |
|
|
399 |
/* |
DEVICE_ACCESS(vr41xx) |
|
* dev_vr41xx_access(): |
|
|
*/ |
|
|
int dev_vr41xx_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
400 |
{ |
{ |
401 |
struct vr41xx_data *d = (struct vr41xx_data *) extra; |
struct vr41xx_data *d = (struct vr41xx_data *) extra; |
402 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
403 |
int regnr; |
int regnr; |
404 |
int revision = 0; |
int revision = 0; |
405 |
|
|
406 |
idata = memory_readmax64(cpu, data, len); |
if (writeflag == MEM_WRITE) |
407 |
|
idata = memory_readmax64(cpu, data, len); |
408 |
|
|
409 |
regnr = relative_addr / sizeof(uint64_t); |
regnr = relative_addr / sizeof(uint64_t); |
410 |
|
|
411 |
/* KIU ("Keyboard Interface Unit") is handled separately. */ |
/* KIU ("Keyboard Interface Unit") is handled separately. */ |
419 |
/* TODO: Maybe these should be handled separately as well? */ |
/* TODO: Maybe these should be handled separately as well? */ |
420 |
|
|
421 |
switch (relative_addr) { |
switch (relative_addr) { |
422 |
|
|
423 |
/* BCU: 0x00 .. 0x1c */ |
/* BCU: 0x00 .. 0x1c */ |
424 |
case BCUREVID_REG_W: /* 0x010 */ |
case BCUREVID_REG_W: /* 0x010 */ |
425 |
case BCU81REVID_REG_W: /* 0x014 */ |
case BCU81REVID_REG_W: /* 0x014 */ |
496 |
d->msysint2 = idata; |
d->msysint2 = idata; |
497 |
break; |
break; |
498 |
|
|
499 |
/* PMU: 0xc0 .. 0xfc */ |
/* RTC: */ |
500 |
/* RTC: 0x100 .. ? */ |
case 0xc0: |
501 |
|
case 0xc2: |
502 |
|
case 0xc4: |
503 |
|
{ |
504 |
|
struct timeval tv; |
505 |
|
gettimeofday(&tv, NULL); |
506 |
|
/* Adjust time by 120 years and 29 days. */ |
507 |
|
tv.tv_sec += (int64_t) (120*365 + 29) * 24*60*60; |
508 |
|
|
509 |
|
switch (relative_addr) { |
510 |
|
case 0xc0: |
511 |
|
odata = (tv.tv_sec & 1) << 15; |
512 |
|
break; |
513 |
|
case 0xc2: |
514 |
|
odata = (tv.tv_sec >> 1) & 0xffff; |
515 |
|
break; |
516 |
|
case 0xc4: |
517 |
|
odata = (tv.tv_sec >> 17) & 0xffff; |
518 |
|
break; |
519 |
|
} |
520 |
|
} |
521 |
|
break; |
522 |
|
|
523 |
|
case 0xd0: /* RTCL1_L_REG_W */ |
524 |
|
if (writeflag == MEM_WRITE && idata != 0) { |
525 |
|
int hz = RTCL1_L_HZ / idata; |
526 |
|
debug("[ vr41xx: rtc interrupts at %i Hz ]\n", hz); |
527 |
|
if (d->timer == NULL) |
528 |
|
d->timer = timer_add(hz, timer_tick, d); |
529 |
|
else |
530 |
|
timer_update_frequency(d->timer, hz); |
531 |
|
} |
532 |
|
break; |
533 |
|
case 0xd2: /* RTCL1_H_REG_W */ |
534 |
|
break; |
535 |
|
|
536 |
case 0x108: |
case 0x108: |
537 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
548 |
/* RTC interrupt register... */ |
/* RTC interrupt register... */ |
549 |
/* Ack. timer interrupts? */ |
/* Ack. timer interrupts? */ |
550 |
cpu_interrupt_ack(cpu, 8 + VRIP_INTR_ETIMER); |
cpu_interrupt_ack(cpu, 8 + VRIP_INTR_ETIMER); |
551 |
|
if (d->pending_timer_interrupts > 0) |
552 |
|
d->pending_timer_interrupts --; |
553 |
break; |
break; |
554 |
|
|
555 |
case 0x1de: /* on 4121? */ |
case 0x1de: /* on 4121? */ |
556 |
/* RTC interrupt register... */ |
/* RTC interrupt register... */ |
557 |
/* Ack. timer interrupts? */ |
/* Ack. timer interrupts? */ |
558 |
cpu_interrupt_ack(cpu, 3); |
cpu_interrupt_ack(cpu, 3); |
559 |
|
if (d->pending_timer_interrupts > 0) |
560 |
|
d->pending_timer_interrupts --; |
561 |
break; |
break; |
562 |
|
|
563 |
default: |
default: |
564 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
565 |
debug("[ vr41xx: unimplemented write to address " |
debug("[ vr41xx: unimplemented write to address " |
566 |
"0x%llx, data=0x%016llx ]\n", |
"0x%"PRIx64", data=0x%016"PRIx64" ]\n", |
567 |
(long long)relative_addr, (long long)idata); |
(uint64_t) relative_addr, (uint64_t) idata); |
568 |
else |
else |
569 |
debug("[ vr41xx: unimplemented read from address " |
debug("[ vr41xx: unimplemented read from address " |
570 |
"0x%llx ]\n", (long long)relative_addr); |
"0x%"PRIx64" ]\n", (uint64_t) relative_addr); |
571 |
} |
} |
572 |
|
|
573 |
ret: |
ret: |
603 |
|
|
604 |
/* TODO: VRC4173 has the KIU at offset 0x100? */ |
/* TODO: VRC4173 has the KIU at offset 0x100? */ |
605 |
d->kiu_offset = 0x180; |
d->kiu_offset = 0x180; |
606 |
d->kiu_console_handle = console_start_slave_inputonly(machine, "kiu"); |
d->kiu_console_handle = console_start_slave_inputonly( |
607 |
|
machine, "kiu", 1); |
608 |
d->kiu_irq_nr = VRIP_INTR_KIU; |
d->kiu_irq_nr = VRIP_INTR_KIU; |
609 |
|
|
610 |
switch (cpumodel) { |
switch (cpumodel) { |
616 |
break; |
break; |
617 |
case 4181: |
case 4181: |
618 |
baseaddr = 0xa000000; |
baseaddr = 0xa000000; |
619 |
dev_ram_init(mem, 0xb000000, 0x1000000, DEV_RAM_MIRROR, |
dev_ram_init(machine, 0xb000000, 0x1000000, DEV_RAM_MIRROR, |
620 |
0xa000000); |
0xa000000); |
621 |
break; |
break; |
622 |
case 4122: |
case 4122: |
629 |
} |
} |
630 |
|
|
631 |
memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH, |
memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH, |
632 |
dev_vr41xx_access, (void *)d, MEM_DEFAULT, NULL); |
dev_vr41xx_access, (void *)d, DM_DEFAULT, NULL); |
633 |
|
|
634 |
/* |
/* |
635 |
* TODO: Find out which controllers are at which addresses on |
* TODO: Find out which controllers are at which addresses on |
636 |
* which chips. |
* which chips. |
637 |
*/ |
*/ |
638 |
if (cpumodel == 4131) { |
if (cpumodel == 4131) { |
639 |
snprintf(tmps, sizeof(tmps), "ns16550 irq=%i addr=0x%llx " |
snprintf(tmps, sizeof(tmps), "ns16550 irq=%i addr=0x%"PRIx64" " |
640 |
"name2=siu", 8+VRIP_INTR_SIU, (long long)(baseaddr+0x800)); |
"name2=siu", 8+VRIP_INTR_SIU, (uint64_t) (baseaddr+0x800)); |
641 |
device_add(machine, tmps); |
device_add(machine, tmps); |
642 |
} else { |
} else { |
643 |
/* This is used by Linux and NetBSD: */ |
/* This is used by Linux and NetBSD: */ |
650 |
device_add(machine, "pcic addr=0x140003e0"); |
device_add(machine, "pcic addr=0x140003e0"); |
651 |
|
|
652 |
machine_add_tickfunction(machine, dev_vr41xx_tick, d, |
machine_add_tickfunction(machine, dev_vr41xx_tick, d, |
653 |
DEV_VR41XX_TICKSHIFT); |
DEV_VR41XX_TICKSHIFT, 0.0); |
654 |
|
|
655 |
/* Some machines (?) use ISA space at 0x15000000 instead of |
/* Some machines (?) use ISA space at 0x15000000 instead of |
656 |
0x14000000, eg IBM WorkPad Z50. */ |
0x14000000, eg IBM WorkPad Z50. */ |
657 |
dev_ram_init(mem, 0x15000000, 0x1000000, DEV_RAM_MIRROR, 0x14000000); |
dev_ram_init(machine, 0x15000000, 0x1000000, DEV_RAM_MIRROR, |
658 |
|
0x14000000); |
659 |
|
|
660 |
return d; |
return d; |
661 |
} |
} |