?? pxa2xx.c
字號(hào):
/* * 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 "hw.h"#include "pxa.h"#include "sysemu.h"#include "pc.h"#include "i2c.h"#include "qemu-timer.h"#include "qemu-char.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 0static PXASSPDef pxa250_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0, 0 }};#endifstatic PXASSPDef pxa255_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0x41400000, PXA25X_PIC_NSSP }, { 0, 0 }};#if 0static PXASSPDef pxa26x_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0x41400000, PXA25X_PIC_NSSP }, { 0x41500000, PXA26X_PIC_ASSP }, { 0, 0 }};#endifstatic 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; addr -= s->pm_base; 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; addr -= s->pm_base; 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 >= PMCR && addr <= PCMD31 && !(addr & 3)) { s->pm_regs[addr >> 2] = value; break; } printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); break; }}static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = { pxa2xx_pm_read, pxa2xx_pm_read, pxa2xx_pm_read,};static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = { pxa2xx_pm_write, pxa2xx_pm_write, pxa2xx_pm_write,};static void pxa2xx_pm_save(QEMUFile *f, void *opaque){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; addr -= s->cm_base; 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; addr -= s->cm_base; 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 *pxa2xx_cm_readfn[] = { pxa2xx_cm_read, pxa2xx_cm_read, pxa2xx_cm_read,};static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = { pxa2xx_cm_write, pxa2xx_cm_write, pxa2xx_cm_write,};static void pxa2xx_cm_save(QEMUFile *f, void *opaque){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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){ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) 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:
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -