/[gxemul]/trunk/src/devices/dev_footbridge.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (show annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 12995 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


1 /*
2 * Copyright (C) 2005-2006 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 * $Id: dev_footbridge.c,v 1.44 2006/08/11 17:43:30 debug Exp $
29 *
30 * Footbridge. Used in Netwinder and Cats.
31 *
32 * TODO:
33 * o) Add actual support for the fcom serial port.
34 * o) FIQs.
35 * o) Pretty much everything else as well :) (This entire thing
36 * is a quick hack to work primarily with NetBSD and OpenBSD
37 * as a guest OS.)
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "bus_pci.h"
45 #include "console.h"
46 #include "cpu.h"
47 #include "device.h"
48 #include "devices.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "misc.h"
52
53
54 #include "dc21285reg.h"
55
56 #define DEV_FOOTBRIDGE_TICK_SHIFT 14
57 #define DEV_FOOTBRIDGE_LENGTH 0x400
58 #define TIMER_POLL_THRESHOLD 15
59
60
61 /*
62 * dev_footbridge_tick():
63 *
64 * The 4 footbridge timers should decrease every now and then, and cause
65 * interrupts. Periodic interrupts restart as soon as they are acknowledged,
66 * non-periodic interrupts need to be "reloaded" to restart.
67 */
68 void dev_footbridge_tick(struct cpu *cpu, void *extra)
69 {
70 int i;
71 struct footbridge_data *d = (struct footbridge_data *) extra;
72
73 if (!d->timer_being_read)
74 d->timer_poll_mode = 0;
75
76 for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
77 unsigned int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
78 if (d->timer_control[i] & TIMER_FCLK_16)
79 amount >>= 4;
80 else if (d->timer_control[i] & TIMER_FCLK_256)
81 amount >>= 8;
82
83 if (d->timer_tick_countdown[i] == 0)
84 continue;
85
86 if (d->timer_value[i] > amount)
87 d->timer_value[i] -= amount;
88 else
89 d->timer_value[i] = 0;
90
91 if (d->timer_value[i] == 0) {
92 d->timer_tick_countdown[i] --;
93 if (d->timer_tick_countdown[i] > 0)
94 continue;
95
96 if (d->timer_control[i] & TIMER_ENABLE)
97 cpu_interrupt(cpu, IRQ_TIMER_1 + i);
98 d->timer_tick_countdown[i] = 0;
99 }
100 }
101 }
102
103
104 /*
105 * dev_footbridge_isa_access():
106 *
107 * Reading the byte at 0x79000000 is a quicker way to figure out which ISA
108 * interrupt has occurred (and acknowledging it at the same time), than
109 * dealing with the legacy 0x20/0xa0 ISA ports.
110 */
111 DEVICE_ACCESS(footbridge_isa)
112 {
113 /* struct footbridge_data *d = extra; */
114 uint64_t idata = 0, odata = 0;
115 int x;
116
117 if (writeflag == MEM_WRITE) {
118 idata = memory_readmax64(cpu, data, len);
119 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
120 }
121
122 x = cpu->machine->isa_pic_data.last_int;
123 if (x == 0)
124 cpu_interrupt_ack(cpu, 32 + x);
125
126 if (x < 8)
127 odata = cpu->machine->isa_pic_data.pic1->irq_base + x;
128 else
129 odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8;
130
131 if (writeflag == MEM_READ)
132 memory_writemax64(cpu, data, len, odata);
133
134 return 1;
135 }
136
137
138 /*
139 * Reset pin at ISA port 0x338, at least in the NetWinder:
140 *
141 * TODO: NOT WORKING YET!
142 */
143 DEVICE_ACCESS(footbridge_reset)
144 {
145 uint64_t idata = 0;
146
147 if (writeflag == MEM_WRITE) {
148 idata = memory_readmax64(cpu, data, len);
149 if (idata & 0x40) {
150 debug("[ footbridge_reset: GP16: Halting. ]\n");
151 cpu->running = 0;
152 exit(1);
153 }
154 }
155
156 return 1;
157 }
158
159
160 /*
161 * dev_footbridge_pci_access():
162 *
163 * The Footbridge PCI configuration space is implemented as a direct memory
164 * space (i.e. not one port for addr and one port for data). This function
165 * translates that into bus_pci calls.
166 */
167 DEVICE_ACCESS(footbridge_pci)
168 {
169 struct footbridge_data *d = extra;
170 uint64_t idata = 0, odata = 0;
171 int bus, dev, func, reg;
172
173 if (writeflag == MEM_WRITE)
174 idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
175
176 /* Decompose the (direct) address into its components: */
177 bus_pci_decompose_1(relative_addr, &bus, &dev, &func, &reg);
178 bus_pci_setaddr(cpu, d->pcibus, bus, dev, func, reg);
179
180 if (bus == 255) {
181 fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
182 " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc);
183 exit(1);
184 }
185
186 debug("[ footbridge pci: %s bus %i, device %i, function %i, register "
187 "%i ]\n", writeflag == MEM_READ? "read from" : "write to", bus,
188 dev, func, reg);
189
190 bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
191 &odata : &idata, len, writeflag);
192
193 if (writeflag == MEM_READ)
194 memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
195
196 return 1;
197 }
198
199
200 /*
201 * dev_footbridge_access():
202 *
203 * The DC21285 registers.
204 */
205 DEVICE_ACCESS(footbridge)
206 {
207 struct footbridge_data *d = extra;
208 uint64_t idata = 0, odata = 0;
209 int timer_nr = 0;
210
211 if (writeflag == MEM_WRITE)
212 idata = memory_readmax64(cpu, data, len);
213
214 if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
215 timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
216 relative_addr &= ~0x060;
217 }
218
219 switch (relative_addr) {
220
221 case VENDOR_ID:
222 odata = 0x1011; /* DC21285_VENDOR_ID */
223 break;
224
225 case DEVICE_ID:
226 odata = 0x1065; /* DC21285_DEVICE_ID */
227 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:
238 odata = 3; /* footbridge revision number */
239 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 SA_CONTROL:
249 /* Read by Linux: */
250 odata = PCI_CENTRAL_FUNCTION;
251 break;
252
253 case UART_DATA:
254 if (writeflag == MEM_WRITE)
255 console_putchar(d->console_handle, idata);
256 break;
257
258 case UART_RX_STAT:
259 /* TODO */
260 odata = 0;
261 break;
262
263 case UART_FLAGS:
264 odata = UART_TX_EMPTY;
265 break;
266
267 case IRQ_STATUS:
268 if (writeflag == MEM_READ)
269 odata = d->irq_status & d->irq_enable;
270 else {
271 fatal("[ WARNING: footbridge write to irq status? ]\n");
272 exit(1);
273 }
274 break;
275
276 case IRQ_RAW_STATUS:
277 if (writeflag == MEM_READ)
278 odata = d->irq_status;
279 else {
280 fatal("[ footbridge write to irq_raw_status ]\n");
281 exit(1);
282 }
283 break;
284
285 case IRQ_ENABLE_SET:
286 if (writeflag == MEM_WRITE) {
287 d->irq_enable |= idata;
288 cpu_interrupt(cpu, 64);
289 } else {
290 odata = d->irq_enable;
291 fatal("[ WARNING: footbridge read from "
292 "ENABLE SET? ]\n");
293 exit(1);
294 }
295 break;
296
297 case IRQ_ENABLE_CLEAR:
298 if (writeflag == MEM_WRITE) {
299 d->irq_enable &= ~idata;
300 cpu_interrupt(cpu, 64);
301 } else {
302 odata = d->irq_enable;
303 fatal("[ WARNING: footbridge read from "
304 "ENABLE CLEAR? ]\n");
305 exit(1);
306 }
307 break;
308
309 case FIQ_STATUS:
310 if (writeflag == MEM_READ)
311 odata = d->fiq_status & d->fiq_enable;
312 else {
313 fatal("[ WARNING: footbridge write to fiq status? ]\n");
314 exit(1);
315 }
316 break;
317
318 case FIQ_RAW_STATUS:
319 if (writeflag == MEM_READ)
320 odata = d->fiq_status;
321 else {
322 fatal("[ footbridge write to fiq_raw_status ]\n");
323 exit(1);
324 }
325 break;
326
327 case FIQ_ENABLE_SET:
328 if (writeflag == MEM_WRITE)
329 d->fiq_enable |= idata;
330 break;
331
332 case FIQ_ENABLE_CLEAR:
333 if (writeflag == MEM_WRITE)
334 d->fiq_enable &= ~idata;
335 break;
336
337 case TIMER_1_LOAD:
338 if (writeflag == MEM_READ)
339 odata = d->timer_load[timer_nr];
340 else {
341 d->timer_value[timer_nr] =
342 d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
343 debug("[ footbridge: timer %i (1-based), value %i ]\n",
344 timer_nr + 1, (int)d->timer_value[timer_nr]);
345 d->timer_tick_countdown[timer_nr] = 1;
346 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
347 }
348 break;
349
350 case TIMER_1_VALUE:
351 if (writeflag == MEM_READ) {
352 /*
353 * NOTE/TODO: This is INCORRECT but speeds up NetBSD
354 * and OpenBSD boot sequences: if the timer is polled
355 * "very often" (such as during bootup), then this
356 * causes the timers to expire quickly.
357 */
358 d->timer_being_read = 1;
359 d->timer_poll_mode ++;
360 if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {
361 d->timer_poll_mode = TIMER_POLL_THRESHOLD;
362 dev_footbridge_tick(cpu, d);
363 dev_footbridge_tick(cpu, d);
364 dev_footbridge_tick(cpu, d);
365 }
366 odata = d->timer_value[timer_nr];
367 d->timer_being_read = 0;
368 } else
369 d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
370 break;
371
372 case TIMER_1_CONTROL:
373 if (writeflag == MEM_READ)
374 odata = d->timer_control[timer_nr];
375 else {
376 d->timer_control[timer_nr] = idata;
377 if (idata & TIMER_FCLK_16 &&
378 idata & TIMER_FCLK_256) {
379 fatal("TODO: footbridge timer: "
380 "both 16 and 256?\n");
381 exit(1);
382 }
383 if (idata & TIMER_ENABLE) {
384 d->timer_value[timer_nr] =
385 d->timer_load[timer_nr];
386 d->timer_tick_countdown[timer_nr] = 1;
387 }
388 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
389 }
390 break;
391
392 case TIMER_1_CLEAR:
393 if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
394 d->timer_value[timer_nr] = d->timer_load[timer_nr];
395 d->timer_tick_countdown[timer_nr] = 1;
396 }
397 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
398 break;
399
400 default:if (writeflag == MEM_READ) {
401 fatal("[ footbridge: read from 0x%x ]\n",
402 (int)relative_addr);
403 } else {
404 fatal("[ footbridge: write to 0x%x: 0x%llx ]\n",
405 (int)relative_addr, (long long)idata);
406 }
407 }
408
409 if (writeflag == MEM_READ)
410 memory_writemax64(cpu, data, len, odata);
411
412 return 1;
413 }
414
415
416 DEVINIT(footbridge)
417 {
418 struct footbridge_data *d;
419 uint64_t pci_addr = 0x7b000000;
420 int i;
421
422 d = malloc(sizeof(struct footbridge_data));
423 if (d == NULL) {
424 fprintf(stderr, "out of memory\n");
425 exit(1);
426 }
427 memset(d, 0, sizeof(struct footbridge_data));
428
429 /* DC21285 register access: */
430 memory_device_register(devinit->machine->memory, devinit->name,
431 devinit->addr, DEV_FOOTBRIDGE_LENGTH,
432 dev_footbridge_access, d, DM_DEFAULT, NULL);
433
434 /* ISA interrupt status/acknowledgement: */
435 memory_device_register(devinit->machine->memory, "footbridge_isa",
436 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
437
438 /* The "fcom" console: */
439 d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
440
441 /* A PCI bus: */
442 d->pcibus = bus_pci_init(
443 devinit->machine,
444 devinit->irq_nr, /* PCI controller irq */
445 0x7c000000, /* PCI device io offset */
446 0x80000000, /* PCI device mem offset */
447 0x00000000, /* PCI port base */
448 0x00000000, /* PCI mem base */
449 0, /* PCI irq base: TODO */
450 0x7c000000, /* ISA port base */
451 0x80000000, /* ISA mem base */
452 32); /* ISA port base */
453
454 /* ... with some default devices for known machine types: */
455 switch (devinit->machine->machine_type) {
456 case MACHINE_CATS:
457 bus_pci_add(devinit->machine, d->pcibus,
458 devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
459 bus_pci_add(devinit->machine, d->pcibus,
460 devinit->machine->memory, 0xc0, 10, 0, "dec21143");
461 bus_pci_add(devinit->machine, d->pcibus,
462 devinit->machine->memory, 0xc0, 16, 0, "ali_m5229");
463 break;
464 case MACHINE_NETWINDER:
465 bus_pci_add(devinit->machine, d->pcibus,
466 devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
467 bus_pci_add(devinit->machine, d->pcibus,
468 devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
469 memory_device_register(devinit->machine->memory,
470 "footbridge_reset", 0x7c000338, 1,
471 dev_footbridge_reset_access, d, DM_DEFAULT, NULL);
472 break;
473 default:fatal("footbridge: unimplemented machine type.\n");
474 exit(1);
475 }
476
477 /* PCI configuration space: */
478 memory_device_register(devinit->machine->memory,
479 "footbridge_pci", pci_addr, 0x1000000,
480 dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
481
482 /* Timer ticks: */
483 for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
484 d->timer_control[i] = TIMER_MODE_PERIODIC;
485 d->timer_load[i] = TIMER_MAX_VAL;
486 }
487 machine_add_tickfunction(devinit->machine,
488 dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT, 0.0);
489
490 devinit->return_ptr = d;
491 return 1;
492 }
493

  ViewVC Help
Powered by ViewVC 1.1.26