/[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 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC
# 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.36 2005/11/21 09:17:26 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.
  *      o)  Lots of other things.  
35   */   */
36    
37  #include <stdio.h>  #include <stdio.h>
# Line 54  Line 52 
52    
53  #define DEV_FOOTBRIDGE_TICK_SHIFT       14  #define DEV_FOOTBRIDGE_TICK_SHIFT       14
54  #define DEV_FOOTBRIDGE_LENGTH           0x400  #define DEV_FOOTBRIDGE_LENGTH           0x400
55    #define TIMER_POLL_THRESHOLD            15
56    
57    
58  /*  /*
# Line 68  void dev_footbridge_tick(struct cpu *cpu Line 67  void dev_footbridge_tick(struct cpu *cpu
67          int i;          int i;
68          struct footbridge_data *d = (struct footbridge_data *) extra;          struct footbridge_data *d = (struct footbridge_data *) extra;
69    
70            if (!d->timer_being_read)
71                    d->timer_poll_mode = 0;
72    
73          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
74                  int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;                  int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;
75                  if (d->timer_control[i] & TIMER_FCLK_16)                  if (d->timer_control[i] & TIMER_FCLK_16)
# Line 99  void dev_footbridge_tick(struct cpu *cpu Line 101  void dev_footbridge_tick(struct cpu *cpu
101  /*  /*
102   *  dev_footbridge_isa_access():   *  dev_footbridge_isa_access():
103   *   *
104   *  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
105   *  a quicker way than dealing with legacy 0x20/0xa0 ISA ports.   *  interrupt has occurred (and acknowledging it at the same time), than
106     *  dealing with the legacy 0x20/0xa0 ISA ports.
107   */   */
108  int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem,  int dev_footbridge_isa_access(struct cpu *cpu, struct memory *mem,
109          uint64_t relative_addr, unsigned char *data, size_t len,          uint64_t relative_addr, unsigned char *data, size_t len,
# Line 110  int dev_footbridge_isa_access(struct cpu Line 113  int dev_footbridge_isa_access(struct cpu
113          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
114          int x;          int x;
115    
116          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE) {
117                    idata = memory_readmax64(cpu, data, len);
         if (writeflag == MEM_WRITE)  
118                  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;  
119          }          }
120    
121          if (x == 16)          x = cpu->machine->isa_pic_data.last_int;
122                  fatal("_\n_  SPORADIC but INVALID ISA interrupt\n_\n");          if (x == 0)
123                    cpu_interrupt_ack(cpu, 32 + x);
124          odata = 0x20 + (x & 15);  
125            if (x < 8)
126                    odata = cpu->machine->isa_pic_data.pic1->irq_base + x;
127            else
128                    odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8;
129    
130          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
131                  memory_writemax64(cpu, data, len, odata);                  memory_writemax64(cpu, data, len, odata);
# Line 162  int dev_footbridge_pci_access(struct cpu Line 151  int dev_footbridge_pci_access(struct cpu
151          int bus, device, function, regnr, res;          int bus, device, function, regnr, res;
152          uint64_t pci_word;          uint64_t pci_word;
153    
154          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
155                    idata = memory_readmax64(cpu, data, len);
156    
157          bus      = (relative_addr >> 16) & 0xff;          bus      = (relative_addr >> 16) & 0xff;
158          device   = (relative_addr >> 11) & 0x1f;          device   = (relative_addr >> 11) & 0x1f;
# Line 187  int dev_footbridge_pci_access(struct cpu Line 177  int dev_footbridge_pci_access(struct cpu
177          pci_word = relative_addr & 0x00ffffff;          pci_word = relative_addr & 0x00ffffff;
178    
179          res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,          res = bus_pci_access(cpu, mem, BUS_PCI_ADDR,
180              &pci_word, MEM_WRITE, d->pcibus);              &pci_word, sizeof(uint32_t), MEM_WRITE, d->pcibus);
181          if (writeflag == MEM_READ) {          if (writeflag == MEM_READ) {
182                  res = bus_pci_access(cpu, mem, BUS_PCI_DATA,                  res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
183                      &pci_word, MEM_READ, d->pcibus);                      &pci_word, len, MEM_READ, d->pcibus);
184                  odata = pci_word;                  odata = pci_word;
185          } else {          } else {
186                  pci_word = idata;                  pci_word = idata;
187                  res = bus_pci_access(cpu, mem, BUS_PCI_DATA,                  res = bus_pci_access(cpu, mem, BUS_PCI_DATA,
188                      &pci_word, MEM_WRITE, d->pcibus);                      &pci_word, len, MEM_WRITE, d->pcibus);
189          }          }
190    
191          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
# Line 218  int dev_footbridge_access(struct cpu *cp Line 208  int dev_footbridge_access(struct cpu *cp
208          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
209          int timer_nr = 0;          int timer_nr = 0;
210    
211          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
212                    idata = memory_readmax64(cpu, data, len);
213    
214          if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {          if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) {
215                  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 226  int dev_footbridge_access(struct cpu *cp
226                  odata = 0x1065;  /*  DC21285_DEVICE_ID  */                  odata = 0x1065;  /*  DC21285_DEVICE_ID  */
227                  break;                  break;
228    
229            case 0x04:
230            case 0x0c:
231            case 0x10:
232            case 0x14:
233            case 0x18:
234                    /*  TODO. Written to by Linux.  */
235                    break;
236    
237          case REVISION:          case REVISION:
238                  odata = 3;  /*  footbridge revision number  */                  odata = 3;  /*  footbridge revision number  */
239                  break;                  break;
240    
241            case PCI_ADDRESS_EXTENSION:
242                    /*  TODO: Written to by Linux.  */
243                    if (writeflag == MEM_WRITE && idata != 0)
244                            fatal("[ footbridge: TODO: write to PCI_ADDRESS_"
245                                "EXTENSION: 0x%llx ]\n", (long long)idata);
246                    break;
247    
248          case UART_DATA:          case UART_DATA:
249                  if (writeflag == MEM_WRITE)                  if (writeflag == MEM_WRITE)
250                          console_putchar(d->console_handle, idata);                          console_putchar(d->console_handle, idata);
# Line 276  int dev_footbridge_access(struct cpu *cp Line 282  int dev_footbridge_access(struct cpu *cp
282                          d->irq_enable |= idata;                          d->irq_enable |= idata;
283                          cpu_interrupt(cpu, 64);                          cpu_interrupt(cpu, 64);
284                  } else {                  } else {
285                            odata = d->irq_enable;
286                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
287                              "ENABLE SET? ]\n");                              "ENABLE SET? ]\n");
288                          exit(1);                          exit(1);
                         odata = d->irq_enable;  
289                  }                  }
290                  break;                  break;
291    
# Line 288  int dev_footbridge_access(struct cpu *cp Line 294  int dev_footbridge_access(struct cpu *cp
294                          d->irq_enable &= ~idata;                          d->irq_enable &= ~idata;
295                          cpu_interrupt(cpu, 64);                          cpu_interrupt(cpu, 64);
296                  } else {                  } else {
297                            odata = d->irq_enable;
298                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
299                              "ENABLE CLEAR? ]\n");                              "ENABLE CLEAR? ]\n");
300                          exit(1);                          exit(1);
                         odata = d->irq_enable;  
301                  }                  }
302                  break;                  break;
303    
# Line 338  int dev_footbridge_access(struct cpu *cp Line 344  int dev_footbridge_access(struct cpu *cp
344    
345          case TIMER_1_VALUE:          case TIMER_1_VALUE:
346                  if (writeflag == MEM_READ) {                  if (writeflag == MEM_READ) {
347                          dev_footbridge_tick(cpu, d);                          /*
348                             *  NOTE/TODO: This is INCORRECT but speeds up NetBSD
349                             *  and OpenBSD boot sequences: if the timer is polled
350                             *  "very often" (such as during bootup), then this
351                             *  causes the timers to expire quickly.
352                             */
353                            d->timer_being_read = 1;
354                            d->timer_poll_mode ++;
355                            if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {
356                                    d->timer_poll_mode = TIMER_POLL_THRESHOLD;
357                                    dev_footbridge_tick(cpu, d);
358                                    dev_footbridge_tick(cpu, d);
359                                    dev_footbridge_tick(cpu, d);
360                            }
361                          odata = d->timer_value[timer_nr];                          odata = d->timer_value[timer_nr];
362                            d->timer_being_read = 0;
363                  } else                  } else
364                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
365                  break;                  break;
# Line 407  int devinit_footbridge(struct devinit *d Line 427  int devinit_footbridge(struct devinit *d
427          /*  DC21285 register access:  */          /*  DC21285 register access:  */
428          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
429              devinit->addr, DEV_FOOTBRIDGE_LENGTH,              devinit->addr, DEV_FOOTBRIDGE_LENGTH,
430              dev_footbridge_access, d, MEM_DEFAULT, NULL);              dev_footbridge_access, d, DM_DEFAULT, NULL);
431    
432          /*  ISA interrupt status word:  */          /*  ISA interrupt status/acknowledgement:  */
433          memory_device_register(devinit->machine->memory, "footbridge_isa",          memory_device_register(devinit->machine->memory, "footbridge_isa",
434              0x79000000, 8, dev_footbridge_isa_access, d, MEM_DEFAULT, NULL);              0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL);
435    
436          /*  The "fcom" console:  */          /*  The "fcom" console:  */
437          d->console_handle = console_start_slave(devinit->machine, "fcom");          d->console_handle = console_start_slave(devinit->machine, "fcom");
438    
439          /*  A PCI bus:  */          /*  A PCI bus:  */
440          d->pcibus = bus_pci_init(devinit->irq_nr);          d->pcibus = bus_pci_init(
441                devinit->irq_nr,    /*  PCI controller irq  */
442                0x7c000000,         /*  PCI device io offset  */
443                0x80000000,         /*  PCI device mem offset  */
444                0x00000000,         /*  PCI port base  */
445                0x00000000,         /*  PCI mem base  */
446                0,                  /*  PCI irq base: TODO  */
447                0x7c000000,         /*  ISA port base  */
448                0x80000000,         /*  ISA mem base  */
449                32);                /*  ISA port base  */
450    
451          /*  ... with some default devices for known machine types:  */          /*  ... with some default devices for known machine types:  */
452          switch (devinit->machine->machine_type) {          switch (devinit->machine->machine_type) {
453          case MACHINE_CATS:          case MACHINE_CATS:
454                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
455                      devinit->machine->memory, 0xc0, 7, 0,                      devinit->machine->memory, 0xc0, 7, 0, "ali_m1543");
456                      pci_ali_m1543_init, pci_ali_m1543_rr);                  bus_pci_add(devinit->machine, d->pcibus,
457                        devinit->machine->memory, 0xc0, 10, 0, "dec21143");
458                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
459                      devinit->machine->memory, 0xc0, 16, 0,                      devinit->machine->memory, 0xc0, 16, 0, "ali_m5229");
                     pci_ali_m5229_init, pci_ali_m5229_rr);  
460                  break;                  break;
461          case MACHINE_NETWINDER:          case MACHINE_NETWINDER:
462                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
463                      devinit->machine->memory, 0xc0, 11, 0,                      devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553");
                     pci_symphony_83c553_init, pci_symphony_83c553_rr);  
464                  bus_pci_add(devinit->machine, d->pcibus,                  bus_pci_add(devinit->machine, d->pcibus,
465                      devinit->machine->memory, 0xc0, 11, 1,                      devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105");
                     pci_symphony_82c105_init, pci_symphony_82c105_rr);  
466                  break;                  break;
467          default:fatal("footbridge: unimplemented machine type.\n");          default:fatal("footbridge: unimplemented machine type.\n");
468                  exit(1);                  exit(1);
# Line 444  int devinit_footbridge(struct devinit *d Line 471  int devinit_footbridge(struct devinit *d
471          /*  PCI configuration space:  */          /*  PCI configuration space:  */
472          memory_device_register(devinit->machine->memory,          memory_device_register(devinit->machine->memory,
473              "footbridge_pci", pci_addr, 0x1000000,              "footbridge_pci", pci_addr, 0x1000000,
474              dev_footbridge_pci_access, d, MEM_DEFAULT, NULL);              dev_footbridge_pci_access, d, DM_DEFAULT, NULL);
475    
476          /*  Timer ticks:  */          /*  Timer ticks:  */
477          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {

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

  ViewVC Help
Powered by ViewVC 1.1.26