25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_footbridge.c,v 1.26 2005/10/26 14:37:04 debug Exp $ |
* $Id: dev_footbridge.c,v 1.36 2005/11/21 09:17:26 debug Exp $ |
29 |
* |
* |
30 |
* Footbridge. Used in Netwinder and Cats. |
* Footbridge. Used in Netwinder and Cats. |
31 |
* |
* |
32 |
* TODO: Most things. For example: |
* TODO: |
|
* |
|
|
* o) Fix the timer TODO (see below). |
|
|
* |
|
33 |
* o) Add actual support for the fcom serial port. |
* o) Add actual support for the fcom serial port. |
|
* |
|
34 |
* o) FIQs. |
* o) FIQs. |
|
* |
|
|
* o) .. |
|
35 |
*/ |
*/ |
36 |
|
|
37 |
#include <stdio.h> |
#include <stdio.h> |
101 |
/* |
/* |
102 |
* dev_footbridge_isa_access(): |
* dev_footbridge_isa_access(): |
103 |
* |
* |
104 |
* NetBSD seems to read 0x79000000 to find out which ISA interrupt occurred, |
* Reading the byte at 0x79000000 is a quicker way to figure out which ISA |
105 |
* a quicker way than dealing with legacy 0x20/0xa0 ISA ports. |
* interrupt has occurred (and acknowledging it at the same time), than |
106 |
|
* dealing with the legacy 0x20/0xa0 ISA ports. |
107 |
*/ |
*/ |
108 |
int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem, |
int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem, |
109 |
uint64_t relative_addr, unsigned char *data, size_t len, |
uint64_t relative_addr, unsigned char *data, size_t len, |
118 |
fatal("[ footbridge_isa: WARNING/TODO: write! ]\n"); |
fatal("[ footbridge_isa: WARNING/TODO: write! ]\n"); |
119 |
} |
} |
120 |
|
|
121 |
/* |
x = cpu->machine->isa_pic_data.last_int; |
122 |
* NetBSD seems to want a value of 0x20 + x, where x is the highest |
if (x == 0) |
123 |
* priority ISA interrupt which is currently asserted and not masked. |
cpu_interrupt_ack(cpu, 32 + x); |
124 |
*/ |
|
125 |
|
if (x < 8) |
126 |
for (x=0; x<16; x++) { |
odata = cpu->machine->isa_pic_data.pic1->irq_base + x; |
127 |
if (x == 2) |
else |
128 |
continue; |
odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8; |
|
if (x < 8 && (cpu->machine->isa_pic_data.pic1->irr & |
|
|
~cpu->machine->isa_pic_data.pic1->ier & |
|
|
(1 << x))) |
|
|
break; |
|
|
if (x >= 8 && (cpu->machine->isa_pic_data.pic2->irr & |
|
|
~cpu->machine->isa_pic_data.pic2->ier & |
|
|
(1 << (x&7)))) |
|
|
break; |
|
|
} |
|
|
|
|
|
if (x == 16) |
|
|
fatal("_\n_ SPORADIC but INVALID ISA interrupt\n_\n"); |
|
|
|
|
|
odata = 0x20 + (x & 15); |
|
129 |
|
|
130 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
131 |
memory_writemax64(cpu, data, len, odata); |
memory_writemax64(cpu, data, len, odata); |
177 |
pci_word = relative_addr & 0x00ffffff; |
pci_word = relative_addr & 0x00ffffff; |
178 |
|
|
179 |
res = bus_pci_access(cpu, mem, BUS_PCI_ADDR, |
res = bus_pci_access(cpu, mem, BUS_PCI_ADDR, |
180 |
&pci_word, MEM_WRITE, d->pcibus); |
&pci_word, sizeof(uint32_t), MEM_WRITE, d->pcibus); |
181 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
182 |
res = bus_pci_access(cpu, mem, BUS_PCI_DATA, |
res = bus_pci_access(cpu, mem, BUS_PCI_DATA, |
183 |
&pci_word, MEM_READ, d->pcibus); |
&pci_word, len, MEM_READ, d->pcibus); |
184 |
odata = pci_word; |
odata = pci_word; |
185 |
} else { |
} else { |
186 |
pci_word = idata; |
pci_word = idata; |
187 |
res = bus_pci_access(cpu, mem, BUS_PCI_DATA, |
res = bus_pci_access(cpu, mem, BUS_PCI_DATA, |
188 |
&pci_word, MEM_WRITE, d->pcibus); |
&pci_word, len, MEM_WRITE, d->pcibus); |
189 |
} |
} |
190 |
|
|
191 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
226 |
odata = 0x1065; /* DC21285_DEVICE_ID */ |
odata = 0x1065; /* DC21285_DEVICE_ID */ |
227 |
break; |
break; |
228 |
|
|
229 |
|
case 0x04: |
230 |
|
case 0x0c: |
231 |
|
case 0x10: |
232 |
|
case 0x14: |
233 |
|
case 0x18: |
234 |
|
/* TODO. Written to by Linux. */ |
235 |
|
break; |
236 |
|
|
237 |
case REVISION: |
case REVISION: |
238 |
odata = 3; /* footbridge revision number */ |
odata = 3; /* footbridge revision number */ |
239 |
break; |
break; |
240 |
|
|
241 |
|
case PCI_ADDRESS_EXTENSION: |
242 |
|
/* TODO: Written to by Linux. */ |
243 |
|
if (writeflag == MEM_WRITE && idata != 0) |
244 |
|
fatal("[ footbridge: TODO: write to PCI_ADDRESS_" |
245 |
|
"EXTENSION: 0x%llx ]\n", (long long)idata); |
246 |
|
break; |
247 |
|
|
248 |
case UART_DATA: |
case UART_DATA: |
249 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
250 |
console_putchar(d->console_handle, idata); |
console_putchar(d->console_handle, idata); |
345 |
case TIMER_1_VALUE: |
case TIMER_1_VALUE: |
346 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
347 |
/* |
/* |
348 |
* TODO: This is INCORRECT! but speeds up NetBSD |
* NOTE/TODO: This is INCORRECT but speeds up NetBSD |
349 |
* and OpenBSD boot sequences. A better solution |
* and OpenBSD boot sequences: if the timer is polled |
350 |
* would be to only call dev_footbridge_tick() if |
* "very often" (such as during bootup), then this |
351 |
* the timer is polled "very often" (such as during |
* causes the timers to expire quickly. |
|
* bootup), but not during normal operation. |
|
352 |
*/ |
*/ |
353 |
d->timer_being_read = 1; |
d->timer_being_read = 1; |
354 |
d->timer_poll_mode ++; |
d->timer_poll_mode ++; |
355 |
if (d->timer_poll_mode > TIMER_POLL_THRESHOLD) |
if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) { |
356 |
|
d->timer_poll_mode = TIMER_POLL_THRESHOLD; |
357 |
dev_footbridge_tick(cpu, d); |
dev_footbridge_tick(cpu, d); |
358 |
|
dev_footbridge_tick(cpu, d); |
359 |
|
dev_footbridge_tick(cpu, d); |
360 |
|
} |
361 |
odata = d->timer_value[timer_nr]; |
odata = d->timer_value[timer_nr]; |
362 |
d->timer_being_read = 0; |
d->timer_being_read = 0; |
363 |
} else |
} else |
427 |
/* DC21285 register access: */ |
/* DC21285 register access: */ |
428 |
memory_device_register(devinit->machine->memory, devinit->name, |
memory_device_register(devinit->machine->memory, devinit->name, |
429 |
devinit->addr, DEV_FOOTBRIDGE_LENGTH, |
devinit->addr, DEV_FOOTBRIDGE_LENGTH, |
430 |
dev_footbridge_access, d, MEM_DEFAULT, NULL); |
dev_footbridge_access, d, DM_DEFAULT, NULL); |
431 |
|
|
432 |
/* ISA interrupt status word: */ |
/* ISA interrupt status/acknowledgement: */ |
433 |
memory_device_register(devinit->machine->memory, "footbridge_isa", |
memory_device_register(devinit->machine->memory, "footbridge_isa", |
434 |
0x79000000, 8, dev_footbridge_isa_access, d, MEM_DEFAULT, NULL); |
0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL); |
435 |
|
|
436 |
/* The "fcom" console: */ |
/* The "fcom" console: */ |
437 |
d->console_handle = console_start_slave(devinit->machine, "fcom"); |
d->console_handle = console_start_slave(devinit->machine, "fcom"); |
438 |
|
|
439 |
/* A PCI bus: */ |
/* A PCI bus: */ |
440 |
d->pcibus = bus_pci_init(devinit->irq_nr); |
d->pcibus = bus_pci_init( |
441 |
|
devinit->irq_nr, /* PCI controller irq */ |
442 |
|
0x7c000000, /* PCI device io offset */ |
443 |
|
0x80000000, /* PCI device mem offset */ |
444 |
|
0x00000000, /* PCI port base */ |
445 |
|
0x00000000, /* PCI mem base */ |
446 |
|
0, /* PCI irq base: TODO */ |
447 |
|
0x7c000000, /* ISA port base */ |
448 |
|
0x80000000, /* ISA mem base */ |
449 |
|
32); /* ISA port base */ |
450 |
|
|
451 |
/* ... with some default devices for known machine types: */ |
/* ... with some default devices for known machine types: */ |
452 |
switch (devinit->machine->machine_type) { |
switch (devinit->machine->machine_type) { |
453 |
case MACHINE_CATS: |
case MACHINE_CATS: |
454 |
bus_pci_add(devinit->machine, d->pcibus, |
bus_pci_add(devinit->machine, d->pcibus, |
455 |
devinit->machine->memory, 0xc0, 7, 0, |
devinit->machine->memory, 0xc0, 7, 0, "ali_m1543"); |
456 |
pci_ali_m1543_init, pci_ali_m1543_rr); |
bus_pci_add(devinit->machine, d->pcibus, |
457 |
/* bus_pci_add(devinit->machine, d->pcibus, |
devinit->machine->memory, 0xc0, 10, 0, "dec21143"); |
|
devinit->machine->memory, 0xc0, 10, 0, |
|
|
pci_dec21143_init, pci_dec21143_rr); */ |
|
458 |
bus_pci_add(devinit->machine, d->pcibus, |
bus_pci_add(devinit->machine, d->pcibus, |
459 |
devinit->machine->memory, 0xc0, 16, 0, |
devinit->machine->memory, 0xc0, 16, 0, "ali_m5229"); |
|
pci_ali_m5229_init, pci_ali_m5229_rr); |
|
460 |
break; |
break; |
461 |
case MACHINE_NETWINDER: |
case MACHINE_NETWINDER: |
462 |
bus_pci_add(devinit->machine, d->pcibus, |
bus_pci_add(devinit->machine, d->pcibus, |
463 |
devinit->machine->memory, 0xc0, 11, 0, |
devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553"); |
|
pci_symphony_83c553_init, pci_symphony_83c553_rr); |
|
464 |
bus_pci_add(devinit->machine, d->pcibus, |
bus_pci_add(devinit->machine, d->pcibus, |
465 |
devinit->machine->memory, 0xc0, 11, 1, |
devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105"); |
|
pci_symphony_82c105_init, pci_symphony_82c105_rr); |
|
466 |
break; |
break; |
467 |
default:fatal("footbridge: unimplemented machine type.\n"); |
default:fatal("footbridge: unimplemented machine type.\n"); |
468 |
exit(1); |
exit(1); |
471 |
/* PCI configuration space: */ |
/* PCI configuration space: */ |
472 |
memory_device_register(devinit->machine->memory, |
memory_device_register(devinit->machine->memory, |
473 |
"footbridge_pci", pci_addr, 0x1000000, |
"footbridge_pci", pci_addr, 0x1000000, |
474 |
dev_footbridge_pci_access, d, MEM_DEFAULT, NULL); |
dev_footbridge_pci_access, d, DM_DEFAULT, NULL); |
475 |
|
|
476 |
/* Timer ticks: */ |
/* Timer ticks: */ |
477 |
for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) { |
for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) { |