| /* |
| * PXA270-based Intel Mainstone platforms. |
| * FPGA driver |
| * |
| * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or |
| * <akuster@mvista.com> |
| * |
| * This code is licensed under the GNU GPL v2. |
| */ |
| #include "hw.h" |
| #include "pxa.h" |
| #include "mainstone.h" |
| |
| /* Mainstone FPGA for extern irqs */ |
| #define FPGA_GPIO_PIN 0 |
| #define MST_NUM_IRQS 16 |
| #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 |
| |
| typedef struct mst_irq_state{ |
| 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, a_target_phys_addr addr) |
| { |
| mst_irq_state *s = (mst_irq_state *) opaque; |
| |
| 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, a_target_phys_addr addr, uint32_t value) |
| { |
| mst_irq_state *s = (mst_irq_state *) opaque; |
| 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); |
| } |
| } |
| |
| static CPUReadMemoryFunc * const mst_fpga_readfn[] = { |
| mst_fpga_readb, |
| mst_fpga_readb, |
| mst_fpga_readb, |
| }; |
| static CPUWriteMemoryFunc * const 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; |
| } |
| |
| qemu_irq *mst_irq_init(PXA2xxState *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)); |
| |
| 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(mst_fpga_readfn, |
| mst_fpga_writefn, s); |
| cpu_register_physical_memory(base, 0x00100000, iomemtype); |
| register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); |
| return qi; |
| } |