qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu


From: Filip Navara
Subject: Re: [Qemu-devel] [PATCH 2/2] [RFC] add emulation of at91sam9263 cpu
Date: Tue, 17 Nov 2009 10:39:27 +0100

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 <address@hidden> wrote:
> add emulation of at91sam9263 cpu, plus sdram, plus nor flash connected to 
> this cpu
>
>
> Signed-off-by: Evgeniy Dushistov <address@hidden>
> ---
>  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
>
>
>
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]