/[gxemul]/trunk/src/devices/dev_i80321.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_i80321.c

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

revision 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  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_i80321.c,v 1.5 2005/11/13 00:14:09 debug Exp $   *  $Id: dev_i80321.c,v 1.20 2007/02/05 16:49:21 debug Exp $
29   *   *
30   *  i80321.  TODO: This is just a dummy so far.   *  Intel i80321 (ARM) core functionality.
31     *
32     *      o)  Interrupt controller
33     *      o)  Timer
34     *      o)  PCI controller
35     *      o)  Memory controller
36     *
37     *  TODO:
38     *      o)  LOTS of things left to implement.
39     *      o)  This is hardcoded for little endian emulation.
40   */   */
41    
42  #include <stdio.h>  #include <stdio.h>
43  #include <stdlib.h>  #include <stdlib.h>
44  #include <string.h>  #include <string.h>
45    
46    #include "bus_pci.h"
47  #include "cpu.h"  #include "cpu.h"
48  #include "device.h"  #include "device.h"
49  #include "machine.h"  #include "machine.h"
50  #include "memory.h"  #include "memory.h"
51  #include "misc.h"  #include "misc.h"
52    #include "timer.h"
53    
54    
55  #include "i80321reg.h"  #include "i80321reg.h"
56    
57  #define DEV_I80321_LENGTH               VERDE_PMMR_SIZE  #define TICK_SHIFT              15
58    #define DEV_I80321_LENGTH       VERDE_PMMR_SIZE
59    
60  struct i80321_data {  struct i80321_data {
61          uint32_t        mcu_reg[VERDE_MCU_SIZE / sizeof(uint32_t)];          /*  Interrupt Controller  */
62            struct interrupt irq;
63            uint32_t        *status;        /*  Note: these point to i80321_isrc  */
64            uint32_t        *enable;        /*  and i80321_inten in the CPU!  */
65    
66            /*  Timer:  */
67            struct timer    *timer;
68            double          hz;
69            int             pending_tmr0_interrupts;
70    
71            /*  PCI Controller:  */
72            uint32_t        pci_addr;
73            struct pci_data *pci_bus;
74    
75            /*  Memory Controller:  */
76            uint32_t        mcu_reg[0x100 / sizeof(uint32_t)];
77  };  };
78    
79    
80  /*  static void i80321_assert(struct i80321_data *d, uint32_t linemask)
81   *  dev_i80321_access():  {
82            *d->status |= linemask;
83            if (*d->status & *d->enable)
84                    INTERRUPT_ASSERT(d->irq);
85    }
86    static void i80321_deassert(struct i80321_data *d, uint32_t linemask)
87    {
88            *d->status &= ~linemask;
89            if (!(*d->status & *d->enable))
90                    INTERRUPT_DEASSERT(d->irq);
91    }
92    
93    
94    /*  
95     *  i80321_interrupt_assert():
96     *  i80321_interrupt_deassert():
97     *
98     *  Called whenever an i80321 interrupt is asserted/deasserted.
99   */   */
100  int dev_i80321_access(struct cpu *cpu, struct memory *mem,  void i80321_interrupt_assert(struct interrupt *interrupt)
101          uint64_t relative_addr, unsigned char *data, size_t len,  { i80321_assert(interrupt->extra, interrupt->line); }
102          int writeflag, void *extra)  void i80321_interrupt_deassert(struct interrupt *interrupt)
103    {
104            struct i80321_data *d = interrupt->extra;
105    
106            /*  Ack. timer interrupts:  */
107            if (interrupt->line == 1 << 9 &&
108                d->pending_tmr0_interrupts > 0)
109                    d->pending_tmr0_interrupts --;
110    
111            i80321_deassert(d, interrupt->line);
112    }
113    
114    
115    /*  TMR0 ticks, called d->hz times per second.  */
116    static void tmr0_tick(struct timer *t, void *extra)
117    {
118            struct i80321_data *d = extra;
119            d->pending_tmr0_interrupts ++;
120    }
121    
122    
123    DEVICE_TICK(i80321)
124    {
125            struct i80321_data *d = extra;
126    
127            if (cpu->cd.arm.tmr0 & TMRx_ENABLE && d->pending_tmr0_interrupts > 0) {
128                    i80321_assert(d, 1 << 9);
129                    cpu->cd.arm.tisr |= TISR_TMR0;
130            } else {
131                    i80321_deassert(d, 1 << 9);
132                    cpu->cd.arm.tisr &= ~TISR_TMR0;
133            }
134    }
135    
136            
137    DEVICE_ACCESS(i80321)
138  {  {
139          struct i80321_data *d = extra;          struct i80321_data *d = extra;
140          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
141          char *n = NULL;          char *n = NULL;
142            int i, bus, dev, func, reg;
143    
144          if (writeflag == MEM_WRITE)          if (writeflag == MEM_WRITE)
145                  idata = memory_readmax64(cpu, data, len);                  idata = memory_readmax64(cpu, data, len);
146    
147            /*  PCI configuration space:  */
148            if (relative_addr >= 0x100 && relative_addr < 0x140) {
149                    /*  TODO  */
150                    goto ret;
151            }
152    
153            /*  MCU registers:  */
154          if (relative_addr >= VERDE_MCU_BASE &&          if (relative_addr >= VERDE_MCU_BASE &&
155              relative_addr <  VERDE_MCU_BASE + VERDE_MCU_SIZE) {              relative_addr <  VERDE_MCU_BASE + VERDE_MCU_SIZE) {
156                  int regnr = (relative_addr - VERDE_MCU_BASE) / sizeof(uint32_t);                  int regnr = (relative_addr - VERDE_MCU_BASE) / sizeof(uint32_t);
# Line 73  int dev_i80321_access(struct cpu *cpu, s Line 160  int dev_i80321_access(struct cpu *cpu, s
160                          odata = d->mcu_reg[regnr];                          odata = d->mcu_reg[regnr];
161          }          }
162    
163    
164          switch (relative_addr) {          switch (relative_addr) {
165    
166            /*  Address Translation Unit:  */
167            case VERDE_ATU_BASE + ATU_IALR0:
168            case VERDE_ATU_BASE + ATU_IATVR0:
169            case VERDE_ATU_BASE + ATU_IALR1:
170            case VERDE_ATU_BASE + ATU_IALR2:
171            case VERDE_ATU_BASE + ATU_IATVR2:
172            case VERDE_ATU_BASE + ATU_OIOWTVR:
173            case VERDE_ATU_BASE + ATU_OMWTVR0:
174            case VERDE_ATU_BASE + ATU_OUMWTVR0:
175            case VERDE_ATU_BASE + ATU_OMWTVR1:
176            case VERDE_ATU_BASE + ATU_OUMWTVR1:
177                    /*  Ignoring these for now. TODO  */
178                    break;
179            case VERDE_ATU_BASE + ATU_ATUCR:
180                    /*  ATU configuration register; ignored for now. TODO  */
181                    break;
182            case VERDE_ATU_BASE + ATU_PCSR:
183                    /*  TODO: Temporary hack to allow NetBSD/evbarm to
184                        reboot itself.  Should be rewritten as soon as possible!  */
185                    if (writeflag == MEM_WRITE && idata == 0x30) {
186                            int j;
187                            for (j=0; j<cpu->machine->ncpus; j++)
188                                    cpu->machine->cpus[j]->running = 0;
189                            cpu->machine->exit_without_entering_debugger = 1;
190                    }
191                    break;
192            case VERDE_ATU_BASE + ATU_ATUIMR:
193            case VERDE_ATU_BASE + ATU_IABAR3:
194            case VERDE_ATU_BASE + ATU_IAUBAR3:
195            case VERDE_ATU_BASE + ATU_IALR3:
196            case VERDE_ATU_BASE + ATU_IATVR3:
197                    /*  Ignoring these for now. TODO  */
198                    break;
199            case VERDE_ATU_BASE + ATU_OCCAR:
200                    /*  PCI address  */
201                    if (writeflag == MEM_WRITE) {
202                            d->pci_addr = idata;
203                            bus_pci_decompose_1(idata, &bus, &dev, &func, &reg);
204                            bus = 0;        /*  NOTE  */
205                            bus_pci_setaddr(cpu, d->pci_bus, bus, dev, func, reg);
206                    } else {
207                            odata = d->pci_addr;
208                    }
209                    break;
210            case VERDE_ATU_BASE + ATU_OCCDR:
211            case VERDE_ATU_BASE + ATU_OCCDR + 1:
212            case VERDE_ATU_BASE + ATU_OCCDR + 2:
213            case VERDE_ATU_BASE + ATU_OCCDR + 3:
214                    /*  PCI data  */
215                    if (writeflag == MEM_READ) {
216                            uint64_t tmp;
217                            bus_pci_data_access(cpu, d->pci_bus, &tmp,
218                                sizeof(uint32_t), MEM_READ);
219                            switch (relative_addr) {
220                            case VERDE_ATU_BASE + ATU_OCCDR + 1:
221                                    odata = tmp >> 8; break;
222                            case VERDE_ATU_BASE + ATU_OCCDR + 2:
223                                    odata = tmp >> 16; break;
224                            case VERDE_ATU_BASE + ATU_OCCDR + 3:
225                                    odata = tmp >> 24; break;
226                            default:odata = tmp;
227                            }
228                    } else {
229                            uint64_t tmp;
230                            int r = relative_addr - (VERDE_ATU_BASE + ATU_OCCDR);
231                            bus_pci_data_access(cpu, d->pci_bus, &tmp,
232                                sizeof(uint32_t), MEM_READ);
233                            for (i=0; i<len; i++) {
234                                    uint8_t b = idata >> (i*8);
235                                    tmp &= ~(0xff << ((r+i)*8));
236                                    tmp |= b << ((r+i)*8);
237                            }
238                            tmp &= 0xffffffff;  /* needed because << is 32-bit */
239                            bus_pci_data_access(cpu, d->pci_bus, &tmp,
240                                sizeof(uint32_t), MEM_WRITE);
241                    }
242                    break;
243            case VERDE_ATU_BASE + ATU_PCIXSR:
244                    odata = 0;              /*  TODO  */
245                    break;
246    
247            /*  Memory Controller Unit:  */
248          case VERDE_MCU_BASE + MCU_SDBR:          case VERDE_MCU_BASE + MCU_SDBR:
249                  n = "MCU_SDBR";                  n = "MCU_SDBR";
250                  break;                  break;
# Line 103  int dev_i80321_access(struct cpu *cpu, s Line 273  int dev_i80321_access(struct cpu *cpu, s
273                  }                  }
274          }          }
275    
276    ret:
277          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
278                  memory_writemax64(cpu, data, len, odata);                  memory_writemax64(cpu, data, len, odata);
279    
# Line 110  int dev_i80321_access(struct cpu *cpu, s Line 281  int dev_i80321_access(struct cpu *cpu, s
281  }  }
282    
283    
284  /*  DEVINIT(i80321)
  *  devinit_i80321():  
  */  
 int devinit_i80321(struct devinit *devinit)  
285  {  {
286          struct i80321_data *d = malloc(sizeof(struct i80321_data));          struct i80321_data *d = malloc(sizeof(struct i80321_data));
287          uint32_t memsize = devinit->machine->physical_ram_in_mb * 1048576;          uint32_t memsize = devinit->machine->physical_ram_in_mb * 1048576;
288          uint32_t base;          uint32_t base;
289            char tmpstr[300];
290            int i;
291            struct cpu *cpu = devinit->machine->cpus[devinit->
292                machine->bootstrap_cpu];
293    
294          if (d == NULL) {          if (d == NULL) {
295                  fprintf(stderr, "out of memory\n");                  fprintf(stderr, "out of memory\n");
# Line 125  int devinit_i80321(struct devinit *devin Line 297  int devinit_i80321(struct devinit *devin
297          }          }
298          memset(d, 0, sizeof(struct i80321_data));          memset(d, 0, sizeof(struct i80321_data));
299    
300            /*  Connect to the CPU interrupt pin:  */
301            INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
302    
303            /*  Register 32 i80321 interrupts:  */
304            for (i=0; i<32; i++) {
305                    struct interrupt template;
306                    char tmpstr[300];
307                    snprintf(tmpstr, sizeof(tmpstr), "%s.i80321.%i",
308                        devinit->interrupt_path, i);
309                    memset(&template, 0, sizeof(template));
310                    template.line = 1 << i;
311                    template.name = tmpstr;
312                    template.extra = d;
313                    template.interrupt_assert = i80321_interrupt_assert;
314                    template.interrupt_deassert = i80321_interrupt_deassert;
315                    interrupt_handler_register(&template);
316    
317                    /*
318                     *  Connect the CPU's TMR0 and TMR1 interrupts to these
319                     *  i80321 timer interrupts (nr 9 and 10):
320                     */
321                    if (i == 9)
322                            INTERRUPT_CONNECT(tmpstr, cpu->cd.arm.tmr0_irq);
323                    if (i == 10)
324                            INTERRUPT_CONNECT(tmpstr, cpu->cd.arm.tmr1_irq);
325            }
326    
327            d->status = &cpu->cd.arm.i80321_isrc;
328            d->enable = &cpu->cd.arm.i80321_inten;
329    
330          d->mcu_reg[MCU_SDBR / sizeof(uint32_t)] = base = 0xa0000000;          d->mcu_reg[MCU_SDBR / sizeof(uint32_t)] = base = 0xa0000000;
331          d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base+memsize) >> 25;          d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base + memsize) >> 25;
332          d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base+memsize) >> 25;          d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base + memsize) >> 25;
333    
334            snprintf(tmpstr, sizeof(tmpstr), "%s.i80321", devinit->interrupt_path);
335    
336            d->pci_bus = bus_pci_init(devinit->machine,
337                tmpstr      /*  pciirq  */,
338                0x90000000  /*  TODO: pci_io_offset  */,
339                0x90010000  /*  TODO: pci_mem_offset  */,
340                0xffff0000  /*  TODO: pci_portbase  */,
341                0x00000000  /*  TODO: pci_membase  */,
342                tmpstr      /*  pci_irqbase  */,
343                0x90000000  /*  TODO: isa_portbase  */,
344                0x90010000  /*  TODO: isa_membase  */,
345                "TODO: isa_irqbase" /*  TODO: isa_irqbase  */);
346    
347          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
348              devinit->addr, DEV_I80321_LENGTH,              devinit->addr, DEV_I80321_LENGTH,
349              dev_i80321_access, d, DM_DEFAULT, NULL);              dev_i80321_access, d, DM_DEFAULT, NULL);
350    
351            /*  TODO: Don't hardcode to 100 Hz!  */
352            d->hz = 100;
353            d->timer = timer_add(d->hz, tmr0_tick, d);
354    
355            machine_add_tickfunction(devinit->machine, dev_i80321_tick,
356                d, TICK_SHIFT, 0.0);
357    
358            devinit->return_ptr = d->pci_bus;
359    
360          return 1;          return 1;
361  }  }
362    

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

  ViewVC Help
Powered by ViewVC 1.1.26