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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12132 byte(s)
0.3.6
1 dpavlin 14 /*
2     * Copyright (C) 2005 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.22 2005/10/07 15:10:02 debug Exp $
29     *
30     * Footbridge. Used in Netwinder and Cats.
31     *
32     * TODO: Most things. For example:
33     *
34     * o) Add actual support for the fcom serial port.
35     * o) FIQs.
36     * o) Lots of other things.
37     */
38    
39     #include <stdio.h>
40     #include <stdlib.h>
41     #include <string.h>
42    
43     #include "bus_pci.h"
44     #include "console.h"
45     #include "cpu.h"
46     #include "device.h"
47     #include "devices.h" /* for struct footbridge_data */
48     #include "machine.h"
49     #include "memory.h"
50     #include "misc.h"
51    
52    
53     #include "dc21285reg.h"
54    
55     #define DEV_FOOTBRIDGE_TICK_SHIFT 14
56     #define DEV_FOOTBRIDGE_LENGTH 0x400
57    
58    
59     /*
60     * dev_footbridge_tick():
61     *
62     * The 4 footbridge timers should decrease every now and then, and cause
63     * interrupts. Periodic interrupts restart as soon as they are acknowledged,
64     * non-periodic interrupts need to be "reloaded" to restart.
65     */
66     void dev_footbridge_tick(struct cpu *cpu, void *extra)
67     {
68     int i;
69     struct footbridge_data *d = (struct footbridge_data *) extra;
70    
71     for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
72     int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
73     if (d->timer_control[i] & TIMER_FCLK_16)
74     amount >>= 4;
75     else if (d->timer_control[i] & TIMER_FCLK_256)
76     amount >>= 8;
77    
78     if (d->timer_tick_countdown[i] == 0)
79     continue;
80    
81     if (d->timer_value[i] > amount)
82     d->timer_value[i] -= amount;
83     else
84     d->timer_value[i] = 0;
85    
86     if (d->timer_value[i] == 0) {
87     d->timer_tick_countdown[i] --;
88     if (d->timer_tick_countdown[i] > 0)
89     continue;
90    
91     if (d->timer_control[i] & TIMER_ENABLE)
92     cpu_interrupt(cpu, IRQ_TIMER_1 + i);
93     d->timer_tick_countdown[i] = 0;
94     }
95     }
96     }
97    
98    
99     /*
100     * dev_footbridge_isa_access():
101     *
102     * NetBSD seems to read 0x79000000 to find out which ISA interrupt occurred,
103     * a quicker way than dealing with legacy 0x20/0xa0 ISA ports.
104     */
105     int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem,
106     uint64_t relative_addr, unsigned char *data, size_t len,
107     int writeflag, void *extra)
108     {
109     /* struct footbridge_data *d = extra; */
110     uint64_t idata = 0, odata = 0;
111     int x;
112    
113     idata = memory_readmax64(cpu, data, len);
114    
115     if (writeflag == MEM_WRITE)
116     fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
117    
118     /*
119     * NetBSD seems to want a value of 0x20 + x, where x is the highest
120     * priority ISA interrupt which is currently asserted and not masked.
121     */
122    
123     for (x=0; x<16; x++) {
124     if (x == 2)
125     continue;
126     if (x < 8 && (cpu->machine->isa_pic_data.pic1->irr &
127     ~cpu->machine->isa_pic_data.pic1->ier &
128     (1 << x)))
129     break;
130     if (x >= 8 && (cpu->machine->isa_pic_data.pic2->irr &
131     ~cpu->machine->isa_pic_data.pic2->ier &
132     (1 << (x&7))))
133     break;
134     }
135    
136     if (x == 16)
137     fatal("_\n_ SPORADIC but INVALID ISA interrupt\n_\n");
138    
139     odata = 0x20 + (x & 15);
140    
141     if (writeflag == MEM_READ)
142     memory_writemax64(cpu, data, len, odata);
143    
144     return 1;
145     }
146    
147    
148     /*
149     * dev_footbridge_pci_access():
150     *
151     * The Footbridge PCI configuration space is not implemented as "address +
152     * data port" pair, but instead a 24-bit (16 MB) chunk of physical memory
153     * decodes as the address. This function translates that into bus_pci_access
154     * calls.
155     */
156     int dev_footbridge_pci_access(struct cpu *cpu, struct memory *mem,
157     uint64_t relative_addr, unsigned char *data, size_t len,
158     int writeflag, void *extra)
159     {
160     struct footbridge_data *d = extra;
161     uint64_t idata = 0, odata = 0;
162     int bus, device, function, regnr, res;
163     uint64_t pci_word;
164    
165     idata = memory_readmax64(cpu, data, len);
166    
167     bus = (relative_addr >> 16) & 0xff;
168     device = (relative_addr >> 11) & 0x1f;
169     function = (relative_addr >> 8) & 0x7;
170     regnr = relative_addr & 0xff;
171    
172     if (bus == 255) {
173     fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
174     " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc);
175     exit(1);
176     }
177    
178     debug("[ footbridge_pci: %s bus %i, device %i, function "
179     "%i, register %i ]\n", writeflag == MEM_READ? "read from"
180     : "write to", bus, device, function, regnr);
181    
182     if (d->pcibus == NULL) {
183     fatal("dev_footbridge_pci_access(): no PCI bus?\n");
184     return 0;
185     }
186    
187     pci_word = relative_addr & 0x00ffffff;
188    
189     res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,
190     &pci_word, MEM_WRITE, d->pcibus);
191     if (writeflag == MEM_READ) {
192     res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
193     &pci_word, MEM_READ, d->pcibus);
194     odata = pci_word;
195     } else {
196     pci_word = idata;
197     res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
198     &pci_word, MEM_WRITE, d->pcibus);
199     }
200    
201     if (writeflag == MEM_READ)
202     memory_writemax64(cpu, data, len, odata);
203    
204     return 1;
205     }
206    
207    
208     /*
209     * dev_footbridge_access():
210     *
211     * The DC21285 registers.
212     */
213     int dev_footbridge_access(struct cpu *cpu, struct memory *mem,
214     uint64_t relative_addr, unsigned char *data, size_t len,
215     int writeflag, void *extra)
216     {
217     struct footbridge_data *d = extra;
218     uint64_t idata = 0, odata = 0;
219     int timer_nr = 0;
220    
221     idata = memory_readmax64(cpu, data, len);
222    
223     if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
224     timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
225     relative_addr &= ~0x060;
226     }
227    
228     switch (relative_addr) {
229    
230     case VENDOR_ID:
231     odata = 0x1011; /* DC21285_VENDOR_ID */
232     break;
233    
234     case DEVICE_ID:
235     odata = 0x1065; /* DC21285_DEVICE_ID */
236     break;
237    
238     case REVISION:
239     odata = 3; /* footbridge revision number */
240     break;
241    
242     case UART_DATA:
243     if (writeflag == MEM_WRITE)
244     console_putchar(d->console_handle, idata);
245     break;
246    
247     case UART_RX_STAT:
248     /* TODO */
249     odata = 0;
250     break;
251    
252     case UART_FLAGS:
253     odata = UART_TX_EMPTY;
254     break;
255    
256     case IRQ_STATUS:
257     if (writeflag == MEM_READ)
258     odata = d->irq_status & d->irq_enable;
259     else {
260     fatal("[ WARNING: footbridge write to irq status? ]\n");
261     exit(1);
262     }
263     break;
264    
265     case IRQ_RAW_STATUS:
266     if (writeflag == MEM_READ)
267     odata = d->irq_status;
268     else {
269     fatal("[ footbridge write to irq_raw_status ]\n");
270     exit(1);
271     }
272     break;
273    
274     case IRQ_ENABLE_SET:
275     if (writeflag == MEM_WRITE) {
276     d->irq_enable |= idata;
277     cpu_interrupt(cpu, 64);
278     } else {
279     fatal("[ WARNING: footbridge read from "
280     "ENABLE SET? ]\n");
281     exit(1);
282     odata = d->irq_enable;
283     }
284     break;
285    
286     case IRQ_ENABLE_CLEAR:
287     if (writeflag == MEM_WRITE) {
288     d->irq_enable &= ~idata;
289     cpu_interrupt(cpu, 64);
290     } else {
291     fatal("[ WARNING: footbridge read from "
292     "ENABLE CLEAR? ]\n");
293     exit(1);
294     odata = d->irq_enable;
295     }
296     break;
297    
298     case FIQ_STATUS:
299     if (writeflag == MEM_READ)
300     odata = d->fiq_status & d->fiq_enable;
301     else {
302     fatal("[ WARNING: footbridge write to fiq status? ]\n");
303     exit(1);
304     }
305     break;
306    
307     case FIQ_RAW_STATUS:
308     if (writeflag == MEM_READ)
309     odata = d->fiq_status;
310     else {
311     fatal("[ footbridge write to fiq_raw_status ]\n");
312     exit(1);
313     }
314     break;
315    
316     case FIQ_ENABLE_SET:
317     if (writeflag == MEM_WRITE)
318     d->fiq_enable |= idata;
319     break;
320    
321     case FIQ_ENABLE_CLEAR:
322     if (writeflag == MEM_WRITE)
323     d->fiq_enable &= ~idata;
324     break;
325    
326     case TIMER_1_LOAD:
327     if (writeflag == MEM_READ)
328     odata = d->timer_load[timer_nr];
329     else {
330     d->timer_value[timer_nr] =
331     d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
332     debug("[ footbridge: timer %i (1-based), value %i ]\n",
333     timer_nr + 1, (int)d->timer_value[timer_nr]);
334     d->timer_tick_countdown[timer_nr] = 1;
335     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
336     }
337     break;
338    
339     case TIMER_1_VALUE:
340     if (writeflag == MEM_READ) {
341     dev_footbridge_tick(cpu, d);
342     odata = d->timer_value[timer_nr];
343     } else
344     d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
345     break;
346    
347     case TIMER_1_CONTROL:
348     if (writeflag == MEM_READ)
349     odata = d->timer_control[timer_nr];
350     else {
351     d->timer_control[timer_nr] = idata;
352     if (idata & TIMER_FCLK_16 &&
353     idata & TIMER_FCLK_256) {
354     fatal("TODO: footbridge timer: "
355     "both 16 and 256?\n");
356     exit(1);
357     }
358     if (idata & TIMER_ENABLE) {
359     d->timer_value[timer_nr] =
360     d->timer_load[timer_nr];
361     d->timer_tick_countdown[timer_nr] = 1;
362     }
363     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
364     }
365     break;
366    
367     case TIMER_1_CLEAR:
368     if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
369     d->timer_value[timer_nr] = d->timer_load[timer_nr];
370     d->timer_tick_countdown[timer_nr] = 1;
371     }
372     cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
373     break;
374    
375     default:if (writeflag == MEM_READ) {
376     fatal("[ footbridge: read from 0x%x ]\n",
377     (int)relative_addr);
378     } else {
379     fatal("[ footbridge: write to 0x%x: 0x%llx ]\n",
380     (int)relative_addr, (long long)idata);
381     }
382     }
383    
384     if (writeflag == MEM_READ)
385     memory_writemax64(cpu, data, len, odata);
386    
387     return 1;
388     }
389    
390    
391     /*
392     * devinit_footbridge():
393     */
394     int devinit_footbridge(struct devinit *devinit)
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, MEM_DEFAULT, NULL);
411    
412     /* ISA interrupt status word: */
413     memory_device_register(devinit->machine->memory, "footbridge_isa",
414     0x79000000, 8, dev_footbridge_isa_access, d, MEM_DEFAULT, NULL);
415    
416     /* The "fcom" console: */
417     d->console_handle = console_start_slave(devinit->machine, "fcom");
418    
419     /* A PCI bus: */
420     d->pcibus = bus_pci_init(devinit->irq_nr);
421    
422     /* ... with some default devices for known machine types: */
423     switch (devinit->machine->machine_type) {
424     case MACHINE_CATS:
425     bus_pci_add(devinit->machine, d->pcibus,
426     devinit->machine->memory, 0xc0, 7, 0,
427     pci_ali_m1543_init, pci_ali_m1543_rr);
428     bus_pci_add(devinit->machine, d->pcibus,
429     devinit->machine->memory, 0xc0, 16, 0,
430     pci_ali_m5229_init, pci_ali_m5229_rr);
431     break;
432     case MACHINE_NETWINDER:
433     bus_pci_add(devinit->machine, d->pcibus,
434     devinit->machine->memory, 0xc0, 11, 0,
435     pci_symphony_83c553_init, pci_symphony_83c553_rr);
436     bus_pci_add(devinit->machine, d->pcibus,
437     devinit->machine->memory, 0xc0, 11, 1,
438     pci_symphony_82c105_init, pci_symphony_82c105_rr);
439     break;
440     default:fatal("footbridge: unimplemented machine type.\n");
441     exit(1);
442     }
443    
444     /* PCI configuration space: */
445     memory_device_register(devinit->machine->memory,
446     "footbridge_pci", pci_addr, 0x1000000,
447     dev_footbridge_pci_access, d, MEM_DEFAULT, NULL);
448    
449     /* Timer ticks: */
450     for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
451     d->timer_control[i] = TIMER_MODE_PERIODIC;
452     d->timer_load[i] = TIMER_MAX_VAL;
453     }
454     machine_add_tickfunction(devinit->machine,
455     dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT);
456    
457     devinit->return_ptr = d;
458     return 1;
459     }
460    

  ViewVC Help
Powered by ViewVC 1.1.26