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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 24 by dpavlin, Mon Oct 8 16:19:56 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: dev_footbridge.c,v 1.22 2005/10/07 15:10:02 debug Exp $   *  $Id: dev_footbridge.c,v 1.43 2006/03/04 12:38:47 debug Exp $
29   *   *
30   *  Footbridge. Used in Netwinder and Cats.   *  Footbridge. Used in Netwinder and Cats.
31   *   *
32   *  TODO: Most things. For example:   *  TODO:
  *  
33   *      o)  Add actual support for the fcom serial port.   *      o)  Add actual support for the fcom serial port.
34   *      o)  FIQs.   *      o)  FIQs.
35   *      o)  Lots of other things.   *      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>  #include <stdio.h>
# Line 44  Line 45 
45  #include "console.h"  #include "console.h"
46  #include "cpu.h"  #include "cpu.h"
47  #include "device.h"  #include "device.h"
48  #include "devices.h"    /*  for struct footbridge_data  */  #include "devices.h"
49  #include "machine.h"  #include "machine.h"
50  #include "memory.h"  #include "memory.h"
51  #include "misc.h"  #include "misc.h"
# Line 54  Line 55 
55    
56  #define DEV_FOOTBRIDGE_TICK_SHIFT       14  #define DEV_FOOTBRIDGE_TICK_SHIFT       14
57  #define DEV_FOOTBRIDGE_LENGTH           0x400  #define DEV_FOOTBRIDGE_LENGTH           0x400
58    #define TIMER_POLL_THRESHOLD            15
59    
60    
61  /*  /*
# Line 68  void dev_footbridge_tick(struct cpu *cpu Line 70  void dev_footbridge_tick(struct cpu *cpu
70          int i;          int i;
71          struct footbridge_data *d = (struct footbridge_data *) extra;          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++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
77                  int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;                  unsigned int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
78                  if (d->timer_control[i] & TIMER_FCLK_16)                  if (d->timer_control[i] & TIMER_FCLK_16)
79                          amount >>= 4;                          amount >>= 4;
80                  else if (d->timer_control[i] & TIMER_FCLK_256)                  else if (d->timer_control[i] & TIMER_FCLK_256)
# Line 99  void dev_footbridge_tick(struct cpu *cpu Line 104  void dev_footbridge_tick(struct cpu *cpu
104  /*  /*
105   *  dev_footbridge_isa_access():   *  dev_footbridge_isa_access():
106   *   *
107   *  NetBSD seems to read 0x79000000 to find out which ISA interrupt occurred,   *  Reading the byte at 0x79000000 is a quicker way to figure out which ISA
108   *  a quicker way than dealing with legacy 0x20/0xa0 ISA ports.   *  interrupt has occurred (and acknowledging it at the same time), than
109     *  dealing with the legacy 0x20/0xa0 ISA ports.
110   */   */
111  int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(footbridge_isa)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
112  {  {
113          /*  struct footbridge_data *d = extra;  */          /*  struct footbridge_data *d = extra;  */
114          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
115          int x;          int x;
116    
117          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE) {
118                    idata = memory_readmax64(cpu, data, len);
         if (writeflag == MEM_WRITE)  
119                  fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");                  fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
   
         /*  
          *  NetBSD seems to want a value of 0x20 + x, where x is the highest  
          *  priority ISA interrupt which is currently asserted and not masked.  
          */  
   
         for (x=0; x<16; x++) {  
                 if (x == 2)  
                         continue;  
                 if (x < 8 && (cpu->machine->isa_pic_data.pic1->irr &  
                     ~cpu->machine->isa_pic_data.pic1->ier &  
                     (1 << x)))  
                         break;  
                 if (x >= 8 && (cpu->machine->isa_pic_data.pic2->irr &  
                     ~cpu->machine->isa_pic_data.pic2->ier &  
                     (1 << (x&7))))  
                         break;  
120          }          }
121    
122          if (x == 16)          x = cpu->machine->isa_pic_data.last_int;
123                  fatal("_\n_  SPORADIC but INVALID ISA interrupt\n_\n");          if (x == 0)
124                    cpu_interrupt_ack(cpu, 32 + x);
125          odata = 0x20 + (x & 15);  
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)          if (writeflag == MEM_READ)
132                  memory_writemax64(cpu, data, len, odata);                  memory_writemax64(cpu, data, len, odata);
# Line 148  int dev_footbridge_isa_access(struct cpu Line 138  int dev_footbridge_isa_access(struct cpu
138  /*  /*
139   *  dev_footbridge_pci_access():   *  dev_footbridge_pci_access():
140   *   *
141   *  The Footbridge PCI configuration space is not implemented as "address +   *  The Footbridge PCI configuration space is implemented as a direct memory
142   *  data port" pair, but instead a 24-bit (16 MB) chunk of physical memory   *  space (i.e. not one port for addr and one port for data). This function
143   *  decodes as the address. This function translates that into bus_pci_access   *  translates that into bus_pci calls.
  *  calls.  
144   */   */
145  int dev_footbridge_pci_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(footbridge_pci)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
146  {  {
147          struct footbridge_data *d = extra;          struct footbridge_data *d = extra;
148          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
149          int bus, device, function, regnr, res;          int bus, dev, func, reg;
         uint64_t pci_word;  
150    
151          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
152                    idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN);
153    
154          bus      = (relative_addr >> 16) & 0xff;          /*  Decompose the (direct) address into its components:  */
155          device   = (relative_addr >> 11) & 0x1f;          bus_pci_decompose_1(relative_addr, &bus, &dev, &func, &reg);
156          function = (relative_addr >> 8) & 0x7;          bus_pci_setaddr(cpu, d->pcibus, bus, dev, func, reg);
         regnr    = relative_addr & 0xff;  
157    
158          if (bus == 255) {          if (bus == 255) {
159                  fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"                  fatal("[ footbridge DEBUG ERROR: bus 255 unlikely,"
# Line 175  int dev_footbridge_pci_access(struct cpu Line 161  int dev_footbridge_pci_access(struct cpu
161                  exit(1);                  exit(1);
162          }          }
163    
164          debug("[ footbridge_pci: %s bus %i, device %i, function "          debug("[ footbridge pci: %s bus %i, device %i, function %i, register "
165              "%i, register %i ]\n", writeflag == MEM_READ? "read from"              "%i ]\n", writeflag == MEM_READ? "read from" : "write to", bus,
166              : "write to", bus, device, function, regnr);              dev, func, reg);
   
         if (d->pcibus == NULL) {  
                 fatal("dev_footbridge_pci_access(): no PCI bus?\n");  
                 return 0;  
         }  
167    
168          pci_word = relative_addr & 0x00ffffff;          bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
169                &odata : &idata, len, writeflag);
         res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,  
             &pci_word, MEM_WRITE, d->pcibus);  
         if (writeflag == MEM_READ) {  
                 res = bus_pci_access(cpu, mem, BUS_PCI_DATA,  
                     &pci_word, MEM_READ, d->pcibus);  
                 odata = pci_word;  
         } else {  
                 pci_word = idata;  
                 res = bus_pci_access(cpu, mem, BUS_PCI_DATA,  
                     &pci_word, MEM_WRITE, d->pcibus);  
         }  
170    
171          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
172                  memory_writemax64(cpu, data, len, odata);                  memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata);
173    
174          return 1;          return 1;
175  }  }
# Line 210  int dev_footbridge_pci_access(struct cpu Line 180  int dev_footbridge_pci_access(struct cpu
180   *   *
181   *  The DC21285 registers.   *  The DC21285 registers.
182   */   */
183  int dev_footbridge_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(footbridge)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
184  {  {
185          struct footbridge_data *d = extra;          struct footbridge_data *d = extra;
186          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
187          int timer_nr = 0;          int timer_nr = 0;
188    
189          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
190                    idata = memory_readmax64(cpu, data, len);
191    
192          if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {          if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
193                  timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);                  timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1);
# Line 235  int dev_footbridge_access(struct cpu *cp Line 204  int dev_footbridge_access(struct cpu *cp
204                  odata = 0x1065;  /*  DC21285_DEVICE_ID  */                  odata = 0x1065;  /*  DC21285_DEVICE_ID  */
205                  break;                  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:          case REVISION:
216                  odata = 3;  /*  footbridge revision number  */                  odata = 3;  /*  footbridge revision number  */
217                  break;                  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:          case UART_DATA:
232                  if (writeflag == MEM_WRITE)                  if (writeflag == MEM_WRITE)
233                          console_putchar(d->console_handle, idata);                          console_putchar(d->console_handle, idata);
# Line 276  int dev_footbridge_access(struct cpu *cp Line 265  int dev_footbridge_access(struct cpu *cp
265                          d->irq_enable |= idata;                          d->irq_enable |= idata;
266                          cpu_interrupt(cpu, 64);                          cpu_interrupt(cpu, 64);
267                  } else {                  } else {
268                            odata = d->irq_enable;
269                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
270                              "ENABLE SET? ]\n");                              "ENABLE SET? ]\n");
271                          exit(1);                          exit(1);
                         odata = d->irq_enable;  
272                  }                  }
273                  break;                  break;
274    
# Line 288  int dev_footbridge_access(struct cpu *cp Line 277  int dev_footbridge_access(struct cpu *cp
277                          d->irq_enable &= ~idata;                          d->irq_enable &= ~idata;
278                          cpu_interrupt(cpu, 64);                          cpu_interrupt(cpu, 64);
279                  } else {                  } else {
280                            odata = d->irq_enable;
281                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
282                              "ENABLE CLEAR? ]\n");                              "ENABLE CLEAR? ]\n");
283                          exit(1);                          exit(1);
                         odata = d->irq_enable;  
284                  }                  }
285                  break;                  break;
286    
# Line 338  int dev_footbridge_access(struct cpu *cp Line 327  int dev_footbridge_access(struct cpu *cp
327    
328          case TIMER_1_VALUE:          case TIMER_1_VALUE:
329                  if (writeflag == MEM_READ) {                  if (writeflag == MEM_READ) {
330                          dev_footbridge_tick(cpu, d);                          /*
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];                          odata = d->timer_value[timer_nr];
345                            d->timer_being_read = 0;
346                  } else                  } else
347                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
348                  break;                  break;
# Line 388  int dev_footbridge_access(struct cpu *cp Line 391  int dev_footbridge_access(struct cpu *cp
391  }  }
392    
393    
394  /*  DEVINIT(footbridge)
  *  devinit_footbridge():  
  */  
 int devinit_footbridge(struct devinit *devinit)  
395  {  {
396          struct footbridge_data *d;          struct footbridge_data *d;
397          uint64_t pci_addr = 0x7b000000;          uint64_t pci_addr = 0x7b000000;
# Line 407  int devinit_footbridge(struct devinit *d Line 407  int devinit_footbridge(struct devinit *d
407          /*  DC21285 register access:  */          /*  DC21285 register access:  */
408          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
409              devinit->addr, DEV_FOOTBRIDGE_LENGTH,              devinit->addr, DEV_FOOTBRIDGE_LENGTH,
410              dev_footbridge_access, d, MEM_DEFAULT, NULL);              dev_footbridge_access, d, DM_DEFAULT, NULL);
411    
412          /*  ISA interrupt status word:  */          /*  ISA interrupt status/acknowledgement:  */
413          memory_device_register(devinit->machine->memory, "footbridge_isa",          memory_device_register(devinit->machine->memory, "footbridge_isa",
414              0x79000000, 8, dev_footbridge_isa_access, d, MEM_DEFAULT, NULL);              0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
415    
416          /*  The "fcom" console:  */          /*  The "fcom" console:  */
417          d->console_handle = console_start_slave(devinit->machine, "fcom");          d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
418    
419          /*  A PCI bus:  */          /*  A PCI bus:  */
420          d->pcibus = bus_pci_init(devinit->irq_nr);          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:  */          /*  ... with some default devices for known machine types:  */
433          switch (devinit->machine->machine_type) {          switch (devinit->machine->machine_type) {
434          case MACHINE_CATS:          case MACHINE_CATS:
435                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
436                      devinit->machine->memory, 0xc0, 7, 0,                      devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
437                      pci_ali_m1543_init, pci_ali_m1543_rr);                  bus_pci_add(devinit->machine, d->pcibus,
438                        devinit->machine->memory, 0xc0, 10, 0, "dec21143");
439                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
440                      devinit->machine->memory, 0xc0, 16, 0,                      devinit->machine->memory, 0xc0, 16, 0, "ali_m5229");
                     pci_ali_m5229_init, pci_ali_m5229_rr);  
441                  break;                  break;
442          case MACHINE_NETWINDER:          case MACHINE_NETWINDER:
443                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
444                      devinit->machine->memory, 0xc0, 11, 0,                      devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
                     pci_symphony_83c553_init, pci_symphony_83c553_rr);  
445                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
446                      devinit->machine->memory, 0xc0, 11, 1,                      devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
                     pci_symphony_82c105_init, pci_symphony_82c105_rr);  
447                  break;                  break;
448          default:fatal("footbridge: unimplemented machine type.\n");          default:fatal("footbridge: unimplemented machine type.\n");
449                  exit(1);                  exit(1);
# Line 444  int devinit_footbridge(struct devinit *d Line 452  int devinit_footbridge(struct devinit *d
452          /*  PCI configuration space:  */          /*  PCI configuration space:  */
453          memory_device_register(devinit->machine->memory,          memory_device_register(devinit->machine->memory,
454              "footbridge_pci", pci_addr, 0x1000000,              "footbridge_pci", pci_addr, 0x1000000,
455              dev_footbridge_pci_access, d, MEM_DEFAULT, NULL);              dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
456    
457          /*  Timer ticks:  */          /*  Timer ticks:  */
458          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
# Line 452  int devinit_footbridge(struct devinit *d Line 460  int devinit_footbridge(struct devinit *d
460                  d->timer_load[i] = TIMER_MAX_VAL;                  d->timer_load[i] = TIMER_MAX_VAL;
461          }          }
462          machine_add_tickfunction(devinit->machine,          machine_add_tickfunction(devinit->machine,
463              dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT);              dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT, 0.0);
464    
465          devinit->return_ptr = d;          devinit->return_ptr = d;
466          return 1;          return 1;

Legend:
Removed from v.14  
changed lines
  Added in v.24

  ViewVC Help
Powered by ViewVC 1.1.26