/[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 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2007  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.48 2006/09/30 10:09:19 debug Exp $   *  $Id: dev_footbridge.c,v 1.57 2007/06/15 19:11:15 debug Exp $
29   *   *
30   *  Footbridge. Used in Netwinder and Cats.   *  COMMENT: DC21285 "Footbridge" controller; used in Netwinder and Cats
31   *   *
32   *  TODO:   *  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)  Pretty much everything else as well :)  (This entire thing   *      o)  Pretty much everything else as well :)  (This entire thing
36   *          is a quick hack to work primarily with NetBSD and OpenBSD   *          is a quick hack to work primarily with NetBSD and OpenBSD
37   *          as a guest OS.)   *          as guest OSes.)
38   */   */
39    
40  #include <stdio.h>  #include <stdio.h>
# Line 57  Line 57 
57  #define DEV_FOOTBRIDGE_TICK_SHIFT       14  #define DEV_FOOTBRIDGE_TICK_SHIFT       14
58  #define DEV_FOOTBRIDGE_LENGTH           0x400  #define DEV_FOOTBRIDGE_LENGTH           0x400
59    
60    #define N_FOOTBRIDGE_TIMERS             4
61    
62    struct footbridge_data {
63            struct interrupt irq;
64    
65            struct pci_data *pcibus;
66    
67            int             console_handle;
68    
69            uint32_t        timer_load[N_FOOTBRIDGE_TIMERS];
70            uint32_t        timer_value[N_FOOTBRIDGE_TIMERS];
71            uint32_t        timer_control[N_FOOTBRIDGE_TIMERS];
72    
73            struct interrupt timer_irq[N_FOOTBRIDGE_TIMERS];
74            struct timer    *timer[N_FOOTBRIDGE_TIMERS];
75            int             pending_timer_interrupts[N_FOOTBRIDGE_TIMERS];
76    
77            int             irq_asserted;
78    
79            uint32_t        irq_status;
80            uint32_t        irq_enable;
81    
82            uint32_t        fiq_status;
83            uint32_t        fiq_enable;
84    };
85    
86    
87  static void timer_tick0(struct timer *t, void *extra)  static void timer_tick0(struct timer *t, void *extra)
88  { ((struct footbridge_data *)extra)->pending_timer_interrupts[0] ++; }  { ((struct footbridge_data *)extra)->pending_timer_interrupts[0] ++; }
# Line 81  static void reload_timer_value(struct cp Line 107  static void reload_timer_value(struct cp
107          freq /= (double)cycles;          freq /= (double)cycles;
108    
109          d->timer_value[timer_nr] = d->timer_load[timer_nr];          d->timer_value[timer_nr] = d->timer_load[timer_nr];
         d->timer_tick_countdown[timer_nr] = 1;  
110    
111          /*  printf("%i: %i -> %f Hz\n", timer_nr,          /*  printf("%i: %i -> %f Hz\n", timer_nr,
112              d->timer_load[timer_nr], freq);  */              d->timer_load[timer_nr], freq);  */
# Line 100  static void reload_timer_value(struct cp Line 125  static void reload_timer_value(struct cp
125    
126    
127  /*  /*
  *  dev_footbridge_tick():  
  *  
128   *  The 4 footbridge timers should decrease and cause interrupts. Periodic   *  The 4 footbridge timers should decrease and cause interrupts. Periodic
129   *  interrupts restart as soon as they are acknowledged, non-periodic   *  interrupts restart as soon as they are acknowledged, non-periodic
130   *  interrupts need to be "reloaded" to restart.   *  interrupts need to be "reloaded" to restart.
# Line 109  static void reload_timer_value(struct cp Line 132  static void reload_timer_value(struct cp
132   *  TODO: Hm. I thought I had solved this, but it didn't quite work.   *  TODO: Hm. I thought I had solved this, but it didn't quite work.
133   *        This needs to be re-checked against documentation, sometime.   *        This needs to be re-checked against documentation, sometime.
134   */   */
135  void dev_footbridge_tick(struct cpu *cpu, void *extra)  DEVICE_TICK(footbridge)
136  {  {
137            struct footbridge_data *d = extra;
138          int i;          int i;
         struct footbridge_data *d = (struct footbridge_data *) extra;  
139    
140          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
141                  if (d->timer_control[i] & TIMER_ENABLE) {                  if (d->timer_control[i] & TIMER_ENABLE) {
142                          if (d->pending_timer_interrupts[i] > 0) {                          if (d->pending_timer_interrupts[i] > 0) {
143                                  d->timer_value[i] = random() % d->timer_load[i];                                  d->timer_value[i] = random() % d->timer_load[i];
144                                  cpu_interrupt(cpu, IRQ_TIMER_1 + i);                                  INTERRUPT_ASSERT(d->timer_irq[i]);
145                          }                          }
146                  }                  }
147          }          }
# Line 126  void dev_footbridge_tick(struct cpu *cpu Line 149  void dev_footbridge_tick(struct cpu *cpu
149    
150    
151  /*  /*
152   *  dev_footbridge_isa_access():   *  footbridge_interrupt_assert():
153   *   */
154    void footbridge_interrupt_assert(struct interrupt *interrupt)
155    {
156            struct footbridge_data *d = (struct footbridge_data *) interrupt->extra;
157            d->irq_status |= interrupt->line;
158    
159            if ((d->irq_status & d->irq_enable) && !d->irq_asserted) {
160                    d->irq_asserted = 1;
161                    INTERRUPT_ASSERT(d->irq);
162            }
163    }
164    
165    
166    /*
167     *  footbridge_interrupt_deassert():
168     */
169    void footbridge_interrupt_deassert(struct interrupt *interrupt)
170    {
171            struct footbridge_data *d = (struct footbridge_data *) interrupt->extra;
172            d->irq_status &= ~interrupt->line;
173    
174            if (!(d->irq_status & d->irq_enable) && d->irq_asserted) {
175                    d->irq_asserted = 0;
176                    INTERRUPT_DEASSERT(d->irq);
177            }
178    }
179    
180    
181    /*
182   *  Reading the byte at 0x79000000 is a quicker way to figure out which ISA   *  Reading the byte at 0x79000000 is a quicker way to figure out which ISA
183   *  interrupt has occurred (and acknowledging it at the same time), than   *  interrupt has occurred (and acknowledging it at the same time), than
184   *  dealing with the legacy 0x20/0xa0 ISA ports.   *  dealing with the legacy 0x20/0xa0 ISA ports.
# Line 144  DEVICE_ACCESS(footbridge_isa) Line 195  DEVICE_ACCESS(footbridge_isa)
195          }          }
196    
197          x = cpu->machine->isa_pic_data.last_int;          x = cpu->machine->isa_pic_data.last_int;
         if (x == 0)  
                 cpu_interrupt_ack(cpu, 32 + x);  
   
198          if (x < 8)          if (x < 8)
199                  odata = cpu->machine->isa_pic_data.pic1->irq_base + x;                  odata = cpu->machine->isa_pic_data.pic1->irq_base + x;
200          else          else
# Line 182  exit(1); Line 230  exit(1);
230    
231    
232  /*  /*
  *  dev_footbridge_pci_access():  
  *  
233   *  The Footbridge PCI configuration space is implemented as a direct memory   *  The Footbridge PCI configuration space is implemented as a direct memory
234   *  space (i.e. not one port for addr and one port for data). This function   *  space (i.e. not one port for addr and one port for data). This function
235   *  translates that into bus_pci calls.   *  translates that into bus_pci calls.
# Line 221  DEVICE_ACCESS(footbridge_pci) Line 267  DEVICE_ACCESS(footbridge_pci)
267  }  }
268    
269    
 /*  
  *  dev_footbridge_access():  
  *  
  *  The DC21285 registers.  
  */  
270  DEVICE_ACCESS(footbridge)  DEVICE_ACCESS(footbridge)
271  {  {
272          struct footbridge_data *d = extra;          struct footbridge_data *d = extra;
# Line 309  DEVICE_ACCESS(footbridge) Line 350  DEVICE_ACCESS(footbridge)
350          case IRQ_ENABLE_SET:          case IRQ_ENABLE_SET:
351                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
352                          d->irq_enable |= idata;                          d->irq_enable |= idata;
353                          cpu_interrupt(cpu, 64);                          if (d->irq_status & d->irq_enable)
354                                    INTERRUPT_ASSERT(d->irq);
355                            else
356                                    INTERRUPT_DEASSERT(d->irq);
357                  } else {                  } else {
358                          odata = d->irq_enable;                          odata = d->irq_enable;
359                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
# Line 321  DEVICE_ACCESS(footbridge) Line 365  DEVICE_ACCESS(footbridge)
365          case IRQ_ENABLE_CLEAR:          case IRQ_ENABLE_CLEAR:
366                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
367                          d->irq_enable &= ~idata;                          d->irq_enable &= ~idata;
368                          cpu_interrupt(cpu, 64);                          if (d->irq_status & d->irq_enable)
369                                    INTERRUPT_ASSERT(d->irq);
370                            else
371                                    INTERRUPT_DEASSERT(d->irq);
372                  } else {                  } else {
373                          odata = d->irq_enable;                          odata = d->irq_enable;
374                          fatal("[ WARNING: footbridge read from "                          fatal("[ WARNING: footbridge read from "
# Line 367  DEVICE_ACCESS(footbridge) Line 414  DEVICE_ACCESS(footbridge)
414                          /*  debug("[ footbridge: timer %i (1-based), "                          /*  debug("[ footbridge: timer %i (1-based), "
415                              "value %i ]\n", timer_nr + 1,                              "value %i ]\n", timer_nr + 1,
416                              (int)d->timer_value[timer_nr]);  */                              (int)d->timer_value[timer_nr]);  */
417                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                          INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
418                  }                  }
419                  break;                  break;
420    
# Line 394  DEVICE_ACCESS(footbridge) Line 441  DEVICE_ACCESS(footbridge)
441                          } else {                          } else {
442                                  d->pending_timer_interrupts[timer_nr] = 0;                                  d->pending_timer_interrupts[timer_nr] = 0;
443                          }                          }
444                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                          INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
445                  }                  }
446                  break;                  break;
447    
# Line 407  DEVICE_ACCESS(footbridge) Line 454  DEVICE_ACCESS(footbridge)
454                          d->pending_timer_interrupts[timer_nr] --;                          d->pending_timer_interrupts[timer_nr] --;
455                  }                  }
456    
457                  cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                  INTERRUPT_DEASSERT(d->timer_irq[timer_nr]);
458                  break;                  break;
459    
460          default:if (writeflag == MEM_READ) {          default:if (writeflag == MEM_READ) {
# Line 429  DEVICE_ACCESS(footbridge) Line 476  DEVICE_ACCESS(footbridge)
476  DEVINIT(footbridge)  DEVINIT(footbridge)
477  {  {
478          struct footbridge_data *d;          struct footbridge_data *d;
479            char irq_path[300], irq_path_isa[300];
480          uint64_t pci_addr = 0x7b000000;          uint64_t pci_addr = 0x7b000000;
481          int i;          int i;
482    
483          d = malloc(sizeof(struct footbridge_data));          CHECK_ALLOCATION(d = malloc(sizeof(struct footbridge_data)));
         if (d == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
484          memset(d, 0, sizeof(struct footbridge_data));          memset(d, 0, sizeof(struct footbridge_data));
485    
486            /*  Connect to the CPU which this footbridge will interrupt:  */
487            INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
488    
489          /*  DC21285 register access:  */          /*  DC21285 register access:  */
490          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
491              devinit->addr, DEV_FOOTBRIDGE_LENGTH,              devinit->addr, DEV_FOOTBRIDGE_LENGTH,
# Line 451  DEVINIT(footbridge) Line 498  DEVINIT(footbridge)
498          /*  The "fcom" console:  */          /*  The "fcom" console:  */
499          d->console_handle = console_start_slave(devinit->machine, "fcom", 0);          d->console_handle = console_start_slave(devinit->machine, "fcom", 0);
500    
501            /*  Register 32 footbridge interrupts:  */
502            snprintf(irq_path, sizeof(irq_path), "%s.footbridge",
503                devinit->interrupt_path);
504            for (i=0; i<32; i++) {
505                    struct interrupt interrupt_template;
506                    char tmpstr[200];
507    
508                    memset(&interrupt_template, 0, sizeof(interrupt_template));
509                    interrupt_template.line = 1 << i;
510                    snprintf(tmpstr, sizeof(tmpstr), "%s.%i", irq_path, i);
511                    interrupt_template.name = tmpstr;
512    
513                    interrupt_template.extra = d;
514                    interrupt_template.interrupt_assert =
515                        footbridge_interrupt_assert;
516                    interrupt_template.interrupt_deassert =
517                        footbridge_interrupt_deassert;
518                    interrupt_handler_register(&interrupt_template);
519    
520                    /*  Connect locally to some interrupts:  */
521                    if (i>=IRQ_TIMER_1 && i<=IRQ_TIMER_4)
522                            INTERRUPT_CONNECT(tmpstr, d->timer_irq[i-IRQ_TIMER_1]);
523            }
524    
525            switch (devinit->machine->machine_type) {
526            case MACHINE_CATS:
527                    snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.10", irq_path);
528                    break;
529            case MACHINE_NETWINDER:
530                    snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.11", irq_path);
531                    break;
532            default:fatal("footbridge unimpl machine type\n");
533                    exit(1);
534            }
535    
536          /*  A PCI bus:  */          /*  A PCI bus:  */
537          d->pcibus = bus_pci_init(          d->pcibus = bus_pci_init(
538              devinit->machine,              devinit->machine,
539              devinit->irq_nr,    /*  PCI controller irq  */              irq_path,
540              0x7c000000,         /*  PCI device io offset  */              0x7c000000,         /*  PCI device io offset  */
541              0x80000000,         /*  PCI device mem offset  */              0x80000000,         /*  PCI device mem offset  */
542              0x00000000,         /*  PCI port base  */              0x00000000,         /*  PCI port base  */
543              0x00000000,         /*  PCI mem base  */              0x00000000,         /*  PCI mem base  */
544              0,                  /*  PCI irq base: TODO  */              irq_path,           /*  PCI irq base  */
545              0x7c000000,         /*  ISA port base  */              0x7c000000,         /*  ISA port base  */
546              0x80000000,         /*  ISA mem base  */              0x80000000,         /*  ISA mem base  */
547              32);                /*  ISA port base  */              irq_path_isa);      /*  ISA port base  */
548    
549          /*  ... with some default devices for known machine types:  */          /*  ... with some default devices for known machine types:  */
550          switch (devinit->machine->machine_type) {          switch (devinit->machine->machine_type) {
# Line 497  DEVINIT(footbridge) Line 579  DEVINIT(footbridge)
579                  d->timer_control[i] = TIMER_MODE_PERIODIC;                  d->timer_control[i] = TIMER_MODE_PERIODIC;
580                  d->timer_load[i] = TIMER_MAX_VAL;                  d->timer_load[i] = TIMER_MAX_VAL;
581          }          }
582    
583          machine_add_tickfunction(devinit->machine,          machine_add_tickfunction(devinit->machine,
584              dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT, 0.0);              dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT);
585    
586          devinit->return_ptr = d;          devinit->return_ptr = d->pcibus;
587          return 1;          return 1;
588  }  }
589    

Legend:
Removed from v.32  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26