diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/omap.h | 304 | ||||
-rw-r--r-- | hw/omap1.c | 441 | ||||
-rw-r--r-- | hw/omap2.c | 3860 | ||||
-rw-r--r-- | hw/omap_clk.c | 522 | ||||
-rw-r--r-- | hw/omap_dma.c | 679 | ||||
-rw-r--r-- | hw/omap_dss.c | 1093 | ||||
-rw-r--r-- | hw/omap_i2c.c | 15 | ||||
-rw-r--r-- | hw/omap_mmc.c | 172 | ||||
-rw-r--r-- | hw/palm.c | 11 | ||||
-rw-r--r-- | hw/sd.c | 51 | ||||
-rw-r--r-- | hw/sd.h | 1 |
11 files changed, 6925 insertions, 224 deletions
@@ -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); } @@ -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); } @@ -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; +} @@ -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); |