* [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu
@ 2009-11-15 20:49 Evgeniy Dushistov
2009-11-17 9:39 ` Filip Navara
0 siblings, 1 reply; 4+ messages in thread
From: Evgeniy Dushistov @ 2009-11-15 20:49 UTC (permalink / raw)
To: qemu-devel
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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu
2009-11-15 20:49 [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu Evgeniy Dushistov
@ 2009-11-17 9:39 ` Filip Navara
2009-11-17 19:23 ` Evgeniy Dushistov
0 siblings, 1 reply; 4+ messages in thread
From: Filip Navara @ 2009-11-17 9:39 UTC (permalink / raw)
To: Evgeniy Dushistov; +Cc: qemu-devel
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
>
>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu
2009-11-17 9:39 ` Filip Navara
@ 2009-11-17 19:23 ` Evgeniy Dushistov
2009-11-17 23:43 ` Filip Navara
0 siblings, 1 reply; 4+ messages in thread
From: Evgeniy Dushistov @ 2009-11-17 19:23 UTC (permalink / raw)
To: Filip Navara; +Cc: qemu-devel
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?
--
/Evgeniy
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu
2009-11-17 19:23 ` Evgeniy Dushistov
@ 2009-11-17 23:43 ` Filip Navara
0 siblings, 0 replies; 4+ messages in thread
From: Filip Navara @ 2009-11-17 23:43 UTC (permalink / raw)
To: Evgeniy Dushistov; +Cc: qemu-devel
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
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-11-17 23:43 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-15 20:49 [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu Evgeniy Dushistov
2009-11-17 9:39 ` Filip Navara
2009-11-17 19:23 ` Evgeniy Dushistov
2009-11-17 23:43 ` Filip Navara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).