aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-04-14 21:05:22 +0000
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-04-14 21:05:22 +0000
commit827df9f3c5fdea53531acf02b2db0afb9858f053 (patch)
tree95cb9c8d0ab76f1155f25df9cda123ce97cb0643 /hw
parentf93eb9ff66868df42f8433d16f2dc48a4af2490f (diff)
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. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4213 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw')
-rw-r--r--hw/omap.h304
-rw-r--r--hw/omap1.c441
-rw-r--r--hw/omap2.c3860
-rw-r--r--hw/omap_clk.c522
-rw-r--r--hw/omap_dma.c679
-rw-r--r--hw/omap_dss.c1093
-rw-r--r--hw/omap_i2c.c15
-rw-r--r--hw/omap_mmc.c172
-rw-r--r--hw/palm.c11
-rw-r--r--hw/sd.c51
-rw-r--r--hw/sd.h1
11 files changed, 6925 insertions, 224 deletions
diff --git a/hw/omap.h b/hw/omap.h
index ecfd54d1db..087b813788 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -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,14 +64,41 @@ int64_t omap_clk_getrate(omap_clk clk);
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_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_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_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
@@ -295,10 +331,20 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
* 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 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
# 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 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
# 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 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta,
# 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;
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 @@ enum omap_dma_port {
tipb,
local, /* omap16xx: ocp_t2 */
tipb_mpui,
- omap_dma_port_last,
+ __omap_dma_port_last,
};
typedef enum {
@@ -488,11 +558,83 @@ struct omap_dma_lcd_channel_s {
# 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;
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 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
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 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
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 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave);
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_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
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 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
# 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 @@ struct omap_mpu_state_s {
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 @@ struct omap_mpu_state_s {
omap_clk clk;
} pwt;
- struct omap_i2c_s *i2c;
+ struct omap_i2c_s *i2c[2];
struct omap_rtc_s *rtc;
@@ -722,7 +931,38 @@ struct omap_mpu_state_s {
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
@@ -743,24 +983,46 @@ uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr);
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)
diff --git a/hw/omap1.c b/hw/omap1.c
index 3888e800f5..b439423035 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -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 @@ struct omap_intr_handler_bank_s {
uint32_t mask;
uint32_t fiq;
uint32_t sens_edge;
+ uint32_t swi;
unsigned char priority[32];
};
@@ -94,11 +96,14 @@ struct omap_intr_handler_s {
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 @@ static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
* 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 @@ static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
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 @@ static void omap_set_intr(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->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 @@ static void omap_set_intr(void *opaque, int irq, int req)
}
}
+/* 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 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
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 @@ static void omap_inth_write(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;
- 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 @@ void omap_inth_reset(struct omap_intr_handler_s *s)
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 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
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 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
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 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
return 0x03310315;
case omap1510:
return 0x03310115;
+ default:
+ cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__);
}
break;
@@ -1298,6 +1554,8 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
return 0xfb57402f;
case omap1510:
return 0xfb47002f;
+ default:
+ cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__);
}
break;
}
@@ -1722,19 +1980,116 @@ static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
/* 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;
}
@@ -2778,9 +3133,10 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
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 @@ static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
}
/* 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 @@ static void omap_mpu_reset(void *opaque)
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_setup_dsp_mapping(const struct omap_map_s *map)
}
}
-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 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req)
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 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
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 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
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 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
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 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
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;
}
diff --git a/hw/omap2.c b/hw/omap2.c
new file mode 100644
index 0000000000..188e0927c0
--- /dev/null
+++ b/hw/omap2.c
@@ -0,0 +1,3860 @@
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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;
+}
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index 37daec266b..da03e156e6 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -1,7 +1,7 @@
/*
* OMAP clocks.
*
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
+ * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
*
* Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
*
@@ -34,6 +34,9 @@ struct clk {
#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_osc12m = {
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 i2c_ick = {
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 @@ static struct clk *onchip_clks[] = {
/* 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 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
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;
diff --git a/hw/omap_dma.c b/hw/omap_dma.c
index 1835826a10..6c0bd8267f 100644
--- a/hw/omap_dma.c
+++ b/hw/omap_dma.c
@@ -28,12 +28,15 @@ struct omap_dma_channel_s {
/* 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 @@ struct omap_dma_channel_s {
int transparent_copy;
int constant_fill;
uint32_t color;
+ int prefetch;
/* auto init and linked channel data */
int end_prog;
@@ -52,11 +56,13 @@ struct omap_dma_channel_s {
/* 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 @@ struct omap_dma_channel_s {
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 @@ struct omap_dma_s {
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 @@ struct omap_dma_s {
#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 @@ static void omap_dma_channel_load(struct omap_dma_s *s,
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 @@ static void omap_dma_deactivate_channel(struct omap_dma_s *s,
/* 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 @@ static void omap_dma_enable_channel(struct omap_dma_s *s,
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_channel_end_prog(struct omap_dma_s *s,
}
}
+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 @@ static void omap_dma_channel_run(struct omap_dma_s *s)
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 @@ static void omap_dma_channel_run(struct omap_dma_s *s)
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 @@ void omap_dma_reset(struct omap_dma_s *s)
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 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s,
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 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
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 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
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 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
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 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
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 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
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 */
- case 0x452: /* DMA_CAPS_1_U */
- *ret = 0;
+ *ret = (s->caps[0] >> 0) & 0xffff;
break;
+ case 0x452: /* DMA_CAPS_1_U */
+ *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 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
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 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
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 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr,
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 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr,
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 CPUWriteMemoryFunc *omap_dma_writefn[] = {
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_clk_update(void *opaque, int line, int on)
}
}
+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 *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
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 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
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 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
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;
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
new file mode 100644
index 0000000000..505438231b
--- /dev/null
+++ b/hw/omap_dss.c
@@ -0,0 +1,1093 @@
+/*
+ * OMAP2 Display Subsystem.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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;
+}
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index de63309ca3..9915676b1f 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -150,6 +150,8 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
}
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 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
}
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 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
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 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
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 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
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:
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index 6fbbb84912..366d51672b 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -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 @@ struct omap_mmc_s {
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 @@ struct omap_mmc_s {
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 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
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 @@ static void omap_mmc_update(void *opaque)
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 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
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 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
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 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
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 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
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 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
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 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
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 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
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 @@ static CPUWriteMemoryFunc *omap_mmc_writefn[] = {
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,6 +584,10 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
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);
@@ -530,7 +599,46 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
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);
}
diff --git a/hw/palm.c b/hw/palm.c
index 6d4e6c69fc..a1ecaf022f 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -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 @@ static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
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);
}
diff --git a/hw/sd.c b/hw/sd.c
index 1f71d85a52..de7dd89c18 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -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 @@ struct SDState {
qemu_irq inserted_cb;
BlockDriverState *bdrv;
uint8_t *buf;
+
+ int enable;
};
static void sd_set_status(SDState *sd)
@@ -530,7 +532,7 @@ static void sd_lock_command(SDState *sd)
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 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
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 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
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 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
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 @@ int sd_do_command(SDState *sd, struct sd_request_s *req,
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 @@ int sd_do_command(SDState *sd, struct sd_request_s *req,
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 @@ static void sd_blk_read(SDState *sd, uint32_t addr, uint32_t len)
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 @@ static void sd_blk_read(SDState *sd, uint32_t addr, uint32_t len)
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 @@ static void sd_blk_write(SDState *sd, uint32_t addr, uint32_t len)
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 @@ void sd_write_data(SDState *sd, uint8_t value)
{
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 @@ void sd_write_data(SDState *sd, uint8_t value)
break;
default:
- printf("sd_write_data: unknown command\n");
+ fprintf(stderr, "sd_write_data: unknown command\n");
break;
}
}
@@ -1499,11 +1501,11 @@ uint8_t sd_read_data(SDState *sd)
/* 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 @@ uint8_t sd_read_data(SDState *sd)
break;
default:
- printf("sd_read_data: unknown command\n");
+ fprintf(stderr, "sd_read_data: unknown command\n");
return 0x00;
}
@@ -1614,3 +1616,8 @@ int sd_data_ready(SDState *sd)
{
return sd->state == sd_sendingdata_state;
}
+
+void sd_enable(SDState *sd, int enable)
+{
+ sd->enable = enable;
+}
diff --git a/hw/sd.h b/hw/sd.h
index 85f110f3c7..cb7bc9c9a4 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -74,6 +74,7 @@ void sd_write_data(SDState *sd, uint8_t value);
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);