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

Contents of /upstream/0.3.6/src/devices/dev_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show 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 /*
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