/[gxemul]/upstream/0.3.8/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 /upstream/0.3.8/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 12486 byte(s)
0.3.8
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.42 2006/02/09 20:02:59 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 * dev_footbridge_pci_access():
140 *
141 * The Footbridge PCI configuration space is implemented as a direct memory
142 * space (i.e. not one port for addr and one port for data). This function
143 * translates that into bus_pci calls.
144 */
145 DEVICE_ACCESS(footbridge_pci)
146 {
147 struct footbridge_data *d = extra;
148 uint64_t idata = 0, odata = 0;
149 int bus, dev, func, reg;
150
151 if (writeflag == MEM_WRITE)
152 idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
153
154 /* Decompose the (direct) address into its components: */
155 bus_pci_decompose_1(relative_addr, &bus, &dev, &func, &reg);
156 bus_pci_setaddr(cpu, d->pcibus, bus, dev, func, reg);
157
158 if (bus == 255) {
159 fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
160 " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc);
161 exit(1);
162 }
163
164 debug("[ footbridge pci: %s bus %i, device %i, function %i, register "
165 "%i ]\n", writeflag == MEM_READ? "read from" : "write to", bus,
166 dev, func, reg);
167
168 bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
169 &odata : &idata, len, writeflag);
170
171 if (writeflag == MEM_READ)
172 memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
173
174 return 1;
175 }
176
177
178 /*
179 * dev_footbridge_access():
180 *
181 * The DC21285 registers.
182 */
183 DEVICE_ACCESS(footbridge)
184 {
185 struct footbridge_data *d = extra;
186 uint64_t idata = 0, odata = 0;
187 int timer_nr = 0;
188
189 if (writeflag == MEM_WRITE)
190 idata = memory_readmax64(cpu, data, len);
191
192 if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
193 timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
194 relative_addr &= ~0x060;
195 }
196
197 switch (relative_addr) {
198
199 case VENDOR_ID:
200 odata = 0x1011; /* DC21285_VENDOR_ID */
201 break;
202
203 case DEVICE_ID:
204 odata = 0x1065; /* DC21285_DEVICE_ID */
205 break;
206
207 case 0x04:
208 case 0x0c:
209 case 0x10:
210 case 0x14:
211 case 0x18:
212 /* TODO. Written to by Linux. */
213 break;
214
215 case REVISION:
216 odata = 3; /* footbridge revision number */
217 break;
218
219 case PCI_ADDRESS_EXTENSION:
220 /* TODO: Written to by Linux. */
221 if (writeflag == MEM_WRITE && idata != 0)
222 fatal("[ footbridge: TODO: write to PCI_ADDRESS_"
223 "EXTENSION: 0x%llx ]\n", (long long)idata);
224 break;
225
226 case SA_CONTROL:
227 /* Read by Linux: */
228 odata = PCI_CENTRAL_FUNCTION;
229 break;
230
231 case UART_DATA:
232 if (writeflag == MEM_WRITE)
233 console_putchar(d->console_handle, idata);
234 break;
235
236 case UART_RX_STAT:
237 /* TODO */
238 odata = 0;
239 break;
240
241 case UART_FLAGS:
242 odata = UART_TX_EMPTY;
243 break;
244
245 case IRQ_STATUS:
246 if (writeflag == MEM_READ)
247 odata = d->irq_status & d->irq_enable;
248 else {
249 fatal("[ WARNING: footbridge write to irq status? ]\n");
250 exit(1);
251 }
252 break;
253
254 case IRQ_RAW_STATUS:
255 if (writeflag == MEM_READ)
256 odata = d->irq_status;
257 else {
258 fatal("[ footbridge write to irq_raw_status ]\n");
259 exit(1);
260 }
261 break;
262
263 case IRQ_ENABLE_SET:
264 if (writeflag == MEM_WRITE) {
265 d->irq_enable |= idata;
266 cpu_interrupt(cpu, 64);
267 } else {
268 odata = d->irq_enable;
269 fatal("[ WARNING: footbridge read from "
270 "ENABLE SET? ]\n");
271 exit(1);
272 }
273 break;
274
275 case IRQ_ENABLE_CLEAR:
276 if (writeflag == MEM_WRITE) {
277 d->irq_enable &= ~idata;
278 cpu_interrupt(cpu, 64);
279 } else {
280 odata = d->irq_enable;
281 fatal("[ WARNING: footbridge read from "
282 "ENABLE CLEAR? ]\n");
283 exit(1);
284 }
285 break;
286
287 case FIQ_STATUS:
288 if (writeflag == MEM_READ)
289 odata = d->fiq_status & d->fiq_enable;
290 else {
291 fatal("[ WARNING: footbridge write to fiq status? ]\n");
292 exit(1);
293 }
294 break;
295
296 case FIQ_RAW_STATUS:
297 if (writeflag == MEM_READ)
298 odata = d->fiq_status;
299 else {
300 fatal("[ footbridge write to fiq_raw_status ]\n");
301 exit(1);
302 }
303 break;
304
305 case FIQ_ENABLE_SET:
306 if (writeflag == MEM_WRITE)
307 d->fiq_enable |= idata;
308 break;
309
310 case FIQ_ENABLE_CLEAR:
311 if (writeflag == MEM_WRITE)
312 d->fiq_enable &= ~idata;
313 break;
314
315 case TIMER_1_LOAD:
316 if (writeflag == MEM_READ)
317 odata = d->timer_load[timer_nr];
318 else {
319 d->timer_value[timer_nr] =
320 d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
321 debug("[ footbridge: timer %i (1-based), value %i ]\n",
322 timer_nr + 1, (int)d->timer_value[timer_nr]);
323 d->timer_tick_countdown[timer_nr] = 1;
324 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
325 }
326 break;
327
328 case TIMER_1_VALUE:
329 if (writeflag == MEM_READ) {
330 /*
331 * NOTE/TODO: This is INCORRECT but speeds up NetBSD
332 * and OpenBSD boot sequences: if the timer is polled
333 * "very often" (such as during bootup), then this
334 * causes the timers to expire quickly.
335 */
336 d->timer_being_read = 1;
337 d->timer_poll_mode ++;
338 if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {
339 d->timer_poll_mode = TIMER_POLL_THRESHOLD;
340 dev_footbridge_tick(cpu, d);
341 dev_footbridge_tick(cpu, d);
342 dev_footbridge_tick(cpu, d);
343 }
344 odata = d->timer_value[timer_nr];
345 d->timer_being_read = 0;
346 } else
347 d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
348 break;
349
350 case TIMER_1_CONTROL:
351 if (writeflag == MEM_READ)
352 odata = d->timer_control[timer_nr];
353 else {
354 d->timer_control[timer_nr] = idata;
355 if (idata & TIMER_FCLK_16 &&
356 idata & TIMER_FCLK_256) {
357 fatal("TODO: footbridge timer: "
358 "both 16 and 256?\n");
359 exit(1);
360 }
361 if (idata & TIMER_ENABLE) {
362 d->timer_value[timer_nr] =
363 d->timer_load[timer_nr];
364 d->timer_tick_countdown[timer_nr] = 1;
365 }
366 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
367 }
368 break;
369
370 case TIMER_1_CLEAR:
371 if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
372 d->timer_value[timer_nr] = d->timer_load[timer_nr];
373 d->timer_tick_countdown[timer_nr] = 1;
374 }
375 cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
376 break;
377
378 default:if (writeflag == MEM_READ) {
379 fatal("[ footbridge: read from 0x%x ]\n",
380 (int)relative_addr);
381 } else {
382 fatal("[ footbridge: write to 0x%x: 0x%llx ]\n",
383 (int)relative_addr, (long long)idata);
384 }
385 }
386
387 if (writeflag == MEM_READ)
388 memory_writemax64(cpu, data, len, odata);
389
390 return 1;
391 }
392
393
394 DEVINIT(footbridge)
395 {
396 struct footbridge_data *d;
397 uint64_t pci_addr = 0x7b000000;
398 int i;
399
400 d = malloc(sizeof(struct footbridge_data));
401 if (d == NULL) {
402 fprintf(stderr, "out of memory\n");
403 exit(1);
404 }
405 memset(d, 0, sizeof(struct footbridge_data));
406
407 /* DC21285 register access: */
408 memory_device_register(devinit->machine->memory, devinit->name,
409 devinit->addr, DEV_FOOTBRIDGE_LENGTH,
410 dev_footbridge_access, d, DM_DEFAULT, NULL);
411
412 /* ISA interrupt status/acknowledgement: */
413 memory_device_register(devinit->machine->memory, "footbridge_isa",
414 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
415
416 /* The "fcom" console: */
417 d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
418
419 /* A PCI bus: */
420 d->pcibus = bus_pci_init(
421 devinit->machine,
422 devinit->irq_nr, /* PCI controller irq */
423 0x7c000000, /* PCI device io offset */
424 0x80000000, /* PCI device mem offset */
425 0x00000000, /* PCI port base */
426 0x00000000, /* PCI mem base */
427 0, /* PCI irq base: TODO */
428 0x7c000000, /* ISA port base */
429 0x80000000, /* ISA mem base */
430 32); /* ISA port base */
431
432 /* ... with some default devices for known machine types: */
433 switch (devinit->machine->machine_type) {
434 case MACHINE_CATS:
435 bus_pci_add(devinit->machine, d->pcibus,
436 devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
437 bus_pci_add(devinit->machine, d->pcibus,
438 devinit->machine->memory, 0xc0, 10, 0, "dec21143");
439 bus_pci_add(devinit->machine, d->pcibus,
440 devinit->machine->memory, 0xc0, 16, 0, "ali_m5229");
441 break;
442 case MACHINE_NETWINDER:
443 bus_pci_add(devinit->machine, d->pcibus,
444 devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
445 bus_pci_add(devinit->machine, d->pcibus,
446 devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
447 break;
448 default:fatal("footbridge: unimplemented machine type.\n");
449 exit(1);
450 }
451
452 /* PCI configuration space: */
453 memory_device_register(devinit->machine->memory,
454 "footbridge_pci", pci_addr, 0x1000000,
455 dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
456
457 /* Timer ticks: */
458 for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
459 d->timer_control[i] = TIMER_MODE_PERIODIC;
460 d->timer_load[i] = TIMER_MAX_VAL;
461 }
462 machine_add_tickfunction(devinit->machine,
463 dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT);
464
465 devinit->return_ptr = d;
466 return 1;
467 }
468

  ViewVC Help
Powered by ViewVC 1.1.26