/[gxemul]/upstream/0.4.4/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

Annotation of /upstream/0.4.4/src/devices/dev_i80321.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (hide annotations)
Mon Oct 8 16:21:26 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 10103 byte(s)
0.4.4
1 dpavlin 18 /*
2 dpavlin 34 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 dpavlin 18 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 34 * $Id: dev_i80321.c,v 1.20 2007/02/05 16:49:21 debug Exp $
29 dpavlin 18 *
30 dpavlin 22 * Intel i80321 (ARM) core functionality.
31     *
32 dpavlin 34 * 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 dpavlin 18 */
41    
42     #include <stdio.h>
43     #include <stdlib.h>
44     #include <string.h>
45    
46 dpavlin 22 #include "bus_pci.h"
47 dpavlin 18 #include "cpu.h"
48     #include "device.h"
49     #include "machine.h"
50     #include "memory.h"
51     #include "misc.h"
52 dpavlin 34 #include "timer.h"
53 dpavlin 18
54    
55     #include "i80321reg.h"
56    
57 dpavlin 34 #define TICK_SHIFT 15
58 dpavlin 22 #define DEV_I80321_LENGTH VERDE_PMMR_SIZE
59 dpavlin 18
60 dpavlin 34 struct i80321_data {
61     /* 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 dpavlin 18
66 dpavlin 34 /* 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 dpavlin 22 {
82 dpavlin 34 *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 dpavlin 18
93 dpavlin 22
94 dpavlin 34 /*
95     * i80321_interrupt_assert():
96     * i80321_interrupt_deassert():
97     *
98     * Called whenever an i80321 interrupt is asserted/deasserted.
99     */
100     void i80321_interrupt_assert(struct interrupt *interrupt)
101     { i80321_assert(interrupt->extra, interrupt->line); }
102     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 dpavlin 22 cpu->cd.arm.tisr |= TISR_TMR0;
130     } else {
131 dpavlin 34 i80321_deassert(d, 1 << 9);
132 dpavlin 22 cpu->cd.arm.tisr &= ~TISR_TMR0;
133     }
134     }
135    
136    
137     DEVICE_ACCESS(i80321)
138 dpavlin 18 {
139     struct i80321_data *d = extra;
140     uint64_t idata = 0, odata = 0;
141     char *n = NULL;
142 dpavlin 22 int i, bus, dev, func, reg;
143 dpavlin 18
144     if (writeflag == MEM_WRITE)
145     idata = memory_readmax64(cpu, data, len);
146    
147 dpavlin 22 /* PCI configuration space: */
148     if (relative_addr >= 0x100 && relative_addr < 0x140) {
149     /* TODO */
150     goto ret;
151     }
152    
153     /* MCU registers: */
154 dpavlin 18 if (relative_addr >= VERDE_MCU_BASE &&
155     relative_addr < VERDE_MCU_BASE + VERDE_MCU_SIZE) {
156     int regnr = (relative_addr - VERDE_MCU_BASE) / sizeof(uint32_t);
157     if (writeflag == MEM_WRITE)
158     d->mcu_reg[regnr] = idata;
159     else
160     odata = d->mcu_reg[regnr];
161     }
162    
163 dpavlin 22
164 dpavlin 18 switch (relative_addr) {
165    
166 dpavlin 22 /* 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 dpavlin 18 case VERDE_MCU_BASE + MCU_SDBR:
249     n = "MCU_SDBR";
250     break;
251     case VERDE_MCU_BASE + MCU_SBR0:
252     n = "MCU_SBR0";
253     break;
254     case VERDE_MCU_BASE + MCU_SBR1:
255     n = "MCU_SBR1";
256     break;
257    
258     default:if (writeflag == MEM_READ) {
259     fatal("[ i80321: read from 0x%x ]\n",
260     (int)relative_addr);
261     } else {
262     fatal("[ i80321: write to 0x%x: 0x%llx ]\n",
263     (int)relative_addr, (long long)idata);
264     }
265     }
266    
267     if (n != NULL) {
268     if (writeflag == MEM_READ) {
269     debug("[ i80321: read from %s ]\n", n);
270     } else {
271     debug("[ i80321: write to %s: 0x%llx ]\n",
272     n, (long long)idata);
273     }
274     }
275    
276 dpavlin 22 ret:
277 dpavlin 18 if (writeflag == MEM_READ)
278     memory_writemax64(cpu, data, len, odata);
279    
280     return 1;
281     }
282    
283    
284 dpavlin 22 DEVINIT(i80321)
285 dpavlin 18 {
286     struct i80321_data *d = malloc(sizeof(struct i80321_data));
287     uint32_t memsize = devinit->machine->physical_ram_in_mb * 1048576;
288     uint32_t base;
289 dpavlin 34 char tmpstr[300];
290     int i;
291     struct cpu *cpu = devinit->machine->cpus[devinit->
292     machine->bootstrap_cpu];
293 dpavlin 18
294     if (d == NULL) {
295     fprintf(stderr, "out of memory\n");
296     exit(1);
297     }
298     memset(d, 0, sizeof(struct i80321_data));
299    
300 dpavlin 34 /* 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 dpavlin 18 d->mcu_reg[MCU_SDBR / sizeof(uint32_t)] = base = 0xa0000000;
331 dpavlin 22 d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base + memsize) >> 25;
332     d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base + memsize) >> 25;
333 dpavlin 18
334 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "%s.i80321", devinit->interrupt_path);
335    
336 dpavlin 22 d->pci_bus = bus_pci_init(devinit->machine,
337 dpavlin 34 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 dpavlin 22
347 dpavlin 18 memory_device_register(devinit->machine->memory, devinit->name,
348     devinit->addr, DEV_I80321_LENGTH,
349 dpavlin 20 dev_i80321_access, d, DM_DEFAULT, NULL);
350 dpavlin 18
351 dpavlin 34 /* TODO: Don't hardcode to 100 Hz! */
352     d->hz = 100;
353     d->timer = timer_add(d->hz, tmr0_tick, d);
354    
355 dpavlin 22 machine_add_tickfunction(devinit->machine, dev_i80321_tick,
356 dpavlin 24 d, TICK_SHIFT, 0.0);
357 dpavlin 22
358 dpavlin 34 devinit->return_ptr = d->pci_bus;
359 dpavlin 22
360 dpavlin 18 return 1;
361     }
362    

  ViewVC Help
Powered by ViewVC 1.1.26