提交 c1713132 编写于 作者: B balrog

Core features of ARM XScale processors. Main PXA270 and PXA255 peripherals.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2749 c046a42c-6fe2-441c-8c8c-71466251a162
上级 201a51fc
/*
* 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.
*/
#ifndef PXA_H
# define PXA_H "pxa.h"
/* Interrupt numbers */
# define PXA2XX_PIC_SSP3 0
# define PXA2XX_PIC_USBH2 2
# define PXA2XX_PIC_USBH1 3
# define PXA2XX_PIC_PWRI2C 6
# define PXA25X_PIC_HWUART 7
# define PXA27X_PIC_OST_4_11 7
# define PXA2XX_PIC_GPIO_0 8
# define PXA2XX_PIC_GPIO_1 9
# define PXA2XX_PIC_GPIO_X 10
# define PXA2XX_PIC_I2S 13
# define PXA26X_PIC_ASSP 15
# define PXA25X_PIC_NSSP 16
# define PXA27X_PIC_SSP2 16
# define PXA2XX_PIC_LCD 17
# define PXA2XX_PIC_I2C 18
# define PXA2XX_PIC_ICP 19
# define PXA2XX_PIC_STUART 20
# define PXA2XX_PIC_BTUART 21
# define PXA2XX_PIC_FFUART 22
# define PXA2XX_PIC_MMC 23
# define PXA2XX_PIC_SSP 24
# define PXA2XX_PIC_DMA 25
# define PXA2XX_PIC_OST_0 26
# define PXA2XX_PIC_RTC1HZ 30
# define PXA2XX_PIC_RTCALARM 31
/* DMA requests */
# define PXA2XX_RX_RQ_I2S 2
# define PXA2XX_TX_RQ_I2S 3
# define PXA2XX_RX_RQ_BTUART 4
# define PXA2XX_TX_RQ_BTUART 5
# define PXA2XX_RX_RQ_FFUART 6
# define PXA2XX_TX_RQ_FFUART 7
# define PXA2XX_RX_RQ_SSP1 13
# define PXA2XX_TX_RQ_SSP1 14
# define PXA2XX_RX_RQ_SSP2 15
# define PXA2XX_TX_RQ_SSP2 16
# define PXA2XX_RX_RQ_ICP 17
# define PXA2XX_TX_RQ_ICP 18
# define PXA2XX_RX_RQ_STUART 19
# define PXA2XX_TX_RQ_STUART 20
# define PXA2XX_RX_RQ_MMCI 21
# define PXA2XX_TX_RQ_MMCI 22
# define PXA2XX_USB_RQ(x) ((x) + 24)
# define PXA2XX_RX_RQ_SSP3 66
# define PXA2XX_TX_RQ_SSP3 67
# define PXA2XX_RAM_BASE 0xa0000000
/* pxa2xx_pic.c */
struct pxa2xx_pic_state_s;
qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
/* pxa2xx_gpio.c */
struct pxa2xx_gpio_info_s;
struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
CPUState *env, qemu_irq *pic, int lines);
void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level);
void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
gpio_handler_t handler, void *opaque);
void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
void (*handler)(void *opaque), void *opaque);
/* pxa2xx_dma.c */
struct pxa2xx_dma_state_s;
struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
qemu_irq irq);
struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
qemu_irq irq);
void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
/* pxa2xx.c */
struct pxa2xx_ssp_s;
void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
uint32_t (*readfn)(void *opaque),
void (*writefn)(void *opaque, uint32_t value), void *opaque);
struct pxa2xx_i2s_s;
struct pxa2xx_fir_s;
struct pxa2xx_state_s {
CPUState *env;
qemu_irq *pic;
struct pxa2xx_dma_state_s *dma;
struct pxa2xx_gpio_info_s *gpio;
struct pxa2xx_ssp_s **ssp;
struct pxa2xx_i2s_s *i2s;
struct pxa2xx_fir_s *fir;
/* Power management */
target_phys_addr_t pm_base;
uint32_t pm_regs[0x40];
/* Clock management */
target_phys_addr_t cm_base;
uint32_t cm_regs[4];
uint32_t clkcfg;
/* Memory management */
target_phys_addr_t mm_base;
uint32_t mm_regs[0x1a];
/* Performance monitoring */
uint32_t pmnc;
/* Real-Time clock */
target_phys_addr_t rtc_base;
uint32_t rttr;
uint32_t rtsr;
uint32_t rtar;
uint32_t rdar1;
uint32_t rdar2;
uint32_t ryar1;
uint32_t ryar2;
uint32_t swar1;
uint32_t swar2;
uint32_t piar;
uint32_t last_rcnr;
uint32_t last_rdcr;
uint32_t last_rycr;
uint32_t last_swcr;
uint32_t last_rtcpicr;
int64_t last_hz;
int64_t last_sw;
int64_t last_pi;
QEMUTimer *rtc_hz;
QEMUTimer *rtc_rdal1;
QEMUTimer *rtc_rdal2;
QEMUTimer *rtc_swal1;
QEMUTimer *rtc_swal2;
QEMUTimer *rtc_pi;
};
struct pxa2xx_i2s_s {
target_phys_addr_t base;
qemu_irq irq;
struct pxa2xx_dma_state_s *dma;
void (*data_req)(void *, int, int);
uint32_t control[2];
uint32_t status;
uint32_t mask;
uint32_t clk;
int enable;
int rx_len;
int tx_len;
void (*codec_out)(void *, uint32_t);
uint32_t (*codec_in)(void *);
void *opaque;
int fifo_len;
uint32_t fifo[16];
};
# define PA_FMT "0x%08lx"
# define REG_FMT "0x%lx"
struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision);
struct pxa2xx_state_s *pxa255_init(DisplayState *ds);
void pxa2xx_reset(int line, int level, void *opaque);
#endif /* PXA_H */
此差异已折叠。
/*
* Intel XScale PXA255/270 DMA controller.
*
* Copyright (c) 2006 Openedhand Ltd.
* Copyright (c) 2006 Thorsten Zitterell
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
* This code is licenced under the GPL.
*/
#include "vl.h"
struct pxa2xx_dma_channel_s {
target_phys_addr_t descr;
target_phys_addr_t src;
target_phys_addr_t dest;
uint32_t cmd;
uint32_t state;
int request;
};
/* Allow the DMA to be used as a PIC. */
typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
struct pxa2xx_dma_state_s {
pxa2xx_dma_handler_t handler;
target_phys_addr_t base;
qemu_irq irq;
uint32_t stopintr;
uint32_t eorintr;
uint32_t rasintr;
uint32_t startintr;
uint32_t endintr;
uint32_t align;
uint32_t pio;
int channels;
struct pxa2xx_dma_channel_s *chan;
uint8_t *req;
/* Flag to avoid recursive DMA invocations. */
int running;
};
#define PXA255_DMA_NUM_CHANNELS 16
#define PXA27X_DMA_NUM_CHANNELS 32
#define PXA2XX_DMA_NUM_REQUESTS 75
#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
#define DALGN 0x00a0 /* DMA Alignment register */
#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
#define DINT 0x00f0 /* DMA Interrupt register */
#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
#define D_CH0 0x0200 /* Channel 0 Descriptor start */
#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
/* Per-channel register */
#define DDADR 0x00
#define DSADR 0x01
#define DTADR 0x02
#define DCMD 0x03
/* Bit-field masks */
#define DRCMR_CHLNUM 0x1f
#define DRCMR_MAPVLD (1 << 7)
#define DDADR_STOP (1 << 0)
#define DDADR_BREN (1 << 1)
#define DCMD_LEN 0x1fff
#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1))
#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3))
#define DCMD_FLYBYT (1 << 19)
#define DCMD_FLYBYS (1 << 20)
#define DCMD_ENDIRQEN (1 << 21)
#define DCMD_STARTIRQEN (1 << 22)
#define DCMD_CMPEN (1 << 25)
#define DCMD_FLOWTRG (1 << 28)
#define DCMD_FLOWSRC (1 << 29)
#define DCMD_INCTRGADDR (1 << 30)
#define DCMD_INCSRCADDR (1 << 31)
#define DCSR_BUSERRINTR (1 << 0)
#define DCSR_STARTINTR (1 << 1)
#define DCSR_ENDINTR (1 << 2)
#define DCSR_STOPINTR (1 << 3)
#define DCSR_RASINTR (1 << 4)
#define DCSR_REQPEND (1 << 8)
#define DCSR_EORINT (1 << 9)
#define DCSR_CMPST (1 << 10)
#define DCSR_MASKRUN (1 << 22)
#define DCSR_RASIRQEN (1 << 23)
#define DCSR_CLRCMPST (1 << 24)
#define DCSR_SETCMPST (1 << 25)
#define DCSR_EORSTOPEN (1 << 26)
#define DCSR_EORJMPEN (1 << 27)
#define DCSR_EORIRQEN (1 << 28)
#define DCSR_STOPIRQEN (1 << 29)
#define DCSR_NODESCFETCH (1 << 30)
#define DCSR_RUN (1 << 31)
static inline void pxa2xx_dma_update(struct pxa2xx_dma_state_s *s, int ch)
{
if (ch >= 0) {
if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
(s->chan[ch].state & DCSR_STOPINTR))
s->stopintr |= 1 << ch;
else
s->stopintr &= ~(1 << ch);
if ((s->chan[ch].state & DCSR_EORIRQEN) &&
(s->chan[ch].state & DCSR_EORINT))
s->eorintr |= 1 << ch;
else
s->eorintr &= ~(1 << ch);
if ((s->chan[ch].state & DCSR_RASIRQEN) &&
(s->chan[ch].state & DCSR_RASINTR))
s->rasintr |= 1 << ch;
else
s->rasintr &= ~(1 << ch);
if (s->chan[ch].state & DCSR_STARTINTR)
s->startintr |= 1 << ch;
else
s->startintr &= ~(1 << ch);
if (s->chan[ch].state & DCSR_ENDINTR)
s->endintr |= 1 << ch;
else
s->endintr &= ~(1 << ch);
}
if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
qemu_irq_raise(s->irq);
else
qemu_irq_lower(s->irq);
}
static inline void pxa2xx_dma_descriptor_fetch(
struct pxa2xx_dma_state_s *s, int ch)
{
uint32_t desc[4];
target_phys_addr_t daddr = s->chan[ch].descr & ~0xf;
if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
daddr += 32;
cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
s->chan[ch].descr = desc[DDADR];
s->chan[ch].src = desc[DSADR];
s->chan[ch].dest = desc[DTADR];
s->chan[ch].cmd = desc[DCMD];
if (s->chan[ch].cmd & DCMD_FLOWSRC)
s->chan[ch].src &= ~3;
if (s->chan[ch].cmd & DCMD_FLOWTRG)
s->chan[ch].dest &= ~3;
if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
if (s->chan[ch].cmd & DCMD_STARTIRQEN)
s->chan[ch].state |= DCSR_STARTINTR;
}
static void pxa2xx_dma_run(struct pxa2xx_dma_state_s *s)
{
int c, srcinc, destinc;
uint32_t n, size;
uint32_t width;
uint32_t length;
char buffer[32];
struct pxa2xx_dma_channel_s *ch;
if (s->running ++)
return;
while (s->running) {
s->running = 1;
for (c = 0; c < s->channels; c ++) {
ch = &s->chan[c];
while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
/* Test for pending requests */
if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
break;
length = ch->cmd & DCMD_LEN;
size = DCMD_SIZE(ch->cmd);
width = DCMD_WIDTH(ch->cmd);
srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
while (length) {
size = MIN(length, size);
for (n = 0; n < size; n += width) {
cpu_physical_memory_read(ch->src, buffer + n, width);
ch->src += srcinc;
}
for (n = 0; n < size; n += width) {
cpu_physical_memory_write(ch->dest, buffer + n, width);
ch->dest += destinc;
}
length -= size;
if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
!ch->request) {
ch->state |= DCSR_EORINT;
if (ch->state & DCSR_EORSTOPEN)
ch->state |= DCSR_STOPINTR;
if ((ch->state & DCSR_EORJMPEN) &&
!(ch->state & DCSR_NODESCFETCH))
pxa2xx_dma_descriptor_fetch(s, c);
break;
}
}
ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
/* Is the transfer complete now? */
if (!length) {
if (ch->cmd & DCMD_ENDIRQEN)
ch->state |= DCSR_ENDINTR;
if ((ch->state & DCSR_NODESCFETCH) ||
(ch->descr & DDADR_STOP) ||
(ch->state & DCSR_EORSTOPEN)) {
ch->state |= DCSR_STOPINTR;
ch->state &= ~DCSR_RUN;
break;
}
ch->state |= DCSR_STOPINTR;
break;
}
}
}
s->running --;
}
}
static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset)
{
struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
unsigned int channel;
offset -= s->base;
switch (offset) {
case DRCMR64 ... DRCMR74:
offset -= DRCMR64 - DRCMR0 - (64 << 2);
/* Fall through */
case DRCMR0 ... DRCMR63:
channel = (offset - DRCMR0) >> 2;
return s->req[channel];
case DRQSR0:
case DRQSR1:
case DRQSR2:
return 0;
case DCSR0 ... DCSR31:
channel = offset >> 2;
if (s->chan[channel].request)
return s->chan[channel].state | DCSR_REQPEND;
return s->chan[channel].state;
case DINT:
return s->stopintr | s->eorintr | s->rasintr |
s->startintr | s->endintr;
case DALGN:
return s->align;
case DPCSR:
return s->pio;
}
if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
channel = (offset - D_CH0) >> 4;
switch ((offset & 0x0f) >> 2) {
case DDADR:
return s->chan[channel].descr;
case DSADR:
return s->chan[channel].src;
case DTADR:
return s->chan[channel].dest;
case DCMD:
return s->chan[channel].cmd;
}
}
cpu_abort(cpu_single_env,
"%s: Bad offset 0x%04lx\n", __FUNCTION__, offset);
return 7;
}
static void pxa2xx_dma_write(void *opaque,
target_phys_addr_t offset, uint32_t value)
{
struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
unsigned int channel;
offset -= s->base;
switch (offset) {
case DRCMR64 ... DRCMR74:
offset -= DRCMR64 - DRCMR0 - (64 << 2);
/* Fall through */
case DRCMR0 ... DRCMR63:
channel = (offset - DRCMR0) >> 2;
if (value & DRCMR_MAPVLD)
if ((value & DRCMR_CHLNUM) > s->channels)
cpu_abort(cpu_single_env, "%s: Bad DMA channel %i\n",
__FUNCTION__, value & DRCMR_CHLNUM);
s->req[channel] = value;
break;
case DRQSR0:
case DRQSR1:
case DRQSR2:
/* Nothing to do */
break;
case DCSR0 ... DCSR31:
channel = offset >> 2;
s->chan[channel].state &= 0x0000071f & ~(value &
(DCSR_EORINT | DCSR_ENDINTR |
DCSR_STARTINTR | DCSR_BUSERRINTR));
s->chan[channel].state |= value & 0xfc800000;
if (s->chan[channel].state & DCSR_STOPIRQEN)
s->chan[channel].state &= ~DCSR_STOPINTR;
if (value & DCSR_NODESCFETCH) {
/* No-descriptor-fetch mode */
if (value & DCSR_RUN)
pxa2xx_dma_run(s);
} else {
/* Descriptor-fetch mode */
if (value & DCSR_RUN) {
s->chan[channel].state &= ~DCSR_STOPINTR;
pxa2xx_dma_descriptor_fetch(s, channel);
pxa2xx_dma_run(s);
}
}
/* Shouldn't matter as our DMA is synchronous. */
if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
s->chan[channel].state |= DCSR_STOPINTR;
if (value & DCSR_CLRCMPST)
s->chan[channel].state &= ~DCSR_CMPST;
if (value & DCSR_SETCMPST)
s->chan[channel].state |= DCSR_CMPST;
pxa2xx_dma_update(s, channel);
break;
case DALGN:
s->align = value;
break;
case DPCSR:
s->pio = value & 0x80000001;
break;
default:
if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
channel = (offset - D_CH0) >> 4;
switch ((offset & 0x0f) >> 2) {
case DDADR:
s->chan[channel].descr = value;
break;
case DSADR:
s->chan[channel].src = value;
break;
case DTADR:
s->chan[channel].dest = value;
break;
case DCMD:
s->chan[channel].cmd = value;
break;
default:
goto fail;
}
break;
}
fail:
cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n",
__FUNCTION__, offset);
}
}
static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset)
{
cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
return 5;
}
static void pxa2xx_dma_writebad(void *opaque,
target_phys_addr_t offset, uint32_t value)
{
cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
}
static CPUReadMemoryFunc *pxa2xx_dma_readfn[] = {
pxa2xx_dma_readbad,
pxa2xx_dma_readbad,
pxa2xx_dma_read
};
static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = {
pxa2xx_dma_writebad,
pxa2xx_dma_writebad,
pxa2xx_dma_write
};
static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base,
qemu_irq irq, int channels)
{
int i, iomemtype;
struct pxa2xx_dma_state_s *s;
s = (struct pxa2xx_dma_state_s *)
qemu_mallocz(sizeof(struct pxa2xx_dma_state_s));
s->channels = channels;
s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels);
s->base = base;
s->irq = irq;
s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
s->req = qemu_mallocz(sizeof(int) * PXA2XX_DMA_NUM_REQUESTS);
memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels);
for (i = 0; i < s->channels; i ++)
s->chan[i].state = DCSR_STOPINTR;
memset(s->req, 0, sizeof(int) * PXA2XX_DMA_NUM_REQUESTS);
iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn,
pxa2xx_dma_writefn, s);
cpu_register_physical_memory(base, 0x0000ffff, iomemtype);
return s;
}
struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
qemu_irq irq)
{
return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
}
struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
qemu_irq irq)
{
return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
}
void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on)
{
int ch;
if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
cpu_abort(cpu_single_env,
"%s: Bad DMA request %i\n", __FUNCTION__, req_num);
if (!(s->req[req_num] & DRCMR_MAPVLD))
return;
ch = s->req[req_num] & DRCMR_CHLNUM;
if (!s->chan[ch].request && on)
s->chan[ch].state |= DCSR_RASINTR;
else
s->chan[ch].state &= ~DCSR_RASINTR;
if (s->chan[ch].request && !on)
s->chan[ch].state |= DCSR_EORINT;
s->chan[ch].request = on;
if (on) {
pxa2xx_dma_run(s);
pxa2xx_dma_update(s, ch);
}
}
/*
* Intel XScale PXA255/270 GPIO controller emulation.
*
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
* This code is licensed under the GPL.
*/
#include "vl.h"
#define PXA2XX_GPIO_BANKS 4
struct pxa2xx_gpio_info_s {
target_phys_addr_t base;
qemu_irq *pic;
int lines;
CPUState *cpu_env;
/* XXX: GNU C vectors are more suitable */
uint32_t ilevel[PXA2XX_GPIO_BANKS];
uint32_t olevel[PXA2XX_GPIO_BANKS];
uint32_t dir[PXA2XX_GPIO_BANKS];
uint32_t rising[PXA2XX_GPIO_BANKS];
uint32_t falling[PXA2XX_GPIO_BANKS];
uint32_t status[PXA2XX_GPIO_BANKS];
uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
uint32_t prev_level[PXA2XX_GPIO_BANKS];
struct {
gpio_handler_t fn;
void *opaque;
} handler[PXA2XX_GPIO_BANKS * 32];
void (*read_notify)(void *opaque);
void *opaque;
};
static struct {
enum {
GPIO_NONE,
GPLR,
GPSR,
GPCR,
GPDR,
GRER,
GFER,
GEDR,
GAFR_L,
GAFR_U,
} reg;
int bank;
} pxa2xx_gpio_regs[0x200] = {
[0 ... 0x1ff] = { GPIO_NONE, 0 },
#define PXA2XX_REG(reg, a0, a1, a2, a3) \
[a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
};
static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s)
{
if (s->status[0] & (1 << 0))
qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
else
qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
if (s->status[0] & (1 << 1))
qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
else
qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
else
qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
}
/* Bitmap of pins used as standby and sleep wake-up sources. */
const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
};
void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level)
{
int bank;
uint32_t mask;
if (line >= s->lines) {
printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
return;
}
bank = line >> 5;
mask = 1 << (line & 31);
if (level) {
s->status[bank] |= s->rising[bank] & mask &
~s->ilevel[bank] & ~s->dir[bank];
s->ilevel[bank] |= mask;
} else {
s->status[bank] |= s->falling[bank] & mask &
s->ilevel[bank] & ~s->dir[bank];
s->ilevel[bank] &= ~mask;
}
if (s->status[bank] & mask)
pxa2xx_gpio_irq_update(s);
/* Wake-up GPIOs */
if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank]))
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
}
static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) {
uint32_t level, diff;
int i, bit, line;
for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
level = s->olevel[i] & s->dir[i];
for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
bit = ffs(diff) - 1;
line = bit + 32 * i;
if (s->handler[line].fn)
s->handler[line].fn(line, (level >> bit) & 1,
s->handler[line].opaque);
}
s->prev_level[i] = level;
}
}
static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset)
{
struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
uint32_t ret;
int bank;
offset -= s->base;
if (offset >= 0x200)
return 0;
bank = pxa2xx_gpio_regs[offset].bank;
switch (pxa2xx_gpio_regs[offset].reg) {
case GPDR: /* GPIO Pin-Direction registers */
return s->dir[bank];
case GRER: /* GPIO Rising-Edge Detect Enable registers */
return s->rising[bank];
case GFER: /* GPIO Falling-Edge Detect Enable registers */
return s->falling[bank];
case GAFR_L: /* GPIO Alternate Function registers */
return s->gafr[bank * 2];
case GAFR_U: /* GPIO Alternate Function registers */
return s->gafr[bank * 2 + 1];
case GPLR: /* GPIO Pin-Level registers */
ret = (s->olevel[bank] & s->dir[bank]) |
(s->ilevel[bank] & ~s->dir[bank]);
if (s->read_notify)
s->read_notify(s->opaque);
return ret;
case GEDR: /* GPIO Edge Detect Status registers */
return s->status[bank];
default:
cpu_abort(cpu_single_env,
"%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
return 0;
}
static void pxa2xx_gpio_write(void *opaque,
target_phys_addr_t offset, uint32_t value)
{
struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
int bank;
offset -= s->base;
if (offset >= 0x200)
return;
bank = pxa2xx_gpio_regs[offset].bank;
switch (pxa2xx_gpio_regs[offset].reg) {
case GPDR: /* GPIO Pin-Direction registers */
s->dir[bank] = value;
pxa2xx_gpio_handler_update(s);
break;
case GPSR: /* GPIO Pin-Output Set registers */
s->olevel[bank] |= value;
pxa2xx_gpio_handler_update(s);
break;
case GPCR: /* GPIO Pin-Output Clear registers */
s->olevel[bank] &= ~value;
pxa2xx_gpio_handler_update(s);
break;
case GRER: /* GPIO Rising-Edge Detect Enable registers */
s->rising[bank] = value;
break;
case GFER: /* GPIO Falling-Edge Detect Enable registers */
s->falling[bank] = value;
break;
case GAFR_L: /* GPIO Alternate Function registers */
s->gafr[bank * 2] = value;
break;
case GAFR_U: /* GPIO Alternate Function registers */
s->gafr[bank * 2 + 1] = value;
break;
case GEDR: /* GPIO Edge Detect Status registers */
s->status[bank] &= ~value;
pxa2xx_gpio_irq_update(s);
break;
default:
cpu_abort(cpu_single_env,
"%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
}
static CPUReadMemoryFunc *pxa2xx_gpio_readfn[] = {
pxa2xx_gpio_read,
pxa2xx_gpio_read,
pxa2xx_gpio_read
};
static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = {
pxa2xx_gpio_write,
pxa2xx_gpio_write,
pxa2xx_gpio_write
};
struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
CPUState *env, qemu_irq *pic, int lines)
{
int iomemtype;
struct pxa2xx_gpio_info_s *s;
s = (struct pxa2xx_gpio_info_s *)
qemu_mallocz(sizeof(struct pxa2xx_gpio_info_s));
memset(s, 0, sizeof(struct pxa2xx_gpio_info_s));
s->base = base;
s->pic = pic;
s->lines = lines;
s->cpu_env = env;
iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn,
pxa2xx_gpio_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
return s;
}
void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
gpio_handler_t handler, void *opaque) {
if (line >= s->lines) {
printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
return;
}
s->handler[line].fn = handler;
s->handler[line].opaque = opaque;
}
/*
* Registers a callback to notify on GPLR reads. This normally
* shouldn't be needed but it is used for the hack on Spitz machines.
*/
void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
void (*handler)(void *opaque), void *opaque) {
s->read_notify = handler;
s->opaque = opaque;
}
/*
* Intel XScale PXA Programmable Interrupt Controller.
*
* Copyright (c) 2006 Openedhand Ltd.
* Copyright (c) 2006 Thorsten Zitterell
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
* This code is licenced under the GPL.
*/
#include "vl.h"
#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */
#define ICMR 0x04 /* Interrupt Controller Mask register */
#define ICLR 0x08 /* Interrupt Controller Level register */
#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */
#define ICPR 0x10 /* Interrupt Controller Pending register */
#define ICCR 0x14 /* Interrupt Controller Control register */
#define ICHP 0x18 /* Interrupt Controller Highest Priority register */
#define IPR0 0x1c /* Interrupt Controller Priority register 0 */
#define IPR31 0x98 /* Interrupt Controller Priority register 31 */
#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */
#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */
#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */
#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */
#define ICPR2 0xac /* Interrupt Controller Pending register 2 */
#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
#define PXA2XX_PIC_SRCS 40
struct pxa2xx_pic_state_s {
target_phys_addr_t base;
CPUState *cpu_env;
uint32_t int_enabled[2];
uint32_t int_pending[2];
uint32_t is_fiq[2];
uint32_t int_idle;
uint32_t priority[PXA2XX_PIC_SRCS];
};
static void pxa2xx_pic_update(void *opaque)
{
uint32_t mask[2];
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
if (s->cpu_env->halted) {
mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
if (mask[0] || mask[1])
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
}
mask[0] = s->int_pending[0] & s->int_enabled[0];
mask[1] = s->int_pending[1] & s->int_enabled[1];
if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1]))
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
else
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1]))
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
/* Note: Here level means state of the signal on a pin, not
* IRQ/FIQ distinction as in PXA Developer Manual. */
static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
{
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
int int_set = (irq >= 32);
irq &= 31;
if (level)
s->int_pending[int_set] |= 1 << irq;
else
s->int_pending[int_set] &= ~(1 << irq);
pxa2xx_pic_update(opaque);
}
static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) {
int i, int_set, irq;
uint32_t bit, mask[2];
uint32_t ichp = 0x003f003f; /* Both IDs invalid */
mask[0] = s->int_pending[0] & s->int_enabled[0];
mask[1] = s->int_pending[1] & s->int_enabled[1];
for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
irq = s->priority[i] & 0x3f;
if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
/* Source peripheral ID is valid. */
bit = 1 << (irq & 31);
int_set = (irq >= 32);
if (mask[int_set] & bit & s->is_fiq[int_set]) {
/* FIQ asserted */
ichp &= 0xffff0000;
ichp |= (1 << 15) | irq;
}
if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
/* IRQ asserted */
ichp &= 0x0000ffff;
ichp |= (1 << 31) | (irq << 16);
}
}
}
return ichp;
}
static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset)
{
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
offset -= s->base;
switch (offset) {
case ICIP: /* IRQ Pending register */
return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
case ICIP2: /* IRQ Pending register 2 */
return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
case ICMR: /* Mask register */
return s->int_enabled[0];
case ICMR2: /* Mask register 2 */
return s->int_enabled[1];
case ICLR: /* Level register */
return s->is_fiq[0];
case ICLR2: /* Level register 2 */
return s->is_fiq[1];
case ICCR: /* Idle mask */
return (s->int_idle == 0);
case ICFP: /* FIQ Pending register */
return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
case ICFP2: /* FIQ Pending register 2 */
return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
case ICPR: /* Pending register */
return s->int_pending[0];
case ICPR2: /* Pending register 2 */
return s->int_pending[1];
case IPR0 ... IPR31:
return s->priority[0 + ((offset - IPR0 ) >> 2)];
case IPR32 ... IPR39:
return s->priority[32 + ((offset - IPR32) >> 2)];
case ICHP: /* Highest Priority register */
return pxa2xx_pic_highest(s);
default:
printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
return 0;
}
}
static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
offset -= s->base;
switch (offset) {
case ICMR: /* Mask register */
s->int_enabled[0] = value;
break;
case ICMR2: /* Mask register 2 */
s->int_enabled[1] = value;
break;
case ICLR: /* Level register */
s->is_fiq[0] = value;
break;
case ICLR2: /* Level register 2 */
s->is_fiq[1] = value;
break;
case ICCR: /* Idle mask */
s->int_idle = (value & 1) ? 0 : ~0;
break;
case IPR0 ... IPR31:
s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
break;
case IPR32 ... IPR39:
s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
break;
default:
printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
return;
}
pxa2xx_pic_update(opaque);
}
/* Interrupt Controller Coprocessor Space Register Mapping */
static const int pxa2xx_cp_reg_map[0x10] = {
[0x0 ... 0xf] = -1,
[0x0] = ICIP,
[0x1] = ICMR,
[0x2] = ICLR,
[0x3] = ICFP,
[0x4] = ICPR,
[0x5] = ICHP,
[0x6] = ICIP2,
[0x7] = ICMR2,
[0x8] = ICLR2,
[0x9] = ICFP2,
[0xa] = ICPR2,
};
static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm)
{
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
target_phys_addr_t offset;
if (pxa2xx_cp_reg_map[reg] == -1) {
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
return 0;
}
offset = s->base + pxa2xx_cp_reg_map[reg];
return pxa2xx_pic_mem_read(opaque, offset);
}
static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm,
uint32_t value)
{
struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
target_phys_addr_t offset;
if (pxa2xx_cp_reg_map[reg] == -1) {
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
return;
}
offset = s->base + pxa2xx_cp_reg_map[reg];
pxa2xx_pic_mem_write(opaque, offset, value);
}
static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = {
pxa2xx_pic_mem_read,
pxa2xx_pic_mem_read,
pxa2xx_pic_mem_read,
};
static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = {
pxa2xx_pic_mem_write,
pxa2xx_pic_mem_write,
pxa2xx_pic_mem_write,
};
qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
{
struct pxa2xx_pic_state_s *s;
int iomemtype;
qemu_irq *qi;
s = (struct pxa2xx_pic_state_s *)
qemu_mallocz(sizeof(struct pxa2xx_pic_state_s));
if (!s)
return NULL;
s->cpu_env = env;
s->base = base;
s->int_pending[0] = 0;
s->int_pending[1] = 0;
s->int_enabled[0] = 0;
s->int_enabled[1] = 0;
s->is_fiq[0] = 0;
s->is_fiq[1] = 0;
qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
/* Enable IC memory-mapped registers access. */
iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn,
pxa2xx_pic_writefn, s);
cpu_register_physical_memory(base, 0x000fffff, iomemtype);
/* Enable IC coprocessor access. */
cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
return qi;
}
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
#define EXCP_FIQ 6 #define EXCP_FIQ 6
#define EXCP_BKPT 7 #define EXCP_BKPT 7
typedef void ARMWriteCPFunc(void *opaque, int cp_info,
int srcreg, int operand, uint32_t value);
typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
int dstreg, int operand);
/* We currently assume float and double are IEEE single and double /* We currently assume float and double are IEEE single and double
precision respectively. precision respectively.
Doing runtime conversions is tricky because VFP registers may contain Doing runtime conversions is tricky because VFP registers may contain
...@@ -75,6 +80,7 @@ typedef struct CPUARMState { ...@@ -75,6 +80,7 @@ typedef struct CPUARMState {
/* System control coprocessor (cp15) */ /* System control coprocessor (cp15) */
struct { struct {
uint32_t c0_cpuid; uint32_t c0_cpuid;
uint32_t c0_cachetype;
uint32_t c1_sys; /* System control register. */ uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c2; /* MMU translation table base. */ uint32_t c2; /* MMU translation table base. */
...@@ -87,8 +93,16 @@ typedef struct CPUARMState { ...@@ -87,8 +93,16 @@ typedef struct CPUARMState {
uint32_t c9_data; uint32_t c9_data;
uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_fcse; /* FCSE PID. */
uint32_t c13_context; /* Context ID. */ uint32_t c13_context; /* Context ID. */
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
} cp15; } cp15;
/* Coprocessor IO used by peripherals */
struct {
ARMReadCPFunc *cp_read;
ARMWriteCPFunc *cp_write;
void *opaque;
} cp[15];
/* Internal CPU feature flags. */ /* Internal CPU feature flags. */
uint32_t features; uint32_t features;
...@@ -204,10 +218,10 @@ enum arm_cpu_mode { ...@@ -204,10 +218,10 @@ enum arm_cpu_mode {
#define ARM_VFP_FPINST 9 #define ARM_VFP_FPINST 9
#define ARM_VFP_FPINST2 10 #define ARM_VFP_FPINST2 10
enum arm_features { enum arm_features {
ARM_FEATURE_VFP, ARM_FEATURE_VFP,
ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register. */ ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
}; };
static inline int arm_feature(CPUARMState *env, int feature) static inline int arm_feature(CPUARMState *env, int feature)
...@@ -218,8 +232,24 @@ static inline int arm_feature(CPUARMState *env, int feature) ...@@ -218,8 +232,24 @@ static inline int arm_feature(CPUARMState *env, int feature)
void arm_cpu_list(void); void arm_cpu_list(void);
void cpu_arm_set_model(CPUARMState *env, const char *name); void cpu_arm_set_model(CPUARMState *env, const char *name);
#define ARM_CPUID_ARM1026 0x4106a262 void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define ARM_CPUID_ARM926 0x41069265 ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
void *opaque);
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
#define ARM_CPUID_PXA250 0x69052100
#define ARM_CPUID_PXA255 0x69052d00
#define ARM_CPUID_PXA260 0x69052903
#define ARM_CPUID_PXA261 0x69052d05
#define ARM_CPUID_PXA262 0x69052d06
#define ARM_CPUID_PXA270 0x69054110
#define ARM_CPUID_PXA270_A0 0x69054110
#define ARM_CPUID_PXA270_A1 0x69054111
#define ARM_CPUID_PXA270_B0 0x69054112
#define ARM_CPUID_PXA270_B1 0x69054113
#define ARM_CPUID_PXA270_C0 0x69054114
#define ARM_CPUID_PXA270_C5 0x69054117
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
......
...@@ -54,6 +54,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ...@@ -54,6 +54,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
void cpu_lock(void); void cpu_lock(void);
void cpu_unlock(void); void cpu_unlock(void);
void helper_set_cp(CPUState *, uint32_t, uint32_t);
uint32_t helper_get_cp(CPUState *, uint32_t);
void helper_set_cp15(CPUState *, uint32_t, uint32_t); void helper_set_cp15(CPUState *, uint32_t, uint32_t);
uint32_t helper_get_cp15(CPUState *, uint32_t); uint32_t helper_get_cp15(CPUState *, uint32_t);
......
...@@ -17,11 +17,32 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) ...@@ -17,11 +17,32 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_ARM926: case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
env->cp15.c0_cachetype = 0x1dd20d2;
break; break;
case ARM_CPUID_ARM1026: case ARM_CPUID_ARM1026:
set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_VFP);
set_feature(env, ARM_FEATURE_AUXCR); set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_PXA250:
case ARM_CPUID_PXA255:
case ARM_CPUID_PXA260:
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->cp15.c0_cachetype = 0xd172172;
break;
case ARM_CPUID_PXA270_A0:
case ARM_CPUID_PXA270_A1:
case ARM_CPUID_PXA270_B0:
case ARM_CPUID_PXA270_B1:
case ARM_CPUID_PXA270_C0:
case ARM_CPUID_PXA270_C5:
set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->cp15.c0_cachetype = 0xd172172;
break; break;
default: default:
cpu_abort(env, "Bad CPU ID: %x\n", id); cpu_abort(env, "Bad CPU ID: %x\n", id);
...@@ -68,6 +89,18 @@ struct arm_cpu_t { ...@@ -68,6 +89,18 @@ struct arm_cpu_t {
static const struct arm_cpu_t arm_cpu_names[] = { static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_ARM926, "arm926"}, { ARM_CPUID_ARM926, "arm926"},
{ ARM_CPUID_ARM1026, "arm1026"}, { ARM_CPUID_ARM1026, "arm1026"},
{ ARM_CPUID_PXA250, "pxa250" },
{ ARM_CPUID_PXA255, "pxa255" },
{ ARM_CPUID_PXA260, "pxa260" },
{ ARM_CPUID_PXA261, "pxa261" },
{ ARM_CPUID_PXA262, "pxa262" },
{ ARM_CPUID_PXA270, "pxa270" },
{ ARM_CPUID_PXA270_A0, "pxa270-a0" },
{ ARM_CPUID_PXA270_A1, "pxa270-a1" },
{ ARM_CPUID_PXA270_B0, "pxa270-b0" },
{ ARM_CPUID_PXA270_B1, "pxa270-b1" },
{ ARM_CPUID_PXA270_C0, "pxa270-c0" },
{ ARM_CPUID_PXA270_C5, "pxa270-c5" },
{ 0, NULL} { 0, NULL}
}; };
...@@ -132,6 +165,20 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ...@@ -132,6 +165,20 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
} }
/* These should probably raise undefined insn exceptions. */ /* These should probably raise undefined insn exceptions. */
void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
{
int op1 = (insn >> 8) & 0xf;
cpu_abort(env, "cp%i insn %08x\n", op1, insn);
return;
}
uint32_t helper_get_cp(CPUState *env, uint32_t insn)
{
int op1 = (insn >> 8) & 0xf;
cpu_abort(env, "cp%i insn %08x\n", op1, insn);
return 0;
}
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
{ {
cpu_abort(env, "cp15 insn %08x\n", insn); cpu_abort(env, "cp15 insn %08x\n", insn);
...@@ -393,12 +440,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, ...@@ -393,12 +440,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
ap = (desc >> (4 + ((address >> 13) & 6))) & 3; ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
break; break;
case 3: /* 1k page. */ case 3: /* 1k page. */
if (type == 1) { if (arm_feature(env, ARM_FEATURE_XSCALE))
/* Page translation fault. */ phys_addr = (desc & 0xfffff000) | (address & 0xfff);
code = 7; else {
goto do_fault; if (type == 1) {
/* Page translation fault. */
code = 7;
goto do_fault;
}
phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
} }
phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
ap = (desc >> 4) & 3; ap = (desc >> 4) & 3;
break; break;
default: default:
...@@ -461,6 +512,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ...@@ -461,6 +512,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
return phys_addr; return phys_addr;
} }
void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
{
int cp_num = (insn >> 8) & 0xf;
int cp_info = (insn >> 5) & 7;
int src = (insn >> 16) & 0xf;
int operand = insn & 0xf;
if (env->cp[cp_num].cp_write)
env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
cp_info, src, operand, val);
}
uint32_t helper_get_cp(CPUState *env, uint32_t insn)
{
int cp_num = (insn >> 8) & 0xf;
int cp_info = (insn >> 5) & 7;
int dest = (insn >> 16) & 0xf;
int operand = insn & 0xf;
if (env->cp[cp_num].cp_read)
return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
cp_info, dest, operand);
return 0;
}
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
{ {
uint32_t op2; uint32_t op2;
...@@ -472,15 +548,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) ...@@ -472,15 +548,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
case 1: /* System configuration. */ case 1: /* System configuration. */
switch (op2) { switch (op2) {
case 0: case 0:
env->cp15.c1_sys = val; if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0)
env->cp15.c1_sys = val;
/* ??? Lots of these bits are not implemented. */ /* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */ /* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(env, 1); tlb_flush(env, 1);
break; break;
case 1:
/* XScale doesn't implement AUX CR (P-Bit) but allows
* writing with zero and reading. */
if (arm_feature(env, ARM_FEATURE_XSCALE))
break;
goto bad_reg;
case 2: case 2:
env->cp15.c1_coproc = val; env->cp15.c1_coproc = val;
/* ??? Is this safe when called from within a TB? */ /* ??? Is this safe when called from within a TB? */
tb_flush(env); tb_flush(env);
break;
default: default:
goto bad_reg; goto bad_reg;
} }
...@@ -584,13 +668,21 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) ...@@ -584,13 +668,21 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
case 14: /* Reserved. */ case 14: /* Reserved. */
goto bad_reg; goto bad_reg;
case 15: /* Implementation specific. */ case 15: /* Implementation specific. */
/* ??? Internal registers not implemented. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
if (op2 == 0 && (insn & 0xf) == 1) {
/* Changes cp0 to cp13 behavior, so needs a TB flush. */
tb_flush(env);
env->cp15.c15_cpar = (val & 0x3fff) | 2;
break;
}
goto bad_reg;
}
break; break;
} }
return; return;
bad_reg: bad_reg:
/* ??? For debugging only. Should raise illegal instruction exception. */ /* ??? For debugging only. Should raise illegal instruction exception. */
cpu_abort(env, "Unimplemented cp15 register read\n"); cpu_abort(env, "Unimplemented cp15 register write\n");
} }
uint32_t helper_get_cp15(CPUState *env, uint32_t insn) uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
...@@ -604,7 +696,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) ...@@ -604,7 +696,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
default: /* Device ID. */ default: /* Device ID. */
return env->cp15.c0_cpuid; return env->cp15.c0_cpuid;
case 1: /* Cache Type. */ case 1: /* Cache Type. */
return 0x1dd20d2; return env->cp15.c0_cachetype;
case 2: /* TCM status. */ case 2: /* TCM status. */
return 0; return 0;
} }
...@@ -615,6 +707,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) ...@@ -615,6 +707,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
case 1: /* Auxiliary control register. */ case 1: /* Auxiliary control register. */
if (arm_feature(env, ARM_FEATURE_AUXCR)) if (arm_feature(env, ARM_FEATURE_AUXCR))
return 1; return 1;
if (arm_feature(env, ARM_FEATURE_XSCALE))
return 0;
goto bad_reg; goto bad_reg;
case 2: /* Coprocessor access register. */ case 2: /* Coprocessor access register. */
return env->cp15.c1_coproc; return env->cp15.c1_coproc;
...@@ -649,7 +743,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) ...@@ -649,7 +743,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
} }
case 7: /* Cache control. */ case 7: /* Cache control. */
/* ??? This is for test, clean and invaidate operations that set the /* ??? This is for test, clean and invaidate operations that set the
Z flag. We can't represent N = Z = 1, so it also clears clears Z flag. We can't represent N = Z = 1, so it also clears
the N flag. Oh well. */ the N flag. Oh well. */
env->NZF = 0; env->NZF = 0;
return 0; return 0;
...@@ -682,7 +776,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) ...@@ -682,7 +776,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
case 14: /* Reserved. */ case 14: /* Reserved. */
goto bad_reg; goto bad_reg;
case 15: /* Implementation specific. */ case 15: /* Implementation specific. */
/* ??? Internal registers not implemented. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
if (op2 == 0 && (insn & 0xf) == 1)
return env->cp15.c15_cpar;
goto bad_reg;
}
return 0; return 0;
} }
bad_reg: bad_reg:
...@@ -691,4 +790,18 @@ bad_reg: ...@@ -691,4 +790,18 @@ bad_reg:
return 0; return 0;
} }
void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
void *opaque)
{
if (cpnum < 0 || cpnum > 14) {
cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
return;
}
env->cp[cpnum].cp_read = cp_read;
env->cp[cpnum].cp_write = cp_write;
env->cp[cpnum].opaque = opaque;
}
#endif #endif
...@@ -1142,12 +1142,24 @@ void OPPROTO op_vfp_mdrr(void) ...@@ -1142,12 +1142,24 @@ void OPPROTO op_vfp_mdrr(void)
FT0d = u.d; FT0d = u.d;
} }
/* Copy the most significant bit to T0 to all bits of T1. */ /* Copy the most significant bit of T0 to all bits of T1. */
void OPPROTO op_signbit_T1_T0(void) void OPPROTO op_signbit_T1_T0(void)
{ {
T1 = (int32_t)T0 >> 31; T1 = (int32_t)T0 >> 31;
} }
void OPPROTO op_movl_cp_T0(void)
{
helper_set_cp(env, PARAM1, T0);
FORCE_RET();
}
void OPPROTO op_movl_T0_cp(void)
{
T0 = helper_get_cp(env, PARAM1);
FORCE_RET();
}
void OPPROTO op_movl_cp15_T0(void) void OPPROTO op_movl_cp15_T0(void)
{ {
helper_set_cp15(env, PARAM1, T0); helper_set_cp15(env, PARAM1, T0);
......
...@@ -492,6 +492,34 @@ static inline void gen_mov_vreg_F0(int dp, int reg) ...@@ -492,6 +492,34 @@ static inline void gen_mov_vreg_F0(int dp, int reg)
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
} }
/* Disassemble system coprocessor instruction. Return nonzero if
instruction is not defined. */
static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
uint32_t rd = (insn >> 12) & 0xf;
uint32_t cp = (insn >> 8) & 0xf;
if (IS_USER(s)) {
return 1;
}
if (insn & (1 << 20)) {
if (!env->cp[cp].cp_read)
return 1;
gen_op_movl_T0_im((uint32_t) s->pc);
gen_op_movl_reg_TN[0][15]();
gen_op_movl_T0_cp(insn);
gen_movl_reg_T0(s, rd);
} else {
if (!env->cp[cp].cp_write)
return 1;
gen_op_movl_T0_im((uint32_t) s->pc);
gen_op_movl_reg_TN[0][15]();
gen_movl_T0_reg(s, rd);
gen_op_movl_cp_T0(insn);
}
return 0;
}
/* Disassemble system coprocessor (cp15) instruction. Return nonzero if /* Disassemble system coprocessor (cp15) instruction. Return nonzero if
instruction is not defined. */ instruction is not defined. */
static int disas_cp15_insn(DisasContext *s, uint32_t insn) static int disas_cp15_insn(DisasContext *s, uint32_t insn)
...@@ -1812,7 +1840,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) ...@@ -1812,7 +1840,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0xe: case 0xe:
/* Coprocessor. */ /* Coprocessor. */
op1 = (insn >> 8) & 0xf; op1 = (insn >> 8) & 0xf;
if (arm_feature(env, ARM_FEATURE_XSCALE) &&
((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
goto illegal_op;
switch (op1) { switch (op1) {
case 0 ... 1:
case 2 ... 9:
case 12 ... 14:
if (disas_cp_insn (env, s, insn))
goto illegal_op;
break;
case 10: case 10:
case 11: case 11:
if (disas_vfp_insn (env, s, insn)) if (disas_vfp_insn (env, s, insn))
......
...@@ -1525,6 +1525,8 @@ struct pcmcia_card_s { ...@@ -1525,6 +1525,8 @@ struct pcmcia_card_s {
/* dscm1xxxx.c */ /* dscm1xxxx.c */
struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
#include "hw/pxa.h"
#include "gdbstub.h" #include "gdbstub.h"
#endif /* defined(QEMU_TOOL) */ #endif /* defined(QEMU_TOOL) */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册