* [Qemu-devel] [PATCH] Add main PXA on-chip peripherals.
@ 2007-03-16 21:19 andrzej zaborowski
0 siblings, 0 replies; 2+ messages in thread
From: andrzej zaborowski @ 2007-03-16 21:19 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 751 bytes --]
This adds the remaining on-chip peripherals of the PXA2xx:
- MMC/SD host.
- PCMCIA sockets.
- System timers.
- LCD controller. For the LCD I added the "-portrait" switch that
rotates the display 90 degrees left. This is for the Spitz machine
(clamshell based PDA) that can work in the two display modes. The
rotation can be changed in runtime when machine code decides so. When
the screen is being rotated, the mouse clicks coordinates are also
rotated so the guest OS doesn't have to recalibrate input devices (i.e
touchscreen).
Apply on top of the earlier patches: "[PATCH] Memory mapped OHCI host
with PXA-specific bits", "[PATCH] SecureDigital card emulation",
"[PATCH] ARM XScale core features. PXA270 and PXA255 emulation."
Cheers,
Andrew
[-- Attachment #2: 0007-Add-main-PXA-on-chip-peripherals.txt --]
[-- Type: text/plain, Size: 82536 bytes --]
From 91faf02612ca8870cc58b76e1b7fd37a8bf132c1 Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Fri, 16 Mar 2007 16:26:25 +0100
Subject: [PATCH] Add main PXA on-chip peripherals.
---
hw/pxa.h | 33 ++
hw/pxa2xx.c | 29 ++
hw/pxa2xx_lcd.c | 1001 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pxa2xx_mmci.c | 489 ++++++++++++++++++++++++
hw/pxa2xx_pcmcia.c | 230 ++++++++++++
hw/pxa2xx_template.h | 431 ++++++++++++++++++++++
hw/pxa2xx_timer.c | 437 ++++++++++++++++++++++
vl.c | 19 +-
vl.h | 1 +
9 files changed, 2669 insertions(+), 1 deletions(-)
diff --git a/hw/pxa.h b/hw/pxa.h
index 16eb32f..08ddb63 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -64,6 +64,12 @@ struct pxa2xx_pic_state_s;
struct pxa2xx_pic_state_s *pxa2xx_pic_init(target_phys_addr_t base,
CPUState *env);
+/* pxa2xx_timer.c */
+void pxa25x_timer_init(target_phys_addr_t base,
+ void *pic, int irq, CPUState *cpustate);
+void pxa27x_timer_init(target_phys_addr_t base,
+ void *pic, int irq, int irq4, CPUState *cpustate);
+
/* pxa2xx_gpio.c */
struct pxa2xx_gpio_info_s;
struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
@@ -82,6 +88,30 @@ struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
void *pic, int irq);
void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
+/* pxa2xx_lcd.c */
+struct pxa2xx_lcdc_s;
+struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base,
+ void *pic, DisplayState *ds);
+void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s,
+ void (*cb)(void *opaque), void *opaque);
+void pxa2xx_lcdc_oritentation(void *opaque, int angle);
+
+/* pxa2xx_mmci.c */
+struct pxa2xx_mmci_s;
+struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
+ void *pic, void *dma);
+void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque,
+ void (*readonly_cb)(void *, int),
+ void (*coverswitch_cb)(void *, int));
+
+/* pxa2xx_pcmcia.c */
+struct pxa2xx_pcmcia_s;
+struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base);
+int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card);
+int pxa2xx_pcmcia_dettach(void *opaque);
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, void (*set_irq)(void *opaque,
+ int line, int level), int irq, int cd_irq, void *pic);
+
/* pxa2xx.c */
struct pxa2xx_ssp_s;
void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
@@ -97,7 +127,10 @@ struct pxa2xx_state_s {
struct pxa2xx_pic_state_s *pic;
struct pxa2xx_dma_state_s *dma;
struct pxa2xx_gpio_info_s *gpio;
+ struct pxa2xx_lcdc_s *lcd;
struct pxa2xx_ssp_s **ssp;
+ struct pxa2xx_mmci_s *mmc;
+ struct pxa2xx_pcmcia_s *pcmcia[2];
struct pxa2xx_i2c_s *i2c[2];
struct pxa2xx_i2s_s *i2s;
struct pxa2xx_fir_s *fir;
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 57231ae..56ea79c 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1725,8 +1725,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision)
s->dma = pxa27x_dma_init(0x40000000, s->pic, PXA2XX_PIC_DMA);
+ pxa27x_timer_init(0x40a00000, s->pic,
+ PXA2XX_PIC_OST_0, PXA27X_PIC_OST_4_11, s->env);
+
s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+ s->mmc = pxa2xx_mmci_init(0x41100000, s->pic, s->dma);
+
for (i = 0; pxa270_serial[i].io_base; i ++)
if (serial_hds[i])
serial_mm_init(*(SetIRQFunc **) s->pic, s->pic,
@@ -1736,6 +1741,9 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision)
s->fir = pxa2xx_fir_init(0x40800000, PXA2XX_PIC_ICP,
s->pic, s->dma, serial_hds[i]);
+ if (ds)
+ s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic, ds);
+
s->cm_base = 0x41300000;
s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */
s->clkcfg = 0x00000009; /* Turbo mode active */
@@ -1769,6 +1777,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision)
cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
}
+ if (usb_enabled) {
+ usb_ohci_init_memio(0x4c000000, 3, -1, 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(0, pxa2xx_rtc_readfn,
pxa2xx_rtc_writefn, s);
@@ -1807,8 +1822,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds)
s->dma = pxa255_dma_init(0x40000000, s->pic, PXA2XX_PIC_DMA);
+ pxa25x_timer_init(0x40a00000, s->pic, PXA2XX_PIC_OST_0, s->env);
+
s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+ s->mmc = pxa2xx_mmci_init(0x41100000, s->pic, s->dma);
+
for (i = 0; pxa255_serial[i].io_base; i ++)
if (serial_hds[i])
serial_mm_init(*(SetIRQFunc **) s->pic, s->pic,
@@ -1818,6 +1837,9 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds)
s->fir = pxa2xx_fir_init(0x40800000, PXA2XX_PIC_ICP,
s->pic, s->dma, serial_hds[i]);
+ if (ds)
+ s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic, ds);
+
s->cm_base = 0x41300000;
s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */
s->clkcfg = 0x00000009; /* Turbo mode active */
@@ -1851,6 +1873,13 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds)
cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
}
+ if (usb_enabled) {
+ usb_ohci_init_memio(0x4c000000, 3, -1, 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(0, pxa2xx_rtc_readfn,
pxa2xx_rtc_writefn, s);
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
new file mode 100644
index 0000000..74b630b
--- /dev/null
+++ b/hw/pxa2xx_lcd.c
@@ -0,0 +1,1001 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+
+typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
+
+struct pxa2xx_lcdc_s {
+ target_phys_addr_t base;
+ void *pic;
+ int irqlevel;
+
+ int invalidated;
+ DisplayState *ds;
+ drawfn *line_fn[2];
+ int dest_width;
+ int xres, yres;
+ int pal_for;
+ int transp;
+ enum {
+ pxa_lcdc_2bpp = 1,
+ pxa_lcdc_4bpp = 2,
+ pxa_lcdc_8bpp = 3,
+ pxa_lcdc_16bpp = 4,
+ pxa_lcdc_18bpp = 5,
+ pxa_lcdc_18pbpp = 6,
+ pxa_lcdc_19bpp = 7,
+ pxa_lcdc_19pbpp = 8,
+ pxa_lcdc_24bpp = 9,
+ pxa_lcdc_25bpp = 10,
+ } bpp;
+
+ uint32_t control[6];
+ uint32_t status[2];
+ uint32_t ovl1c[2];
+ uint32_t ovl2c[2];
+ uint32_t ccr;
+ uint32_t cmdcr;
+ uint32_t trgbr;
+ uint32_t tcr;
+ uint32_t liidr;
+ uint8_t bscntr;
+
+ struct {
+ target_phys_addr_t branch;
+ int up;
+ uint8_t palette[1024];
+ uint8_t pbuffer[1024];
+ void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb,
+ int *miny, int *maxy);
+
+ target_phys_addr_t descriptor;
+ target_phys_addr_t source;
+ uint32_t id;
+ uint32_t command;
+ } dma_ch[7];
+
+ void (*vsync_cb)(void *opaque);
+ void *opaque;
+ int orientation;
+};
+
+struct __attribute__ ((__packed__)) pxa_frame_descriptor_s {
+ uint32_t fdaddr;
+ uint32_t fsaddr;
+ uint32_t fidr;
+ uint32_t ldcmd;
+};
+
+#define LCCR0 0x000 /* LCD Controller Control register 0 */
+#define LCCR1 0x004 /* LCD Controller Control register 1 */
+#define LCCR2 0x008 /* LCD Controller Control register 2 */
+#define LCCR3 0x00c /* LCD Controller Control register 3 */
+#define LCCR4 0x010 /* LCD Controller Control register 4 */
+#define LCCR5 0x014 /* LCD Controller Control register 5 */
+
+#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */
+#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */
+#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */
+#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */
+#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */
+#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */
+#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */
+
+#define LCSR1 0x034 /* LCD Controller Status register 1 */
+#define LCSR0 0x038 /* LCD Controller Status register 0 */
+#define LIIDR 0x03c /* LCD Controller Interrupt ID register */
+
+#define TRGBR 0x040 /* TMED RGB Seed register */
+#define TCR 0x044 /* TMED Control register */
+
+#define OVL1C1 0x050 /* Overlay 1 Control register 1 */
+#define OVL1C2 0x060 /* Overlay 1 Control register 2 */
+#define OVL2C1 0x070 /* Overlay 2 Control register 1 */
+#define OVL2C2 0x080 /* Overlay 2 Control register 2 */
+#define CCR 0x090 /* Cursor Control register */
+
+#define CMDCR 0x100 /* Command Control register */
+#define PRSR 0x104 /* Panel Read Status register */
+
+#define PXA_LCDDMA_CHANS 7
+#define DMA_FDADR 0x00 /* Frame Descriptor Address register */
+#define DMA_FSADR 0x04 /* Frame Source Address register */
+#define DMA_FIDR 0x08 /* Frame ID register */
+#define DMA_LDCMD 0x0c /* Command register */
+
+/* LCD Buffer Strength Control register */
+#define BSCNTR 0x04000054
+
+/* Bitfield masks */
+#define LCCR0_ENB (1 << 0)
+#define LCCR0_CMS (1 << 1)
+#define LCCR0_SDS (1 << 2)
+#define LCCR0_LDM (1 << 3)
+#define LCCR0_SOFM0 (1 << 4)
+#define LCCR0_IUM (1 << 5)
+#define LCCR0_EOFM0 (1 << 6)
+#define LCCR0_PAS (1 << 7)
+#define LCCR0_DPD (1 << 9)
+#define LCCR0_DIS (1 << 10)
+#define LCCR0_QDM (1 << 11)
+#define LCCR0_PDD (0xff << 12)
+#define LCCR0_BSM0 (1 << 20)
+#define LCCR0_OUM (1 << 21)
+#define LCCR0_LCDT (1 << 22)
+#define LCCR0_RDSTM (1 << 23)
+#define LCCR0_CMDIM (1 << 24)
+#define LCCR0_OUC (1 << 25)
+#define LCCR0_LDDALT (1 << 26)
+#define LCCR1_PPL(x) ((x) & 0x3ff)
+#define LCCR2_LPP(x) ((x) & 0x3ff)
+#define LCCR3_API (15 << 16)
+#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8))
+#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
+#define LCCR4_K1(x) (((x) >> 0) & 7)
+#define LCCR4_K2(x) (((x) >> 3) & 7)
+#define LCCR4_K3(x) (((x) >> 6) & 7)
+#define LCCR4_PALFOR(x) (((x) >> 15) & 3)
+#define LCCR5_SOFM(ch) (1 << (ch - 1))
+#define LCCR5_EOFM(ch) (1 << (ch + 7))
+#define LCCR5_BSM(ch) (1 << (ch + 15))
+#define LCCR5_IUM(ch) (1 << (ch + 23))
+#define OVLC1_EN (1 << 31)
+#define CCR_CEN (1 << 31)
+#define FBR_BRA (1 << 0)
+#define FBR_BINT (1 << 1)
+#define FBR_SRCADDR (0xfffffff << 4)
+#define LCSR0_LDD (1 << 0)
+#define LCSR0_SOF0 (1 << 1)
+#define LCSR0_BER (1 << 2)
+#define LCSR0_ABC (1 << 3)
+#define LCSR0_IU0 (1 << 4)
+#define LCSR0_IU1 (1 << 5)
+#define LCSR0_OU (1 << 6)
+#define LCSR0_QD (1 << 7)
+#define LCSR0_EOF0 (1 << 8)
+#define LCSR0_BS0 (1 << 9)
+#define LCSR0_SINT (1 << 10)
+#define LCSR0_RDST (1 << 11)
+#define LCSR0_CMDINT (1 << 12)
+#define LCSR0_BERCH(x) (((x) & 7) << 28)
+#define LCSR1_SOF(ch) (1 << (ch - 1))
+#define LCSR1_EOF(ch) (1 << (ch + 7))
+#define LCSR1_BS(ch) (1 << (ch + 15))
+#define LCSR1_IU(ch) (1 << (ch + 23))
+#define LDCMD_LENGTH(x) ((x) & 0x001ffffc)
+#define LDCMD_EOFINT (1 << 21)
+#define LDCMD_SOFINT (1 << 22)
+#define LDCMD_PAL (1 << 26)
+
+/* Route internal interrupt lines to the global IC */
+static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s)
+{
+ int level = 0;
+ level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM);
+ level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0);
+ level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM);
+ level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1));
+ level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM);
+ level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM);
+ level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0);
+ level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0);
+ level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM);
+ level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
+ level |= (s->status[1] & ~s->control[5]);
+
+ pic_set_irq_new(s->pic, PXA2XX_PIC_LCD, !!level);
+ s->irqlevel = level;
+}
+
+/* Set Branch Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+ int unmasked;
+ if (ch == 0) {
+ s->status[0] |= LCSR0_BS0;
+ unmasked = !(s->control[0] & LCCR0_BSM0);
+ } else {
+ s->status[1] |= LCSR1_BS(ch);
+ unmasked = !(s->control[5] & LCCR5_BSM(ch));
+ }
+
+ if (unmasked) {
+ if (s->irqlevel)
+ s->status[0] |= LCSR0_SINT;
+ else
+ s->liidr = s->dma_ch[ch].id;
+ }
+}
+
+/* Set Start Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+ int unmasked;
+ if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
+ return;
+
+ if (ch == 0) {
+ s->status[0] |= LCSR0_SOF0;
+ unmasked = !(s->control[0] & LCCR0_SOFM0);
+ } else {
+ s->status[1] |= LCSR1_SOF(ch);
+ unmasked = !(s->control[5] & LCCR5_SOFM(ch));
+ }
+
+ if (unmasked) {
+ if (s->irqlevel)
+ s->status[0] |= LCSR0_SINT;
+ else
+ s->liidr = s->dma_ch[ch].id;
+ }
+}
+
+/* Set End Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+ int unmasked;
+ if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
+ return;
+
+ if (ch == 0) {
+ s->status[0] |= LCSR0_EOF0;
+ unmasked = !(s->control[0] & LCCR0_EOFM0);
+ } else {
+ s->status[1] |= LCSR1_EOF(ch);
+ unmasked = !(s->control[5] & LCCR5_EOFM(ch));
+ }
+
+ if (unmasked) {
+ if (s->irqlevel)
+ s->status[0] |= LCSR0_SINT;
+ else
+ s->liidr = s->dma_ch[ch].id;
+ }
+}
+
+/* Set Bus Error Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+ s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
+ if (s->irqlevel)
+ s->status[0] |= LCSR0_SINT;
+ else
+ s->liidr = s->dma_ch[ch].id;
+}
+
+/* Set Read Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s)
+{
+ s->status[0] |= LCSR0_RDST;
+ if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
+ s->status[0] |= LCSR0_SINT;
+}
+
+/* Load new Frame Descriptors from DMA */
+static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
+{
+ struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS];
+ target_phys_addr_t descptr;
+ int i;
+
+ for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
+ desc[i] = 0;
+ s->dma_ch[i].source = 0;
+
+ if (!s->dma_ch[i].up)
+ continue;
+
+ if (s->dma_ch[i].branch & FBR_BRA) {
+ descptr = s->dma_ch[i].branch & FBR_SRCADDR;
+ if (s->dma_ch[i].branch & FBR_BINT)
+ pxa2xx_dma_bs_set(s, i);
+ s->dma_ch[i].branch &= ~FBR_BRA;
+ } else
+ descptr = s->dma_ch[i].descriptor;
+
+ if (!(descptr >= PXA2XX_RAM_BASE && descptr +
+ sizeof(*desc[i]) <= PXA2XX_RAM_BASE + phys_ram_size))
+ continue;
+
+ descptr -= PXA2XX_RAM_BASE;
+ desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr);
+ s->dma_ch[i].descriptor = desc[i]->fdaddr;
+ s->dma_ch[i].source = desc[i]->fsaddr;
+ s->dma_ch[i].id = desc[i]->fidr;
+ s->dma_ch[i].command = desc[i]->ldcmd;
+ }
+}
+
+static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset)
+{
+ struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+ int ch;
+ offset -= s->base;
+
+ switch (offset) {
+ case LCCR0:
+ return s->control[0];
+ case LCCR1:
+ return s->control[1];
+ case LCCR2:
+ return s->control[2];
+ case LCCR3:
+ return s->control[3];
+ case LCCR4:
+ return s->control[4];
+ case LCCR5:
+ return s->control[5];
+
+ case OVL1C1:
+ return s->ovl1c[0];
+ case OVL1C2:
+ return s->ovl1c[1];
+ case OVL2C1:
+ return s->ovl2c[0];
+ case OVL2C2:
+ return s->ovl2c[1];
+
+ case CCR:
+ return s->ccr;
+
+ case CMDCR:
+ return s->cmdcr;
+
+ case TRGBR:
+ return s->trgbr;
+ case TCR:
+ return s->tcr;
+
+ case 0x200 ... 0x1000: /* DMA per-channel registers */
+ ch = (offset - 0x200) >> 4;
+ if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+ goto fail;
+
+ switch (offset & 0xf) {
+ case DMA_FDADR:
+ return s->dma_ch[ch].descriptor;
+ case DMA_FSADR:
+ return s->dma_ch[ch].source;
+ case DMA_FIDR:
+ return s->dma_ch[ch].id;
+ case DMA_LDCMD:
+ return s->dma_ch[ch].command;
+ default:
+ goto fail;
+ }
+
+ case FBR0:
+ return s->dma_ch[0].branch;
+ case FBR1:
+ return s->dma_ch[1].branch;
+ case FBR2:
+ return s->dma_ch[2].branch;
+ case FBR3:
+ return s->dma_ch[3].branch;
+ case FBR4:
+ return s->dma_ch[4].branch;
+ case FBR5:
+ return s->dma_ch[5].branch;
+ case FBR6:
+ return s->dma_ch[6].branch;
+
+ case BSCNTR:
+ return s->bscntr;
+
+ case PRSR:
+ return 0;
+
+ case LCSR0:
+ return s->status[0];
+ case LCSR1:
+ return s->status[1];
+ case LIIDR:
+ return s->liidr;
+
+ default:
+ fail:
+ cpu_abort(cpu_single_env,
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_lcdc_write(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+ int ch;
+ offset -= s->base;
+
+ switch (offset) {
+ case LCCR0:
+ /* ACK Quick Disable done */
+ if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
+ s->status[0] |= LCSR0_QD;
+
+ if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
+ printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
+
+ if ((s->control[3] & LCCR3_API) &&
+ (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
+ s->status[0] |= LCSR0_ABC;
+
+ s->control[0] = value & 0x07ffffff;
+ pxa2xx_lcdc_int_update(s);
+
+ s->dma_ch[0].up = !!(value & LCCR0_ENB);
+ s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
+ break;
+
+ case LCCR1:
+ s->control[1] = value;
+ break;
+
+ case LCCR2:
+ s->control[2] = value;
+ break;
+
+ case LCCR3:
+ s->control[3] = value & 0xefffffff;
+ s->bpp = LCCR3_BPP(value);
+ break;
+
+ case LCCR4:
+ s->control[4] = value & 0x83ff81ff;
+ break;
+
+ case LCCR5:
+ s->control[5] = value & 0x3f3f3f3f;
+ break;
+
+ case OVL1C1:
+ if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
+ printf("%s: Overlay 1 not supported\n", __FUNCTION__);
+
+ s->ovl1c[0] = value & 0x80ffffff;
+ s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
+ break;
+
+ case OVL1C2:
+ s->ovl1c[1] = value & 0x000fffff;
+ break;
+
+ case OVL2C1:
+ if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
+ printf("%s: Overlay 2 not supported\n", __FUNCTION__);
+
+ s->ovl2c[0] = value & 0x80ffffff;
+ s->dma_ch[2].up = !!(value & OVLC1_EN);
+ s->dma_ch[3].up = !!(value & OVLC1_EN);
+ s->dma_ch[4].up = !!(value & OVLC1_EN);
+ break;
+
+ case OVL2C2:
+ s->ovl2c[1] = value & 0x007fffff;
+ break;
+
+ case CCR:
+ if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
+ printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
+
+ s->ccr = value & 0x81ffffe7;
+ s->dma_ch[5].up = !!(value & CCR_CEN);
+ break;
+
+ case CMDCR:
+ s->cmdcr = value & 0xff;
+ break;
+
+ case TRGBR:
+ s->trgbr = value & 0x00ffffff;
+ break;
+
+ case TCR:
+ s->tcr = value & 0x7fff;
+ break;
+
+ case 0x200 ... 0x1000: /* DMA per-channel registers */
+ ch = (offset - 0x200) >> 4;
+ if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+ goto fail;
+
+ switch (offset & 0xf) {
+ case DMA_FDADR:
+ s->dma_ch[ch].descriptor = value & 0xfffffff0;
+ break;
+
+ default:
+ goto fail;
+ }
+ break;
+
+ case FBR0:
+ s->dma_ch[0].branch = value & 0xfffffff3;
+ break;
+ case FBR1:
+ s->dma_ch[1].branch = value & 0xfffffff3;
+ break;
+ case FBR2:
+ s->dma_ch[2].branch = value & 0xfffffff3;
+ break;
+ case FBR3:
+ s->dma_ch[3].branch = value & 0xfffffff3;
+ break;
+ case FBR4:
+ s->dma_ch[4].branch = value & 0xfffffff3;
+ break;
+ case FBR5:
+ s->dma_ch[5].branch = value & 0xfffffff3;
+ break;
+ case FBR6:
+ s->dma_ch[6].branch = value & 0xfffffff3;
+ break;
+
+ case BSCNTR:
+ s->bscntr = value & 0xf;
+ break;
+
+ case PRSR:
+ break;
+
+ case LCSR0:
+ s->status[0] &= ~(value & 0xfff);
+ if (value & LCSR0_BER)
+ s->status[0] &= ~LCSR0_BERCH(7);
+ break;
+
+ case LCSR1:
+ s->status[1] &= ~(value & 0x3e3f3f);
+ break;
+
+ default:
+ fail:
+ cpu_abort(cpu_single_env,
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = {
+ pxa2xx_lcdc_read,
+ pxa2xx_lcdc_read,
+ pxa2xx_lcdc_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = {
+ pxa2xx_lcdc_write,
+ pxa2xx_lcdc_write,
+ pxa2xx_lcdc_write
+};
+
+static inline
+uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
+}
+
+static inline
+uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
+{
+ return (r << 16) | (g << 8) | b;
+}
+
+static inline
+uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
+{
+ return (r << 16) | (g << 8) | b;
+}
+
+/* Load new palette for a given DMA channel, convert to internal format */
+static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp)
+{
+ int i, n, format, r, g, b, alpha;
+ uint32_t *dest, *src;
+ s->pal_for = LCCR4_PALFOR(s->control[4]);
+ format = s->pal_for;
+
+ switch (bpp) {
+ case pxa_lcdc_2bpp:
+ n = 4;
+ break;
+ case pxa_lcdc_4bpp:
+ n = 16;
+ break;
+ case pxa_lcdc_8bpp:
+ n = 256;
+ break;
+ default:
+ format = 0;
+ return;
+ }
+
+ src = (uint32_t *) s->dma_ch[ch].pbuffer;
+ dest = (uint32_t *) s->dma_ch[ch].palette;
+ alpha = r = g = b = 0;
+
+ for (i = 0; i < n; i ++) {
+ switch (format) {
+ case 0: /* 16 bpp, no transparency */
+ alpha = 0;
+ if (s->control[0] & LCCR0_CMS)
+ r = g = b = *src & 0xff;
+ else {
+ r = (*src & 0xf800) >> 8;
+ g = (*src & 0x07e0) >> 3;
+ b = (*src & 0x001f) << 3;
+ }
+ break;
+ case 1: /* 16 bpp plus transparency */
+ alpha = *src & (1 << 24);
+ if (s->control[0] & LCCR0_CMS)
+ r = g = b = *src & 0xff;
+ else {
+ r = (*src & 0xf800) >> 8;
+ g = (*src & 0x07e0) >> 3;
+ b = (*src & 0x001f) << 3;
+ }
+ break;
+ case 2: /* 18 bpp plus transparency */
+ alpha = *src & (1 << 24);
+ if (s->control[0] & LCCR0_CMS)
+ r = g = b = *src & 0xff;
+ else {
+ r = (*src & 0xf80000) >> 16;
+ g = (*src & 0x00fc00) >> 8;
+ b = (*src & 0x0000f8);
+ }
+ break;
+ case 3: /* 24 bpp plus transparency */
+ alpha = *src & (1 << 24);
+ if (s->control[0] & LCCR0_CMS)
+ r = g = b = *src & 0xff;
+ else {
+ r = (*src & 0xff0000) >> 16;
+ g = (*src & 0x00ff00) >> 8;
+ b = (*src & 0x0000ff);
+ }
+ break;
+ }
+ switch (s->ds->depth) {
+ case 8:
+ *dest = rgb_to_pixel8(r, g, b) | alpha;
+ break;
+ case 15:
+ *dest = rgb_to_pixel15(r, g, b) | alpha;
+ break;
+ case 16:
+ *dest = rgb_to_pixel16(r, g, b) | alpha;
+ break;
+ case 24:
+ *dest = rgb_to_pixel24(r, g, b) | alpha;
+ break;
+ case 32:
+ *dest = rgb_to_pixel32(r, g, b) | alpha;
+ break;
+ }
+ src ++;
+ dest ++;
+ }
+}
+
+static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
+ uint8_t *fb, int *miny, int *maxy)
+{
+ int y, src_width, dest_width, dirty[2];
+ uint8_t *src, *dest;
+ ram_addr_t x, addr, new_addr, start, end;
+ drawfn fn = 0;
+ if (s->dest_width)
+ fn = s->line_fn[s->transp][s->bpp];
+ if (!fn)
+ return;
+
+ src = fb;
+ src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
+ if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+ src_width *= 3;
+ else if (s->bpp > pxa_lcdc_16bpp)
+ src_width *= 4;
+ else if (s->bpp > pxa_lcdc_8bpp)
+ src_width *= 2;
+
+ dest = s->ds->data;
+ dest_width = s->xres * s->dest_width;
+
+ addr = (ram_addr_t) (fb - phys_ram_base);
+ start = addr + s->yres * src_width;
+ end = addr;
+ dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
+ for (y = 0; y < s->yres; y ++) {
+ new_addr = addr + src_width;
+ for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
+ x += TARGET_PAGE_SIZE) {
+ dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+ dirty[0] |= dirty[1];
+ }
+ if (dirty[0] || s->invalidated) {
+ fn((uint32_t *) s->dma_ch[0].palette,
+ dest, src, s->xres, s->dest_width);
+ if (addr < start)
+ start = addr;
+ if (new_addr > end)
+ end = new_addr;
+ if (y < *miny)
+ *miny = y;
+ if (y >= *maxy)
+ *maxy = y + 1;
+ }
+ addr = new_addr;
+ dirty[0] = dirty[1];
+ src += src_width;
+ dest += dest_width;
+ }
+
+ if (end > start)
+ cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
+ uint8_t *fb, int *miny, int *maxy)
+{
+ int y, src_width, dest_width, dirty[2];
+ uint8_t *src, *dest;
+ ram_addr_t x, addr, new_addr, start, end;
+ drawfn fn = 0;
+ if (s->dest_width)
+ fn = s->line_fn[s->transp][s->bpp];
+ if (!fn)
+ return;
+
+ src = fb;
+ src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
+ if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+ src_width *= 3;
+ else if (s->bpp > pxa_lcdc_16bpp)
+ src_width *= 4;
+ else if (s->bpp > pxa_lcdc_8bpp)
+ src_width *= 2;
+
+ dest_width = s->yres * s->dest_width;
+ dest = s->ds->data + dest_width * (s->xres - 1);
+
+ addr = (ram_addr_t) (fb - phys_ram_base);
+ start = addr + s->yres * src_width;
+ end = addr;
+ dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
+ for (y = 0; y < s->yres; y ++) {
+ new_addr = addr + src_width;
+ for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
+ x += TARGET_PAGE_SIZE) {
+ dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+ dirty[0] |= dirty[1];
+ }
+ if (dirty[0] || s->invalidated) {
+ fn((uint32_t *) s->dma_ch[0].palette,
+ dest, src, s->xres, -dest_width);
+ if (addr < start)
+ start = addr;
+ if (new_addr > end)
+ end = new_addr;
+ if (y < *miny)
+ *miny = y;
+ if (y >= *maxy)
+ *maxy = y + 1;
+ }
+ addr = new_addr;
+ dirty[0] = dirty[1];
+ src += src_width;
+ dest += s->dest_width;
+ }
+
+ if (end > start)
+ cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+}
+
+static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
+{
+ int width, height;
+ if (!(s->control[0] & LCCR0_ENB))
+ return;
+
+ width = LCCR1_PPL(s->control[1]) + 1;
+ height = LCCR2_LPP(s->control[2]) + 1;
+
+ if (width != s->xres || height != s->yres) {
+ if (s->orientation)
+ dpy_resize(s->ds, height, width);
+ else
+ dpy_resize(s->ds, width, height);
+ s->invalidated = 1;
+ s->xres = width;
+ s->yres = height;
+ }
+}
+
+static void pxa2xx_update_display(void *opaque)
+{
+ struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+ uint8_t *fb;
+ target_phys_addr_t fbptr;
+ int miny, maxy;
+ int ch;
+ if (!(s->control[0] & LCCR0_ENB))
+ return;
+
+ pxa2xx_descriptor_load(s);
+
+ pxa2xx_lcdc_resize(s);
+ miny = s->yres;
+ maxy = 0;
+ s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
+ /* Note: With overlay planes the order depends on LCCR0 bit 25. */
+ for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
+ if (s->dma_ch[ch].up) {
+ if (!s->dma_ch[ch].source) {
+ pxa2xx_dma_ber_set(s, ch);
+ continue;
+ }
+ fbptr = s->dma_ch[ch].source;
+ if (!(fbptr >= PXA2XX_RAM_BASE &&
+ fbptr <= PXA2XX_RAM_BASE + phys_ram_size)) {
+ pxa2xx_dma_ber_set(s, ch);
+ continue;
+ }
+ fbptr -= PXA2XX_RAM_BASE;
+ fb = phys_ram_base + fbptr;
+
+ if (s->dma_ch[ch].command & LDCMD_PAL) {
+ memcpy(s->dma_ch[ch].pbuffer, fb,
+ MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+ sizeof(s->dma_ch[ch].pbuffer)));
+ pxa2xx_palette_parse(s, ch, s->bpp);
+ } else {
+ /* Do we need to reparse palette */
+ if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
+ pxa2xx_palette_parse(s, ch, s->bpp);
+
+ /* ACK frame start */
+ pxa2xx_dma_sof_set(s, ch);
+
+ s->dma_ch[ch].redraw(s, fb, &miny, &maxy);
+ s->invalidated = 0;
+
+ /* ACK frame completed */
+ pxa2xx_dma_eof_set(s, ch);
+ }
+ }
+
+ if (s->control[0] & LCCR0_DIS) {
+ /* ACK last frame completed */
+ s->control[0] &= ~LCCR0_ENB;
+ s->status[0] |= LCSR0_LDD;
+ }
+
+ if (s->orientation)
+ dpy_update(s->ds, miny, 0, maxy, s->xres);
+ else
+ dpy_update(s->ds, 0, miny, s->xres, maxy);
+ pxa2xx_lcdc_int_update(s);
+
+ if (s->vsync_cb)
+ s->vsync_cb(s->opaque);
+}
+
+static void pxa2xx_invalidate_display(void *opaque)
+{
+ struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+ s->invalidated = 1;
+}
+
+static void pxa2xx_screen_dump(void *opaque, const char *filename)
+{
+ /* TODO */
+}
+
+void pxa2xx_lcdc_orientation(void *opaque, int angle)
+{
+ struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+
+ if (angle) {
+ s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert;
+ } else {
+ s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz;
+ }
+
+ s->orientation = angle;
+ s->xres = s->yres = -1;
+ pxa2xx_lcdc_resize(s);
+}
+
+#define BITS 8
+#include "pxa2xx_template.h"
+#define BITS 15
+#include "pxa2xx_template.h"
+#define BITS 16
+#include "pxa2xx_template.h"
+#define BITS 24
+#include "pxa2xx_template.h"
+#define BITS 32
+#include "pxa2xx_template.h"
+
+struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, void *pic,
+ DisplayState *ds)
+{
+ int iomemtype;
+ struct pxa2xx_lcdc_s *s;
+
+ s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s));
+ s->base = base;
+ s->invalidated = 1;
+ s->pic = pic;
+ s->ds = ds;
+
+ pxa2xx_lcdc_orientation(s, graphic_rotate);
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn,
+ pxa2xx_lcdc_writefn, s);
+ cpu_register_physical_memory(base, 0x000fffff, iomemtype);
+
+ graphic_console_init(ds, pxa2xx_update_display,
+ pxa2xx_invalidate_display, pxa2xx_screen_dump, s);
+
+ switch (s->ds->depth) {
+ case 0:
+ s->dest_width = 0;
+ break;
+ case 8:
+ s->line_fn[0] = pxa2xx_draw_fn_8;
+ s->line_fn[1] = pxa2xx_draw_fn_8t;
+ s->dest_width = 1;
+ break;
+ case 15:
+ s->line_fn[0] = pxa2xx_draw_fn_15;
+ s->line_fn[1] = pxa2xx_draw_fn_15t;
+ s->dest_width = 2;
+ break;
+ case 16:
+ s->line_fn[0] = pxa2xx_draw_fn_16;
+ s->line_fn[1] = pxa2xx_draw_fn_16t;
+ s->dest_width = 2;
+ break;
+ case 24:
+ s->line_fn[0] = pxa2xx_draw_fn_24;
+ s->line_fn[1] = pxa2xx_draw_fn_24t;
+ s->dest_width = 3;
+ break;
+ case 32:
+ s->line_fn[0] = pxa2xx_draw_fn_32;
+ s->line_fn[1] = pxa2xx_draw_fn_32t;
+ s->dest_width = 4;
+ break;
+ default:
+ fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+ exit(1);
+ }
+ return s;
+}
+
+void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s,
+ void (*cb)(void *opaque), void *opaque) {
+ s->vsync_cb = cb;
+ s->opaque = opaque;
+}
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
new file mode 100644
index 0000000..8dc6a09
--- /dev/null
+++ b/hw/pxa2xx_mmci.c
@@ -0,0 +1,489 @@
+/*
+ * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+#include "sd.h"
+
+struct pxa2xx_mmci_s {
+ target_phys_addr_t base;
+ void *pic;
+ void *dma;
+
+ struct sd_state_s *card;
+
+ uint32_t status;
+ uint32_t clkrt;
+ uint32_t spi;
+ uint32_t cmdat;
+ uint32_t resp_tout;
+ uint32_t read_tout;
+ int blklen;
+ int numblk;
+ uint32_t intmask;
+ uint32_t intreq;
+ int cmd;
+ uint32_t arg;
+
+ int active;
+ int bytesleft;
+ uint8_t tx_fifo[64];
+ int tx_start;
+ int tx_len;
+ uint8_t rx_fifo[32];
+ int rx_start;
+ int rx_len;
+ uint16_t resp_fifo[9];
+ int resp_len;
+
+ int cmdreq;
+ int ac_width;
+};
+
+#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
+#define MMC_STAT 0x04 /* MMC Status register */
+#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
+#define MMC_SPI 0x0c /* MMC SPI Mode register */
+#define MMC_CMDAT 0x10 /* MMC Command/Data register */
+#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
+#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
+#define MMC_BLKLEN 0x1c /* MMC Block Length register */
+#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
+#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
+#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
+#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
+#define MMC_CMD 0x30 /* MMC Command register */
+#define MMC_ARGH 0x34 /* MMC Argument High register */
+#define MMC_ARGL 0x38 /* MMC Argument Low register */
+#define MMC_RES 0x3c /* MMC Response FIFO */
+#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
+#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
+#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
+#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
+
+/* Bitfield masks */
+#define STRPCL_STOP_CLK (1 << 0)
+#define STRPCL_STRT_CLK (1 << 1)
+#define STAT_TOUT_RES (1 << 1)
+#define STAT_CLK_EN (1 << 8)
+#define STAT_DATA_DONE (1 << 11)
+#define STAT_PRG_DONE (1 << 12)
+#define STAT_END_CMDRES (1 << 13)
+#define SPI_SPI_MODE (1 << 0)
+#define CMDAT_RES_TYPE (3 << 0)
+#define CMDAT_DATA_EN (1 << 2)
+#define CMDAT_WR_RD (1 << 3)
+#define CMDAT_DMA_EN (1 << 7)
+#define CMDAT_STOP_TRAN (1 << 10)
+#define INT_DATA_DONE (1 << 0)
+#define INT_PRG_DONE (1 << 1)
+#define INT_END_CMD (1 << 2)
+#define INT_STOP_CMD (1 << 3)
+#define INT_CLK_OFF (1 << 4)
+#define INT_RXFIFO_REQ (1 << 5)
+#define INT_TXFIFO_REQ (1 << 6)
+#define INT_TINT (1 << 7)
+#define INT_DAT_ERR (1 << 8)
+#define INT_RES_ERR (1 << 9)
+#define INT_RD_STALLED (1 << 10)
+#define INT_SDIO_INT (1 << 11)
+#define INT_SDIO_SACK (1 << 12)
+#define PRTBUF_PRT_BUF (1 << 0)
+
+/* Route internal interrupt lines to the global IC and DMA */
+static void pxa2xx_mmci_int_update(struct pxa2xx_mmci_s *s)
+{
+ uint32_t mask = s->intmask;
+ if (s->cmdat & CMDAT_DMA_EN) {
+ mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
+
+ pic_set_irq_new(s->dma, PXA2XX_RX_RQ_MMCI,
+ !!(s->intreq & INT_RXFIFO_REQ));
+ pic_set_irq_new(s->dma, PXA2XX_TX_RQ_MMCI,
+ !!(s->intreq & INT_TXFIFO_REQ));
+ }
+
+ pic_set_irq_new(s->pic, PXA2XX_PIC_MMC, !!(s->intreq & ~mask));
+}
+
+static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s)
+{
+ if (!s->active)
+ return;
+
+ if (s->cmdat & CMDAT_WR_RD) {
+ while (s->bytesleft && s->tx_len) {
+ sd_write_datline(s->card, s->tx_fifo[s->tx_start ++]);
+ s->tx_start &= 0x1f;
+ s->tx_len --;
+ s->bytesleft --;
+ }
+ if (s->bytesleft)
+ s->intreq |= INT_TXFIFO_REQ;
+ } else
+ while (s->bytesleft && s->rx_len < 32) {
+ s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
+ sd_read_datline(s->card);
+ s->bytesleft --;
+ s->intreq |= INT_RXFIFO_REQ;
+ }
+
+ if (!s->bytesleft) {
+ s->active = 0;
+ s->intreq |= INT_DATA_DONE;
+ s->status |= STAT_DATA_DONE;
+
+ if (s->cmdat & CMDAT_WR_RD) {
+ s->intreq |= INT_PRG_DONE;
+ s->status |= STAT_PRG_DONE;
+ }
+ }
+
+ pxa2xx_mmci_int_update(s);
+}
+
+static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s)
+{
+ int rsplen;
+ struct sd_request_s request;
+ union sd_response_u response;
+
+ s->active = 1;
+ s->rx_len = 0;
+ s->tx_len = 0;
+ s->cmdreq = 0;
+
+ request.cmd = s->cmd;
+ request.arg = s->arg;
+ request.crc = 0; /* FIXME */
+
+ response = sd_write_cmdline(s->card, request, &rsplen);
+ s->intreq |= INT_END_CMD;
+
+ memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
+ switch (s->cmdat & CMDAT_RES_TYPE) {
+#define PXAMMCI_RESP(wd, value) \
+ s->resp_fifo[(wd) + 0] |= (value) >> 8; \
+ s->resp_fifo[(wd) + 1] |= (value) << 8;
+ case 0: /* No response */
+ goto complete;
+
+ case 1: /* R1, R4, R5 or R6 */
+ if (rsplen < 48)
+ goto timeout;
+
+ if (request.cmd == 3) { /* R6 */
+ PXAMMCI_RESP(0, response.r6.arg);
+ PXAMMCI_RESP(1, response.r6.status);
+ } else {
+ PXAMMCI_RESP(0, response.r1.status >> 16);
+ PXAMMCI_RESP(1, response.r1.status & 0x0000ffff);
+ }
+ goto complete;
+
+ case 2: /* R2 */
+ if (rsplen < 128)
+ goto timeout;
+
+ PXAMMCI_RESP(0, bswap16(response.r2.reg[0]));
+ PXAMMCI_RESP(1, bswap16(response.r2.reg[1]));
+ PXAMMCI_RESP(2, bswap16(response.r2.reg[2]));
+ PXAMMCI_RESP(3, bswap16(response.r2.reg[3]));
+ PXAMMCI_RESP(4, bswap16(response.r2.reg[4]));
+ PXAMMCI_RESP(5, bswap16(response.r2.reg[5]));
+ PXAMMCI_RESP(6, bswap16(response.r2.reg[6]));
+ PXAMMCI_RESP(7, bswap16(response.r2.reg[7]));
+ goto complete;
+
+ case 3: /* R3 */
+ if (rsplen < 32)
+ goto timeout;
+
+ PXAMMCI_RESP(0, response.r3.ocr_reg >> 16);
+ PXAMMCI_RESP(1, response.r3.ocr_reg & 0x0000ffff);
+ goto complete;
+
+ complete:
+ s->status |= STAT_END_CMDRES;
+
+ if (!(s->cmdat & CMDAT_DATA_EN))
+ s->active = 0;
+ else
+ s->bytesleft = s->numblk * s->blklen;
+
+ s->resp_len = 0;
+ break;
+
+ timeout:
+ s->active = 0;
+ s->status |= STAT_TOUT_RES;
+ break;
+ }
+
+ pxa2xx_mmci_fifo_update(s);
+}
+
+static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ uint32_t ret;
+ offset -= s->base;
+
+ switch (offset) {
+ case MMC_STRPCL:
+ return 0;
+ case MMC_STAT:
+ return s->status;
+ case MMC_CLKRT:
+ return s->clkrt;
+ case MMC_SPI:
+ return s->spi;
+ case MMC_CMDAT:
+ return s->cmdat;
+ case MMC_RESTO:
+ return s->resp_tout;
+ case MMC_RDTO:
+ return s->read_tout;
+ case MMC_BLKLEN:
+ return s->blklen;
+ case MMC_NUMBLK:
+ return s->numblk;
+ case MMC_PRTBUF:
+ return 0;
+ case MMC_I_MASK:
+ return s->intmask;
+ case MMC_I_REG:
+ return s->intreq;
+ case MMC_CMD:
+ return s->cmd | 0x40;
+ case MMC_ARGH:
+ return s->arg >> 16;
+ case MMC_ARGL:
+ return s->arg & 0xffff;
+ case MMC_RES:
+ if (s->resp_len < 9)
+ return s->resp_fifo[s->resp_len ++];
+ return 0;
+ case MMC_RXFIFO:
+ ret = 0;
+ while (s->ac_width -- && s->rx_len) {
+ ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
+ s->rx_start &= 0x1f;
+ s->rx_len --;
+ }
+ s->intreq &= ~INT_RXFIFO_REQ;
+ pxa2xx_mmci_fifo_update(s);
+ return ret;
+ case MMC_RDWAIT:
+ return 0;
+ case MMC_BLKS_REM:
+ return s->numblk;
+ default:
+ cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+ __FUNCTION__, offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_mmci_write(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ offset -= s->base;
+
+ switch (offset) {
+ case MMC_STRPCL:
+ if (value & STRPCL_STRT_CLK) {
+ s->status |= STAT_CLK_EN;
+ s->intreq &= ~INT_CLK_OFF;
+
+ if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
+ s->status &= STAT_CLK_EN;
+ pxa2xx_mmci_wakequeues(s);
+ }
+ }
+
+ if (value & STRPCL_STOP_CLK) {
+ s->status &= ~STAT_CLK_EN;
+ s->intreq |= INT_CLK_OFF;
+ s->active = 0;
+ }
+
+ pxa2xx_mmci_int_update(s);
+ break;
+
+ case MMC_CLKRT:
+ s->clkrt = value & 7;
+ break;
+
+ case MMC_SPI:
+ s->spi = value & 0xf;
+ if (value & SPI_SPI_MODE)
+ printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+ break;
+
+ case MMC_CMDAT:
+ s->cmdat = value & 0x3dff;
+ s->active = 0;
+ s->cmdreq = 1;
+ if (!(value & CMDAT_STOP_TRAN)) {
+ s->status &= STAT_CLK_EN;
+
+ if (s->status & STAT_CLK_EN)
+ pxa2xx_mmci_wakequeues(s);
+ }
+
+ pxa2xx_mmci_int_update(s);
+ break;
+
+ case MMC_RESTO:
+ s->resp_tout = value & 0x7f;
+ break;
+
+ case MMC_RDTO:
+ s->read_tout = value & 0xffff;
+ break;
+
+ case MMC_BLKLEN:
+ s->blklen = value & 0xfff;
+ break;
+
+ case MMC_NUMBLK:
+ s->numblk = value & 0xffff;
+ break;
+
+ case MMC_PRTBUF:
+ if (value & PRTBUF_PRT_BUF) {
+ s->tx_start ^= 32;
+ s->tx_len = 0;
+ }
+ pxa2xx_mmci_fifo_update(s);
+ break;
+
+ case MMC_I_MASK:
+ s->intmask = value & 0x1fff;
+ pxa2xx_mmci_int_update(s);
+ break;
+
+ case MMC_CMD:
+ s->cmd = value & 0x3f;
+ break;
+
+ case MMC_ARGH:
+ s->arg &= 0x0000ffff;
+ s->arg |= value << 16;
+ break;
+
+ case MMC_ARGL:
+ s->arg &= 0xffff0000;
+ s->arg |= value & 0x0000ffff;
+ break;
+
+ case MMC_TXFIFO:
+ while (s->ac_width -- && s->tx_len < 0x20)
+ s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
+ (value >> (s->ac_width << 3)) & 0xff;
+ s->intreq &= ~INT_TXFIFO_REQ;
+ pxa2xx_mmci_fifo_update(s);
+ break;
+
+ case MMC_RDWAIT:
+ case MMC_BLKS_REM:
+ break;
+
+ default:
+ cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+ __FUNCTION__, offset);
+ }
+}
+
+static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 1;
+ return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 2;
+ return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 4;
+ return pxa2xx_mmci_read(opaque, offset);
+}
+
+static CPUReadMemoryFunc *pxa2xx_mmci_readfn[] = {
+ pxa2xx_mmci_readb,
+ pxa2xx_mmci_readh,
+ pxa2xx_mmci_readw
+};
+
+static void pxa2xx_mmci_writeb(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 1;
+ pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writeh(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 2;
+ pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writew(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+ s->ac_width = 4;
+ pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = {
+ pxa2xx_mmci_writeb,
+ pxa2xx_mmci_writeh,
+ pxa2xx_mmci_writew
+};
+
+struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
+ void *pic, void *dma)
+{
+ int iomemtype;
+ struct pxa2xx_mmci_s *s;
+
+ s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s));
+ s->base = base;
+ s->pic = pic;
+ s->dma = dma;
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn,
+ pxa2xx_mmci_writefn, s);
+ cpu_register_physical_memory(base, 0x000fffff, iomemtype);
+
+ /* Instantiate the actual storage */
+ s->card = sd_init();
+
+ return s;
+}
+
+void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque,
+ void (*readonly_cb)(void *, int),
+ void (*coverswitch_cb)(void *, int))
+{
+ sd_set_cb(s->card, opaque, readonly_cb, coverswitch_cb);
+}
diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c
new file mode 100644
index 0000000..68dc492
--- /dev/null
+++ b/hw/pxa2xx_pcmcia.c
@@ -0,0 +1,230 @@
+/*
+ * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+
+struct pxa2xx_pcmcia_s {
+ struct pcmcia_socket_s slot;
+ struct pcmcia_card_s *card;
+ target_phys_addr_t common_base;
+ target_phys_addr_t attr_base;
+ target_phys_addr_t io_base;
+
+ void *pic;
+ int irq;
+ int cd_irq;
+ void (*set_irq)(void *opaque, int line, int level);
+};
+
+static uint32_t pxa2xx_pcmcia_common_read(void *opaque,
+ target_phys_addr_t offset)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->common_base;
+ return s->card->common_read(s->card->state, offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_pcmcia_common_write(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->common_base;
+ s->card->common_write(s->card->state, offset, value);
+ }
+}
+
+static uint32_t pxa2xx_pcmcia_attr_read(void *opaque,
+ target_phys_addr_t offset)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->attr_base;
+ return s->card->attr_read(s->card->state, offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_pcmcia_attr_write(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->attr_base;
+ s->card->attr_write(s->card->state, offset, value);
+ }
+}
+
+static uint32_t pxa2xx_pcmcia_io_read(void *opaque,
+ target_phys_addr_t offset)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->io_base;
+ return s->card->io_read(s->card->state, offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_pcmcia_io_write(void *opaque,
+ target_phys_addr_t offset, uint32_t value)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+ if (s->slot.attached) {
+ offset -= s->io_base;
+ s->card->io_write(s->card->state, offset, value);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_common_readfn[] = {
+ pxa2xx_pcmcia_common_read,
+ pxa2xx_pcmcia_common_read,
+ pxa2xx_pcmcia_common_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_common_writefn[] = {
+ pxa2xx_pcmcia_common_write,
+ pxa2xx_pcmcia_common_write,
+ pxa2xx_pcmcia_common_write,
+};
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_attr_readfn[] = {
+ pxa2xx_pcmcia_attr_read,
+ pxa2xx_pcmcia_attr_read,
+ pxa2xx_pcmcia_attr_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_attr_writefn[] = {
+ pxa2xx_pcmcia_attr_write,
+ pxa2xx_pcmcia_attr_write,
+ pxa2xx_pcmcia_attr_write,
+};
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_io_readfn[] = {
+ pxa2xx_pcmcia_io_read,
+ pxa2xx_pcmcia_io_read,
+ pxa2xx_pcmcia_io_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_io_writefn[] = {
+ pxa2xx_pcmcia_io_write,
+ pxa2xx_pcmcia_io_write,
+ pxa2xx_pcmcia_io_write,
+};
+
+static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+ if (!s->set_irq)
+ return;
+
+ s->set_irq(s->pic, s->irq, level);
+}
+
+struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base)
+{
+ int iomemtype;
+ struct pxa2xx_pcmcia_s *s;
+
+ s = (struct pxa2xx_pcmcia_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_pcmcia_s));
+
+ /* Socket I/O Memory Space */
+ s->io_base = base | 0x00000000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn,
+ pxa2xx_pcmcia_io_writefn, s);
+ cpu_register_physical_memory(s->io_base, 0x03ffffff, iomemtype);
+
+ /* Then next 64 MB is reserved */
+
+ /* Socket Attribute Memory Space */
+ s->attr_base = base | 0x08000000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn,
+ pxa2xx_pcmcia_attr_writefn, s);
+ cpu_register_physical_memory(s->attr_base, 0x03ffffff, iomemtype);
+
+ /* Socket Common Memory Space */
+ s->common_base = base | 0x0c000000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn,
+ pxa2xx_pcmcia_common_writefn, s);
+ cpu_register_physical_memory(s->common_base, 0x03ffffff, iomemtype);
+
+ if (base == 0x30000000)
+ s->slot.slot_string = "PXA PC Card Socket 1";
+ else
+ s->slot.slot_string = "PXA PC Card Socket 0";
+ s->slot.opaque = s;
+ s->slot.set_irq = pxa2xx_pcmcia_set_irq;
+ pcmcia_socket_register(&s->slot);
+ return s;
+}
+
+/* Insert a new card into a slot */
+int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+ if (s->slot.attached)
+ return -EEXIST;
+
+ if (s->set_irq) {
+ s->set_irq(s->pic, s->cd_irq, 1);
+ }
+
+ s->card = card;
+
+ s->slot.attached = 1;
+ s->card->slot = &s->slot;
+ s->card->attach(s->card->state);
+
+ return 0;
+}
+
+/* Eject card from the slot */
+int pxa2xx_pcmcia_dettach(void *opaque)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+ if (!s->slot.attached)
+ return -ENOENT;
+
+ s->card->detach(s->card->state);
+ s->card->slot = 0;
+ s->card = 0;
+
+ s->slot.attached = 0;
+
+ if (s->set_irq) {
+ s->set_irq(s->pic, s->irq, 0);
+ s->set_irq(s->pic, s->cd_irq, 0);
+ }
+
+ return 0;
+}
+
+/* Who to notify on card events */
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, void (*set_irq)(void *opaque,
+ int line, int level), int irq, int cd_irq, void *pic)
+{
+ struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+ s->set_irq = set_irq;
+ s->pic = pic;
+ s->irq = irq;
+ s->cd_irq = cd_irq;
+}
diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h
new file mode 100644
index 0000000..341be12
--- /dev/null
+++ b/hw/pxa2xx_template.h
@@ -0,0 +1,431 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to) to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from) *(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24
+# define COPY_PIXEL(to, from) \
+ *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from) *(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS 1
+#endif
+
+#define FN_2(x) FN(x + 1) FN(x)
+#define FN_4(x) FN_2(x + 2) FN_2(x)
+
+static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+ FN_4(12)
+ FN_4(8)
+ FN_4(4)
+ FN_4(0)
+#else
+ FN_4(0)
+ FN_4(4)
+ FN_4(8)
+ FN_4(12)
+#endif
+#undef FN
+ width -= 16;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+ FN_2(6)
+ FN_2(4)
+ FN_2(2)
+ FN_2(0)
+#else
+ FN_2(0)
+ FN_2(2)
+ FN_2(4)
+ FN_2(6)
+#endif
+#undef FN
+ width -= 8;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+ FN(24)
+ FN(16)
+ FN(8)
+ FN(0)
+#else
+ FN(0)
+ FN(8)
+ FN(16)
+ FN(24)
+#endif
+#undef FN
+ width -= 4;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ if (data & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ data >>= 1;
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x1f) << 3;
+ if (data & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x3f) << 2;
+ data >>= 6;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x3f) << 2;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data[3];
+ unsigned int r, g, b;
+ while (width > 0) {
+ data[0] = *(uint32_t *) src;
+ src += 4;
+ data[1] = *(uint32_t *) src;
+ src += 4;
+ data[2] = *(uint32_t *) src;
+ src += 4;
+#ifdef SWAP_WORDS
+ data[0] = bswap32(data[0]);
+ data[1] = bswap32(data[1]);
+ data[2] = bswap32(data[2]);
+#endif
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ r = (data[0] & 0x3f) << 2;
+ data[0] >>= 12;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+ data[1] >>= 4;
+ r = (data[1] & 0x3f) << 2;
+ data[1] >>= 12;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ b = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ g = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+ data[2] >>= 8;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ b = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ g = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ r = data[2] << 2;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x3f) << 2;
+ data >>= 6;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x3f) << 2;
+ data >>= 6;
+ if (data & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data[3];
+ unsigned int r, g, b;
+ while (width > 0) {
+ data[0] = *(uint32_t *) src;
+ src += 4;
+ data[1] = *(uint32_t *) src;
+ src += 4;
+ data[2] = *(uint32_t *) src;
+ src += 4;
+# ifdef SWAP_WORDS
+ data[0] = bswap32(data[0]);
+ data[1] = bswap32(data[1]);
+ data[2] = bswap32(data[2]);
+# endif
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ r = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ if (data[0] & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ data[0] >>= 6;
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+ data[1] >>= 4;
+ r = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ if (data[1] & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ data[1] >>= 6;
+ b = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ g = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+ data[2] >>= 2;
+ if (data[2] & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ data[2] >>= 6;
+ b = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ g = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ r = data[2] << 2;
+ data[2] >>= 6;
+ if (data[2] & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = data & 0xff;
+ data >>= 8;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x7f) << 1;
+ data >>= 7;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ data >>= 8;
+ if (data & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = data & 0xff;
+ data >>= 8;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ data >>= 8;
+ if (data & 1)
+ SKIP_PIXEL(dest);
+ else
+ COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* Overlay planes disabled, no transparency */
+static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
+{
+ [0 ... 0xf] = 0,
+ [pxa_lcdc_2bpp] = glue(pxa2xx_draw_line2_, BITS),
+ [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
+ [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
+ [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16_, BITS),
+ [pxa_lcdc_18bpp] = glue(pxa2xx_draw_line18_, BITS),
+ [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
+ [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24_, BITS),
+};
+
+/* Overlay planes enabled, transparency used */
+static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
+{
+ [0 ... 0xf] = 0,
+ [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
+ [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
+ [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16t_, BITS),
+ [pxa_lcdc_19bpp] = glue(pxa2xx_draw_line19_, BITS),
+ [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
+ [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24t_, BITS),
+ [pxa_lcdc_25bpp] = glue(pxa2xx_draw_line25_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
new file mode 100644
index 0000000..5eff01a
--- /dev/null
+++ b/hw/pxa2xx_timer.c
@@ -0,0 +1,437 @@
+/*
+ * Intel XScale PXA255/270 OS Timers.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+#define OSMR0 0x00
+#define OSMR1 0x04
+#define OSMR2 0x08
+#define OSMR3 0x0c
+#define OSMR4 0x80
+#define OSMR5 0x84
+#define OSMR6 0x88
+#define OSMR7 0x8c
+#define OSMR8 0x90
+#define OSMR9 0x94
+#define OSMR10 0x98
+#define OSMR11 0x9c
+#define OSCR 0x10 /* OS Timer Count */
+#define OSCR4 0x40
+#define OSCR5 0x44
+#define OSCR6 0x48
+#define OSCR7 0x4c
+#define OSCR8 0x50
+#define OSCR9 0x54
+#define OSCR10 0x58
+#define OSCR11 0x5c
+#define OSSR 0x14 /* Timer status register */
+#define OWER 0x18
+#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
+#define OMCR4 0xc0 /* OS Match Control registers */
+#define OMCR5 0xc4
+#define OMCR6 0xc8
+#define OMCR7 0xcc
+#define OMCR8 0xd0
+#define OMCR9 0xd4
+#define OMCR10 0xd8
+#define OMCR11 0xdc
+#define OSNR 0x20
+
+#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
+#define PXA27X_FREQ 3250000 /* 3.25 MHz */
+
+static int pxa2xx_timer4_freq[8] = {
+ [0] = 0,
+ [1] = 32768,
+ [2] = 1000,
+ [3] = 1,
+ [4] = 1000000,
+ /* [5] is the "Externally supplied clock". Assign if necessary. */
+ [5 ... 7] = 0,
+};
+
+struct pxa2xx_timer0_s {
+ uint32_t value;
+ int level;
+ int irq;
+ void *pic;
+ QEMUTimer *qtimer;
+ int num;
+ void *info;
+};
+
+struct pxa2xx_timer4_s {
+ uint32_t value;
+ int level;
+ int irq;
+ void *pic;
+ QEMUTimer *qtimer;
+ int num;
+ void *info;
+ int32_t oldclock;
+ int32_t clock;
+ uint64_t lastload;
+ uint32_t freq;
+ uint32_t control;
+};
+
+typedef struct {
+ uint32_t base;
+ int32_t clock;
+ int32_t oldclock;
+ uint64_t lastload;
+ uint32_t freq;
+ struct pxa2xx_timer0_s timer[4];
+ struct pxa2xx_timer4_s *tm4;
+ uint32_t events;
+ uint32_t irq_enabled;
+ uint32_t reset3;
+ CPUState *cpustate;
+ int64_t qemu_ticks;
+ uint32_t snapshot;
+} pxa2xx_timer_info;
+
+static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
+{
+ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ int i;
+ uint32_t now_vm;
+ uint64_t new_qemu;
+
+ now_vm = s->clock +
+ muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec);
+
+ for (i = 0; i < 4; i ++) {
+ new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
+ ticks_per_sec, s->freq);
+ qemu_mod_timer(s->timer[i].qtimer, new_qemu);
+ }
+}
+
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ uint32_t now_vm;
+ uint64_t new_qemu;
+ static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+ int counter;
+
+ if (s->tm4[n].control & (1 << 7))
+ counter = n;
+ else
+ counter = counters[n];
+
+ if (!s->tm4[counter].freq) {
+ qemu_del_timer(s->timer[n].qtimer);
+ return;
+ }
+
+ now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+ s->tm4[counter].lastload,
+ s->tm4[counter].freq, ticks_per_sec);
+
+ new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].value - now_vm),
+ ticks_per_sec, s->tm4[counter].freq);
+ qemu_mod_timer(s->timer[n].qtimer, new_qemu);
+}
+
+static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
+{
+ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ int tm = 0;
+
+ offset -= s->base;
+
+ switch (offset) {
+ case OSMR3: tm ++;
+ case OSMR2: tm ++;
+ case OSMR1: tm ++;
+ case OSMR0:
+ return s->timer[tm].value;
+ case OSMR11: tm ++;
+ case OSMR10: tm ++;
+ case OSMR9: tm ++;
+ case OSMR8: tm ++;
+ case OSMR7: tm ++;
+ case OSMR6: tm ++;
+ case OSMR5: tm ++;
+ case OSMR4:
+ if (!s->tm4)
+ goto badreg;
+ return s->tm4[tm].value;
+ case OSCR:
+ return s->clock + muldiv64(qemu_get_clock(vm_clock) -
+ s->lastload, s->freq, ticks_per_sec);
+ case OSCR11: tm ++;
+ case OSCR10: tm ++;
+ case OSCR9: tm ++;
+ case OSCR8: tm ++;
+ case OSCR7: tm ++;
+ case OSCR6: tm ++;
+ case OSCR5: tm ++;
+ case OSCR4:
+ if (!s->tm4)
+ goto badreg;
+
+ if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+ if (s->tm4[tm - 1].freq)
+ s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+ qemu_get_clock(vm_clock) -
+ s->tm4[tm - 1].lastload,
+ s->tm4[tm - 1].freq, ticks_per_sec);
+ else
+ s->snapshot = s->tm4[tm - 1].clock;
+ }
+
+ if (!s->tm4[tm].freq)
+ return s->tm4[tm].clock;
+ return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
+ s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
+ case OIER:
+ return s->irq_enabled;
+ case OSSR: /* Status register */
+ return s->events;
+ case OWER:
+ return s->reset3;
+ case OMCR11: tm ++;
+ case OMCR10: tm ++;
+ case OMCR9: tm ++;
+ case OMCR8: tm ++;
+ case OMCR7: tm ++;
+ case OMCR6: tm ++;
+ case OMCR5: tm ++;
+ case OMCR4:
+ if (!s->tm4)
+ goto badreg;
+ return s->tm4[tm].control;
+ case OSNR:
+ return s->snapshot;
+ default:
+ badreg:
+ cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
+ REG_FMT "\n", offset);
+ }
+
+ return 0;
+}
+
+static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ int i, tm = 0;
+ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+
+ offset -= s->base;
+
+ switch (offset) {
+ case OSMR3: tm ++;
+ case OSMR2: tm ++;
+ case OSMR1: tm ++;
+ case OSMR0:
+ s->timer[tm].value = value;
+ pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
+ break;
+ case OSMR11: tm ++;
+ case OSMR10: tm ++;
+ case OSMR9: tm ++;
+ case OSMR8: tm ++;
+ case OSMR7: tm ++;
+ case OSMR6: tm ++;
+ case OSMR5: tm ++;
+ case OSMR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].value = value;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ break;
+ case OSCR:
+ s->oldclock = s->clock;
+ s->lastload = qemu_get_clock(vm_clock);
+ s->clock = value;
+ pxa2xx_timer_update(s, s->lastload);
+ break;
+ case OSCR11: tm ++;
+ case OSCR10: tm ++;
+ case OSCR9: tm ++;
+ case OSCR8: tm ++;
+ case OSCR7: tm ++;
+ case OSCR6: tm ++;
+ case OSCR5: tm ++;
+ case OSCR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].oldclock = s->tm4[tm].clock;
+ s->tm4[tm].lastload = qemu_get_clock(vm_clock);
+ s->tm4[tm].clock = value;
+ pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+ break;
+ case OIER:
+ s->irq_enabled = value & 0xfff;
+ break;
+ case OSSR: /* Status register */
+ s->events &= ~value;
+ for (i = 0; i < 4; i ++, value >>= 1) {
+ if (s->timer[i].level && (value & 1)) {
+ s->timer[i].level = 0;
+ pic_set_irq_new(s->timer[i].pic, s->timer[i].irq, 0);
+ }
+ }
+ if (s->tm4) {
+ for (i = 0; i < 8; i ++, value >>= 1)
+ if (s->tm4[i].level && (value & 1))
+ s->tm4[i].level = 0;
+ if (!(s->events & 0xff0))
+ pic_set_irq_new(s->tm4->pic, s->tm4->irq, 0);
+ }
+ break;
+ case OWER: /* XXX: Reset on OSMR3 match? */
+ s->reset3 = value;
+ break;
+ case OMCR7: tm ++;
+ case OMCR6: tm ++;
+ case OMCR5: tm ++;
+ case OMCR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].control = value & 0x0ff;
+ /* XXX Stop if running (shouldn't happen) */
+ if ((value & (1 << 7)) || tm == 0)
+ s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+ else {
+ s->tm4[tm].freq = 0;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ }
+ break;
+ case OMCR11: tm ++;
+ case OMCR10: tm ++;
+ case OMCR9: tm ++;
+ case OMCR8: tm += 4;
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].control = value & 0x3ff;
+ /* XXX Stop if running (shouldn't happen) */
+ if ((value & (1 << 7)) || !(tm & 1))
+ s->tm4[tm].freq =
+ pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
+ else {
+ s->tm4[tm].freq = 0;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ }
+ break;
+ default:
+ badreg:
+ cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
+ REG_FMT "\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = {
+ pxa2xx_timer_read,
+ pxa2xx_timer_read,
+ pxa2xx_timer_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
+ pxa2xx_timer_write,
+ pxa2xx_timer_write,
+ pxa2xx_timer_write,
+};
+
+static void pxa2xx_timer_tick(void *opaque)
+{
+ struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
+ pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+
+ if (i->irq_enabled & (1 << t->num)) {
+ t->level = 1;
+ i->events |= 1 << t->num;
+ pic_set_irq_new(t->pic, t->irq, 1);
+ }
+
+ if (t->num == 3)
+ if (i->reset3 & 1) {
+ i->reset3 = 0;
+ cpu_reset(i->cpustate);
+ }
+}
+
+static void pxa2xx_timer_tick4(void *opaque)
+{
+ struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
+ pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+
+ pxa2xx_timer_tick4(opaque);
+ if (t->control & (1 << 3))
+ t->clock = 0;
+ if (t->control & (1 << 6))
+ pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->num - 4);
+}
+
+static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
+ void *pic, int irq, CPUState *cpustate)
+{
+ int i;
+ int iomemtype;
+ pxa2xx_timer_info *s;
+
+ s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
+ s->base = base;
+ s->irq_enabled = 0;
+ s->oldclock = 0;
+ s->clock = 0;
+ s->lastload = qemu_get_clock(vm_clock);
+ s->reset3 = 0;
+ s->cpustate = cpustate;
+
+ for (i = 0; i < 4; i ++) {
+ s->timer[i].value = 0;
+ s->timer[i].irq = irq + i;
+ s->timer[i].pic = pic;
+ s->timer[i].info = s;
+ s->timer[i].num = i;
+ s->timer[i].level = 0;
+ s->timer[i].qtimer = qemu_new_timer(vm_clock,
+ pxa2xx_timer_tick, &s->timer[i]);
+ }
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn,
+ pxa2xx_timer_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ return s;
+}
+
+void pxa25x_timer_init(target_phys_addr_t base,
+ void *pic, int irq, CPUState *cpustate)
+{
+ pxa2xx_timer_info *s = pxa2xx_timer_init(base, pic, irq, cpustate);
+ s->freq = PXA25X_FREQ;
+ s->tm4 = 0;
+}
+
+void pxa27x_timer_init(target_phys_addr_t base,
+ void *pic, int irq, int irq4, CPUState *cpustate)
+{
+ pxa2xx_timer_info *s = pxa2xx_timer_init(base, pic, irq, cpustate);
+ int i;
+ s->freq = PXA27X_FREQ;
+ s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
+ sizeof(struct pxa2xx_timer4_s));
+ for (i = 0; i < 8; i ++) {
+ s->tm4[i].value = 0;
+ s->tm4[i].irq = irq4;
+ s->tm4[i].pic = pic;
+ s->tm4[i].info = s;
+ s->tm4[i].num = i + 4;
+ s->tm4[i].level = 0;
+ s->tm4[i].freq = 0;
+ s->tm4[i].control = 0x0;
+ s->tm4[i].qtimer = qemu_new_timer(vm_clock,
+ pxa2xx_timer_tick4, &s->tm4[i]);
+ }
+}
diff --git a/vl.c b/vl.c
index a22ef95..281e541 100644
--- a/vl.c
+++ b/vl.c
@@ -186,6 +186,7 @@ int fd_bootchk = 1;
int no_reboot = 0;
int snapshot = 0;
const char *sd_filename = 0;
+int graphic_rotate = 0;
int daemonize = 0;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
@@ -521,6 +522,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
QEMUPutMouseEvent *mouse_event;
void *mouse_event_opaque;
+ int width;
if (!qemu_put_mouse_event_current) {
return;
@@ -532,7 +534,16 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
qemu_put_mouse_event_current->qemu_put_mouse_event_opaque;
if (mouse_event) {
- mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
+ if (graphic_rotate) {
+ if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)
+ width = 0x7fff;
+ else
+ width = graphic_width;
+ mouse_event(mouse_event_opaque,
+ width - dy, dx, dz, buttons_state);
+ } else
+ mouse_event(mouse_event_opaque,
+ dx, dy, dz, buttons_state);
}
}
@@ -6420,6 +6431,7 @@ void help(void)
"-m megs set virtual RAM size to megs MB [default=%d]\n"
"-smp n set the number of CPUs to 'n' [default=1]\n"
"-nographic disable graphical output and redirect serial I/Os to console\n"
+ "-portrait rotate graphical output 90 deg left (only PXA LCD)\n"
#ifndef _WIN32
"-k language use keyboard layout (for example \"fr\" for French)\n"
#endif
@@ -6552,6 +6564,7 @@ enum {
#endif
QEMU_OPTION_m,
QEMU_OPTION_nographic,
+ QEMU_OPTION_portrait,
#ifdef HAS_AUDIO
QEMU_OPTION_audio_help,
QEMU_OPTION_soundhw,
@@ -6629,6 +6642,7 @@ const QEMUOption qemu_options[] = {
#endif
{ "m", HAS_ARG, QEMU_OPTION_m },
{ "nographic", 0, QEMU_OPTION_nographic },
+ { "portrait", 0, QEMU_OPTION_portrait },
{ "k", HAS_ARG, QEMU_OPTION_k },
#ifdef HAS_AUDIO
{ "audio-help", 0, QEMU_OPTION_audio_help },
@@ -7133,6 +7147,9 @@ int main(int argc, char **argv)
pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
nographic = 1;
break;
+ case QEMU_OPTION_portrait:
+ graphic_rotate = 1;
+ break;
case QEMU_OPTION_kernel:
kernel_filename = optarg;
break;
diff --git a/vl.h b/vl.h
index 453e78d..c4d66d8 100644
--- a/vl.h
+++ b/vl.h
@@ -158,6 +158,7 @@ extern int usb_enabled;
extern int smp_cpus;
extern int snapshot;
extern const char *sd_filename;
+extern int graphic_rotate;
extern int no_quit;
extern int semihosting_enabled;
extern int autostart;
--
1.4.4.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [Qemu-devel] [PATCH] Add main PXA on-chip peripherals.
@ 2007-03-17 14:53 andrzej zaborowski
0 siblings, 0 replies; 2+ messages in thread
From: andrzej zaborowski @ 2007-03-17 14:53 UTC (permalink / raw)
To: qemu-devel
This adds the remaining on-chip peripherals of the PXA2xx:
- MMC/SD host.
- PCMCIA sockets.
- System timers.
- LCD controller. For the LCD I added the "-portrait" switch that
rotates the display 90 degrees left. This is for the Spitz machine
(clamshell based PDA) that can work in the two display modes. The
rotation can be changed in runtime when machine code decides so, for
example signaled by the OS through a GPIO. When the screen is being
rotated, the mouse clicks coordinates are also rotated so the guest OS
doesn't have to recalibrate input devices (i.e touchscreen).
[Apparently, this patch is too big for the list software, this time I
uploaded it at http://students.mimuw.edu.pl/~az258116/0007-Add-main-PXA-on-chip-peripherals.txt
instead of attaching. All 17 files I sent yesterday are in
http://students.mimuw.edu.pl/~az258116/qemu-pxa-patches.tar Sorry for
inconvenience]
Cheers,
Andrew
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-03-17 14:54 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-17 14:53 [Qemu-devel] [PATCH] Add main PXA on-chip peripherals andrzej zaborowski
-- strict thread matches above, loose matches on Subject: below --
2007-03-16 21:19 andrzej zaborowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).