/* * PXA270-based Intel Mainstone platforms. * * Copyright (c) 2007 by Armin Kuster or * * * Code based on spitz platform by Andrzej Zaborowski * * This code is licensed under the GNU GPL v2. */ #include "hw.h" #include "pxa.h" #include "arm-misc.h" #include "net.h" #include "devices.h" #include "boards.h" #define MST_ETH_PHYS 0x10000300 #define MST_FPGA_PHYS 0x08000000 /* Mainstone FPGA for extern irqs */ #define FPGA_GPIO_PIN 0 #define MST_NUM_IRQS 16 #define MST_BASE MST_FPGA_PHYS #define MST_LEDDAT1 0x10 #define MST_LEDDAT2 0x14 #define MST_LEDCTRL 0x40 #define MST_GPSWR 0x60 #define MST_MSCWR1 0x80 #define MST_MSCWR2 0x84 #define MST_MSCWR3 0x88 #define MST_MSCRD 0x90 #define MST_INTMSKENA 0xc0 #define MST_INTSETCLR 0xd0 #define MST_PCMCIA0 0xe0 #define MST_PCMCIA1 0xe4 /* IRQ definitions */ #define ETHERNET_IRQ 3 typedef struct mst_irq_state { target_phys_addr_t target_base; qemu_irq *parent; qemu_irq *pins; uint32_t prev_level; uint32_t leddat1; uint32_t leddat2; uint32_t ledctrl; uint32_t gpswr; uint32_t mscwr1; uint32_t mscwr2; uint32_t mscwr3; uint32_t mscrd; uint32_t intmskena; uint32_t intsetclr; uint32_t pcmcia0; uint32_t pcmcia1; } mst_irq_state; static void mst_fpga_update_gpio(mst_irq_state *s) { uint32_t level, diff; int bit; level = s->prev_level ^ s->intsetclr; for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { bit = ffs(diff) - 1; qemu_set_irq(s->pins[bit], (level >> bit) & 1 ); } s->prev_level = level; } static void mst_fpga_set_irq(void *opaque, int irq, int level) { mst_irq_state *s = (mst_irq_state *)opaque; if (level) s->prev_level |= 1u << irq; else s->prev_level &= ~(1u << irq); if(s->intmskena & (1u << irq)) { s->intsetclr = 1u << irq; qemu_set_irq(s->parent[0], level); } } static uint32_t mst_fpga_readb(void *opaque, target_phys_addr_t addr) { mst_irq_state *s = (mst_irq_state *) opaque; addr -= s->target_base; switch (addr) { case MST_LEDDAT1: return s->leddat1; case MST_LEDDAT2: return s->leddat2; case MST_LEDCTRL: return s->ledctrl; case MST_GPSWR: return s->gpswr; case MST_MSCWR1: return s->mscwr1; case MST_MSCWR2: return s->mscwr2; case MST_MSCWR3: return s->mscwr3; case MST_MSCRD: return s->mscrd; case MST_INTMSKENA: return s->intmskena; case MST_INTSETCLR: return s->intsetclr; case MST_PCMCIA0: return s->pcmcia0; case MST_PCMCIA1: return s->pcmcia1; default: printf("Mainstone - mst_fpga_readb: Bad register offset " REG_FMT " \n", addr); } return 0; } static void mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { mst_irq_state *s = (mst_irq_state *) opaque; addr -= s->target_base; value &= 0xffffffff; switch (addr) { case MST_LEDDAT1: s->leddat1 = value; break; case MST_LEDDAT2: s->leddat2 = value; break; case MST_LEDCTRL: s->ledctrl = value; break; case MST_GPSWR: s->gpswr = value; break; case MST_MSCWR1: s->mscwr1 = value; break; case MST_MSCWR2: s->mscwr2 = value; break; case MST_MSCWR3: s->mscwr3 = value; break; case MST_MSCRD: s->mscrd = value; break; case MST_INTMSKENA: /* Mask interupt */ s->intmskena = (value & 0xFEEFF); mst_fpga_update_gpio(s); break; case MST_INTSETCLR: /* clear or set interrupt */ s->intsetclr = (value & 0xFEEFF); break; case MST_PCMCIA0: s->pcmcia0 = value; break; case MST_PCMCIA1: s->pcmcia1 = value; break; default: printf("Mainstone - mst_fpga_writeb: Bad register offset " REG_FMT " \n", addr); } } CPUReadMemoryFunc *mst_fpga_readfn[] = { mst_fpga_readb, mst_fpga_readb, mst_fpga_readb, }; CPUWriteMemoryFunc *mst_fpga_writefn[] = { mst_fpga_writeb, mst_fpga_writeb, mst_fpga_writeb, }; static void mst_fpga_save(QEMUFile *f, void *opaque) { struct mst_irq_state *s = (mst_irq_state *) opaque; qemu_put_be32s(f, &s->prev_level); qemu_put_be32s(f, &s->leddat1); qemu_put_be32s(f, &s->leddat2); qemu_put_be32s(f, &s->ledctrl); qemu_put_be32s(f, &s->gpswr); qemu_put_be32s(f, &s->mscwr1); qemu_put_be32s(f, &s->mscwr2); qemu_put_be32s(f, &s->mscwr3); qemu_put_be32s(f, &s->mscrd); qemu_put_be32s(f, &s->intmskena); qemu_put_be32s(f, &s->intsetclr); qemu_put_be32s(f, &s->pcmcia0); qemu_put_be32s(f, &s->pcmcia1); } static int mst_fpga_load(QEMUFile *f, void *opaque, int version_id) { mst_irq_state *s = (mst_irq_state *) opaque; qemu_get_be32s(f, &s->prev_level); qemu_get_be32s(f, &s->leddat1); qemu_get_be32s(f, &s->leddat2); qemu_get_be32s(f, &s->ledctrl); qemu_get_be32s(f, &s->gpswr); qemu_get_be32s(f, &s->mscwr1); qemu_get_be32s(f, &s->mscwr2); qemu_get_be32s(f, &s->mscwr3); qemu_get_be32s(f, &s->mscrd); qemu_get_be32s(f, &s->intmskena); qemu_get_be32s(f, &s->intsetclr); qemu_get_be32s(f, &s->pcmcia0); qemu_get_be32s(f, &s->pcmcia1); return 0; } static qemu_irq *mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq) { mst_irq_state *s; int iomemtype; qemu_irq *qi; s = (mst_irq_state *) qemu_mallocz(sizeof(mst_irq_state)); if (!s) return NULL; s->target_base = base; s->parent = &cpu->pic[irq]; /* alloc the external 16 irqs */ qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); s->pins = qi; iomemtype = cpu_register_io_memory(0, mst_fpga_readfn, mst_fpga_writefn, s); cpu_register_physical_memory(MST_BASE, 0x00100000, iomemtype); register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); return qi; } enum mainstone_model_e { mainstone }; static void mainstone_common_init(int ram_size, int vga_ram_size, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, enum mainstone_model_e model, int arm_id) { uint32_t mainstone_ram = 0x04000000; uint32_t mainstone_rom = 0x00800000; struct pxa2xx_state_s *cpu; qemu_irq *mst_irq; if (!cpu_model) cpu_model = "pxa270-c5"; /* Setup CPU & memory */ if (ram_size < mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE) { fprintf(stderr, "This platform requires %i bytes of memory\n", mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE); exit(1); } cpu = pxa270_init(mainstone_ram, ds, cpu_model); cpu_register_physical_memory(0, mainstone_rom, qemu_ram_alloc(mainstone_rom) | IO_MEM_ROM); /* Setup initial (reset) machine state */ cpu->env->regs[15] = PXA2XX_SDRAM_BASE; mst_irq = mst_irq_init(cpu, MST_BASE, PXA2XX_PIC_GPIO_0); smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, initrd_filename, arm_id, PXA2XX_SDRAM_BASE); } static void mainstone_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { mainstone_common_init(ram_size, vga_ram_size, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196); } QEMUMachine mainstone2_machine = { "mainstone", "Mainstone II (PXA27x)", mainstone_init, };