qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [4213] Add basic OMAP2 chip support.


From: Andrzej Zaborowski
Subject: [Qemu-devel] [4213] Add basic OMAP2 chip support.
Date: Mon, 14 Apr 2008 21:05:23 +0000

Revision: 4213
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4213
Author:   balrog
Date:     2008-04-14 21:05:22 +0000 (Mon, 14 Apr 2008)

Log Message:
-----------
Add basic OMAP2 chip support.

Add the OMAP242x (arm1136 core) initialisation with basic on-chip
peripherals and update OMAP1 peripherals which are re-used in OMAP2.
Make palmte.c and sd.c errors go to stderr.
Allow disabling SD chipselect.

Modified Paths:
--------------
    trunk/Makefile.target
    trunk/hw/omap.h
    trunk/hw/omap1.c
    trunk/hw/omap_clk.c
    trunk/hw/omap_dma.c
    trunk/hw/omap_i2c.c
    trunk/hw/omap_mmc.c
    trunk/hw/palm.c
    trunk/hw/sd.c
    trunk/hw/sd.h
    trunk/target-arm/cpu.h
    trunk/target-arm/helper.c

Added Paths:
-----------
    trunk/hw/omap2.c
    trunk/hw/omap_dss.c

Modified: trunk/Makefile.target
===================================================================
--- trunk/Makefile.target       2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/Makefile.target       2008-04-14 21:05:22 UTC (rev 4213)
@@ -610,6 +610,7 @@
 OBJS+= pflash_cfi01.o gumstix.o
 OBJS+= spitz.o ide.o serial.o nand.o ecc.o
 OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
+OBJS+= omap2.o omap_dss.o
 OBJS+= palm.o tsc210x.o
 OBJS+= mst_fpga.o mainstone.o
 CPPFLAGS += -DHAS_AUDIO

Modified: trunk/hw/omap.h
===================================================================
--- trunk/hw/omap.h     2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap.h     2008-04-14 21:05:22 UTC (rev 4213)
@@ -5,8 +5,8 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,6 +22,7 @@
 # define hw_omap_h             "omap.h"
 
 # define OMAP_EMIFS_BASE       0x00000000
+# define OMAP2_Q0_BASE         0x00000000
 # define OMAP_CS0_BASE         0x00000000
 # define OMAP_CS1_BASE         0x04000000
 # define OMAP_CS2_BASE         0x08000000
@@ -29,18 +30,26 @@
 # define OMAP_EMIFF_BASE       0x10000000
 # define OMAP_IMIF_BASE                0x20000000
 # define OMAP_LOCALBUS_BASE    0x30000000
+# define OMAP2_Q1_BASE         0x40000000
+# define OMAP2_L4_BASE         0x48000000
+# define OMAP2_SRAM_BASE       0x40200000
+# define OMAP2_L3_BASE         0x68000000
+# define OMAP2_Q2_BASE         0x80000000
+# define OMAP2_Q3_BASE         0xc0000000
 # define OMAP_MPUI_BASE                0xe1000000
 
 # define OMAP730_SRAM_SIZE     0x00032000
 # define OMAP15XX_SRAM_SIZE    0x00030000
 # define OMAP16XX_SRAM_SIZE    0x00004000
 # define OMAP1611_SRAM_SIZE    0x0003e800
+# define OMAP242X_SRAM_SIZE    0x000a0000
+# define OMAP243X_SRAM_SIZE    0x00010000
 # define OMAP_CS0_SIZE         0x04000000
 # define OMAP_CS1_SIZE         0x04000000
 # define OMAP_CS2_SIZE         0x04000000
 # define OMAP_CS3_SIZE         0x04000000
 
-/* omap1_clk.c */
+/* omap_clk.c */
 struct omap_mpu_state_s;
 typedef struct clk *omap_clk;
 omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name);
@@ -55,15 +64,42 @@
 void omap_clk_reparent(omap_clk clk, omap_clk parent);
 
 /* omap[123].c */
+struct omap_l4_s;
+struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num);
+
+struct omap_target_agent_s;
+struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs);
+target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
+                int iotype);
+
 struct omap_intr_handler_s;
 struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks,
+                unsigned long size, unsigned char nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
+struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+                int size, int nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq,
+                omap_clk fclk, omap_clk iclk);
+void omap_inth_reset(struct omap_intr_handler_s *s);
 
-struct omap_target_agent_s;
-static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
-                int region, int iotype) { return 0; }
+struct omap_prcm_s;
+struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
+                qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
+                struct omap_mpu_state_s *mpu);
 
+struct omap_sysctl_s;
+struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
+                omap_clk iclk, struct omap_mpu_state_s *mpu);
+
+struct omap_sdrc_s;
+struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
+
+struct omap_gpmc_s;
+struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq);
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
+                void (*base_upd)(void *opaque, target_phys_addr_t new),
+                void (*unmap)(void *opaque), void *opaque);
+
 /*
  * Common IRQ numbers for level 1 interrupt handler
  * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
@@ -295,10 +331,20 @@
  * OMAP-24xx common IRQ numbers
  */
 # define OMAP_INT_24XX_SYS_NIRQ                7
+# define OMAP_INT_24XX_L3_IRQ          10
+# define OMAP_INT_24XX_PRCM_MPU_IRQ    11
 # define OMAP_INT_24XX_SDMA_IRQ0       12
 # define OMAP_INT_24XX_SDMA_IRQ1       13
 # define OMAP_INT_24XX_SDMA_IRQ2       14
 # define OMAP_INT_24XX_SDMA_IRQ3       15
+# define OMAP_INT_243X_MCBSP2_IRQ      16
+# define OMAP_INT_243X_MCBSP3_IRQ      17
+# define OMAP_INT_243X_MCBSP4_IRQ      18
+# define OMAP_INT_243X_MCBSP5_IRQ      19
+# define OMAP_INT_24XX_GPMC_IRQ                20
+# define OMAP_INT_24XX_GUFFAW_IRQ      21
+# define OMAP_INT_24XX_IVA_IRQ         22
+# define OMAP_INT_24XX_EAC_IRQ         23
 # define OMAP_INT_24XX_CAM_IRQ         24
 # define OMAP_INT_24XX_DSS_IRQ         25
 # define OMAP_INT_24XX_MAIL_U0_MPU     26
@@ -308,8 +354,10 @@
 # define OMAP_INT_24XX_GPIO_BANK2      30
 # define OMAP_INT_24XX_GPIO_BANK3      31
 # define OMAP_INT_24XX_GPIO_BANK4      32
-# define OMAP_INT_24XX_GPIO_BANK5      33
+# define OMAP_INT_243X_GPIO_BANK5      33
 # define OMAP_INT_24XX_MAIL_U3_MPU     34
+# define OMAP_INT_24XX_WDT3            35
+# define OMAP_INT_24XX_WDT4            36
 # define OMAP_INT_24XX_GPTIMER1                37
 # define OMAP_INT_24XX_GPTIMER2                38
 # define OMAP_INT_24XX_GPTIMER3                39
@@ -322,10 +370,24 @@
 # define OMAP_INT_24XX_GPTIMER10       46
 # define OMAP_INT_24XX_GPTIMER11       47
 # define OMAP_INT_24XX_GPTIMER12       48
+# define OMAP_INT_24XX_PKA_IRQ         50
+# define OMAP_INT_24XX_SHA1MD5_IRQ     51
+# define OMAP_INT_24XX_RNG_IRQ         52
+# define OMAP_INT_24XX_MG_IRQ          53
+# define OMAP_INT_24XX_I2C1_IRQ                56
+# define OMAP_INT_24XX_I2C2_IRQ                57
 # define OMAP_INT_24XX_MCBSP1_IRQ_TX   59
 # define OMAP_INT_24XX_MCBSP1_IRQ_RX   60
 # define OMAP_INT_24XX_MCBSP2_IRQ_TX   62
 # define OMAP_INT_24XX_MCBSP2_IRQ_RX   63
+# define OMAP_INT_243X_MCBSP1_IRQ      64
+# define OMAP_INT_24XX_MCSPI1_IRQ      65
+# define OMAP_INT_24XX_MCSPI2_IRQ      66
+# define OMAP_INT_24XX_SSI1_IRQ0       67
+# define OMAP_INT_24XX_SSI1_IRQ1       68
+# define OMAP_INT_24XX_SSI2_IRQ0       69
+# define OMAP_INT_24XX_SSI2_IRQ1       70
+# define OMAP_INT_24XX_SSI_GDD_IRQ     71
 # define OMAP_INT_24XX_UART1_IRQ       72
 # define OMAP_INT_24XX_UART2_IRQ       73
 # define OMAP_INT_24XX_UART3_IRQ       74
@@ -335,10 +397,15 @@
 # define OMAP_INT_24XX_USB_IRQ_HGEN    78
 # define OMAP_INT_24XX_USB_IRQ_HSOF    79
 # define OMAP_INT_24XX_USB_IRQ_OTG     80
+# define OMAP_INT_24XX_VLYNQ_IRQ       81
 # define OMAP_INT_24XX_MMC_IRQ         83
+# define OMAP_INT_24XX_MS_IRQ          84
+# define OMAP_INT_24XX_FAC_IRQ         85
+# define OMAP_INT_24XX_MCSPI3_IRQ      91
 # define OMAP_INT_243X_HS_USB_MC       92
 # define OMAP_INT_243X_HS_USB_DMA      93
 # define OMAP_INT_243X_CARKIT          94
+# define OMAP_INT_34XX_GPTIMER12       95
 
 /* omap_dma.c */
 enum omap_dma_model {
@@ -352,6 +419,9 @@
 struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
                 qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
                 enum omap_dma_model model);
+struct omap_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk);
 void omap_dma_reset(struct omap_dma_s *s);
 
 struct dma_irq_map {
@@ -367,7 +437,7 @@
     tipb,
     local,     /* omap16xx: ocp_t2 */
     tipb_mpui,
-    omap_dma_port_last,
+    __omap_dma_port_last,
 };
 
 typedef enum {
@@ -488,11 +558,83 @@
 # define OMAP_DMA_MMC2_RX              55
 # define OMAP_DMA_CRYPTO_DES_OUT       56
 
+/*
+ * DMA request numbers for the OMAP2
+ */
+# define OMAP24XX_DMA_NO_DEVICE                0
+# define OMAP24XX_DMA_XTI_DMA          1       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ0      2
+# define OMAP24XX_DMA_EXT_DMAREQ1      3
+# define OMAP24XX_DMA_GPMC             4
+# define OMAP24XX_DMA_GFX              5       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DSS              6
+# define OMAP24XX_DMA_VLYNQ_TX         7       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_CWT              8       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_TX           9       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_RX           10      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_TX           11      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_RX           12      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_SHA1MD5_RX       13      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ2      14
+# define OMAP24XX_DMA_EXT_DMAREQ3      15
+# define OMAP24XX_DMA_EXT_DMAREQ4      16
+# define OMAP24XX_DMA_EAC_AC_RD                17
+# define OMAP24XX_DMA_EAC_AC_WR                18
+# define OMAP24XX_DMA_EAC_MD_UL_RD     19
+# define OMAP24XX_DMA_EAC_MD_UL_WR     20
+# define OMAP24XX_DMA_EAC_MD_DL_RD     21
+# define OMAP24XX_DMA_EAC_MD_DL_WR     22
+# define OMAP24XX_DMA_EAC_BT_UL_RD     23
+# define OMAP24XX_DMA_EAC_BT_UL_WR     24
+# define OMAP24XX_DMA_EAC_BT_DL_RD     25
+# define OMAP24XX_DMA_EAC_BT_DL_WR     26
+# define OMAP24XX_DMA_I2C1_TX          27
+# define OMAP24XX_DMA_I2C1_RX          28
+# define OMAP24XX_DMA_I2C2_TX          29
+# define OMAP24XX_DMA_I2C2_RX          30
+# define OMAP24XX_DMA_MCBSP1_TX                31
+# define OMAP24XX_DMA_MCBSP1_RX                32
+# define OMAP24XX_DMA_MCBSP2_TX                33
+# define OMAP24XX_DMA_MCBSP2_RX                34
+# define OMAP24XX_DMA_SPI1_TX0         35
+# define OMAP24XX_DMA_SPI1_RX0         36
+# define OMAP24XX_DMA_SPI1_TX1         37
+# define OMAP24XX_DMA_SPI1_RX1         38
+# define OMAP24XX_DMA_SPI1_TX2         39
+# define OMAP24XX_DMA_SPI1_RX2         40
+# define OMAP24XX_DMA_SPI1_TX3         41
+# define OMAP24XX_DMA_SPI1_RX3         42
+# define OMAP24XX_DMA_SPI2_TX0         43
+# define OMAP24XX_DMA_SPI2_RX0         44
+# define OMAP24XX_DMA_SPI2_TX1         45
+# define OMAP24XX_DMA_SPI2_RX1         46
+
+# define OMAP24XX_DMA_UART1_TX         49
+# define OMAP24XX_DMA_UART1_RX         50
+# define OMAP24XX_DMA_UART2_TX         51
+# define OMAP24XX_DMA_UART2_RX         52
+# define OMAP24XX_DMA_UART3_TX         53
+# define OMAP24XX_DMA_UART3_RX         54
+# define OMAP24XX_DMA_USB_W2FC_TX0     55
+# define OMAP24XX_DMA_USB_W2FC_RX0     56
+# define OMAP24XX_DMA_USB_W2FC_TX1     57
+# define OMAP24XX_DMA_USB_W2FC_RX1     58
+# define OMAP24XX_DMA_USB_W2FC_TX2     59
+# define OMAP24XX_DMA_USB_W2FC_RX2     60
+# define OMAP24XX_DMA_MMC1_TX          61
+# define OMAP24XX_DMA_MMC1_RX          62
+# define OMAP24XX_DMA_MS               63      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ5      64
+
 /* omap[123].c */
 struct omap_mpu_timer_s;
 struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk);
 
+struct omap_gp_timer_s;
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk);
+
 struct omap_watchdog_timer_s;
 struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk);
@@ -501,13 +643,21 @@
 struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk);
 
+void omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
+
 struct omap_tipb_bridge_s;
 struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
                 qemu_irq abort_irq, omap_clk clk);
 
 struct omap_uart_s;
 struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
-                qemu_irq irq, omap_clk clk, CharDriverState *chr);
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+void omap_uart_reset(struct omap_uart_s *s);
 
 struct omap_mpuio_s;
 struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
@@ -523,6 +673,12 @@
 qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
 void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
 
+struct omap_gpif_s;
+struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
+qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
+void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
+
 struct uwire_slave_s {
     uint16_t (*receive)(void *opaque);
     void (*send)(void *opaque, uint16_t data);
@@ -534,6 +690,13 @@
 void omap_uwire_attach(struct omap_uwire_s *s,
                 struct uwire_slave_s *slave, int chipselect);
 
+struct omap_mcspi_s;
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t), void *opaque,
+                int chipselect);
+
 struct omap_rtc_s;
 struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
                 qemu_irq *irq, omap_clk clk);
@@ -570,6 +733,9 @@
 struct omap_lpg_s;
 struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk);
 
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu);
+
 /* omap_lcdc.c */
 struct omap_lcd_panel_s;
 void omap_lcdc_reset(struct omap_lcd_panel_s *s);
@@ -577,13 +743,33 @@
                 struct omap_dma_lcd_channel_s *dma, DisplayState *ds,
                 ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
 
+/* omap_dss.c */
+struct rfbi_chip_s {
+    void *opaque;
+    void (*write)(void *opaque, int dc, uint16_t value);
+    void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
+    uint16_t (*read)(void *opaque, int dc);
+};
+struct omap_dss_s;
+void omap_dss_reset(struct omap_dss_s *s);
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                target_phys_addr_t l3_base, DisplayState *ds,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2);
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
+
 /* omap_mmc.c */
 struct omap_mmc_s;
 struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
                 BlockDriverState *bd,
                 qemu_irq irq, qemu_irq dma[], omap_clk clk);
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk);
 void omap_mmc_reset(struct omap_mmc_s *s);
 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
+void omap_mmc_enable(struct omap_mmc_s *s, int enable);
 
 /* omap_i2c.c */
 struct omap_i2c_s;
@@ -596,14 +782,37 @@
 
 # define cpu_is_omap310(cpu)           (cpu->mpu_model == omap310)
 # define cpu_is_omap1510(cpu)          (cpu->mpu_model == omap1510)
+# define cpu_is_omap1610(cpu)          (cpu->mpu_model == omap1610)
+# define cpu_is_omap1710(cpu)          (cpu->mpu_model == omap1710)
+# define cpu_is_omap2410(cpu)          (cpu->mpu_model == omap2410)
+# define cpu_is_omap2420(cpu)          (cpu->mpu_model == omap2420)
+# define cpu_is_omap2430(cpu)          (cpu->mpu_model == omap2430)
+# define cpu_is_omap3430(cpu)          (cpu->mpu_model == omap3430)
+
 # define cpu_is_omap15xx(cpu)          \
         (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
-# define cpu_class_omap1(cpu)          1
+# define cpu_is_omap16xx(cpu)          \
+        (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
+# define cpu_is_omap24xx(cpu)          \
+        (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
 
+# define cpu_class_omap1(cpu)          \
+        (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
+# define cpu_class_omap2(cpu)          cpu_is_omap24xx(cpu)
+# define cpu_class_omap3(cpu)          cpu_is_omap3430(cpu)
+
 struct omap_mpu_state_s {
-    enum omap1_mpu_model {
+    enum omap_mpu_model {
         omap310,
         omap1510,
+        omap1610,
+        omap1710,
+        omap2410,
+        omap2420,
+        omap2422,
+        omap2423,
+        omap2430,
+        omap3430,
     } mpu_model;
 
     CPUState *env;
@@ -620,7 +829,7 @@
                         target_phys_addr_t offset, uint32_t value);
         int (*addr_valid)(struct omap_mpu_state_s *s,
                         target_phys_addr_t addr);
-    } port[omap_dma_port_last];
+    } port[__omap_dma_port_last];
 
     unsigned long sdram_size;
     unsigned long sram_size;
@@ -656,7 +865,7 @@
         omap_clk clk;
     } pwt;
 
-    struct omap_i2c_s *i2c;
+    struct omap_i2c_s *i2c[2];
 
     struct omap_rtc_s *rtc;
 
@@ -722,9 +931,40 @@
         uint16_t dsp_idlect2;
         uint16_t dsp_rstct2;
     } clkm;
-} *omap310_mpu_init(unsigned long sdram_size,
+
+    /* OMAP2-only peripherals */
+    struct omap_l4_s *l4;
+
+    struct omap_gp_timer_s *gptimer[12];
+
+    target_phys_addr_t tap_base;
+
+    struct omap_synctimer_s {
+        target_phys_addr_t base;
+        uint32_t val;
+        uint16_t readh;
+    } synctimer;
+
+    struct omap_prcm_s *prcm;
+    struct omap_sdrc_s *sdrc;
+    struct omap_gpmc_s *gpmc;
+    struct omap_sysctl_s *sysc;
+
+    struct omap_gpif_s *gpif;
+
+    struct omap_mcspi_s *mcspi[2];
+
+    struct omap_dss_s *dss;
+};
+
+/* omap1.c */
+struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
                 DisplayState *ds, const char *core);
 
+/* omap2.c */
+struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
+                DisplayState *ds, const char *core);
+
 # if TARGET_PHYS_ADDR_BITS == 32
 #  define OMAP_FMT_plx "%#08x"
 # elif TARGET_PHYS_ADDR_BITS == 64
@@ -743,24 +983,46 @@
 void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
                 uint32_t value);
 
+void omap_mpu_wakeup(void *opaque, int irq, int req);
+
 # define OMAP_BAD_REG(paddr)           \
-        printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr)
+        fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \
+                        __FUNCTION__, paddr)
 # define OMAP_RO_REG(paddr)            \
-        printf("%s: Read-only register " OMAP_FMT_plx "\n",    \
+        fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n",   \
                         __FUNCTION__, paddr)
 
+/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
+   (Board-specifc tags are not here)  */
+#define OMAP_TAG_CLOCK         0x4f01
+#define OMAP_TAG_MMC           0x4f02
+#define OMAP_TAG_SERIAL_CONSOLE        0x4f03
+#define OMAP_TAG_USB           0x4f04
+#define OMAP_TAG_LCD           0x4f05
+#define OMAP_TAG_GPIO_SWITCH   0x4f06
+#define OMAP_TAG_UART          0x4f07
+#define OMAP_TAG_FBMEM         0x4f08
+#define OMAP_TAG_STI_CONSOLE   0x4f09
+#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
+#define OMAP_TAG_PARTITION     0x4f0b
+#define OMAP_TAG_TEA5761       0x4f10
+#define OMAP_TAG_TMP105                0x4f11
+#define OMAP_TAG_BOOT_REASON   0x4f80
+#define OMAP_TAG_FLASH_PART_STR        0x4f81
+#define OMAP_TAG_VERSION_STR   0x4f82
+
 # define TCMI_VERBOSE                  1
 //# define MEM_VERBOSE                 1
 
 # ifdef TCMI_VERBOSE
 #  define OMAP_8B_REG(paddr)           \
-        printf("%s: 8-bit register " OMAP_FMT_plx "\n",        \
+        fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n",       \
                         __FUNCTION__, paddr)
 #  define OMAP_16B_REG(paddr)          \
-        printf("%s: 16-bit register " OMAP_FMT_plx "\n",       \
+        fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n",      \
                         __FUNCTION__, paddr)
 #  define OMAP_32B_REG(paddr)          \
-        printf("%s: 32-bit register " OMAP_FMT_plx "\n",       \
+        fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n",      \
                         __FUNCTION__, paddr)
 # else
 #  define OMAP_8B_REG(paddr)

Modified: trunk/hw/omap1.c
===================================================================
--- trunk/hw/omap1.c    2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap1.c    2008-04-14 21:05:22 UTC (rev 4213)
@@ -5,8 +5,8 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,10 +23,11 @@
 #include "omap.h"
 #include "sysemu.h"
 #include "qemu-timer.h"
+#include "qemu-char.h"
 /* We use pc-style serial ports.  */
 #include "pc.h"
 
-/* Should signal the TCMI */
+/* Should signal the TCMI/GPMC */
 uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
 {
     uint8_t ret;
@@ -86,6 +87,7 @@
     uint32_t mask;
     uint32_t fiq;
     uint32_t sens_edge;
+    uint32_t swi;
     unsigned char priority[32];
 };
 
@@ -94,11 +96,14 @@
     qemu_irq parent_intr[2];
     target_phys_addr_t base;
     unsigned char nbanks;
+    int level_only;
 
     /* state */
     uint32_t new_agr[2];
     int sir_intr[2];
-    struct omap_intr_handler_bank_s banks[];
+    int autoidle;
+    uint32_t mask;
+    struct omap_intr_handler_bank_s bank[];
 };
 
 static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
@@ -113,11 +118,11 @@
      * If all interrupts have the same priority, the default order is IRQ_N,
      * IRQ_N-1,...,IRQ_0. */
     for (j = 0; j < s->nbanks; ++j) {
-        level = s->banks[j].irqs & ~s->banks[j].mask &
-                (is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq);
+        level = s->bank[j].irqs & ~s->bank[j].mask &
+                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
         for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
                         level >>= f) {
-            p = s->banks[j].priority[i];
+            p = s->bank[j].priority[i];
             if (p <= p_intr) {
                 p_intr = p;
                 sir_intr = 32 * j + i;
@@ -134,10 +139,10 @@
     uint32_t has_intr = 0;
 
     for (i = 0; i < s->nbanks; ++i)
-        has_intr |= s->banks[i].irqs & ~s->banks[i].mask &
-                (is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq);
+        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
+                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
 
-    if (s->new_agr[is_fiq] && has_intr) {
+    if (s->new_agr[is_fiq] & has_intr & s->mask) {
         s->new_agr[is_fiq] = 0;
         omap_inth_sir_update(s, is_fiq);
         qemu_set_irq(s->parent_intr[is_fiq], 1);
@@ -152,13 +157,13 @@
     struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
     uint32_t rise;
 
-    struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5];
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
     int n = irq & 31;
 
     if (req) {
         rise = ~bank->irqs & (1 << n);
         if (~bank->sens_edge & (1 << n))
-            rise &= ~bank->inputs & (1 << n);
+            rise &= ~bank->inputs;
 
         bank->inputs |= (1 << n);
         if (rise) {
@@ -173,13 +178,33 @@
     }
 }
 
+/* Simplified version with no edge detection */
+static void omap_set_intr_noedge(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->inputs & (1 << n);
+        if (rise) {
+            bank->irqs |= bank->inputs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else
+        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
+}
+
 static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr - s->base;
     int bank_no = offset >> 8;
     int line_no;
-    struct omap_intr_handler_bank_s *bank = &s->banks[bank_no];
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
     offset &= 0xff;
 
     switch (offset) {
@@ -194,7 +219,7 @@
         if (bank_no != 0)
             break;
         line_no = s->sir_intr[(offset - 0x10) >> 2];
-        bank = &s->banks[line_no >> 5];
+        bank = &s->bank[line_no >> 5];
         i = line_no & 31;
         if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
             bank->irqs &= ~(1 << i);
@@ -256,7 +281,7 @@
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr - s->base;
     int bank_no = offset >> 8;
-    struct omap_intr_handler_bank_s *bank = &s->banks[bank_no];
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
     offset &= 0xff;
 
     switch (offset) {
@@ -360,25 +385,31 @@
     int i;
 
     for (i = 0; i < s->nbanks; ++i){
-        s->banks[i].irqs = 0x00000000;
-        s->banks[i].mask = 0xffffffff;
-        s->banks[i].sens_edge = 0x00000000;
-        s->banks[i].fiq = 0x00000000;
-        s->banks[i].inputs = 0x00000000;
-        memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority));
+        s->bank[i].irqs = 0x00000000;
+        s->bank[i].mask = 0xffffffff;
+        s->bank[i].sens_edge = 0x00000000;
+        s->bank[i].fiq = 0x00000000;
+        s->bank[i].inputs = 0x00000000;
+        s->bank[i].swi = 0x00000000;
+        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
+
+        if (s->level_only)
+            s->bank[i].sens_edge = 0xffffffff;
     }
 
     s->new_agr[0] = ~0;
     s->new_agr[1] = ~0;
     s->sir_intr[0] = 0;
     s->sir_intr[1] = 0;
+    s->autoidle = 0;
+    s->mask = ~0;
 
     qemu_set_irq(s->parent_intr[0], 0);
     qemu_set_irq(s->parent_intr[1], 0);
 }
 
 struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks,
+                unsigned long size, unsigned char nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
 {
     int iomemtype;
@@ -391,6 +422,8 @@
     s->base = base;
     s->nbanks = nbanks;
     s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
+    if (pins)
+        *pins = s->pins;
 
     omap_inth_reset(s);
 
@@ -401,6 +434,227 @@
     return s;
 }
 
+static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr - s->base;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = 0;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        }
+    }
+
+    switch (offset) {
+    case 0x00: /* INTC_REVISION */
+        return 0x21;
+
+    case 0x10: /* INTC_SYSCONFIG */
+        return (s->autoidle >> 2) & 1;
+
+    case 0x14: /* INTC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* INTC_SIR_IRQ */
+        return s->sir_intr[0];
+
+    case 0x44: /* INTC_SIR_FIQ */
+        return s->sir_intr[1];
+
+    case 0x48: /* INTC_CONTROL */
+        return (!s->mask) << 2;                                        /* 
GLOBALMASK */
+
+    case 0x4c: /* INTC_PROTECTION */
+        return 0;
+
+    case 0x50: /* INTC_IDLE */
+        return s->autoidle & 3;
+
+    /* Per-bank registers */
+    case 0x80: /* INTC_ITR */
+        return bank->inputs;
+
+    case 0x84: /* INTC_MIR */
+        return bank->mask;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+    case 0x8c: /* INTC_MIR_SET */
+        return 0;
+
+    case 0x90: /* INTC_ISR_SET */
+        return bank->swi;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        return 0;
+
+    case 0x98: /* INTC_PENDING_IRQ */
+        return bank->irqs & ~bank->mask & ~bank->fiq;
+
+    case 0x9c: /* INTC_PENDING_FIQ */
+        return bank->irqs & ~bank->mask & bank->fiq;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        return (bank->priority[line_no] << 2) |
+                ((bank->fiq >> line_no) & 1);
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr - s->base;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = 0;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        }
+    }
+
+    switch (offset) {
+    case 0x10: /* INTC_SYSCONFIG */
+        s->autoidle &= 4;
+        s->autoidle |= (value & 1) << 2;
+        if (value & 2)                                         /* SOFTRESET */
+            omap_inth_reset(s);
+        return;
+
+    case 0x48: /* INTC_CONTROL */
+        s->mask = (value & 4) ? 0 : ~0;                                /* 
GLOBALMASK */
+        if (value & 2) {                                       /* NEWFIQAGR */
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {                                       /* NEWIRQAGR */
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x4c: /* INTC_PROTECTION */
+        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
+         * for every register, see Chapter 3 and 4 for privileged mode.  */
+        if (value & 1)
+            fprintf(stderr, "%s: protection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+
+    case 0x50: /* INTC_IDLE */
+        s->autoidle &= ~3;
+        s->autoidle |= value & 3;
+        return;
+
+    /* Per-bank registers */
+    case 0x84: /* INTC_MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+        bank->mask &= ~value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x8c: /* INTC_MIR_SET */
+        bank->mask |= value;
+        return;
+
+    case 0x90: /* INTC_ISR_SET */
+        bank->irqs |= bank->swi |= value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        bank->swi &= ~value;
+        bank->irqs = bank->swi & bank->inputs;
+        return;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        bank->priority[line_no] = (value >> 2) & 0x3f;
+        bank->fiq &= ~(1 << line_no);
+        bank->fiq |= (value & 1) << line_no;
+        return;
+
+    case 0x00: /* INTC_REVISION */
+    case 0x14: /* INTC_SYSSTATUS */
+    case 0x40: /* INTC_SIR_IRQ */
+    case 0x44: /* INTC_SIR_FIQ */
+    case 0x80: /* INTC_ITR */
+    case 0x98: /* INTC_PENDING_IRQ */
+    case 0x9c: /* INTC_PENDING_FIQ */
+        OMAP_RO_REG(addr);
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc *omap2_inth_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap2_inth_read,
+};
+
+static CPUWriteMemoryFunc *omap2_inth_writefn[] = {
+    omap2_inth_write,
+    omap2_inth_write,
+    omap2_inth_write,
+};
+
+struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+                int size, int nbanks, qemu_irq **pins,
+                qemu_irq parent_irq, qemu_irq parent_fiq,
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
+            qemu_mallocz(sizeof(struct omap_intr_handler_s) +
+                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
+
+    s->parent_intr[0] = parent_irq;
+    s->parent_intr[1] = parent_fiq;
+    s->base = base;
+    s->nbanks = nbanks;
+    s->level_only = 1;
+    s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
+    if (pins)
+        *pins = s->pins;
+
+    omap_inth_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap2_inth_readfn,
+                    omap2_inth_writefn, s);
+    cpu_register_physical_memory(s->base, size, iomemtype);
+
+    return s;
+}
+
 /* MPU OS timers */
 struct omap_mpu_timer_s {
     qemu_irq irq;
@@ -1289,6 +1543,8 @@
             return 0x03310315;
         case omap1510:
             return 0x03310115;
+        default:
+            cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__);
         }
         break;
 
@@ -1298,6 +1554,8 @@
             return 0xfb57402f;
         case omap1510:
             return 0xfb47002f;
+        default:
+            cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__);
         }
         break;
     }
@@ -1722,22 +1980,119 @@
 /* UARTs */
 struct omap_uart_s {
     SerialState *serial; /* TODO */
+    struct omap_target_agent_s *ta;
+    target_phys_addr_t base;
+
+    uint8_t eblr;
+    uint8_t syscontrol;
+    uint8_t wkup;
+    uint8_t cfps;
 };
 
-static void omap_uart_reset(struct omap_uart_s *s)
+void omap_uart_reset(struct omap_uart_s *s)
 {
+    s->eblr = 0x00;
+    s->syscontrol = 0;
+    s->wkup = 0x3f;
+    s->cfps = 0x69;
 }
 
 struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
-                qemu_irq irq, omap_clk clk, CharDriverState *chr)
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
 {
     struct omap_uart_s *s = (struct omap_uart_s *)
             qemu_mallocz(sizeof(struct omap_uart_s));
-    if (chr)
-        s->serial = serial_mm_init(base, 2, irq, chr, 1);
+
+    s->serial = serial_mm_init(base, 2, irq, chr ?: qemu_chr_open("null"), 1);
+
     return s;
 }
 
+static uint32_t omap_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x48: /* EBLR */
+        return s->eblr;
+    case 0x50: /* MVR */
+        return 0x30;
+    case 0x54: /* SYSC */
+        return s->syscontrol;
+    case 0x58: /* SYSS */
+        return 1;
+    case 0x5c: /* WER */
+        return s->wkup;
+    case 0x60: /* CFPS */
+        return s->cfps;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_uart_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x48: /* EBLR */
+        s->eblr = value & 0xff;
+        break;
+    case 0x50: /* MVR */
+    case 0x58: /* SYSS */
+        OMAP_RO_REG(addr);
+        break;
+    case 0x54: /* SYSC */
+        s->syscontrol = value & 0x1d;
+        if (value & 2)
+            omap_uart_reset(s);
+        break;
+    case 0x5c: /* WER */
+        s->wkup = value & 0x7f;
+        break;
+    case 0x60: /* CFPS */
+        s->cfps = value & 0xff;
+        break;
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_uart_readfn[] = {
+    omap_uart_read,
+    omap_uart_read,
+    omap_badwidth_read8,
+};
+
+static CPUWriteMemoryFunc *omap_uart_writefn[] = {
+    omap_uart_write,
+    omap_uart_write,
+    omap_badwidth_write8,
+};
+
+struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
+{
+    target_phys_addr_t base = omap_l4_attach(ta, 0, 0);
+    struct omap_uart_s *s = omap_uart_init(base, irq,
+                    fclk, iclk, txdma, rxdma, chr);
+    int iomemtype = cpu_register_io_memory(0, omap_uart_readfn,
+                    omap_uart_writefn, s);
+
+    s->ta = ta;
+    s->base = base;
+
+    cpu_register_physical_memory(s->base + 0x20, 0x100, iomemtype);
+
+    return s;
+}
+
 /* MPU Clock/Reset/Power Mode Control */
 static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr)
 {
@@ -2778,9 +3133,10 @@
 void omap_uwire_attach(struct omap_uwire_s *s,
                 struct uwire_slave_s *slave, int chipselect)
 {
-    if (chipselect < 0 || chipselect > 3)
-        cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", __FUNCTION__,
-                        chipselect);
+    if (chipselect < 0 || chipselect > 3) {
+        fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
+        exit(-1);
+    }
 
     s->chip[chipselect] = slave;
 }
@@ -4123,7 +4479,7 @@
 }
 
 /* General chip reset */
-static void omap_mpu_reset(void *opaque)
+static void omap1_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
@@ -4153,7 +4509,7 @@
     omap_uwire_reset(mpu->microwire);
     omap_pwl_reset(mpu);
     omap_pwt_reset(mpu);
-    omap_i2c_reset(mpu->i2c);
+    omap_i2c_reset(mpu->i2c[0]);
     omap_rtc_reset(mpu->rtc);
     omap_mcbsp_reset(mpu->mcbsp1);
     omap_mcbsp_reset(mpu->mcbsp2);
@@ -4205,7 +4561,7 @@
     }
 }
 
-static void omap_mpu_wakeup(void *opaque, int irq, int req)
+void omap_mpu_wakeup(void *opaque, int irq, int req)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
@@ -4213,7 +4569,7 @@
         cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB);
 }
 
-static const struct dma_irq_map omap_dma_irq_map[] = {
+static const struct dma_irq_map omap1_dma_irq_map[] = {
     { 0, OMAP_INT_DMA_CH0_6 },
     { 0, OMAP_INT_DMA_CH1_7 },
     { 0, OMAP_INT_DMA_CH2_8 },
@@ -4307,17 +4663,16 @@
     omap_clkm_init(0xfffece00, 0xe1008000, s);
 
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1,
+    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
                     cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
                     omap_findclk(s, "arminth_ck"));
-    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1,
+    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1],
                     s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL,
                     omap_findclk(s, "arminth_ck"));
-    s->irq[0] = s->ih[0]->pins;
-    s->irq[1] = s->ih[1]->pins;
 
     for (i = 0; i < 6; i ++)
-        dma_irqs[i] = s->irq[omap_dma_irq_map[i].ih][omap_dma_irq_map[i].intr];
+        dma_irqs[i] =
+                s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr];
     s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
                            s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
 
@@ -4367,12 +4722,18 @@
 
     s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
                     omap_findclk(s, "uart1_ck"),
+                    omap_findclk(s, "uart1_ck"),
+                    s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
                     serial_hds[0]);
     s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
                     omap_findclk(s, "uart2_ck"),
+                    omap_findclk(s, "uart2_ck"),
+                    s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
                     serial_hds[0] ? serial_hds[1] : 0);
     s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3],
                     omap_findclk(s, "uart3_ck"),
+                    omap_findclk(s, "uart3_ck"),
+                    s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0);
 
     omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
@@ -4401,7 +4762,7 @@
     omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck"));
     omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck"));
 
-    s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
+    s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
                     &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
 
     s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
@@ -4435,7 +4796,7 @@
     omap_setup_dsp_mapping(omap15xx_dsp_mm);
     omap_setup_mpui_io(s);
 
-    qemu_register_reset(omap_mpu_reset, s);
+    qemu_register_reset(omap1_mpu_reset, s);
 
     return s;
 }

Added: trunk/hw/omap2.c
===================================================================
--- trunk/hw/omap2.c                            (rev 0)
+++ trunk/hw/omap2.c    2008-04-14 21:05:22 UTC (rev 4213)
@@ -0,0 +1,3860 @@
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "flash.h"
+
+/* GP timers */
+struct omap_gp_timer_s {
+    qemu_irq irq;
+    qemu_irq wkup;
+    qemu_irq in;
+    qemu_irq out;
+    omap_clk clk;
+    target_phys_addr_t base;
+    QEMUTimer *timer;
+    QEMUTimer *match;
+    struct omap_target_agent_s *ta;
+
+    int in_val;
+    int out_val;
+    int64_t time;
+    int64_t rate;
+    int64_t ticks_per_sec;
+
+    int16_t config;
+    int status;
+    int it_ena;
+    int wu_ena;
+    int enable;
+    int inout;
+    int capt2;
+    int pt;
+    enum {
+        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
+    } trigger;
+    enum {
+        gpt_capture_none, gpt_capture_rising,
+        gpt_capture_falling, gpt_capture_both
+    } capture;
+    int scpwm;
+    int ce;
+    int pre;
+    int ptv;
+    int ar;
+    int st;
+    int posted;
+    uint32_t val;
+    uint32_t load_val;
+    uint32_t capture_val[2];
+    uint32_t match_val;
+    int capt_num;
+
+    uint16_t writeh;   /* LSB */
+    uint16_t readh;    /* MSB */
+};
+
+#define GPT_TCAR_IT    (1 << 2)
+#define GPT_OVF_IT     (1 << 1)
+#define GPT_MAT_IT     (1 << 0)
+
+static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
+{
+    if (timer->it_ena & it) {
+        if (!timer->status)
+            qemu_irq_raise(timer->irq);
+
+        timer->status |= it;
+        /* Or are the status bits set even when masked?
+         * i.e. is masking applied before or after the status register?  */
+    }
+
+    if (timer->wu_ena & it)
+        qemu_irq_pulse(timer->wkup);
+}
+
+static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
+{
+    if (!timer->inout && timer->out_val != level) {
+        timer->out_val = level;
+        qemu_set_irq(timer->out, level);
+    }
+}
+
+static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
+{
+    uint64_t distance;
+
+    if (timer->st && timer->rate) {
+        distance = qemu_get_clock(vm_clock) - timer->time;
+        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
+
+        if (distance >= 0xffffffff - timer->val)
+            return 0xffffffff;
+        else
+            return timer->val + distance;
+    } else
+        return timer->val;
+}
+
+static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
+{
+    if (timer->st) {
+        timer->val = omap_gp_timer_read(timer);
+        timer->time = qemu_get_clock(vm_clock);
+    }
+}
+
+static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
+{
+    int64_t expires, matches;
+
+    if (timer->st && timer->rate) {
+        expires = muldiv64(0x100000000ll - timer->val,
+                        timer->ticks_per_sec, timer->rate);
+        qemu_mod_timer(timer->timer, timer->time + expires);
+
+        if (timer->ce && timer->match_val >= timer->val) {
+            matches = muldiv64(timer->match_val - timer->val,
+                            timer->ticks_per_sec, timer->rate);
+            qemu_mod_timer(timer->match, timer->time + matches);
+        } else
+            qemu_del_timer(timer->match);
+    } else {
+        qemu_del_timer(timer->timer);
+        qemu_del_timer(timer->match);
+        omap_gp_timer_out(timer, timer->scpwm);
+    }
+}
+
+static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
+{
+    if (timer->pt)
+        /* TODO in overflow-and-match mode if the first event to
+         * occurs is the match, don't toggle.  */
+        omap_gp_timer_out(timer, !timer->out_val);
+    else
+        /* TODO inverted pulse on timer->out_val == 1?  */
+        qemu_irq_pulse(timer->out);
+}
+
+static void omap_gp_timer_tick(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (!timer->ar) {
+        timer->st = 0;
+        timer->val = 0;
+    } else {
+        timer->val = timer->load_val;
+        timer->time = qemu_get_clock(vm_clock);
+    }
+
+    if (timer->trigger == gpt_trigger_overflow ||
+                    timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_OVF_IT);
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_match(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_MAT_IT);
+}
+
+static void omap_gp_timer_input(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int trigger;
+
+    switch (s->capture) {
+    default:
+    case gpt_capture_none:
+        trigger = 0;
+        break;
+    case gpt_capture_rising:
+        trigger = !s->in_val && on;
+        break;
+    case gpt_capture_falling:
+        trigger = s->in_val && !on;
+        break;
+    case gpt_capture_both:
+        trigger = (s->in_val == !on);
+        break;
+    }
+    s->in_val = on;
+
+    if (s->inout && trigger && s->capt_num < 2) {
+        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
+
+        if (s->capt2 == s->capt_num ++)
+            omap_gp_timer_intr(s, GPT_TCAR_IT);
+    }
+}
+
+static void omap_gp_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    omap_gp_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+static void omap_gp_timer_reset(struct omap_gp_timer_s *s)
+{
+    s->config = 0x000;
+    s->status = 0;
+    s->it_ena = 0;
+    s->wu_ena = 0;
+    s->inout = 0;
+    s->capt2 = 0;
+    s->capt_num = 0;
+    s->pt = 0;
+    s->trigger = gpt_trigger_none;
+    s->capture = gpt_capture_none;
+    s->scpwm = 0;
+    s->ce = 0;
+    s->pre = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->posted = 1;
+    s->val = 0x00000000;
+    s->load_val = 0x00000000;
+    s->capture_val[0] = 0x00000000;
+    s->capture_val[1] = 0x00000000;
+    s->match_val = 0x00000000;
+    omap_gp_timer_update(s);
+}
+
+static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* TIDR */
+        return 0x21;
+
+    case 0x10: /* TIOCP_CFG */
+        return s->config;
+
+    case 0x14: /* TISTAT */
+        /* ??? When's this bit reset? */
+        return 1;                                              /* RESETDONE */
+
+    case 0x18: /* TISR */
+        return s->status;
+
+    case 0x1c: /* TIER */
+        return s->it_ena;
+
+    case 0x20: /* TWER */
+        return s->wu_ena;
+
+    case 0x24: /* TCLR */
+        return (s->inout << 14) |
+                (s->capt2 << 13) |
+                (s->pt << 12) |
+                (s->trigger << 10) |
+                (s->capture << 8) |
+                (s->scpwm << 7) |
+                (s->ce << 6) |
+                (s->pre << 5) |
+                (s->ptv << 2) |
+                (s->ar << 1) |
+                (s->st << 0);
+
+    case 0x28: /* TCRR */
+        return omap_gp_timer_read(s);
+
+    case 0x2c: /* TLDR */
+        return s->load_val;
+
+    case 0x30: /* TTGR */
+        return 0xffffffff;
+
+    case 0x34: /* TWPS */
+        return 0x00000000;     /* No posted writes pending.  */
+
+    case 0x38: /* TMAR */
+        return s->match_val;
+
+    case 0x3c: /* TCAR1 */
+        return s->capture_val[0];
+
+    case 0x40: /* TSICR */
+        return s->posted << 2;
+
+    case 0x44: /* TCAR2 */
+        return s->capture_val[1];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_gp_timer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static CPUReadMemoryFunc *omap_gp_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_gp_timer_readh,
+    omap_gp_timer_readw,
+};
+
+static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* TIDR */
+    case 0x14: /* TISTAT */
+    case 0x34: /* TWPS */
+    case 0x3c: /* TCAR1 */
+    case 0x44: /* TCAR2 */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* TIOCP_CFG */
+        s->config = value & 0x33d;
+        if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
+            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
+                            __FUNCTION__);
+        if (value & 2)                                         /* SOFTRESET */
+            omap_gp_timer_reset(s);
+        break;
+
+    case 0x18: /* TISR */
+        if (value & GPT_TCAR_IT)
+            s->capt_num = 0;
+        if (s->status && !(s->status &= ~value))
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x1c: /* TIER */
+        s->it_ena = value & 7;
+        break;
+
+    case 0x20: /* TWER */
+        s->wu_ena = value & 7;
+        break;
+
+    case 0x24: /* TCLR */
+        omap_gp_timer_sync(s);
+        s->inout = (value >> 14) & 1;
+        s->capt2 = (value >> 13) & 1;
+        s->pt = (value >> 12) & 1;
+        s->trigger = (value >> 10) & 3;
+        if (s->capture == gpt_capture_none &&
+                        ((value >> 8) & 3) != gpt_capture_none)
+            s->capt_num = 0;
+        s->capture = (value >> 8) & 3;
+        s->scpwm = (value >> 7) & 1;
+        s->ce = (value >> 6) & 1;
+        s->pre = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = (value >> 0) & 1;
+        if (s->inout && s->trigger != gpt_trigger_none)
+            fprintf(stderr, "%s: GP timer pin must be an output "
+                            "for this trigger mode\n", __FUNCTION__);
+        if (!s->inout && s->capture != gpt_capture_none)
+            fprintf(stderr, "%s: GP timer pin must be an input "
+                            "for this capture mode\n", __FUNCTION__);
+        if (s->trigger == gpt_trigger_none)
+            omap_gp_timer_out(s, s->scpwm);
+        /* TODO: make sure this doesn't overflow 32-bits */
+        s->ticks_per_sec = ticks_per_sec << (s->pre ? s->ptv + 1 : 0);
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x28: /* TCRR */
+        s->time = qemu_get_clock(vm_clock);
+        s->val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x2c: /* TLDR */
+        s->load_val = value;
+        break;
+
+    case 0x30: /* TTGR */
+        s->time = qemu_get_clock(vm_clock);
+        s->val = s->load_val;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x38: /* TMAR */
+        omap_gp_timer_sync(s);
+        s->match_val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x40: /* TSICR */
+        s->posted = (value >> 2) & 1;
+        if (value & 2) /* How much exactly are we supposed to reset? */
+            omap_gp_timer_reset(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    if (addr & 2)
+        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
+    else
+        s->writeh = (uint16_t) value;
+}
+
+static CPUWriteMemoryFunc *omap_gp_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_gp_timer_writeh,
+    omap_gp_timer_write,
+};
+
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
+            qemu_mallocz(sizeof(struct omap_gp_timer_s));
+
+    s->ta = ta;
+    s->irq = irq;
+    s->clk = fclk;
+    s->timer = qemu_new_timer(vm_clock, omap_gp_timer_tick, s);
+    s->match = qemu_new_timer(vm_clock, omap_gp_timer_match, s);
+    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
+    omap_gp_timer_reset(s);
+    omap_gp_timer_clk_setup(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_gp_timer_readfn,
+                    omap_gp_timer_writefn, s);
+    s->base = omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+/* 32-kHz Sync Timer of the OMAP2 */
+static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
+    return muldiv64(qemu_get_clock(vm_clock), 0x8000, ticks_per_sec);
+}
+
+static void omap_synctimer_reset(struct omap_synctimer_s *s)
+{
+    s->val = omap_synctimer_read(s);
+}
+
+static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* 32KSYNCNT_REV */
+        return 0x21;
+
+    case 0x10: /* CR */
+        return omap_synctimer_read(s) - s->val;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_synctimer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static CPUReadMemoryFunc *omap_synctimer_readfn[] = {
+    omap_badwidth_read32,
+    omap_synctimer_readh,
+    omap_synctimer_readw,
+};
+
+static void omap_synctimer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUWriteMemoryFunc *omap_synctimer_writefn[] = {
+    omap_badwidth_write32,
+    omap_synctimer_write,
+    omap_synctimer_write,
+};
+
+void omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_synctimer_s *s = &mpu->synctimer;
+
+    omap_synctimer_reset(s);
+    s->base = omap_l4_attach(ta, 0, cpu_register_io_memory(0,
+                            omap_synctimer_readfn, omap_synctimer_writefn, s));
+}
+
+/* General-Purpose Interface of OMAP2 */
+struct omap2_gpio_s {
+    target_phys_addr_t base;
+    qemu_irq irq[2];
+    qemu_irq wkup;
+    qemu_irq *in;
+    qemu_irq handler[32];
+
+    uint8_t config[2];
+    uint32_t inputs;
+    uint32_t outputs;
+    uint32_t dir;
+    uint32_t level[2];
+    uint32_t edge[2];
+    uint32_t mask[2];
+    uint32_t wumask;
+    uint32_t ints[2];
+    uint32_t debounce;
+    uint8_t delay;
+};
+
+static inline void omap_gpio_module_int_update(struct omap2_gpio_s *s,
+                int line)
+{
+    qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
+}
+
+static void omap_gpio_module_wake(struct omap2_gpio_s *s, int line)
+{
+    if (!(s->config[0] & (1 << 2)))                    /* ENAWAKEUP */
+        return;
+    if (!(s->config[0] & (3 << 3)))                    /* Force Idle */
+        return;
+    if (!(s->wumask & (1 << line)))
+        return;
+
+    qemu_irq_raise(s->wkup);
+}
+
+static inline void omap_gpio_module_out_update(struct omap2_gpio_s *s,
+                uint32_t diff)
+{
+    int ln;
+
+    s->outputs ^= diff;
+    diff &= ~s->dir;
+    while ((ln = ffs(diff))) {
+        ln --;
+        qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
+        diff &= ~(1 << ln);
+    }
+}
+
+static void omap_gpio_module_level_update(struct omap2_gpio_s *s, int line)
+{
+    s->ints[line] |= s->dir &
+            ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
+    omap_gpio_module_int_update(s, line);
+}
+
+static inline void omap_gpio_module_int(struct omap2_gpio_s *s, int line)
+{
+    s->ints[0] |= 1 << line;
+    omap_gpio_module_int_update(s, 0);
+    s->ints[1] |= 1 << line;
+    omap_gpio_module_int_update(s, 1);
+    omap_gpio_module_wake(s, line);
+}
+
+static void omap_gpio_module_set(void *opaque, int line, int level)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+
+    if (level) {
+        if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
+            omap_gpio_module_int(s, line);
+        s->inputs |= 1 << line;
+    } else {
+        if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
+            omap_gpio_module_int(s, line);
+        s->inputs &= ~(1 << line);
+    }
+}
+
+static void omap_gpio_module_reset(struct omap2_gpio_s *s)
+{
+    s->config[0] = 0;
+    s->config[1] = 2;
+    s->ints[0] = 0;
+    s->ints[1] = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+    s->wumask = 0;
+    s->dir = ~0;
+    s->level[0] = 0;
+    s->level[1] = 0;
+    s->edge[0] = 0;
+    s->edge[1] = 0;
+    s->debounce = 0;
+    s->delay = 0;
+}
+
+static uint32_t omap_gpio_module_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* GPIO_REVISION */
+        return 0x18;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+        return s->config[0];
+
+    case 0x14: /* GPIO_SYSSTATUS */
+        return 0x01;
+
+    case 0x18: /* GPIO_IRQSTATUS1 */
+        return s->ints[0];
+
+    case 0x1c: /* GPIO_IRQENABLE1 */
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+        return s->mask[0];
+
+    case 0x20: /* GPIO_WAKEUPENABLE */
+    case 0x80: /* GPIO_CLEARWKUENA */
+    case 0x84: /* GPIO_SETWKUENA */
+        return s->wumask;
+
+    case 0x28: /* GPIO_IRQSTATUS2 */
+        return s->ints[1];
+
+    case 0x2c: /* GPIO_IRQENABLE2 */
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+        return s->mask[1];
+
+    case 0x30: /* GPIO_CTRL */
+        return s->config[1];
+
+    case 0x34: /* GPIO_OE */
+        return s->dir;
+
+    case 0x38: /* GPIO_DATAIN */
+        return s->inputs;
+
+    case 0x3c: /* GPIO_DATAOUT */
+    case 0x90: /* GPIO_CLEARDATAOUT */
+    case 0x94: /* GPIO_SETDATAOUT */
+        return s->outputs;
+
+    case 0x40: /* GPIO_LEVELDETECT0 */
+        return s->level[0];
+
+    case 0x44: /* GPIO_LEVELDETECT1 */
+        return s->level[1];
+
+    case 0x48: /* GPIO_RISINGDETECT */
+        return s->edge[0];
+
+    case 0x4c: /* GPIO_FALLINGDETECT */
+        return s->edge[1];
+
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+        return s->debounce;
+
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        return s->delay;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    int offset = addr - s->base;
+    uint32_t diff;
+    int ln;
+
+    switch (offset) {
+    case 0x00: /* GPIO_REVISION */
+    case 0x14: /* GPIO_SYSSTATUS */
+    case 0x38: /* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+        if (((value >> 3) & 3) == 3)
+            fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
+        if (value & 2)
+            omap_gpio_module_reset(s);
+        s->config[0] = value & 0x1d;
+        break;
+
+    case 0x18: /* GPIO_IRQSTATUS1 */
+        if (s->ints[0] & value) {
+            s->ints[0] &= ~value;
+            omap_gpio_module_level_update(s, 0);
+        }
+        break;
+
+    case 0x1c: /* GPIO_IRQENABLE1 */
+        s->mask[0] = value;
+        omap_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x20: /* GPIO_WAKEUPENABLE */
+        s->wumask = value;
+        break;
+
+    case 0x28: /* GPIO_IRQSTATUS2 */
+        if (s->ints[1] & value) {
+            s->ints[1] &= ~value;
+            omap_gpio_module_level_update(s, 1);
+        }
+        break;
+
+    case 0x2c: /* GPIO_IRQENABLE2 */
+        s->mask[1] = value;
+        omap_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x30: /* GPIO_CTRL */
+        s->config[1] = value & 7;
+        break;
+
+    case 0x34: /* GPIO_OE */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            diff &= ~(1 <<-- ln);
+            qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+        }
+
+        omap_gpio_module_level_update(s, 0);
+        omap_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x3c: /* GPIO_DATAOUT */
+        omap_gpio_module_out_update(s, s->outputs ^ value);
+        break;
+
+    case 0x40: /* GPIO_LEVELDETECT0 */
+        s->level[0] = value;
+        omap_gpio_module_level_update(s, 0);
+        omap_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x44: /* GPIO_LEVELDETECT1 */
+        s->level[1] = value;
+        omap_gpio_module_level_update(s, 0);
+        omap_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x48: /* GPIO_RISINGDETECT */
+        s->edge[0] = value;
+        break;
+
+    case 0x4c: /* GPIO_FALLINGDETECT */
+        s->edge[1] = value;
+        break;
+
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+        s->debounce = value;
+        break;
+
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        s->delay = value;
+        break;
+
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+        s->mask[0] &= ~value;
+        omap_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+        s->mask[0] |= value;
+        omap_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+        s->mask[1] &= ~value;
+        omap_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+        s->mask[1] |= value;
+        omap_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x80: /* GPIO_CLEARWKUENA */
+        s->wumask &= ~value;
+        break;
+
+    case 0x84: /* GPIO_SETWKUENA */
+        s->wumask |= value;
+        break;
+
+    case 0x90: /* GPIO_CLEARDATAOUT */
+        omap_gpio_module_out_update(s, s->outputs & value);
+        break;
+
+    case 0x94: /* GPIO_SETDATAOUT */
+        omap_gpio_module_out_update(s, ~s->outputs & value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static uint32_t omap_gpio_module_readp(void *opaque, target_phys_addr_t addr)
+{
+    return omap_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3);
+}
+
+static void omap_gpio_module_writep(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    int offset = addr - s->base;
+    uint32_t cur = 0;
+    uint32_t mask = 0xffff;
+
+    switch (offset & ~3) {
+    case 0x00: /* GPIO_REVISION */
+    case 0x14: /* GPIO_SYSSTATUS */
+    case 0x38: /* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+    case 0x1c: /* GPIO_IRQENABLE1 */
+    case 0x20: /* GPIO_WAKEUPENABLE */
+    case 0x2c: /* GPIO_IRQENABLE2 */
+    case 0x30: /* GPIO_CTRL */
+    case 0x34: /* GPIO_OE */
+    case 0x3c: /* GPIO_DATAOUT */
+    case 0x40: /* GPIO_LEVELDETECT0 */
+    case 0x44: /* GPIO_LEVELDETECT1 */
+    case 0x48: /* GPIO_RISINGDETECT */
+    case 0x4c: /* GPIO_FALLINGDETECT */
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        cur = omap_gpio_module_read(opaque, addr & ~3) &
+                ~(mask << ((addr & 3) << 3));
+
+        /* Fall through.  */
+    case 0x18: /* GPIO_IRQSTATUS1 */
+    case 0x28: /* GPIO_IRQSTATUS2 */
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+    case 0x80: /* GPIO_CLEARWKUENA */
+    case 0x84: /* GPIO_SETWKUENA */
+    case 0x90: /* GPIO_CLEARDATAOUT */
+    case 0x94: /* GPIO_SETDATAOUT */
+        value <<= (addr & 3) << 3;
+        omap_gpio_module_write(opaque, addr, cur | value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_gpio_module_readfn[] = {
+    omap_gpio_module_readp,
+    omap_gpio_module_readp,
+    omap_gpio_module_read,
+};
+
+static CPUWriteMemoryFunc *omap_gpio_module_writefn[] = {
+    omap_gpio_module_writep,
+    omap_gpio_module_writep,
+    omap_gpio_module_write,
+};
+
+static void omap_gpio_module_init(struct omap2_gpio_s *s,
+                struct omap_target_agent_s *ta, int region,
+                qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+
+    s->irq[0] = mpu;
+    s->irq[1] = dsp;
+    s->wkup = wkup;
+    s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32);
+
+    iomemtype = cpu_register_io_memory(0, omap_gpio_module_readfn,
+                    omap_gpio_module_writefn, s);
+    s->base = omap_l4_attach(ta, region, iomemtype);
+}
+
+struct omap_gpif_s {
+    struct omap2_gpio_s module[5];
+    int modules;
+
+    target_phys_addr_t topbase;
+    int autoidle;
+    int gpo;
+};
+
+static void omap_gpif_reset(struct omap_gpif_s *s)
+{
+    int i;
+
+    for (i = 0; i < s->modules; i ++)
+        omap_gpio_module_reset(s->module + i);
+
+    s->autoidle = 0;
+    s->gpo = 0;
+}
+
+static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+    int offset = addr - s->topbase;
+
+    switch (offset) {
+    case 0x00: /* IPGENERICOCPSPL_REVISION */
+        return 0x18;
+
+    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
+        return 0x01;
+
+    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
+        return 0x00;
+
+    case 0x40: /* IPGENERICOCPSPL_GPO */
+        return s->gpo;
+
+    case 0x50: /* IPGENERICOCPSPL_GPI */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+    int offset = addr - s->topbase;
+
+    switch (offset) {
+    case 0x00: /* IPGENERICOCPSPL_REVISION */
+    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
+    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
+    case 0x50: /* IPGENERICOCPSPL_GPI */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
+        if (value & (1 << 1))                                  /* SOFTRESET */
+            omap_gpif_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40: /* IPGENERICOCPSPL_GPO */
+        s->gpo = value & 1;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_gpif_top_readfn[] = {
+    omap_gpif_top_read,
+    omap_gpif_top_read,
+    omap_gpif_top_read,
+};
+
+static CPUWriteMemoryFunc *omap_gpif_top_writefn[] = {
+    omap_gpif_top_write,
+    omap_gpif_top_write,
+    omap_gpif_top_write,
+};
+
+struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+                qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+{
+    int iomemtype, i;
+    struct omap_gpif_s *s = (struct omap_gpif_s *)
+            qemu_mallocz(sizeof(struct omap_gpif_s));
+    int region[4] = { 0, 2, 4, 5 };
+
+    s->modules = modules;
+    for (i = 0; i < modules; i ++)
+        omap_gpio_module_init(s->module + i, ta, region[i],
+                        irq[i], 0, 0, fclk[i], iclk);
+
+    omap_gpif_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_gpif_top_readfn,
+                    omap_gpif_top_writefn, s);
+    s->topbase = omap_l4_attach(ta, 1, iomemtype);
+
+    return s;
+}
+
+qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+{
+    if (start >= s->modules * 32 || start < 0)
+        cpu_abort(cpu_single_env, "%s: No GPIO line %i\n",
+                        __FUNCTION__, start);
+    return s->module[start >> 5].in + (start & 31);
+}
+
+void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
+{
+    if (line >= s->modules * 32 || line < 0)
+        cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line);
+    s->module[line >> 5].handler[line & 31] = handler;
+}
+
+/* Multichannel SPI */
+struct omap_mcspi_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    int chnum;
+
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t wken;
+    uint32_t control;
+
+    struct omap_mcspi_ch_s {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t);
+        void *opaque;
+
+        uint32_t tx;
+        uint32_t rx;
+
+        uint32_t config;
+        uint32_t status;
+        uint32_t control;
+    } ch[4];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
+{
+    qemu_set_irq(ch->txdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 14)) &&                /* DMAW */
+                    (ch->status & (1 << 1)) &&         /* TXS */
+                    ((ch->config >> 12) & 3) != 1);    /* TRM */
+    qemu_set_irq(ch->rxdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 15)) &&                /* DMAW */
+                    (ch->status & (1 << 0)) &&         /* RXS */
+                    ((ch->config >> 12) & 3) != 2);    /* TRM */
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+    struct omap_mcspi_ch_s *ch = s->ch + chnum;
+
+    if (!(ch->control & 1))                            /* EN */
+        return;
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        goto intr_update;
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        goto intr_update;
+
+    if (!(s->control & 1) ||                           /* SINGLE */
+                    (ch->config & (1 << 20))) {                /* FORCE */
+        if (ch->txrx)
+            ch->rx = ch->txrx(ch->opaque, ch->tx);
+    }
+
+    ch->tx = 0;
+    ch->status |= 1 << 2;                              /* EOT */
+    ch->status |= 1 << 1;                              /* TXS */
+    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
+        ch->status |= 1 << 0;                          /* RXS */
+
+intr_update:
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
+    omap_mcspi_interrupt_update(s);
+    omap_mcspi_dmarequest_update(ch);
+}
+
+static void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+    int ch;
+
+    s->sysconfig = 0;
+    s->systest = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->wken = 0;
+    s->control = 4;
+
+    for (ch = 0; ch < 4; ch ++) {
+        s->ch[ch].config = 0x060000;
+        s->ch[ch].status = 2;                          /* TXS */
+        s->ch[ch].control = 0;
+
+        omap_mcspi_dmarequest_update(s->ch + ch);
+    }
+
+    omap_mcspi_interrupt_update(s);
+}
+
+static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int offset = addr - s->base;
+    int ch = 0;
+    uint32_t ret;
+
+    switch (offset) {
+    case 0x00: /* MCSPI_REVISION */
+        return 0x91;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x14: /* MCSPI_SYSSTATUS */
+        return 1;                                      /* RESETDONE */
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        return s->irqst;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        return s->irqen;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        return s->wken;
+
+    case 0x24: /* MCSPI_SYST */
+        return s->systest;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        return s->control;
+
+    case 0x68: ch ++;
+    case 0x54: ch ++;
+    case 0x40: ch ++;
+    case 0x2c: /* MCSPI_CHCONF */
+        return s->ch[ch].config;
+
+    case 0x6c: ch ++;
+    case 0x58: ch ++;
+    case 0x44: ch ++;
+    case 0x30: /* MCSPI_CHSTAT */
+        return s->ch[ch].status;
+
+    case 0x70: ch ++;
+    case 0x5c: ch ++;
+    case 0x48: ch ++;
+    case 0x34: /* MCSPI_CHCTRL */
+        return s->ch[ch].control;
+
+    case 0x74: ch ++;
+    case 0x60: ch ++;
+    case 0x4c: ch ++;
+    case 0x38: /* MCSPI_TX */
+        return s->ch[ch].tx;
+
+    case 0x78: ch ++;
+    case 0x64: ch ++;
+    case 0x50: ch ++;
+    case 0x3c: /* MCSPI_RX */
+        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
+        ret = s->ch[ch].rx;
+        omap_mcspi_transfer_run(s, ch);
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int offset = addr - s->base;
+    int ch = 0;
+
+    switch (offset) {
+    case 0x00: /* MCSPI_REVISION */
+    case 0x14: /* MCSPI_SYSSTATUS */
+    case 0x30: /* MCSPI_CHSTAT0 */
+    case 0x3c: /* MCSPI_RX0 */
+    case 0x44: /* MCSPI_CHSTAT1 */
+    case 0x50: /* MCSPI_RX1 */
+    case 0x58: /* MCSPI_CHSTAT2 */
+    case 0x64: /* MCSPI_RX2 */
+    case 0x6c: /* MCSPI_CHSTAT3 */
+    case 0x78: /* MCSPI_RX3 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        if (value & (1 << 1))                          /* SOFTRESET */
+            omap_mcspi_reset(s);
+        s->sysconfig = value & 0x31d;
+        break;
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+            s->irqst &= ~value;
+            omap_mcspi_interrupt_update(s);
+        }
+        break;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        s->irqen = value & 0x1777f;
+        omap_mcspi_interrupt_update(s);
+        break;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        s->wken = value & 1;
+        break;
+
+    case 0x24: /* MCSPI_SYST */
+        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
+            if (value & (1 << 11)) {                   /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->systest = value & 0xfff;
+        break;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        if (value & (1 << 3))                          /* SYSTEM_TEST */
+            if (s->systest & (1 << 11)) {              /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->control = value & 0xf;
+        break;
+
+    case 0x68: ch ++;
+    case 0x54: ch ++;
+    case 0x40: ch ++;
+    case 0x2c: /* MCSPI_CHCONF */
+        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
+            omap_mcspi_dmarequest_update(s->ch + ch);
+        if (((value >> 12) & 3) == 3)                  /* TRM */
+            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
+        if (((value >> 7) & 0x1f) < 3)                 /* WL */
+            fprintf(stderr, "%s: invalid WL value (%i)\n",
+                            __FUNCTION__, (value >> 7) & 0x1f);
+        s->ch[ch].config = value & 0x7fffff;
+        break;
+
+    case 0x70: ch ++;
+    case 0x5c: ch ++;
+    case 0x48: ch ++;
+    case 0x34: /* MCSPI_CHCTRL */
+        if (value & ~s->ch[ch].control & 1) {          /* EN */
+            s->ch[ch].control |= 1;
+            omap_mcspi_transfer_run(s, ch);
+        } else
+            s->ch[ch].control = value & 1;
+        break;
+
+    case 0x74: ch ++;
+    case 0x60: ch ++;
+    case 0x4c: ch ++;
+    case 0x38: /* MCSPI_TX */
+        s->ch[ch].tx = value;
+        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
+        omap_mcspi_transfer_run(s, ch);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_mcspi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mcspi_read,
+};
+
+static CPUWriteMemoryFunc *omap_mcspi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mcspi_write,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+            qemu_mallocz(sizeof(struct omap_mcspi_s));
+    struct omap_mcspi_ch_s *ch = s->ch;
+
+    s->irq = irq;
+    s->chnum = chnum;
+    while (chnum --) {
+        ch->txdrq = *drq ++;
+        ch->rxdrq = *drq ++;
+        ch ++;
+    }
+    omap_mcspi_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_mcspi_readfn,
+                    omap_mcspi_writefn, s);
+    s->base = omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t), void *opaque,
+                int chipselect)
+{
+    if (chipselect < 0 || chipselect >= s->chnum)
+        cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n",
+                        __FUNCTION__, chipselect);
+
+    s->ch[chipselect].txrx = txrx;
+    s->ch[chipselect].opaque = opaque;
+}
+
+/* L4 Interconnect */
+struct omap_target_agent_s {
+    struct omap_l4_s *bus;
+    int regions;
+    struct omap_l4_region_s *start;
+    target_phys_addr_t base;
+    uint32_t component;
+    uint32_t control;
+    uint32_t status;
+};
+
+struct omap_l4_s {
+    target_phys_addr_t base;
+    int ta_num;
+    struct omap_target_agent_s ta[0];
+};
+
+struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
+{
+    struct omap_l4_s *bus = qemu_mallocz(
+                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
+
+    bus->ta_num = ta_num;
+    bus->base = base;
+
+    return bus;
+}
+
+static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+    target_phys_addr_t reg = addr - s->base;
+
+    switch (reg) {
+    case 0x00: /* COMPONENT */
+        return s->component;
+
+    case 0x20: /* AGENT_CONTROL */
+        return s->control;
+
+    case 0x28: /* AGENT_STATUS */
+        return s->status;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_l4ta_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+    target_phys_addr_t reg = addr - s->base;
+
+    switch (reg) {
+    case 0x00: /* COMPONENT */
+    case 0x28: /* AGENT_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x20: /* AGENT_CONTROL */
+        s->control = value & 0x01000700;
+        if (value & 1)                                 /* OCP_RESET */
+            s->status &= ~1;                           /* REQ_TIMEOUT */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_l4ta_readfn[] = {
+    omap_badwidth_read16,
+    omap_l4ta_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_l4ta_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_l4ta_write,
+};
+
+#define L4TA(n)                (n)
+#define L4TAO(n)       ((n) + 39)
+
+static struct omap_l4_region_s {
+    target_phys_addr_t offset;
+    size_t size;
+    int access;
+} omap_l4_region[125] = {
+    [  1] = { 0x40800,  0x800, 32          }, /* Initiator agent */
+    [  2] = { 0x41000, 0x1000, 32          }, /* Link agent */
+    [  0] = { 0x40000,  0x800, 32          }, /* Address and protection */
+    [  3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */
+    [  4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */
+    [  5] = { 0x04000, 0x1000, 32 | 16     }, /* 32K Timer */
+    [  6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */
+    [  7] = { 0x08000,  0x800, 32          }, /* PRCM Region A */
+    [  8] = { 0x08800,  0x800, 32          }, /* PRCM Region B */
+    [  9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */
+    [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */
+    [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */
+    [ 12] = { 0x14000, 0x1000, 32          }, /* Test/emulation (TAP) */
+    [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */
+    [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */
+    [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */
+    [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */
+    [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */
+    [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */
+    [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */
+    [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */
+    [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */
+    [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */
+    [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */
+    [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */
+    [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */
+    [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */
+    [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */
+    [ 28] = { 0x50000,  0x400, 32 | 16 | 8 }, /* Display top */
+    [ 29] = { 0x50400,  0x400, 32 | 16 | 8 }, /* Display control */
+    [ 30] = { 0x50800,  0x400, 32 | 16 | 8 }, /* Display RFBI */
+    [ 31] = { 0x50c00,  0x400, 32 | 16 | 8 }, /* Display encoder */
+    [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */
+    [ 33] = { 0x52000,  0x400, 32 | 16 | 8 }, /* Camera top */
+    [ 34] = { 0x52400,  0x400, 32 | 16 | 8 }, /* Camera core */
+    [ 35] = { 0x52800,  0x400, 32 | 16 | 8 }, /* Camera DMA */
+    [ 36] = { 0x52c00,  0x400, 32 | 16 | 8 }, /* Camera MMU */
+    [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */
+    [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */
+    [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */
+    [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */
+    [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */
+    [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */
+    [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */
+    [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */
+    [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */
+    [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */
+    [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */
+    [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */
+    [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */
+    [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */
+    [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */
+    [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */
+    [ 53] = { 0x66000,  0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */
+    [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */
+    [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */
+    [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */
+    [ 57] = { 0x6a000, 0x1000,      16 | 8 }, /* UART1 */
+    [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */
+    [ 59] = { 0x6c000, 0x1000,      16 | 8 }, /* UART2 */
+    [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */
+    [ 61] = { 0x6e000, 0x1000,      16 | 8 }, /* UART3 */
+    [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */
+    [ 63] = { 0x70000, 0x1000,      16     }, /* I2C1 */
+    [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */
+    [ 65] = { 0x72000, 0x1000,      16     }, /* I2C2 */
+    [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */
+    [ 67] = { 0x74000, 0x1000,      16     }, /* McBSP1 */
+    [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */
+    [ 69] = { 0x76000, 0x1000,      16     }, /* McBSP2 */
+    [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */
+    [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */
+    [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */
+    [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */
+    [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */
+    [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */
+    [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */
+    [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */
+    [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */
+    [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */
+    [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */
+    [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */
+    [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */
+    [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */
+    [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */
+    [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */
+    [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */
+    [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */
+    [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */
+    [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */
+    [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */
+    [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */
+    [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */
+    [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */
+    [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */
+    [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */
+    [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */
+    [ 97] = { 0x90000, 0x1000,      16     }, /* EAC */
+    [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */
+    [ 99] = { 0x92000, 0x1000,      16     }, /* FAC */
+    [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */
+    [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */
+    [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */
+    [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */
+    [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */
+    [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */
+    [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */
+    [107] = { 0x9c000, 0x1000,      16 | 8 }, /* MMC SDIO */
+    [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */
+    [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */
+    [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */
+    [111] = { 0xa0000, 0x1000, 32          }, /* RNG */
+    [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */
+    [113] = { 0xa2000, 0x1000, 32          }, /* DES3DES */
+    [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */
+    [115] = { 0xa4000, 0x1000, 32          }, /* SHA1MD5 */
+    [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */
+    [117] = { 0xa6000, 0x1000, 32          }, /* AES */
+    [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */
+    [119] = { 0xa8000, 0x2000, 32          }, /* PKA */
+    [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */
+    [121] = { 0xb0000, 0x1000, 32          }, /* MG */
+    [122] = { 0xb1000, 0x1000, 32 | 16 | 8 },
+    [123] = { 0xb2000, 0x1000, 32          }, /* HDQ/1-Wire */
+    [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
+};
+
+static struct omap_l4_agent_info_s {
+    int ta;
+    int region;
+    int regions;
+    int ta_region;
+} omap_l4_agent_info[54] = {
+    { 0,           0, 3, 2 }, /* L4IA initiatior agent */
+    { L4TAO(1),    3, 2, 1 }, /* Control and pinout module */
+    { L4TAO(2),    5, 2, 1 }, /* 32K timer */
+    { L4TAO(3),    7, 3, 2 }, /* PRCM */
+    { L4TA(1),    10, 2, 1 }, /* BCM */
+    { L4TA(2),    12, 2, 1 }, /* Test JTAG */
+    { L4TA(3),    14, 6, 3 }, /* Quad GPIO */
+    { L4TA(4),    20, 4, 3 }, /* WD timer 1/2 */
+    { L4TA(7),    24, 2, 1 }, /* GP timer 1 */
+    { L4TA(9),    26, 2, 1 }, /* ATM11 ETB */
+    { L4TA(10),   28, 5, 4 }, /* Display subsystem */
+    { L4TA(11),   33, 5, 4 }, /* Camera subsystem */
+    { L4TA(12),   38, 2, 1 }, /* sDMA */
+    { L4TA(13),   40, 5, 4 }, /* SSI */
+    { L4TAO(4),   45, 2, 1 }, /* USB */
+    { L4TA(14),   47, 2, 1 }, /* Win Tracer1 */
+    { L4TA(15),   49, 2, 1 }, /* Win Tracer2 */
+    { L4TA(16),   51, 2, 1 }, /* Win Tracer3 */
+    { L4TA(17),   53, 2, 1 }, /* Win Tracer4 */
+    { L4TA(18),   55, 2, 1 }, /* XTI */
+    { L4TA(19),   57, 2, 1 }, /* UART1 */
+    { L4TA(20),   59, 2, 1 }, /* UART2 */
+    { L4TA(21),   61, 2, 1 }, /* UART3 */
+    { L4TAO(5),   63, 2, 1 }, /* I2C1 */
+    { L4TAO(6),   65, 2, 1 }, /* I2C2 */
+    { L4TAO(7),   67, 2, 1 }, /* McBSP1 */
+    { L4TAO(8),   69, 2, 1 }, /* McBSP2 */
+    { L4TA(5),    71, 2, 1 }, /* WD Timer 3 (DSP) */
+    { L4TA(6),    73, 2, 1 }, /* WD Timer 4 (IVA) */
+    { L4TA(8),    75, 2, 1 }, /* GP Timer 2 */
+    { L4TA(22),   77, 2, 1 }, /* GP Timer 3 */
+    { L4TA(23),   79, 2, 1 }, /* GP Timer 4 */
+    { L4TA(24),   81, 2, 1 }, /* GP Timer 5 */
+    { L4TA(25),   83, 2, 1 }, /* GP Timer 6 */
+    { L4TA(26),   85, 2, 1 }, /* GP Timer 7 */
+    { L4TA(27),   87, 2, 1 }, /* GP Timer 8 */
+    { L4TA(28),   89, 2, 1 }, /* GP Timer 9 */
+    { L4TA(29),   91, 2, 1 }, /* GP Timer 10 */
+    { L4TA(30),   93, 2, 1 }, /* GP Timer 11 */
+    { L4TA(31),   95, 2, 1 }, /* GP Timer 12 */
+    { L4TA(32),   97, 2, 1 }, /* EAC */
+    { L4TA(33),   99, 2, 1 }, /* FAC */
+    { L4TA(34),  101, 2, 1 }, /* IPC */
+    { L4TA(35),  103, 2, 1 }, /* SPI1 */
+    { L4TA(36),  105, 2, 1 }, /* SPI2 */
+    { L4TAO(9),  107, 2, 1 }, /* MMC SDIO */
+    { L4TAO(10), 109, 2, 1 },
+    { L4TAO(11), 111, 2, 1 }, /* RNG */
+    { L4TAO(12), 113, 2, 1 }, /* DES3DES */
+    { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */
+    { L4TA(37),  117, 2, 1 }, /* AES */
+    { L4TA(38),  119, 2, 1 }, /* PKA */
+    { -1,        121, 2, 1 },
+    { L4TA(39),  123, 2, 1 }, /* HDQ/1-Wire */
+};
+
+#define omap_l4ta(bus, cs)     omap_l4ta_get(bus, L4TA(cs))
+#define omap_l4tao(bus, cs)    omap_l4ta_get(bus, L4TAO(cs))
+
+struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs)
+{
+    int i, iomemtype;
+    struct omap_target_agent_s *ta = 0;
+    struct omap_l4_agent_info_s *info = 0;
+
+    for (i = 0; i < bus->ta_num; i ++)
+        if (omap_l4_agent_info[i].ta == cs) {
+            ta = &bus->ta[i];
+            info = &omap_l4_agent_info[i];
+            break;
+        }
+    if (!ta) {
+        fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+
+    ta->bus = bus;
+    ta->start = &omap_l4_region[info->region];
+    ta->regions = info->regions;
+    ta->base = bus->base + ta->start[info->ta_region].offset;
+
+    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    ta->status = 0x00000000;
+    ta->control = 0x00000200;  /* XXX 01000200 for L4TAO */
+
+    iomemtype = cpu_register_io_memory(0, omap_l4ta_readfn,
+                    omap_l4ta_writefn, ta);
+    cpu_register_physical_memory(ta->base, 0x200, iomemtype);
+
+    return ta;
+}
+
+target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
+                int iotype)
+{
+    target_phys_addr_t base;
+    size_t size;
+
+    if (region < 0 || region >= ta->regions) {
+        fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
+        exit(-1);
+    }
+
+    base = ta->bus->base + ta->start[region].offset;
+    size = ta->start[region].size;
+    if (iotype)
+        cpu_register_physical_memory(base, size, iotype);
+
+    return base;
+}
+
+/* TEST-Chip-level TAP */
+static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    target_phys_addr_t reg = addr - s->tap_base;
+
+    switch (reg) {
+    case 0x204:        /* IDCODE_reg */
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0x5b5d902f; /* ES 2.2 */
+        case omap2430:
+            return 0x5b68a02f; /* ES 2.2 */
+        case omap3430:
+            return 0x1b7ae02f; /* ES 2 */
+        default:
+            cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x208:        /* PRODUCTION_ID_reg for OMAP2 */
+    case 0x210:        /* PRODUCTION_ID_reg for OMAP3 */
+        switch (s->mpu_model) {
+        case omap2420:
+            return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
+        case omap2422:
+            return 0x000400f0;
+        case omap2423:
+            return 0x000800f0;
+        case omap2430:
+            return 0x000000f0;
+        case omap3430:
+            return 0x000000f0;
+        default:
+            cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x20c:
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0xcafeb5d9; /* ES 2.2 */
+        case omap2430:
+            return 0xcafeb68a; /* ES 2.2 */
+        case omap3430:
+            return 0xcafeb7ae; /* ES 2 */
+        default:
+            cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x218:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x21c:        /* DIE_ID_reg */
+        return 0x54 << 24;
+    case 0x220:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x224:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tap_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc *omap_tap_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_tap_read,
+};
+
+static CPUWriteMemoryFunc *omap_tap_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_tap_write,
+};
+
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu)
+{
+    mpu->tap_base = omap_l4_attach(ta, 0, cpu_register_io_memory(0,
+                            omap_tap_readfn, omap_tap_writefn, mpu));
+}
+
+/* Power, Reset, and Clock Management */
+struct omap_prcm_s {
+    target_phys_addr_t base;
+    qemu_irq irq[3];
+    struct omap_mpu_state_s *mpu;
+
+    uint32_t irqst[3];
+    uint32_t irqen[3];
+
+    uint32_t sysconfig;
+    uint32_t voltctrl;
+    uint32_t scratch[20];
+
+    uint32_t clksrc[1];
+    uint32_t clkout[1];
+    uint32_t clkemul[1];
+    uint32_t clkpol[1];
+    uint32_t clksel[8];
+    uint32_t clken[12];
+    uint32_t clkctrl[4];
+    uint32_t clkidle[7];
+    uint32_t setuptime[2];
+
+    uint32_t wkup[3];
+    uint32_t wken[3];
+    uint32_t wkst[3];
+    uint32_t rst[4];
+    uint32_t rstctrl[1];
+    uint32_t power[4];
+    uint32_t rsttime_wkup;
+
+    uint32_t ev;
+    uint32_t evtime[2];
+};
+
+static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
+{
+    qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]);
+    /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */
+}
+
+static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x000:        /* PRCM_REVISION */
+        return 0x10;
+
+    case 0x010:        /* PRCM_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x018:        /* PRCM_IRQSTATUS_MPU */
+        return s->irqst[0];
+
+    case 0x01c:        /* PRCM_IRQENABLE_MPU */
+        return s->irqen[0];
+
+    case 0x050:        /* PRCM_VOLTCTRL */
+        return s->voltctrl;
+    case 0x054:        /* PRCM_VOLTST */
+        return s->voltctrl & 3;
+
+    case 0x060:        /* PRCM_CLKSRC_CTRL */
+        return s->clksrc[0];
+    case 0x070:        /* PRCM_CLKOUT_CTRL */
+        return s->clkout[0];
+    case 0x078:        /* PRCM_CLKEMUL_CTRL */
+        return s->clkemul[0];
+    case 0x080:        /* PRCM_CLKCFG_CTRL */
+    case 0x084:        /* PRCM_CLKCFG_STATUS */
+        return 0;
+
+    case 0x090:        /* PRCM_VOLTSETUP */
+        return s->setuptime[0];
+
+    case 0x094:        /* PRCM_CLKSSETUP */
+        return s->setuptime[1];
+
+    case 0x098:        /* PRCM_POLCTRL */
+        return s->clkpol[0];
+
+    case 0x0b0:        /* GENERAL_PURPOSE1 */
+    case 0x0b4:        /* GENERAL_PURPOSE2 */
+    case 0x0b8:        /* GENERAL_PURPOSE3 */
+    case 0x0bc:        /* GENERAL_PURPOSE4 */
+    case 0x0c0:        /* GENERAL_PURPOSE5 */
+    case 0x0c4:        /* GENERAL_PURPOSE6 */
+    case 0x0c8:        /* GENERAL_PURPOSE7 */
+    case 0x0cc:        /* GENERAL_PURPOSE8 */
+    case 0x0d0:        /* GENERAL_PURPOSE9 */
+    case 0x0d4:        /* GENERAL_PURPOSE10 */
+    case 0x0d8:        /* GENERAL_PURPOSE11 */
+    case 0x0dc:        /* GENERAL_PURPOSE12 */
+    case 0x0e0:        /* GENERAL_PURPOSE13 */
+    case 0x0e4:        /* GENERAL_PURPOSE14 */
+    case 0x0e8:        /* GENERAL_PURPOSE15 */
+    case 0x0ec:        /* GENERAL_PURPOSE16 */
+    case 0x0f0:        /* GENERAL_PURPOSE17 */
+    case 0x0f4:        /* GENERAL_PURPOSE18 */
+    case 0x0f8:        /* GENERAL_PURPOSE19 */
+    case 0x0fc:        /* GENERAL_PURPOSE20 */
+        return s->scratch[(offset - 0xb0) >> 2];
+
+    case 0x140:        /* CM_CLKSEL_MPU */
+        return s->clksel[0];
+    case 0x148:        /* CM_CLKSTCTRL_MPU */
+        return s->clkctrl[0];
+
+    case 0x158:        /* RM_RSTST_MPU */
+        return s->rst[0];
+    case 0x1c8:        /* PM_WKDEP_MPU */
+        return s->wkup[0];
+    case 0x1d4:        /* PM_EVGENCTRL_MPU */
+        return s->ev;
+    case 0x1d8:        /* PM_EVEGENONTIM_MPU */
+        return s->evtime[0];
+    case 0x1dc:        /* PM_EVEGENOFFTIM_MPU */
+        return s->evtime[1];
+    case 0x1e0:        /* PM_PWSTCTRL_MPU */
+        return s->power[0];
+    case 0x1e4:        /* PM_PWSTST_MPU */
+        return 0;
+
+    case 0x200:        /* CM_FCLKEN1_CORE */
+        return s->clken[0];
+    case 0x204:        /* CM_FCLKEN2_CORE */
+        return s->clken[1];
+    case 0x210:        /* CM_ICLKEN1_CORE */
+        return s->clken[2];
+    case 0x214:        /* CM_ICLKEN2_CORE */
+        return s->clken[3];
+    case 0x21c:        /* CM_ICLKEN4_CORE */
+        return s->clken[4];
+
+    case 0x220:        /* CM_IDLEST1_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x7ffffff9;
+    case 0x224:        /* CM_IDLEST2_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x00000007;
+    case 0x22c:        /* CM_IDLEST4_CORE */
+        /* TODO: check the actual iclk status */
+        return 0x0000001f;
+
+    case 0x230:        /* CM_AUTOIDLE1_CORE */
+        return s->clkidle[0];
+    case 0x234:        /* CM_AUTOIDLE2_CORE */
+        return s->clkidle[1];
+    case 0x238:        /* CM_AUTOIDLE3_CORE */
+        return s->clkidle[2];
+    case 0x23c:        /* CM_AUTOIDLE4_CORE */
+        return s->clkidle[3];
+
+    case 0x240:        /* CM_CLKSEL1_CORE */
+        return s->clksel[1];
+    case 0x244:        /* CM_CLKSEL2_CORE */
+        return s->clksel[2];
+
+    case 0x248:        /* CM_CLKSTCTRL_CORE */
+        return s->clkctrl[1];
+
+    case 0x2a0:        /* PM_WKEN1_CORE */
+        return s->wken[0];
+    case 0x2a4:        /* PM_WKEN2_CORE */
+        return s->wken[1];
+
+    case 0x2b0:        /* PM_WKST1_CORE */
+        return s->wkst[0];
+    case 0x2b4:        /* PM_WKST2_CORE */
+        return s->wkst[1];
+    case 0x2c8:        /* PM_WKDEP_CORE */
+        return 0x1e;
+
+    case 0x2e0:        /* PM_PWSTCTRL_CORE */
+        return s->power[1];
+    case 0x2e4:        /* PM_PWSTST_CORE */
+        return 0x000030 | (s->power[1] & 0xfc00);
+
+    case 0x300:        /* CM_FCLKEN_GFX */
+        return s->clken[5];
+    case 0x310:        /* CM_ICLKEN_GFX */
+        return s->clken[6];
+    case 0x320:        /* CM_IDLEST_GFX */
+        /* TODO: check the actual iclk status */
+        return 0x00000001;
+    case 0x340:        /* CM_CLKSEL_GFX */
+        return s->clksel[3];
+    case 0x348:        /* CM_CLKSTCTRL_GFX */
+        return s->clkctrl[2];
+    case 0x350:        /* RM_RSTCTRL_GFX */
+        return s->rstctrl[0];
+    case 0x358:        /* RM_RSTST_GFX */
+        return s->rst[1];
+    case 0x3c8:        /* PM_WKDEP_GFX */
+        return s->wkup[1];
+
+    case 0x3e0:        /* PM_PWSTCTRL_GFX */
+        return s->power[2];
+    case 0x3e4:        /* PM_PWSTST_GFX */
+        return s->power[2] & 3;
+
+    case 0x400:        /* CM_FCLKEN_WKUP */
+        return s->clken[7];
+    case 0x410:        /* CM_ICLKEN_WKUP */
+        return s->clken[8];
+    case 0x420:        /* CM_IDLEST_WKUP */
+        /* TODO: check the actual iclk status */
+        return 0x0000003f;
+    case 0x430:        /* CM_AUTOIDLE_WKUP */
+        return s->clkidle[4];
+    case 0x440:        /* CM_CLKSEL_WKUP */
+        return s->clksel[4];
+    case 0x450:        /* RM_RSTCTRL_WKUP */
+        return 0;
+    case 0x454:        /* RM_RSTTIME_WKUP */
+        return s->rsttime_wkup;
+    case 0x458:        /* RM_RSTST_WKUP */
+        return s->rst[2];
+    case 0x4a0:        /* PM_WKEN_WKUP */
+        return s->wken[2];
+    case 0x4b0:        /* PM_WKST_WKUP */
+        return s->wkst[2];
+
+    case 0x500:        /* CM_CLKEN_PLL */
+        return s->clken[9];
+    case 0x520:        /* CM_IDLEST_CKGEN */
+        /* Core uses 32-kHz clock */
+        if (!(s->clksel[6] & 3))
+            return 0x00000377;
+        /* DPLL not in lock mode, core uses ref_clk */
+        if ((s->clken[9] & 3) != 3)
+            return 0x00000375;
+        /* Core uses DPLL */
+        return 0x00000376;
+    case 0x530:        /* CM_AUTOIDLE_PLL */
+        return s->clkidle[5];
+    case 0x540:        /* CM_CLKSEL1_PLL */
+        return s->clksel[5];
+    case 0x544:        /* CM_CLKSEL2_PLL */
+        return s->clksel[6];
+
+    case 0x800:        /* CM_FCLKEN_DSP */
+        return s->clken[10];
+    case 0x810:        /* CM_ICLKEN_DSP */
+        return s->clken[11];
+    case 0x820:        /* CM_IDLEST_DSP */
+        /* TODO: check the actual iclk status */
+        return 0x00000103;
+    case 0x830:        /* CM_AUTOIDLE_DSP */
+        return s->clkidle[6];
+    case 0x840:        /* CM_CLKSEL_DSP */
+        return s->clksel[7];
+    case 0x848:        /* CM_CLKSTCTRL_DSP */
+        return s->clkctrl[3];
+    case 0x850:        /* RM_RSTCTRL_DSP */
+        return 0;
+    case 0x858:        /* RM_RSTST_DSP */
+        return s->rst[3];
+    case 0x8c8:        /* PM_WKDEP_DSP */
+        return s->wkup[2];
+    case 0x8e0:        /* PM_PWSTCTRL_DSP */
+        return s->power[3];
+    case 0x8e4:        /* PM_PWSTST_DSP */
+        return 0x008030 | (s->power[3] & 0x3003);
+
+    case 0x8f0:        /* PRCM_IRQSTATUS_DSP */
+        return s->irqst[1];
+    case 0x8f4:        /* PRCM_IRQENABLE_DSP */
+        return s->irqen[1];
+
+    case 0x8f8:        /* PRCM_IRQSTATUS_IVA */
+        return s->irqst[2];
+    case 0x8fc:        /* PRCM_IRQENABLE_IVA */
+        return s->irqen[2];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x000:        /* PRCM_REVISION */
+    case 0x054:        /* PRCM_VOLTST */
+    case 0x084:        /* PRCM_CLKCFG_STATUS */
+    case 0x1e4:        /* PM_PWSTST_MPU */
+    case 0x220:        /* CM_IDLEST1_CORE */
+    case 0x224:        /* CM_IDLEST2_CORE */
+    case 0x22c:        /* CM_IDLEST4_CORE */
+    case 0x2c8:        /* PM_WKDEP_CORE */
+    case 0x2e4:        /* PM_PWSTST_CORE */
+    case 0x320:        /* CM_IDLEST_GFX */
+    case 0x3e4:        /* PM_PWSTST_GFX */
+    case 0x420:        /* CM_IDLEST_WKUP */
+    case 0x520:        /* CM_IDLEST_CKGEN */
+    case 0x820:        /* CM_IDLEST_DSP */
+    case 0x8e4:        /* PM_PWSTST_DSP */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x010:        /* PRCM_SYSCONFIG */
+        s->sysconfig = value & 1;
+        break;
+
+    case 0x018:        /* PRCM_IRQSTATUS_MPU */
+        s->irqst[0] &= ~value;
+        omap_prcm_int_update(s, 0);
+        break;
+    case 0x01c:        /* PRCM_IRQENABLE_MPU */
+        s->irqen[0] = value & 0x3f;
+        omap_prcm_int_update(s, 0);
+        break;
+
+    case 0x050:        /* PRCM_VOLTCTRL */
+        s->voltctrl = value & 0xf1c3;
+        break;
+
+    case 0x060:        /* PRCM_CLKSRC_CTRL */
+        s->clksrc[0] = value & 0xdb;
+        /* TODO update clocks */
+        break;
+
+    case 0x070:        /* PRCM_CLKOUT_CTRL */
+        s->clkout[0] = value & 0xbbbb;
+        /* TODO update clocks */
+        break;
+
+    case 0x078:        /* PRCM_CLKEMUL_CTRL */
+        s->clkemul[0] = value & 1;
+        /* TODO update clocks */
+        break;
+
+    case 0x080:        /* PRCM_CLKCFG_CTRL */
+        break;
+
+    case 0x090:        /* PRCM_VOLTSETUP */
+        s->setuptime[0] = value & 0xffff;
+        break;
+    case 0x094:        /* PRCM_CLKSSETUP */
+        s->setuptime[1] = value & 0xffff;
+        break;
+
+    case 0x098:        /* PRCM_POLCTRL */
+        s->clkpol[0] = value & 0x701;
+        break;
+
+    case 0x0b0:        /* GENERAL_PURPOSE1 */
+    case 0x0b4:        /* GENERAL_PURPOSE2 */
+    case 0x0b8:        /* GENERAL_PURPOSE3 */
+    case 0x0bc:        /* GENERAL_PURPOSE4 */
+    case 0x0c0:        /* GENERAL_PURPOSE5 */
+    case 0x0c4:        /* GENERAL_PURPOSE6 */
+    case 0x0c8:        /* GENERAL_PURPOSE7 */
+    case 0x0cc:        /* GENERAL_PURPOSE8 */
+    case 0x0d0:        /* GENERAL_PURPOSE9 */
+    case 0x0d4:        /* GENERAL_PURPOSE10 */
+    case 0x0d8:        /* GENERAL_PURPOSE11 */
+    case 0x0dc:        /* GENERAL_PURPOSE12 */
+    case 0x0e0:        /* GENERAL_PURPOSE13 */
+    case 0x0e4:        /* GENERAL_PURPOSE14 */
+    case 0x0e8:        /* GENERAL_PURPOSE15 */
+    case 0x0ec:        /* GENERAL_PURPOSE16 */
+    case 0x0f0:        /* GENERAL_PURPOSE17 */
+    case 0x0f4:        /* GENERAL_PURPOSE18 */
+    case 0x0f8:        /* GENERAL_PURPOSE19 */
+    case 0x0fc:        /* GENERAL_PURPOSE20 */
+        s->scratch[(offset - 0xb0) >> 2] = value;
+        break;
+
+    case 0x140:        /* CM_CLKSEL_MPU */
+        s->clksel[0] = value & 0x1f;
+        /* TODO update clocks */
+        break;
+    case 0x148:        /* CM_CLKSTCTRL_MPU */
+        s->clkctrl[0] = value & 0x1f;
+        break;
+
+    case 0x158:        /* RM_RSTST_MPU */
+        s->rst[0] &= ~value;
+        break;
+    case 0x1c8:        /* PM_WKDEP_MPU */
+        s->wkup[0] = value & 0x15;
+        break;
+
+    case 0x1d4:        /* PM_EVGENCTRL_MPU */
+        s->ev = value & 0x1f;
+        break;
+    case 0x1d8:        /* PM_EVEGENONTIM_MPU */
+        s->evtime[0] = value;
+        break;
+    case 0x1dc:        /* PM_EVEGENOFFTIM_MPU */
+        s->evtime[1] = value;
+        break;
+
+    case 0x1e0:        /* PM_PWSTCTRL_MPU */
+        s->power[0] = value & 0xc0f;
+        break;
+
+    case 0x200:        /* CM_FCLKEN1_CORE */
+        s->clken[0] = value & 0xbfffffff;
+        /* TODO update clocks */
+        break;
+    case 0x204:        /* CM_FCLKEN2_CORE */
+        s->clken[1] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x210:        /* CM_ICLKEN1_CORE */
+        s->clken[2] = value & 0xfffffff9;
+        /* TODO update clocks */
+        break;
+    case 0x214:        /* CM_ICLKEN2_CORE */
+        s->clken[3] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x21c:        /* CM_ICLKEN4_CORE */
+        s->clken[4] = value & 0x0000001f;
+        /* TODO update clocks */
+        break;
+
+    case 0x230:        /* CM_AUTOIDLE1_CORE */
+        s->clkidle[0] = value & 0xfffffff9;
+        /* TODO update clocks */
+        break;
+    case 0x234:        /* CM_AUTOIDLE2_CORE */
+        s->clkidle[1] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x238:        /* CM_AUTOIDLE3_CORE */
+        s->clkidle[2] = value & 0x00000007;
+        /* TODO update clocks */
+        break;
+    case 0x23c:        /* CM_AUTOIDLE4_CORE */
+        s->clkidle[3] = value & 0x0000001f;
+        /* TODO update clocks */
+        break;
+
+    case 0x240:        /* CM_CLKSEL1_CORE */
+        s->clksel[1] = value & 0x0fffbf7f;
+        /* TODO update clocks */
+        break;
+
+    case 0x244:        /* CM_CLKSEL2_CORE */
+        s->clksel[2] = value & 0x00fffffc;
+        /* TODO update clocks */
+        break;
+
+    case 0x248:        /* CM_CLKSTCTRL_CORE */
+        s->clkctrl[1] = value & 0x7;
+        break;
+
+    case 0x2a0:        /* PM_WKEN1_CORE */
+        s->wken[0] = value & 0x04667ff8;
+        break;
+    case 0x2a4:        /* PM_WKEN2_CORE */
+        s->wken[1] = value & 0x00000005;
+        break;
+
+    case 0x2b0:        /* PM_WKST1_CORE */
+        s->wkst[0] &= ~value;
+        break;
+    case 0x2b4:        /* PM_WKST2_CORE */
+        s->wkst[1] &= ~value;
+        break;
+
+    case 0x2e0:        /* PM_PWSTCTRL_CORE */
+        s->power[1] = (value & 0x00fc3f) | (1 << 2);
+        break;
+
+    case 0x300:        /* CM_FCLKEN_GFX */
+        s->clken[5] = value & 6;
+        /* TODO update clocks */
+        break;
+    case 0x310:        /* CM_ICLKEN_GFX */
+        s->clken[6] = value & 1;
+        /* TODO update clocks */
+        break;
+    case 0x340:        /* CM_CLKSEL_GFX */
+        s->clksel[3] = value & 7;
+        /* TODO update clocks */
+        break;
+    case 0x348:        /* CM_CLKSTCTRL_GFX */
+        s->clkctrl[2] = value & 1;
+        break;
+    case 0x350:        /* RM_RSTCTRL_GFX */
+        s->rstctrl[0] = value & 1;
+        /* TODO: reset */
+        break;
+    case 0x358:        /* RM_RSTST_GFX */
+        s->rst[1] &= ~value;
+        break;
+    case 0x3c8:        /* PM_WKDEP_GFX */
+        s->wkup[1] = value & 0x13;
+        break;
+    case 0x3e0:        /* PM_PWSTCTRL_GFX */
+        s->power[2] = (value & 0x00c0f) | (3 << 2);
+        break;
+
+    case 0x400:        /* CM_FCLKEN_WKUP */
+        s->clken[7] = value & 0xd;
+        /* TODO update clocks */
+        break;
+    case 0x410:        /* CM_ICLKEN_WKUP */
+        s->clken[8] = value & 0x3f;
+        /* TODO update clocks */
+        break;
+    case 0x430:        /* CM_AUTOIDLE_WKUP */
+        s->clkidle[4] = value & 0x0000003f;
+        /* TODO update clocks */
+        break;
+    case 0x440:        /* CM_CLKSEL_WKUP */
+        s->clksel[4] = value & 3;
+        /* TODO update clocks */
+        break;
+    case 0x450:        /* RM_RSTCTRL_WKUP */
+        /* TODO: reset */
+        if (value & 2)
+            qemu_system_reset_request();
+        break;
+    case 0x454:        /* RM_RSTTIME_WKUP */
+        s->rsttime_wkup = value & 0x1fff;
+        break;
+    case 0x458:        /* RM_RSTST_WKUP */
+        s->rst[2] &= ~value;
+        break;
+    case 0x4a0:        /* PM_WKEN_WKUP */
+        s->wken[2] = value & 0x00000005;
+        break;
+    case 0x4b0:        /* PM_WKST_WKUP */
+        s->wkst[2] &= ~value;
+        break;
+
+    case 0x500:        /* CM_CLKEN_PLL */
+        s->clken[9] = value & 0xcf;
+        /* TODO update clocks */
+        break;
+    case 0x530:        /* CM_AUTOIDLE_PLL */
+        s->clkidle[5] = value & 0x000000cf;
+        /* TODO update clocks */
+        break;
+    case 0x540:        /* CM_CLKSEL1_PLL */
+        s->clksel[5] = value & 0x03bfff28;
+        /* TODO update clocks */
+        break;
+    case 0x544:        /* CM_CLKSEL2_PLL */
+        s->clksel[6] = value & 3;
+        /* TODO update clocks */
+        break;
+
+    case 0x800:        /* CM_FCLKEN_DSP */
+        s->clken[10] = value & 0x501;
+        /* TODO update clocks */
+        break;
+    case 0x810:        /* CM_ICLKEN_DSP */
+        s->clken[11] = value & 0x2;
+        /* TODO update clocks */
+        break;
+    case 0x830:        /* CM_AUTOIDLE_DSP */
+        s->clkidle[6] = value & 0x2;
+        /* TODO update clocks */
+        break;
+    case 0x840:        /* CM_CLKSEL_DSP */
+        s->clksel[7] = value & 0x3fff;
+        /* TODO update clocks */
+        break;
+    case 0x848:        /* CM_CLKSTCTRL_DSP */
+        s->clkctrl[3] = value & 0x101;
+        break;
+    case 0x850:        /* RM_RSTCTRL_DSP */
+        /* TODO: reset */
+        break;
+    case 0x858:        /* RM_RSTST_DSP */
+        s->rst[3] &= ~value;
+        break;
+    case 0x8c8:        /* PM_WKDEP_DSP */
+        s->wkup[2] = value & 0x13;
+        break;
+    case 0x8e0:        /* PM_PWSTCTRL_DSP */
+        s->power[3] = (value & 0x03017) | (3 << 2);
+        break;
+
+    case 0x8f0:        /* PRCM_IRQSTATUS_DSP */
+        s->irqst[1] &= ~value;
+        omap_prcm_int_update(s, 1);
+        break;
+    case 0x8f4:        /* PRCM_IRQENABLE_DSP */
+        s->irqen[1] = value & 0x7;
+        omap_prcm_int_update(s, 1);
+        break;
+
+    case 0x8f8:        /* PRCM_IRQSTATUS_IVA */
+        s->irqst[2] &= ~value;
+        omap_prcm_int_update(s, 2);
+        break;
+    case 0x8fc:        /* PRCM_IRQENABLE_IVA */
+        s->irqen[2] = value & 0x7;
+        omap_prcm_int_update(s, 2);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_prcm_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_prcm_read,
+};
+
+static CPUWriteMemoryFunc *omap_prcm_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_prcm_write,
+};
+
+static void omap_prcm_reset(struct omap_prcm_s *s)
+{
+    s->sysconfig = 0;
+    s->irqst[0] = 0;
+    s->irqst[1] = 0;
+    s->irqst[2] = 0;
+    s->irqen[0] = 0;
+    s->irqen[1] = 0;
+    s->irqen[2] = 0;
+    s->voltctrl = 0x1040;
+    s->ev = 0x14;
+    s->evtime[0] = 0;
+    s->evtime[1] = 0;
+    s->clkctrl[0] = 0;
+    s->clkctrl[1] = 0;
+    s->clkctrl[2] = 0;
+    s->clkctrl[3] = 0;
+    s->clken[1] = 7;
+    s->clken[3] = 7;
+    s->clken[4] = 0;
+    s->clken[5] = 0;
+    s->clken[6] = 0;
+    s->clken[7] = 0xc;
+    s->clken[8] = 0x3e;
+    s->clken[9] = 0x0d;
+    s->clken[10] = 0;
+    s->clken[11] = 0;
+    s->clkidle[0] = 0;
+    s->clkidle[2] = 7;
+    s->clkidle[3] = 0;
+    s->clkidle[4] = 0;
+    s->clkidle[5] = 0x0c;
+    s->clkidle[6] = 0;
+    s->clksel[0] = 0x01;
+    s->clksel[1] = 0x02100121;
+    s->clksel[2] = 0x00000000;
+    s->clksel[3] = 0x01;
+    s->clksel[4] = 0;
+    s->clksel[7] = 0x0121;
+    s->wkup[0] = 0x15;
+    s->wkup[1] = 0x13;
+    s->wkup[2] = 0x13;
+    s->wken[0] = 0x04667ff8;
+    s->wken[1] = 0x00000005;
+    s->wken[2] = 5;
+    s->wkst[0] = 0;
+    s->wkst[1] = 0;
+    s->wkst[2] = 0;
+    s->power[0] = 0x00c;
+    s->power[1] = 4;
+    s->power[2] = 0x0000c;
+    s->power[3] = 0x14;
+    s->rstctrl[0] = 1;
+    s->rst[3] = 1;
+}
+
+static void omap_prcm_coldreset(struct omap_prcm_s *s)
+{
+    s->setuptime[0] = 0;
+    s->setuptime[1] = 0;
+    memset(&s->scratch, 0, sizeof(s->scratch));
+    s->rst[0] = 0x01;
+    s->rst[1] = 0x00;
+    s->rst[2] = 0x01;
+    s->clken[0] = 0;
+    s->clken[2] = 0;
+    s->clkidle[1] = 0;
+    s->clksel[5] = 0;
+    s->clksel[6] = 2;
+    s->clksrc[0] = 0x43;
+    s->clkout[0] = 0x0303;
+    s->clkemul[0] = 0;
+    s->clkpol[0] = 0x100;
+    s->rsttime_wkup = 0x1002;
+
+    omap_prcm_reset(s);
+}
+
+struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
+                qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap_prcm_s *s = (struct omap_prcm_s *)
+            qemu_mallocz(sizeof(struct omap_prcm_s));
+
+    s->irq[0] = mpu_int;
+    s->irq[1] = dsp_int;
+    s->irq[2] = iva_int;
+    s->mpu = mpu;
+    omap_prcm_coldreset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_prcm_readfn,
+                    omap_prcm_writefn, s);
+    s->base = omap_l4_attach(ta, 0, iomemtype);
+    omap_l4_attach(ta, 1, iomemtype);
+
+    return s;
+}
+
+/* System and Pinout control */
+struct omap_sysctl_s {
+    target_phys_addr_t base;
+    struct omap_mpu_state_s *mpu;
+
+    uint32_t sysconfig;
+    uint32_t devconfig;
+    uint32_t psaconfig;
+    uint32_t padconf[0x45];
+    uint8_t obs;
+    uint32_t msuspendmux[5];
+};
+
+static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x000:        /* CONTROL_REVISION */
+        return 0x20;
+
+    case 0x010:        /* CONTROL_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x030 ... 0x140:      /* CONTROL_PADCONF - only used in the POP */
+        return s->padconf[(offset - 0x30) >> 2];
+
+    case 0x270:        /* CONTROL_DEBOBS */
+        return s->obs;
+
+    case 0x274:        /* CONTROL_DEVCONF */
+        return s->devconfig;
+
+    case 0x28c:        /* CONTROL_EMU_SUPPORT */
+        return 0;
+
+    case 0x290:        /* CONTROL_MSUSPENDMUX_0 */
+        return s->msuspendmux[0];
+    case 0x294:        /* CONTROL_MSUSPENDMUX_1 */
+        return s->msuspendmux[1];
+    case 0x298:        /* CONTROL_MSUSPENDMUX_2 */
+        return s->msuspendmux[2];
+    case 0x29c:        /* CONTROL_MSUSPENDMUX_3 */
+        return s->msuspendmux[3];
+    case 0x2a0:        /* CONTROL_MSUSPENDMUX_4 */
+        return s->msuspendmux[4];
+    case 0x2a4:        /* CONTROL_MSUSPENDMUX_5 */
+        return 0;
+
+    case 0x2b8:        /* CONTROL_PSA_CTRL */
+        return s->psaconfig;
+    case 0x2bc:        /* CONTROL_PSA_CMD */
+    case 0x2c0:        /* CONTROL_PSA_VALUE */
+        return 0;
+
+    case 0x2b0:        /* CONTROL_SEC_CTRL */
+        return 0x800000f1;
+    case 0x2d0:        /* CONTROL_SEC_EMU */
+        return 0x80000015;
+    case 0x2d4:        /* CONTROL_SEC_TAP */
+        return 0x8000007f;
+    case 0x2b4:        /* CONTROL_SEC_TEST */
+    case 0x2f0:        /* CONTROL_SEC_STATUS */
+    case 0x2f4:        /* CONTROL_SEC_ERR_STATUS */
+        /* Secure mode is not present on general-pusrpose device.  Outside
+         * secure mode these values cannot be read or written.  */
+        return 0;
+
+    case 0x2d8:        /* CONTROL_OCM_RAM_PERM */
+        return 0xff;
+    case 0x2dc:        /* CONTROL_OCM_PUB_RAM_ADD */
+    case 0x2e0:        /* CONTROL_EXT_SEC_RAM_START_ADD */
+    case 0x2e4:        /* CONTROL_EXT_SEC_RAM_STOP_ADD */
+        /* No secure mode so no Extended Secure RAM present.  */
+        return 0;
+
+    case 0x2f8:        /* CONTROL_STATUS */
+        /* Device Type => General-purpose */
+        return 0x0300;
+    case 0x2fc:        /* CONTROL_GENERAL_PURPOSE_STATUS */
+
+    case 0x300:        /* CONTROL_RPUB_KEY_H_0 */
+    case 0x304:        /* CONTROL_RPUB_KEY_H_1 */
+    case 0x308:        /* CONTROL_RPUB_KEY_H_2 */
+    case 0x30c:        /* CONTROL_RPUB_KEY_H_3 */
+        return 0xdecafbad;
+
+    case 0x310:        /* CONTROL_RAND_KEY_0 */
+    case 0x314:        /* CONTROL_RAND_KEY_1 */
+    case 0x318:        /* CONTROL_RAND_KEY_2 */
+    case 0x31c:        /* CONTROL_RAND_KEY_3 */
+    case 0x320:        /* CONTROL_CUST_KEY_0 */
+    case 0x324:        /* CONTROL_CUST_KEY_1 */
+    case 0x330:        /* CONTROL_TEST_KEY_0 */
+    case 0x334:        /* CONTROL_TEST_KEY_1 */
+    case 0x338:        /* CONTROL_TEST_KEY_2 */
+    case 0x33c:        /* CONTROL_TEST_KEY_3 */
+    case 0x340:        /* CONTROL_TEST_KEY_4 */
+    case 0x344:        /* CONTROL_TEST_KEY_5 */
+    case 0x348:        /* CONTROL_TEST_KEY_6 */
+    case 0x34c:        /* CONTROL_TEST_KEY_7 */
+    case 0x350:        /* CONTROL_TEST_KEY_8 */
+    case 0x354:        /* CONTROL_TEST_KEY_9 */
+        /* Can only be accessed in secure mode and when C_FieldAccEnable
+         * bit is set in CONTROL_SEC_CTRL.
+         * TODO: otherwise an interconnect access error is generated.  */
+        return 0;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sysctl_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x000:        /* CONTROL_REVISION */
+    case 0x2a4:        /* CONTROL_MSUSPENDMUX_5 */
+    case 0x2c0:        /* CONTROL_PSA_VALUE */
+    case 0x2f8:        /* CONTROL_STATUS */
+    case 0x2fc:        /* CONTROL_GENERAL_PURPOSE_STATUS */
+    case 0x300:        /* CONTROL_RPUB_KEY_H_0 */
+    case 0x304:        /* CONTROL_RPUB_KEY_H_1 */
+    case 0x308:        /* CONTROL_RPUB_KEY_H_2 */
+    case 0x30c:        /* CONTROL_RPUB_KEY_H_3 */
+    case 0x310:        /* CONTROL_RAND_KEY_0 */
+    case 0x314:        /* CONTROL_RAND_KEY_1 */
+    case 0x318:        /* CONTROL_RAND_KEY_2 */
+    case 0x31c:        /* CONTROL_RAND_KEY_3 */
+    case 0x320:        /* CONTROL_CUST_KEY_0 */
+    case 0x324:        /* CONTROL_CUST_KEY_1 */
+    case 0x330:        /* CONTROL_TEST_KEY_0 */
+    case 0x334:        /* CONTROL_TEST_KEY_1 */
+    case 0x338:        /* CONTROL_TEST_KEY_2 */
+    case 0x33c:        /* CONTROL_TEST_KEY_3 */
+    case 0x340:        /* CONTROL_TEST_KEY_4 */
+    case 0x344:        /* CONTROL_TEST_KEY_5 */
+    case 0x348:        /* CONTROL_TEST_KEY_6 */
+    case 0x34c:        /* CONTROL_TEST_KEY_7 */
+    case 0x350:        /* CONTROL_TEST_KEY_8 */
+    case 0x354:        /* CONTROL_TEST_KEY_9 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x010:        /* CONTROL_SYSCONFIG */
+        s->sysconfig = value & 0x1e;
+        break;
+
+    case 0x030 ... 0x140:      /* CONTROL_PADCONF - only used in the POP */
+        /* XXX: should check constant bits */
+        s->padconf[(offset - 0x30) >> 2] = value & 0x1f1f1f1f;
+        break;
+
+    case 0x270:        /* CONTROL_DEBOBS */
+        s->obs = value & 0xff;
+        break;
+
+    case 0x274:        /* CONTROL_DEVCONF */
+        s->devconfig = value & 0xffffc7ff;
+        break;
+
+    case 0x28c:        /* CONTROL_EMU_SUPPORT */
+        break;
+
+    case 0x290:        /* CONTROL_MSUSPENDMUX_0 */
+        s->msuspendmux[0] = value & 0x3fffffff;
+        break;
+    case 0x294:        /* CONTROL_MSUSPENDMUX_1 */
+        s->msuspendmux[1] = value & 0x3fffffff;
+        break;
+    case 0x298:        /* CONTROL_MSUSPENDMUX_2 */
+        s->msuspendmux[2] = value & 0x3fffffff;
+        break;
+    case 0x29c:        /* CONTROL_MSUSPENDMUX_3 */
+        s->msuspendmux[3] = value & 0x3fffffff;
+        break;
+    case 0x2a0:        /* CONTROL_MSUSPENDMUX_4 */
+        s->msuspendmux[4] = value & 0x3fffffff;
+        break;
+
+    case 0x2b8:        /* CONTROL_PSA_CTRL */
+        s->psaconfig = value & 0x1c;
+        s->psaconfig |= (value & 0x20) ? 2 : 1;
+        break;
+    case 0x2bc:        /* CONTROL_PSA_CMD */
+        break;
+
+    case 0x2b0:        /* CONTROL_SEC_CTRL */
+    case 0x2b4:        /* CONTROL_SEC_TEST */
+    case 0x2d0:        /* CONTROL_SEC_EMU */
+    case 0x2d4:        /* CONTROL_SEC_TAP */
+    case 0x2d8:        /* CONTROL_OCM_RAM_PERM */
+    case 0x2dc:        /* CONTROL_OCM_PUB_RAM_ADD */
+    case 0x2e0:        /* CONTROL_EXT_SEC_RAM_START_ADD */
+    case 0x2e4:        /* CONTROL_EXT_SEC_RAM_STOP_ADD */
+    case 0x2f0:        /* CONTROL_SEC_STATUS */
+    case 0x2f4:        /* CONTROL_SEC_ERR_STATUS */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_sysctl_readfn[] = {
+    omap_badwidth_read32,      /* TODO */
+    omap_badwidth_read32,      /* TODO */
+    omap_sysctl_read,
+};
+
+static CPUWriteMemoryFunc *omap_sysctl_writefn[] = {
+    omap_badwidth_write32,     /* TODO */
+    omap_badwidth_write32,     /* TODO */
+    omap_sysctl_write,
+};
+
+static void omap_sysctl_reset(struct omap_sysctl_s *s)
+{
+    /* (power-on reset) */
+    s->sysconfig = 0;
+    s->obs = 0;
+    s->devconfig = 0x0c000000;
+    s->msuspendmux[0] = 0x00000000;
+    s->msuspendmux[1] = 0x00000000;
+    s->msuspendmux[2] = 0x00000000;
+    s->msuspendmux[3] = 0x00000000;
+    s->msuspendmux[4] = 0x00000000;
+    s->psaconfig = 1;
+
+    s->padconf[0x00] = 0x000f0f0f;
+    s->padconf[0x01] = 0x00000000;
+    s->padconf[0x02] = 0x00000000;
+    s->padconf[0x03] = 0x00000000;
+    s->padconf[0x04] = 0x00000000;
+    s->padconf[0x05] = 0x00000000;
+    s->padconf[0x06] = 0x00000000;
+    s->padconf[0x07] = 0x00000000;
+    s->padconf[0x08] = 0x08080800;
+    s->padconf[0x09] = 0x08080808;
+    s->padconf[0x0a] = 0x08080808;
+    s->padconf[0x0b] = 0x08080808;
+    s->padconf[0x0c] = 0x08080808;
+    s->padconf[0x0d] = 0x08080800;
+    s->padconf[0x0e] = 0x08080808;
+    s->padconf[0x0f] = 0x08080808;
+    s->padconf[0x10] = 0x18181808;     /* | 0x07070700 if SBoot3 */
+    s->padconf[0x11] = 0x18181818;     /* | 0x07070707 if SBoot3 */
+    s->padconf[0x12] = 0x18181818;     /* | 0x07070707 if SBoot3 */
+    s->padconf[0x13] = 0x18181818;     /* | 0x07070707 if SBoot3 */
+    s->padconf[0x14] = 0x18181818;     /* | 0x00070707 if SBoot3 */
+    s->padconf[0x15] = 0x18181818;
+    s->padconf[0x16] = 0x18181818;     /* | 0x07000000 if SBoot3 */
+    s->padconf[0x17] = 0x1f001f00;
+    s->padconf[0x18] = 0x1f1f1f1f;
+    s->padconf[0x19] = 0x00000000;
+    s->padconf[0x1a] = 0x1f180000;
+    s->padconf[0x1b] = 0x00001f1f;
+    s->padconf[0x1c] = 0x1f001f00;
+    s->padconf[0x1d] = 0x00000000;
+    s->padconf[0x1e] = 0x00000000;
+    s->padconf[0x1f] = 0x08000000;
+    s->padconf[0x20] = 0x08080808;
+    s->padconf[0x21] = 0x08080808;
+    s->padconf[0x22] = 0x0f080808;
+    s->padconf[0x23] = 0x0f0f0f0f;
+    s->padconf[0x24] = 0x000f0f0f;
+    s->padconf[0x25] = 0x1f1f1f0f;
+    s->padconf[0x26] = 0x080f0f1f;
+    s->padconf[0x27] = 0x070f1808;
+    s->padconf[0x28] = 0x0f070707;
+    s->padconf[0x29] = 0x000f0f1f;
+    s->padconf[0x2a] = 0x0f0f0f1f;
+    s->padconf[0x2b] = 0x08000000;
+    s->padconf[0x2c] = 0x0000001f;
+    s->padconf[0x2d] = 0x0f0f1f00;
+    s->padconf[0x2e] = 0x1f1f0f0f;
+    s->padconf[0x2f] = 0x0f1f1f1f;
+    s->padconf[0x30] = 0x0f0f0f0f;
+    s->padconf[0x31] = 0x0f1f0f1f;
+    s->padconf[0x32] = 0x0f0f0f0f;
+    s->padconf[0x33] = 0x0f1f0f1f;
+    s->padconf[0x34] = 0x1f1f0f0f;
+    s->padconf[0x35] = 0x0f0f1f1f;
+    s->padconf[0x36] = 0x0f0f1f0f;
+    s->padconf[0x37] = 0x0f0f0f0f;
+    s->padconf[0x38] = 0x1f18180f;
+    s->padconf[0x39] = 0x1f1f1f1f;
+    s->padconf[0x3a] = 0x00001f1f;
+    s->padconf[0x3b] = 0x00000000;
+    s->padconf[0x3c] = 0x00000000;
+    s->padconf[0x3d] = 0x0f0f0f0f;
+    s->padconf[0x3e] = 0x18000f0f;
+    s->padconf[0x3f] = 0x00070000;
+    s->padconf[0x40] = 0x00000707;
+    s->padconf[0x41] = 0x0f1f0700;
+    s->padconf[0x42] = 0x1f1f070f;
+    s->padconf[0x43] = 0x0008081f;
+    s->padconf[0x44] = 0x00000800;
+}
+
+struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
+                omap_clk iclk, struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap_sysctl_s *s = (struct omap_sysctl_s *)
+            qemu_mallocz(sizeof(struct omap_sysctl_s));
+
+    s->mpu = mpu;
+    omap_sysctl_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_sysctl_readfn,
+                    omap_sysctl_writefn, s);
+    s->base = omap_l4_attach(ta, 0, iomemtype);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    return s;
+}
+
+/* SDRAM Controller Subsystem */
+struct omap_sdrc_s {
+    target_phys_addr_t base;
+
+    uint8_t config;
+};
+
+static void omap_sdrc_reset(struct omap_sdrc_s *s)
+{
+    s->config = 0x10;
+}
+
+static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* SDRC_REVISION */
+        return 0x20;
+
+    case 0x10: /* SDRC_SYSCONFIG */
+        return s->config;
+
+    case 0x14: /* SDRC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* SDRC_CS_CFG */
+    case 0x44: /* SDRC_SHARING */
+    case 0x48: /* SDRC_ERR_ADDR */
+    case 0x4c: /* SDRC_ERR_TYPE */
+    case 0x60: /* SDRC_DLLA_SCTRL */
+    case 0x64: /* SDRC_DLLA_STATUS */
+    case 0x68: /* SDRC_DLLB_CTRL */
+    case 0x6c: /* SDRC_DLLB_STATUS */
+    case 0x70: /* SDRC_POWER */
+    case 0x80: /* SDRC_MCFG_0 */
+    case 0x84: /* SDRC_MR_0 */
+    case 0x88: /* SDRC_EMR1_0 */
+    case 0x8c: /* SDRC_EMR2_0 */
+    case 0x90: /* SDRC_EMR3_0 */
+    case 0x94: /* SDRC_DCDL1_CTRL */
+    case 0x98: /* SDRC_DCDL2_CTRL */
+    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4: /* SDRC_RFR_CTRL_0 */
+    case 0xa8: /* SDRC_MANUAL_0 */
+    case 0xb0: /* SDRC_MCFG_1 */
+    case 0xb4: /* SDRC_MR_1 */
+    case 0xb8: /* SDRC_EMR1_1 */
+    case 0xbc: /* SDRC_EMR2_1 */
+    case 0xc0: /* SDRC_EMR3_1 */
+    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4: /* SDRC_RFR_CTRL_1 */
+    case 0xd8: /* SDRC_MANUAL_1 */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sdrc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00: /* SDRC_REVISION */
+    case 0x14: /* SDRC_SYSSTATUS */
+    case 0x48: /* SDRC_ERR_ADDR */
+    case 0x64: /* SDRC_DLLA_STATUS */
+    case 0x6c: /* SDRC_DLLB_STATUS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10: /* SDRC_SYSCONFIG */
+        if ((value >> 3) != 0x2)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+                            __FUNCTION__, value >> 3);
+        if (value & 2)
+            omap_sdrc_reset(s);
+        s->config = value & 0x18;
+        break;
+
+    case 0x40: /* SDRC_CS_CFG */
+    case 0x44: /* SDRC_SHARING */
+    case 0x4c: /* SDRC_ERR_TYPE */
+    case 0x60: /* SDRC_DLLA_SCTRL */
+    case 0x68: /* SDRC_DLLB_CTRL */
+    case 0x70: /* SDRC_POWER */
+    case 0x80: /* SDRC_MCFG_0 */
+    case 0x84: /* SDRC_MR_0 */
+    case 0x88: /* SDRC_EMR1_0 */
+    case 0x8c: /* SDRC_EMR2_0 */
+    case 0x90: /* SDRC_EMR3_0 */
+    case 0x94: /* SDRC_DCDL1_CTRL */
+    case 0x98: /* SDRC_DCDL2_CTRL */
+    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4: /* SDRC_RFR_CTRL_0 */
+    case 0xa8: /* SDRC_MANUAL_0 */
+    case 0xb0: /* SDRC_MCFG_1 */
+    case 0xb4: /* SDRC_MR_1 */
+    case 0xb8: /* SDRC_EMR1_1 */
+    case 0xbc: /* SDRC_EMR2_1 */
+    case 0xc0: /* SDRC_EMR3_1 */
+    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4: /* SDRC_RFR_CTRL_1 */
+    case 0xd8: /* SDRC_MANUAL_1 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_sdrc_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_sdrc_read,
+};
+
+static CPUWriteMemoryFunc *omap_sdrc_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_sdrc_write,
+};
+
+struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
+{
+    int iomemtype;
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *)
+            qemu_mallocz(sizeof(struct omap_sdrc_s));
+
+    s->base = base;
+    omap_sdrc_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_sdrc_readfn,
+                    omap_sdrc_writefn, s);
+    cpu_register_physical_memory(s->base, 0x1000, iomemtype);
+
+    return s;
+}
+
+/* General-Purpose Memory Controller */
+struct omap_gpmc_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+
+    uint8_t sysconfig;
+    uint16_t irqst;
+    uint16_t irqen;
+    uint16_t timeout;
+    uint16_t config;
+    uint32_t prefconfig[2];
+    int prefcontrol;
+    int preffifo;
+    int prefcount;
+    struct omap_gpmc_cs_file_s {
+        uint32_t config[7];
+        target_phys_addr_t base;
+        size_t size;
+        int iomemtype;
+        void (*base_update)(void *opaque, target_phys_addr_t new);
+        void (*unmap)(void *opaque);
+        void *opaque;
+    } cs_file[8];
+    int ecc_cs;
+    int ecc_ptr;
+    uint32_t ecc_cfg;
+    struct ecc_state_s ecc[9];
+};
+
+static void omap_gpmc_int_update(struct omap_gpmc_s *s)
+{
+    qemu_set_irq(s->irq, s->irqen & s->irqst);
+}
+
+static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask)
+{
+    /* TODO: check for overlapping regions and report access errors */
+    if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) ||
+                    (base < 0 || base >= 0x40) ||
+                    (base & 0x0f & ~mask)) {
+        fprintf(stderr, "%s: wrong cs address mapping/decoding!\n",
+                        __FUNCTION__);
+        return;
+    }
+
+    if (!f->opaque)
+        return;
+
+    f->base = base << 24;
+    f->size = (0x0fffffff & ~(mask << 24)) + 1;
+    /* TODO: rather than setting the size of the mapping (which should be
+     * constant), the mask should cause wrapping of the address space, so
+     * that the same memory becomes accessible at every <i>size</i> bytes
+     * starting from <i>base</i>.  */
+    if (f->iomemtype)
+        cpu_register_physical_memory(f->base, f->size, f->iomemtype);
+
+    if (f->base_update)
+        f->base_update(f->opaque, f->base);
+}
+
+static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f)
+{
+    if (f->size) {
+        if (f->unmap)
+            f->unmap(f->opaque);
+        if (f->iomemtype)
+            cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED);
+        f->base = 0;
+        f->size = 0;
+    }
+}
+
+static void omap_gpmc_reset(struct omap_gpmc_s *s)
+{
+    int i;
+
+    s->sysconfig = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    omap_gpmc_int_update(s);
+    s->timeout = 0;
+    s->config = 0xa00;
+    s->prefconfig[0] = 0x00004000;
+    s->prefconfig[1] = 0x00000000;
+    s->prefcontrol = 0;
+    s->preffifo = 0;
+    s->prefcount = 0;
+    for (i = 0; i < 8; i ++) {
+        if (s->cs_file[i].config[6] & (1 << 6))                        /* 
CSVALID */
+            omap_gpmc_cs_unmap(s->cs_file + i);
+        s->cs_file[i].config[0] = i ? 1 << 12 : 0;
+        s->cs_file[i].config[1] = 0x101001;
+        s->cs_file[i].config[2] = 0x020201;
+        s->cs_file[i].config[3] = 0x10031003;
+        s->cs_file[i].config[4] = 0x10f1111;
+        s->cs_file[i].config[5] = 0;
+        s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
+        if (s->cs_file[i].config[6] & (1 << 6))                        /* 
CSVALID */
+            omap_gpmc_cs_map(&s->cs_file[i],
+                            s->cs_file[i].config[6] & 0x1f,    /* MASKADDR */
+                        (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */
+    }
+    omap_gpmc_cs_map(s->cs_file, 0, 0xf);
+    s->ecc_cs = 0;
+    s->ecc_ptr = 0;
+    s->ecc_cfg = 0x3fcff000;
+    for (i = 0; i < 9; i ++)
+        ecc_reset(&s->ecc[i]);
+}
+
+static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int offset = addr - s->base;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    switch (offset) {
+    case 0x000:        /* GPMC_REVISION */
+        return 0x20;
+
+    case 0x010:        /* GPMC_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x014:        /* GPMC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x018:        /* GPMC_IRQSTATUS */
+        return s->irqst;
+
+    case 0x01c:        /* GPMC_IRQENABLE */
+        return s->irqen;
+
+    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
+        return s->timeout;
+
+    case 0x044:        /* GPMC_ERR_ADDRESS */
+    case 0x048:        /* GPMC_ERR_TYPE */
+        return 0;
+
+    case 0x050:        /* GPMC_CONFIG */
+        return s->config;
+
+    case 0x054:        /* GPMC_STATUS */
+        return 0x001;
+
+    case 0x060 ... 0x1d4:
+        cs = (offset - 0x060) / 0x30;
+        offset -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (offset - cs * 0x30) {
+            case 0x60: /* GPMC_CONFIG1 */
+                return f->config[0];
+            case 0x64: /* GPMC_CONFIG2 */
+                return f->config[1];
+            case 0x68: /* GPMC_CONFIG3 */
+                return f->config[2];
+            case 0x6c: /* GPMC_CONFIG4 */
+                return f->config[3];
+            case 0x70: /* GPMC_CONFIG5 */
+                return f->config[4];
+            case 0x74: /* GPMC_CONFIG6 */
+                return f->config[5];
+            case 0x78: /* GPMC_CONFIG7 */
+                return f->config[6];
+            case 0x84: /* GPMC_NAND_DATA */
+                return 0;
+        }
+        break;
+
+    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
+        return s->prefconfig[0];
+    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
+        return s->prefconfig[1];
+    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
+        return s->prefcontrol;
+    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
+        return (s->preffifo << 24) |
+                ((s->preffifo >
+                  ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) |
+                s->prefcount;
+
+    case 0x1f4:        /* GPMC_ECC_CONFIG */
+        return s->ecc_cs;
+    case 0x1f8:        /* GPMC_ECC_CONTROL */
+        return s->ecc_ptr;
+    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
+        return s->ecc_cfg;
+    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
+        cs = (offset & 0x1f) >> 2;
+        /* TODO: check correctness */
+        return
+                ((s->ecc[cs].cp    &  0x07) <<  0) |
+                ((s->ecc[cs].cp    &  0x38) << 13) |
+                ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
+                ((s->ecc[cs].lp[1] & 0x1ff) << 19);
+
+    case 0x230:        /* GPMC_TESTMODE_CTRL */
+        return 0;
+    case 0x234:        /* GPMC_PSA_LSB */
+    case 0x238:        /* GPMC_PSA_MSB */
+        return 0x00000000;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int offset = addr - s->base;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    switch (offset) {
+    case 0x000:        /* GPMC_REVISION */
+    case 0x014:        /* GPMC_SYSSTATUS */
+    case 0x054:        /* GPMC_STATUS */
+    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
+    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
+    case 0x234:        /* GPMC_PSA_LSB */
+    case 0x238:        /* GPMC_PSA_MSB */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x010:        /* GPMC_SYSCONFIG */
+        if ((value >> 3) == 0x3)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+                            __FUNCTION__, value >> 3);
+        if (value & 2)
+            omap_gpmc_reset(s);
+        s->sysconfig = value & 0x19;
+        break;
+
+    case 0x018:        /* GPMC_IRQSTATUS */
+        s->irqen = ~value;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x01c:        /* GPMC_IRQENABLE */
+        s->irqen = value & 0xf03;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
+        s->timeout = value & 0x1ff1;
+        break;
+
+    case 0x044:        /* GPMC_ERR_ADDRESS */
+    case 0x048:        /* GPMC_ERR_TYPE */
+        break;
+
+    case 0x050:        /* GPMC_CONFIG */
+        s->config = value & 0xf13;
+        break;
+
+    case 0x060 ... 0x1d4:
+        cs = (offset - 0x060) / 0x30;
+        offset -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (offset) {
+            case 0x60: /* GPMC_CONFIG1 */
+                f->config[0] = value & 0xffef3e13;
+                break;
+            case 0x64: /* GPMC_CONFIG2 */
+                f->config[1] = value & 0x001f1f8f;
+                break;
+            case 0x68: /* GPMC_CONFIG3 */
+                f->config[2] = value & 0x001f1f8f;
+                break;
+            case 0x6c: /* GPMC_CONFIG4 */
+                f->config[3] = value & 0x1f8f1f8f;
+                break;
+            case 0x70: /* GPMC_CONFIG5 */
+                f->config[4] = value & 0x0f1f1f1f;
+                break;
+            case 0x74: /* GPMC_CONFIG6 */
+                f->config[5] = value & 0x00000fcf;
+                break;
+            case 0x78: /* GPMC_CONFIG7 */
+                if ((f->config[6] ^ value) & 0xf7f) {
+                    if (f->config[6] & (1 << 6))               /* CSVALID */
+                        omap_gpmc_cs_unmap(f);
+                    if (value & (1 << 6))                      /* CSVALID */
+                        omap_gpmc_cs_map(f, value & 0x1f,      /* MASKADDR */
+                                        (value >> 8 & 0xf));   /* BASEADDR */
+                }
+                f->config[6] = value & 0x00000f7f;
+                break;
+            case 0x7c: /* GPMC_NAND_COMMAND */
+            case 0x80: /* GPMC_NAND_ADDRESS */
+            case 0x84: /* GPMC_NAND_DATA */
+                break;
+
+            default:
+                goto bad_reg;
+        }
+        break;
+
+    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
+        s->prefconfig[0] = value & 0x7f8f7fbf;
+        /* TODO: update interrupts, fifos, dmas */
+        break;
+
+    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
+        s->prefconfig[1] = value & 0x3fff;
+        break;
+
+    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
+        s->prefcontrol = value & 1;
+        if (s->prefcontrol) {
+            if (s->prefconfig[0] & 1)
+                s->preffifo = 0x40;
+            else
+                s->preffifo = 0x00;
+        }
+        /* TODO: start */
+        break;
+
+    case 0x1f4:        /* GPMC_ECC_CONFIG */
+        s->ecc_cs = 0x8f;
+        break;
+    case 0x1f8:        /* GPMC_ECC_CONTROL */
+        if (value & (1 << 8))
+            for (cs = 0; cs < 9; cs ++)
+                ecc_reset(&s->ecc[cs]);
+        s->ecc_ptr = value & 0xf;
+        if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
+            s->ecc_ptr = 0;
+            s->ecc_cs &= ~1;
+        }
+        break;
+    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
+        s->ecc_cfg = value & 0x3fcff1ff;
+        break;
+    case 0x230:        /* GPMC_TESTMODE_CTRL */
+        if (value & 7)
+            fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
+        break;
+
+    default:
+    bad_reg:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_gpmc_readfn[] = {
+    omap_badwidth_read32,      /* TODO */
+    omap_badwidth_read32,      /* TODO */
+    omap_gpmc_read,
+};
+
+static CPUWriteMemoryFunc *omap_gpmc_writefn[] = {
+    omap_badwidth_write32,     /* TODO */
+    omap_badwidth_write32,     /* TODO */
+    omap_gpmc_write,
+};
+
+struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
+{
+    int iomemtype;
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *)
+            qemu_mallocz(sizeof(struct omap_gpmc_s));
+
+    s->base = base;
+    omap_gpmc_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_gpmc_readfn,
+                    omap_gpmc_writefn, s);
+    cpu_register_physical_memory(s->base, 0x1000, iomemtype);
+
+    return s;
+}
+
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
+                void (*base_upd)(void *opaque, target_phys_addr_t new),
+                void (*unmap)(void *opaque), void *opaque)
+{
+    struct omap_gpmc_cs_file_s *f;
+
+    if (cs < 0 || cs >= 8) {
+        fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+    f = &s->cs_file[cs];
+
+    f->iomemtype = iomemtype;
+    f->base_update = base_upd;
+    f->unmap = unmap;
+    f->opaque = opaque;
+
+    if (f->config[6] & (1 << 6))                               /* CSVALID */
+        omap_gpmc_cs_map(f, f->config[6] & 0x1f,               /* MASKADDR */
+                        (f->config[6] >> 8 & 0xf));            /* BASEADDR */
+}
+
+/* General chip reset */
+static void omap2_mpu_reset(void *opaque)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    omap_inth_reset(mpu->ih[0]);
+    omap_dma_reset(mpu->dma);
+    omap_prcm_reset(mpu->prcm);
+    omap_sysctl_reset(mpu->sysc);
+    omap_gp_timer_reset(mpu->gptimer[0]);
+    omap_gp_timer_reset(mpu->gptimer[1]);
+    omap_gp_timer_reset(mpu->gptimer[2]);
+    omap_gp_timer_reset(mpu->gptimer[3]);
+    omap_gp_timer_reset(mpu->gptimer[4]);
+    omap_gp_timer_reset(mpu->gptimer[5]);
+    omap_gp_timer_reset(mpu->gptimer[6]);
+    omap_gp_timer_reset(mpu->gptimer[7]);
+    omap_gp_timer_reset(mpu->gptimer[8]);
+    omap_gp_timer_reset(mpu->gptimer[9]);
+    omap_gp_timer_reset(mpu->gptimer[10]);
+    omap_gp_timer_reset(mpu->gptimer[11]);
+    omap_synctimer_reset(&mpu->synctimer);
+    omap_sdrc_reset(mpu->sdrc);
+    omap_gpmc_reset(mpu->gpmc);
+    omap_dss_reset(mpu->dss);
+    omap_uart_reset(mpu->uart[0]);
+    omap_uart_reset(mpu->uart[1]);
+    omap_uart_reset(mpu->uart[2]);
+    omap_mmc_reset(mpu->mmc);
+    omap_gpif_reset(mpu->gpif);
+    omap_mcspi_reset(mpu->mcspi[0]);
+    omap_mcspi_reset(mpu->mcspi[1]);
+    omap_i2c_reset(mpu->i2c[0]);
+    omap_i2c_reset(mpu->i2c[1]);
+    cpu_reset(mpu->env);
+}
+
+static int omap2_validate_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return 1;
+}
+
+static const struct dma_irq_map omap2_dma_irq_map[] = {
+    { 0, OMAP_INT_24XX_SDMA_IRQ0 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ1 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ2 },
+    { 0, OMAP_INT_24XX_SDMA_IRQ3 },
+};
+
+struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
+                DisplayState *ds, const char *core)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_state_s));
+    ram_addr_t sram_base, q3_base;
+    qemu_irq *cpu_irq;
+    qemu_irq dma_irqs[4];
+    omap_clk gpio_clks[4];
+    int sdindex;
+    int i;
+
+    /* Core */
+    s->mpu_model = omap2420;
+    s->env = cpu_init(core ?: "arm1136-r2");
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->sdram_size = sdram_size;
+    s->sram_size = OMAP242X_SRAM_SIZE;
+
+    s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
+
+    /* Clocks */
+    omap_clk_init(s);
+
+    /* Memory-mapped stuff */
+    cpu_register_physical_memory(OMAP2_Q2_BASE, s->sdram_size,
+                    (q3_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM);
+    cpu_register_physical_memory(OMAP2_SRAM_BASE, s->sram_size,
+                    (sram_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM);
+
+    s->l4 = omap_l4_init(OMAP2_L4_BASE, 54);
+
+    /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
+    cpu_irq = arm_pic_init_cpu(s->env);
+    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
+                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
+                    omap_findclk(s, "mpu_intc_fclk"),
+                    omap_findclk(s, "mpu_intc_iclk"));
+
+    s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
+                    s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s);
+
+    s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
+                    omap_findclk(s, "omapctrl_iclk"), s);
+
+    for (i = 0; i < 4; i ++)
+        dma_irqs[i] =
+                s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr];
+    s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
+                    omap_findclk(s, "sdma_iclk"),
+                    omap_findclk(s, "sdma_fclk"));
+    s->port->addr_valid = omap2_validate_addr;
+
+    s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
+                    s->irq[0][OMAP_INT_24XX_UART1_IRQ],
+                    omap_findclk(s, "uart1_fclk"),
+                    omap_findclk(s, "uart1_iclk"),
+                    s->drq[OMAP24XX_DMA_UART1_TX],
+                    s->drq[OMAP24XX_DMA_UART1_RX], serial_hds[0]);
+    s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
+                    s->irq[0][OMAP_INT_24XX_UART2_IRQ],
+                    omap_findclk(s, "uart2_fclk"),
+                    omap_findclk(s, "uart2_iclk"),
+                    s->drq[OMAP24XX_DMA_UART2_TX],
+                    s->drq[OMAP24XX_DMA_UART2_RX],
+                    serial_hds[0] ? serial_hds[1] : 0);
+    s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
+                    s->irq[0][OMAP_INT_24XX_UART3_IRQ],
+                    omap_findclk(s, "uart3_fclk"),
+                    omap_findclk(s, "uart3_iclk"),
+                    s->drq[OMAP24XX_DMA_UART3_TX],
+                    s->drq[OMAP24XX_DMA_UART3_RX],
+                    serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0);
+
+    s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER1],
+                    omap_findclk(s, "wu_gpt1_clk"),
+                    omap_findclk(s, "wu_l4_iclk"));
+    s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER2],
+                    omap_findclk(s, "core_gpt2_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER3],
+                    omap_findclk(s, "core_gpt3_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER4],
+                    omap_findclk(s, "core_gpt4_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER5],
+                    omap_findclk(s, "core_gpt5_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER6],
+                    omap_findclk(s, "core_gpt6_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER7],
+                    omap_findclk(s, "core_gpt7_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER8],
+                    omap_findclk(s, "core_gpt8_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER9],
+                    omap_findclk(s, "core_gpt9_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER10],
+                    omap_findclk(s, "core_gpt10_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER11],
+                    omap_findclk(s, "core_gpt11_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+    s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
+                    s->irq[0][OMAP_INT_24XX_GPTIMER12],
+                    omap_findclk(s, "core_gpt12_clk"),
+                    omap_findclk(s, "core_l4_iclk"));
+
+    omap_tap_init(omap_l4ta(s->l4, 2), s);
+
+    omap_synctimer_init(omap_l4tao(s->l4, 2), s,
+                    omap_findclk(s, "clk32-kHz"),
+                    omap_findclk(s, "core_l4_iclk"));
+
+    s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
+                    s->irq[0][OMAP_INT_24XX_I2C1_IRQ],
+                    &s->drq[OMAP24XX_DMA_I2C1_TX],
+                    omap_findclk(s, "i2c1.fclk"),
+                    omap_findclk(s, "i2c1.iclk"));
+    s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
+                    s->irq[0][OMAP_INT_24XX_I2C2_IRQ],
+                    &s->drq[OMAP24XX_DMA_I2C2_TX],
+                    omap_findclk(s, "i2c2.fclk"),
+                    omap_findclk(s, "i2c2.iclk"));
+
+    gpio_clks[0] = omap_findclk(s, "gpio1_dbclk");
+    gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
+    gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
+    gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
+    s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
+                    &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
+                    gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
+
+    s->sdrc = omap_sdrc_init(0x68009000);
+    s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
+
+    sdindex = drive_get_index(IF_SD, 0, 0);
+    if (sdindex == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), drives_table[sdindex].bdrv,
+                    s->irq[0][OMAP_INT_24XX_MMC_IRQ],
+                    &s->drq[OMAP24XX_DMA_MMC1_TX],
+                    omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
+
+    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
+                    s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ], 
+                    &s->drq[OMAP24XX_DMA_SPI1_TX0],
+                    omap_findclk(s, "spi1_fclk"),
+                    omap_findclk(s, "spi1_iclk"));
+    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
+                    s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ], 
+                    &s->drq[OMAP24XX_DMA_SPI2_TX0],
+                    omap_findclk(s, "spi2_fclk"),
+                    omap_findclk(s, "spi2_iclk"));
+
+    s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800, ds,
+                    /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
+                    s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
+                    omap_findclk(s, "dss_54m_clk"),
+                    omap_findclk(s, "dss_l3_iclk"),
+                    omap_findclk(s, "dss_l4_iclk"));
+
+    /* All register mappings (includin those not currenlty implemented):
+     * SystemControlMod        48000000 - 48000fff
+     * SystemControlL4 48001000 - 48001fff
+     * 32kHz Timer Mod 48004000 - 48004fff
+     * 32kHz Timer L4  48005000 - 48005fff
+     * PRCM ModA       48008000 - 480087ff
+     * PRCM ModB       48008800 - 48008fff
+     * PRCM L4         48009000 - 48009fff
+     * TEST-BCM Mod    48012000 - 48012fff
+     * TEST-BCM L4     48013000 - 48013fff
+     * TEST-TAP Mod    48014000 - 48014fff
+     * TEST-TAP L4     48015000 - 48015fff
+     * GPIO1 Mod       48018000 - 48018fff
+     * GPIO Top                48019000 - 48019fff
+     * GPIO2 Mod       4801a000 - 4801afff
+     * GPIO L4         4801b000 - 4801bfff
+     * GPIO3 Mod       4801c000 - 4801cfff
+     * GPIO4 Mod       4801e000 - 4801efff
+     * WDTIMER1 Mod    48020000 - 48010fff
+     * WDTIMER Top     48021000 - 48011fff
+     * WDTIMER2 Mod    48022000 - 48012fff
+     * WDTIMER L4      48023000 - 48013fff
+     * WDTIMER3 Mod    48024000 - 48014fff
+     * WDTIMER3 L4     48025000 - 48015fff
+     * WDTIMER4 Mod    48026000 - 48016fff
+     * WDTIMER4 L4     48027000 - 48017fff
+     * GPTIMER1 Mod    48028000 - 48018fff
+     * GPTIMER1 L4     48029000 - 48019fff
+     * GPTIMER2 Mod    4802a000 - 4801afff
+     * GPTIMER2 L4     4802b000 - 4801bfff
+     * L4-Config AP    48040000 - 480407ff
+     * L4-Config IP    48040800 - 48040fff
+     * L4-Config LA    48041000 - 48041fff
+     * ARM11ETB Mod    48048000 - 48049fff
+     * ARM11ETB L4     4804a000 - 4804afff
+     * DISPLAY Top     48050000 - 480503ff
+     * DISPLAY DISPC   48050400 - 480507ff
+     * DISPLAY RFBI    48050800 - 48050bff
+     * DISPLAY VENC    48050c00 - 48050fff
+     * DISPLAY L4      48051000 - 48051fff
+     * CAMERA Top      48052000 - 480523ff
+     * CAMERA core     48052400 - 480527ff
+     * CAMERA DMA      48052800 - 48052bff
+     * CAMERA MMU      48052c00 - 48052fff
+     * CAMERA L4       48053000 - 48053fff
+     * SDMA Mod                48056000 - 48056fff
+     * SDMA L4         48057000 - 48057fff
+     * SSI Top         48058000 - 48058fff
+     * SSI GDD         48059000 - 48059fff
+     * SSI Port1       4805a000 - 4805afff
+     * SSI Port2       4805b000 - 4805bfff
+     * SSI L4          4805c000 - 4805cfff
+     * USB Mod         4805e000 - 480fefff
+     * USB L4          4805f000 - 480fffff
+     * WIN_TRACER1 Mod 48060000 - 48060fff
+     * WIN_TRACER1 L4  48061000 - 48061fff
+     * WIN_TRACER2 Mod 48062000 - 48062fff
+     * WIN_TRACER2 L4  48063000 - 48063fff
+     * WIN_TRACER3 Mod 48064000 - 48064fff
+     * WIN_TRACER3 L4  48065000 - 48065fff
+     * WIN_TRACER4 Top 48066000 - 480660ff
+     * WIN_TRACER4 ETT 48066100 - 480661ff
+     * WIN_TRACER4 WT  48066200 - 480662ff
+     * WIN_TRACER4 L4  48067000 - 48067fff
+     * XTI Mod         48068000 - 48068fff
+     * XTI L4          48069000 - 48069fff
+     * UART1 Mod       4806a000 - 4806afff
+     * UART1 L4                4806b000 - 4806bfff
+     * UART2 Mod       4806c000 - 4806cfff
+     * UART2 L4                4806d000 - 4806dfff
+     * UART3 Mod       4806e000 - 4806efff
+     * UART3 L4                4806f000 - 4806ffff
+     * I2C1 Mod                48070000 - 48070fff
+     * I2C1 L4         48071000 - 48071fff
+     * I2C2 Mod                48072000 - 48072fff
+     * I2C2 L4         48073000 - 48073fff
+     * McBSP1 Mod      48074000 - 48074fff
+     * McBSP1 L4       48075000 - 48075fff
+     * McBSP2 Mod      48076000 - 48076fff
+     * McBSP2 L4       48077000 - 48077fff
+     * GPTIMER3 Mod    48078000 - 48078fff
+     * GPTIMER3 L4     48079000 - 48079fff
+     * GPTIMER4 Mod    4807a000 - 4807afff
+     * GPTIMER4 L4     4807b000 - 4807bfff
+     * GPTIMER5 Mod    4807c000 - 4807cfff
+     * GPTIMER5 L4     4807d000 - 4807dfff
+     * GPTIMER6 Mod    4807e000 - 4807efff
+     * GPTIMER6 L4     4807f000 - 4807ffff
+     * GPTIMER7 Mod    48080000 - 48080fff
+     * GPTIMER7 L4     48081000 - 48081fff
+     * GPTIMER8 Mod    48082000 - 48082fff
+     * GPTIMER8 L4     48083000 - 48083fff
+     * GPTIMER9 Mod    48084000 - 48084fff
+     * GPTIMER9 L4     48085000 - 48085fff
+     * GPTIMER10 Mod   48086000 - 48086fff
+     * GPTIMER10 L4    48087000 - 48087fff
+     * GPTIMER11 Mod   48088000 - 48088fff
+     * GPTIMER11 L4    48089000 - 48089fff
+     * GPTIMER12 Mod   4808a000 - 4808afff
+     * GPTIMER12 L4    4808b000 - 4808bfff
+     * EAC Mod         48090000 - 48090fff
+     * EAC L4          48091000 - 48091fff
+     * FAC Mod         48092000 - 48092fff
+     * FAC L4          48093000 - 48093fff
+     * MAILBOX Mod     48094000 - 48094fff
+     * MAILBOX L4      48095000 - 48095fff
+     * SPI1 Mod                48098000 - 48098fff
+     * SPI1 L4         48099000 - 48099fff
+     * SPI2 Mod                4809a000 - 4809afff
+     * SPI2 L4         4809b000 - 4809bfff
+     * MMC/SDIO Mod    4809c000 - 4809cfff
+     * MMC/SDIO L4     4809d000 - 4809dfff
+     * MS_PRO Mod      4809e000 - 4809efff
+     * MS_PRO L4       4809f000 - 4809ffff
+     * RNG Mod         480a0000 - 480a0fff
+     * RNG L4          480a1000 - 480a1fff
+     * DES3DES Mod     480a2000 - 480a2fff
+     * DES3DES L4      480a3000 - 480a3fff
+     * SHA1MD5 Mod     480a4000 - 480a4fff
+     * SHA1MD5 L4      480a5000 - 480a5fff
+     * AES Mod         480a6000 - 480a6fff
+     * AES L4          480a7000 - 480a7fff
+     * PKA Mod         480a8000 - 480a9fff
+     * PKA L4          480aa000 - 480aafff
+     * MG Mod          480b0000 - 480b0fff
+     * MG L4           480b1000 - 480b1fff
+     * HDQ/1-wire Mod  480b2000 - 480b2fff
+     * HDQ/1-wire L4   480b3000 - 480b3fff
+     * MPU interrupt   480fe000 - 480fefff
+     * IVA RAM         5c000000 - 5c01ffff
+     * IVA ROM         5c020000 - 5c027fff
+     * IMG_BUF_A       5c040000 - 5c040fff
+     * IMG_BUF_B       5c042000 - 5c042fff
+     * VLCDS           5c048000 - 5c0487ff
+     * IMX_COEF                5c049000 - 5c04afff
+     * IMX_CMD         5c051000 - 5c051fff
+     * VLCDQ           5c053000 - 5c0533ff
+     * VLCDH           5c054000 - 5c054fff
+     * SEQ_CMD         5c055000 - 5c055fff
+     * IMX_REG         5c056000 - 5c0560ff
+     * VLCD_REG                5c056100 - 5c0561ff
+     * SEQ_REG         5c056200 - 5c0562ff
+     * IMG_BUF_REG     5c056300 - 5c0563ff
+     * SEQIRQ_REG      5c056400 - 5c0564ff
+     * OCP_REG         5c060000 - 5c060fff
+     * SYSC_REG                5c070000 - 5c070fff
+     * MMU_REG         5d000000 - 5d000fff
+     * sDMA R          68000400 - 680005ff
+     * sDMA W          68000600 - 680007ff
+     * Display Control 68000800 - 680009ff
+     * DSP subsystem   68000a00 - 68000bff
+     * MPU subsystem   68000c00 - 68000dff
+     * IVA subsystem   68001000 - 680011ff
+     * USB             68001200 - 680013ff
+     * Camera          68001400 - 680015ff
+     * VLYNQ (firewall)        68001800 - 68001bff
+     * VLYNQ           68001e00 - 68001fff
+     * SSI             68002000 - 680021ff
+     * L4              68002400 - 680025ff
+     * DSP (firewall)  68002800 - 68002bff
+     * DSP subsystem   68002e00 - 68002fff
+     * IVA (firewall)  68003000 - 680033ff
+     * IVA             68003600 - 680037ff
+     * GFX             68003a00 - 68003bff
+     * CMDWR emulation 68003c00 - 68003dff
+     * SMS             68004000 - 680041ff
+     * OCM             68004200 - 680043ff
+     * GPMC            68004400 - 680045ff
+     * RAM (firewall)  68005000 - 680053ff
+     * RAM (err login) 68005400 - 680057ff
+     * ROM (firewall)  68005800 - 68005bff
+     * ROM (err login) 68005c00 - 68005fff
+     * GPMC (firewall) 68006000 - 680063ff
+     * GPMC (err login)        68006400 - 680067ff
+     * SMS (err login) 68006c00 - 68006fff
+     * SMS registers   68008000 - 68008fff
+     * SDRC registers  68009000 - 68009fff
+     * GPMC registers  6800a000   6800afff
+     */
+
+    qemu_register_reset(omap2_mpu_reset, s);
+
+    return s;
+}

Modified: trunk/hw/omap_clk.c
===================================================================
--- trunk/hw/omap_clk.c 2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap_clk.c 2008-04-14 21:05:22 UTC (rev 4213)
@@ -1,7 +1,7 @@
 /*
  * OMAP clocks.
  *
- * Copyright (C) 2006-2007 Andrzej Zaborowski  <address@hidden>
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <address@hidden>
  *
  * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
  *
@@ -34,6 +34,9 @@
 #define CLOCK_IN_OMAP730       (1 << 11)
 #define CLOCK_IN_OMAP1510      (1 << 12)
 #define CLOCK_IN_OMAP16XX      (1 << 13)
+#define CLOCK_IN_OMAP242X      (1 << 14)
+#define CLOCK_IN_OMAP243X      (1 << 15)
+#define CLOCK_IN_OMAP343X      (1 << 16)
     uint32_t flags;
     int id;
 
@@ -55,7 +58,8 @@
 static struct clk xtal_osc32k = {
     .name      = "xtal_osc_32k",
     .rate      = 32768,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
 };
 
 static struct clk ck_ref = {
@@ -502,11 +506,441 @@
 static struct clk clk32k = {
     .name      = "clk32-kHz",
     .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-            ALWAYS_ENABLED,
-    .parent     = &xtal_osc32k,
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent    = &xtal_osc32k,
 };
 
+static struct clk apll_96m = {
+    .name      = "apll_96m",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 96000000,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk apll_54m = {
+    .name      = "apll_54m",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 54000000,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk sys_clk = {
+    .name      = "sys_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk sleep_clk = {
+    .name      = "sleep_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk dpll_ck = {
+    .name      = "dpll",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk dpll_x2_ck = {
+    .name      = "dpll_x2",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk wdt1_sys_clk = {
+    .name      = "wdt1_sys_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk func_96m_clk = {
+    .name      = "func_96m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 1,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_48m_clk = {
+    .name      = "func_48m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_12m_clk = {
+    .name      = "func_12m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 8,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_54m_clk = {
+    .name      = "func_54m_clk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .divisor   = 1,
+    .parent    = &apll_54m,
+};
+
+static struct clk sys_clkout = {
+    .name      = "clkout",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk sys_clkout2 = {
+    .name      = "clkout2",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_clk = {
+    .name      = "core_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &dpll_ck,
+};
+
+static struct clk l3_clk = {
+    .name      = "l3_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_l4_iclk = {
+    .name      = "core_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk wu_l4_iclk = {
+    .name      = "wu_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk core_l3_iclk = {
+    .name      = "core_l3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_l4_usb_clk = {
+    .name      = "core_l4_usb_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk wu_gpt1_clk = {
+    .name      = "wu_gpt1_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk wu_32k_clk = {
+    .name      = "wu_32k_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk uart1_fclk = {
+    .name      = "uart1_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart1_iclk = {
+    .name      = "uart1_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk uart2_fclk = {
+    .name      = "uart2_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart2_iclk = {
+    .name      = "uart2_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk uart3_fclk = {
+    .name      = "uart3_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart3_iclk = {
+    .name      = "uart3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk mpu_fclk = {
+    .name      = "mpu_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk mpu_iclk = {
+    .name      = "mpu_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk int_m_fclk = {
+    .name      = "int_m_fclk",
+    .alias     = "mpu_intc_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk int_m_iclk = {
+    .name      = "int_m_iclk",
+    .alias     = "mpu_intc_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_gpt2_clk = {
+    .name      = "core_gpt2_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt3_clk = {
+    .name      = "core_gpt3_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt4_clk = {
+    .name      = "core_gpt4_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt5_clk = {
+    .name      = "core_gpt5_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt6_clk = {
+    .name      = "core_gpt6_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt7_clk = {
+    .name      = "core_gpt7_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt8_clk = {
+    .name      = "core_gpt8_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt9_clk = {
+    .name      = "core_gpt9_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt10_clk = {
+    .name      = "core_gpt10_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt11_clk = {
+    .name      = "core_gpt11_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt12_clk = {
+    .name      = "core_gpt12_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk mcbsp1_clk = {
+    .name      = "mcbsp1_cg",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk mcbsp2_clk = {
+    .name      = "mcbsp2_cg",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk emul_clk = {
+    .name      = "emul_ck",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_54m_clk,
+};
+
+static struct clk sdma_fclk = {
+    .name      = "sdma_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk sdma_iclk = {
+    .name      = "sdma_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l3_iclk, /* core_l4_iclk for the configuration port */
+};
+
+static struct clk i2c1_fclk = {
+    .name      = "i2c1.fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_12m_clk,
+    .divisor   = 1,
+};
+
+static struct clk i2c1_iclk = {
+    .name      = "i2c1.iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk i2c2_fclk = {
+    .name      = "i2c2.fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_12m_clk,
+    .divisor   = 1,
+};
+
+static struct clk i2c2_iclk = {
+    .name      = "i2c2.iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk gpio_dbclk[4] = {
+    {
+        .name  = "gpio1_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio2_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio3_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio4_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    },
+};
+
+static struct clk gpio_iclk = {
+    .name      = "gpio_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &wu_l4_iclk,
+};
+
+static struct clk mmc_fck = {
+    .name      = "mmc_fclk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk mmc_ick = {
+    .name      = "mmc_iclk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk spi_fclk[3] = {
+    {
+        .name  = "spi1_fclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    }, {
+        .name  = "spi2_fclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    }, {
+        .name  = "spi3_fclk",
+        .flags = CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    },
+};
+
+static struct clk dss_clk[2] = {
+    {
+        .name  = "dss_clk1",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_clk,
+    }, {
+        .name  = "dss_clk2",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &sys_clk,
+    },
+};
+
+static struct clk dss_54m_clk = {
+    .name      = "dss_54m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_54m_clk,
+};
+
+static struct clk dss_l3_iclk = {
+    .name      = "dss_l3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l3_iclk,
+};
+
+static struct clk dss_l4_iclk = {
+    .name      = "dss_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk spi_iclk[3] = {
+    {
+        .name  = "spi1_iclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    }, {
+        .name  = "spi2_iclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    }, {
+        .name  = "spi3_iclk",
+        .flags = CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    },
+};
+
+static struct clk omapctrl_clk = {
+    .name      = "omapctrl_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    /* XXX Should be in WKUP domain */
+    .parent    = &core_l4_iclk,
+};
+
 static struct clk *onchip_clks[] = {
+    /* OMAP 1 */
+
     /* non-ULPD clocks */
     &xtal_osc12m,
     &xtal_osc32k,
@@ -572,6 +1006,80 @@
     /* Virtual clocks */
     &i2c_fck,
     &i2c_ick,
+
+    /* OMAP 2 */
+
+    &apll_96m,
+    &apll_54m,
+    &sys_clk,
+    &sleep_clk,
+    &dpll_ck,
+    &dpll_x2_ck,
+    &wdt1_sys_clk,
+    &func_96m_clk,
+    &func_48m_clk,
+    &func_12m_clk,
+    &func_54m_clk,
+    &sys_clkout,
+    &sys_clkout2,
+    &core_clk,
+    &l3_clk,
+    &core_l4_iclk,
+    &wu_l4_iclk,
+    &core_l3_iclk,
+    &core_l4_usb_clk,
+    &wu_gpt1_clk,
+    &wu_32k_clk,
+    &uart1_fclk,
+    &uart1_iclk,
+    &uart2_fclk,
+    &uart2_iclk,
+    &uart3_fclk,
+    &uart3_iclk,
+    &mpu_fclk,
+    &mpu_iclk,
+    &int_m_fclk,
+    &int_m_iclk,
+    &core_gpt2_clk,
+    &core_gpt3_clk,
+    &core_gpt4_clk,
+    &core_gpt5_clk,
+    &core_gpt6_clk,
+    &core_gpt7_clk,
+    &core_gpt8_clk,
+    &core_gpt9_clk,
+    &core_gpt10_clk,
+    &core_gpt11_clk,
+    &core_gpt12_clk,
+    &mcbsp1_clk,
+    &mcbsp2_clk,
+    &emul_clk,
+    &sdma_fclk,
+    &sdma_iclk,
+    &i2c1_fclk,
+    &i2c1_iclk,
+    &i2c2_fclk,
+    &i2c2_iclk,
+    &gpio_dbclk[0],
+    &gpio_dbclk[1],
+    &gpio_dbclk[2],
+    &gpio_dbclk[3],
+    &gpio_iclk,
+    &mmc_fck,
+    &mmc_ick,
+    &spi_fclk[0],
+    &spi_iclk[0],
+    &spi_fclk[1],
+    &spi_iclk[1],
+    &spi_fclk[2],
+    &spi_iclk[2],
+    &dss_clk[0],
+    &dss_clk[1],
+    &dss_54m_clk,
+    &dss_l3_iclk,
+    &dss_l4_iclk,
+    &omapctrl_clk,
+
     0
 };
 
@@ -727,6 +1235,12 @@
         flag = CLOCK_IN_OMAP310;
     else if (cpu_is_omap1510(mpu))
         flag = CLOCK_IN_OMAP1510;
+    else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
+        flag = CLOCK_IN_OMAP242X;
+    else if (cpu_is_omap2430(mpu))
+        flag = CLOCK_IN_OMAP243X;
+    else if (cpu_is_omap3430(mpu))
+        flag = CLOCK_IN_OMAP243X;
     else
         return;
 

Modified: trunk/hw/omap_dma.c
===================================================================
--- trunk/hw/omap_dma.c 2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap_dma.c 2008-04-14 21:05:22 UTC (rev 4213)
@@ -28,12 +28,15 @@
     /* transfer data */
     int burst[2];
     int pack[2];
+    int endian[2];
+    int endian_lock[2];
+    int translate[2];
     enum omap_dma_port port[2];
     target_phys_addr_t addr[2];
     omap_dma_addressing_t mode[2];
-    uint16_t elements;
+    uint32_t elements;
     uint16_t frames;
-    int16_t frame_index[2];
+    int32_t frame_index[2];
     int16_t element_index[2];
     int data_type;
 
@@ -41,6 +44,7 @@
     int transparent_copy;
     int constant_fill;
     uint32_t color;
+    int prefetch;
 
     /* auto init and linked channel data */
     int end_prog;
@@ -52,11 +56,13 @@
     /* interruption data */
     int interrupts;
     int status;
+    int cstatus;
 
     /* state data */
     int active;
     int enable;
     int sync;
+    int src_sync;
     int pending_request;
     int waiting_end_prog;
     uint16_t cpc;
@@ -75,16 +81,21 @@
         target_phys_addr_t src, dest;
         int frame;
         int element;
+        int pck_element;
         int frame_delta[2];
         int elem_delta[2];
         int frames;
         int elements;
+        int pck_elements;
     } active_set;
 
     /* unused parameters */
+    int write_mode;
     int priority;
     int interleave_disabled;
     int type;
+    int suspend;
+    int buf_disable;
 };
 
 struct omap_dma_s {
@@ -93,15 +104,21 @@
     target_phys_addr_t base;
     omap_clk clk;
     int64_t delay;
-    uint32_t drq;
+    uint64_t drq;
+    qemu_irq irq[4];
+    void (*intr_update)(struct omap_dma_s *s);
     enum omap_dma_model model;
     int omap_3_1_mapping_disabled;
 
-    uint16_t gcr;
+    uint32_t gcr;
+    uint32_t ocp;
+    uint32_t caps[5];
+    uint32_t irqen[4];
+    uint32_t irqstat[4];
     int run_count;
 
     int chans;
-    struct omap_dma_channel_s ch[16];
+    struct omap_dma_channel_s ch[32];
     struct omap_dma_lcd_channel_s lcd_ch;
 };
 
@@ -113,23 +130,13 @@
 #define LAST_FRAME_INTR (1 << 4)
 #define END_BLOCK_INTR  (1 << 5)
 #define SYNC            (1 << 6)
+#define END_PKT_INTR   (1 << 7)
+#define TRANS_ERR_INTR (1 << 8)
+#define MISALIGN_INTR  (1 << 11)
 
-static void omap_dma_interrupts_update(struct omap_dma_s *s)
+static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
 {
-    struct omap_dma_channel_s *ch = s->ch;
-    int i;
-
-    if (s->omap_3_1_mapping_disabled) {
-        for (i = 0; i < s->chans; i ++, ch ++)
-            if (ch->status)
-                qemu_irq_raise(ch->irq);
-    } else {
-        /* First three interrupts are shared between two channels each. */
-        for (i = 0; i < 6; i ++, ch ++) {
-            if (ch->status || (ch->sibling && ch->sibling->status))
-                qemu_irq_raise(ch->irq);
-        }
-    }
+    return s->intr_update(s);
 }
 
 static void omap_dma_channel_load(struct omap_dma_s *s,
@@ -148,8 +155,10 @@
     a->dest = ch->addr[1];
     a->frames = ch->frames;
     a->elements = ch->elements;
+    a->pck_elements = ch->frame_index[!ch->src_sync];
     a->frame = 0;
     a->element = 0;
+    a->pck_element = 0;
 
     if (unlikely(!ch->elements || !ch->frames)) {
         printf("%s: bad DMA request\n", __FUNCTION__);
@@ -202,16 +211,15 @@
     /* Update cpc */
     ch->cpc = ch->active_set.dest & 0xffff;
 
-    if (ch->pending_request && !ch->waiting_end_prog) {
+    if (ch->pending_request && !ch->waiting_end_prog && ch->enable) {
         /* Don't deactivate the channel */
         ch->pending_request = 0;
-        if (ch->enable)
-            return;
+        return;
     }
 
     /* Don't deactive the channel if it is synchronized and the DMA request is
        active */
-    if (ch->sync && (s->drq & (1 << ch->sync)) && ch->enable)
+    if (ch->sync && ch->enable && (s->drq & (1 << ch->sync)))
         return;
 
     if (ch->active) {
@@ -231,6 +239,9 @@
         ch->enable = 1;
         ch->waiting_end_prog = 0;
         omap_dma_channel_load(s, ch);
+        /* TODO: theoretically if ch->sync && ch->prefetch &&
+         * !s->drq[ch->sync], we should also activate and fetch from source
+         * and then stall until signalled.  */
         if ((!ch->sync) || (s->drq & (1 << ch->sync)))
             omap_dma_activate_channel(s, ch);
     }
@@ -259,16 +270,47 @@
     }
 }
 
+static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+
+    /* First three interrupts are shared between two channels each. */
+    if (ch[0].status | ch[6].status)
+        qemu_irq_raise(ch[0].irq);
+    if (ch[1].status | ch[7].status)
+        qemu_irq_raise(ch[1].irq);
+    if (ch[2].status | ch[8].status)
+        qemu_irq_raise(ch[2].irq);
+    if (ch[3].status)
+        qemu_irq_raise(ch[3].irq);
+    if (ch[4].status)
+        qemu_irq_raise(ch[4].irq);
+    if (ch[5].status)
+        qemu_irq_raise(ch[5].irq);
+}
+
+static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    int i;
+
+    for (i = s->chans; i; ch ++, i --)
+        if (ch->status)
+            qemu_irq_raise(ch->irq);
+}
+
 static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
 {
     s->omap_3_1_mapping_disabled = 0;
     s->chans = 9;
+    s->intr_update = omap_dma_interrupts_3_1_update;
 }
 
 static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
 {
     s->omap_3_1_mapping_disabled = 1;
     s->chans = 16;
+    s->intr_update = omap_dma_interrupts_3_2_update;
 }
 
 static void omap_dma_process_request(struct omap_dma_s *s, int request)
@@ -358,6 +400,22 @@
                 if (ch->interrupts & HALF_FRAME_INTR)
                     ch->status |= HALF_FRAME_INTR;
 
+            if (ch->fs && ch->bs) {
+                a->pck_element ++;
+                /* Check if a full packet has beed transferred.  */
+                if (a->pck_element == a->pck_elements) {
+                    a->pck_element = 0;
+
+                    /* Set the END_PKT interrupt */
+                    if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
+                        ch->status |= END_PKT_INTR;
+
+                    /* If the channel is packet-synchronized, deactivate it */
+                    if (ch->sync)
+                        omap_dma_deactivate_channel(s, ch);
+                }
+            }
+
             if (a->element == a->elements) {
                 /* End of Frame */
                 a->element = 0;
@@ -366,7 +424,7 @@
                 a->frame ++;
 
                 /* If the channel is frame synchronized, deactivate it */
-                if (ch->sync && ch->fs)
+                if (ch->sync && ch->fs && !ch->bs)
                     omap_dma_deactivate_channel(s, ch);
 
                 /* If the channel is async, update cpc */
@@ -414,50 +472,62 @@
     int i;
 
     qemu_del_timer(s->tm);
-    s->gcr = 0x0004;
+    if (s->model < omap_dma_4)
+        s->gcr = 0x0004;
+    else
+        s->gcr = 0x00010010;
+    s->ocp = 0x00000000;
+    memset(&s->irqstat, 0, sizeof(s->irqstat));
+    memset(&s->irqen, 0, sizeof(s->irqen));
     s->drq = 0x00000000;
     s->run_count = 0;
     s->lcd_ch.src = emiff;
     s->lcd_ch.condition = 0;
     s->lcd_ch.interrupts = 0;
     s->lcd_ch.dual = 0;
-    omap_dma_enable_3_1_mapping(s);
+    if (s->model < omap_dma_4)
+        omap_dma_enable_3_1_mapping(s);
     for (i = 0; i < s->chans; i ++) {
+        s->ch[i].suspend = 0;
+        s->ch[i].prefetch = 0;
+        s->ch[i].buf_disable = 0;
+        s->ch[i].src_sync = 0;
         memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
         memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
         memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
-        memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements));
-        memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames));
         memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
         memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
-        memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type));
-        memset(&s->ch[i].transparent_copy, 0,
-                        sizeof(s->ch[i].transparent_copy));
-        memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill));
-        memset(&s->ch[i].color, 0, sizeof(s->ch[i].color));
-        memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog));
-        memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat));
-        memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init));
-        memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled));
-        memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch));
-        s->ch[i].interrupts = 0x0003;
-        memset(&s->ch[i].status, 0, sizeof(s->ch[i].status));
-        memset(&s->ch[i].active, 0, sizeof(s->ch[i].active));
-        memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable));
-        memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync));
-        memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request));
-        memset(&s->ch[i].waiting_end_prog, 0,
-                        sizeof(s->ch[i].waiting_end_prog));
-        memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc));
-        memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs));
-        memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs));
-        memset(&s->ch[i].omap_3_1_compatible_disable, 0,
-                        sizeof(s->ch[i].omap_3_1_compatible_disable));
+        memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian));
+        memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock));
+        memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate));
+        s->ch[i].write_mode = 0;
+        s->ch[i].data_type = 0;
+        s->ch[i].transparent_copy = 0;
+        s->ch[i].constant_fill = 0;
+        s->ch[i].color = 0x00000000;
+        s->ch[i].end_prog = 0;
+        s->ch[i].repeat = 0;
+        s->ch[i].auto_init = 0;
+        s->ch[i].link_enabled = 0;
+        if (s->model < omap_dma_4)
+            s->ch[i].interrupts = 0x0003;
+        else
+            s->ch[i].interrupts = 0x0000;
+        s->ch[i].status = 0;
+        s->ch[i].cstatus = 0;
+        s->ch[i].active = 0;
+        s->ch[i].enable = 0;
+        s->ch[i].sync = 0;
+        s->ch[i].pending_request = 0;
+        s->ch[i].waiting_end_prog = 0;
+        s->ch[i].cpc = 0x0000;
+        s->ch[i].fs = 0;
+        s->ch[i].bs = 0;
+        s->ch[i].omap_3_1_compatible_disable = 0;
         memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
-        memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority));
-        memset(&s->ch[i].interleave_disabled, 0,
-                        sizeof(s->ch[i].interleave_disabled));
-        memset(&s->ch[i].type, 0, sizeof(s->ch[i].type));
+        s->ch[i].priority = 0;
+        s->ch[i].interleave_disabled = 0;
+        s->ch[i].type = 0;
     }
 }
 
@@ -476,7 +546,7 @@
         break;
 
     case 0x02: /* SYS_DMA_CCR_CH0 */
-        if (s->model == omap_dma_3_1)
+        if (s->model <= omap_dma_3_1)
             *value = 0 << 10;                  /* FIFO_FLUSH reads as 0 */
         else
             *value = ch->omap_3_1_compatible_disable << 10;
@@ -596,11 +666,11 @@
         ch->burst[0] = (value & 0x0180) >> 7;
         ch->pack[0] = (value & 0x0040) >> 6;
         ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
-        ch->data_type = (1 << (value & 3));
-        if (ch->port[0] >= omap_dma_port_last)
+        ch->data_type = 1 << (value & 3);
+        if (ch->port[0] >= __omap_dma_port_last)
             printf("%s: invalid DMA port %i\n", __FUNCTION__,
                             ch->port[0]);
-        if (ch->port[1] >= omap_dma_port_last)
+        if (ch->port[1] >= __omap_dma_port_last)
             printf("%s: invalid DMA port %i\n", __FUNCTION__,
                             ch->port[1]);
         if ((value & 3) == 3)
@@ -611,7 +681,7 @@
         ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
         ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
         ch->end_prog = (value & 0x0800) >> 11;
-        if (s->model > omap_dma_3_1)
+        if (s->model >= omap_dma_3_2)
             ch->omap_3_1_compatible_disable  = (value >> 10) & 0x1;
         ch->repeat = (value & 0x0200) >> 9;
         ch->auto_init = (value & 0x0100) >> 8;
@@ -630,7 +700,7 @@
         break;
 
     case 0x04: /* SYS_DMA_CICR_CH0 */
-        ch->interrupts = value;
+        ch->interrupts = value & 0x3f;
         break;
 
     case 0x06: /* SYS_DMA_CSR_CH0 */
@@ -696,7 +766,7 @@
         break;
 
     case 0x24: /* DMA_CCR2 */
-        ch->bs  = (value >> 2) & 0x1;
+        ch->bs = (value >> 2) & 0x1;
         ch->transparent_copy = (value >> 1) & 0x1;
         ch->constant_fill = value & 0x1;
         break;
@@ -1126,48 +1196,29 @@
         break;
 
     case 0x44e:        /* DMA_CAPS_0_U */
-        *ret = (1 << 3) | /* Constant Fill Capacity */
-            (1 << 2);     /* Transparent BLT Capacity */
+        *ret = (s->caps[0] >> 16) & 0xffff;
         break;
+    case 0x450:        /* DMA_CAPS_0_L */
+        *ret = (s->caps[0] >>  0) & 0xffff;
+        break;
 
-    case 0x450:        /* DMA_CAPS_0_L */
     case 0x452:        /* DMA_CAPS_1_U */
-        *ret = 0;
+        *ret = (s->caps[1] >> 16) & 0xffff;
         break;
-
     case 0x454:        /* DMA_CAPS_1_L */
-        *ret = (1 << 1); /* 1-bit palletized capability */
+        *ret = (s->caps[1] >>  0) & 0xffff;
         break;
 
     case 0x456:        /* DMA_CAPS_2 */
-        *ret = (1 << 8) | /* SSDIC */
-            (1 << 7) |    /* DDIAC */
-            (1 << 6) |    /* DSIAC */
-            (1 << 5) |    /* DPIAC */
-            (1 << 4) |    /* DCAC  */
-            (1 << 3) |    /* SDIAC */
-            (1 << 2) |    /* SSIAC */
-            (1 << 1) |    /* SPIAC */
-            1;            /* SCAC  */
+        *ret = s->caps[2];
         break;
 
     case 0x458:        /* DMA_CAPS_3 */
-        *ret = (1 << 5) | /* CCC */
-            (1 << 4) |    /* IC  */
-            (1 << 3) |    /* ARC */
-            (1 << 2) |    /* AEC */
-            (1 << 1) |    /* FSC */
-            1;            /* ESC */
+        *ret = s->caps[3];
         break;
 
     case 0x45a:        /* DMA_CAPS_4 */
-        *ret = (1 << 6) | /* SSC  */
-            (1 << 5) |    /* BIC  */
-            (1 << 4) |    /* LFIC */
-            (1 << 3) |    /* FIC  */
-            (1 << 2) |    /* HFIC */
-            (1 << 1) |    /* EDIC */
-            1;            /* TOIC */
+        *ret = s->caps[4];
         break;
 
     case 0x460:        /* DMA_PCh2_SR */
@@ -1193,7 +1244,7 @@
 
     switch (offset) {
     case 0x300 ... 0x3fe:
-        if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
             if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret))
                 break;
             return ret;
@@ -1207,7 +1258,7 @@
         return ret;
 
     case 0x404 ... 0x4fe:
-        if (s->model == omap_dma_3_1)
+        if (s->model <= omap_dma_3_1)
             break;
         /* Fall through. */
     case 0x400:
@@ -1236,7 +1287,7 @@
 
     switch (offset) {
     case 0x300 ... 0x3fe:
-        if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
             if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value))
                 break;
             return;
@@ -1250,7 +1301,7 @@
         return;
 
     case 0x404 ... 0x4fe:
-        if (s->model == omap_dma_3_1)
+        if (s->model <= omap_dma_3_1)
             break;
     case 0x400:
         /* Fall through. */
@@ -1285,7 +1336,7 @@
 static void omap_dma_request(void *opaque, int drq, int req)
 {
     struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    /* The request pins are level triggered.  */
+    /* The request pins are level triggered in QEMU.  */
     if (req) {
         if (~s->drq & (1 << drq)) {
             s->drq |= 1 << drq;
@@ -1310,6 +1361,52 @@
     }
 }
 
+static void omap_dma_setcaps(struct omap_dma_s *s)
+{
+    switch (s->model) {
+    default:
+    case omap_dma_3_1:
+        break;
+    case omap_dma_3_2:
+    case omap_dma_4:
+        /* XXX Only available for sDMA */
+        s->caps[0] =
+                (1 << 19) |    /* Constant Fill Capability */
+                (1 << 18);     /* Transparent BLT Capability */
+        s->caps[1] =
+                (1 << 1);      /* 1-bit palettized capability (DMA 3.2 only) */
+        s->caps[2] =
+                (1 << 8) |     /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
+                (1 << 7) |     /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 6) |     /* DST_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 5) |     /* DST_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 4) |     /* DST_CONST_ADRS_CPBLTY */
+                (1 << 3) |     /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 2) |     /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 1) |     /* SRC_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 0);      /* SRC_CONST_ADRS_CPBLTY */
+        s->caps[3] =
+                (1 << 6) |     /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 7) |     /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 5) |     /* CHANNEL_CHAINING_CPBLTY */
+                (1 << 4) |     /* LCh_INTERLEAVE_CPBLTY */
+                (1 << 3) |     /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
+                (1 << 2) |     /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
+                (1 << 1) |     /* FRAME_SYNCHR_CPBLTY */
+                (1 << 0);      /* ELMNT_SYNCHR_CPBLTY */
+        s->caps[4] =
+                (1 << 7) |     /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
+                (1 << 6) |     /* SYNC_STATUS_CPBLTY */
+                (1 << 5) |     /* BLOCK_INTERRUPT_CPBLTY */
+                (1 << 4) |     /* LAST_FRAME_INTERRUPT_CPBLTY */
+                (1 << 3) |     /* FRAME_INTERRUPT_CPBLTY */
+                (1 << 2) |     /* HALF_FRAME_INTERRUPT_CPBLTY */
+                (1 << 1) |     /* EVENT_DROP_INTERRUPT_CPBLTY */
+                (1 << 0);      /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
+        break;
+    }
+}
+
 struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
                 qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
                 enum omap_dma_model model)
@@ -1318,7 +1415,7 @@
     struct omap_dma_s *s = (struct omap_dma_s *)
             qemu_mallocz(sizeof(struct omap_dma_s));
 
-    if (model == omap_dma_3_1) {
+    if (model <= omap_dma_3_1) {
         num_irqs = 6;
         memsize = 0x800;
     } else {
@@ -1331,6 +1428,7 @@
     s->clk = clk;
     s->lcd_ch.irq = lcd_irq;
     s->lcd_ch.mpu = mpu;
+    omap_dma_setcaps(s);
     while (num_irqs --)
         s->ch[num_irqs].irq = irqs[num_irqs];
     for (i = 0; i < 3; i ++) {
@@ -1350,6 +1448,393 @@
     return s;
 }
 
+static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    uint32_t bmp, bit;
+
+    for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
+        if (ch->status) {
+            bmp |= bit;
+            ch->cstatus |= ch->status;
+            ch->status = 0;
+        }
+    if ((s->irqstat[0] |= s->irqen[0] & bmp))
+        qemu_irq_raise(s->irq[0]);
+    if ((s->irqstat[1] |= s->irqen[1] & bmp))
+        qemu_irq_raise(s->irq[1]);
+    if ((s->irqstat[2] |= s->irqen[2] & bmp))
+        qemu_irq_raise(s->irq[2]);
+    if ((s->irqstat[3] |= s->irqen[3] & bmp))
+        qemu_irq_raise(s->irq[3]);
+}
+
+static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int irqn = 0, chnum, offset = addr - s->base;
+    struct omap_dma_channel_s *ch;
+
+    switch (offset) {
+    case 0x00: /* DMA4_REVISION */
+        return 0x40;
+
+    case 0x14: /* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+    case 0x10: /* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+    case 0x0c: /* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+    case 0x08: /* DMA4_IRQSTATUS_L0 */
+        return s->irqstat[irqn];
+
+    case 0x24: /* DMA4_IRQENABLE_L3 */
+        irqn ++;
+    case 0x20: /* DMA4_IRQENABLE_L2 */
+        irqn ++;
+    case 0x1c: /* DMA4_IRQENABLE_L1 */
+        irqn ++;
+    case 0x18: /* DMA4_IRQENABLE_L0 */
+        return s->irqen[irqn];
+
+    case 0x28: /* DMA4_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x2c: /* DMA4_OCP_SYSCONFIG */
+        return s->ocp;
+
+    case 0x64: /* DMA4_CAPS_0 */
+        return s->caps[0];
+    case 0x6c: /* DMA4_CAPS_2 */
+        return s->caps[2];
+    case 0x70: /* DMA4_CAPS_3 */
+        return s->caps[3];
+    case 0x74: /* DMA4_CAPS_4 */
+        return s->caps[4];
+
+    case 0x78: /* DMA4_GCR */
+        return s->gcr;
+
+    case 0x80 ... 0xfff:
+        offset -= 0x80;
+        chnum = offset / 0x60;
+        ch = s->ch + chnum;
+        offset -= chnum * 0x60;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+
+    /* Per-channel registers */
+    switch (offset) {
+    case 0x00: /* DMA4_CCR */
+        return (ch->buf_disable << 25) |
+                (ch->src_sync << 24) |
+                (ch->prefetch << 23) |
+                ((ch->sync & 0x60) << 14) |
+                (ch->bs << 18) |
+                (ch->transparent_copy << 17) |
+                (ch->constant_fill << 16) |
+                (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (0 << 10) | (0 << 9) |
+                (ch->suspend << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | (ch->sync & 0x1f);
+
+    case 0x04: /* DMA4_CLNK_CTRL */
+        return (ch->link_enabled << 15) | ch->link_next_ch;
+
+    case 0x08: /* DMA4_CICR */
+        return ch->interrupts;
+
+    case 0x0c: /* DMA4_CSR */
+        return ch->cstatus;
+
+    case 0x10: /* DMA4_CSDP */
+        return (ch->endian[0] << 21) |
+                (ch->endian_lock[0] << 20) |
+                (ch->endian[1] << 19) |
+                (ch->endian_lock[1] << 18) |
+                (ch->write_mode << 16) |
+                (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->translate[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->translate[0] << 2) |
+                (ch->data_type >> 1);
+
+    case 0x14: /* DMA4_CEN */
+        return ch->elements;
+
+    case 0x18: /* DMA4_CFN */
+        return ch->frames;
+
+    case 0x1c: /* DMA4_CSSA */
+        return ch->addr[0];
+
+    case 0x20: /* DMA4_CDSA */
+        return ch->addr[1];
+
+    case 0x24: /* DMA4_CSEI */
+        return ch->element_index[0];
+
+    case 0x28: /* DMA4_CSFI */
+        return ch->frame_index[0];
+
+    case 0x2c: /* DMA4_CDEI */
+        return ch->element_index[1];
+
+    case 0x30: /* DMA4_CDFI */
+        return ch->frame_index[1];
+
+    case 0x34: /* DMA4_CSAC */
+        return ch->active_set.src & 0xffff;
+
+    case 0x38: /* DMA4_CDAC */
+        return ch->active_set.dest & 0xffff;
+
+    case 0x3c: /* DMA4_CCEN */
+        return ch->active_set.element;
+
+    case 0x40: /* DMA4_CCFN */
+        return ch->active_set.frame;
+
+    case 0x44: /* DMA4_COLOR */
+        /* XXX only in sDMA */
+        return ch->color;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+}
+
+static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int chnum, irqn = 0, offset = addr - s->base;
+    struct omap_dma_channel_s *ch;
+
+    switch (offset) {
+    case 0x14: /* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+    case 0x10: /* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+    case 0x0c: /* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+    case 0x08: /* DMA4_IRQSTATUS_L0 */
+        s->irqstat[irqn] &= ~value;
+        if (!s->irqstat[irqn])
+            qemu_irq_lower(s->irq[irqn]);
+        return;
+
+    case 0x24: /* DMA4_IRQENABLE_L3 */
+        irqn ++;
+    case 0x20: /* DMA4_IRQENABLE_L2 */
+        irqn ++;
+    case 0x1c: /* DMA4_IRQENABLE_L1 */
+        irqn ++;
+    case 0x18: /* DMA4_IRQENABLE_L0 */
+        s->irqen[irqn] = value;
+        return;
+
+    case 0x2c: /* DMA4_OCP_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dma_reset(s);
+        s->ocp = value & 0x3321;
+        if (((s->ocp >> 12) & 3) == 3)                         /* MIDLEMODE */
+            fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
+        return;
+
+    case 0x78: /* DMA4_GCR */
+        s->gcr = value & 0x00ff00ff;
+       if ((value & 0xff) == 0x00)             /* MAX_CHANNEL_FIFO_DEPTH */
+            fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__);
+        return;
+
+    case 0x80 ... 0xfff:
+        offset -= 0x80;
+        chnum = offset / 0x60;
+        ch = s->ch + chnum;
+        offset -= chnum * 0x60;
+        break;
+
+    case 0x00: /* DMA4_REVISION */
+    case 0x28: /* DMA4_SYSSTATUS */
+    case 0x64: /* DMA4_CAPS_0 */
+    case 0x6c: /* DMA4_CAPS_2 */
+    case 0x70: /* DMA4_CAPS_3 */
+    case 0x74: /* DMA4_CAPS_4 */
+        OMAP_RO_REG(addr);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+
+    /* Per-channel registers */
+    switch (offset) {
+    case 0x00: /* DMA4_CCR */
+        ch->buf_disable = (value >> 25) & 1;
+        ch->src_sync = (value >> 24) & 1;      /* XXX For CamDMA must be 1 */
+        if (ch->buf_disable && !ch->src_sync)
+            fprintf(stderr, "%s: Buffering disable is not allowed in "
+                            "destination synchronised mode\n", __FUNCTION__);
+        ch->prefetch = (value >> 23) & 1;
+        ch->bs = (value >> 18) & 1;
+        ch->transparent_copy = (value >> 17) & 1;
+        ch->constant_fill = (value >> 16) & 1;
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->suspend = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1])
+            fprintf(stderr, "%s: For a packet transfer at least one port "
+                            "must be constant-addressed\n", __FUNCTION__);
+        ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
+        /* XXX must be 0x01 for CamDMA */
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        break;
+
+    case 0x04: /* DMA4_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x08: /* DMA4_CICR */
+        ch->interrupts = value & 0x09be;
+        break;
+
+    case 0x0c: /* DMA4_CSR */
+        ch->cstatus &= ~value;
+        break;
+
+    case 0x10: /* DMA4_CSDP */
+        ch->endian[0] =(value >> 21) & 1;
+        ch->endian_lock[0] =(value >> 20) & 1;
+        ch->endian[1] =(value >> 19) & 1;
+        ch->endian_lock[1] =(value >> 18) & 1;
+        if (ch->endian[0] != ch->endian[1])
+            fprintf(stderr, "%s: DMA endianned conversion enable attempt\n",
+                            __FUNCTION__);
+        ch->write_mode = (value >> 16) & 3;
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->translate[1] = (value & 0x1e00) >> 9;
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->translate[0] = (value & 0x003c) >> 2;
+        if (ch->translate[0] | ch->translate[1])
+            fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
+                            __FUNCTION__);
+        ch->data_type = 1 << (value & 3);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
+        break;
+
+    case 0x14: /* DMA4_CEN */
+        ch->elements = value & 0xffffff;
+        break;
+
+    case 0x18: /* DMA4_CFN */
+        ch->frames = value & 0xffff;
+        break;
+
+    case 0x1c: /* DMA4_CSSA */
+        ch->addr[0] = (target_phys_addr_t) (uint32_t) value;
+        break;
+
+    case 0x20: /* DMA4_CDSA */
+        ch->addr[1] = (target_phys_addr_t) (uint32_t) value;
+        break;
+
+    case 0x24: /* DMA4_CSEI */
+        ch->element_index[0] = (int16_t) value;
+        break;
+
+    case 0x28: /* DMA4_CSFI */
+        ch->frame_index[0] = (int32_t) value;
+        break;
+
+    case 0x2c: /* DMA4_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        break;
+
+    case 0x30: /* DMA4_CDFI */
+        ch->frame_index[1] = (int32_t) value;
+        break;
+
+    case 0x44: /* DMA4_COLOR */
+        /* XXX only in sDMA */
+        ch->color = value;
+        break;
+
+    case 0x34: /* DMA4_CSAC */
+    case 0x38: /* DMA4_CDAC */
+    case 0x3c: /* DMA4_CCEN */
+    case 0x40: /* DMA4_CCFN */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_dma4_readfn[] = {
+    omap_badwidth_read16,
+    omap_dma4_read,
+    omap_dma4_read,
+};
+
+static CPUWriteMemoryFunc *omap_dma4_writefn[] = {
+    omap_badwidth_write16,
+    omap_dma4_write,
+    omap_dma4_write,
+};
+
+struct omap_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk)
+{
+    int iomemtype;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            qemu_mallocz(sizeof(struct omap_dma_s));
+
+    s->base = base;
+    s->model = omap_dma_4;
+    s->chans = chans;
+    s->mpu = mpu;
+    s->clk = fclk;
+    memcpy(&s->irq, irqs, sizeof(s->irq));
+    s->intr_update = omap_dma_interrupts_4_update;
+    omap_dma_setcaps(s);
+    s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
+    omap_dma_reset(s);
+    omap_dma_clk_update(s, 0, 1);
+
+    iomemtype = cpu_register_io_memory(0, omap_dma4_readfn,
+                    omap_dma4_writefn, s);
+    cpu_register_physical_memory(s->base, 0x1000, iomemtype);
+
+    return s;
+}
+
 struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct omap_dma_s *s)
 {
     return &s->lcd_ch;

Added: trunk/hw/omap_dss.c
===================================================================
--- trunk/hw/omap_dss.c                         (rev 0)
+++ trunk/hw/omap_dss.c 2008-04-14 21:05:22 UTC (rev 4213)
@@ -0,0 +1,1093 @@
+/*
+ * OMAP2 Display Subsystem.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "console.h"
+#include "omap.h"
+
+struct omap_dss_s {
+    target_phys_addr_t diss_base;
+    target_phys_addr_t disc_base;
+    target_phys_addr_t rfbi_base;
+    target_phys_addr_t venc_base;
+    target_phys_addr_t im3_base;
+    qemu_irq irq;
+    qemu_irq drq;
+    DisplayState *state;
+
+    int autoidle;
+    int control;
+    int enable;
+
+    struct omap_dss_panel_s {
+        int enable;
+        int nx;
+        int ny;
+
+        int x;
+        int y;
+    } dig, lcd;
+
+    struct {
+        uint32_t idlemode;
+        uint32_t irqst;
+        uint32_t irqen;
+        uint32_t control;
+        uint32_t config;
+        uint32_t capable;
+        uint32_t timing[3];
+        int line;
+        uint32_t bg[2];
+        uint32_t trans[2];
+
+        struct omap_dss_plane_s {
+            int enable;
+            int bpp;
+            int posx;
+            int posy;
+            int nx;
+            int ny;
+
+            target_phys_addr_t addr[3];
+
+            uint32_t attr;
+            uint32_t tresh;
+            int rowinc;
+            int colinc;
+            int wininc;
+        } l[3];
+
+        int invalidate;
+        uint16_t palette[256];
+    } dispc;
+
+    struct {
+        int idlemode;
+        uint32_t control;
+        int enable;
+        int pixels;
+        int busy;
+        int skiplines;
+        uint16_t rxbuf;
+        uint32_t config[2];
+        uint32_t time[4];
+        uint32_t data[6];
+        uint16_t vsync;
+        uint16_t hsync;
+        struct rfbi_chip_s *chip[2];
+    } rfbi;
+};
+
+static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+{
+    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+}
+
+static void omap_rfbi_reset(struct omap_dss_s *s)
+{
+    s->rfbi.idlemode = 0;
+    s->rfbi.control = 2;
+    s->rfbi.enable = 0;
+    s->rfbi.pixels = 0;
+    s->rfbi.skiplines = 0;
+    s->rfbi.busy = 0;
+    s->rfbi.config[0] = 0x00310000;
+    s->rfbi.config[1] = 0x00310000;
+    s->rfbi.time[0] = 0;
+    s->rfbi.time[1] = 0;
+    s->rfbi.time[2] = 0;
+    s->rfbi.time[3] = 0;
+    s->rfbi.data[0] = 0;
+    s->rfbi.data[1] = 0;
+    s->rfbi.data[2] = 0;
+    s->rfbi.data[3] = 0;
+    s->rfbi.data[4] = 0;
+    s->rfbi.data[5] = 0;
+    s->rfbi.vsync = 0;
+    s->rfbi.hsync = 0;
+}
+
+void omap_dss_reset(struct omap_dss_s *s)
+{
+    s->autoidle = 0;
+    s->control = 0;
+    s->enable = 0;
+
+    s->dig.enable = 0;
+    s->dig.nx = 1;
+    s->dig.ny = 1;
+
+    s->lcd.enable = 0;
+    s->lcd.nx = 1;
+    s->lcd.ny = 1;
+
+    s->dispc.idlemode = 0;
+    s->dispc.irqst = 0;
+    s->dispc.irqen = 0;
+    s->dispc.control = 0;
+    s->dispc.config = 0;
+    s->dispc.capable = 0x161;
+    s->dispc.timing[0] = 0;
+    s->dispc.timing[1] = 0;
+    s->dispc.timing[2] = 0;
+    s->dispc.line = 0;
+    s->dispc.bg[0] = 0;
+    s->dispc.bg[1] = 0;
+    s->dispc.trans[0] = 0;
+    s->dispc.trans[1] = 0;
+
+    s->dispc.l[0].enable = 0;
+    s->dispc.l[0].bpp = 0;
+    s->dispc.l[0].addr[0] = 0;
+    s->dispc.l[0].addr[1] = 0;
+    s->dispc.l[0].addr[2] = 0;
+    s->dispc.l[0].posx = 0;
+    s->dispc.l[0].posy = 0;
+    s->dispc.l[0].nx = 1;
+    s->dispc.l[0].ny = 1;
+    s->dispc.l[0].attr = 0;
+    s->dispc.l[0].tresh = 0;
+    s->dispc.l[0].rowinc = 1;
+    s->dispc.l[0].colinc = 1;
+    s->dispc.l[0].wininc = 0;
+
+    omap_rfbi_reset(s);
+    omap_dispc_interrupt_update(s);
+}
+
+static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->diss_base;
+
+    switch (offset) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+        return 0x20;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14: /* DSS_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* DSS_CONTROL */
+        return s->control;
+
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+        /* TODO: fake some values when appropriate s->control bits are set */
+        return 0;
+
+    case 0x5c: /* DSS_STATUS */
+        return 1 + (s->control & 1);
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_diss_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->diss_base;
+
+    switch (offset) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+    case 0x14: /* DSS_SYSSTATUS */
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+    case 0x5c: /* DSS_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40: /* DSS_CONTROL */
+        s->control = value & 0x3dd;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_diss1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_diss_read,
+};
+
+static CPUWriteMemoryFunc *omap_diss1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_diss_write,
+};
+
+static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->disc_base;
+
+    switch (offset) {
+    case 0x000:        /* DISPC_REVISION */
+        return 0x20;
+
+    case 0x010:        /* DISPC_SYSCONFIG */
+        return s->dispc.idlemode;
+
+    case 0x014:        /* DISPC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        return s->dispc.irqst;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        return s->dispc.irqen;
+
+    case 0x040:        /* DISPC_CONTROL */
+        return s->dispc.control;
+
+    case 0x044:        /* DISPC_CONFIG */
+        return s->dispc.config;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        return s->dispc.capable;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        return s->dispc.bg[0];
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        return s->dispc.bg[1];
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        return s->dispc.trans[0];
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        return s->dispc.trans[1];
+
+    case 0x05c:        /* DISPC_LINE_STATUS */
+        return 0x7ff;
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        return s->dispc.line;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        return s->dispc.timing[0];
+    case 0x068:        /* DISPC_TIMING_V */
+        return s->dispc.timing[1];
+    case 0x06c:        /* DISPC_POL_FREQ */
+        return s->dispc.timing[2];
+    case 0x070:        /* DISPC_DIVISOR */
+        return s->dispc.timing[3];
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
+
+    case 0x080:        /* DISPC_GFX_BA0 */
+        return s->dispc.l[0].addr[0];
+    case 0x084:        /* DISPC_GFX_BA1 */
+        return s->dispc.l[0].addr[1];
+    case 0x088:        /* DISPC_GFX_POSITION */
+        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        return s->dispc.l[0].attr;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        return s->dispc.l[0].tresh;
+    case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
+        return 256;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        return s->dispc.l[0].rowinc;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        return s->dispc.l[0].colinc;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        return s->dispc.l[0].wininc;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        return s->dispc.l[0].addr[2];
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_disc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->disc_base;
+
+    switch (offset) {
+    case 0x010:        /* DISPC_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->dispc.idlemode = value & 0x301b;
+        break;
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        s->dispc.irqst &= ~value;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        s->dispc.irqen = value & 0xffff;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x040:        /* DISPC_CONTROL */
+        s->dispc.control = value & 0x07ff9fff;
+        s->dig.enable = (value >> 1) & 1;
+        s->lcd.enable = (value >> 0) & 1;
+        if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
+            if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
+                 fprintf(stderr, "%s: Overlay Optimization when no overlay "
+                                 "region effectively exists leads to "
+                                 "unpredictable behaviour!\n", __FUNCTION__);
+        if (value & (1 << 6)) {                                /* GODIGITAL */
+            /* XXX: Shadowed fields are:
+             * s->dispc.config
+             * s->dispc.capable
+             * s->dispc.bg[0]
+             * s->dispc.bg[1]
+             * s->dispc.trans[0]
+             * s->dispc.trans[1]
+             * s->dispc.line
+             * s->dispc.timing[0]
+             * s->dispc.timing[1]
+             * s->dispc.timing[2]
+             * s->dispc.timing[3]
+             * s->lcd.nx
+             * s->lcd.ny
+             * s->dig.nx
+             * s->dig.ny
+             * s->dispc.l[0].addr[0]
+             * s->dispc.l[0].addr[1]
+             * s->dispc.l[0].addr[2]
+             * s->dispc.l[0].posx
+             * s->dispc.l[0].posy
+             * s->dispc.l[0].nx
+             * s->dispc.l[0].ny
+             * s->dispc.l[0].tresh
+             * s->dispc.l[0].rowinc
+             * s->dispc.l[0].colinc
+             * s->dispc.l[0].wininc
+             * All they need to be loaded here from their shadow registers.
+             */
+        }
+        if (value & (1 << 5)) {                                /* GOLCD */
+             /* XXX: Likewise for LCD here.  */
+        }
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x044:        /* DISPC_CONFIG */
+        s->dispc.config = value & 0x3fff;
+        /* XXX:
+         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
+         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
+         */
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        s->dispc.capable = value & 0x3ff;
+        break;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        s->dispc.bg[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        s->dispc.bg[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        s->dispc.trans[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        s->dispc.trans[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        s->dispc.line = value & 0x7ff;
+        break;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        s->dispc.timing[0] = value & 0x0ff0ff3f;
+        break;
+    case 0x068:        /* DISPC_TIMING_V */
+        s->dispc.timing[1] = value & 0x0ff0ff3f;
+        break;
+    case 0x06c:        /* DISPC_POL_FREQ */
+        s->dispc.timing[2] = value & 0x0003ffff;
+        break;
+    case 0x070:        /* DISPC_DIVISOR */
+        s->dispc.timing[3] = value & 0x00ff00ff;
+        break;
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x080:        /* DISPC_GFX_BA0 */
+        s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x084:        /* DISPC_GFX_BA1 */
+        s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x088:        /* DISPC_GFX_POSITION */
+        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
+        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* 
GFXSIZEX */
+        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* 
GFXSIZEY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        s->dispc.l[0].attr = value & 0x7ff;
+        if (value & (3 << 9))
+            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
+                            __FUNCTION__);
+        s->dispc.l[0].enable = value & 1;
+        s->dispc.l[0].bpp = (value >> 1) & 0xf;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        s->dispc.l[0].tresh = value & 0x01ff01ff;
+        break;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        s->dispc.l[0].rowinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        s->dispc.l[0].colinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        s->dispc.l[0].wininc = value;
+        break;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_disc1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_disc_read,
+};
+
+static CPUWriteMemoryFunc *omap_disc1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_disc_write,
+};
+
+static void *omap_rfbi_get_buffer(struct omap_dss_s *s)
+{
+    target_phys_addr_t fb;
+    uint32_t pd;
+
+    /* TODO */
+    fb = s->dispc.l[0].addr[0];
+
+    pd = cpu_get_physical_page_desc(fb);
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
+        /* TODO */
+        cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n",
+                        __FUNCTION__);
+    else
+        return phys_ram_base +
+                (pd & TARGET_PAGE_MASK) +
+                (fb & ~TARGET_PAGE_MASK);
+}
+
+static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
+{
+    if (!s->rfbi.busy)
+        return;
+
+    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
+
+    s->rfbi.busy = 0;
+}
+
+static void omap_rfbi_transfer_start(struct omap_dss_s *s)
+{
+    void *data;
+    size_t len;
+    int pitch;
+
+    if (!s->rfbi.enable || s->rfbi.busy)
+        return;
+
+    if (s->rfbi.control & (1 << 1)) {                          /* BYPASS */
+        /* TODO: in non-Bypass mode we probably need to just assert the
+         * DRQ and wait for DMA to write the pixels.  */
+        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
+        return;
+    }
+
+    if (!(s->dispc.control & (1 << 11)))                       /* RFBIMODE */
+        return;
+    /* TODO: check that LCD output is enabled in DISPC.  */
+
+    s->rfbi.busy = 1;
+
+    data = omap_rfbi_get_buffer(s);
+
+    /* TODO bpp */
+    len = s->rfbi.pixels * 2;
+    s->rfbi.pixels = 0;
+
+    /* TODO: negative values */
+    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
+
+    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
+    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+
+    omap_rfbi_transfer_stop(s);
+
+    /* TODO */
+    s->dispc.irqst |= 1;                                       /* FRAMEDONE */
+    omap_dispc_interrupt_update(s);
+}
+
+static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->rfbi_base;
+
+    switch (offset) {
+    case 0x00: /* RFBI_REVISION */
+        return 0x10;
+
+    case 0x10: /* RFBI_SYSCONFIG */
+        return s->rfbi.idlemode;
+
+    case 0x14: /* RFBI_SYSSTATUS */
+        return 1 | (s->rfbi.busy << 8);                                /* 
RESETDONE */
+
+    case 0x40: /* RFBI_CONTROL */
+        return s->rfbi.control;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        return s->rfbi.pixels;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        return s->rfbi.skiplines;
+
+    case 0x58: /* RFBI_READ */
+    case 0x5c: /* RFBI_STATUS */
+        return s->rfbi.rxbuf;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        return s->rfbi.config[0];
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        return s->rfbi.time[0];
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        return s->rfbi.time[1];
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        return s->rfbi.data[0];
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        return s->rfbi.data[1];
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        return s->rfbi.data[2];
+
+    case 0x78: /* RFBI_CONFIG1 */
+        return s->rfbi.config[1];
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        return s->rfbi.time[2];
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        return s->rfbi.time[3];
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        return s->rfbi.data[3];
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        return s->rfbi.data[4];
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        return s->rfbi.data[5];
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        return s->rfbi.vsync;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        return s->rfbi.hsync;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->rfbi_base;
+
+    switch (offset) {
+    case 0x10: /* RFBI_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_rfbi_reset(s);
+        s->rfbi.idlemode = value & 0x19;
+        break;
+
+    case 0x40: /* RFBI_CONTROL */
+        s->rfbi.control = value & 0xf;
+        s->rfbi.enable = value & 1;
+        if (value & (1 << 4) &&                                        /* ITE 
*/
+                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
+            omap_rfbi_transfer_start(s);
+        break;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        s->rfbi.pixels = value;
+        break;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        s->rfbi.skiplines = value & 0x7ff;
+        break;
+
+    case 0x4c: /* RFBI_CMD */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
+        break;
+    case 0x50: /* RFBI_PARAM */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+        break;
+    case 0x54: /* RFBI_DATA */
+        /* TODO: take into account the format set up in s->rfbi.config[?] and
+         * s->rfbi.data[?], but special-case the most usual scenario so that
+         * speed doesn't suffer.  */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
+        }
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
+        }
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+    case 0x58: /* RFBI_READ */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x5c: /* RFBI_STATUS */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        s->rfbi.config[0] = value & 0x003f1fff;
+        break;
+
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        s->rfbi.time[0] = value & 0x3fffffff;
+        break;
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        s->rfbi.time[1] = value & 0x0fffffff;
+        break;
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        s->rfbi.data[0] = value & 0x0f1f0f1f;
+        break;
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        s->rfbi.data[1] = value & 0x0f1f0f1f;
+        break;
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        s->rfbi.data[2] = value & 0x0f1f0f1f;
+        break;
+    case 0x78: /* RFBI_CONFIG1 */
+        s->rfbi.config[1] = value & 0x003f1fff;
+        break;
+
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        s->rfbi.time[2] = value & 0x3fffffff;
+        break;
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        s->rfbi.time[3] = value & 0x0fffffff;
+        break;
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        s->rfbi.data[3] = value & 0x0f1f0f1f;
+        break;
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        s->rfbi.data[4] = value & 0x0f1f0f1f;
+        break;
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        s->rfbi.data[5] = value & 0x0f1f0f1f;
+        break;
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        s->rfbi.vsync = value & 0xffff;
+        break;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        s->rfbi.hsync = value & 0xffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_rfbi1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_rfbi_read,
+};
+
+static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_rfbi_write,
+};
+
+static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->venc_base;
+
+    switch (offset) {
+    case 0x00: /* REV_ID */
+    case 0x04: /* STATUS */
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_venc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->venc_base;
+
+    switch (offset) {
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_venc1_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_venc_read,
+};
+
+static CPUWriteMemoryFunc *omap_venc1_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_venc_write,
+};
+
+static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->im3_base;
+
+    switch (offset) {
+    case 0x0a8:        /* SBIMERRLOGA */
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+    case 0x1f8:        /* SBID_L */
+    case 0x1fc:        /* SBID_H */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_im3_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int offset = addr - s->im3_base;
+
+    switch (offset) {
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_im3_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_im3_read,
+};
+
+static CPUWriteMemoryFunc *omap_im3_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_im3_write,
+};
+
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                target_phys_addr_t l3_base, DisplayState *ds,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2)
+{
+    int iomemtype[5];
+    struct omap_dss_s *s = (struct omap_dss_s *)
+            qemu_mallocz(sizeof(struct omap_dss_s));
+
+    s->irq = irq;
+    s->drq = drq;
+    s->state = ds;
+    omap_dss_reset(s);
+
+    iomemtype[0] = cpu_register_io_memory(0, omap_diss1_readfn,
+                    omap_diss1_writefn, s);
+    iomemtype[1] = cpu_register_io_memory(0, omap_disc1_readfn,
+                    omap_disc1_writefn, s);
+    iomemtype[2] = cpu_register_io_memory(0, omap_rfbi1_readfn,
+                    omap_rfbi1_writefn, s);
+    iomemtype[3] = cpu_register_io_memory(0, omap_venc1_readfn,
+                    omap_venc1_writefn, s);
+    iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn,
+                    omap_im3_writefn, s);
+    s->diss_base = omap_l4_attach(ta, 0, iomemtype[0]);
+    s->disc_base = omap_l4_attach(ta, 1, iomemtype[1]);
+    s->rfbi_base = omap_l4_attach(ta, 2, iomemtype[2]);
+    s->venc_base = omap_l4_attach(ta, 3, iomemtype[3]);
+    s->im3_base = l3_base;
+    cpu_register_physical_memory(s->im3_base, 0x1000, iomemtype[4]);
+
+#if 0
+    if (ds)
+        graphic_console_init(ds, omap_update_display,
+                        omap_invalidate_display, omap_screen_dump, s);
+#endif
+
+    return s;
+}
+
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
+{
+    if (cs < 0 || cs > 1)
+        cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
+    s->rfbi.chip[cs] = chip;
+}

Modified: trunk/hw/omap_i2c.c
===================================================================
--- trunk/hw/omap_i2c.c 2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap_i2c.c 2008-04-14 21:05:22 UTC (rev 4213)
@@ -150,6 +150,8 @@
             }
             if (ack && s->count_cur)
                 s->stat |= 1 << 4;                             /* XRDY */
+            else
+                s->stat &= ~(1 << 4);                          /* XRDY */
             if (!s->count_cur) {
                 s->stat |= 1 << 2;                             /* ARDY */
                 s->control &= ~(1 << 10);                      /* MST */
@@ -161,6 +163,8 @@
             }
             if (s->rxlen)
                 s->stat |= 1 << 3;                             /* RRDY */
+            else
+                s->stat &= ~(1 << 3);                          /* RRDY */
         }
         if (!s->count_cur) {
             if ((s->control >> 1) & 1) {                       /* STP */
@@ -321,7 +325,8 @@
             return;
         }
 
-        s->stat &= ~(value & 0x3f);
+        /* RRDY and XRDY are reset by hardware. (in all versions???) */
+        s->stat &= ~(value & 0x27);
         omap_i2c_interrupts_update(s);
         break;
 
@@ -376,11 +381,13 @@
             break;
         }
         if ((value & (1 << 15)) && !(value & (1 << 10))) {     /* MST */
-            printf("%s: I^2C slave mode not supported\n", __FUNCTION__);
+            fprintf(stderr, "%s: I^2C slave mode not supported\n",
+                            __FUNCTION__);
             break;
         }
         if ((value & (1 << 15)) && value & (1 << 8)) {         /* XA */
-            printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__);
+            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
+                            __FUNCTION__);
             break;
         }
         if ((value & (1 << 15)) && value & (1 << 0)) {         /* STT */
@@ -427,7 +434,7 @@
                 omap_i2c_interrupts_update(s);
             }
         if (value & (1 << 15))                                 /* ST_EN */
-            printf("%s: System Test not supported\n", __FUNCTION__);
+            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
         break;
 
     default:

Modified: trunk/hw/omap_mmc.c
===================================================================
--- trunk/hw/omap_mmc.c 2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/omap_mmc.c 2008-04-14 21:05:22 UTC (rev 4213)
@@ -5,8 +5,8 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,19 +26,24 @@
     target_phys_addr_t base;
     qemu_irq irq;
     qemu_irq *dma;
+    qemu_irq coverswitch;
     omap_clk clk;
     SDState *card;
     uint16_t last_cmd;
     uint16_t sdio;
     uint16_t rsp[8];
     uint32_t arg;
+    int lines;
     int dw;
     int mode;
     int enable;
+    int be;
+    int rev;
     uint16_t status;
     uint16_t mask;
     uint8_t cto;
     uint16_t dto;
+    int clkdiv;
     uint16_t fifo[32];
     int fifo_start;
     int fifo_len;
@@ -53,6 +58,11 @@
 
     int ddir;
     int transfer;
+
+    int cdet_wakeup;
+    int cdet_enable;
+    int cdet_state;
+    qemu_irq cdet;
 };
 
 static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
@@ -107,6 +117,11 @@
     struct sd_request_s request;
     uint8_t response[16];
 
+    if (init && cmd == 0) {
+        host->status |= 0x0001;
+        return;
+    }
+
     if (resptype == sd_r1 && busy)
         resptype = sd_r1b;
 
@@ -265,6 +280,34 @@
     omap_mmc_interrupts_update(s);
 }
 
+void omap_mmc_reset(struct omap_mmc_s *host)
+{
+    host->last_cmd = 0;
+    memset(host->rsp, 0, sizeof(host->rsp));
+    host->arg = 0;
+    host->dw = 0;
+    host->mode = 0;
+    host->enable = 0;
+    host->status = 0;
+    host->mask = 0;
+    host->cto = 0;
+    host->dto = 0;
+    host->fifo_len = 0;
+    host->blen = 0;
+    host->blen_counter = 0;
+    host->nblk = 0;
+    host->nblk_counter = 0;
+    host->tx_dma = 0;
+    host->rx_dma = 0;
+    host->ae_level = 0x00;
+    host->af_level = 0x1f;
+    host->transfer = 0;
+    host->cdet_wakeup = 0;
+    host->cdet_enable = 0;
+    qemu_set_irq(host->coverswitch, host->cdet_state);
+    host->clkdiv = 0;
+}
+
 static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
 {
     uint16_t i;
@@ -282,7 +325,8 @@
         return s->arg >> 16;
 
     case 0x0c: /* MMC_CON */
-        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
+        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | 
+                (s->be << 10) | s->clkdiv;
 
     case 0x10: /* MMC_STAT */
         return s->status;
@@ -324,12 +368,12 @@
     case 0x30: /* MMC_SPI */
         return 0x0000;
     case 0x34: /* MMC_SDIO */
-        return s->sdio;
+        return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
     case 0x38: /* MMC_SYST */
         return 0x0000;
 
     case 0x3c: /* MMC_REV */
-        return 0x0001;
+        return s->rev;
 
     case 0x40: /* MMC_RSP0 */
     case 0x44: /* MMC_RSP1 */
@@ -340,6 +384,13 @@
     case 0x58: /* MMC_RSP6 */
     case 0x5c: /* MMC_RSP7 */
         return s->rsp[(offset - 0x40) >> 2];
+
+    /* OMAP2-specific */
+    case 0x60: /* MMC_IOSR */
+    case 0x64: /* MMC_SYSC */
+        return 0;
+    case 0x68: /* MMC_SYSS */
+        return 1;                                              /* RSTD */
     }
 
     OMAP_BAD_REG(offset);
@@ -383,10 +434,16 @@
         s->dw = (value >> 15) & 1;
         s->mode = (value >> 12) & 3;
         s->enable = (value >> 11) & 1;
+        s->be = (value >> 10) & 1;
+        s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff);
         if (s->mode != 0)
             printf("SD mode %i unimplemented!\n", s->mode);
-        if (s->dw != 0)
+        if (s->be != 0)
+            printf("SD FIFO byte sex unimplemented!\n");
+        if (s->dw != 0 && s->lines < 4)
             printf("4-bit SD bus enabled\n");
+        if (!s->enable)
+            omap_mmc_reset(s);
         break;
 
     case 0x10: /* MMC_STAT */
@@ -395,13 +452,13 @@
         break;
 
     case 0x14: /* MMC_IE */
-        s->mask = value;
+        s->mask = value & 0x7fff;
         omap_mmc_interrupts_update(s);
         break;
 
     case 0x18: /* MMC_CTO */
         s->cto = value & 0xff;
-        if (s->cto > 0xfd)
+        if (s->cto > 0xfd && s->rev <= 1)
             printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
         break;
 
@@ -446,10 +503,12 @@
         break;
 
     /* SPI, SDIO and TEST modes unimplemented */
-    case 0x30: /* MMC_SPI */
+    case 0x30: /* MMC_SPI (OMAP1 only) */
         break;
     case 0x34: /* MMC_SDIO */
-        s->sdio = value & 0x2020;
+        s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
+        s->cdet_wakeup = (value >> 9) & 1;
+        s->cdet_enable = (value >> 2) & 1;
         break;
     case 0x38: /* MMC_SYST */
         break;
@@ -466,6 +525,19 @@
         OMAP_RO_REG(offset);
         break;
 
+    /* OMAP2-specific */
+    case 0x60: /* MMC_IOSR */
+        if (value & 0xf)
+            printf("MMC: SDIO bits used!\n");
+        break;
+    case 0x64: /* MMC_SYSC */
+        if (value & (1 << 2))                                  /* SRTS */
+            omap_mmc_reset(s);
+        break;
+    case 0x68: /* MMC_SYSS */
+        OMAP_RO_REG(offset);
+        break;
+
     default:
         OMAP_BAD_REG(offset);
     }
@@ -483,28 +555,21 @@
     omap_badwidth_write16,
 };
 
-void omap_mmc_reset(struct omap_mmc_s *host)
+static void omap_mmc_cover_cb(void *opaque, int line, int level)
 {
-    host->last_cmd = 0;
-    memset(host->rsp, 0, sizeof(host->rsp));
-    host->arg = 0;
-    host->dw = 0;
-    host->mode = 0;
-    host->enable = 0;
-    host->status = 0;
-    host->mask = 0;
-    host->cto = 0;
-    host->dto = 0;
-    host->fifo_len = 0;
-    host->blen = 0;
-    host->blen_counter = 0;
-    host->nblk = 0;
-    host->nblk_counter = 0;
-    host->tx_dma = 0;
-    host->rx_dma = 0;
-    host->ae_level = 0x00;
-    host->af_level = 0x1f;
-    host->transfer = 0;
+    struct omap_mmc_s *host = (struct omap_mmc_s *) opaque;
+
+    if (!host->cdet_state && level) {
+        host->status |= 0x0002;
+        omap_mmc_interrupts_update(host);
+        if (host->cdet_wakeup)
+            /* TODO: Assert wake-up */;
+    }
+
+    if (host->cdet_state != level) {
+        qemu_set_irq(host->coverswitch, level);
+        host->cdet_state = level;
+    }
 }
 
 struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
@@ -519,7 +584,11 @@
     s->base = base;
     s->dma = dma;
     s->clk = clk;
+    s->lines = 1;      /* TODO: needs to be settable per-board */
+    s->rev = 1;
 
+    omap_mmc_reset(s);
+
     iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
                     omap_mmc_writefn, s);
     cpu_register_physical_memory(s->base, 0x800, iomemtype);
@@ -530,7 +599,46 @@
     return s;
 }
 
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            qemu_mallocz(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = fclk;
+    s->lines = 4;
+    s->rev = 2;
+
+    omap_mmc_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
+                    omap_mmc_writefn, s);
+    s->base = omap_l4_attach(ta, 0, iomemtype);
+
+    /* Instantiate the storage */
+    s->card = sd_init(bd, 0);
+
+    s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
+    sd_set_cb(s->card, 0, s->cdet);
+
+    return s;
+}
+
 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
 {
-    sd_set_cb(s->card, ro, cover);
+    if (s->cdet) {
+        sd_set_cb(s->card, ro, s->cdet);
+        s->coverswitch = cover;
+        qemu_set_irq(cover, s->cdet_state);
+    } else
+        sd_set_cb(s->card, ro, cover);
 }
+
+void omap_mmc_enable(struct omap_mmc_s *s, int enable)
+{
+    sd_enable(s->card, enable);
+}

Modified: trunk/hw/palm.c
===================================================================
--- trunk/hw/palm.c     2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/palm.c     2008-04-14 21:05:22 UTC (rev 4213)
@@ -5,8 +5,8 @@
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,6 +25,7 @@
 #include "omap.h"
 #include "boards.h"
 #include "arm-misc.h"
+#include "devices.h"
 
 static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
 {
@@ -32,12 +33,14 @@
     return *val >> ((offset & 3) << 3);
 }
 
-static uint32_t static_readh(void *opaque, target_phys_addr_t offset) {
+static uint32_t static_readh(void *opaque, target_phys_addr_t offset)
+{
     uint32_t *val = (uint32_t *) opaque;
     return *val >> ((offset & 1) << 3);
 }
 
-static uint32_t static_readw(void *opaque, target_phys_addr_t offset) {
+static uint32_t static_readw(void *opaque, target_phys_addr_t offset)
+{
     uint32_t *val = (uint32_t *) opaque;
     return *val >> ((offset & 0) << 3);
 }

Modified: trunk/hw/sd.c
===================================================================
--- trunk/hw/sd.c       2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/sd.c       2008-04-14 21:05:22 UTC (rev 4213)
@@ -37,7 +37,7 @@
 
 #ifdef DEBUG_SD
 #define DPRINTF(fmt, args...) \
-do { printf("SD: " fmt , ##args); } while (0)
+do { fprintf(stderr, "SD: " fmt , ##args); } while (0)
 #else
 #define DPRINTF(fmt, args...) do {} while(0)
 #endif
@@ -99,6 +99,8 @@
     qemu_irq inserted_cb;
     BlockDriverState *bdrv;
     uint8_t *buf;
+
+    int enable;
 };
 
 static void sd_set_status(SDState *sd)
@@ -530,7 +532,7 @@
         sd->card_status &= ~CARD_IS_LOCKED;
         sd->pwd_len = 0;
         /* Erasing the entire card here! */
-        printf("SD: Card force-erased by CMD42\n");
+        fprintf(stderr, "SD: Card force-erased by CMD42\n");
         return;
     }
 
@@ -1076,7 +1078,7 @@
         return sd_r1;
 
     case 56:   /* CMD56:  GEN_CMD */
-        printf("SD: GEN_CMD 0x%08x\n", req.arg);
+        fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg);
 
         switch (sd->state) {
         case sd_transfer_state:
@@ -1096,18 +1098,18 @@
     bad_cmd:
         sd->card_status |= ILLEGAL_COMMAND;
 
-        printf("SD: Unknown CMD%i\n", req.cmd);
+        fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
         return sd_r0;
 
     unimplemented_cmd:
         /* Commands that are recognised but not yet implemented in SPI mode.  
*/
         sd->card_status |= ILLEGAL_COMMAND;
-        printf ("SD: CMD%i not implemented in SPI mode\n", req.cmd);
+        fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
         return sd_r0;
     }
 
     sd->card_status |= ILLEGAL_COMMAND;
-    printf("SD: CMD%i in a wrong state\n", req.cmd);
+    fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
     return sd_r0;
 }
 
@@ -1217,7 +1219,7 @@
         return sd_normal_command(sd, req);
     }
 
-    printf("SD: ACMD%i in a wrong state\n", req.cmd);
+    fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
     return sd_r0;
 }
 
@@ -1227,7 +1229,7 @@
     sd_rsp_type_t rtype;
     int rsplen;
 
-    if (!bdrv_is_inserted(sd->bdrv)) {
+    if (!bdrv_is_inserted(sd->bdrv) || !sd->enable) {
         return 0;
     }
 
@@ -1247,7 +1249,7 @@
                           sd_cmd_class[req->cmd] == 7 ||
                           req->cmd == 16 || req->cmd == 55))) {
             sd->card_status |= ILLEGAL_COMMAND;
-            printf("SD: Card is locked\n");
+            fprintf(stderr, "SD: Card is locked\n");
             return 0;
         }
 
@@ -1321,7 +1323,7 @@
     uint32_t end = addr + len;
 
     if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
-        printf("sd_blk_read: read error on host side\n");
+        fprintf(stderr, "sd_blk_read: read error on host side\n");
         return;
     }
 
@@ -1329,7 +1331,7 @@
         memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
 
         if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
-            printf("sd_blk_read: read error on host side\n");
+            fprintf(stderr, "sd_blk_read: read error on host side\n");
             return;
         }
         memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
@@ -1343,28 +1345,28 @@
 
     if ((addr & 511) || len < 512)
         if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
-            printf("sd_blk_write: read error on host side\n");
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
             return;
         }
 
     if (end > (addr & ~511) + 512) {
         memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
         if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) {
-            printf("sd_blk_write: write error on host side\n");
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
             return;
         }
 
         if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) {
-            printf("sd_blk_write: read error on host side\n");
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
             return;
         }
         memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
         if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1)
-            printf("sd_blk_write: write error on host side\n");
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
     } else {
         memcpy(sd->buf + (addr & 511), sd->data, len);
         if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1)
-            printf("sd_blk_write: write error on host side\n");
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
     }
 }
 
@@ -1377,11 +1379,11 @@
 {
     int i;
 
-    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
         return;
 
     if (sd->state != sd_receivingdata_state) {
-        printf("sd_write_data: not in Receiving-Data state\n");
+        fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
         return;
     }
 
@@ -1489,7 +1491,7 @@
         break;
 
     default:
-        printf("sd_write_data: unknown command\n");
+        fprintf(stderr, "sd_write_data: unknown command\n");
         break;
     }
 }
@@ -1499,11 +1501,11 @@
     /* TODO: Append CRCs */
     uint8_t ret;
 
-    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
         return 0x00;
 
     if (sd->state != sd_sendingdata_state) {
-        printf("sd_read_data: not in Sending-Data state\n");
+        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
         return 0x00;
     }
 
@@ -1603,7 +1605,7 @@
         break;
 
     default:
-        printf("sd_read_data: unknown command\n");
+        fprintf(stderr, "sd_read_data: unknown command\n");
         return 0x00;
     }
 
@@ -1614,3 +1616,8 @@
 {
     return sd->state == sd_sendingdata_state;
 }
+
+void sd_enable(SDState *sd, int enable)
+{
+    sd->enable = enable;
+}

Modified: trunk/hw/sd.h
===================================================================
--- trunk/hw/sd.h       2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/hw/sd.h       2008-04-14 21:05:22 UTC (rev 4213)
@@ -74,6 +74,7 @@
 uint8_t sd_read_data(SDState *sd);
 void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
 int sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, int enable);
 
 /* ssi-sd.c */
 int ssi_sd_xfer(void *opaque, int val);

Modified: trunk/target-arm/cpu.h
===================================================================
--- trunk/target-arm/cpu.h      2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/target-arm/cpu.h      2008-04-14 21:05:22 UTC (rev 4213)
@@ -373,6 +373,7 @@
 #define ARM_CPUID_PXA270_C0   0x69054114
 #define ARM_CPUID_PXA270_C5   0x69054117
 #define ARM_CPUID_ARM1136     0x4117b363
+#define ARM_CPUID_ARM1136_R2  0x4107b362
 #define ARM_CPUID_ARM11MPCORE 0x410fb022
 #define ARM_CPUID_CORTEXA8    0x410fc080
 #define ARM_CPUID_CORTEXM3    0x410fc231

Modified: trunk/target-arm/helper.c
===================================================================
--- trunk/target-arm/helper.c   2008-04-14 20:27:51 UTC (rev 4212)
+++ trunk/target-arm/helper.c   2008-04-14 21:05:22 UTC (rev 4213)
@@ -55,6 +55,7 @@
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
+    case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
@@ -206,6 +207,7 @@
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
     { ARM_CPUID_ARM1136, "arm1136"},
+    { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
     { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
     { ARM_CPUID_CORTEXM3, "cortex-m3"},
     { ARM_CPUID_CORTEXA8, "cortex-a8"},
@@ -1582,6 +1584,7 @@
             case ARM_CPUID_ARM1026:
                 return 1;
             case ARM_CPUID_ARM1136:
+            case ARM_CPUID_ARM1136_R2:
                 return 7;
             case ARM_CPUID_ARM11MPCORE:
                 return 1;
@@ -1762,6 +1765,10 @@
             case 8: /* TI925T_status */
                 return 0;
             }
+            /* TODO: Peripheral port remap register:
+             * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt
+             * controller base address at $rn & ~0xfff and map size of
+             * 0x200 << ($rn & 0xfff), when MMU is off.  */
             goto bad_reg;
         }
         return 0;






reply via email to

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