qemu-e2k/hw/pxa2xx.c
Alexander Graf 2507c12ab0 Add endianness as io mem parameter
As stated before, devices can be little, big or native endian. The
target endianness is not of their concern, so we need to push things
down a level.

This patch adds a parameter to cpu_register_io_memory that allows a
device to choose its endianness. For now, all devices simply choose
native endian, because that's the same behavior as before.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2010-12-11 15:24:25 +00:00

2293 lines
65 KiB
C

/*
* Intel XScale PXA255/270 processor support.
*
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
* This code is licenced under the GPL.
*/
#include "sysbus.h"
#include "pxa.h"
#include "sysemu.h"
#include "pc.h"
#include "i2c.h"
#include "ssi.h"
#include "qemu-timer.h"
#include "qemu-char.h"
#include "blockdev.h"
static struct {
target_phys_addr_t io_base;
int irqn;
} pxa255_serial[] = {
{ 0x40100000, PXA2XX_PIC_FFUART },
{ 0x40200000, PXA2XX_PIC_BTUART },
{ 0x40700000, PXA2XX_PIC_STUART },
{ 0x41600000, PXA25X_PIC_HWUART },
{ 0, 0 }
}, pxa270_serial[] = {
{ 0x40100000, PXA2XX_PIC_FFUART },
{ 0x40200000, PXA2XX_PIC_BTUART },
{ 0x40700000, PXA2XX_PIC_STUART },
{ 0, 0 }
};
typedef struct PXASSPDef {
target_phys_addr_t io_base;
int irqn;
} PXASSPDef;
#if 0
static PXASSPDef pxa250_ssp[] = {
{ 0x41000000, PXA2XX_PIC_SSP },
{ 0, 0 }
};
#endif
static PXASSPDef pxa255_ssp[] = {
{ 0x41000000, PXA2XX_PIC_SSP },
{ 0x41400000, PXA25X_PIC_NSSP },
{ 0, 0 }
};
#if 0
static PXASSPDef pxa26x_ssp[] = {
{ 0x41000000, PXA2XX_PIC_SSP },
{ 0x41400000, PXA25X_PIC_NSSP },
{ 0x41500000, PXA26X_PIC_ASSP },
{ 0, 0 }
};
#endif
static PXASSPDef pxa27x_ssp[] = {
{ 0x41000000, PXA2XX_PIC_SSP },
{ 0x41700000, PXA27X_PIC_SSP2 },
{ 0x41900000, PXA2XX_PIC_SSP3 },
{ 0, 0 }
};
#define PMCR 0x00 /* Power Manager Control register */
#define PSSR 0x04 /* Power Manager Sleep Status register */
#define PSPR 0x08 /* Power Manager Scratch-Pad register */
#define PWER 0x0c /* Power Manager Wake-Up Enable register */
#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */
#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */
#define PEDR 0x18 /* Power Manager Edge-Detect Status register */
#define PCFR 0x1c /* Power Manager General Configuration register */
#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */
#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */
#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */
#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */
#define RCSR 0x30 /* Reset Controller Status register */
#define PSLR 0x34 /* Power Manager Sleep Configuration register */
#define PTSR 0x38 /* Power Manager Standby Configuration register */
#define PVCR 0x40 /* Power Manager Voltage Change Control register */
#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */
#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */
#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */
#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */
static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case PMCR ... PCMD31:
if (addr & 3)
goto fail;
return s->pm_regs[addr >> 2];
default:
fail:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case PMCR:
s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
s->pm_regs[addr >> 2] |= value & 0x15;
break;
case PSSR: /* Read-clean registers */
case RCSR:
case PKSR:
s->pm_regs[addr >> 2] &= ~value;
break;
default: /* Read-write registers */
if (!(addr & 3)) {
s->pm_regs[addr >> 2] = value;
break;
}
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
}
static CPUReadMemoryFunc * const pxa2xx_pm_readfn[] = {
pxa2xx_pm_read,
pxa2xx_pm_read,
pxa2xx_pm_read,
};
static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = {
pxa2xx_pm_write,
pxa2xx_pm_write,
pxa2xx_pm_write,
};
static void pxa2xx_pm_save(QEMUFile *f, void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 0x40; i ++)
qemu_put_be32s(f, &s->pm_regs[i]);
}
static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 0x40; i ++)
qemu_get_be32s(f, &s->pm_regs[i]);
return 0;
}
#define CCCR 0x00 /* Core Clock Configuration register */
#define CKEN 0x04 /* Clock Enable register */
#define OSCC 0x08 /* Oscillator Configuration register */
#define CCSR 0x0c /* Core Clock Status register */
static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case CCCR:
case CKEN:
case OSCC:
return s->cm_regs[addr >> 2];
case CCSR:
return s->cm_regs[CCCR >> 2] | (3 << 28);
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case CCCR:
case CKEN:
s->cm_regs[addr >> 2] = value;
break;
case OSCC:
s->cm_regs[addr >> 2] &= ~0x6c;
s->cm_regs[addr >> 2] |= value & 0x6e;
if ((value >> 1) & 1) /* OON */
s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
}
static CPUReadMemoryFunc * const pxa2xx_cm_readfn[] = {
pxa2xx_cm_read,
pxa2xx_cm_read,
pxa2xx_cm_read,
};
static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = {
pxa2xx_cm_write,
pxa2xx_cm_write,
pxa2xx_cm_write,
};
static void pxa2xx_cm_save(QEMUFile *f, void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 4; i ++)
qemu_put_be32s(f, &s->cm_regs[i]);
qemu_put_be32s(f, &s->clkcfg);
qemu_put_be32s(f, &s->pmnc);
}
static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 4; i ++)
qemu_get_be32s(f, &s->cm_regs[i]);
qemu_get_be32s(f, &s->clkcfg);
qemu_get_be32s(f, &s->pmnc);
return 0;
}
static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (reg) {
case 6: /* Clock Configuration register */
return s->clkcfg;
case 7: /* Power Mode register */
return 0;
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
return 0;
}
static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
static const char *pwrmode[8] = {
"Normal", "Idle", "Deep-idle", "Standby",
"Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
};
switch (reg) {
case 6: /* Clock Configuration register */
s->clkcfg = value & 0xf;
if (value & 2)
printf("%s: CPU frequency change attempt\n", __FUNCTION__);
break;
case 7: /* Power Mode register */
if (value & 8)
printf("%s: CPU voltage change attempt\n", __FUNCTION__);
switch (value & 7) {
case 0:
/* Do nothing */
break;
case 1:
/* Idle */
if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */
cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
break;
}
/* Fall through. */
case 2:
/* Deep-Idle */
cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
goto message;
case 3:
s->env->uncached_cpsr =
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
s->env->cp15.c1_sys = 0;
s->env->cp15.c1_coproc = 0;
s->env->cp15.c2_base0 = 0;
s->env->cp15.c3 = 0;
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
/*
* The scratch-pad register is almost universally used
* for storing the return address on suspend. For the
* lack of a resuming bootloader, perform a jump
* directly to that address.
*/
memset(s->env->regs, 0, 4 * 15);
s->env->regs[15] = s->pm_regs[PSPR >> 2];
#if 0
buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
cpu_physical_memory_write(0, &buffer, 4);
buffer = s->pm_regs[PSPR >> 2];
cpu_physical_memory_write(8, &buffer, 4);
#endif
/* Suspend */
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
goto message;
default:
message:
printf("%s: machine entered %s mode\n", __FUNCTION__,
pwrmode[value & 7]);
}
break;
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
}
/* Performace Monitoring Registers */
#define CPPMNC 0 /* Performance Monitor Control register */
#define CPCCNT 1 /* Clock Counter register */
#define CPINTEN 4 /* Interrupt Enable register */
#define CPFLAG 5 /* Overflow Flag register */
#define CPEVTSEL 8 /* Event Selection register */
#define CPPMN0 0 /* Performance Count register 0 */
#define CPPMN1 1 /* Performance Count register 1 */
#define CPPMN2 2 /* Performance Count register 2 */
#define CPPMN3 3 /* Performance Count register 3 */
static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (reg) {
case CPPMNC:
return s->pmnc;
case CPCCNT:
if (s->pmnc & 1)
return qemu_get_clock(vm_clock);
else
return 0;
case CPINTEN:
case CPFLAG:
case CPEVTSEL:
return 0;
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
return 0;
}
static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (reg) {
case CPPMNC:
s->pmnc = value;
break;
case CPCCNT:
case CPINTEN:
case CPFLAG:
case CPEVTSEL:
break;
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
}
static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
{
switch (crm) {
case 0:
return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
case 1:
return pxa2xx_perf_read(opaque, op2, reg, crm);
case 2:
switch (reg) {
case CPPMN0:
case CPPMN1:
case CPPMN2:
case CPPMN3:
return 0;
}
/* Fall through */
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
return 0;
}
static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
uint32_t value)
{
switch (crm) {
case 0:
pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
break;
case 1:
pxa2xx_perf_write(opaque, op2, reg, crm, value);
break;
case 2:
switch (reg) {
case CPPMN0:
case CPPMN1:
case CPPMN2:
case CPPMN3:
return;
}
/* Fall through */
default:
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
break;
}
}
#define MDCNFG 0x00 /* SDRAM Configuration register */
#define MDREFR 0x04 /* SDRAM Refresh Control register */
#define MSC0 0x08 /* Static Memory Control register 0 */
#define MSC1 0x0c /* Static Memory Control register 1 */
#define MSC2 0x10 /* Static Memory Control register 2 */
#define MECR 0x14 /* Expansion Memory Bus Config register */
#define SXCNFG 0x1c /* Synchronous Static Memory Config register */
#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */
#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */
#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */
#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */
#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */
#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */
#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */
#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */
#define ARB_CNTL 0x48 /* Arbiter Control register */
#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */
#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */
#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */
#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */
#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */
#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */
#define SA1110 0x64 /* SA-1110 Memory Compatibility register */
static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case MDCNFG ... SA1110:
if ((addr & 3) == 0)
return s->mm_regs[addr >> 2];
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case MDCNFG ... SA1110:
if ((addr & 3) == 0) {
s->mm_regs[addr >> 2] = value;
break;
}
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
}
static CPUReadMemoryFunc * const pxa2xx_mm_readfn[] = {
pxa2xx_mm_read,
pxa2xx_mm_read,
pxa2xx_mm_read,
};
static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = {
pxa2xx_mm_write,
pxa2xx_mm_write,
pxa2xx_mm_write,
};
static void pxa2xx_mm_save(QEMUFile *f, void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 0x1a; i ++)
qemu_put_be32s(f, &s->mm_regs[i]);
}
static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxState *s = (PXA2xxState *) opaque;
int i;
for (i = 0; i < 0x1a; i ++)
qemu_get_be32s(f, &s->mm_regs[i]);
return 0;
}
/* Synchronous Serial Ports */
typedef struct {
SysBusDevice busdev;
qemu_irq irq;
int enable;
SSIBus *bus;
uint32_t sscr[2];
uint32_t sspsp;
uint32_t ssto;
uint32_t ssitr;
uint32_t sssr;
uint8_t sstsa;
uint8_t ssrsa;
uint8_t ssacd;
uint32_t rx_fifo[16];
int rx_level;
int rx_start;
} PXA2xxSSPState;
#define SSCR0 0x00 /* SSP Control register 0 */
#define SSCR1 0x04 /* SSP Control register 1 */
#define SSSR 0x08 /* SSP Status register */
#define SSITR 0x0c /* SSP Interrupt Test register */
#define SSDR 0x10 /* SSP Data register */
#define SSTO 0x28 /* SSP Time-Out register */
#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */
#define SSTSA 0x30 /* SSP TX Time Slot Active register */
#define SSRSA 0x34 /* SSP RX Time Slot Active register */
#define SSTSS 0x38 /* SSP Time Slot Status register */
#define SSACD 0x3c /* SSP Audio Clock Divider register */
/* Bitfields for above registers */
#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
#define SSCR0_SSE (1 << 7)
#define SSCR0_RIM (1 << 22)
#define SSCR0_TIM (1 << 23)
#define SSCR0_MOD (1 << 31)
#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
#define SSCR1_RIE (1 << 0)
#define SSCR1_TIE (1 << 1)
#define SSCR1_LBM (1 << 2)
#define SSCR1_MWDS (1 << 5)
#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
#define SSCR1_EFWR (1 << 14)
#define SSCR1_PINTE (1 << 18)
#define SSCR1_TINTE (1 << 19)
#define SSCR1_RSRE (1 << 20)
#define SSCR1_TSRE (1 << 21)
#define SSCR1_EBCEI (1 << 29)
#define SSITR_INT (7 << 5)
#define SSSR_TNF (1 << 2)
#define SSSR_RNE (1 << 3)
#define SSSR_TFS (1 << 5)
#define SSSR_RFS (1 << 6)
#define SSSR_ROR (1 << 7)
#define SSSR_PINT (1 << 18)
#define SSSR_TINT (1 << 19)
#define SSSR_EOC (1 << 20)
#define SSSR_TUR (1 << 21)
#define SSSR_BCE (1 << 23)
#define SSSR_RW 0x00bc0080
static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
{
int level = 0;
level |= s->ssitr & SSITR_INT;
level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
qemu_set_irq(s->irq, !!level);
}
static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
{
s->sssr &= ~(0xf << 12); /* Clear RFL */
s->sssr &= ~(0xf << 8); /* Clear TFL */
s->sssr &= ~SSSR_TFS;
s->sssr &= ~SSSR_TNF;
if (s->enable) {
s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
s->sssr |= SSSR_RFS;
else
s->sssr &= ~SSSR_RFS;
if (s->rx_level)
s->sssr |= SSSR_RNE;
else
s->sssr &= ~SSSR_RNE;
/* TX FIFO is never filled, so it is always in underrun
condition if SSP is enabled */
s->sssr |= SSSR_TFS;
s->sssr |= SSSR_TNF;
}
pxa2xx_ssp_int_update(s);
}
static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
uint32_t retval;
switch (addr) {
case SSCR0:
return s->sscr[0];
case SSCR1:
return s->sscr[1];
case SSPSP:
return s->sspsp;
case SSTO:
return s->ssto;
case SSITR:
return s->ssitr;
case SSSR:
return s->sssr | s->ssitr;
case SSDR:
if (!s->enable)
return 0xffffffff;
if (s->rx_level < 1) {
printf("%s: SSP Rx Underrun\n", __FUNCTION__);
return 0xffffffff;
}
s->rx_level --;
retval = s->rx_fifo[s->rx_start ++];
s->rx_start &= 0xf;
pxa2xx_ssp_fifo_update(s);
return retval;
case SSTSA:
return s->sstsa;
case SSRSA:
return s->ssrsa;
case SSTSS:
return 0;
case SSACD:
return s->ssacd;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
switch (addr) {
case SSCR0:
s->sscr[0] = value & 0xc7ffffff;
s->enable = value & SSCR0_SSE;
if (value & SSCR0_MOD)
printf("%s: Attempt to use network mode\n", __FUNCTION__);
if (s->enable && SSCR0_DSS(value) < 4)
printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
SSCR0_DSS(value));
if (!(value & SSCR0_SSE)) {
s->sssr = 0;
s->ssitr = 0;
s->rx_level = 0;
}
pxa2xx_ssp_fifo_update(s);
break;
case SSCR1:
s->sscr[1] = value;
if (value & (SSCR1_LBM | SSCR1_EFWR))
printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
pxa2xx_ssp_fifo_update(s);
break;
case SSPSP:
s->sspsp = value;
break;
case SSTO:
s->ssto = value;
break;
case SSITR:
s->ssitr = value & SSITR_INT;
pxa2xx_ssp_int_update(s);
break;
case SSSR:
s->sssr &= ~(value & SSSR_RW);
pxa2xx_ssp_int_update(s);
break;
case SSDR:
if (SSCR0_UWIRE(s->sscr[0])) {
if (s->sscr[1] & SSCR1_MWDS)
value &= 0xffff;
else
value &= 0xff;
} else
/* Note how 32bits overflow does no harm here */
value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
/* Data goes from here to the Tx FIFO and is shifted out from
* there directly to the slave, no need to buffer it.
*/
if (s->enable) {
uint32_t readval;
readval = ssi_transfer(s->bus, value);
if (s->rx_level < 0x10) {
s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
} else {
s->sssr |= SSSR_ROR;
}
}
pxa2xx_ssp_fifo_update(s);
break;
case SSTSA:
s->sstsa = value;
break;
case SSRSA:
s->ssrsa = value;
break;
case SSACD:
s->ssacd = value;
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
}
static CPUReadMemoryFunc * const pxa2xx_ssp_readfn[] = {
pxa2xx_ssp_read,
pxa2xx_ssp_read,
pxa2xx_ssp_read,
};
static CPUWriteMemoryFunc * const pxa2xx_ssp_writefn[] = {
pxa2xx_ssp_write,
pxa2xx_ssp_write,
pxa2xx_ssp_write,
};
static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
int i;
qemu_put_be32(f, s->enable);
qemu_put_be32s(f, &s->sscr[0]);
qemu_put_be32s(f, &s->sscr[1]);
qemu_put_be32s(f, &s->sspsp);
qemu_put_be32s(f, &s->ssto);
qemu_put_be32s(f, &s->ssitr);
qemu_put_be32s(f, &s->sssr);
qemu_put_8s(f, &s->sstsa);
qemu_put_8s(f, &s->ssrsa);
qemu_put_8s(f, &s->ssacd);
qemu_put_byte(f, s->rx_level);
for (i = 0; i < s->rx_level; i ++)
qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]);
}
static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
int i;
s->enable = qemu_get_be32(f);
qemu_get_be32s(f, &s->sscr[0]);
qemu_get_be32s(f, &s->sscr[1]);
qemu_get_be32s(f, &s->sspsp);
qemu_get_be32s(f, &s->ssto);
qemu_get_be32s(f, &s->ssitr);
qemu_get_be32s(f, &s->sssr);
qemu_get_8s(f, &s->sstsa);
qemu_get_8s(f, &s->ssrsa);
qemu_get_8s(f, &s->ssacd);
s->rx_level = qemu_get_byte(f);
s->rx_start = 0;
for (i = 0; i < s->rx_level; i ++)
s->rx_fifo[i] = qemu_get_byte(f);
return 0;
}
static int pxa2xx_ssp_init(SysBusDevice *dev)
{
int iomemtype;
PXA2xxSSPState *s = FROM_SYSBUS(PXA2xxSSPState, dev);
sysbus_init_irq(dev, &s->irq);
iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn,
pxa2xx_ssp_writefn, s,
DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0,
pxa2xx_ssp_save, pxa2xx_ssp_load, s);
s->bus = ssi_create_bus(&dev->qdev, "ssi");
return 0;
}
/* Real-Time Clock */
#define RCNR 0x00 /* RTC Counter register */
#define RTAR 0x04 /* RTC Alarm register */
#define RTSR 0x08 /* RTC Status register */
#define RTTR 0x0c /* RTC Timer Trim register */
#define RDCR 0x10 /* RTC Day Counter register */
#define RYCR 0x14 /* RTC Year Counter register */
#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */
#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */
#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */
#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */
#define SWCR 0x28 /* RTC Stopwatch Counter register */
#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */
#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */
#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */
#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */
static inline void pxa2xx_rtc_int_update(PXA2xxState *s)
{
qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553));
}
static void pxa2xx_rtc_hzupdate(PXA2xxState *s)
{
int64_t rt = qemu_get_clock(rt_clock);
s->last_rcnr += ((rt - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
s->last_rdcr += ((rt - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
s->last_hz = rt;
}
static void pxa2xx_rtc_swupdate(PXA2xxState *s)
{
int64_t rt = qemu_get_clock(rt_clock);
if (s->rtsr & (1 << 12))
s->last_swcr += (rt - s->last_sw) / 10;
s->last_sw = rt;
}
static void pxa2xx_rtc_piupdate(PXA2xxState *s)
{
int64_t rt = qemu_get_clock(rt_clock);
if (s->rtsr & (1 << 15))
s->last_swcr += rt - s->last_pi;
s->last_pi = rt;
}
static inline void pxa2xx_rtc_alarm_update(PXA2xxState *s,
uint32_t rtsr)
{
if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
qemu_mod_timer(s->rtc_hz, s->last_hz +
(((s->rtar - s->last_rcnr) * 1000 *
((s->rttr & 0xffff) + 1)) >> 15));
else
qemu_del_timer(s->rtc_hz);
if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
qemu_mod_timer(s->rtc_rdal1, s->last_hz +
(((s->rdar1 - s->last_rdcr) * 1000 *
((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
else
qemu_del_timer(s->rtc_rdal1);
if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
qemu_mod_timer(s->rtc_rdal2, s->last_hz +
(((s->rdar2 - s->last_rdcr) * 1000 *
((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
else
qemu_del_timer(s->rtc_rdal2);
if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
qemu_mod_timer(s->rtc_swal1, s->last_sw +
(s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
else
qemu_del_timer(s->rtc_swal1);
if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
qemu_mod_timer(s->rtc_swal2, s->last_sw +
(s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
else
qemu_del_timer(s->rtc_swal2);
if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
qemu_mod_timer(s->rtc_pi, s->last_pi +
(s->piar & 0xffff) - s->last_rtcpicr);
else
qemu_del_timer(s->rtc_pi);
}
static inline void pxa2xx_rtc_hz_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 0);
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 4);
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 6);
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static inline void pxa2xx_rtc_swal1_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 8);
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static inline void pxa2xx_rtc_swal2_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 10);
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static inline void pxa2xx_rtc_pi_tick(void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
s->rtsr |= (1 << 13);
pxa2xx_rtc_piupdate(s);
s->last_rtcpicr = 0;
pxa2xx_rtc_alarm_update(s, s->rtsr);
pxa2xx_rtc_int_update(s);
}
static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case RTTR:
return s->rttr;
case RTSR:
return s->rtsr;
case RTAR:
return s->rtar;
case RDAR1:
return s->rdar1;
case RDAR2:
return s->rdar2;
case RYAR1:
return s->ryar1;
case RYAR2:
return s->ryar2;
case SWAR1:
return s->swar1;
case SWAR2:
return s->swar2;
case PIAR:
return s->piar;
case RCNR:
return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
case RDCR:
return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1));
case RYCR:
return s->last_rycr;
case SWCR:
if (s->rtsr & (1 << 12))
return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
else
return s->last_swcr;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxState *s = (PXA2xxState *) opaque;
switch (addr) {
case RTTR:
if (!(s->rttr & (1 << 31))) {
pxa2xx_rtc_hzupdate(s);
s->rttr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
}
break;
case RTSR:
if ((s->rtsr ^ value) & (1 << 15))
pxa2xx_rtc_piupdate(s);
if ((s->rtsr ^ value) & (1 << 12))
pxa2xx_rtc_swupdate(s);
if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
pxa2xx_rtc_alarm_update(s, value);
s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
pxa2xx_rtc_int_update(s);
break;
case RTAR:
s->rtar = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RDAR1:
s->rdar1 = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RDAR2:
s->rdar2 = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RYAR1:
s->ryar1 = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RYAR2:
s->ryar2 = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case SWAR1:
pxa2xx_rtc_swupdate(s);
s->swar1 = value;
s->last_swcr = 0;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case SWAR2:
s->swar2 = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case PIAR:
s->piar = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RCNR:
pxa2xx_rtc_hzupdate(s);
s->last_rcnr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RDCR:
pxa2xx_rtc_hzupdate(s);
s->last_rdcr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RYCR:
s->last_rycr = value;
break;
case SWCR:
pxa2xx_rtc_swupdate(s);
s->last_swcr = value;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
case RTCPICR:
pxa2xx_rtc_piupdate(s);
s->last_rtcpicr = value & 0xffff;
pxa2xx_rtc_alarm_update(s, s->rtsr);
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
}
}
static CPUReadMemoryFunc * const pxa2xx_rtc_readfn[] = {
pxa2xx_rtc_read,
pxa2xx_rtc_read,
pxa2xx_rtc_read,
};
static CPUWriteMemoryFunc * const pxa2xx_rtc_writefn[] = {
pxa2xx_rtc_write,
pxa2xx_rtc_write,
pxa2xx_rtc_write,
};
static void pxa2xx_rtc_init(PXA2xxState *s)
{
struct tm tm;
int wom;
s->rttr = 0x7fff;
s->rtsr = 0;
qemu_get_timedate(&tm, 0);
wom = ((tm.tm_mday - 1) / 7) + 1;
s->last_rcnr = (uint32_t) mktimegm(&tm);
s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
(tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
s->last_rycr = ((tm.tm_year + 1900) << 9) |
((tm.tm_mon + 1) << 5) | tm.tm_mday;
s->last_swcr = (tm.tm_hour << 19) |
(tm.tm_min << 13) | (tm.tm_sec << 7);
s->last_rtcpicr = 0;
s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
s->rtc_hz = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick, s);
s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
s->rtc_pi = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick, s);
}
static void pxa2xx_rtc_save(QEMUFile *f, void *opaque)
{
PXA2xxState *s = (PXA2xxState *) opaque;
pxa2xx_rtc_hzupdate(s);
pxa2xx_rtc_piupdate(s);
pxa2xx_rtc_swupdate(s);
qemu_put_be32s(f, &s->rttr);
qemu_put_be32s(f, &s->rtsr);
qemu_put_be32s(f, &s->rtar);
qemu_put_be32s(f, &s->rdar1);
qemu_put_be32s(f, &s->rdar2);
qemu_put_be32s(f, &s->ryar1);
qemu_put_be32s(f, &s->ryar2);
qemu_put_be32s(f, &s->swar1);
qemu_put_be32s(f, &s->swar2);
qemu_put_be32s(f, &s->piar);
qemu_put_be32s(f, &s->last_rcnr);
qemu_put_be32s(f, &s->last_rdcr);
qemu_put_be32s(f, &s->last_rycr);
qemu_put_be32s(f, &s->last_swcr);
qemu_put_be32s(f, &s->last_rtcpicr);
qemu_put_sbe64s(f, &s->last_hz);
qemu_put_sbe64s(f, &s->last_sw);
qemu_put_sbe64s(f, &s->last_pi);
}
static int pxa2xx_rtc_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxState *s = (PXA2xxState *) opaque;
qemu_get_be32s(f, &s->rttr);
qemu_get_be32s(f, &s->rtsr);
qemu_get_be32s(f, &s->rtar);
qemu_get_be32s(f, &s->rdar1);
qemu_get_be32s(f, &s->rdar2);
qemu_get_be32s(f, &s->ryar1);
qemu_get_be32s(f, &s->ryar2);
qemu_get_be32s(f, &s->swar1);
qemu_get_be32s(f, &s->swar2);
qemu_get_be32s(f, &s->piar);
qemu_get_be32s(f, &s->last_rcnr);
qemu_get_be32s(f, &s->last_rdcr);
qemu_get_be32s(f, &s->last_rycr);
qemu_get_be32s(f, &s->last_swcr);
qemu_get_be32s(f, &s->last_rtcpicr);
qemu_get_sbe64s(f, &s->last_hz);
qemu_get_sbe64s(f, &s->last_sw);
qemu_get_sbe64s(f, &s->last_pi);
pxa2xx_rtc_alarm_update(s, s->rtsr);
return 0;
}
/* I2C Interface */
typedef struct {
i2c_slave i2c;
PXA2xxI2CState *host;
} PXA2xxI2CSlaveState;
struct PXA2xxI2CState {
PXA2xxI2CSlaveState *slave;
i2c_bus *bus;
qemu_irq irq;
target_phys_addr_t offset;
uint16_t control;
uint16_t status;
uint8_t ibmr;
uint8_t data;
};
#define IBMR 0x80 /* I2C Bus Monitor register */
#define IDBR 0x88 /* I2C Data Buffer register */
#define ICR 0x90 /* I2C Control register */
#define ISR 0x98 /* I2C Status register */
#define ISAR 0xa0 /* I2C Slave Address register */
static void pxa2xx_i2c_update(PXA2xxI2CState *s)
{
uint16_t level = 0;
level |= s->status & s->control & (1 << 10); /* BED */
level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
level |= s->status & (1 << 9); /* SAD */
qemu_set_irq(s->irq, !!level);
}
/* These are only stubs now. */
static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
switch (event) {
case I2C_START_SEND:
s->status |= (1 << 9); /* set SAD */
s->status &= ~(1 << 0); /* clear RWM */
break;
case I2C_START_RECV:
s->status |= (1 << 9); /* set SAD */
s->status |= 1 << 0; /* set RWM */
break;
case I2C_FINISH:
s->status |= (1 << 4); /* set SSD */
break;
case I2C_NACK:
s->status |= 1 << 1; /* set ACKNAK */
break;
}
pxa2xx_i2c_update(s);
}
static int pxa2xx_i2c_rx(i2c_slave *i2c)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
return 0;
if (s->status & (1 << 0)) { /* RWM */
s->status |= 1 << 6; /* set ITE */
}
pxa2xx_i2c_update(s);
return s->data;
}
static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
return 1;
if (!(s->status & (1 << 0))) { /* RWM */
s->status |= 1 << 7; /* set IRF */
s->data = data;
}
pxa2xx_i2c_update(s);
return 1;
}
static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
addr -= s->offset;
switch (addr) {
case ICR:
return s->control;
case ISR:
return s->status | (i2c_bus_busy(s->bus) << 2);
case ISAR:
return s->slave->i2c.address;
case IDBR:
return s->data;
case IBMR:
if (s->status & (1 << 2))
s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
else
s->ibmr = 0;
return s->ibmr;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
int ack;
addr -= s->offset;
switch (addr) {
case ICR:
s->control = value & 0xfff7;
if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
/* TODO: slave mode */
if (value & (1 << 0)) { /* START condition */
if (s->data & 1)
s->status |= 1 << 0; /* set RWM */
else
s->status &= ~(1 << 0); /* clear RWM */
ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
} else {
if (s->status & (1 << 0)) { /* RWM */
s->data = i2c_recv(s->bus);
if (value & (1 << 2)) /* ACKNAK */
i2c_nack(s->bus);
ack = 1;
} else
ack = !i2c_send(s->bus, s->data);
}
if (value & (1 << 1)) /* STOP condition */
i2c_end_transfer(s->bus);
if (ack) {
if (value & (1 << 0)) /* START condition */
s->status |= 1 << 6; /* set ITE */
else
if (s->status & (1 << 0)) /* RWM */
s->status |= 1 << 7; /* set IRF */
else
s->status |= 1 << 6; /* set ITE */
s->status &= ~(1 << 1); /* clear ACKNAK */
} else {
s->status |= 1 << 6; /* set ITE */
s->status |= 1 << 10; /* set BED */
s->status |= 1 << 1; /* set ACKNAK */
}
}
if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
if (value & (1 << 4)) /* MA */
i2c_end_transfer(s->bus);
pxa2xx_i2c_update(s);
break;
case ISR:
s->status &= ~(value & 0x07f0);
pxa2xx_i2c_update(s);
break;
case ISAR:
i2c_set_slave_address(&s->slave->i2c, value & 0x7f);
break;
case IDBR:
s->data = value & 0xff;
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
}
}
static CPUReadMemoryFunc * const pxa2xx_i2c_readfn[] = {
pxa2xx_i2c_read,
pxa2xx_i2c_read,
pxa2xx_i2c_read,
};
static CPUWriteMemoryFunc * const pxa2xx_i2c_writefn[] = {
pxa2xx_i2c_write,
pxa2xx_i2c_write,
pxa2xx_i2c_write,
};
static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
.name = "pxa2xx_i2c_slave",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_I2C_SLAVE(i2c, PXA2xxI2CSlaveState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_pxa2xx_i2c = {
.name = "pxa2xx_i2c",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT16(control, PXA2xxI2CState),
VMSTATE_UINT16(status, PXA2xxI2CState),
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
VMSTATE_UINT8(data, PXA2xxI2CState),
VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
vmstate_pxa2xx_i2c, PXA2xxI2CSlaveState *),
VMSTATE_END_OF_LIST()
}
};
static int pxa2xx_i2c_slave_init(i2c_slave *i2c)
{
/* Nothing to do. */
return 0;
}
static I2CSlaveInfo pxa2xx_i2c_slave_info = {
.qdev.name = "pxa2xx-i2c-slave",
.qdev.size = sizeof(PXA2xxI2CSlaveState),
.init = pxa2xx_i2c_slave_init,
.event = pxa2xx_i2c_event,
.recv = pxa2xx_i2c_rx,
.send = pxa2xx_i2c_tx
};
PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
qemu_irq irq, uint32_t region_size)
{
int iomemtype;
DeviceState *dev;
PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState));
/* FIXME: Should the slave device really be on a separate bus? */
dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0);
s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev));
s->slave->host = s;
s->irq = irq;
s->bus = i2c_init_bus(NULL, "i2c");
s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn,
pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(base & ~region_size,
region_size + 1, iomemtype);
vmstate_register(NULL, base, &vmstate_pxa2xx_i2c, s);
return s;
}
i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
{
return s->bus;
}
/* PXA Inter-IC Sound Controller */
static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
{
i2s->rx_len = 0;
i2s->tx_len = 0;
i2s->fifo_len = 0;
i2s->clk = 0x1a;
i2s->control[0] = 0x00;
i2s->control[1] = 0x00;
i2s->status = 0x00;
i2s->mask = 0x00;
}
#define SACR_TFTH(val) ((val >> 8) & 0xf)
#define SACR_RFTH(val) ((val >> 12) & 0xf)
#define SACR_DREC(val) (val & (1 << 3))
#define SACR_DPRL(val) (val & (1 << 4))
static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
{
int rfs, tfs;
rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
!SACR_DREC(i2s->control[1]);
tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
i2s->enable && !SACR_DPRL(i2s->control[1]);
pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
i2s->status &= 0xe0;
if (i2s->fifo_len < 16 || !i2s->enable)
i2s->status |= 1 << 0; /* TNF */
if (i2s->rx_len)
i2s->status |= 1 << 1; /* RNE */
if (i2s->enable)
i2s->status |= 1 << 2; /* BSY */
if (tfs)
i2s->status |= 1 << 3; /* TFS */
if (rfs)
i2s->status |= 1 << 4; /* RFS */
if (!(i2s->tx_len && i2s->enable))
i2s->status |= i2s->fifo_len << 8; /* TFL */
i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
}
#define SACR0 0x00 /* Serial Audio Global Control register */
#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */
#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */
#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */
#define SAICR 0x18 /* Serial Audio Interrupt Clear register */
#define SADIV 0x60 /* Serial Audio Clock Divider register */
#define SADR 0x80 /* Serial Audio Data register */
static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
switch (addr) {
case SACR0:
return s->control[0];
case SACR1:
return s->control[1];
case SASR0:
return s->status;
case SAIMR:
return s->mask;
case SAICR:
return 0;
case SADIV:
return s->clk;
case SADR:
if (s->rx_len > 0) {
s->rx_len --;
pxa2xx_i2s_update(s);
return s->codec_in(s->opaque);
}
return 0;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
uint32_t *sample;
switch (addr) {
case SACR0:
if (value & (1 << 3)) /* RST */
pxa2xx_i2s_reset(s);
s->control[0] = value & 0xff3d;
if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
s->codec_out(s->opaque, *sample);
s->status &= ~(1 << 7); /* I2SOFF */
}
if (value & (1 << 4)) /* EFWR */
printf("%s: Attempt to use special function\n", __FUNCTION__);
s->enable = ((value ^ 4) & 5) == 5; /* ENB && !RST*/
pxa2xx_i2s_update(s);
break;
case SACR1:
s->control[1] = value & 0x0039;
if (value & (1 << 5)) /* ENLBF */
printf("%s: Attempt to use loopback function\n", __FUNCTION__);
if (value & (1 << 4)) /* DPRL */
s->fifo_len = 0;
pxa2xx_i2s_update(s);
break;
case SAIMR:
s->mask = value & 0x0078;
pxa2xx_i2s_update(s);
break;
case SAICR:
s->status &= ~(value & (3 << 5));
pxa2xx_i2s_update(s);
break;
case SADIV:
s->clk = value & 0x007f;
break;
case SADR:
if (s->tx_len && s->enable) {
s->tx_len --;
pxa2xx_i2s_update(s);
s->codec_out(s->opaque, value);
} else if (s->fifo_len < 16) {
s->fifo[s->fifo_len ++] = value;
pxa2xx_i2s_update(s);
}
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
}
}
static CPUReadMemoryFunc * const pxa2xx_i2s_readfn[] = {
pxa2xx_i2s_read,
pxa2xx_i2s_read,
pxa2xx_i2s_read,
};
static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = {
pxa2xx_i2s_write,
pxa2xx_i2s_write,
pxa2xx_i2s_write,
};
static void pxa2xx_i2s_save(QEMUFile *f, void *opaque)
{
PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
qemu_put_be32s(f, &s->control[0]);
qemu_put_be32s(f, &s->control[1]);
qemu_put_be32s(f, &s->status);
qemu_put_be32s(f, &s->mask);
qemu_put_be32s(f, &s->clk);
qemu_put_be32(f, s->enable);
qemu_put_be32(f, s->rx_len);
qemu_put_be32(f, s->tx_len);
qemu_put_be32(f, s->fifo_len);
}
static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
qemu_get_be32s(f, &s->control[0]);
qemu_get_be32s(f, &s->control[1]);
qemu_get_be32s(f, &s->status);
qemu_get_be32s(f, &s->mask);
qemu_get_be32s(f, &s->clk);
s->enable = qemu_get_be32(f);
s->rx_len = qemu_get_be32(f);
s->tx_len = qemu_get_be32(f);
s->fifo_len = qemu_get_be32(f);
return 0;
}
static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
{
PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
uint32_t *sample;
/* Signal FIFO errors */
if (s->enable && s->tx_len)
s->status |= 1 << 5; /* TUR */
if (s->enable && s->rx_len)
s->status |= 1 << 6; /* ROR */
/* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
* handle the cases where it makes a difference. */
s->tx_len = tx - s->fifo_len;
s->rx_len = rx;
/* Note that is s->codec_out wasn't set, we wouldn't get called. */
if (s->enable)
for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
s->codec_out(s->opaque, *sample);
pxa2xx_i2s_update(s);
}
static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
qemu_irq irq, PXA2xxDMAState *dma)
{
int iomemtype;
PXA2xxI2SState *s = (PXA2xxI2SState *)
qemu_mallocz(sizeof(PXA2xxI2SState));
s->irq = irq;
s->dma = dma;
s->data_req = pxa2xx_i2s_data_req;
pxa2xx_i2s_reset(s);
iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn,
pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(base, 0x100000, iomemtype);
register_savevm(NULL, "pxa2xx_i2s", base, 0,
pxa2xx_i2s_save, pxa2xx_i2s_load, s);
return s;
}
/* PXA Fast Infra-red Communications Port */
struct PXA2xxFIrState {
qemu_irq irq;
PXA2xxDMAState *dma;
int enable;
CharDriverState *chr;
uint8_t control[3];
uint8_t status[2];
int rx_len;
int rx_start;
uint8_t rx_fifo[64];
};
static void pxa2xx_fir_reset(PXA2xxFIrState *s)
{
s->control[0] = 0x00;
s->control[1] = 0x00;
s->control[2] = 0x00;
s->status[0] = 0x00;
s->status[1] = 0x00;
s->enable = 0;
}
static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
{
static const int tresh[4] = { 8, 16, 32, 0 };
int intr = 0;
if ((s->control[0] & (1 << 4)) && /* RXE */
s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */
s->status[0] |= 1 << 4; /* RFS */
else
s->status[0] &= ~(1 << 4); /* RFS */
if (s->control[0] & (1 << 3)) /* TXE */
s->status[0] |= 1 << 3; /* TFS */
else
s->status[0] &= ~(1 << 3); /* TFS */
if (s->rx_len)
s->status[1] |= 1 << 2; /* RNE */
else
s->status[1] &= ~(1 << 2); /* RNE */
if (s->control[0] & (1 << 4)) /* RXE */
s->status[1] |= 1 << 0; /* RSY */
else
s->status[1] &= ~(1 << 0); /* RSY */
intr |= (s->control[0] & (1 << 5)) && /* RIE */
(s->status[0] & (1 << 4)); /* RFS */
intr |= (s->control[0] & (1 << 6)) && /* TIE */
(s->status[0] & (1 << 3)); /* TFS */
intr |= (s->control[2] & (1 << 4)) && /* TRAIL */
(s->status[0] & (1 << 6)); /* EOC */
intr |= (s->control[0] & (1 << 2)) && /* TUS */
(s->status[0] & (1 << 1)); /* TUR */
intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */
pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1);
pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1);
qemu_set_irq(s->irq, intr && s->enable);
}
#define ICCR0 0x00 /* FICP Control register 0 */
#define ICCR1 0x04 /* FICP Control register 1 */
#define ICCR2 0x08 /* FICP Control register 2 */
#define ICDR 0x0c /* FICP Data register */
#define ICSR0 0x14 /* FICP Status register 0 */
#define ICSR1 0x18 /* FICP Status register 1 */
#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */
static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
uint8_t ret;
switch (addr) {
case ICCR0:
return s->control[0];
case ICCR1:
return s->control[1];
case ICCR2:
return s->control[2];
case ICDR:
s->status[0] &= ~0x01;
s->status[1] &= ~0x72;
if (s->rx_len) {
s->rx_len --;
ret = s->rx_fifo[s->rx_start ++];
s->rx_start &= 63;
pxa2xx_fir_update(s);
return ret;
}
printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
break;
case ICSR0:
return s->status[0];
case ICSR1:
return s->status[1] | (1 << 3); /* TNF */
case ICFOR:
return s->rx_len;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
break;
}
return 0;
}
static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
uint8_t ch;
switch (addr) {
case ICCR0:
s->control[0] = value;
if (!(value & (1 << 4))) /* RXE */
s->rx_len = s->rx_start = 0;
if (!(value & (1 << 3))) { /* TXE */
/* Nop */
}
s->enable = value & 1; /* ITR */
if (!s->enable)
s->status[0] = 0;
pxa2xx_fir_update(s);
break;
case ICCR1:
s->control[1] = value;
break;
case ICCR2:
s->control[2] = value & 0x3f;
pxa2xx_fir_update(s);
break;
case ICDR:
if (s->control[2] & (1 << 2)) /* TXP */
ch = value;
else
ch = ~value;
if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
qemu_chr_write(s->chr, &ch, 1);
break;
case ICSR0:
s->status[0] &= ~(value & 0x66);
pxa2xx_fir_update(s);
break;
case ICFOR:
break;
default:
printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
}
}
static CPUReadMemoryFunc * const pxa2xx_fir_readfn[] = {
pxa2xx_fir_read,
pxa2xx_fir_read,
pxa2xx_fir_read,
};
static CPUWriteMemoryFunc * const pxa2xx_fir_writefn[] = {
pxa2xx_fir_write,
pxa2xx_fir_write,
pxa2xx_fir_write,
};
static int pxa2xx_fir_is_empty(void *opaque)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
return (s->rx_len < 64);
}
static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
if (!(s->control[0] & (1 << 4))) /* RXE */
return;
while (size --) {
s->status[1] |= 1 << 4; /* EOF */
if (s->rx_len >= 64) {
s->status[1] |= 1 << 6; /* ROR */
break;
}
if (s->control[2] & (1 << 3)) /* RXP */
s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
else
s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
}
pxa2xx_fir_update(s);
}
static void pxa2xx_fir_event(void *opaque, int event)
{
}
static void pxa2xx_fir_save(QEMUFile *f, void *opaque)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
int i;
qemu_put_be32(f, s->enable);
qemu_put_8s(f, &s->control[0]);
qemu_put_8s(f, &s->control[1]);
qemu_put_8s(f, &s->control[2]);
qemu_put_8s(f, &s->status[0]);
qemu_put_8s(f, &s->status[1]);
qemu_put_byte(f, s->rx_len);
for (i = 0; i < s->rx_len; i ++)
qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]);
}
static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
{
PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
int i;
s->enable = qemu_get_be32(f);
qemu_get_8s(f, &s->control[0]);
qemu_get_8s(f, &s->control[1]);
qemu_get_8s(f, &s->control[2]);
qemu_get_8s(f, &s->status[0]);
qemu_get_8s(f, &s->status[1]);
s->rx_len = qemu_get_byte(f);
s->rx_start = 0;
for (i = 0; i < s->rx_len; i ++)
s->rx_fifo[i] = qemu_get_byte(f);
return 0;
}
static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
qemu_irq irq, PXA2xxDMAState *dma,
CharDriverState *chr)
{
int iomemtype;
PXA2xxFIrState *s = (PXA2xxFIrState *)
qemu_mallocz(sizeof(PXA2xxFIrState));
s->irq = irq;
s->dma = dma;
s->chr = chr;
pxa2xx_fir_reset(s);
iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn,
pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(base, 0x1000, iomemtype);
if (chr)
qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
pxa2xx_fir_rx, pxa2xx_fir_event, s);
register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
pxa2xx_fir_load, s);
return s;
}
static void pxa2xx_reset(void *opaque, int line, int level)
{
PXA2xxState *s = (PXA2xxState *) opaque;
if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
cpu_reset(s->env);
/* TODO: reset peripherals */
}
}
/* Initialise a PXA270 integrated chip (ARM based core). */
PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
{
PXA2xxState *s;
int iomemtype, i;
DriveInfo *dinfo;
s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
if (revision && strncmp(revision, "pxa27", 5)) {
fprintf(stderr, "Machine requires a PXA27x processor.\n");
exit(1);
}
if (!revision)
revision = "pxa270";
s->env = cpu_init(revision);
if (!s->env) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
/* SDRAM & Internal Memory Storage */
cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
sdram_size, qemu_ram_alloc(NULL, "pxa270.sdram",
sdram_size) | IO_MEM_RAM);
cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
0x40000, qemu_ram_alloc(NULL, "pxa270.internal",
0x40000) | IO_MEM_RAM);
s->pic = pxa2xx_pic_init(0x40d00000, s->env);
s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0],
s->pic[PXA27X_PIC_OST_4_11]);
s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
dinfo = drive_get(IF_SD, 0, 0);
if (!dinfo) {
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
s->pic[PXA2XX_PIC_MMC], s->dma);
for (i = 0; pxa270_serial[i].io_base; i ++)
if (serial_hds[i])
#ifdef TARGET_WORDS_BIGENDIAN
serial_mm_init(pxa270_serial[i].io_base, 2,
s->pic[pxa270_serial[i].irqn], 14857000/16,
serial_hds[i], 1, 1);
#else
serial_mm_init(pxa270_serial[i].io_base, 2,
s->pic[pxa270_serial[i].irqn], 14857000/16,
serial_hds[i], 1, 0);
#endif
else
break;
if (serial_hds[i])
s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
s->dma, serial_hds[i]);
s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD]);
s->cm_base = 0x41300000;
s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
s->clkcfg = 0x00000009; /* Turbo mode active */
iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
s->mm_base = 0x48000000;
s->mm_regs[MDMRS >> 2] = 0x00020002;
s->mm_regs[MDREFR >> 2] = 0x03ca4000;
s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
s->pm_base = 0x40f00000;
iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
for (i = 0; pxa27x_ssp[i].io_base; i ++);
s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
for (i = 0; pxa27x_ssp[i].io_base; i ++) {
DeviceState *dev;
dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
s->pic[pxa27x_ssp[i].irqn]);
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
if (usb_enabled) {
sysbus_create_simple("sysbus-ohci", 0x4c000000,
s->pic[PXA2XX_PIC_USBH1]);
}
s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
s->rtc_base = 0x40900000;
iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
pxa2xx_rtc_init(s);
register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
pxa2xx_rtc_load, s);
s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
s->kp = pxa27x_keypad_init(0x41500000, s->pic[PXA2XX_PIC_KEYPAD]);
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
return s;
}
/* Initialise a PXA255 integrated chip (ARM based core). */
PXA2xxState *pxa255_init(unsigned int sdram_size)
{
PXA2xxState *s;
int iomemtype, i;
DriveInfo *dinfo;
s = (PXA2xxState *) qemu_mallocz(sizeof(PXA2xxState));
s->env = cpu_init("pxa255");
if (!s->env) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0];
/* SDRAM & Internal Memory Storage */
cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size,
qemu_ram_alloc(NULL, "pxa255.sdram",
sdram_size) | IO_MEM_RAM);
cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE,
qemu_ram_alloc(NULL, "pxa255.internal",
PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM);
s->pic = pxa2xx_pic_init(0x40d00000, s->env);
s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0]);
s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
dinfo = drive_get(IF_SD, 0, 0);
if (!dinfo) {
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = pxa2xx_mmci_init(0x41100000, dinfo->bdrv,
s->pic[PXA2XX_PIC_MMC], s->dma);
for (i = 0; pxa255_serial[i].io_base; i ++)
if (serial_hds[i]) {
#ifdef TARGET_WORDS_BIGENDIAN
serial_mm_init(pxa255_serial[i].io_base, 2,
s->pic[pxa255_serial[i].irqn], 14745600/16,
serial_hds[i], 1, 1);
#else
serial_mm_init(pxa255_serial[i].io_base, 2,
s->pic[pxa255_serial[i].irqn], 14745600/16,
serial_hds[i], 1, 0);
#endif
} else {
break;
}
if (serial_hds[i])
s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
s->dma, serial_hds[i]);
s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD]);
s->cm_base = 0x41300000;
s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
s->clkcfg = 0x00000009; /* Turbo mode active */
iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
s->mm_base = 0x48000000;
s->mm_regs[MDMRS >> 2] = 0x00020002;
s->mm_regs[MDREFR >> 2] = 0x03ca4000;
s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
s->pm_base = 0x40f00000;
iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
for (i = 0; pxa255_ssp[i].io_base; i ++);
s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i);
for (i = 0; pxa255_ssp[i].io_base; i ++) {
DeviceState *dev;
dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
s->pic[pxa255_ssp[i].irqn]);
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
if (usb_enabled) {
sysbus_create_simple("sysbus-ohci", 0x4c000000,
s->pic[PXA2XX_PIC_USBH1]);
}
s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
s->rtc_base = 0x40900000;
iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
pxa2xx_rtc_init(s);
register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
pxa2xx_rtc_load, s);
s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
return s;
}
static void pxa2xx_register_devices(void)
{
i2c_register_slave(&pxa2xx_i2c_slave_info);
sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
}
device_init(pxa2xx_register_devices)