/[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 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC revision 22 by dpavlin, Mon Oct 8 16:19:37 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.26 2005/10/26 14:37:04 debug Exp $   *  $Id: dev_footbridge.c,v 1.42 2006/02/09 20:02:59 debug Exp $
29   *   *
30   *  Footbridge. Used in Netwinder and Cats.   *  Footbridge. Used in Netwinder and Cats.
31   *   *
32   *  TODO: Most things. For example:   *  TODO:
  *  
  *      o)  Fix the timer TODO (see below).  
  *  
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)  Pretty much everything else as well :)  (This entire thing
36   *      o)  ..   *          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 48  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 77  void dev_footbridge_tick(struct cpu *cpu Line 74  void dev_footbridge_tick(struct cpu *cpu
74                  d->timer_poll_mode = 0;                  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 107  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;
# Line 123  int dev_footbridge_isa_access(struct cpu Line 119  int dev_footbridge_isa_access(struct cpu
119                  fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");                  fatal("[ footbridge_isa: WARNING/TODO: write! ]\n");
120          }          }
121    
122          /*          x = cpu->machine->isa_pic_data.last_int;
123           *  NetBSD seems to want a value of 0x20 + x, where x is the highest          if (x == 0)
124           *  priority ISA interrupt which is currently asserted and not masked.                  cpu_interrupt_ack(cpu, 32 + x);
125           */  
126            if (x < 8)
127          for (x=0; x<16; x++) {                  odata = cpu->machine->isa_pic_data.pic1->irq_base + x;
128                  if (x == 2)          else
129                          continue;                  odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8;
                 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;  
         }  
   
         if (x == 16)  
                 fatal("_\n_  SPORADIC but INVALID ISA interrupt\n_\n");  
   
         odata = 0x20 + (x & 15);  
130    
131          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
132                  memory_writemax64(cpu, data, len, odata);                  memory_writemax64(cpu, data, len, odata);
# Line 156  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          if (writeflag == MEM_WRITE)          if (writeflag == MEM_WRITE)
152                  idata = memory_readmax64(cpu, data, len);                  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 184  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;  
         }  
   
         pci_word = relative_addr & 0x00ffffff;  
167    
168          res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,          bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ?
169              &pci_word, MEM_WRITE, d->pcibus);              &odata : &idata, len, writeflag);
         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 219  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;
# Line 245  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 349  int dev_footbridge_access(struct cpu *cp Line 328  int dev_footbridge_access(struct cpu *cp
328          case TIMER_1_VALUE:          case TIMER_1_VALUE:
329                  if (writeflag == MEM_READ) {                  if (writeflag == MEM_READ) {
330                          /*                          /*
331                           *  TODO: This is INCORRECT! but speeds up NetBSD                           *  NOTE/TODO: This is INCORRECT but speeds up NetBSD
332                           *  and OpenBSD boot sequences. A better solution                           *  and OpenBSD boot sequences: if the timer is polled
333                           *  would be to only call dev_footbridge_tick() if                           *  "very often" (such as during bootup), then this
334                           *  the timer is polled "very often" (such as during                           *  causes the timers to expire quickly.
                          *  bootup), but not during normal operation.  
335                           */                           */
336                          d->timer_being_read = 1;                          d->timer_being_read = 1;
337                          d->timer_poll_mode ++;                          d->timer_poll_mode ++;
338                          if (d->timer_poll_mode > TIMER_POLL_THRESHOLD)                          if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {
339                                    d->timer_poll_mode = TIMER_POLL_THRESHOLD;
340                                  dev_footbridge_tick(cpu, d);                                  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;                          d->timer_being_read = 0;
346                  } else                  } else
# Line 409  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 428  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                  /*  bus_pci_add(devinit->machine, d->pcibus,                      devinit->machine->memory, 0xc0, 10, 0, "dec21143");
                     devinit->machine->memory, 0xc0, 10, 0,  
                     pci_dec21143_init, pci_dec21143_rr);  */  
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 468  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++) {

Legend:
Removed from v.18  
changed lines
  Added in v.22

  ViewVC Help
Powered by ViewVC 1.1.26