--- trunk/src/devices/dev_i80321.c 2007/10/08 16:19:28 21 +++ trunk/src/devices/dev_i80321.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,17 +25,22 @@ * SUCH DAMAGE. * * - * $Id: dev_i80321.c,v 1.5 2005/11/13 00:14:09 debug Exp $ + * $Id: dev_i80321.c,v 1.14 2006/02/18 17:55:25 debug Exp $ * - * i80321. TODO: This is just a dummy so far. + * Intel i80321 (ARM) core functionality. + * + * TODO: This is mostly just a dummy device. + * TODO 2: This is hardcoded for little endian emulation. */ #include #include #include +#include "bus_pci.h" #include "cpu.h" #include "device.h" +#include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" @@ -43,27 +48,46 @@ #include "i80321reg.h" -#define DEV_I80321_LENGTH VERDE_PMMR_SIZE +#define TICK_SHIFT 20 +#define DEV_I80321_LENGTH VERDE_PMMR_SIZE -struct i80321_data { - uint32_t mcu_reg[VERDE_MCU_SIZE / sizeof(uint32_t)]; -}; +void dev_i80321_tick(struct cpu *cpu, void *extra) +{ + /* struct i80321_data *d = extra; */ + int do_timer_interrupt = 0; -/* - * dev_i80321_access(): - */ -int dev_i80321_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) + if (cpu->cd.arm.tmr0 & TMRx_ENABLE) { + do_timer_interrupt = 1; + } + + if (do_timer_interrupt) { + cpu_interrupt(cpu, 9); + cpu->cd.arm.tisr |= TISR_TMR0; + } else { + cpu_interrupt_ack(cpu, 9); + cpu->cd.arm.tisr &= ~TISR_TMR0; + } +} + + +DEVICE_ACCESS(i80321) { struct i80321_data *d = extra; uint64_t idata = 0, odata = 0; char *n = NULL; + int i, bus, dev, func, reg; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); + /* PCI configuration space: */ + if (relative_addr >= 0x100 && relative_addr < 0x140) { + /* TODO */ + goto ret; + } + + /* MCU registers: */ if (relative_addr >= VERDE_MCU_BASE && relative_addr < VERDE_MCU_BASE + VERDE_MCU_SIZE) { int regnr = (relative_addr - VERDE_MCU_BASE) / sizeof(uint32_t); @@ -73,8 +97,91 @@ odata = d->mcu_reg[regnr]; } + switch (relative_addr) { + /* Address Translation Unit: */ + case VERDE_ATU_BASE + ATU_IALR0: + case VERDE_ATU_BASE + ATU_IATVR0: + case VERDE_ATU_BASE + ATU_IALR1: + case VERDE_ATU_BASE + ATU_IALR2: + case VERDE_ATU_BASE + ATU_IATVR2: + case VERDE_ATU_BASE + ATU_OIOWTVR: + case VERDE_ATU_BASE + ATU_OMWTVR0: + case VERDE_ATU_BASE + ATU_OUMWTVR0: + case VERDE_ATU_BASE + ATU_OMWTVR1: + case VERDE_ATU_BASE + ATU_OUMWTVR1: + /* Ignoring these for now. TODO */ + break; + case VERDE_ATU_BASE + ATU_ATUCR: + /* ATU configuration register; ignored for now. TODO */ + break; + case VERDE_ATU_BASE + ATU_PCSR: + /* TODO: Temporary hack to allow NetBSD/evbarm to + reboot itself. Should be rewritten as soon as possible! */ + if (writeflag == MEM_WRITE && idata == 0x30) { + int j; + for (j=0; jmachine->ncpus; j++) + cpu->machine->cpus[j]->running = 0; + cpu->machine->exit_without_entering_debugger = 1; + } + break; + case VERDE_ATU_BASE + ATU_ATUIMR: + case VERDE_ATU_BASE + ATU_IABAR3: + case VERDE_ATU_BASE + ATU_IAUBAR3: + case VERDE_ATU_BASE + ATU_IALR3: + case VERDE_ATU_BASE + ATU_IATVR3: + /* Ignoring these for now. TODO */ + break; + case VERDE_ATU_BASE + ATU_OCCAR: + /* PCI address */ + if (writeflag == MEM_WRITE) { + d->pci_addr = idata; + bus_pci_decompose_1(idata, &bus, &dev, &func, ®); + bus = 0; /* NOTE */ + bus_pci_setaddr(cpu, d->pci_bus, bus, dev, func, reg); + } else { + odata = d->pci_addr; + } + break; + case VERDE_ATU_BASE + ATU_OCCDR: + case VERDE_ATU_BASE + ATU_OCCDR + 1: + case VERDE_ATU_BASE + ATU_OCCDR + 2: + case VERDE_ATU_BASE + ATU_OCCDR + 3: + /* PCI data */ + if (writeflag == MEM_READ) { + uint64_t tmp; + bus_pci_data_access(cpu, d->pci_bus, &tmp, + sizeof(uint32_t), MEM_READ); + switch (relative_addr) { + case VERDE_ATU_BASE + ATU_OCCDR + 1: + odata = tmp >> 8; break; + case VERDE_ATU_BASE + ATU_OCCDR + 2: + odata = tmp >> 16; break; + case VERDE_ATU_BASE + ATU_OCCDR + 3: + odata = tmp >> 24; break; + default:odata = tmp; + } + } else { + uint64_t tmp; + int r = relative_addr - (VERDE_ATU_BASE + ATU_OCCDR); + bus_pci_data_access(cpu, d->pci_bus, &tmp, + sizeof(uint32_t), MEM_READ); + for (i=0; i> (i*8); + tmp &= ~(0xff << ((r+i)*8)); + tmp |= b << ((r+i)*8); + } + tmp &= 0xffffffff; /* needed because << is 32-bit */ + bus_pci_data_access(cpu, d->pci_bus, &tmp, + sizeof(uint32_t), MEM_WRITE); + } + break; + case VERDE_ATU_BASE + ATU_PCIXSR: + odata = 0; /* TODO */ + break; + + /* Memory Controller Unit: */ case VERDE_MCU_BASE + MCU_SDBR: n = "MCU_SDBR"; break; @@ -103,6 +210,7 @@ } } +ret: if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); @@ -110,10 +218,7 @@ } -/* - * devinit_i80321(): - */ -int devinit_i80321(struct devinit *devinit) +DEVINIT(i80321) { struct i80321_data *d = malloc(sizeof(struct i80321_data)); uint32_t memsize = devinit->machine->physical_ram_in_mb * 1048576; @@ -126,13 +231,29 @@ memset(d, 0, sizeof(struct i80321_data)); d->mcu_reg[MCU_SDBR / sizeof(uint32_t)] = base = 0xa0000000; - d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base+memsize) >> 25; - d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base+memsize) >> 25; + d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base + memsize) >> 25; + d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base + memsize) >> 25; + + d->pci_bus = bus_pci_init(devinit->machine, + 0 /* TODO: pciirq */, + 0x90000000 /* TODO: pci_io_offset */, + 0x90010000 /* TODO: pci_mem_offset */, + 0xffff0000 /* TODO: pci_portbase */, + 0x00000000 /* TODO: pci_membase */, + 29 /* TODO: pci_irqbase */, + 0x90000000 /* TODO: isa_portbase */, + 0x90010000 /* TODO: isa_membase */, + 0 /* TODO: isa_irqbase */); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_I80321_LENGTH, dev_i80321_access, d, DM_DEFAULT, NULL); + machine_add_tickfunction(devinit->machine, dev_i80321_tick, + d, TICK_SHIFT); + + devinit->return_ptr = d; + return 1; }