AACI emulation This patch implements the emulation of the Advanced Audio Codec Interface, found on ARM Versatile platforms. As of now, the implementation is very basic, and doesn't do anything useful. Signed-off-by: Thomas Petazzoni --- Makefile.target | 1 hw/aaci.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/primecell.h | 3 + hw/versatilepb.c | 2 4 files changed, 146 insertions(+) Index: qemu/Makefile.target =================================================================== --- qemu.orig/Makefile.target +++ qemu/Makefile.target @@ -619,6 +619,7 @@ OBJS+= tsc2005.o bt-hci-csr.o OBJS+= mst_fpga.o mainstone.o OBJS+= musicpal.o pflash_cfi02.o +OBJS+= aaci.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) Index: qemu/hw/aaci.c =================================================================== --- /dev/null +++ qemu/hw/aaci.c @@ -0,0 +1,140 @@ +/* + * ARM PrimeCell AACI emulation. + * + * Copyright (c) 2008 Thomas Petazzoni + * + * This code is licensed under the GPL + */ + +#include "hw.h" +#include "primecell.h" + +#define AACI_DEBUG +#ifdef AACI_DEBUG +#define DPRINTF(fmt, args...) \ +do { \ + printf("AACI: " fmt , ##args); \ +} while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif + +/* + * Control and status register offsets + * P39. + */ +#define AACI_CSCH1 0x000 +#define AACI_CSCH2 0x014 +#define AACI_CSCH3 0x028 +#define AACI_CSCH4 0x03c + +#define AACI_RXCR 0x000 /* 29 bits Control Rx FIFO */ +#define AACI_TXCR 0x004 /* 17 bits Control Tx FIFO */ +#define AACI_SR 0x008 /* 12 bits Status */ +#define AACI_ISR 0x00c /* 7 bits Int Status */ +#define AACI_IE 0x010 /* 7 bits Int Enable */ + +/* + * Other registers + */ +#define AACI_SL1RX 0x050 +#define AACI_SL1TX 0x054 +#define AACI_SL2RX 0x058 +#define AACI_SL2TX 0x05c +#define AACI_SL12RX 0x060 +#define AACI_SL12TX 0x064 +#define AACI_SLFR 0x068 /* slot flags */ +#define AACI_SLISTAT 0x06c /* slot interrupt status */ +#define AACI_SLIEN 0x070 /* slot interrupt enable */ +#define AACI_INTCLR 0x074 /* interrupt clear */ +#define AACI_MAINCR 0x078 /* main control */ +#define AACI_RESET 0x07c /* reset control */ +#define AACI_SYNC 0x080 /* sync control */ +#define AACI_ALLINTS 0x084 /* all fifo interrupt status */ +#define AACI_MAINFR 0x088 /* main flag register */ +#define AACI_DR1 0x090 /* data read/written fifo 1 */ +#define AACI_DR2 0x0b0 /* data read/written fifo 2 */ +#define AACI_DR3 0x0d0 /* data read/written fifo 3 */ +#define AACI_DR4 0x0f0 /* data read/written fifo 4 */ + +/* + * slot flag register bits. P56 + */ +#define SLFR_RWIS (1 << 13) /* raw wake-up interrupt status */ +#define SLFR_RGPIOINTR (1 << 12) /* raw gpio interrupt */ +#define SLFR_12TXE (1 << 11) /* slot 12 tx empty */ +#define SLFR_12RXV (1 << 10) /* slot 12 rx valid */ +#define SLFR_2TXE (1 << 9) /* slot 2 tx empty */ +#define SLFR_2RXV (1 << 8) /* slot 2 rx valid */ +#define SLFR_1TXE (1 << 7) /* slot 1 tx empty */ +#define SLFR_1RXV (1 << 6) /* slot 1 rx valid */ +#define SLFR_12TXB (1 << 5) /* slot 12 tx busy */ +#define SLFR_12RXB (1 << 4) /* slot 12 rx busy */ +#define SLFR_2TXB (1 << 3) /* slot 2 tx busy */ +#define SLFR_2RXB (1 << 2) /* slot 2 rx busy */ +#define SLFR_1TXB (1 << 1) /* slot 1 tx busy */ +#define SLFR_1RXB (1 << 0) /* slot 1 rx busy */ + +typedef struct { + uint32_t base; +} aaci_state; + +static const unsigned char aaci_id[8] = + { 0x41, 0x10, 0x4, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static uint32_t aaci_read(void *opaque, target_phys_addr_t offset) +{ + aaci_state *s = (aaci_state *) opaque; + + offset -= s->base; + + DPRINTF("reading from 0x%x\n", offset); + + if (offset >= 0xfe0 && offset < 0x1000) + { + DPRINTF("returning 0x%x\n", aaci_id[(offset - 0xfe0) >> 2]); + return aaci_id[(offset - 0xfe0) >> 2]; + } + + switch(offset) + { + case AACI_SLFR: + return SLFR_12TXE | SLFR_2TXE | SLFR_1TXE; + + default: + DPRINTF("unimplemented\n"); + } + + return 0; +} + +static void aaci_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + DPRINTF("writing 0x%x to 0x%x\n", value, offset); +} + +static CPUReadMemoryFunc *aaci_readfn[] = { + aaci_read, + aaci_read, + aaci_read +}; + +static CPUWriteMemoryFunc *aaci_writefn[] = { + aaci_write, + aaci_write, + aaci_write +}; + +void aaci_init(uint32_t base) +{ + int iomemtype; + aaci_state *s; + + s = (aaci_state *) qemu_mallocz(sizeof(aaci_state)); + s->base = base; + + iomemtype = cpu_register_io_memory(0, aaci_readfn, + aaci_writefn, s); + cpu_register_physical_memory(base, 0x1000, iomemtype); +} Index: qemu/hw/primecell.h =================================================================== --- qemu.orig/hw/primecell.h +++ qemu/hw/primecell.h @@ -42,6 +42,9 @@ /* pl190.c */ qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq); +/* aaci.c */ +void aaci_init(uint32_t base); + /* realview_gic.c */ qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq); Index: qemu/hw/versatilepb.c =================================================================== --- qemu.orig/hw/versatilepb.c +++ qemu/hw/versatilepb.c @@ -240,6 +240,8 @@ sp804_init(0x101e2000, pic[4]); sp804_init(0x101e3000, pic[5]); + aaci_init(0x10004000); + /* The versatile/PB actually has a modified Color LCD controller that includes hardware cursor support from the PL111. */ pl110_init(ds, 0x10120000, pic[16], 1);