/[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

Annotation of /upstream/0.3.8/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12486 byte(s)
0.3.8
1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 22 * $Id: dev_footbridge.c,v 1.42 2006/02/09 20:02:59 debug Exp $
29 dpavlin 14 *
30     * Footbridge. Used in Netwinder and Cats.
31     *
32 dpavlin 20 * TODO:
33 dpavlin 14 * o) Add actual support for the fcom serial port.
34     * o) FIQs.
35 dpavlin 22 * 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 dpavlin 14 */
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 dpavlin 22 #include "devices.h"
49 dpavlin 14 #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 dpavlin 18 #define TIMER_POLL_THRESHOLD 15
59 dpavlin 14
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 dpavlin 18 if (!d->timer_being_read)
74     d->timer_poll_mode = 0;
75    
76 dpavlin 14 for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
77 dpavlin 22 unsigned int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
78 dpavlin 14 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 dpavlin 20 * 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 dpavlin 14 */
111 dpavlin 22 DEVICE_ACCESS(footbridge_isa)
112 dpavlin 14 {
113     /* struct footbridge_data *d = extra; */
114     uint64_t idata = 0, odata = 0;
115     int x;
116    
117 dpavlin 18 if (writeflag == MEM_WRITE) {
118     idata = memory_readmax64(cpu, data, len);
119 dpavlin 14 fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
120 dpavlin 18 }
121 dpavlin 14
122 dpavlin 20 x = cpu->machine->isa_pic_data.last_int;
123     if (x == 0)
124     cpu_interrupt_ack(cpu, 32 + x);
125 dpavlin 14
126 dpavlin 20 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 dpavlin 14
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 dpavlin 22 * 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 dpavlin 14 */
145 dpavlin 22 DEVICE_ACCESS(footbridge_pci)
146 dpavlin 14 {
147     struct footbridge_data *d = extra;
148     uint64_t idata = 0, odata = 0;
149 dpavlin 22 int bus, dev, func, reg;
150 dpavlin 14
151 dpavlin 18 if (writeflag == MEM_WRITE)
152 dpavlin 22 idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
153 dpavlin 14
154 dpavlin 22 /* 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 dpavlin 14
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 dpavlin 22 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 dpavlin 14
168 dpavlin 22 bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
169     &odata : &idata, len, writeflag);
170 dpavlin 14
171     if (writeflag == MEM_READ)
172 dpavlin 22 memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
173 dpavlin 14
174     return 1;
175     }
176    
177    
178     /*
179     * dev_footbridge_access():
180     *
181     * The DC21285 registers.
182     */
183 dpavlin 22 DEVICE_ACCESS(footbridge)
184 dpavlin 14 {
185     struct footbridge_data *d = extra;
186     uint64_t idata = 0, odata = 0;
187     int timer_nr = 0;
188    
189 dpavlin 18 if (writeflag == MEM_WRITE)
190     idata = memory_readmax64(cpu, data, len);
191 dpavlin 14
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 dpavlin 20 case 0x04:
208     case 0x0c:
209     case 0x10:
210     case 0x14:
211     case 0x18:
212     /* TODO. Written to by Linux. */
213     break;
214    
215 dpavlin 14 case REVISION:
216     odata = 3; /* footbridge revision number */
217     break;
218    
219 dpavlin 20 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 dpavlin 22 case SA_CONTROL:
227     /* Read by Linux: */
228     odata = PCI_CENTRAL_FUNCTION;
229     break;
230    
231 dpavlin 14 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 dpavlin 18 odata = d->irq_enable;
269 dpavlin 14 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 dpavlin 18 odata = d->irq_enable;
281 dpavlin 14 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 dpavlin 18 /*
331 dpavlin 20 * 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 dpavlin 18 */
336     d->timer_being_read = 1;
337     d->timer_poll_mode ++;
338 dpavlin 20 if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {
339     d->timer_poll_mode = TIMER_POLL_THRESHOLD;
340 dpavlin 18 dev_footbridge_tick(cpu, d);
341 dpavlin 20 dev_footbridge_tick(cpu, d);
342     dev_footbridge_tick(cpu, d);
343     }
344 dpavlin 14 odata = d->timer_value[timer_nr];
345 dpavlin 18 d->timer_being_read = 0;
346 dpavlin 14 } 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 dpavlin 22 DEVINIT(footbridge)
395 dpavlin 14 {
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 dpavlin 20 dev_footbridge_access, d, DM_DEFAULT, NULL);
411 dpavlin 14
412 dpavlin 20 /* ISA interrupt status/acknowledgement: */
413 dpavlin 14 memory_device_register(devinit->machine->memory, "footbridge_isa",
414 dpavlin 20 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
415 dpavlin 14
416     /* The "fcom" console: */
417 dpavlin 22 d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
418 dpavlin 14
419     /* A PCI bus: */
420 dpavlin 20 d->pcibus = bus_pci_init(
421 dpavlin 22 devinit->machine,
422 dpavlin 20 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 dpavlin 14
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 dpavlin 20 devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
437 dpavlin 14 bus_pci_add(devinit->machine, d->pcibus,
438 dpavlin 20 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 dpavlin 14 break;
442     case MACHINE_NETWINDER:
443     bus_pci_add(devinit->machine, d->pcibus,
444 dpavlin 20 devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
445 dpavlin 14 bus_pci_add(devinit->machine, d->pcibus,
446 dpavlin 20 devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
447 dpavlin 14 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 dpavlin 20 dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
456 dpavlin 14
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