Message ID | 20091115204930.GA25677@rain |
---|---|
State | New |
Headers | show |
I'd say it is preferable to split the individual devices and model them using the QDEV infrastructure instead of putting it all together into one "system controller" device. I've QDEV-based implementation of these devices already: PMC, DBGU, PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and USART (which is very similar to DBGU) to be split up. Best regards, Filip Navara On Sun, Nov 15, 2009 at 9:49 PM, Evgeniy Dushistov <dushistov@mail.ru> wrote: > add emulation of at91sam9263 cpu, plus sdram, plus nor flash connected to this cpu > > > Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> > --- > Makefile.target | 2 +- > hw/at91sam9.c | 695 +++++++++++++++++++++++++++++++++++++++++++++++++ > hw/at91sam9263_defs.h | 144 ++++++++++ > 3 files changed, 840 insertions(+), 1 deletions(-) > create mode 100644 hw/at91sam9.c > create mode 100644 hw/at91sam9263_defs.h > > diff --git a/Makefile.target b/Makefile.target > index 7542199..67f441d 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -268,7 +268,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o > endif > > obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o > -obj-arm-y += pflash_atmel.o > +obj-arm-y += pflash_atmel.o at91sam9.o > obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o > obj-arm-y += versatile_pci.o > obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o > diff --git a/hw/at91sam9.c b/hw/at91sam9.c > new file mode 100644 > index 0000000..7ac60d9 > --- /dev/null > +++ b/hw/at91sam9.c > @@ -0,0 +1,695 @@ > +/* > + * Atmel at91sam9263 cpu + NOR flash + SDRAM emulation > + * Written by Evgeniy Dushistov > + * This code is licenced under the GPL. > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > + > +#include "hw.h" > +#include "arm-misc.h" > +#include "primecell.h" > +#include "devices.h" > +#include "net.h" > +#include "sysemu.h" > +#include "flash.h" > +#include "boards.h" > +#include "qemu-char.h" > +#include "qemu-timer.h" > + > +#include "at91sam9263_defs.h" > + > +//#define AT91_TRACE_ON > +//#define AT91_DEBUG_ON > + > +#define ARM_AIC_CPU_IRQ 0 > +#define ARM_AIC_CPU_FIQ 1 > + > +#define NOR_FLASH_SIZE (1024 * 1024 * 8) > +#define AT91SAM9263EK_SDRAM_SIZE (1024 * 1024 * 64) > +#define AT91SAM9263EK_SDRAM_OFF 0x20000000 > +#define AT91SAM9263EK_NORFLASH_OFF 0x10000000 > + > +#ifdef AT91_DEBUG_ON > +# define DEBUG(f, a...) { \ > + printf ("at91 (%s, %d): %s:", \ > + __FILE__, __LINE__, __func__); \ > + printf (f, ## a); \ > + } > +#else > +# define DEBUG(f, a...) do { } while (0) > +#endif > + > +#ifdef AT91_TRACE_ON > +static FILE *trace_file; > +# define TRACE(f, a...) do { \ > + fprintf (trace_file, f, ## a); \ > + } while (0) > +#else > +# define TRACE(f, a...) do { } while (0) > +#endif > + > + > +struct dbgu_state { > + CharDriverState *chr; > +}; > + > +struct at91sam9_state { > + uint32_t pmc_regs[28]; > + uint32_t dbgu_regs[0x124 / 4]; > + uint32_t bus_matrix_regs[0x100 / 4]; > + uint32_t ccfg_regs[(0x01FC - 0x0110 + 1) / sizeof(uint32_t)]; > + uint32_t pio_regs[(AT91_PMC_BASE - AT91_PIO_BASE) / sizeof(uint32_t)]; > + uint32_t sdramc0_regs[(AT91_SMC0_BASE - AT91_SDRAMC0_BASE) / sizeof(uint32_t)]; > + uint32_t smc0_regs[(AT91_ECC1_BASE - AT91_SMC0_BASE) / sizeof(uint32_t)]; > + uint32_t pitc_regs[80]; > + uint32_t aic_regs[(AT91_PIO_BASE - AT91_AIC_BASE) / sizeof(uint32_t)]; > + uint32_t usart0_regs[0x1000 / sizeof(uint32_t)]; > + struct dbgu_state dbgu; > + pflash_t *norflash; > + ram_addr_t internal_sram; > + QEMUTimer *dbgu_tr_timer; > + ptimer_state *pitc_timer; > + int timer_active; > + CPUState *env; > + qemu_irq *qirq; > + uint64_t char_transmit_time; > +}; > + > +static uint32_t at91_pmc_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + TRACE("pmc read offset %X\n", offset); > + return sam9->pmc_regs[offset / 4]; > +} > + > +static void at91_pmc_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("pmc write offset %X, value %X\n", offset, value); > + switch (offset / 4) { > + case AT91_PMC_MCKR: > + sam9->pmc_regs[AT91_PMC_MCKR] = value; > + switch (value & AT91_PMC_CSS) { > + case 1: > + //Main clock is selected > + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MCKRDY | AT91_PMC_MOSCS; > + break; > + default: > + DEBUG("unimplemented\n"); > + break; > + } > + break; > + case AT91_PMC_MOR: > + sam9->pmc_regs[AT91_PMC_MOR] = value; > + if (value & 1) { > + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MOSCS; > + } > + break; > + case AT91_PMC_PLLAR: > + sam9->pmc_regs[AT91_PMC_PLLAR] = value; > + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKA; > + break; > + case AT91_PMC_PLLBR: > + sam9->pmc_regs[AT91_PMC_PLLBR] = value; > + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKB; > + break; > + case AT91_PMC_PCER: > + sam9->pmc_regs[AT91_PMC_PCER] |= value; > + break; > + default: > + //DEBUG("unimplemented, offset %X\n", offset); > + break; > + } > +} > + > +static uint32_t at91_dbgu_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + offset /= 4; > + if (offset == AT91_DBGU_RHR) { > + sam9->dbgu_regs[AT91_DBGU_SR] &= (uint32_t)~1; > + }/* else if (offset == AT91_DBGU_SR)*/ > + > + return sam9->dbgu_regs[offset]; > +} > + > +static void at91_dbgu_state_changed(struct at91sam9_state *sam9) > +{ > + if ((sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) && > + (sam9->dbgu_regs[AT91_DBGU_IMR] & sam9->dbgu_regs[AT91_DBGU_SR])) { > + sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID; > + sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID]; > + qemu_irq_raise(sam9->qirq[0]); > + } > +} > + > +static void dbgu_serial_end_xmit(void *opaque) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + sam9->dbgu_regs[AT91_DBGU_SR] |= (AT91_US_TXEMPTY | AT91_US_TXRDY); > + at91_dbgu_state_changed(sam9); > +} > + > +static void at91_dbgu_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + unsigned char ch; > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + switch (offset / 4) { > + case AT91_DBGU_CR: > + sam9->dbgu_regs[AT91_DBGU_CR] = value; > + if (value & AT91_US_TXEN) > + sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_TXRDY | AT91_US_TXEMPTY; > + if (value & AT91_US_TXDIS) > + sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXRDY | AT91_US_TXEMPTY); > + break; > + case AT91_DBGU_IER: > + sam9->dbgu_regs[AT91_DBGU_IMR] |= value; > + at91_dbgu_state_changed(sam9); > + break; > + case AT91_DBGU_IDR: > + sam9->dbgu_regs[AT91_DBGU_IMR] &= ~value; > + break; > + case AT91_DBGU_THR: > + sam9->dbgu_regs[AT91_DBGU_THR] = value; > + sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXEMPTY | AT91_US_TXRDY); > + ch = value; > + if (sam9->dbgu.chr) > + qemu_chr_write(sam9->dbgu.chr, &ch, 1); > + qemu_mod_timer(sam9->dbgu_tr_timer , qemu_get_clock(vm_clock) + sam9->char_transmit_time); > + break; > + default: > + //DEBUG("unimplemented\n"); > + break; > + } > +} > + > +static int at91_dbgu_can_receive(void *opaque) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + return (sam9->dbgu_regs[AT91_DBGU_SR] & AT91_US_RXRDY) == 0; > +} > + > +static void at91_dbgu_receive(void *opaque, const uint8_t *buf, int size) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + int i; > + /*! \todo if not one character we need wait before irq handled, > + but from other hand at91_dbgu_can_receive should prevent this > + */ > + for (i = 0; i < size; ++i) { > + sam9->dbgu_regs[AT91_DBGU_RHR] = buf[i]; > + sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_RXRDY; > + at91_dbgu_state_changed(sam9); > + } > +} > + > +static void at91_dbgu_event(void *opaque, int event) > +{ > + DEBUG("begin\n"); > +} > + > +static uint32_t at91_bus_matrix_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("bus_matrix read offset %X\n", offset); > + return sam9->bus_matrix_regs[offset / 4]; > +} > + > +static void at91_bus_matrix_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("bus_matrix write offset %X, value %X\n", offset, value); > + switch (offset) { > + case MATRIX_MRCR: > + DEBUG("write to MATRIX mrcr reg\n"); > + if (value & (AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D)) { > + cpu_register_physical_memory(0x0, 80 * 1024, sam9->internal_sram | IO_MEM_RAM); > + } > + break; > + default: > + DEBUG("unimplemented\n"); > + break; > + } > +} > + > +static void at91_init_pmc(struct at91sam9_state *sam9) > +{ > + DEBUG("begin\n"); > + sam9->pmc_regs[AT91_PMC_MCKR] = 0; > + sam9->pmc_regs[AT91_PMC_MOR] = 0; > + sam9->pmc_regs[AT91_PMC_SR] = 0x08; > + sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00; > + sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00; > +} > + > +static void at91_init_bus_matrix(struct at91sam9_state *sam9) > +{ > + DEBUG("begin\n"); > + memset(&sam9->bus_matrix_regs, 0, sizeof(sam9->bus_matrix_regs)); > +} > + > +static void at91_init_dbgu(struct at91sam9_state *sam9, CharDriverState *chr) > +{ > + DEBUG("begin\n"); > + > + memset(&sam9->dbgu_regs, 0, sizeof(sam9->dbgu_regs)); > + sam9->dbgu_regs[AT91_DBGU_SR] = AT91_US_TXEMPTY | AT91_US_TXRDY; > + > + sam9->dbgu.chr = chr; > + sam9->dbgu_tr_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *)dbgu_serial_end_xmit, sam9); > + sam9->char_transmit_time = (get_ticks_per_sec() / 115200) * 10; > + if (chr) > + qemu_chr_add_handlers(chr, at91_dbgu_can_receive, > + at91_dbgu_receive, > + at91_dbgu_event, sam9); > +} > + > +static uint32_t at91_ccfg_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("ccfg read offset %X\n", offset); > + return sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])]; > +} > + > +static void at91_ccfg_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("ccfg write offset %X, value %X\n", offset, value); > + sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])] = value; > +} > + > +static uint32_t at91_pio_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("pio read offset %X\n", offset); > + return sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])]; > +} > + > +static void at91_pio_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("pio write offset %X, value %X\n", offset, value); > + sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])] = value; > +} > + > +static uint32_t at91_sdramc0_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("sdramc0 read offset %X\n", offset); > + return sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])]; > +} > + > +static void at91_sdramc0_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("sdramc0 write offset %X, value %X\n", offset, value); > + sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])] = value; > +} > + > +static uint32_t at91_smc0_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("smc0 read offset %X\n", offset); > + return sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])]; > +} > + > +static void at91_smc0_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("smc0 write offset %X, value %X\n", offset, value); > + sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])] = value; > +} > + > +static void at91_pitc_timer_tick(void * opaque) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + uint64_t val = ptimer_get_count(sam9->pitc_timer); > + > + unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20) + 1; > + sam9->pitc_regs[AT91_PITC_PIIR] = (val & ((1 << 21) - 1)) | (tick << 20); > + sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR]; > + > + if ((sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITIEN) && > + (sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) && > + !sam9->pitc_regs[AT91_PITC_SR]) { > + sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID; > + sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID]; > + > + sam9->pitc_regs[AT91_PITC_SR] = 1; > + qemu_irq_raise(sam9->qirq[0]); > + } > +} > + > +static uint32_t at91_pitc_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + int pitc_enable = !!(sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITEN); > + int idx; > + > + idx = offset / sizeof(sam9->pitc_regs[0]); > + switch (idx) { > + case AT91_PITC_SR: > +// DEBUG("read sr: %X\n", sam9->pitc_regs[idx]); > + break; > + case AT91_PITC_PIVR: > + if (pitc_enable) { > +// DEBUG("clear sr\n"); > + sam9->pitc_regs[AT91_PITC_SR] = 0; > + } else { > +// DEBUG("pitc disabled\n"); > + break; > + } > + case AT91_PITC_PIIR: > + if (pitc_enable) { > + uint64_t val = ptimer_get_count(sam9->pitc_timer); > + unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20); > + uint32_t res = (tick << 20) | (val & ((1 << 21) - 1)); > + > + if (idx == AT91_PITC_PIVR) > + tick = 0; > + sam9->pitc_regs[AT91_PITC_PIIR] = (tick << 20) | (val & ((1 << 21) - 1)); > + sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR]; > + TRACE("pitc read offset %X, value %X\n", offset, res); > + return res; > + } else { > +// DEBUG("pitc disabled\n"); > + break; > + } > + > + default: > + /*nothing*/break; > + } > + TRACE("pitc read offset %X, value %X\n", offset, sam9->pitc_regs[idx]); > + > + return sam9->pitc_regs[idx]; > +} > + > +static void at91_pitc_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + > + TRACE("pitc write offset %X, value %X\n", offset, value); > + int idx = offset / sizeof(sam9->pitc_regs[0]); > + switch (idx) { > + case AT91_PITC_MR: { > + int pitc_enable = !!(value & AT91_PTIC_MR_PITEN); > + unsigned int period = value & 0xFFFFF; > + > + //DEBUG("set period %u, int enabled? %d\n", period, !!(value & AT91_PTIC_MR_PITIEN)); > + > + if (pitc_enable && period != 0) { > + sam9->timer_active = 1; > + //! \todo get real value from PLL > + ptimer_set_freq(sam9->pitc_timer, (100 * 1000 * 1000) / 16); > + ptimer_set_limit(sam9->pitc_timer, period, 1); > + ptimer_run(sam9->pitc_timer, 0); > + } else if (sam9->timer_active) { > + TRACE("disable timer\n"); > + sam9->pitc_regs[AT91_PITC_PIVR] = 0; > + ptimer_stop(sam9->pitc_timer); > + } > + } > + break; > + default: > + TRACE("unhandled register %d\n", idx); > + break; > + } > + sam9->pitc_regs[idx] = value; > +} > + > +static void at91_init_pitc(struct at91sam9_state *sam9) > +{ > + QEMUBH *bh; > + > + DEBUG("begin\n"); > + memset(&sam9->pitc_regs, 0, sizeof(sam9->pitc_regs)); > + sam9->pitc_regs[AT91_PITC_MR] = 0xFFFFF; > + bh = qemu_bh_new(at91_pitc_timer_tick, sam9); > + sam9->pitc_timer = ptimer_init(bh); > +} > + > +static uint32_t at91_aic_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + unsigned int idx = offset / sizeof(sam9->aic_regs[0]); > + if (idx == AT91_AIC_IVR) { > + qemu_irq_lower(sam9->qirq[0]); > + } else if (idx == AT91_AIC_ISR) { > + uint32_t val = sam9->aic_regs[idx]; > + sam9->aic_regs[idx] = 0; > + return val; > + } > + > + return sam9->aic_regs[idx]; > +} > + > +static void at91_aic_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + unsigned int idx = offset / sizeof(sam9->aic_regs[0]); > + > + switch (idx) { > + case AT91_AIC_IECR: > + sam9->aic_regs[idx] |= value; > + break; > + case AT91_AIC_IDCR: > + sam9->aic_regs[idx] |= value; > + sam9->aic_regs[AT91_AIC_IECR] &= ~value; > + break; > + case AT91_AIC_IVR://ignore write > + break; > + case AT91_AIC_EOICR: > +// DEBUG("we write to end of interrupt reg\n"); > + break; > + default: > + sam9->aic_regs[idx] = value; > + break; > + } > +} > + > +static uint32_t at91_usart_read(void *opaque, target_phys_addr_t offset) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + DEBUG("we read from %X\n", offset); > + return sam9->usart0_regs[offset / sizeof(uint32_t)]; > +} > + > +static void at91_usart_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; > + DEBUG("we write to %X: %X\n", offset, value); > + sam9->usart0_regs[offset / sizeof(uint32_t)] = value; > +} > + > + > +struct ip_block { > + target_phys_addr_t offset; > + target_phys_addr_t end_offset; > + uint32_t (*read_func)(void *, target_phys_addr_t); > + void (*write_func)(void *, target_phys_addr_t, uint32_t); > +}; > + > +static struct ip_block ip_blocks[] = { > + {AT91_USART0_BASE - AT91_PERIPH_BASE, AT91_USART0_BASE - AT91_PERIPH_BASE + 0x1000, at91_usart_read, at91_usart_write}, > + {AT91_SDRAMC0_BASE - AT91_PERIPH_BASE, AT91_SMC0_BASE - AT91_PERIPH_BASE, at91_sdramc0_read, at91_sdramc0_write}, > + {AT91_SMC0_BASE - AT91_PERIPH_BASE, AT91_ECC1_BASE - AT91_PERIPH_BASE, at91_smc0_read, at91_smc0_write}, > + {AT91_BUS_MATRIX_BASE - AT91_PERIPH_BASE, AT91_CCFG_BASE - AT91_PERIPH_BASE, at91_bus_matrix_read, at91_bus_matrix_write}, > + {AT91_CCFG_BASE - AT91_PERIPH_BASE, AT91_DBGU_BASE - AT91_PERIPH_BASE, at91_ccfg_read, at91_ccfg_write}, > + {AT91_DBGU_BASE - AT91_PERIPH_BASE, AT91_AIC_BASE - AT91_PERIPH_BASE, at91_dbgu_read, at91_dbgu_write}, > + {AT91_AIC_BASE - AT91_PERIPH_BASE, AT91_PIO_BASE - AT91_PERIPH_BASE, at91_aic_read, at91_aic_write}, > + {AT91_PIO_BASE - AT91_PERIPH_BASE, AT91_PMC_BASE - AT91_PERIPH_BASE, at91_pio_read, at91_pio_write}, > + {AT91_PMC_BASE - AT91_PERIPH_BASE, AT91_RSTC_BASE - AT91_PERIPH_BASE, at91_pmc_read, at91_pmc_write}, > + {AT91_PITC_BASE - AT91_PERIPH_BASE, AT91_WDT_BASE - AT91_PERIPH_BASE, at91_pitc_read, at91_pitc_write}, > +}; > + > +static uint32_t at91_periph_read(void *opaque, target_phys_addr_t offset) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i) > + if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) > + return ip_blocks[i].read_func(opaque, offset - ip_blocks[i].offset); > + DEBUG("read from unsupported periph addr %X\n", offset); > + return 0xFFFFFFFFUL; > +} > + > +static void at91_periph_write(void *opaque, target_phys_addr_t offset, > + uint32_t value) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i) > + if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) { > + ip_blocks[i].write_func(opaque, offset - ip_blocks[i].offset, value); > + return; > + } > + DEBUG("write to unsupported periph: addr %X, val %X\n", offset, value); > +} > + > +/* Input 0 is IRQ and input 1 is FIQ. */ > +static void arm_aic_cpu_handler(void *opaque, int irq, int level) > +{ > + CPUState *env = (CPUState *)opaque; > + switch (irq) { > + case ARM_AIC_CPU_IRQ: > + if (level) > + cpu_interrupt(env, CPU_INTERRUPT_HARD); > + else > + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); > + break; > + case ARM_AIC_CPU_FIQ: > + if (level) > + cpu_interrupt(env, CPU_INTERRUPT_FIQ); > + else > + cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); > + break; > + default: > + hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq); > + } > +} > + > +static void at91_aic_init(struct at91sam9_state *sam9) > +{ > + memset(&sam9->aic_regs[0], 0, sizeof(sam9->aic_regs)); > + sam9->qirq = qemu_allocate_irqs(arm_aic_cpu_handler, sam9->env, 2); > +} > + > +static CPUReadMemoryFunc *at91_periph_readfn[] = { > + at91_periph_read, > + at91_periph_read, > + at91_periph_read > +}; > + > +static CPUWriteMemoryFunc *at91_periph_writefn[] = { > + at91_periph_write, > + at91_periph_write, > + at91_periph_write > +}; > + > + > +static void at91sam9_init(ram_addr_t ram_size, > + const char *boot_device, > + const char *kernel_filename, > + const char *kernel_cmdline, > + const char *initrd_filename, > + const char *cpu_model) > +{ > + CPUState *env; > + DriveInfo *dinfo; > + struct at91sam9_state *sam9; > + int iomemtype; > + > + DEBUG("begin, ram_size %llu\n", (unsigned long long)ram_size); > +#ifdef TRACE_ON > + trace_file = fopen("/tmp/trace.log", "w"); > +#endif > + if (!cpu_model) > + cpu_model = "arm926"; > + env = cpu_init(cpu_model); > + if (!env) { > + fprintf(stderr, "Unable to find CPU definition\n"); > + exit(EXIT_FAILURE); > + } > + /* SDRAM at chipselect 1. */ > + cpu_register_physical_memory(AT91SAM9263EK_SDRAM_OFF, AT91SAM9263EK_SDRAM_SIZE, > + qemu_ram_alloc(AT91SAM9263EK_SDRAM_SIZE) | IO_MEM_RAM); > + > + sam9 = (struct at91sam9_state *)qemu_mallocz(sizeof(*sam9)); > + if (!sam9) { > + fprintf(stderr, "allocation failed\n"); > + exit(EXIT_FAILURE); > + } > + sam9->env = env; > + /* Internal SRAM */ > + sam9->internal_sram = qemu_ram_alloc(80 * 1024); > + cpu_register_physical_memory(0x00300000, 80 * 1024, sam9->internal_sram | IO_MEM_RAM); > + > + /*Internal Peripherals */ > + iomemtype = cpu_register_io_memory(at91_periph_readfn, at91_periph_writefn, sam9); > + cpu_register_physical_memory(0xF0000000, 0xFFFFFFFF - 0xF0000000, iomemtype); > + > + at91_init_pmc(sam9); > + at91_init_bus_matrix(sam9); > + memset(&sam9->ccfg_regs, 0, sizeof(sam9->ccfg_regs)); > + memset(&sam9->pio_regs, 0, sizeof(sam9->pio_regs)); > + memset(&sam9->sdramc0_regs, 0, sizeof(sam9->sdramc0_regs)); > + memset(&sam9->smc0_regs, 0, sizeof(sam9->smc0_regs)); > + at91_init_dbgu(sam9, serial_hds[0]); > + at91_init_pitc(sam9); > + at91_aic_init(sam9); > + memset(sam9->usart0_regs, 0, sizeof(sam9->usart0_regs)); > + > + /* > + we use variant of booting from external memory (NOR FLASH), > + it mapped to 0x0 at start, and also it is accessable from 0x10000000 address > + */ > + dinfo = drive_get(IF_PFLASH, 0, 0); > + if (dinfo) { > + ram_addr_t nor_flash_mem = qemu_ram_alloc(NOR_FLASH_SIZE); > + if (!nor_flash_mem) { > + fprintf(stderr, "allocation failed\n"); > + exit(EXIT_FAILURE); > + } > + > + sam9->norflash = pflash_cfi_atmel_register(AT91SAM9263EK_NORFLASH_OFF, > + nor_flash_mem, > + dinfo->bdrv, > + 4 * 1024 * 2, 8, > + 32 * 1024 * 2, > + (135 - 8), > + 2, 0x001F, 0x01D6, 0, 0); > + > + if (!sam9->norflash) { > + fprintf(stderr, "qemu: error registering flash memory.\n"); > + exit(EXIT_FAILURE); > + } > + > + DEBUG("register flash at 0x0\n"); > + //register only part of flash, to prevent conflict with internal sram > + cpu_register_physical_memory(0x0, 100 * 1024 /*NOR_FLASH_SIZE*/, > + nor_flash_mem | IO_MEM_ROMD); > + } else { > + fprintf(stderr, "qemu: can not start without flash.\n"); > + exit(EXIT_FAILURE); > + } > + env->regs[15] = 0x0; > +} > + > +static QEMUMachine at91sam9263ek_machine = { > + .name = "at91sam9263ek", > + .desc = "Atmel at91sam9263ek board (ARM926EJ-S)", > + .init = at91sam9_init, > +}; > + > +static void at91sam9_machine_init(void) > +{ > + qemu_register_machine(&at91sam9263ek_machine); > +} > + > +machine_init(at91sam9_machine_init) > diff --git a/hw/at91sam9263_defs.h b/hw/at91sam9263_defs.h > new file mode 100644 > index 0000000..c7136c3 > --- /dev/null > +++ b/hw/at91sam9263_defs.h > @@ -0,0 +1,144 @@ > +#ifndef _HW_AT91SAM9263_DEFS_H_ > +#define _HW_AT91SAM9263_DEFS_H_ > + > +/* base periph addresses */ > +#define AT91_PERIPH_BASE 0xF0000000 > +#define AT91_USART0_BASE 0xFFF8C000 > +#define AT91_SDRAMC0_BASE 0xFFFFE200 > +#define AT91_SMC0_BASE 0xFFFFE400 > +#define AT91_ECC1_BASE 0xFFFFE600 > +#define AT91_BUS_MATRIX_BASE 0xFFFFEC00 > +#define AT91_CCFG_BASE 0xFFFFED10 > +#define AT91_DBGU_BASE 0xFFFFEE00 > +#define AT91_AIC_BASE 0xFFFFF000 > +#define AT91_PIO_BASE 0xFFFFF200 > +#define AT91_PMC_BASE 0xFFFFFC00 > +#define AT91_RSTC_BASE 0xFFFFFD00 > +#define AT91_PITC_BASE 0xFFFFFD30 > +#define AT91_WDT_BASE 0xFFFFFD40 > + > +/* PMC registers */ > +#define AT91_PMC_SR (0x68 / sizeof(uint32_t)) > +#define AT91_PMC_MCKR (0x0020 / sizeof(uint32_t)) > +#define AT91_PMC_MOR (0x30 / sizeof(uint32_t)) > +#define AT91_PMC_CSS (0x3 << 0) // (PMC) Programmable Clock Selection > +#define AT91_PMC_MCKRDY (0x1 << 3) // (PMC) Master Clock Status/Enable/Disable/Mask > +#define AT91_PMC_MOSCS (0x1 << 0) // (PMC) MOSC Status/Enable/Disable/Mask > +#define AT91_CKGR_MOSCEN (0x1 << 0) // (CKGR) Main Oscillator Enable > +#define AT91_PMC_PLLAR (0x0028 / sizeof(uint32_t)) > +#define AT91_PMC_PLLBR (0x002C / sizeof(uint32_t)) > +#define AT91_PMC_LOCKA (0x1 << 1) // (PMC) PLL A Status/Enable/Disable/Mask > +#define AT91_PMC_LOCKB (0x1 << 2) // (PMC) PLL B Status/Enable/Disable/Mask > +#define AT91_PMC_PCER (0x10 / sizeof(uint32_t)) > + > +/*dbgu registers */ > +#define AT91_DBGU_CR 0x0 > +#define AT91_DBGU_MR (4 / sizeof(uint32_t)) > +#define AT91_DBGU_IER (8 / sizeof(uint32_t)) > +#define AT91_DBGU_IDR (0xC / sizeof(uint32_t)) > +#define AT91_DBGU_IMR (0x10 / sizeof(uint32_t)) > +#define AT91_DBGU_SR (0x14 / sizeof(uint32_t)) > +#define AT91_DBGU_RHR (0x18 / sizeof(uint32_t)) > +#define AT91_DBGU_THR (0x001C / sizeof(uint32_t)) > +#define AT91_DBGU_BRGR (0x0020 / sizeof(uint32_t)) > + > + > +// -------- DBGU_CR : (DBGU Offset: 0x0) Debug Unit Control Register -------- > +#define AT91_US_RSTRX (0x1 << 2) // (DBGU) Reset Receiver > +#define AT91_US_RSTTX (0x1 << 3) // (DBGU) Reset Transmitter > +#define AT91_US_RXEN (0x1 << 4) // (DBGU) Receiver Enable > +#define AT91_US_RXDIS (0x1 << 5) // (DBGU) Receiver Disable > +#define AT91_US_TXEN (0x1 << 6) // (DBGU) Transmitter Enable > +#define AT91_US_TXDIS (0x1 << 7) // (DBGU) Transmitter Disable > +#define AT91_US_RSTSTA (0x1 << 8) // (DBGU) Reset Status Bits > +// -------- DBGU_IER : (DBGU Offset: 0x8) Debug Unit Interrupt Enable Register -------- > +#define AT91_US_RXRDY (0x1 << 0) // (DBGU) RXRDY Interrupt > +#define AT91_US_TXRDY (0x1 << 1) // (DBGU) TXRDY Interrupt > +#define AT91_US_ENDRX (0x1 << 3) // (DBGU) End of Receive Transfer Interrupt > +#define AT91_US_ENDTX (0x1 << 4) // (DBGU) End of Transmit Interrupt > +#define AT91_US_OVRE (0x1 << 5) // (DBGU) Overrun Interrupt > +#define AT91_US_FRAME (0x1 << 6) // (DBGU) Framing Error Interrupt > +#define AT91_US_PARE (0x1 << 7) // (DBGU) Parity Error Interrupt > +#define AT91_US_TXEMPTY (0x1 << 9) // (DBGU) TXEMPTY Interrupt > +#define AT91_US_TXBUFE (0x1 << 11) // (DBGU) TXBUFE Interrupt > +#define AT91_US_RXBUFF (0x1 << 12) // (DBGU) RXBUFF Interrupt > +#define AT91_US_COMM_TX (0x1 << 30) // (DBGU) COMM_TX Interrupt > +#define AT91_US_COMM_RX (0x1 << 31) // (DBGU) COMM_RX Interrupt > + > +/* US registers */ > +#define AT91_US_CR (0) > +#define AT91_US_MR (4 / sizeof(uint32_t)) > +#define AT91_US_IER (8 / sizeof(uint32_t)) > +#define AT91_US_IDR (0xC / sizeof(uint32_t)) > +#define AT91_US_IMR (0x10 / sizeof(uint32_t)) > + > +/* matrix */ > + > +// ***************************************************************************** > +// SOFTWARE API DEFINITION FOR AHB Matrix Interface > +// ***************************************************************************** > +// *** Register offset in AT91S_MATRIX structure *** > +#define MATRIX_MCFG0 ( 0) // Master Configuration Register 0 > +#define MATRIX_MCFG1 ( 4) // Master Configuration Register 1 > +#define MATRIX_MCFG2 ( 8) // Master Configuration Register 2 > +#define MATRIX_MCFG3 (12) // Master Configuration Register 3 > +#define MATRIX_MCFG4 (16) // Master Configuration Register 4 > +#define MATRIX_MCFG5 (20) // Master Configuration Register 5 > +#define MATRIX_MCFG6 (24) // Master Configuration Register 6 > +#define MATRIX_MCFG7 (28) // Master Configuration Register 7 > +#define MATRIX_MCFG8 (32) // Master Configuration Register 8 > +#define MATRIX_SCFG0 (64) // Slave Configuration Register 0 > +#define MATRIX_SCFG1 (68) // Slave Configuration Register 1 > +#define MATRIX_SCFG2 (72) // Slave Configuration Register 2 > +#define MATRIX_SCFG3 (76) // Slave Configuration Register 3 > +#define MATRIX_SCFG4 (80) // Slave Configuration Register 4 > +#define MATRIX_SCFG5 (84) // Slave Configuration Register 5 > +#define MATRIX_SCFG6 (88) // Slave Configuration Register 6 > +#define MATRIX_SCFG7 (92) // Slave Configuration Register 7 > +#define MATRIX_PRAS0 (128) // PRAS0 > +#define MATRIX_PRBS0 (132) // PRBS0 > +#define MATRIX_PRAS1 (136) // PRAS1 > +#define MATRIX_PRBS1 (140) // PRBS1 > +#define MATRIX_PRAS2 (144) // PRAS2 > +#define MATRIX_PRBS2 (148) // PRBS2 > +#define MATRIX_PRAS3 (152) // PRAS3 > +#define MATRIX_PRBS3 (156) // PRBS3 > +#define MATRIX_PRAS4 (160) // PRAS4 > +#define MATRIX_PRBS4 (164) // PRBS4 > +#define MATRIX_PRAS5 (168) // PRAS5 > +#define MATRIX_PRBS5 (172) // PRBS5 > +#define MATRIX_PRAS6 (176) // PRAS6 > +#define MATRIX_PRBS6 (180) // PRBS6 > +#define MATRIX_PRAS7 (184) // PRAS7 > +#define MATRIX_PRBS7 (188) // PRBS7 > +#define MATRIX_MRCR (256) // Master Remp Control Register > + > +#define AT91C_MATRIX_RCA926I (0x1 << 0) // (MATRIX) Remap Command Bit for ARM926EJ-S Instruction > +#define AT91C_MATRIX_RCA926D (0x1 << 1) // (MATRIX) Remap Command Bit for ARM926EJ-S Data > +#define AT91C_MATRIX_RCB2 (0x1 << 2) // (MATRIX) Remap Command Bit for PDC > +#define AT91C_MATRIX_RCB3 (0x1 << 3) // (MATRIX) Remap Command Bit for LCD > +#define AT91C_MATRIX_RCB4 (0x1 << 4) // (MATRIX) Remap Command Bit for 2DGC > +#define AT91C_MATRIX_RCB5 (0x1 << 5) // (MATRIX) Remap Command Bit for ISI > +#define AT91C_MATRIX_RCB6 (0x1 << 6) // (MATRIX) Remap Command Bit for DMA > +#define AT91C_MATRIX_RCB7 (0x1 << 7) // (MATRIX) Remap Command Bit for EMAC > +#define AT91C_MATRIX_RCB8 (0x1 << 8) // (MATRIX) Remap Command Bit for USB > + > +/*pitc */ > +#define AT91_PTIC_MR_PITEN (1 << 24) > +#define AT91_PTIC_MR_PITIEN (1 << 25) > +#define AT91_PITC_MR 0 > +#define AT91_PITC_SR (0x4 / sizeof(uint32_t)) > +#define AT91_PITC_PIVR (0x8 / sizeof(uint32_t)) > +#define AT91_PITC_PIIR (0xC / sizeof(uint32_t)) > + > +/*AIC registers*/ > +#define AT91_AIC_SVR0 (0x80 / sizeof(uint32_t)) > +#define AT91_AIC_ISR (0x108 / sizeof(uint32_t)) > +#define AT91_AIC_IECR (0x120 / sizeof(uint32_t)) > +#define AT91_AIC_EOICR (0x130 / sizeof(uint32_t)) > +#define AT91_AIC_IVR (0x100 / sizeof(uint32_t)) > +#define AT91_AIC_IDCR (0x124 / sizeof(uint32_t)) > + > +#define AT91_PERIPH_SYS_ID 1 > + > +#endif//!_HW_AT91SAM9263_DEFS_H_ > -- > 1.6.5.2 > > -- > /Evgeniy > > > >
On Tue, Nov 17, 2009 at 10:39:27AM +0100, Filip Navara wrote: > I'd say it is preferable to split the individual devices and model > them using the QDEV infrastructure instead of putting it all together > into one "system controller" device. > > I've QDEV-based implementation of these devices already: PMC, DBGU, > PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and > USART (which is very similar to DBGU) to be split up. > I also see ethernet IP block (emac), I have plans to implement it, what about USB slave and CAN controller, you plan/have implementations of them?
On Tue, Nov 17, 2009 at 8:23 PM, Evgeniy Dushistov <dushistov@mail.ru> wrote: > On Tue, Nov 17, 2009 at 10:39:27AM +0100, Filip Navara wrote: >> I'd say it is preferable to split the individual devices and model >> them using the QDEV infrastructure instead of putting it all together >> into one "system controller" device. >> >> I've QDEV-based implementation of these devices already: PMC, DBGU, >> PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and >> USART (which is very similar to DBGU) to be split up. >> > > I also see ethernet IP block (emac), > I have plans to implement it, > what about USB slave and CAN controller, you plan/have implementations > of them? The EMAC emulation is fully functional and good enough to run a FreeRTOS/uIP web server and all Atmel examples. I do not plan to implement USB slave or CAN controller, but I would certainly welcome if you (or someone else) implemented it. If anything then I will implement I2C. Best regards, Filip Navara
diff --git a/Makefile.target b/Makefile.target index 7542199..67f441d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -268,7 +268,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o endif obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o -obj-arm-y += pflash_atmel.o +obj-arm-y += pflash_atmel.o at91sam9.o obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o obj-arm-y += versatile_pci.o obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o diff --git a/hw/at91sam9.c b/hw/at91sam9.c new file mode 100644 index 0000000..7ac60d9 --- /dev/null +++ b/hw/at91sam9.c @@ -0,0 +1,695 @@ +/* + * Atmel at91sam9263 cpu + NOR flash + SDRAM emulation + * Written by Evgeniy Dushistov + * This code is licenced under the GPL. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "hw.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "net.h" +#include "sysemu.h" +#include "flash.h" +#include "boards.h" +#include "qemu-char.h" +#include "qemu-timer.h" + +#include "at91sam9263_defs.h" + +//#define AT91_TRACE_ON +//#define AT91_DEBUG_ON + +#define ARM_AIC_CPU_IRQ 0 +#define ARM_AIC_CPU_FIQ 1 + +#define NOR_FLASH_SIZE (1024 * 1024 * 8) +#define AT91SAM9263EK_SDRAM_SIZE (1024 * 1024 * 64) +#define AT91SAM9263EK_SDRAM_OFF 0x20000000 +#define AT91SAM9263EK_NORFLASH_OFF 0x10000000 + +#ifdef AT91_DEBUG_ON +# define DEBUG(f, a...) { \ + printf ("at91 (%s, %d): %s:", \ + __FILE__, __LINE__, __func__); \ + printf (f, ## a); \ + } +#else +# define DEBUG(f, a...) do { } while (0) +#endif + +#ifdef AT91_TRACE_ON +static FILE *trace_file; +# define TRACE(f, a...) do { \ + fprintf (trace_file, f, ## a); \ + } while (0) +#else +# define TRACE(f, a...) do { } while (0) +#endif + + +struct dbgu_state { + CharDriverState *chr; +}; + +struct at91sam9_state { + uint32_t pmc_regs[28]; + uint32_t dbgu_regs[0x124 / 4]; + uint32_t bus_matrix_regs[0x100 / 4]; + uint32_t ccfg_regs[(0x01FC - 0x0110 + 1) / sizeof(uint32_t)]; + uint32_t pio_regs[(AT91_PMC_BASE - AT91_PIO_BASE) / sizeof(uint32_t)]; + uint32_t sdramc0_regs[(AT91_SMC0_BASE - AT91_SDRAMC0_BASE) / sizeof(uint32_t)]; + uint32_t smc0_regs[(AT91_ECC1_BASE - AT91_SMC0_BASE) / sizeof(uint32_t)]; + uint32_t pitc_regs[80]; + uint32_t aic_regs[(AT91_PIO_BASE - AT91_AIC_BASE) / sizeof(uint32_t)]; + uint32_t usart0_regs[0x1000 / sizeof(uint32_t)]; + struct dbgu_state dbgu; + pflash_t *norflash; + ram_addr_t internal_sram; + QEMUTimer *dbgu_tr_timer; + ptimer_state *pitc_timer; + int timer_active; + CPUState *env; + qemu_irq *qirq; + uint64_t char_transmit_time; +}; + +static uint32_t at91_pmc_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + TRACE("pmc read offset %X\n", offset); + return sam9->pmc_regs[offset / 4]; +} + +static void at91_pmc_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("pmc write offset %X, value %X\n", offset, value); + switch (offset / 4) { + case AT91_PMC_MCKR: + sam9->pmc_regs[AT91_PMC_MCKR] = value; + switch (value & AT91_PMC_CSS) { + case 1: + //Main clock is selected + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MCKRDY | AT91_PMC_MOSCS; + break; + default: + DEBUG("unimplemented\n"); + break; + } + break; + case AT91_PMC_MOR: + sam9->pmc_regs[AT91_PMC_MOR] = value; + if (value & 1) { + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MOSCS; + } + break; + case AT91_PMC_PLLAR: + sam9->pmc_regs[AT91_PMC_PLLAR] = value; + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKA; + break; + case AT91_PMC_PLLBR: + sam9->pmc_regs[AT91_PMC_PLLBR] = value; + sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKB; + break; + case AT91_PMC_PCER: + sam9->pmc_regs[AT91_PMC_PCER] |= value; + break; + default: + //DEBUG("unimplemented, offset %X\n", offset); + break; + } +} + +static uint32_t at91_dbgu_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + offset /= 4; + if (offset == AT91_DBGU_RHR) { + sam9->dbgu_regs[AT91_DBGU_SR] &= (uint32_t)~1; + }/* else if (offset == AT91_DBGU_SR)*/ + + return sam9->dbgu_regs[offset]; +} + +static void at91_dbgu_state_changed(struct at91sam9_state *sam9) +{ + if ((sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) && + (sam9->dbgu_regs[AT91_DBGU_IMR] & sam9->dbgu_regs[AT91_DBGU_SR])) { + sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID; + sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID]; + qemu_irq_raise(sam9->qirq[0]); + } +} + +static void dbgu_serial_end_xmit(void *opaque) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + sam9->dbgu_regs[AT91_DBGU_SR] |= (AT91_US_TXEMPTY | AT91_US_TXRDY); + at91_dbgu_state_changed(sam9); +} + +static void at91_dbgu_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + unsigned char ch; + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + switch (offset / 4) { + case AT91_DBGU_CR: + sam9->dbgu_regs[AT91_DBGU_CR] = value; + if (value & AT91_US_TXEN) + sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_TXRDY | AT91_US_TXEMPTY; + if (value & AT91_US_TXDIS) + sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXRDY | AT91_US_TXEMPTY); + break; + case AT91_DBGU_IER: + sam9->dbgu_regs[AT91_DBGU_IMR] |= value; + at91_dbgu_state_changed(sam9); + break; + case AT91_DBGU_IDR: + sam9->dbgu_regs[AT91_DBGU_IMR] &= ~value; + break; + case AT91_DBGU_THR: + sam9->dbgu_regs[AT91_DBGU_THR] = value; + sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXEMPTY | AT91_US_TXRDY); + ch = value; + if (sam9->dbgu.chr) + qemu_chr_write(sam9->dbgu.chr, &ch, 1); + qemu_mod_timer(sam9->dbgu_tr_timer , qemu_get_clock(vm_clock) + sam9->char_transmit_time); + break; + default: + //DEBUG("unimplemented\n"); + break; + } +} + +static int at91_dbgu_can_receive(void *opaque) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + return (sam9->dbgu_regs[AT91_DBGU_SR] & AT91_US_RXRDY) == 0; +} + +static void at91_dbgu_receive(void *opaque, const uint8_t *buf, int size) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + int i; + /*! \todo if not one character we need wait before irq handled, + but from other hand at91_dbgu_can_receive should prevent this + */ + for (i = 0; i < size; ++i) { + sam9->dbgu_regs[AT91_DBGU_RHR] = buf[i]; + sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_RXRDY; + at91_dbgu_state_changed(sam9); + } +} + +static void at91_dbgu_event(void *opaque, int event) +{ + DEBUG("begin\n"); +} + +static uint32_t at91_bus_matrix_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("bus_matrix read offset %X\n", offset); + return sam9->bus_matrix_regs[offset / 4]; +} + +static void at91_bus_matrix_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("bus_matrix write offset %X, value %X\n", offset, value); + switch (offset) { + case MATRIX_MRCR: + DEBUG("write to MATRIX mrcr reg\n"); + if (value & (AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D)) { + cpu_register_physical_memory(0x0, 80 * 1024, sam9->internal_sram | IO_MEM_RAM); + } + break; + default: + DEBUG("unimplemented\n"); + break; + } +} + +static void at91_init_pmc(struct at91sam9_state *sam9) +{ + DEBUG("begin\n"); + sam9->pmc_regs[AT91_PMC_MCKR] = 0; + sam9->pmc_regs[AT91_PMC_MOR] = 0; + sam9->pmc_regs[AT91_PMC_SR] = 0x08; + sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00; + sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00; +} + +static void at91_init_bus_matrix(struct at91sam9_state *sam9) +{ + DEBUG("begin\n"); + memset(&sam9->bus_matrix_regs, 0, sizeof(sam9->bus_matrix_regs)); +} + +static void at91_init_dbgu(struct at91sam9_state *sam9, CharDriverState *chr) +{ + DEBUG("begin\n"); + + memset(&sam9->dbgu_regs, 0, sizeof(sam9->dbgu_regs)); + sam9->dbgu_regs[AT91_DBGU_SR] = AT91_US_TXEMPTY | AT91_US_TXRDY; + + sam9->dbgu.chr = chr; + sam9->dbgu_tr_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *)dbgu_serial_end_xmit, sam9); + sam9->char_transmit_time = (get_ticks_per_sec() / 115200) * 10; + if (chr) + qemu_chr_add_handlers(chr, at91_dbgu_can_receive, + at91_dbgu_receive, + at91_dbgu_event, sam9); +} + +static uint32_t at91_ccfg_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("ccfg read offset %X\n", offset); + return sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])]; +} + +static void at91_ccfg_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("ccfg write offset %X, value %X\n", offset, value); + sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])] = value; +} + +static uint32_t at91_pio_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("pio read offset %X\n", offset); + return sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])]; +} + +static void at91_pio_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("pio write offset %X, value %X\n", offset, value); + sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])] = value; +} + +static uint32_t at91_sdramc0_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("sdramc0 read offset %X\n", offset); + return sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])]; +} + +static void at91_sdramc0_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("sdramc0 write offset %X, value %X\n", offset, value); + sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])] = value; +} + +static uint32_t at91_smc0_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("smc0 read offset %X\n", offset); + return sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])]; +} + +static void at91_smc0_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("smc0 write offset %X, value %X\n", offset, value); + sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])] = value; +} + +static void at91_pitc_timer_tick(void * opaque) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + uint64_t val = ptimer_get_count(sam9->pitc_timer); + + unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20) + 1; + sam9->pitc_regs[AT91_PITC_PIIR] = (val & ((1 << 21) - 1)) | (tick << 20); + sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR]; + + if ((sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITIEN) && + (sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) && + !sam9->pitc_regs[AT91_PITC_SR]) { + sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID; + sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID]; + + sam9->pitc_regs[AT91_PITC_SR] = 1; + qemu_irq_raise(sam9->qirq[0]); + } +} + +static uint32_t at91_pitc_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + int pitc_enable = !!(sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITEN); + int idx; + + idx = offset / sizeof(sam9->pitc_regs[0]); + switch (idx) { + case AT91_PITC_SR: +// DEBUG("read sr: %X\n", sam9->pitc_regs[idx]); + break; + case AT91_PITC_PIVR: + if (pitc_enable) { +// DEBUG("clear sr\n"); + sam9->pitc_regs[AT91_PITC_SR] = 0; + } else { +// DEBUG("pitc disabled\n"); + break; + } + case AT91_PITC_PIIR: + if (pitc_enable) { + uint64_t val = ptimer_get_count(sam9->pitc_timer); + unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20); + uint32_t res = (tick << 20) | (val & ((1 << 21) - 1)); + + if (idx == AT91_PITC_PIVR) + tick = 0; + sam9->pitc_regs[AT91_PITC_PIIR] = (tick << 20) | (val & ((1 << 21) - 1)); + sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR]; + TRACE("pitc read offset %X, value %X\n", offset, res); + return res; + } else { +// DEBUG("pitc disabled\n"); + break; + } + + default: + /*nothing*/break; + } + TRACE("pitc read offset %X, value %X\n", offset, sam9->pitc_regs[idx]); + + return sam9->pitc_regs[idx]; +} + +static void at91_pitc_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + + TRACE("pitc write offset %X, value %X\n", offset, value); + int idx = offset / sizeof(sam9->pitc_regs[0]); + switch (idx) { + case AT91_PITC_MR: { + int pitc_enable = !!(value & AT91_PTIC_MR_PITEN); + unsigned int period = value & 0xFFFFF; + + //DEBUG("set period %u, int enabled? %d\n", period, !!(value & AT91_PTIC_MR_PITIEN)); + + if (pitc_enable && period != 0) { + sam9->timer_active = 1; + //! \todo get real value from PLL + ptimer_set_freq(sam9->pitc_timer, (100 * 1000 * 1000) / 16); + ptimer_set_limit(sam9->pitc_timer, period, 1); + ptimer_run(sam9->pitc_timer, 0); + } else if (sam9->timer_active) { + TRACE("disable timer\n"); + sam9->pitc_regs[AT91_PITC_PIVR] = 0; + ptimer_stop(sam9->pitc_timer); + } + } + break; + default: + TRACE("unhandled register %d\n", idx); + break; + } + sam9->pitc_regs[idx] = value; +} + +static void at91_init_pitc(struct at91sam9_state *sam9) +{ + QEMUBH *bh; + + DEBUG("begin\n"); + memset(&sam9->pitc_regs, 0, sizeof(sam9->pitc_regs)); + sam9->pitc_regs[AT91_PITC_MR] = 0xFFFFF; + bh = qemu_bh_new(at91_pitc_timer_tick, sam9); + sam9->pitc_timer = ptimer_init(bh); +} + +static uint32_t at91_aic_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + unsigned int idx = offset / sizeof(sam9->aic_regs[0]); + if (idx == AT91_AIC_IVR) { + qemu_irq_lower(sam9->qirq[0]); + } else if (idx == AT91_AIC_ISR) { + uint32_t val = sam9->aic_regs[idx]; + sam9->aic_regs[idx] = 0; + return val; + } + + return sam9->aic_regs[idx]; +} + +static void at91_aic_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + unsigned int idx = offset / sizeof(sam9->aic_regs[0]); + + switch (idx) { + case AT91_AIC_IECR: + sam9->aic_regs[idx] |= value; + break; + case AT91_AIC_IDCR: + sam9->aic_regs[idx] |= value; + sam9->aic_regs[AT91_AIC_IECR] &= ~value; + break; + case AT91_AIC_IVR://ignore write + break; + case AT91_AIC_EOICR: +// DEBUG("we write to end of interrupt reg\n"); + break; + default: + sam9->aic_regs[idx] = value; + break; + } +} + +static uint32_t at91_usart_read(void *opaque, target_phys_addr_t offset) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + DEBUG("we read from %X\n", offset); + return sam9->usart0_regs[offset / sizeof(uint32_t)]; +} + +static void at91_usart_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque; + DEBUG("we write to %X: %X\n", offset, value); + sam9->usart0_regs[offset / sizeof(uint32_t)] = value; +} + + +struct ip_block { + target_phys_addr_t offset; + target_phys_addr_t end_offset; + uint32_t (*read_func)(void *, target_phys_addr_t); + void (*write_func)(void *, target_phys_addr_t, uint32_t); +}; + +static struct ip_block ip_blocks[] = { + {AT91_USART0_BASE - AT91_PERIPH_BASE, AT91_USART0_BASE - AT91_PERIPH_BASE + 0x1000, at91_usart_read, at91_usart_write}, + {AT91_SDRAMC0_BASE - AT91_PERIPH_BASE, AT91_SMC0_BASE - AT91_PERIPH_BASE, at91_sdramc0_read, at91_sdramc0_write}, + {AT91_SMC0_BASE - AT91_PERIPH_BASE, AT91_ECC1_BASE - AT91_PERIPH_BASE, at91_smc0_read, at91_smc0_write}, + {AT91_BUS_MATRIX_BASE - AT91_PERIPH_BASE, AT91_CCFG_BASE - AT91_PERIPH_BASE, at91_bus_matrix_read, at91_bus_matrix_write}, + {AT91_CCFG_BASE - AT91_PERIPH_BASE, AT91_DBGU_BASE - AT91_PERIPH_BASE, at91_ccfg_read, at91_ccfg_write}, + {AT91_DBGU_BASE - AT91_PERIPH_BASE, AT91_AIC_BASE - AT91_PERIPH_BASE, at91_dbgu_read, at91_dbgu_write}, + {AT91_AIC_BASE - AT91_PERIPH_BASE, AT91_PIO_BASE - AT91_PERIPH_BASE, at91_aic_read, at91_aic_write}, + {AT91_PIO_BASE - AT91_PERIPH_BASE, AT91_PMC_BASE - AT91_PERIPH_BASE, at91_pio_read, at91_pio_write}, + {AT91_PMC_BASE - AT91_PERIPH_BASE, AT91_RSTC_BASE - AT91_PERIPH_BASE, at91_pmc_read, at91_pmc_write}, + {AT91_PITC_BASE - AT91_PERIPH_BASE, AT91_WDT_BASE - AT91_PERIPH_BASE, at91_pitc_read, at91_pitc_write}, +}; + +static uint32_t at91_periph_read(void *opaque, target_phys_addr_t offset) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i) + if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) + return ip_blocks[i].read_func(opaque, offset - ip_blocks[i].offset); + DEBUG("read from unsupported periph addr %X\n", offset); + return 0xFFFFFFFFUL; +} + +static void at91_periph_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i) + if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) { + ip_blocks[i].write_func(opaque, offset - ip_blocks[i].offset, value); + return; + } + DEBUG("write to unsupported periph: addr %X, val %X\n", offset, value); +} + +/* Input 0 is IRQ and input 1 is FIQ. */ +static void arm_aic_cpu_handler(void *opaque, int irq, int level) +{ + CPUState *env = (CPUState *)opaque; + switch (irq) { + case ARM_AIC_CPU_IRQ: + if (level) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + break; + case ARM_AIC_CPU_FIQ: + if (level) + cpu_interrupt(env, CPU_INTERRUPT_FIQ); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); + break; + default: + hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq); + } +} + +static void at91_aic_init(struct at91sam9_state *sam9) +{ + memset(&sam9->aic_regs[0], 0, sizeof(sam9->aic_regs)); + sam9->qirq = qemu_allocate_irqs(arm_aic_cpu_handler, sam9->env, 2); +} + +static CPUReadMemoryFunc *at91_periph_readfn[] = { + at91_periph_read, + at91_periph_read, + at91_periph_read +}; + +static CPUWriteMemoryFunc *at91_periph_writefn[] = { + at91_periph_write, + at91_periph_write, + at91_periph_write +}; + + +static void at91sam9_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + CPUState *env; + DriveInfo *dinfo; + struct at91sam9_state *sam9; + int iomemtype; + + DEBUG("begin, ram_size %llu\n", (unsigned long long)ram_size); +#ifdef TRACE_ON + trace_file = fopen("/tmp/trace.log", "w"); +#endif + if (!cpu_model) + cpu_model = "arm926"; + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(EXIT_FAILURE); + } + /* SDRAM at chipselect 1. */ + cpu_register_physical_memory(AT91SAM9263EK_SDRAM_OFF, AT91SAM9263EK_SDRAM_SIZE, + qemu_ram_alloc(AT91SAM9263EK_SDRAM_SIZE) | IO_MEM_RAM); + + sam9 = (struct at91sam9_state *)qemu_mallocz(sizeof(*sam9)); + if (!sam9) { + fprintf(stderr, "allocation failed\n"); + exit(EXIT_FAILURE); + } + sam9->env = env; + /* Internal SRAM */ + sam9->internal_sram = qemu_ram_alloc(80 * 1024); + cpu_register_physical_memory(0x00300000, 80 * 1024, sam9->internal_sram | IO_MEM_RAM); + + /*Internal Peripherals */ + iomemtype = cpu_register_io_memory(at91_periph_readfn, at91_periph_writefn, sam9); + cpu_register_physical_memory(0xF0000000, 0xFFFFFFFF - 0xF0000000, iomemtype); + + at91_init_pmc(sam9); + at91_init_bus_matrix(sam9); + memset(&sam9->ccfg_regs, 0, sizeof(sam9->ccfg_regs)); + memset(&sam9->pio_regs, 0, sizeof(sam9->pio_regs)); + memset(&sam9->sdramc0_regs, 0, sizeof(sam9->sdramc0_regs)); + memset(&sam9->smc0_regs, 0, sizeof(sam9->smc0_regs)); + at91_init_dbgu(sam9, serial_hds[0]); + at91_init_pitc(sam9); + at91_aic_init(sam9); + memset(sam9->usart0_regs, 0, sizeof(sam9->usart0_regs)); + + /* + we use variant of booting from external memory (NOR FLASH), + it mapped to 0x0 at start, and also it is accessable from 0x10000000 address + */ + dinfo = drive_get(IF_PFLASH, 0, 0); + if (dinfo) { + ram_addr_t nor_flash_mem = qemu_ram_alloc(NOR_FLASH_SIZE); + if (!nor_flash_mem) { + fprintf(stderr, "allocation failed\n"); + exit(EXIT_FAILURE); + } + + sam9->norflash = pflash_cfi_atmel_register(AT91SAM9263EK_NORFLASH_OFF, + nor_flash_mem, + dinfo->bdrv, + 4 * 1024 * 2, 8, + 32 * 1024 * 2, + (135 - 8), + 2, 0x001F, 0x01D6, 0, 0); + + if (!sam9->norflash) { + fprintf(stderr, "qemu: error registering flash memory.\n"); + exit(EXIT_FAILURE); + } + + DEBUG("register flash at 0x0\n"); + //register only part of flash, to prevent conflict with internal sram + cpu_register_physical_memory(0x0, 100 * 1024 /*NOR_FLASH_SIZE*/, + nor_flash_mem | IO_MEM_ROMD); + } else { + fprintf(stderr, "qemu: can not start without flash.\n"); + exit(EXIT_FAILURE); + } + env->regs[15] = 0x0; +} + +static QEMUMachine at91sam9263ek_machine = { + .name = "at91sam9263ek", + .desc = "Atmel at91sam9263ek board (ARM926EJ-S)", + .init = at91sam9_init, +}; + +static void at91sam9_machine_init(void) +{ + qemu_register_machine(&at91sam9263ek_machine); +} + +machine_init(at91sam9_machine_init) diff --git a/hw/at91sam9263_defs.h b/hw/at91sam9263_defs.h new file mode 100644 index 0000000..c7136c3 --- /dev/null +++ b/hw/at91sam9263_defs.h @@ -0,0 +1,144 @@ +#ifndef _HW_AT91SAM9263_DEFS_H_ +#define _HW_AT91SAM9263_DEFS_H_ + +/* base periph addresses */ +#define AT91_PERIPH_BASE 0xF0000000 +#define AT91_USART0_BASE 0xFFF8C000 +#define AT91_SDRAMC0_BASE 0xFFFFE200 +#define AT91_SMC0_BASE 0xFFFFE400 +#define AT91_ECC1_BASE 0xFFFFE600 +#define AT91_BUS_MATRIX_BASE 0xFFFFEC00 +#define AT91_CCFG_BASE 0xFFFFED10 +#define AT91_DBGU_BASE 0xFFFFEE00 +#define AT91_AIC_BASE 0xFFFFF000 +#define AT91_PIO_BASE 0xFFFFF200 +#define AT91_PMC_BASE 0xFFFFFC00 +#define AT91_RSTC_BASE 0xFFFFFD00 +#define AT91_PITC_BASE 0xFFFFFD30 +#define AT91_WDT_BASE 0xFFFFFD40 + +/* PMC registers */ +#define AT91_PMC_SR (0x68 / sizeof(uint32_t)) +#define AT91_PMC_MCKR (0x0020 / sizeof(uint32_t)) +#define AT91_PMC_MOR (0x30 / sizeof(uint32_t)) +#define AT91_PMC_CSS (0x3 << 0) // (PMC) Programmable Clock Selection +#define AT91_PMC_MCKRDY (0x1 << 3) // (PMC) Master Clock Status/Enable/Disable/Mask +#define AT91_PMC_MOSCS (0x1 << 0) // (PMC) MOSC Status/Enable/Disable/Mask +#define AT91_CKGR_MOSCEN (0x1 << 0) // (CKGR) Main Oscillator Enable +#define AT91_PMC_PLLAR (0x0028 / sizeof(uint32_t)) +#define AT91_PMC_PLLBR (0x002C / sizeof(uint32_t)) +#define AT91_PMC_LOCKA (0x1 << 1) // (PMC) PLL A Status/Enable/Disable/Mask +#define AT91_PMC_LOCKB (0x1 << 2) // (PMC) PLL B Status/Enable/Disable/Mask +#define AT91_PMC_PCER (0x10 / sizeof(uint32_t)) + +/*dbgu registers */ +#define AT91_DBGU_CR 0x0 +#define AT91_DBGU_MR (4 / sizeof(uint32_t)) +#define AT91_DBGU_IER (8 / sizeof(uint32_t)) +#define AT91_DBGU_IDR (0xC / sizeof(uint32_t)) +#define AT91_DBGU_IMR (0x10 / sizeof(uint32_t)) +#define AT91_DBGU_SR (0x14 / sizeof(uint32_t)) +#define AT91_DBGU_RHR (0x18 / sizeof(uint32_t)) +#define AT91_DBGU_THR (0x001C / sizeof(uint32_t)) +#define AT91_DBGU_BRGR (0x0020 / sizeof(uint32_t)) + + +// -------- DBGU_CR : (DBGU Offset: 0x0) Debug Unit Control Register -------- +#define AT91_US_RSTRX (0x1 << 2) // (DBGU) Reset Receiver +#define AT91_US_RSTTX (0x1 << 3) // (DBGU) Reset Transmitter +#define AT91_US_RXEN (0x1 << 4) // (DBGU) Receiver Enable +#define AT91_US_RXDIS (0x1 << 5) // (DBGU) Receiver Disable +#define AT91_US_TXEN (0x1 << 6) // (DBGU) Transmitter Enable +#define AT91_US_TXDIS (0x1 << 7) // (DBGU) Transmitter Disable +#define AT91_US_RSTSTA (0x1 << 8) // (DBGU) Reset Status Bits +// -------- DBGU_IER : (DBGU Offset: 0x8) Debug Unit Interrupt Enable Register -------- +#define AT91_US_RXRDY (0x1 << 0) // (DBGU) RXRDY Interrupt +#define AT91_US_TXRDY (0x1 << 1) // (DBGU) TXRDY Interrupt +#define AT91_US_ENDRX (0x1 << 3) // (DBGU) End of Receive Transfer Interrupt +#define AT91_US_ENDTX (0x1 << 4) // (DBGU) End of Transmit Interrupt +#define AT91_US_OVRE (0x1 << 5) // (DBGU) Overrun Interrupt +#define AT91_US_FRAME (0x1 << 6) // (DBGU) Framing Error Interrupt +#define AT91_US_PARE (0x1 << 7) // (DBGU) Parity Error Interrupt +#define AT91_US_TXEMPTY (0x1 << 9) // (DBGU) TXEMPTY Interrupt +#define AT91_US_TXBUFE (0x1 << 11) // (DBGU) TXBUFE Interrupt +#define AT91_US_RXBUFF (0x1 << 12) // (DBGU) RXBUFF Interrupt +#define AT91_US_COMM_TX (0x1 << 30) // (DBGU) COMM_TX Interrupt +#define AT91_US_COMM_RX (0x1 << 31) // (DBGU) COMM_RX Interrupt + +/* US registers */ +#define AT91_US_CR (0) +#define AT91_US_MR (4 / sizeof(uint32_t)) +#define AT91_US_IER (8 / sizeof(uint32_t)) +#define AT91_US_IDR (0xC / sizeof(uint32_t)) +#define AT91_US_IMR (0x10 / sizeof(uint32_t)) + +/* matrix */ + +// ***************************************************************************** +// SOFTWARE API DEFINITION FOR AHB Matrix Interface +// ***************************************************************************** +// *** Register offset in AT91S_MATRIX structure *** +#define MATRIX_MCFG0 ( 0) // Master Configuration Register 0 +#define MATRIX_MCFG1 ( 4) // Master Configuration Register 1 +#define MATRIX_MCFG2 ( 8) // Master Configuration Register 2 +#define MATRIX_MCFG3 (12) // Master Configuration Register 3 +#define MATRIX_MCFG4 (16) // Master Configuration Register 4 +#define MATRIX_MCFG5 (20) // Master Configuration Register 5 +#define MATRIX_MCFG6 (24) // Master Configuration Register 6 +#define MATRIX_MCFG7 (28) // Master Configuration Register 7 +#define MATRIX_MCFG8 (32) // Master Configuration Register 8 +#define MATRIX_SCFG0 (64) // Slave Configuration Register 0 +#define MATRIX_SCFG1 (68) // Slave Configuration Register 1 +#define MATRIX_SCFG2 (72) // Slave Configuration Register 2 +#define MATRIX_SCFG3 (76) // Slave Configuration Register 3 +#define MATRIX_SCFG4 (80) // Slave Configuration Register 4 +#define MATRIX_SCFG5 (84) // Slave Configuration Register 5 +#define MATRIX_SCFG6 (88) // Slave Configuration Register 6 +#define MATRIX_SCFG7 (92) // Slave Configuration Register 7 +#define MATRIX_PRAS0 (128) // PRAS0 +#define MATRIX_PRBS0 (132) // PRBS0 +#define MATRIX_PRAS1 (136) // PRAS1 +#define MATRIX_PRBS1 (140) // PRBS1 +#define MATRIX_PRAS2 (144) // PRAS2 +#define MATRIX_PRBS2 (148) // PRBS2 +#define MATRIX_PRAS3 (152) // PRAS3 +#define MATRIX_PRBS3 (156) // PRBS3 +#define MATRIX_PRAS4 (160) // PRAS4 +#define MATRIX_PRBS4 (164) // PRBS4 +#define MATRIX_PRAS5 (168) // PRAS5 +#define MATRIX_PRBS5 (172) // PRBS5 +#define MATRIX_PRAS6 (176) // PRAS6 +#define MATRIX_PRBS6 (180) // PRBS6 +#define MATRIX_PRAS7 (184) // PRAS7 +#define MATRIX_PRBS7 (188) // PRBS7 +#define MATRIX_MRCR (256) // Master Remp Control Register + +#define AT91C_MATRIX_RCA926I (0x1 << 0) // (MATRIX) Remap Command Bit for ARM926EJ-S Instruction +#define AT91C_MATRIX_RCA926D (0x1 << 1) // (MATRIX) Remap Command Bit for ARM926EJ-S Data +#define AT91C_MATRIX_RCB2 (0x1 << 2) // (MATRIX) Remap Command Bit for PDC +#define AT91C_MATRIX_RCB3 (0x1 << 3) // (MATRIX) Remap Command Bit for LCD +#define AT91C_MATRIX_RCB4 (0x1 << 4) // (MATRIX) Remap Command Bit for 2DGC +#define AT91C_MATRIX_RCB5 (0x1 << 5) // (MATRIX) Remap Command Bit for ISI +#define AT91C_MATRIX_RCB6 (0x1 << 6) // (MATRIX) Remap Command Bit for DMA +#define AT91C_MATRIX_RCB7 (0x1 << 7) // (MATRIX) Remap Command Bit for EMAC +#define AT91C_MATRIX_RCB8 (0x1 << 8) // (MATRIX) Remap Command Bit for USB + +/*pitc */ +#define AT91_PTIC_MR_PITEN (1 << 24) +#define AT91_PTIC_MR_PITIEN (1 << 25) +#define AT91_PITC_MR 0 +#define AT91_PITC_SR (0x4 / sizeof(uint32_t)) +#define AT91_PITC_PIVR (0x8 / sizeof(uint32_t)) +#define AT91_PITC_PIIR (0xC / sizeof(uint32_t)) + +/*AIC registers*/ +#define AT91_AIC_SVR0 (0x80 / sizeof(uint32_t)) +#define AT91_AIC_ISR (0x108 / sizeof(uint32_t)) +#define AT91_AIC_IECR (0x120 / sizeof(uint32_t)) +#define AT91_AIC_EOICR (0x130 / sizeof(uint32_t)) +#define AT91_AIC_IVR (0x100 / sizeof(uint32_t)) +#define AT91_AIC_IDCR (0x124 / sizeof(uint32_t)) + +#define AT91_PERIPH_SYS_ID 1 + +#endif//!_HW_AT91SAM9263_DEFS_H_
add emulation of at91sam9263 cpu, plus sdram, plus nor flash connected to this cpu Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> --- Makefile.target | 2 +- hw/at91sam9.c | 695 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/at91sam9263_defs.h | 144 ++++++++++ 3 files changed, 840 insertions(+), 1 deletions(-) create mode 100644 hw/at91sam9.c create mode 100644 hw/at91sam9263_defs.h