Commit a171fe394a82e3a2dad76e901959d859b1966541
1 parent
2bac6019
Add remaining PXA2xx on-chip peripherals except I2C master.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2751 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
2642 additions
and
2 deletions
hw/pxa.h
| ... | ... | @@ -63,6 +63,12 @@ |
| 63 | 63 | struct pxa2xx_pic_state_s; |
| 64 | 64 | qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); |
| 65 | 65 | |
| 66 | +/* pxa2xx_timer.c */ | |
| 67 | +void pxa25x_timer_init(target_phys_addr_t base, | |
| 68 | + qemu_irq *irqs, CPUState *cpustate); | |
| 69 | +void pxa27x_timer_init(target_phys_addr_t base, | |
| 70 | + qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate); | |
| 71 | + | |
| 66 | 72 | /* pxa2xx_gpio.c */ |
| 67 | 73 | struct pxa2xx_gpio_info_s; |
| 68 | 74 | struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, |
| ... | ... | @@ -81,6 +87,29 @@ struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base, |
| 81 | 87 | qemu_irq irq); |
| 82 | 88 | void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on); |
| 83 | 89 | |
| 90 | +/* pxa2xx_lcd.c */ | |
| 91 | +struct pxa2xx_lcdc_s; | |
| 92 | +struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, | |
| 93 | + qemu_irq irq, DisplayState *ds); | |
| 94 | +void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, | |
| 95 | + void (*cb)(void *opaque), void *opaque); | |
| 96 | +void pxa2xx_lcdc_oritentation(void *opaque, int angle); | |
| 97 | + | |
| 98 | +/* pxa2xx_mmci.c */ | |
| 99 | +struct pxa2xx_mmci_s; | |
| 100 | +struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, | |
| 101 | + qemu_irq irq, void *dma); | |
| 102 | +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, | |
| 103 | + void (*readonly_cb)(void *, int), | |
| 104 | + void (*coverswitch_cb)(void *, int)); | |
| 105 | + | |
| 106 | +/* pxa2xx_pcmcia.c */ | |
| 107 | +struct pxa2xx_pcmcia_s; | |
| 108 | +struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base); | |
| 109 | +int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card); | |
| 110 | +int pxa2xx_pcmcia_dettach(void *opaque); | |
| 111 | +void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq); | |
| 112 | + | |
| 84 | 113 | /* pxa2xx.c */ |
| 85 | 114 | struct pxa2xx_ssp_s; |
| 86 | 115 | void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, |
| ... | ... | @@ -95,7 +124,10 @@ struct pxa2xx_state_s { |
| 95 | 124 | qemu_irq *pic; |
| 96 | 125 | struct pxa2xx_dma_state_s *dma; |
| 97 | 126 | struct pxa2xx_gpio_info_s *gpio; |
| 127 | + struct pxa2xx_lcdc_s *lcd; | |
| 98 | 128 | struct pxa2xx_ssp_s **ssp; |
| 129 | + struct pxa2xx_mmci_s *mmc; | |
| 130 | + struct pxa2xx_pcmcia_s *pcmcia[2]; | |
| 99 | 131 | struct pxa2xx_i2s_s *i2s; |
| 100 | 132 | struct pxa2xx_fir_s *fir; |
| 101 | 133 | ... | ... |
hw/pxa2xx.c
| ... | ... | @@ -1531,8 +1531,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) |
| 1531 | 1531 | |
| 1532 | 1532 | s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); |
| 1533 | 1533 | |
| 1534 | + pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], | |
| 1535 | + s->pic[PXA27X_PIC_OST_4_11], s->env); | |
| 1536 | + | |
| 1534 | 1537 | s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); |
| 1535 | 1538 | |
| 1539 | + s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); | |
| 1540 | + | |
| 1536 | 1541 | for (i = 0; pxa270_serial[i].io_base; i ++) |
| 1537 | 1542 | if (serial_hds[i]) |
| 1538 | 1543 | serial_mm_init(pxa270_serial[i].io_base, 2, |
| ... | ... | @@ -1543,6 +1548,9 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) |
| 1543 | 1548 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], |
| 1544 | 1549 | s->dma, serial_hds[i]); |
| 1545 | 1550 | |
| 1551 | + if (ds) | |
| 1552 | + s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); | |
| 1553 | + | |
| 1546 | 1554 | s->cm_base = 0x41300000; |
| 1547 | 1555 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ |
| 1548 | 1556 | s->clkcfg = 0x00000009; /* Turbo mode active */ |
| ... | ... | @@ -1575,6 +1583,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) |
| 1575 | 1583 | cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); |
| 1576 | 1584 | } |
| 1577 | 1585 | |
| 1586 | + if (usb_enabled) { | |
| 1587 | + usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]); | |
| 1588 | + } | |
| 1589 | + | |
| 1590 | + s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000); | |
| 1591 | + s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); | |
| 1592 | + | |
| 1578 | 1593 | s->rtc_base = 0x40900000; |
| 1579 | 1594 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, |
| 1580 | 1595 | pxa2xx_rtc_writefn, s); |
| ... | ... | @@ -1609,8 +1624,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) |
| 1609 | 1624 | |
| 1610 | 1625 | s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); |
| 1611 | 1626 | |
| 1627 | + pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], s->env); | |
| 1628 | + | |
| 1612 | 1629 | s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); |
| 1613 | 1630 | |
| 1631 | + s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); | |
| 1632 | + | |
| 1614 | 1633 | for (i = 0; pxa255_serial[i].io_base; i ++) |
| 1615 | 1634 | if (serial_hds[i]) |
| 1616 | 1635 | serial_mm_init(pxa255_serial[i].io_base, 2, |
| ... | ... | @@ -1621,6 +1640,9 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) |
| 1621 | 1640 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], |
| 1622 | 1641 | s->dma, serial_hds[i]); |
| 1623 | 1642 | |
| 1643 | + if (ds) | |
| 1644 | + s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); | |
| 1645 | + | |
| 1624 | 1646 | s->cm_base = 0x41300000; |
| 1625 | 1647 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ |
| 1626 | 1648 | s->clkcfg = 0x00000009; /* Turbo mode active */ |
| ... | ... | @@ -1653,6 +1675,13 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) |
| 1653 | 1675 | cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); |
| 1654 | 1676 | } |
| 1655 | 1677 | |
| 1678 | + if (usb_enabled) { | |
| 1679 | + usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]); | |
| 1680 | + } | |
| 1681 | + | |
| 1682 | + s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000); | |
| 1683 | + s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); | |
| 1684 | + | |
| 1656 | 1685 | s->rtc_base = 0x40900000; |
| 1657 | 1686 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, |
| 1658 | 1687 | pxa2xx_rtc_writefn, s); | ... | ... |
hw/pxa2xx_lcd.c
0 โ 100644
| 1 | +/* | |
| 2 | + * Intel XScale PXA255/270 LCDC emulation. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | |
| 5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | |
| 6 | + * | |
| 7 | + * This code is licensed under the GPLv2. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include "vl.h" | |
| 11 | + | |
| 12 | +typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); | |
| 13 | + | |
| 14 | +struct pxa2xx_lcdc_s { | |
| 15 | + target_phys_addr_t base; | |
| 16 | + qemu_irq irq; | |
| 17 | + int irqlevel; | |
| 18 | + | |
| 19 | + int invalidated; | |
| 20 | + DisplayState *ds; | |
| 21 | + drawfn *line_fn[2]; | |
| 22 | + int dest_width; | |
| 23 | + int xres, yres; | |
| 24 | + int pal_for; | |
| 25 | + int transp; | |
| 26 | + enum { | |
| 27 | + pxa_lcdc_2bpp = 1, | |
| 28 | + pxa_lcdc_4bpp = 2, | |
| 29 | + pxa_lcdc_8bpp = 3, | |
| 30 | + pxa_lcdc_16bpp = 4, | |
| 31 | + pxa_lcdc_18bpp = 5, | |
| 32 | + pxa_lcdc_18pbpp = 6, | |
| 33 | + pxa_lcdc_19bpp = 7, | |
| 34 | + pxa_lcdc_19pbpp = 8, | |
| 35 | + pxa_lcdc_24bpp = 9, | |
| 36 | + pxa_lcdc_25bpp = 10, | |
| 37 | + } bpp; | |
| 38 | + | |
| 39 | + uint32_t control[6]; | |
| 40 | + uint32_t status[2]; | |
| 41 | + uint32_t ovl1c[2]; | |
| 42 | + uint32_t ovl2c[2]; | |
| 43 | + uint32_t ccr; | |
| 44 | + uint32_t cmdcr; | |
| 45 | + uint32_t trgbr; | |
| 46 | + uint32_t tcr; | |
| 47 | + uint32_t liidr; | |
| 48 | + uint8_t bscntr; | |
| 49 | + | |
| 50 | + struct { | |
| 51 | + target_phys_addr_t branch; | |
| 52 | + int up; | |
| 53 | + uint8_t palette[1024]; | |
| 54 | + uint8_t pbuffer[1024]; | |
| 55 | + void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb, | |
| 56 | + int *miny, int *maxy); | |
| 57 | + | |
| 58 | + target_phys_addr_t descriptor; | |
| 59 | + target_phys_addr_t source; | |
| 60 | + uint32_t id; | |
| 61 | + uint32_t command; | |
| 62 | + } dma_ch[7]; | |
| 63 | + | |
| 64 | + void (*vsync_cb)(void *opaque); | |
| 65 | + void *opaque; | |
| 66 | + int orientation; | |
| 67 | +}; | |
| 68 | + | |
| 69 | +struct __attribute__ ((__packed__)) pxa_frame_descriptor_s { | |
| 70 | + uint32_t fdaddr; | |
| 71 | + uint32_t fsaddr; | |
| 72 | + uint32_t fidr; | |
| 73 | + uint32_t ldcmd; | |
| 74 | +}; | |
| 75 | + | |
| 76 | +#define LCCR0 0x000 /* LCD Controller Control register 0 */ | |
| 77 | +#define LCCR1 0x004 /* LCD Controller Control register 1 */ | |
| 78 | +#define LCCR2 0x008 /* LCD Controller Control register 2 */ | |
| 79 | +#define LCCR3 0x00c /* LCD Controller Control register 3 */ | |
| 80 | +#define LCCR4 0x010 /* LCD Controller Control register 4 */ | |
| 81 | +#define LCCR5 0x014 /* LCD Controller Control register 5 */ | |
| 82 | + | |
| 83 | +#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ | |
| 84 | +#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ | |
| 85 | +#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ | |
| 86 | +#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ | |
| 87 | +#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ | |
| 88 | +#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ | |
| 89 | +#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ | |
| 90 | + | |
| 91 | +#define LCSR1 0x034 /* LCD Controller Status register 1 */ | |
| 92 | +#define LCSR0 0x038 /* LCD Controller Status register 0 */ | |
| 93 | +#define LIIDR 0x03c /* LCD Controller Interrupt ID register */ | |
| 94 | + | |
| 95 | +#define TRGBR 0x040 /* TMED RGB Seed register */ | |
| 96 | +#define TCR 0x044 /* TMED Control register */ | |
| 97 | + | |
| 98 | +#define OVL1C1 0x050 /* Overlay 1 Control register 1 */ | |
| 99 | +#define OVL1C2 0x060 /* Overlay 1 Control register 2 */ | |
| 100 | +#define OVL2C1 0x070 /* Overlay 2 Control register 1 */ | |
| 101 | +#define OVL2C2 0x080 /* Overlay 2 Control register 2 */ | |
| 102 | +#define CCR 0x090 /* Cursor Control register */ | |
| 103 | + | |
| 104 | +#define CMDCR 0x100 /* Command Control register */ | |
| 105 | +#define PRSR 0x104 /* Panel Read Status register */ | |
| 106 | + | |
| 107 | +#define PXA_LCDDMA_CHANS 7 | |
| 108 | +#define DMA_FDADR 0x00 /* Frame Descriptor Address register */ | |
| 109 | +#define DMA_FSADR 0x04 /* Frame Source Address register */ | |
| 110 | +#define DMA_FIDR 0x08 /* Frame ID register */ | |
| 111 | +#define DMA_LDCMD 0x0c /* Command register */ | |
| 112 | + | |
| 113 | +/* LCD Buffer Strength Control register */ | |
| 114 | +#define BSCNTR 0x04000054 | |
| 115 | + | |
| 116 | +/* Bitfield masks */ | |
| 117 | +#define LCCR0_ENB (1 << 0) | |
| 118 | +#define LCCR0_CMS (1 << 1) | |
| 119 | +#define LCCR0_SDS (1 << 2) | |
| 120 | +#define LCCR0_LDM (1 << 3) | |
| 121 | +#define LCCR0_SOFM0 (1 << 4) | |
| 122 | +#define LCCR0_IUM (1 << 5) | |
| 123 | +#define LCCR0_EOFM0 (1 << 6) | |
| 124 | +#define LCCR0_PAS (1 << 7) | |
| 125 | +#define LCCR0_DPD (1 << 9) | |
| 126 | +#define LCCR0_DIS (1 << 10) | |
| 127 | +#define LCCR0_QDM (1 << 11) | |
| 128 | +#define LCCR0_PDD (0xff << 12) | |
| 129 | +#define LCCR0_BSM0 (1 << 20) | |
| 130 | +#define LCCR0_OUM (1 << 21) | |
| 131 | +#define LCCR0_LCDT (1 << 22) | |
| 132 | +#define LCCR0_RDSTM (1 << 23) | |
| 133 | +#define LCCR0_CMDIM (1 << 24) | |
| 134 | +#define LCCR0_OUC (1 << 25) | |
| 135 | +#define LCCR0_LDDALT (1 << 26) | |
| 136 | +#define LCCR1_PPL(x) ((x) & 0x3ff) | |
| 137 | +#define LCCR2_LPP(x) ((x) & 0x3ff) | |
| 138 | +#define LCCR3_API (15 << 16) | |
| 139 | +#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) | |
| 140 | +#define LCCR3_PDFOR(x) (((x) >> 30) & 3) | |
| 141 | +#define LCCR4_K1(x) (((x) >> 0) & 7) | |
| 142 | +#define LCCR4_K2(x) (((x) >> 3) & 7) | |
| 143 | +#define LCCR4_K3(x) (((x) >> 6) & 7) | |
| 144 | +#define LCCR4_PALFOR(x) (((x) >> 15) & 3) | |
| 145 | +#define LCCR5_SOFM(ch) (1 << (ch - 1)) | |
| 146 | +#define LCCR5_EOFM(ch) (1 << (ch + 7)) | |
| 147 | +#define LCCR5_BSM(ch) (1 << (ch + 15)) | |
| 148 | +#define LCCR5_IUM(ch) (1 << (ch + 23)) | |
| 149 | +#define OVLC1_EN (1 << 31) | |
| 150 | +#define CCR_CEN (1 << 31) | |
| 151 | +#define FBR_BRA (1 << 0) | |
| 152 | +#define FBR_BINT (1 << 1) | |
| 153 | +#define FBR_SRCADDR (0xfffffff << 4) | |
| 154 | +#define LCSR0_LDD (1 << 0) | |
| 155 | +#define LCSR0_SOF0 (1 << 1) | |
| 156 | +#define LCSR0_BER (1 << 2) | |
| 157 | +#define LCSR0_ABC (1 << 3) | |
| 158 | +#define LCSR0_IU0 (1 << 4) | |
| 159 | +#define LCSR0_IU1 (1 << 5) | |
| 160 | +#define LCSR0_OU (1 << 6) | |
| 161 | +#define LCSR0_QD (1 << 7) | |
| 162 | +#define LCSR0_EOF0 (1 << 8) | |
| 163 | +#define LCSR0_BS0 (1 << 9) | |
| 164 | +#define LCSR0_SINT (1 << 10) | |
| 165 | +#define LCSR0_RDST (1 << 11) | |
| 166 | +#define LCSR0_CMDINT (1 << 12) | |
| 167 | +#define LCSR0_BERCH(x) (((x) & 7) << 28) | |
| 168 | +#define LCSR1_SOF(ch) (1 << (ch - 1)) | |
| 169 | +#define LCSR1_EOF(ch) (1 << (ch + 7)) | |
| 170 | +#define LCSR1_BS(ch) (1 << (ch + 15)) | |
| 171 | +#define LCSR1_IU(ch) (1 << (ch + 23)) | |
| 172 | +#define LDCMD_LENGTH(x) ((x) & 0x001ffffc) | |
| 173 | +#define LDCMD_EOFINT (1 << 21) | |
| 174 | +#define LDCMD_SOFINT (1 << 22) | |
| 175 | +#define LDCMD_PAL (1 << 26) | |
| 176 | + | |
| 177 | +/* Route internal interrupt lines to the global IC */ | |
| 178 | +static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s) | |
| 179 | +{ | |
| 180 | + int level = 0; | |
| 181 | + level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM); | |
| 182 | + level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0); | |
| 183 | + level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM); | |
| 184 | + level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1)); | |
| 185 | + level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM); | |
| 186 | + level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM); | |
| 187 | + level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0); | |
| 188 | + level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0); | |
| 189 | + level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM); | |
| 190 | + level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM); | |
| 191 | + level |= (s->status[1] & ~s->control[5]); | |
| 192 | + | |
| 193 | + qemu_set_irq(s->irq, !!level); | |
| 194 | + s->irqlevel = level; | |
| 195 | +} | |
| 196 | + | |
| 197 | +/* Set Branch Status interrupt high and poke associated registers */ | |
| 198 | +static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch) | |
| 199 | +{ | |
| 200 | + int unmasked; | |
| 201 | + if (ch == 0) { | |
| 202 | + s->status[0] |= LCSR0_BS0; | |
| 203 | + unmasked = !(s->control[0] & LCCR0_BSM0); | |
| 204 | + } else { | |
| 205 | + s->status[1] |= LCSR1_BS(ch); | |
| 206 | + unmasked = !(s->control[5] & LCCR5_BSM(ch)); | |
| 207 | + } | |
| 208 | + | |
| 209 | + if (unmasked) { | |
| 210 | + if (s->irqlevel) | |
| 211 | + s->status[0] |= LCSR0_SINT; | |
| 212 | + else | |
| 213 | + s->liidr = s->dma_ch[ch].id; | |
| 214 | + } | |
| 215 | +} | |
| 216 | + | |
| 217 | +/* Set Start Of Frame Status interrupt high and poke associated registers */ | |
| 218 | +static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch) | |
| 219 | +{ | |
| 220 | + int unmasked; | |
| 221 | + if (!(s->dma_ch[ch].command & LDCMD_SOFINT)) | |
| 222 | + return; | |
| 223 | + | |
| 224 | + if (ch == 0) { | |
| 225 | + s->status[0] |= LCSR0_SOF0; | |
| 226 | + unmasked = !(s->control[0] & LCCR0_SOFM0); | |
| 227 | + } else { | |
| 228 | + s->status[1] |= LCSR1_SOF(ch); | |
| 229 | + unmasked = !(s->control[5] & LCCR5_SOFM(ch)); | |
| 230 | + } | |
| 231 | + | |
| 232 | + if (unmasked) { | |
| 233 | + if (s->irqlevel) | |
| 234 | + s->status[0] |= LCSR0_SINT; | |
| 235 | + else | |
| 236 | + s->liidr = s->dma_ch[ch].id; | |
| 237 | + } | |
| 238 | +} | |
| 239 | + | |
| 240 | +/* Set End Of Frame Status interrupt high and poke associated registers */ | |
| 241 | +static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch) | |
| 242 | +{ | |
| 243 | + int unmasked; | |
| 244 | + if (!(s->dma_ch[ch].command & LDCMD_EOFINT)) | |
| 245 | + return; | |
| 246 | + | |
| 247 | + if (ch == 0) { | |
| 248 | + s->status[0] |= LCSR0_EOF0; | |
| 249 | + unmasked = !(s->control[0] & LCCR0_EOFM0); | |
| 250 | + } else { | |
| 251 | + s->status[1] |= LCSR1_EOF(ch); | |
| 252 | + unmasked = !(s->control[5] & LCCR5_EOFM(ch)); | |
| 253 | + } | |
| 254 | + | |
| 255 | + if (unmasked) { | |
| 256 | + if (s->irqlevel) | |
| 257 | + s->status[0] |= LCSR0_SINT; | |
| 258 | + else | |
| 259 | + s->liidr = s->dma_ch[ch].id; | |
| 260 | + } | |
| 261 | +} | |
| 262 | + | |
| 263 | +/* Set Bus Error Status interrupt high and poke associated registers */ | |
| 264 | +static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch) | |
| 265 | +{ | |
| 266 | + s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER; | |
| 267 | + if (s->irqlevel) | |
| 268 | + s->status[0] |= LCSR0_SINT; | |
| 269 | + else | |
| 270 | + s->liidr = s->dma_ch[ch].id; | |
| 271 | +} | |
| 272 | + | |
| 273 | +/* Set Read Status interrupt high and poke associated registers */ | |
| 274 | +static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s) | |
| 275 | +{ | |
| 276 | + s->status[0] |= LCSR0_RDST; | |
| 277 | + if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM)) | |
| 278 | + s->status[0] |= LCSR0_SINT; | |
| 279 | +} | |
| 280 | + | |
| 281 | +/* Load new Frame Descriptors from DMA */ | |
| 282 | +static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s) | |
| 283 | +{ | |
| 284 | + struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS]; | |
| 285 | + target_phys_addr_t descptr; | |
| 286 | + int i; | |
| 287 | + | |
| 288 | + for (i = 0; i < PXA_LCDDMA_CHANS; i ++) { | |
| 289 | + desc[i] = 0; | |
| 290 | + s->dma_ch[i].source = 0; | |
| 291 | + | |
| 292 | + if (!s->dma_ch[i].up) | |
| 293 | + continue; | |
| 294 | + | |
| 295 | + if (s->dma_ch[i].branch & FBR_BRA) { | |
| 296 | + descptr = s->dma_ch[i].branch & FBR_SRCADDR; | |
| 297 | + if (s->dma_ch[i].branch & FBR_BINT) | |
| 298 | + pxa2xx_dma_bs_set(s, i); | |
| 299 | + s->dma_ch[i].branch &= ~FBR_BRA; | |
| 300 | + } else | |
| 301 | + descptr = s->dma_ch[i].descriptor; | |
| 302 | + | |
| 303 | + if (!(descptr >= PXA2XX_RAM_BASE && descptr + | |
| 304 | + sizeof(*desc[i]) <= PXA2XX_RAM_BASE + phys_ram_size)) | |
| 305 | + continue; | |
| 306 | + | |
| 307 | + descptr -= PXA2XX_RAM_BASE; | |
| 308 | + desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr); | |
| 309 | + s->dma_ch[i].descriptor = desc[i]->fdaddr; | |
| 310 | + s->dma_ch[i].source = desc[i]->fsaddr; | |
| 311 | + s->dma_ch[i].id = desc[i]->fidr; | |
| 312 | + s->dma_ch[i].command = desc[i]->ldcmd; | |
| 313 | + } | |
| 314 | +} | |
| 315 | + | |
| 316 | +static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset) | |
| 317 | +{ | |
| 318 | + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; | |
| 319 | + int ch; | |
| 320 | + offset -= s->base; | |
| 321 | + | |
| 322 | + switch (offset) { | |
| 323 | + case LCCR0: | |
| 324 | + return s->control[0]; | |
| 325 | + case LCCR1: | |
| 326 | + return s->control[1]; | |
| 327 | + case LCCR2: | |
| 328 | + return s->control[2]; | |
| 329 | + case LCCR3: | |
| 330 | + return s->control[3]; | |
| 331 | + case LCCR4: | |
| 332 | + return s->control[4]; | |
| 333 | + case LCCR5: | |
| 334 | + return s->control[5]; | |
| 335 | + | |
| 336 | + case OVL1C1: | |
| 337 | + return s->ovl1c[0]; | |
| 338 | + case OVL1C2: | |
| 339 | + return s->ovl1c[1]; | |
| 340 | + case OVL2C1: | |
| 341 | + return s->ovl2c[0]; | |
| 342 | + case OVL2C2: | |
| 343 | + return s->ovl2c[1]; | |
| 344 | + | |
| 345 | + case CCR: | |
| 346 | + return s->ccr; | |
| 347 | + | |
| 348 | + case CMDCR: | |
| 349 | + return s->cmdcr; | |
| 350 | + | |
| 351 | + case TRGBR: | |
| 352 | + return s->trgbr; | |
| 353 | + case TCR: | |
| 354 | + return s->tcr; | |
| 355 | + | |
| 356 | + case 0x200 ... 0x1000: /* DMA per-channel registers */ | |
| 357 | + ch = (offset - 0x200) >> 4; | |
| 358 | + if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) | |
| 359 | + goto fail; | |
| 360 | + | |
| 361 | + switch (offset & 0xf) { | |
| 362 | + case DMA_FDADR: | |
| 363 | + return s->dma_ch[ch].descriptor; | |
| 364 | + case DMA_FSADR: | |
| 365 | + return s->dma_ch[ch].source; | |
| 366 | + case DMA_FIDR: | |
| 367 | + return s->dma_ch[ch].id; | |
| 368 | + case DMA_LDCMD: | |
| 369 | + return s->dma_ch[ch].command; | |
| 370 | + default: | |
| 371 | + goto fail; | |
| 372 | + } | |
| 373 | + | |
| 374 | + case FBR0: | |
| 375 | + return s->dma_ch[0].branch; | |
| 376 | + case FBR1: | |
| 377 | + return s->dma_ch[1].branch; | |
| 378 | + case FBR2: | |
| 379 | + return s->dma_ch[2].branch; | |
| 380 | + case FBR3: | |
| 381 | + return s->dma_ch[3].branch; | |
| 382 | + case FBR4: | |
| 383 | + return s->dma_ch[4].branch; | |
| 384 | + case FBR5: | |
| 385 | + return s->dma_ch[5].branch; | |
| 386 | + case FBR6: | |
| 387 | + return s->dma_ch[6].branch; | |
| 388 | + | |
| 389 | + case BSCNTR: | |
| 390 | + return s->bscntr; | |
| 391 | + | |
| 392 | + case PRSR: | |
| 393 | + return 0; | |
| 394 | + | |
| 395 | + case LCSR0: | |
| 396 | + return s->status[0]; | |
| 397 | + case LCSR1: | |
| 398 | + return s->status[1]; | |
| 399 | + case LIIDR: | |
| 400 | + return s->liidr; | |
| 401 | + | |
| 402 | + default: | |
| 403 | + fail: | |
| 404 | + cpu_abort(cpu_single_env, | |
| 405 | + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); | |
| 406 | + } | |
| 407 | + | |
| 408 | + return 0; | |
| 409 | +} | |
| 410 | + | |
| 411 | +static void pxa2xx_lcdc_write(void *opaque, | |
| 412 | + target_phys_addr_t offset, uint32_t value) | |
| 413 | +{ | |
| 414 | + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; | |
| 415 | + int ch; | |
| 416 | + offset -= s->base; | |
| 417 | + | |
| 418 | + switch (offset) { | |
| 419 | + case LCCR0: | |
| 420 | + /* ACK Quick Disable done */ | |
| 421 | + if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB)) | |
| 422 | + s->status[0] |= LCSR0_QD; | |
| 423 | + | |
| 424 | + if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) | |
| 425 | + printf("%s: internal frame buffer unsupported\n", __FUNCTION__); | |
| 426 | + | |
| 427 | + if ((s->control[3] & LCCR3_API) && | |
| 428 | + (value & LCCR0_ENB) && !(value & LCCR0_LCDT)) | |
| 429 | + s->status[0] |= LCSR0_ABC; | |
| 430 | + | |
| 431 | + s->control[0] = value & 0x07ffffff; | |
| 432 | + pxa2xx_lcdc_int_update(s); | |
| 433 | + | |
| 434 | + s->dma_ch[0].up = !!(value & LCCR0_ENB); | |
| 435 | + s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS); | |
| 436 | + break; | |
| 437 | + | |
| 438 | + case LCCR1: | |
| 439 | + s->control[1] = value; | |
| 440 | + break; | |
| 441 | + | |
| 442 | + case LCCR2: | |
| 443 | + s->control[2] = value; | |
| 444 | + break; | |
| 445 | + | |
| 446 | + case LCCR3: | |
| 447 | + s->control[3] = value & 0xefffffff; | |
| 448 | + s->bpp = LCCR3_BPP(value); | |
| 449 | + break; | |
| 450 | + | |
| 451 | + case LCCR4: | |
| 452 | + s->control[4] = value & 0x83ff81ff; | |
| 453 | + break; | |
| 454 | + | |
| 455 | + case LCCR5: | |
| 456 | + s->control[5] = value & 0x3f3f3f3f; | |
| 457 | + break; | |
| 458 | + | |
| 459 | + case OVL1C1: | |
| 460 | + if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) | |
| 461 | + printf("%s: Overlay 1 not supported\n", __FUNCTION__); | |
| 462 | + | |
| 463 | + s->ovl1c[0] = value & 0x80ffffff; | |
| 464 | + s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS); | |
| 465 | + break; | |
| 466 | + | |
| 467 | + case OVL1C2: | |
| 468 | + s->ovl1c[1] = value & 0x000fffff; | |
| 469 | + break; | |
| 470 | + | |
| 471 | + case OVL2C1: | |
| 472 | + if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) | |
| 473 | + printf("%s: Overlay 2 not supported\n", __FUNCTION__); | |
| 474 | + | |
| 475 | + s->ovl2c[0] = value & 0x80ffffff; | |
| 476 | + s->dma_ch[2].up = !!(value & OVLC1_EN); | |
| 477 | + s->dma_ch[3].up = !!(value & OVLC1_EN); | |
| 478 | + s->dma_ch[4].up = !!(value & OVLC1_EN); | |
| 479 | + break; | |
| 480 | + | |
| 481 | + case OVL2C2: | |
| 482 | + s->ovl2c[1] = value & 0x007fffff; | |
| 483 | + break; | |
| 484 | + | |
| 485 | + case CCR: | |
| 486 | + if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) | |
| 487 | + printf("%s: Hardware cursor unimplemented\n", __FUNCTION__); | |
| 488 | + | |
| 489 | + s->ccr = value & 0x81ffffe7; | |
| 490 | + s->dma_ch[5].up = !!(value & CCR_CEN); | |
| 491 | + break; | |
| 492 | + | |
| 493 | + case CMDCR: | |
| 494 | + s->cmdcr = value & 0xff; | |
| 495 | + break; | |
| 496 | + | |
| 497 | + case TRGBR: | |
| 498 | + s->trgbr = value & 0x00ffffff; | |
| 499 | + break; | |
| 500 | + | |
| 501 | + case TCR: | |
| 502 | + s->tcr = value & 0x7fff; | |
| 503 | + break; | |
| 504 | + | |
| 505 | + case 0x200 ... 0x1000: /* DMA per-channel registers */ | |
| 506 | + ch = (offset - 0x200) >> 4; | |
| 507 | + if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) | |
| 508 | + goto fail; | |
| 509 | + | |
| 510 | + switch (offset & 0xf) { | |
| 511 | + case DMA_FDADR: | |
| 512 | + s->dma_ch[ch].descriptor = value & 0xfffffff0; | |
| 513 | + break; | |
| 514 | + | |
| 515 | + default: | |
| 516 | + goto fail; | |
| 517 | + } | |
| 518 | + break; | |
| 519 | + | |
| 520 | + case FBR0: | |
| 521 | + s->dma_ch[0].branch = value & 0xfffffff3; | |
| 522 | + break; | |
| 523 | + case FBR1: | |
| 524 | + s->dma_ch[1].branch = value & 0xfffffff3; | |
| 525 | + break; | |
| 526 | + case FBR2: | |
| 527 | + s->dma_ch[2].branch = value & 0xfffffff3; | |
| 528 | + break; | |
| 529 | + case FBR3: | |
| 530 | + s->dma_ch[3].branch = value & 0xfffffff3; | |
| 531 | + break; | |
| 532 | + case FBR4: | |
| 533 | + s->dma_ch[4].branch = value & 0xfffffff3; | |
| 534 | + break; | |
| 535 | + case FBR5: | |
| 536 | + s->dma_ch[5].branch = value & 0xfffffff3; | |
| 537 | + break; | |
| 538 | + case FBR6: | |
| 539 | + s->dma_ch[6].branch = value & 0xfffffff3; | |
| 540 | + break; | |
| 541 | + | |
| 542 | + case BSCNTR: | |
| 543 | + s->bscntr = value & 0xf; | |
| 544 | + break; | |
| 545 | + | |
| 546 | + case PRSR: | |
| 547 | + break; | |
| 548 | + | |
| 549 | + case LCSR0: | |
| 550 | + s->status[0] &= ~(value & 0xfff); | |
| 551 | + if (value & LCSR0_BER) | |
| 552 | + s->status[0] &= ~LCSR0_BERCH(7); | |
| 553 | + break; | |
| 554 | + | |
| 555 | + case LCSR1: | |
| 556 | + s->status[1] &= ~(value & 0x3e3f3f); | |
| 557 | + break; | |
| 558 | + | |
| 559 | + default: | |
| 560 | + fail: | |
| 561 | + cpu_abort(cpu_single_env, | |
| 562 | + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); | |
| 563 | + } | |
| 564 | +} | |
| 565 | + | |
| 566 | +static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = { | |
| 567 | + pxa2xx_lcdc_read, | |
| 568 | + pxa2xx_lcdc_read, | |
| 569 | + pxa2xx_lcdc_read | |
| 570 | +}; | |
| 571 | + | |
| 572 | +static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = { | |
| 573 | + pxa2xx_lcdc_write, | |
| 574 | + pxa2xx_lcdc_write, | |
| 575 | + pxa2xx_lcdc_write | |
| 576 | +}; | |
| 577 | + | |
| 578 | +static inline | |
| 579 | +uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) | |
| 580 | +{ | |
| 581 | + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); | |
| 582 | +} | |
| 583 | + | |
| 584 | +static inline | |
| 585 | +uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) | |
| 586 | +{ | |
| 587 | + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); | |
| 588 | +} | |
| 589 | + | |
| 590 | +static inline | |
| 591 | +uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) | |
| 592 | +{ | |
| 593 | + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); | |
| 594 | +} | |
| 595 | + | |
| 596 | +static inline | |
| 597 | +uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) | |
| 598 | +{ | |
| 599 | + return (r << 16) | (g << 8) | b; | |
| 600 | +} | |
| 601 | + | |
| 602 | +static inline | |
| 603 | +uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) | |
| 604 | +{ | |
| 605 | + return (r << 16) | (g << 8) | b; | |
| 606 | +} | |
| 607 | + | |
| 608 | +/* Load new palette for a given DMA channel, convert to internal format */ | |
| 609 | +static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp) | |
| 610 | +{ | |
| 611 | + int i, n, format, r, g, b, alpha; | |
| 612 | + uint32_t *dest, *src; | |
| 613 | + s->pal_for = LCCR4_PALFOR(s->control[4]); | |
| 614 | + format = s->pal_for; | |
| 615 | + | |
| 616 | + switch (bpp) { | |
| 617 | + case pxa_lcdc_2bpp: | |
| 618 | + n = 4; | |
| 619 | + break; | |
| 620 | + case pxa_lcdc_4bpp: | |
| 621 | + n = 16; | |
| 622 | + break; | |
| 623 | + case pxa_lcdc_8bpp: | |
| 624 | + n = 256; | |
| 625 | + break; | |
| 626 | + default: | |
| 627 | + format = 0; | |
| 628 | + return; | |
| 629 | + } | |
| 630 | + | |
| 631 | + src = (uint32_t *) s->dma_ch[ch].pbuffer; | |
| 632 | + dest = (uint32_t *) s->dma_ch[ch].palette; | |
| 633 | + alpha = r = g = b = 0; | |
| 634 | + | |
| 635 | + for (i = 0; i < n; i ++) { | |
| 636 | + switch (format) { | |
| 637 | + case 0: /* 16 bpp, no transparency */ | |
| 638 | + alpha = 0; | |
| 639 | + if (s->control[0] & LCCR0_CMS) | |
| 640 | + r = g = b = *src & 0xff; | |
| 641 | + else { | |
| 642 | + r = (*src & 0xf800) >> 8; | |
| 643 | + g = (*src & 0x07e0) >> 3; | |
| 644 | + b = (*src & 0x001f) << 3; | |
| 645 | + } | |
| 646 | + break; | |
| 647 | + case 1: /* 16 bpp plus transparency */ | |
| 648 | + alpha = *src & (1 << 24); | |
| 649 | + if (s->control[0] & LCCR0_CMS) | |
| 650 | + r = g = b = *src & 0xff; | |
| 651 | + else { | |
| 652 | + r = (*src & 0xf800) >> 8; | |
| 653 | + g = (*src & 0x07e0) >> 3; | |
| 654 | + b = (*src & 0x001f) << 3; | |
| 655 | + } | |
| 656 | + break; | |
| 657 | + case 2: /* 18 bpp plus transparency */ | |
| 658 | + alpha = *src & (1 << 24); | |
| 659 | + if (s->control[0] & LCCR0_CMS) | |
| 660 | + r = g = b = *src & 0xff; | |
| 661 | + else { | |
| 662 | + r = (*src & 0xf80000) >> 16; | |
| 663 | + g = (*src & 0x00fc00) >> 8; | |
| 664 | + b = (*src & 0x0000f8); | |
| 665 | + } | |
| 666 | + break; | |
| 667 | + case 3: /* 24 bpp plus transparency */ | |
| 668 | + alpha = *src & (1 << 24); | |
| 669 | + if (s->control[0] & LCCR0_CMS) | |
| 670 | + r = g = b = *src & 0xff; | |
| 671 | + else { | |
| 672 | + r = (*src & 0xff0000) >> 16; | |
| 673 | + g = (*src & 0x00ff00) >> 8; | |
| 674 | + b = (*src & 0x0000ff); | |
| 675 | + } | |
| 676 | + break; | |
| 677 | + } | |
| 678 | + switch (s->ds->depth) { | |
| 679 | + case 8: | |
| 680 | + *dest = rgb_to_pixel8(r, g, b) | alpha; | |
| 681 | + break; | |
| 682 | + case 15: | |
| 683 | + *dest = rgb_to_pixel15(r, g, b) | alpha; | |
| 684 | + break; | |
| 685 | + case 16: | |
| 686 | + *dest = rgb_to_pixel16(r, g, b) | alpha; | |
| 687 | + break; | |
| 688 | + case 24: | |
| 689 | + *dest = rgb_to_pixel24(r, g, b) | alpha; | |
| 690 | + break; | |
| 691 | + case 32: | |
| 692 | + *dest = rgb_to_pixel32(r, g, b) | alpha; | |
| 693 | + break; | |
| 694 | + } | |
| 695 | + src ++; | |
| 696 | + dest ++; | |
| 697 | + } | |
| 698 | +} | |
| 699 | + | |
| 700 | +static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, | |
| 701 | + uint8_t *fb, int *miny, int *maxy) | |
| 702 | +{ | |
| 703 | + int y, src_width, dest_width, dirty[2]; | |
| 704 | + uint8_t *src, *dest; | |
| 705 | + ram_addr_t x, addr, new_addr, start, end; | |
| 706 | + drawfn fn = 0; | |
| 707 | + if (s->dest_width) | |
| 708 | + fn = s->line_fn[s->transp][s->bpp]; | |
| 709 | + if (!fn) | |
| 710 | + return; | |
| 711 | + | |
| 712 | + src = fb; | |
| 713 | + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ | |
| 714 | + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) | |
| 715 | + src_width *= 3; | |
| 716 | + else if (s->bpp > pxa_lcdc_16bpp) | |
| 717 | + src_width *= 4; | |
| 718 | + else if (s->bpp > pxa_lcdc_8bpp) | |
| 719 | + src_width *= 2; | |
| 720 | + | |
| 721 | + dest = s->ds->data; | |
| 722 | + dest_width = s->xres * s->dest_width; | |
| 723 | + | |
| 724 | + addr = (ram_addr_t) (fb - phys_ram_base); | |
| 725 | + start = addr + s->yres * src_width; | |
| 726 | + end = addr; | |
| 727 | + dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); | |
| 728 | + for (y = 0; y < s->yres; y ++) { | |
| 729 | + new_addr = addr + src_width; | |
| 730 | + for (x = addr + TARGET_PAGE_SIZE; x < new_addr; | |
| 731 | + x += TARGET_PAGE_SIZE) { | |
| 732 | + dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); | |
| 733 | + dirty[0] |= dirty[1]; | |
| 734 | + } | |
| 735 | + if (dirty[0] || s->invalidated) { | |
| 736 | + fn((uint32_t *) s->dma_ch[0].palette, | |
| 737 | + dest, src, s->xres, s->dest_width); | |
| 738 | + if (addr < start) | |
| 739 | + start = addr; | |
| 740 | + if (new_addr > end) | |
| 741 | + end = new_addr; | |
| 742 | + if (y < *miny) | |
| 743 | + *miny = y; | |
| 744 | + if (y >= *maxy) | |
| 745 | + *maxy = y + 1; | |
| 746 | + } | |
| 747 | + addr = new_addr; | |
| 748 | + dirty[0] = dirty[1]; | |
| 749 | + src += src_width; | |
| 750 | + dest += dest_width; | |
| 751 | + } | |
| 752 | + | |
| 753 | + if (end > start) | |
| 754 | + cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); | |
| 755 | +} | |
| 756 | + | |
| 757 | +static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, | |
| 758 | + uint8_t *fb, int *miny, int *maxy) | |
| 759 | +{ | |
| 760 | + int y, src_width, dest_width, dirty[2]; | |
| 761 | + uint8_t *src, *dest; | |
| 762 | + ram_addr_t x, addr, new_addr, start, end; | |
| 763 | + drawfn fn = 0; | |
| 764 | + if (s->dest_width) | |
| 765 | + fn = s->line_fn[s->transp][s->bpp]; | |
| 766 | + if (!fn) | |
| 767 | + return; | |
| 768 | + | |
| 769 | + src = fb; | |
| 770 | + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ | |
| 771 | + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) | |
| 772 | + src_width *= 3; | |
| 773 | + else if (s->bpp > pxa_lcdc_16bpp) | |
| 774 | + src_width *= 4; | |
| 775 | + else if (s->bpp > pxa_lcdc_8bpp) | |
| 776 | + src_width *= 2; | |
| 777 | + | |
| 778 | + dest_width = s->yres * s->dest_width; | |
| 779 | + dest = s->ds->data + dest_width * (s->xres - 1); | |
| 780 | + | |
| 781 | + addr = (ram_addr_t) (fb - phys_ram_base); | |
| 782 | + start = addr + s->yres * src_width; | |
| 783 | + end = addr; | |
| 784 | + dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); | |
| 785 | + for (y = 0; y < s->yres; y ++) { | |
| 786 | + new_addr = addr + src_width; | |
| 787 | + for (x = addr + TARGET_PAGE_SIZE; x < new_addr; | |
| 788 | + x += TARGET_PAGE_SIZE) { | |
| 789 | + dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); | |
| 790 | + dirty[0] |= dirty[1]; | |
| 791 | + } | |
| 792 | + if (dirty[0] || s->invalidated) { | |
| 793 | + fn((uint32_t *) s->dma_ch[0].palette, | |
| 794 | + dest, src, s->xres, -dest_width); | |
| 795 | + if (addr < start) | |
| 796 | + start = addr; | |
| 797 | + if (new_addr > end) | |
| 798 | + end = new_addr; | |
| 799 | + if (y < *miny) | |
| 800 | + *miny = y; | |
| 801 | + if (y >= *maxy) | |
| 802 | + *maxy = y + 1; | |
| 803 | + } | |
| 804 | + addr = new_addr; | |
| 805 | + dirty[0] = dirty[1]; | |
| 806 | + src += src_width; | |
| 807 | + dest += s->dest_width; | |
| 808 | + } | |
| 809 | + | |
| 810 | + if (end > start) | |
| 811 | + cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); | |
| 812 | +} | |
| 813 | + | |
| 814 | +static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s) | |
| 815 | +{ | |
| 816 | + int width, height; | |
| 817 | + if (!(s->control[0] & LCCR0_ENB)) | |
| 818 | + return; | |
| 819 | + | |
| 820 | + width = LCCR1_PPL(s->control[1]) + 1; | |
| 821 | + height = LCCR2_LPP(s->control[2]) + 1; | |
| 822 | + | |
| 823 | + if (width != s->xres || height != s->yres) { | |
| 824 | + if (s->orientation) | |
| 825 | + dpy_resize(s->ds, height, width); | |
| 826 | + else | |
| 827 | + dpy_resize(s->ds, width, height); | |
| 828 | + s->invalidated = 1; | |
| 829 | + s->xres = width; | |
| 830 | + s->yres = height; | |
| 831 | + } | |
| 832 | +} | |
| 833 | + | |
| 834 | +static void pxa2xx_update_display(void *opaque) | |
| 835 | +{ | |
| 836 | + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; | |
| 837 | + uint8_t *fb; | |
| 838 | + target_phys_addr_t fbptr; | |
| 839 | + int miny, maxy; | |
| 840 | + int ch; | |
| 841 | + if (!(s->control[0] & LCCR0_ENB)) | |
| 842 | + return; | |
| 843 | + | |
| 844 | + pxa2xx_descriptor_load(s); | |
| 845 | + | |
| 846 | + pxa2xx_lcdc_resize(s); | |
| 847 | + miny = s->yres; | |
| 848 | + maxy = 0; | |
| 849 | + s->transp = s->dma_ch[2].up || s->dma_ch[3].up; | |
| 850 | + /* Note: With overlay planes the order depends on LCCR0 bit 25. */ | |
| 851 | + for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++) | |
| 852 | + if (s->dma_ch[ch].up) { | |
| 853 | + if (!s->dma_ch[ch].source) { | |
| 854 | + pxa2xx_dma_ber_set(s, ch); | |
| 855 | + continue; | |
| 856 | + } | |
| 857 | + fbptr = s->dma_ch[ch].source; | |
| 858 | + if (!(fbptr >= PXA2XX_RAM_BASE && | |
| 859 | + fbptr <= PXA2XX_RAM_BASE + phys_ram_size)) { | |
| 860 | + pxa2xx_dma_ber_set(s, ch); | |
| 861 | + continue; | |
| 862 | + } | |
| 863 | + fbptr -= PXA2XX_RAM_BASE; | |
| 864 | + fb = phys_ram_base + fbptr; | |
| 865 | + | |
| 866 | + if (s->dma_ch[ch].command & LDCMD_PAL) { | |
| 867 | + memcpy(s->dma_ch[ch].pbuffer, fb, | |
| 868 | + MAX(LDCMD_LENGTH(s->dma_ch[ch].command), | |
| 869 | + sizeof(s->dma_ch[ch].pbuffer))); | |
| 870 | + pxa2xx_palette_parse(s, ch, s->bpp); | |
| 871 | + } else { | |
| 872 | + /* Do we need to reparse palette */ | |
| 873 | + if (LCCR4_PALFOR(s->control[4]) != s->pal_for) | |
| 874 | + pxa2xx_palette_parse(s, ch, s->bpp); | |
| 875 | + | |
| 876 | + /* ACK frame start */ | |
| 877 | + pxa2xx_dma_sof_set(s, ch); | |
| 878 | + | |
| 879 | + s->dma_ch[ch].redraw(s, fb, &miny, &maxy); | |
| 880 | + s->invalidated = 0; | |
| 881 | + | |
| 882 | + /* ACK frame completed */ | |
| 883 | + pxa2xx_dma_eof_set(s, ch); | |
| 884 | + } | |
| 885 | + } | |
| 886 | + | |
| 887 | + if (s->control[0] & LCCR0_DIS) { | |
| 888 | + /* ACK last frame completed */ | |
| 889 | + s->control[0] &= ~LCCR0_ENB; | |
| 890 | + s->status[0] |= LCSR0_LDD; | |
| 891 | + } | |
| 892 | + | |
| 893 | + if (s->orientation) | |
| 894 | + dpy_update(s->ds, miny, 0, maxy, s->xres); | |
| 895 | + else | |
| 896 | + dpy_update(s->ds, 0, miny, s->xres, maxy); | |
| 897 | + pxa2xx_lcdc_int_update(s); | |
| 898 | + | |
| 899 | + if (s->vsync_cb) | |
| 900 | + s->vsync_cb(s->opaque); | |
| 901 | +} | |
| 902 | + | |
| 903 | +static void pxa2xx_invalidate_display(void *opaque) | |
| 904 | +{ | |
| 905 | + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; | |
| 906 | + s->invalidated = 1; | |
| 907 | +} | |
| 908 | + | |
| 909 | +static void pxa2xx_screen_dump(void *opaque, const char *filename) | |
| 910 | +{ | |
| 911 | + /* TODO */ | |
| 912 | +} | |
| 913 | + | |
| 914 | +void pxa2xx_lcdc_orientation(void *opaque, int angle) | |
| 915 | +{ | |
| 916 | + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; | |
| 917 | + | |
| 918 | + if (angle) { | |
| 919 | + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert; | |
| 920 | + } else { | |
| 921 | + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz; | |
| 922 | + } | |
| 923 | + | |
| 924 | + s->orientation = angle; | |
| 925 | + s->xres = s->yres = -1; | |
| 926 | + pxa2xx_lcdc_resize(s); | |
| 927 | +} | |
| 928 | + | |
| 929 | +#define BITS 8 | |
| 930 | +#include "pxa2xx_template.h" | |
| 931 | +#define BITS 15 | |
| 932 | +#include "pxa2xx_template.h" | |
| 933 | +#define BITS 16 | |
| 934 | +#include "pxa2xx_template.h" | |
| 935 | +#define BITS 24 | |
| 936 | +#include "pxa2xx_template.h" | |
| 937 | +#define BITS 32 | |
| 938 | +#include "pxa2xx_template.h" | |
| 939 | + | |
| 940 | +struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, | |
| 941 | + DisplayState *ds) | |
| 942 | +{ | |
| 943 | + int iomemtype; | |
| 944 | + struct pxa2xx_lcdc_s *s; | |
| 945 | + | |
| 946 | + s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s)); | |
| 947 | + s->base = base; | |
| 948 | + s->invalidated = 1; | |
| 949 | + s->irq = irq; | |
| 950 | + s->ds = ds; | |
| 951 | + | |
| 952 | + pxa2xx_lcdc_orientation(s, graphic_rotate); | |
| 953 | + | |
| 954 | + iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn, | |
| 955 | + pxa2xx_lcdc_writefn, s); | |
| 956 | + cpu_register_physical_memory(base, 0x000fffff, iomemtype); | |
| 957 | + | |
| 958 | + graphic_console_init(ds, pxa2xx_update_display, | |
| 959 | + pxa2xx_invalidate_display, pxa2xx_screen_dump, s); | |
| 960 | + | |
| 961 | + switch (s->ds->depth) { | |
| 962 | + case 0: | |
| 963 | + s->dest_width = 0; | |
| 964 | + break; | |
| 965 | + case 8: | |
| 966 | + s->line_fn[0] = pxa2xx_draw_fn_8; | |
| 967 | + s->line_fn[1] = pxa2xx_draw_fn_8t; | |
| 968 | + s->dest_width = 1; | |
| 969 | + break; | |
| 970 | + case 15: | |
| 971 | + s->line_fn[0] = pxa2xx_draw_fn_15; | |
| 972 | + s->line_fn[1] = pxa2xx_draw_fn_15t; | |
| 973 | + s->dest_width = 2; | |
| 974 | + break; | |
| 975 | + case 16: | |
| 976 | + s->line_fn[0] = pxa2xx_draw_fn_16; | |
| 977 | + s->line_fn[1] = pxa2xx_draw_fn_16t; | |
| 978 | + s->dest_width = 2; | |
| 979 | + break; | |
| 980 | + case 24: | |
| 981 | + s->line_fn[0] = pxa2xx_draw_fn_24; | |
| 982 | + s->line_fn[1] = pxa2xx_draw_fn_24t; | |
| 983 | + s->dest_width = 3; | |
| 984 | + break; | |
| 985 | + case 32: | |
| 986 | + s->line_fn[0] = pxa2xx_draw_fn_32; | |
| 987 | + s->line_fn[1] = pxa2xx_draw_fn_32t; | |
| 988 | + s->dest_width = 4; | |
| 989 | + break; | |
| 990 | + default: | |
| 991 | + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); | |
| 992 | + exit(1); | |
| 993 | + } | |
| 994 | + return s; | |
| 995 | +} | |
| 996 | + | |
| 997 | +void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, | |
| 998 | + void (*cb)(void *opaque), void *opaque) { | |
| 999 | + s->vsync_cb = cb; | |
| 1000 | + s->opaque = opaque; | |
| 1001 | +} | ... | ... |
hw/pxa2xx_mmci.c
0 โ 100644
| 1 | +/* | |
| 2 | + * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | |
| 5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | |
| 6 | + * | |
| 7 | + * This code is licensed under the GPLv2. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include "vl.h" | |
| 11 | +#include "sd.h" | |
| 12 | + | |
| 13 | +struct pxa2xx_mmci_s { | |
| 14 | + target_phys_addr_t base; | |
| 15 | + qemu_irq irq; | |
| 16 | + void *dma; | |
| 17 | + | |
| 18 | + SDState *card; | |
| 19 | + | |
| 20 | + uint32_t status; | |
| 21 | + uint32_t clkrt; | |
| 22 | + uint32_t spi; | |
| 23 | + uint32_t cmdat; | |
| 24 | + uint32_t resp_tout; | |
| 25 | + uint32_t read_tout; | |
| 26 | + int blklen; | |
| 27 | + int numblk; | |
| 28 | + uint32_t intmask; | |
| 29 | + uint32_t intreq; | |
| 30 | + int cmd; | |
| 31 | + uint32_t arg; | |
| 32 | + | |
| 33 | + int active; | |
| 34 | + int bytesleft; | |
| 35 | + uint8_t tx_fifo[64]; | |
| 36 | + int tx_start; | |
| 37 | + int tx_len; | |
| 38 | + uint8_t rx_fifo[32]; | |
| 39 | + int rx_start; | |
| 40 | + int rx_len; | |
| 41 | + uint16_t resp_fifo[9]; | |
| 42 | + int resp_len; | |
| 43 | + | |
| 44 | + int cmdreq; | |
| 45 | + int ac_width; | |
| 46 | +}; | |
| 47 | + | |
| 48 | +#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ | |
| 49 | +#define MMC_STAT 0x04 /* MMC Status register */ | |
| 50 | +#define MMC_CLKRT 0x08 /* MMC Clock Rate register */ | |
| 51 | +#define MMC_SPI 0x0c /* MMC SPI Mode register */ | |
| 52 | +#define MMC_CMDAT 0x10 /* MMC Command/Data register */ | |
| 53 | +#define MMC_RESTO 0x14 /* MMC Response Time-Out register */ | |
| 54 | +#define MMC_RDTO 0x18 /* MMC Read Time-Out register */ | |
| 55 | +#define MMC_BLKLEN 0x1c /* MMC Block Length register */ | |
| 56 | +#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */ | |
| 57 | +#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */ | |
| 58 | +#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */ | |
| 59 | +#define MMC_I_REG 0x2c /* MMC Interrupt Request register */ | |
| 60 | +#define MMC_CMD 0x30 /* MMC Command register */ | |
| 61 | +#define MMC_ARGH 0x34 /* MMC Argument High register */ | |
| 62 | +#define MMC_ARGL 0x38 /* MMC Argument Low register */ | |
| 63 | +#define MMC_RES 0x3c /* MMC Response FIFO */ | |
| 64 | +#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */ | |
| 65 | +#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */ | |
| 66 | +#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */ | |
| 67 | +#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */ | |
| 68 | + | |
| 69 | +/* Bitfield masks */ | |
| 70 | +#define STRPCL_STOP_CLK (1 << 0) | |
| 71 | +#define STRPCL_STRT_CLK (1 << 1) | |
| 72 | +#define STAT_TOUT_RES (1 << 1) | |
| 73 | +#define STAT_CLK_EN (1 << 8) | |
| 74 | +#define STAT_DATA_DONE (1 << 11) | |
| 75 | +#define STAT_PRG_DONE (1 << 12) | |
| 76 | +#define STAT_END_CMDRES (1 << 13) | |
| 77 | +#define SPI_SPI_MODE (1 << 0) | |
| 78 | +#define CMDAT_RES_TYPE (3 << 0) | |
| 79 | +#define CMDAT_DATA_EN (1 << 2) | |
| 80 | +#define CMDAT_WR_RD (1 << 3) | |
| 81 | +#define CMDAT_DMA_EN (1 << 7) | |
| 82 | +#define CMDAT_STOP_TRAN (1 << 10) | |
| 83 | +#define INT_DATA_DONE (1 << 0) | |
| 84 | +#define INT_PRG_DONE (1 << 1) | |
| 85 | +#define INT_END_CMD (1 << 2) | |
| 86 | +#define INT_STOP_CMD (1 << 3) | |
| 87 | +#define INT_CLK_OFF (1 << 4) | |
| 88 | +#define INT_RXFIFO_REQ (1 << 5) | |
| 89 | +#define INT_TXFIFO_REQ (1 << 6) | |
| 90 | +#define INT_TINT (1 << 7) | |
| 91 | +#define INT_DAT_ERR (1 << 8) | |
| 92 | +#define INT_RES_ERR (1 << 9) | |
| 93 | +#define INT_RD_STALLED (1 << 10) | |
| 94 | +#define INT_SDIO_INT (1 << 11) | |
| 95 | +#define INT_SDIO_SACK (1 << 12) | |
| 96 | +#define PRTBUF_PRT_BUF (1 << 0) | |
| 97 | + | |
| 98 | +/* Route internal interrupt lines to the global IC and DMA */ | |
| 99 | +static void pxa2xx_mmci_int_update(struct pxa2xx_mmci_s *s) | |
| 100 | +{ | |
| 101 | + uint32_t mask = s->intmask; | |
| 102 | + if (s->cmdat & CMDAT_DMA_EN) { | |
| 103 | + mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ; | |
| 104 | + | |
| 105 | + pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, | |
| 106 | + PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ)); | |
| 107 | + pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, | |
| 108 | + PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ)); | |
| 109 | + } | |
| 110 | + | |
| 111 | + qemu_set_irq(s->irq, !!(s->intreq & ~mask)); | |
| 112 | +} | |
| 113 | + | |
| 114 | +static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s) | |
| 115 | +{ | |
| 116 | + if (!s->active) | |
| 117 | + return; | |
| 118 | + | |
| 119 | + if (s->cmdat & CMDAT_WR_RD) { | |
| 120 | + while (s->bytesleft && s->tx_len) { | |
| 121 | + sd_write_data(s->card, s->tx_fifo[s->tx_start ++]); | |
| 122 | + s->tx_start &= 0x1f; | |
| 123 | + s->tx_len --; | |
| 124 | + s->bytesleft --; | |
| 125 | + } | |
| 126 | + if (s->bytesleft) | |
| 127 | + s->intreq |= INT_TXFIFO_REQ; | |
| 128 | + } else | |
| 129 | + while (s->bytesleft && s->rx_len < 32) { | |
| 130 | + s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] = | |
| 131 | + sd_read_data(s->card); | |
| 132 | + s->bytesleft --; | |
| 133 | + s->intreq |= INT_RXFIFO_REQ; | |
| 134 | + } | |
| 135 | + | |
| 136 | + if (!s->bytesleft) { | |
| 137 | + s->active = 0; | |
| 138 | + s->intreq |= INT_DATA_DONE; | |
| 139 | + s->status |= STAT_DATA_DONE; | |
| 140 | + | |
| 141 | + if (s->cmdat & CMDAT_WR_RD) { | |
| 142 | + s->intreq |= INT_PRG_DONE; | |
| 143 | + s->status |= STAT_PRG_DONE; | |
| 144 | + } | |
| 145 | + } | |
| 146 | + | |
| 147 | + pxa2xx_mmci_int_update(s); | |
| 148 | +} | |
| 149 | + | |
| 150 | +static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s) | |
| 151 | +{ | |
| 152 | + int rsplen, i; | |
| 153 | + struct sd_request_s request; | |
| 154 | + uint8_t response[16]; | |
| 155 | + | |
| 156 | + s->active = 1; | |
| 157 | + s->rx_len = 0; | |
| 158 | + s->tx_len = 0; | |
| 159 | + s->cmdreq = 0; | |
| 160 | + | |
| 161 | + request.cmd = s->cmd; | |
| 162 | + request.arg = s->arg; | |
| 163 | + request.crc = 0; /* FIXME */ | |
| 164 | + | |
| 165 | + rsplen = sd_do_command(s->card, &request, response); | |
| 166 | + s->intreq |= INT_END_CMD; | |
| 167 | + | |
| 168 | + memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); | |
| 169 | + switch (s->cmdat & CMDAT_RES_TYPE) { | |
| 170 | +#define PXAMMCI_RESP(wd, value0, value1) \ | |
| 171 | + s->resp_fifo[(wd) + 0] |= (value0); \ | |
| 172 | + s->resp_fifo[(wd) + 1] |= (value1) << 8; | |
| 173 | + case 0: /* No response */ | |
| 174 | + goto complete; | |
| 175 | + | |
| 176 | + case 1: /* R1, R4, R5 or R6 */ | |
| 177 | + if (rsplen < 4) | |
| 178 | + goto timeout; | |
| 179 | + goto complete; | |
| 180 | + | |
| 181 | + case 2: /* R2 */ | |
| 182 | + if (rsplen < 16) | |
| 183 | + goto timeout; | |
| 184 | + goto complete; | |
| 185 | + | |
| 186 | + case 3: /* R3 */ | |
| 187 | + if (rsplen < 4) | |
| 188 | + goto timeout; | |
| 189 | + goto complete; | |
| 190 | + | |
| 191 | + complete: | |
| 192 | + for (i = 0; rsplen > 0; i ++, rsplen -= 2) { | |
| 193 | + PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]); | |
| 194 | + } | |
| 195 | + s->status |= STAT_END_CMDRES; | |
| 196 | + | |
| 197 | + if (!(s->cmdat & CMDAT_DATA_EN)) | |
| 198 | + s->active = 0; | |
| 199 | + else | |
| 200 | + s->bytesleft = s->numblk * s->blklen; | |
| 201 | + | |
| 202 | + s->resp_len = 0; | |
| 203 | + break; | |
| 204 | + | |
| 205 | + timeout: | |
| 206 | + s->active = 0; | |
| 207 | + s->status |= STAT_TOUT_RES; | |
| 208 | + break; | |
| 209 | + } | |
| 210 | + | |
| 211 | + pxa2xx_mmci_fifo_update(s); | |
| 212 | +} | |
| 213 | + | |
| 214 | +static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) | |
| 215 | +{ | |
| 216 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 217 | + uint32_t ret; | |
| 218 | + offset -= s->base; | |
| 219 | + | |
| 220 | + switch (offset) { | |
| 221 | + case MMC_STRPCL: | |
| 222 | + return 0; | |
| 223 | + case MMC_STAT: | |
| 224 | + return s->status; | |
| 225 | + case MMC_CLKRT: | |
| 226 | + return s->clkrt; | |
| 227 | + case MMC_SPI: | |
| 228 | + return s->spi; | |
| 229 | + case MMC_CMDAT: | |
| 230 | + return s->cmdat; | |
| 231 | + case MMC_RESTO: | |
| 232 | + return s->resp_tout; | |
| 233 | + case MMC_RDTO: | |
| 234 | + return s->read_tout; | |
| 235 | + case MMC_BLKLEN: | |
| 236 | + return s->blklen; | |
| 237 | + case MMC_NUMBLK: | |
| 238 | + return s->numblk; | |
| 239 | + case MMC_PRTBUF: | |
| 240 | + return 0; | |
| 241 | + case MMC_I_MASK: | |
| 242 | + return s->intmask; | |
| 243 | + case MMC_I_REG: | |
| 244 | + return s->intreq; | |
| 245 | + case MMC_CMD: | |
| 246 | + return s->cmd | 0x40; | |
| 247 | + case MMC_ARGH: | |
| 248 | + return s->arg >> 16; | |
| 249 | + case MMC_ARGL: | |
| 250 | + return s->arg & 0xffff; | |
| 251 | + case MMC_RES: | |
| 252 | + if (s->resp_len < 9) | |
| 253 | + return s->resp_fifo[s->resp_len ++]; | |
| 254 | + return 0; | |
| 255 | + case MMC_RXFIFO: | |
| 256 | + ret = 0; | |
| 257 | + while (s->ac_width -- && s->rx_len) { | |
| 258 | + ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3); | |
| 259 | + s->rx_start &= 0x1f; | |
| 260 | + s->rx_len --; | |
| 261 | + } | |
| 262 | + s->intreq &= ~INT_RXFIFO_REQ; | |
| 263 | + pxa2xx_mmci_fifo_update(s); | |
| 264 | + return ret; | |
| 265 | + case MMC_RDWAIT: | |
| 266 | + return 0; | |
| 267 | + case MMC_BLKS_REM: | |
| 268 | + return s->numblk; | |
| 269 | + default: | |
| 270 | + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", | |
| 271 | + __FUNCTION__, offset); | |
| 272 | + } | |
| 273 | + | |
| 274 | + return 0; | |
| 275 | +} | |
| 276 | + | |
| 277 | +static void pxa2xx_mmci_write(void *opaque, | |
| 278 | + target_phys_addr_t offset, uint32_t value) | |
| 279 | +{ | |
| 280 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 281 | + offset -= s->base; | |
| 282 | + | |
| 283 | + switch (offset) { | |
| 284 | + case MMC_STRPCL: | |
| 285 | + if (value & STRPCL_STRT_CLK) { | |
| 286 | + s->status |= STAT_CLK_EN; | |
| 287 | + s->intreq &= ~INT_CLK_OFF; | |
| 288 | + | |
| 289 | + if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) { | |
| 290 | + s->status &= STAT_CLK_EN; | |
| 291 | + pxa2xx_mmci_wakequeues(s); | |
| 292 | + } | |
| 293 | + } | |
| 294 | + | |
| 295 | + if (value & STRPCL_STOP_CLK) { | |
| 296 | + s->status &= ~STAT_CLK_EN; | |
| 297 | + s->intreq |= INT_CLK_OFF; | |
| 298 | + s->active = 0; | |
| 299 | + } | |
| 300 | + | |
| 301 | + pxa2xx_mmci_int_update(s); | |
| 302 | + break; | |
| 303 | + | |
| 304 | + case MMC_CLKRT: | |
| 305 | + s->clkrt = value & 7; | |
| 306 | + break; | |
| 307 | + | |
| 308 | + case MMC_SPI: | |
| 309 | + s->spi = value & 0xf; | |
| 310 | + if (value & SPI_SPI_MODE) | |
| 311 | + printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); | |
| 312 | + break; | |
| 313 | + | |
| 314 | + case MMC_CMDAT: | |
| 315 | + s->cmdat = value & 0x3dff; | |
| 316 | + s->active = 0; | |
| 317 | + s->cmdreq = 1; | |
| 318 | + if (!(value & CMDAT_STOP_TRAN)) { | |
| 319 | + s->status &= STAT_CLK_EN; | |
| 320 | + | |
| 321 | + if (s->status & STAT_CLK_EN) | |
| 322 | + pxa2xx_mmci_wakequeues(s); | |
| 323 | + } | |
| 324 | + | |
| 325 | + pxa2xx_mmci_int_update(s); | |
| 326 | + break; | |
| 327 | + | |
| 328 | + case MMC_RESTO: | |
| 329 | + s->resp_tout = value & 0x7f; | |
| 330 | + break; | |
| 331 | + | |
| 332 | + case MMC_RDTO: | |
| 333 | + s->read_tout = value & 0xffff; | |
| 334 | + break; | |
| 335 | + | |
| 336 | + case MMC_BLKLEN: | |
| 337 | + s->blklen = value & 0xfff; | |
| 338 | + break; | |
| 339 | + | |
| 340 | + case MMC_NUMBLK: | |
| 341 | + s->numblk = value & 0xffff; | |
| 342 | + break; | |
| 343 | + | |
| 344 | + case MMC_PRTBUF: | |
| 345 | + if (value & PRTBUF_PRT_BUF) { | |
| 346 | + s->tx_start ^= 32; | |
| 347 | + s->tx_len = 0; | |
| 348 | + } | |
| 349 | + pxa2xx_mmci_fifo_update(s); | |
| 350 | + break; | |
| 351 | + | |
| 352 | + case MMC_I_MASK: | |
| 353 | + s->intmask = value & 0x1fff; | |
| 354 | + pxa2xx_mmci_int_update(s); | |
| 355 | + break; | |
| 356 | + | |
| 357 | + case MMC_CMD: | |
| 358 | + s->cmd = value & 0x3f; | |
| 359 | + break; | |
| 360 | + | |
| 361 | + case MMC_ARGH: | |
| 362 | + s->arg &= 0x0000ffff; | |
| 363 | + s->arg |= value << 16; | |
| 364 | + break; | |
| 365 | + | |
| 366 | + case MMC_ARGL: | |
| 367 | + s->arg &= 0xffff0000; | |
| 368 | + s->arg |= value & 0x0000ffff; | |
| 369 | + break; | |
| 370 | + | |
| 371 | + case MMC_TXFIFO: | |
| 372 | + while (s->ac_width -- && s->tx_len < 0x20) | |
| 373 | + s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = | |
| 374 | + (value >> (s->ac_width << 3)) & 0xff; | |
| 375 | + s->intreq &= ~INT_TXFIFO_REQ; | |
| 376 | + pxa2xx_mmci_fifo_update(s); | |
| 377 | + break; | |
| 378 | + | |
| 379 | + case MMC_RDWAIT: | |
| 380 | + case MMC_BLKS_REM: | |
| 381 | + break; | |
| 382 | + | |
| 383 | + default: | |
| 384 | + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", | |
| 385 | + __FUNCTION__, offset); | |
| 386 | + } | |
| 387 | +} | |
| 388 | + | |
| 389 | +static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset) | |
| 390 | +{ | |
| 391 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 392 | + s->ac_width = 1; | |
| 393 | + return pxa2xx_mmci_read(opaque, offset); | |
| 394 | +} | |
| 395 | + | |
| 396 | +static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset) | |
| 397 | +{ | |
| 398 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 399 | + s->ac_width = 2; | |
| 400 | + return pxa2xx_mmci_read(opaque, offset); | |
| 401 | +} | |
| 402 | + | |
| 403 | +static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) | |
| 404 | +{ | |
| 405 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 406 | + s->ac_width = 4; | |
| 407 | + return pxa2xx_mmci_read(opaque, offset); | |
| 408 | +} | |
| 409 | + | |
| 410 | +static CPUReadMemoryFunc *pxa2xx_mmci_readfn[] = { | |
| 411 | + pxa2xx_mmci_readb, | |
| 412 | + pxa2xx_mmci_readh, | |
| 413 | + pxa2xx_mmci_readw | |
| 414 | +}; | |
| 415 | + | |
| 416 | +static void pxa2xx_mmci_writeb(void *opaque, | |
| 417 | + target_phys_addr_t offset, uint32_t value) | |
| 418 | +{ | |
| 419 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 420 | + s->ac_width = 1; | |
| 421 | + pxa2xx_mmci_write(opaque, offset, value); | |
| 422 | +} | |
| 423 | + | |
| 424 | +static void pxa2xx_mmci_writeh(void *opaque, | |
| 425 | + target_phys_addr_t offset, uint32_t value) | |
| 426 | +{ | |
| 427 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 428 | + s->ac_width = 2; | |
| 429 | + pxa2xx_mmci_write(opaque, offset, value); | |
| 430 | +} | |
| 431 | + | |
| 432 | +static void pxa2xx_mmci_writew(void *opaque, | |
| 433 | + target_phys_addr_t offset, uint32_t value) | |
| 434 | +{ | |
| 435 | + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; | |
| 436 | + s->ac_width = 4; | |
| 437 | + pxa2xx_mmci_write(opaque, offset, value); | |
| 438 | +} | |
| 439 | + | |
| 440 | +static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = { | |
| 441 | + pxa2xx_mmci_writeb, | |
| 442 | + pxa2xx_mmci_writeh, | |
| 443 | + pxa2xx_mmci_writew | |
| 444 | +}; | |
| 445 | + | |
| 446 | +struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, | |
| 447 | + qemu_irq irq, void *dma) | |
| 448 | +{ | |
| 449 | + int iomemtype; | |
| 450 | + struct pxa2xx_mmci_s *s; | |
| 451 | + | |
| 452 | + s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s)); | |
| 453 | + s->base = base; | |
| 454 | + s->irq = irq; | |
| 455 | + s->dma = dma; | |
| 456 | + | |
| 457 | + iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn, | |
| 458 | + pxa2xx_mmci_writefn, s); | |
| 459 | + cpu_register_physical_memory(base, 0x000fffff, iomemtype); | |
| 460 | + | |
| 461 | + /* Instantiate the actual storage */ | |
| 462 | + s->card = sd_init(sd_bdrv); | |
| 463 | + | |
| 464 | + return s; | |
| 465 | +} | |
| 466 | + | |
| 467 | +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, | |
| 468 | + void (*readonly_cb)(void *, int), | |
| 469 | + void (*coverswitch_cb)(void *, int)) | |
| 470 | +{ | |
| 471 | + sd_set_cb(s->card, opaque, readonly_cb, coverswitch_cb); | |
| 472 | +} | ... | ... |
hw/pxa2xx_pcmcia.c
0 โ 100644
| 1 | +/* | |
| 2 | + * Intel XScale PXA255/270 PC Card and CompactFlash Interface. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | |
| 5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | |
| 6 | + * | |
| 7 | + * This code is licensed under the GPLv2. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include "vl.h" | |
| 11 | + | |
| 12 | +struct pxa2xx_pcmcia_s { | |
| 13 | + struct pcmcia_socket_s slot; | |
| 14 | + struct pcmcia_card_s *card; | |
| 15 | + target_phys_addr_t common_base; | |
| 16 | + target_phys_addr_t attr_base; | |
| 17 | + target_phys_addr_t io_base; | |
| 18 | + | |
| 19 | + qemu_irq irq; | |
| 20 | + qemu_irq cd_irq; | |
| 21 | +}; | |
| 22 | + | |
| 23 | +static uint32_t pxa2xx_pcmcia_common_read(void *opaque, | |
| 24 | + target_phys_addr_t offset) | |
| 25 | +{ | |
| 26 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 27 | + | |
| 28 | + if (s->slot.attached) { | |
| 29 | + offset -= s->common_base; | |
| 30 | + return s->card->common_read(s->card->state, offset); | |
| 31 | + } | |
| 32 | + | |
| 33 | + return 0; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static void pxa2xx_pcmcia_common_write(void *opaque, | |
| 37 | + target_phys_addr_t offset, uint32_t value) | |
| 38 | +{ | |
| 39 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 40 | + | |
| 41 | + if (s->slot.attached) { | |
| 42 | + offset -= s->common_base; | |
| 43 | + s->card->common_write(s->card->state, offset, value); | |
| 44 | + } | |
| 45 | +} | |
| 46 | + | |
| 47 | +static uint32_t pxa2xx_pcmcia_attr_read(void *opaque, | |
| 48 | + target_phys_addr_t offset) | |
| 49 | +{ | |
| 50 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 51 | + | |
| 52 | + if (s->slot.attached) { | |
| 53 | + offset -= s->attr_base; | |
| 54 | + return s->card->attr_read(s->card->state, offset); | |
| 55 | + } | |
| 56 | + | |
| 57 | + return 0; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static void pxa2xx_pcmcia_attr_write(void *opaque, | |
| 61 | + target_phys_addr_t offset, uint32_t value) | |
| 62 | +{ | |
| 63 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 64 | + | |
| 65 | + if (s->slot.attached) { | |
| 66 | + offset -= s->attr_base; | |
| 67 | + s->card->attr_write(s->card->state, offset, value); | |
| 68 | + } | |
| 69 | +} | |
| 70 | + | |
| 71 | +static uint32_t pxa2xx_pcmcia_io_read(void *opaque, | |
| 72 | + target_phys_addr_t offset) | |
| 73 | +{ | |
| 74 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 75 | + | |
| 76 | + if (s->slot.attached) { | |
| 77 | + offset -= s->io_base; | |
| 78 | + return s->card->io_read(s->card->state, offset); | |
| 79 | + } | |
| 80 | + | |
| 81 | + return 0; | |
| 82 | +} | |
| 83 | + | |
| 84 | +static void pxa2xx_pcmcia_io_write(void *opaque, | |
| 85 | + target_phys_addr_t offset, uint32_t value) | |
| 86 | +{ | |
| 87 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 88 | + | |
| 89 | + if (s->slot.attached) { | |
| 90 | + offset -= s->io_base; | |
| 91 | + s->card->io_write(s->card->state, offset, value); | |
| 92 | + } | |
| 93 | +} | |
| 94 | + | |
| 95 | +static CPUReadMemoryFunc *pxa2xx_pcmcia_common_readfn[] = { | |
| 96 | + pxa2xx_pcmcia_common_read, | |
| 97 | + pxa2xx_pcmcia_common_read, | |
| 98 | + pxa2xx_pcmcia_common_read, | |
| 99 | +}; | |
| 100 | + | |
| 101 | +static CPUWriteMemoryFunc *pxa2xx_pcmcia_common_writefn[] = { | |
| 102 | + pxa2xx_pcmcia_common_write, | |
| 103 | + pxa2xx_pcmcia_common_write, | |
| 104 | + pxa2xx_pcmcia_common_write, | |
| 105 | +}; | |
| 106 | + | |
| 107 | +static CPUReadMemoryFunc *pxa2xx_pcmcia_attr_readfn[] = { | |
| 108 | + pxa2xx_pcmcia_attr_read, | |
| 109 | + pxa2xx_pcmcia_attr_read, | |
| 110 | + pxa2xx_pcmcia_attr_read, | |
| 111 | +}; | |
| 112 | + | |
| 113 | +static CPUWriteMemoryFunc *pxa2xx_pcmcia_attr_writefn[] = { | |
| 114 | + pxa2xx_pcmcia_attr_write, | |
| 115 | + pxa2xx_pcmcia_attr_write, | |
| 116 | + pxa2xx_pcmcia_attr_write, | |
| 117 | +}; | |
| 118 | + | |
| 119 | +static CPUReadMemoryFunc *pxa2xx_pcmcia_io_readfn[] = { | |
| 120 | + pxa2xx_pcmcia_io_read, | |
| 121 | + pxa2xx_pcmcia_io_read, | |
| 122 | + pxa2xx_pcmcia_io_read, | |
| 123 | +}; | |
| 124 | + | |
| 125 | +static CPUWriteMemoryFunc *pxa2xx_pcmcia_io_writefn[] = { | |
| 126 | + pxa2xx_pcmcia_io_write, | |
| 127 | + pxa2xx_pcmcia_io_write, | |
| 128 | + pxa2xx_pcmcia_io_write, | |
| 129 | +}; | |
| 130 | + | |
| 131 | +static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) | |
| 132 | +{ | |
| 133 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 134 | + if (!s->irq) | |
| 135 | + return; | |
| 136 | + | |
| 137 | + qemu_set_irq(s->irq, level); | |
| 138 | +} | |
| 139 | + | |
| 140 | +struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base) | |
| 141 | +{ | |
| 142 | + int iomemtype; | |
| 143 | + struct pxa2xx_pcmcia_s *s; | |
| 144 | + | |
| 145 | + s = (struct pxa2xx_pcmcia_s *) | |
| 146 | + qemu_mallocz(sizeof(struct pxa2xx_pcmcia_s)); | |
| 147 | + | |
| 148 | + /* Socket I/O Memory Space */ | |
| 149 | + s->io_base = base | 0x00000000; | |
| 150 | + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn, | |
| 151 | + pxa2xx_pcmcia_io_writefn, s); | |
| 152 | + cpu_register_physical_memory(s->io_base, 0x03ffffff, iomemtype); | |
| 153 | + | |
| 154 | + /* Then next 64 MB is reserved */ | |
| 155 | + | |
| 156 | + /* Socket Attribute Memory Space */ | |
| 157 | + s->attr_base = base | 0x08000000; | |
| 158 | + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn, | |
| 159 | + pxa2xx_pcmcia_attr_writefn, s); | |
| 160 | + cpu_register_physical_memory(s->attr_base, 0x03ffffff, iomemtype); | |
| 161 | + | |
| 162 | + /* Socket Common Memory Space */ | |
| 163 | + s->common_base = base | 0x0c000000; | |
| 164 | + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn, | |
| 165 | + pxa2xx_pcmcia_common_writefn, s); | |
| 166 | + cpu_register_physical_memory(s->common_base, 0x03ffffff, iomemtype); | |
| 167 | + | |
| 168 | + if (base == 0x30000000) | |
| 169 | + s->slot.slot_string = "PXA PC Card Socket 1"; | |
| 170 | + else | |
| 171 | + s->slot.slot_string = "PXA PC Card Socket 0"; | |
| 172 | + s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; | |
| 173 | + pcmcia_socket_register(&s->slot); | |
| 174 | + return s; | |
| 175 | +} | |
| 176 | + | |
| 177 | +/* Insert a new card into a slot */ | |
| 178 | +int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card) | |
| 179 | +{ | |
| 180 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 181 | + if (s->slot.attached) | |
| 182 | + return -EEXIST; | |
| 183 | + | |
| 184 | + if (s->cd_irq) { | |
| 185 | + qemu_irq_raise(s->cd_irq); | |
| 186 | + } | |
| 187 | + | |
| 188 | + s->card = card; | |
| 189 | + | |
| 190 | + s->slot.attached = 1; | |
| 191 | + s->card->slot = &s->slot; | |
| 192 | + s->card->attach(s->card->state); | |
| 193 | + | |
| 194 | + return 0; | |
| 195 | +} | |
| 196 | + | |
| 197 | +/* Eject card from the slot */ | |
| 198 | +int pxa2xx_pcmcia_dettach(void *opaque) | |
| 199 | +{ | |
| 200 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 201 | + if (!s->slot.attached) | |
| 202 | + return -ENOENT; | |
| 203 | + | |
| 204 | + s->card->detach(s->card->state); | |
| 205 | + s->card->slot = 0; | |
| 206 | + s->card = 0; | |
| 207 | + | |
| 208 | + s->slot.attached = 0; | |
| 209 | + | |
| 210 | + if (s->irq) | |
| 211 | + qemu_irq_lower(s->irq); | |
| 212 | + if (s->cd_irq) | |
| 213 | + qemu_irq_lower(s->cd_irq); | |
| 214 | + | |
| 215 | + return 0; | |
| 216 | +} | |
| 217 | + | |
| 218 | +/* Who to notify on card events */ | |
| 219 | +void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq) | |
| 220 | +{ | |
| 221 | + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; | |
| 222 | + s->irq = irq; | |
| 223 | + s->cd_irq = cd_irq; | |
| 224 | +} | ... | ... |
hw/pxa2xx_template.h
0 โ 100644
| 1 | +/* | |
| 2 | + * Intel XScale PXA255/270 LCDC emulation. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | |
| 5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | |
| 6 | + * | |
| 7 | + * This code is licensed under the GPLv2. | |
| 8 | + * | |
| 9 | + * Framebuffer format conversion routines. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +# define SKIP_PIXEL(to) to += deststep | |
| 13 | +#if BITS == 8 | |
| 14 | +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) | |
| 15 | +#elif BITS == 15 || BITS == 16 | |
| 16 | +# define COPY_PIXEL(to, from) *(uint16_t *) to = from; SKIP_PIXEL(to) | |
| 17 | +#elif BITS == 24 | |
| 18 | +# define COPY_PIXEL(to, from) \ | |
| 19 | + *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to) | |
| 20 | +#elif BITS == 32 | |
| 21 | +# define COPY_PIXEL(to, from) *(uint32_t *) to = from; SKIP_PIXEL(to) | |
| 22 | +#else | |
| 23 | +# error unknown bit depth | |
| 24 | +#endif | |
| 25 | + | |
| 26 | +#ifdef WORDS_BIGENDIAN | |
| 27 | +# define SWAP_WORDS 1 | |
| 28 | +#endif | |
| 29 | + | |
| 30 | +#define FN_2(x) FN(x + 1) FN(x) | |
| 31 | +#define FN_4(x) FN_2(x + 2) FN_2(x) | |
| 32 | + | |
| 33 | +static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette, | |
| 34 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 35 | +{ | |
| 36 | + uint32_t data; | |
| 37 | + while (width > 0) { | |
| 38 | + data = *(uint32_t *) src; | |
| 39 | +#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]); | |
| 40 | +#ifdef SWAP_WORDS | |
| 41 | + FN_4(12) | |
| 42 | + FN_4(8) | |
| 43 | + FN_4(4) | |
| 44 | + FN_4(0) | |
| 45 | +#else | |
| 46 | + FN_4(0) | |
| 47 | + FN_4(4) | |
| 48 | + FN_4(8) | |
| 49 | + FN_4(12) | |
| 50 | +#endif | |
| 51 | +#undef FN | |
| 52 | + width -= 16; | |
| 53 | + src += 4; | |
| 54 | + } | |
| 55 | +} | |
| 56 | + | |
| 57 | +static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette, | |
| 58 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 59 | +{ | |
| 60 | + uint32_t data; | |
| 61 | + while (width > 0) { | |
| 62 | + data = *(uint32_t *) src; | |
| 63 | +#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]); | |
| 64 | +#ifdef SWAP_WORDS | |
| 65 | + FN_2(6) | |
| 66 | + FN_2(4) | |
| 67 | + FN_2(2) | |
| 68 | + FN_2(0) | |
| 69 | +#else | |
| 70 | + FN_2(0) | |
| 71 | + FN_2(2) | |
| 72 | + FN_2(4) | |
| 73 | + FN_2(6) | |
| 74 | +#endif | |
| 75 | +#undef FN | |
| 76 | + width -= 8; | |
| 77 | + src += 4; | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette, | |
| 82 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 83 | +{ | |
| 84 | + uint32_t data; | |
| 85 | + while (width > 0) { | |
| 86 | + data = *(uint32_t *) src; | |
| 87 | +#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]); | |
| 88 | +#ifdef SWAP_WORDS | |
| 89 | + FN(24) | |
| 90 | + FN(16) | |
| 91 | + FN(8) | |
| 92 | + FN(0) | |
| 93 | +#else | |
| 94 | + FN(0) | |
| 95 | + FN(8) | |
| 96 | + FN(16) | |
| 97 | + FN(24) | |
| 98 | +#endif | |
| 99 | +#undef FN | |
| 100 | + width -= 4; | |
| 101 | + src += 4; | |
| 102 | + } | |
| 103 | +} | |
| 104 | + | |
| 105 | +static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette, | |
| 106 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 107 | +{ | |
| 108 | + uint32_t data; | |
| 109 | + unsigned int r, g, b; | |
| 110 | + while (width > 0) { | |
| 111 | + data = *(uint32_t *) src; | |
| 112 | +#ifdef SWAP_WORDS | |
| 113 | + data = bswap32(data); | |
| 114 | +#endif | |
| 115 | + b = (data & 0x1f) << 3; | |
| 116 | + data >>= 5; | |
| 117 | + g = (data & 0x3f) << 2; | |
| 118 | + data >>= 6; | |
| 119 | + r = (data & 0x1f) << 3; | |
| 120 | + data >>= 5; | |
| 121 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 122 | + b = (data & 0x1f) << 3; | |
| 123 | + data >>= 5; | |
| 124 | + g = (data & 0x3f) << 2; | |
| 125 | + data >>= 6; | |
| 126 | + r = (data & 0x1f) << 3; | |
| 127 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 128 | + width -= 2; | |
| 129 | + src += 4; | |
| 130 | + } | |
| 131 | +} | |
| 132 | + | |
| 133 | +static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette, | |
| 134 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 135 | +{ | |
| 136 | + uint32_t data; | |
| 137 | + unsigned int r, g, b; | |
| 138 | + while (width > 0) { | |
| 139 | + data = *(uint32_t *) src; | |
| 140 | +#ifdef SWAP_WORDS | |
| 141 | + data = bswap32(data); | |
| 142 | +#endif | |
| 143 | + b = (data & 0x1f) << 3; | |
| 144 | + data >>= 5; | |
| 145 | + g = (data & 0x1f) << 3; | |
| 146 | + data >>= 5; | |
| 147 | + r = (data & 0x1f) << 3; | |
| 148 | + data >>= 5; | |
| 149 | + if (data & 1) | |
| 150 | + SKIP_PIXEL(dest); | |
| 151 | + else | |
| 152 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 153 | + data >>= 1; | |
| 154 | + b = (data & 0x1f) << 3; | |
| 155 | + data >>= 5; | |
| 156 | + g = (data & 0x1f) << 3; | |
| 157 | + data >>= 5; | |
| 158 | + r = (data & 0x1f) << 3; | |
| 159 | + if (data & 1) | |
| 160 | + SKIP_PIXEL(dest); | |
| 161 | + else | |
| 162 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 163 | + width -= 2; | |
| 164 | + src += 4; | |
| 165 | + } | |
| 166 | +} | |
| 167 | + | |
| 168 | +static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette, | |
| 169 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 170 | +{ | |
| 171 | + uint32_t data; | |
| 172 | + unsigned int r, g, b; | |
| 173 | + while (width > 0) { | |
| 174 | + data = *(uint32_t *) src; | |
| 175 | +#ifdef SWAP_WORDS | |
| 176 | + data = bswap32(data); | |
| 177 | +#endif | |
| 178 | + b = (data & 0x3f) << 2; | |
| 179 | + data >>= 6; | |
| 180 | + g = (data & 0x3f) << 2; | |
| 181 | + data >>= 6; | |
| 182 | + r = (data & 0x3f) << 2; | |
| 183 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 184 | + width -= 1; | |
| 185 | + src += 4; | |
| 186 | + } | |
| 187 | +} | |
| 188 | + | |
| 189 | +/* The wicked packed format */ | |
| 190 | +static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette, | |
| 191 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 192 | +{ | |
| 193 | + uint32_t data[3]; | |
| 194 | + unsigned int r, g, b; | |
| 195 | + while (width > 0) { | |
| 196 | + data[0] = *(uint32_t *) src; | |
| 197 | + src += 4; | |
| 198 | + data[1] = *(uint32_t *) src; | |
| 199 | + src += 4; | |
| 200 | + data[2] = *(uint32_t *) src; | |
| 201 | + src += 4; | |
| 202 | +#ifdef SWAP_WORDS | |
| 203 | + data[0] = bswap32(data[0]); | |
| 204 | + data[1] = bswap32(data[1]); | |
| 205 | + data[2] = bswap32(data[2]); | |
| 206 | +#endif | |
| 207 | + b = (data[0] & 0x3f) << 2; | |
| 208 | + data[0] >>= 6; | |
| 209 | + g = (data[0] & 0x3f) << 2; | |
| 210 | + data[0] >>= 6; | |
| 211 | + r = (data[0] & 0x3f) << 2; | |
| 212 | + data[0] >>= 12; | |
| 213 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 214 | + b = (data[0] & 0x3f) << 2; | |
| 215 | + data[0] >>= 6; | |
| 216 | + g = ((data[1] & 0xf) << 4) | (data[0] << 2); | |
| 217 | + data[1] >>= 4; | |
| 218 | + r = (data[1] & 0x3f) << 2; | |
| 219 | + data[1] >>= 12; | |
| 220 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 221 | + b = (data[1] & 0x3f) << 2; | |
| 222 | + data[1] >>= 6; | |
| 223 | + g = (data[1] & 0x3f) << 2; | |
| 224 | + data[1] >>= 6; | |
| 225 | + r = ((data[2] & 0x3) << 6) | (data[1] << 2); | |
| 226 | + data[2] >>= 8; | |
| 227 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 228 | + b = (data[2] & 0x3f) << 2; | |
| 229 | + data[2] >>= 6; | |
| 230 | + g = (data[2] & 0x3f) << 2; | |
| 231 | + data[2] >>= 6; | |
| 232 | + r = data[2] << 2; | |
| 233 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 234 | + width -= 4; | |
| 235 | + } | |
| 236 | +} | |
| 237 | + | |
| 238 | +static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette, | |
| 239 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 240 | +{ | |
| 241 | + uint32_t data; | |
| 242 | + unsigned int r, g, b; | |
| 243 | + while (width > 0) { | |
| 244 | + data = *(uint32_t *) src; | |
| 245 | +#ifdef SWAP_WORDS | |
| 246 | + data = bswap32(data); | |
| 247 | +#endif | |
| 248 | + b = (data & 0x3f) << 2; | |
| 249 | + data >>= 6; | |
| 250 | + g = (data & 0x3f) << 2; | |
| 251 | + data >>= 6; | |
| 252 | + r = (data & 0x3f) << 2; | |
| 253 | + data >>= 6; | |
| 254 | + if (data & 1) | |
| 255 | + SKIP_PIXEL(dest); | |
| 256 | + else | |
| 257 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 258 | + width -= 1; | |
| 259 | + src += 4; | |
| 260 | + } | |
| 261 | +} | |
| 262 | + | |
| 263 | +/* The wicked packed format */ | |
| 264 | +static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette, | |
| 265 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 266 | +{ | |
| 267 | + uint32_t data[3]; | |
| 268 | + unsigned int r, g, b; | |
| 269 | + while (width > 0) { | |
| 270 | + data[0] = *(uint32_t *) src; | |
| 271 | + src += 4; | |
| 272 | + data[1] = *(uint32_t *) src; | |
| 273 | + src += 4; | |
| 274 | + data[2] = *(uint32_t *) src; | |
| 275 | + src += 4; | |
| 276 | +# ifdef SWAP_WORDS | |
| 277 | + data[0] = bswap32(data[0]); | |
| 278 | + data[1] = bswap32(data[1]); | |
| 279 | + data[2] = bswap32(data[2]); | |
| 280 | +# endif | |
| 281 | + b = (data[0] & 0x3f) << 2; | |
| 282 | + data[0] >>= 6; | |
| 283 | + g = (data[0] & 0x3f) << 2; | |
| 284 | + data[0] >>= 6; | |
| 285 | + r = (data[0] & 0x3f) << 2; | |
| 286 | + data[0] >>= 6; | |
| 287 | + if (data[0] & 1) | |
| 288 | + SKIP_PIXEL(dest); | |
| 289 | + else | |
| 290 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 291 | + data[0] >>= 6; | |
| 292 | + b = (data[0] & 0x3f) << 2; | |
| 293 | + data[0] >>= 6; | |
| 294 | + g = ((data[1] & 0xf) << 4) | (data[0] << 2); | |
| 295 | + data[1] >>= 4; | |
| 296 | + r = (data[1] & 0x3f) << 2; | |
| 297 | + data[1] >>= 6; | |
| 298 | + if (data[1] & 1) | |
| 299 | + SKIP_PIXEL(dest); | |
| 300 | + else | |
| 301 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 302 | + data[1] >>= 6; | |
| 303 | + b = (data[1] & 0x3f) << 2; | |
| 304 | + data[1] >>= 6; | |
| 305 | + g = (data[1] & 0x3f) << 2; | |
| 306 | + data[1] >>= 6; | |
| 307 | + r = ((data[2] & 0x3) << 6) | (data[1] << 2); | |
| 308 | + data[2] >>= 2; | |
| 309 | + if (data[2] & 1) | |
| 310 | + SKIP_PIXEL(dest); | |
| 311 | + else | |
| 312 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 313 | + data[2] >>= 6; | |
| 314 | + b = (data[2] & 0x3f) << 2; | |
| 315 | + data[2] >>= 6; | |
| 316 | + g = (data[2] & 0x3f) << 2; | |
| 317 | + data[2] >>= 6; | |
| 318 | + r = data[2] << 2; | |
| 319 | + data[2] >>= 6; | |
| 320 | + if (data[2] & 1) | |
| 321 | + SKIP_PIXEL(dest); | |
| 322 | + else | |
| 323 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 324 | + width -= 4; | |
| 325 | + } | |
| 326 | +} | |
| 327 | + | |
| 328 | +static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette, | |
| 329 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 330 | +{ | |
| 331 | + uint32_t data; | |
| 332 | + unsigned int r, g, b; | |
| 333 | + while (width > 0) { | |
| 334 | + data = *(uint32_t *) src; | |
| 335 | +#ifdef SWAP_WORDS | |
| 336 | + data = bswap32(data); | |
| 337 | +#endif | |
| 338 | + b = data & 0xff; | |
| 339 | + data >>= 8; | |
| 340 | + g = data & 0xff; | |
| 341 | + data >>= 8; | |
| 342 | + r = data & 0xff; | |
| 343 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 344 | + width -= 1; | |
| 345 | + src += 4; | |
| 346 | + } | |
| 347 | +} | |
| 348 | + | |
| 349 | +static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette, | |
| 350 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 351 | +{ | |
| 352 | + uint32_t data; | |
| 353 | + unsigned int r, g, b; | |
| 354 | + while (width > 0) { | |
| 355 | + data = *(uint32_t *) src; | |
| 356 | +#ifdef SWAP_WORDS | |
| 357 | + data = bswap32(data); | |
| 358 | +#endif | |
| 359 | + b = (data & 0x7f) << 1; | |
| 360 | + data >>= 7; | |
| 361 | + g = data & 0xff; | |
| 362 | + data >>= 8; | |
| 363 | + r = data & 0xff; | |
| 364 | + data >>= 8; | |
| 365 | + if (data & 1) | |
| 366 | + SKIP_PIXEL(dest); | |
| 367 | + else | |
| 368 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 369 | + width -= 1; | |
| 370 | + src += 4; | |
| 371 | + } | |
| 372 | +} | |
| 373 | + | |
| 374 | +static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette, | |
| 375 | + uint8_t *dest, const uint8_t *src, int width, int deststep) | |
| 376 | +{ | |
| 377 | + uint32_t data; | |
| 378 | + unsigned int r, g, b; | |
| 379 | + while (width > 0) { | |
| 380 | + data = *(uint32_t *) src; | |
| 381 | +#ifdef SWAP_WORDS | |
| 382 | + data = bswap32(data); | |
| 383 | +#endif | |
| 384 | + b = data & 0xff; | |
| 385 | + data >>= 8; | |
| 386 | + g = data & 0xff; | |
| 387 | + data >>= 8; | |
| 388 | + r = data & 0xff; | |
| 389 | + data >>= 8; | |
| 390 | + if (data & 1) | |
| 391 | + SKIP_PIXEL(dest); | |
| 392 | + else | |
| 393 | + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); | |
| 394 | + width -= 1; | |
| 395 | + src += 4; | |
| 396 | + } | |
| 397 | +} | |
| 398 | + | |
| 399 | +/* Overlay planes disabled, no transparency */ | |
| 400 | +static drawfn glue(pxa2xx_draw_fn_, BITS)[16] = | |
| 401 | +{ | |
| 402 | + [0 ... 0xf] = 0, | |
| 403 | + [pxa_lcdc_2bpp] = glue(pxa2xx_draw_line2_, BITS), | |
| 404 | + [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS), | |
| 405 | + [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS), | |
| 406 | + [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16_, BITS), | |
| 407 | + [pxa_lcdc_18bpp] = glue(pxa2xx_draw_line18_, BITS), | |
| 408 | + [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS), | |
| 409 | + [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24_, BITS), | |
| 410 | +}; | |
| 411 | + | |
| 412 | +/* Overlay planes enabled, transparency used */ | |
| 413 | +static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] = | |
| 414 | +{ | |
| 415 | + [0 ... 0xf] = 0, | |
| 416 | + [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS), | |
| 417 | + [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS), | |
| 418 | + [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16t_, BITS), | |
| 419 | + [pxa_lcdc_19bpp] = glue(pxa2xx_draw_line19_, BITS), | |
| 420 | + [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS), | |
| 421 | + [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24t_, BITS), | |
| 422 | + [pxa_lcdc_25bpp] = glue(pxa2xx_draw_line25_, BITS), | |
| 423 | +}; | |
| 424 | + | |
| 425 | +#undef BITS | |
| 426 | +#undef COPY_PIXEL | |
| 427 | +#undef SKIP_PIXEL | |
| 428 | + | |
| 429 | +#ifdef SWAP_WORDS | |
| 430 | +# undef SWAP_WORDS | |
| 431 | +#endif | ... | ... |
hw/pxa2xx_timer.c
0 โ 100644
| 1 | +/* | |
| 2 | + * Intel XScale PXA255/270 OS Timers. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | |
| 5 | + * Copyright (c) 2006 Thorsten Zitterell | |
| 6 | + * | |
| 7 | + * This code is licenced under the GPL. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include "vl.h" | |
| 11 | + | |
| 12 | +#define OSMR0 0x00 | |
| 13 | +#define OSMR1 0x04 | |
| 14 | +#define OSMR2 0x08 | |
| 15 | +#define OSMR3 0x0c | |
| 16 | +#define OSMR4 0x80 | |
| 17 | +#define OSMR5 0x84 | |
| 18 | +#define OSMR6 0x88 | |
| 19 | +#define OSMR7 0x8c | |
| 20 | +#define OSMR8 0x90 | |
| 21 | +#define OSMR9 0x94 | |
| 22 | +#define OSMR10 0x98 | |
| 23 | +#define OSMR11 0x9c | |
| 24 | +#define OSCR 0x10 /* OS Timer Count */ | |
| 25 | +#define OSCR4 0x40 | |
| 26 | +#define OSCR5 0x44 | |
| 27 | +#define OSCR6 0x48 | |
| 28 | +#define OSCR7 0x4c | |
| 29 | +#define OSCR8 0x50 | |
| 30 | +#define OSCR9 0x54 | |
| 31 | +#define OSCR10 0x58 | |
| 32 | +#define OSCR11 0x5c | |
| 33 | +#define OSSR 0x14 /* Timer status register */ | |
| 34 | +#define OWER 0x18 | |
| 35 | +#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ | |
| 36 | +#define OMCR4 0xc0 /* OS Match Control registers */ | |
| 37 | +#define OMCR5 0xc4 | |
| 38 | +#define OMCR6 0xc8 | |
| 39 | +#define OMCR7 0xcc | |
| 40 | +#define OMCR8 0xd0 | |
| 41 | +#define OMCR9 0xd4 | |
| 42 | +#define OMCR10 0xd8 | |
| 43 | +#define OMCR11 0xdc | |
| 44 | +#define OSNR 0x20 | |
| 45 | + | |
| 46 | +#define PXA25X_FREQ 3686400 /* 3.6864 MHz */ | |
| 47 | +#define PXA27X_FREQ 3250000 /* 3.25 MHz */ | |
| 48 | + | |
| 49 | +static int pxa2xx_timer4_freq[8] = { | |
| 50 | + [0] = 0, | |
| 51 | + [1] = 32768, | |
| 52 | + [2] = 1000, | |
| 53 | + [3] = 1, | |
| 54 | + [4] = 1000000, | |
| 55 | + /* [5] is the "Externally supplied clock". Assign if necessary. */ | |
| 56 | + [5 ... 7] = 0, | |
| 57 | +}; | |
| 58 | + | |
| 59 | +struct pxa2xx_timer0_s { | |
| 60 | + uint32_t value; | |
| 61 | + int level; | |
| 62 | + qemu_irq irq; | |
| 63 | + QEMUTimer *qtimer; | |
| 64 | + int num; | |
| 65 | + void *info; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +struct pxa2xx_timer4_s { | |
| 69 | + uint32_t value; | |
| 70 | + int level; | |
| 71 | + qemu_irq irq; | |
| 72 | + QEMUTimer *qtimer; | |
| 73 | + int num; | |
| 74 | + void *info; | |
| 75 | + int32_t oldclock; | |
| 76 | + int32_t clock; | |
| 77 | + uint64_t lastload; | |
| 78 | + uint32_t freq; | |
| 79 | + uint32_t control; | |
| 80 | +}; | |
| 81 | + | |
| 82 | +typedef struct { | |
| 83 | + uint32_t base; | |
| 84 | + int32_t clock; | |
| 85 | + int32_t oldclock; | |
| 86 | + uint64_t lastload; | |
| 87 | + uint32_t freq; | |
| 88 | + struct pxa2xx_timer0_s timer[4]; | |
| 89 | + struct pxa2xx_timer4_s *tm4; | |
| 90 | + uint32_t events; | |
| 91 | + uint32_t irq_enabled; | |
| 92 | + uint32_t reset3; | |
| 93 | + CPUState *cpustate; | |
| 94 | + int64_t qemu_ticks; | |
| 95 | + uint32_t snapshot; | |
| 96 | +} pxa2xx_timer_info; | |
| 97 | + | |
| 98 | +static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) | |
| 99 | +{ | |
| 100 | + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; | |
| 101 | + int i; | |
| 102 | + uint32_t now_vm; | |
| 103 | + uint64_t new_qemu; | |
| 104 | + | |
| 105 | + now_vm = s->clock + | |
| 106 | + muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec); | |
| 107 | + | |
| 108 | + for (i = 0; i < 4; i ++) { | |
| 109 | + new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), | |
| 110 | + ticks_per_sec, s->freq); | |
| 111 | + qemu_mod_timer(s->timer[i].qtimer, new_qemu); | |
| 112 | + } | |
| 113 | +} | |
| 114 | + | |
| 115 | +static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) | |
| 116 | +{ | |
| 117 | + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; | |
| 118 | + uint32_t now_vm; | |
| 119 | + uint64_t new_qemu; | |
| 120 | + static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; | |
| 121 | + int counter; | |
| 122 | + | |
| 123 | + if (s->tm4[n].control & (1 << 7)) | |
| 124 | + counter = n; | |
| 125 | + else | |
| 126 | + counter = counters[n]; | |
| 127 | + | |
| 128 | + if (!s->tm4[counter].freq) { | |
| 129 | + qemu_del_timer(s->timer[n].qtimer); | |
| 130 | + return; | |
| 131 | + } | |
| 132 | + | |
| 133 | + now_vm = s->tm4[counter].clock + muldiv64(now_qemu - | |
| 134 | + s->tm4[counter].lastload, | |
| 135 | + s->tm4[counter].freq, ticks_per_sec); | |
| 136 | + | |
| 137 | + new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].value - now_vm), | |
| 138 | + ticks_per_sec, s->tm4[counter].freq); | |
| 139 | + qemu_mod_timer(s->timer[n].qtimer, new_qemu); | |
| 140 | +} | |
| 141 | + | |
| 142 | +static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset) | |
| 143 | +{ | |
| 144 | + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; | |
| 145 | + int tm = 0; | |
| 146 | + | |
| 147 | + offset -= s->base; | |
| 148 | + | |
| 149 | + switch (offset) { | |
| 150 | + case OSMR3: tm ++; | |
| 151 | + case OSMR2: tm ++; | |
| 152 | + case OSMR1: tm ++; | |
| 153 | + case OSMR0: | |
| 154 | + return s->timer[tm].value; | |
| 155 | + case OSMR11: tm ++; | |
| 156 | + case OSMR10: tm ++; | |
| 157 | + case OSMR9: tm ++; | |
| 158 | + case OSMR8: tm ++; | |
| 159 | + case OSMR7: tm ++; | |
| 160 | + case OSMR6: tm ++; | |
| 161 | + case OSMR5: tm ++; | |
| 162 | + case OSMR4: | |
| 163 | + if (!s->tm4) | |
| 164 | + goto badreg; | |
| 165 | + return s->tm4[tm].value; | |
| 166 | + case OSCR: | |
| 167 | + return s->clock + muldiv64(qemu_get_clock(vm_clock) - | |
| 168 | + s->lastload, s->freq, ticks_per_sec); | |
| 169 | + case OSCR11: tm ++; | |
| 170 | + case OSCR10: tm ++; | |
| 171 | + case OSCR9: tm ++; | |
| 172 | + case OSCR8: tm ++; | |
| 173 | + case OSCR7: tm ++; | |
| 174 | + case OSCR6: tm ++; | |
| 175 | + case OSCR5: tm ++; | |
| 176 | + case OSCR4: | |
| 177 | + if (!s->tm4) | |
| 178 | + goto badreg; | |
| 179 | + | |
| 180 | + if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { | |
| 181 | + if (s->tm4[tm - 1].freq) | |
| 182 | + s->snapshot = s->tm4[tm - 1].clock + muldiv64( | |
| 183 | + qemu_get_clock(vm_clock) - | |
| 184 | + s->tm4[tm - 1].lastload, | |
| 185 | + s->tm4[tm - 1].freq, ticks_per_sec); | |
| 186 | + else | |
| 187 | + s->snapshot = s->tm4[tm - 1].clock; | |
| 188 | + } | |
| 189 | + | |
| 190 | + if (!s->tm4[tm].freq) | |
| 191 | + return s->tm4[tm].clock; | |
| 192 | + return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) - | |
| 193 | + s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec); | |
| 194 | + case OIER: | |
| 195 | + return s->irq_enabled; | |
| 196 | + case OSSR: /* Status register */ | |
| 197 | + return s->events; | |
| 198 | + case OWER: | |
| 199 | + return s->reset3; | |
| 200 | + case OMCR11: tm ++; | |
| 201 | + case OMCR10: tm ++; | |
| 202 | + case OMCR9: tm ++; | |
| 203 | + case OMCR8: tm ++; | |
| 204 | + case OMCR7: tm ++; | |
| 205 | + case OMCR6: tm ++; | |
| 206 | + case OMCR5: tm ++; | |
| 207 | + case OMCR4: | |
| 208 | + if (!s->tm4) | |
| 209 | + goto badreg; | |
| 210 | + return s->tm4[tm].control; | |
| 211 | + case OSNR: | |
| 212 | + return s->snapshot; | |
| 213 | + default: | |
| 214 | + badreg: | |
| 215 | + cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset " | |
| 216 | + REG_FMT "\n", offset); | |
| 217 | + } | |
| 218 | + | |
| 219 | + return 0; | |
| 220 | +} | |
| 221 | + | |
| 222 | +static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, | |
| 223 | + uint32_t value) | |
| 224 | +{ | |
| 225 | + int i, tm = 0; | |
| 226 | + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; | |
| 227 | + | |
| 228 | + offset -= s->base; | |
| 229 | + | |
| 230 | + switch (offset) { | |
| 231 | + case OSMR3: tm ++; | |
| 232 | + case OSMR2: tm ++; | |
| 233 | + case OSMR1: tm ++; | |
| 234 | + case OSMR0: | |
| 235 | + s->timer[tm].value = value; | |
| 236 | + pxa2xx_timer_update(s, qemu_get_clock(vm_clock)); | |
| 237 | + break; | |
| 238 | + case OSMR11: tm ++; | |
| 239 | + case OSMR10: tm ++; | |
| 240 | + case OSMR9: tm ++; | |
| 241 | + case OSMR8: tm ++; | |
| 242 | + case OSMR7: tm ++; | |
| 243 | + case OSMR6: tm ++; | |
| 244 | + case OSMR5: tm ++; | |
| 245 | + case OSMR4: | |
| 246 | + if (!s->tm4) | |
| 247 | + goto badreg; | |
| 248 | + s->tm4[tm].value = value; | |
| 249 | + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); | |
| 250 | + break; | |
| 251 | + case OSCR: | |
| 252 | + s->oldclock = s->clock; | |
| 253 | + s->lastload = qemu_get_clock(vm_clock); | |
| 254 | + s->clock = value; | |
| 255 | + pxa2xx_timer_update(s, s->lastload); | |
| 256 | + break; | |
| 257 | + case OSCR11: tm ++; | |
| 258 | + case OSCR10: tm ++; | |
| 259 | + case OSCR9: tm ++; | |
| 260 | + case OSCR8: tm ++; | |
| 261 | + case OSCR7: tm ++; | |
| 262 | + case OSCR6: tm ++; | |
| 263 | + case OSCR5: tm ++; | |
| 264 | + case OSCR4: | |
| 265 | + if (!s->tm4) | |
| 266 | + goto badreg; | |
| 267 | + s->tm4[tm].oldclock = s->tm4[tm].clock; | |
| 268 | + s->tm4[tm].lastload = qemu_get_clock(vm_clock); | |
| 269 | + s->tm4[tm].clock = value; | |
| 270 | + pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); | |
| 271 | + break; | |
| 272 | + case OIER: | |
| 273 | + s->irq_enabled = value & 0xfff; | |
| 274 | + break; | |
| 275 | + case OSSR: /* Status register */ | |
| 276 | + s->events &= ~value; | |
| 277 | + for (i = 0; i < 4; i ++, value >>= 1) { | |
| 278 | + if (s->timer[i].level && (value & 1)) { | |
| 279 | + s->timer[i].level = 0; | |
| 280 | + qemu_irq_lower(s->timer[i].irq); | |
| 281 | + } | |
| 282 | + } | |
| 283 | + if (s->tm4) { | |
| 284 | + for (i = 0; i < 8; i ++, value >>= 1) | |
| 285 | + if (s->tm4[i].level && (value & 1)) | |
| 286 | + s->tm4[i].level = 0; | |
| 287 | + if (!(s->events & 0xff0)) | |
| 288 | + qemu_irq_lower(s->tm4->irq); | |
| 289 | + } | |
| 290 | + break; | |
| 291 | + case OWER: /* XXX: Reset on OSMR3 match? */ | |
| 292 | + s->reset3 = value; | |
| 293 | + break; | |
| 294 | + case OMCR7: tm ++; | |
| 295 | + case OMCR6: tm ++; | |
| 296 | + case OMCR5: tm ++; | |
| 297 | + case OMCR4: | |
| 298 | + if (!s->tm4) | |
| 299 | + goto badreg; | |
| 300 | + s->tm4[tm].control = value & 0x0ff; | |
| 301 | + /* XXX Stop if running (shouldn't happen) */ | |
| 302 | + if ((value & (1 << 7)) || tm == 0) | |
| 303 | + s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; | |
| 304 | + else { | |
| 305 | + s->tm4[tm].freq = 0; | |
| 306 | + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); | |
| 307 | + } | |
| 308 | + break; | |
| 309 | + case OMCR11: tm ++; | |
| 310 | + case OMCR10: tm ++; | |
| 311 | + case OMCR9: tm ++; | |
| 312 | + case OMCR8: tm += 4; | |
| 313 | + if (!s->tm4) | |
| 314 | + goto badreg; | |
| 315 | + s->tm4[tm].control = value & 0x3ff; | |
| 316 | + /* XXX Stop if running (shouldn't happen) */ | |
| 317 | + if ((value & (1 << 7)) || !(tm & 1)) | |
| 318 | + s->tm4[tm].freq = | |
| 319 | + pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; | |
| 320 | + else { | |
| 321 | + s->tm4[tm].freq = 0; | |
| 322 | + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); | |
| 323 | + } | |
| 324 | + break; | |
| 325 | + default: | |
| 326 | + badreg: | |
| 327 | + cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset " | |
| 328 | + REG_FMT "\n", offset); | |
| 329 | + } | |
| 330 | +} | |
| 331 | + | |
| 332 | +static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = { | |
| 333 | + pxa2xx_timer_read, | |
| 334 | + pxa2xx_timer_read, | |
| 335 | + pxa2xx_timer_read, | |
| 336 | +}; | |
| 337 | + | |
| 338 | +static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = { | |
| 339 | + pxa2xx_timer_write, | |
| 340 | + pxa2xx_timer_write, | |
| 341 | + pxa2xx_timer_write, | |
| 342 | +}; | |
| 343 | + | |
| 344 | +static void pxa2xx_timer_tick(void *opaque) | |
| 345 | +{ | |
| 346 | + struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque; | |
| 347 | + pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; | |
| 348 | + | |
| 349 | + if (i->irq_enabled & (1 << t->num)) { | |
| 350 | + t->level = 1; | |
| 351 | + i->events |= 1 << t->num; | |
| 352 | + qemu_irq_raise(t->irq); | |
| 353 | + } | |
| 354 | + | |
| 355 | + if (t->num == 3) | |
| 356 | + if (i->reset3 & 1) { | |
| 357 | + i->reset3 = 0; | |
| 358 | + cpu_reset(i->cpustate); | |
| 359 | + } | |
| 360 | +} | |
| 361 | + | |
| 362 | +static void pxa2xx_timer_tick4(void *opaque) | |
| 363 | +{ | |
| 364 | + struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque; | |
| 365 | + pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; | |
| 366 | + | |
| 367 | + pxa2xx_timer_tick4(opaque); | |
| 368 | + if (t->control & (1 << 3)) | |
| 369 | + t->clock = 0; | |
| 370 | + if (t->control & (1 << 6)) | |
| 371 | + pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->num - 4); | |
| 372 | +} | |
| 373 | + | |
| 374 | +static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, | |
| 375 | + qemu_irq *irqs, CPUState *cpustate) | |
| 376 | +{ | |
| 377 | + int i; | |
| 378 | + int iomemtype; | |
| 379 | + pxa2xx_timer_info *s; | |
| 380 | + | |
| 381 | + s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info)); | |
| 382 | + s->base = base; | |
| 383 | + s->irq_enabled = 0; | |
| 384 | + s->oldclock = 0; | |
| 385 | + s->clock = 0; | |
| 386 | + s->lastload = qemu_get_clock(vm_clock); | |
| 387 | + s->reset3 = 0; | |
| 388 | + s->cpustate = cpustate; | |
| 389 | + | |
| 390 | + for (i = 0; i < 4; i ++) { | |
| 391 | + s->timer[i].value = 0; | |
| 392 | + s->timer[i].irq = irqs[i]; | |
| 393 | + s->timer[i].info = s; | |
| 394 | + s->timer[i].num = i; | |
| 395 | + s->timer[i].level = 0; | |
| 396 | + s->timer[i].qtimer = qemu_new_timer(vm_clock, | |
| 397 | + pxa2xx_timer_tick, &s->timer[i]); | |
| 398 | + } | |
| 399 | + | |
| 400 | + iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, | |
| 401 | + pxa2xx_timer_writefn, s); | |
| 402 | + cpu_register_physical_memory(base, 0x00000fff, iomemtype); | |
| 403 | + return s; | |
| 404 | +} | |
| 405 | + | |
| 406 | +void pxa25x_timer_init(target_phys_addr_t base, | |
| 407 | + qemu_irq *irqs, CPUState *cpustate) | |
| 408 | +{ | |
| 409 | + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); | |
| 410 | + s->freq = PXA25X_FREQ; | |
| 411 | + s->tm4 = 0; | |
| 412 | +} | |
| 413 | + | |
| 414 | +void pxa27x_timer_init(target_phys_addr_t base, | |
| 415 | + qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate) | |
| 416 | +{ | |
| 417 | + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); | |
| 418 | + int i; | |
| 419 | + s->freq = PXA27X_FREQ; | |
| 420 | + s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 * | |
| 421 | + sizeof(struct pxa2xx_timer4_s)); | |
| 422 | + for (i = 0; i < 8; i ++) { | |
| 423 | + s->tm4[i].value = 0; | |
| 424 | + s->tm4[i].irq = irq4; | |
| 425 | + s->tm4[i].info = s; | |
| 426 | + s->tm4[i].num = i + 4; | |
| 427 | + s->tm4[i].level = 0; | |
| 428 | + s->tm4[i].freq = 0; | |
| 429 | + s->tm4[i].control = 0x0; | |
| 430 | + s->tm4[i].qtimer = qemu_new_timer(vm_clock, | |
| 431 | + pxa2xx_timer_tick4, &s->tm4[i]); | |
| 432 | + } | |
| 433 | +} | ... | ... |
vl.c
| ... | ... | @@ -188,6 +188,7 @@ const char *vnc_display; |
| 188 | 188 | int acpi_enabled = 1; |
| 189 | 189 | int fd_bootchk = 1; |
| 190 | 190 | int no_reboot = 0; |
| 191 | +int graphic_rotate = 0; | |
| 191 | 192 | int daemonize = 0; |
| 192 | 193 | const char *option_rom[MAX_OPTION_ROMS]; |
| 193 | 194 | int nb_option_roms; |
| ... | ... | @@ -524,6 +525,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) |
| 524 | 525 | { |
| 525 | 526 | QEMUPutMouseEvent *mouse_event; |
| 526 | 527 | void *mouse_event_opaque; |
| 528 | + int width; | |
| 527 | 529 | |
| 528 | 530 | if (!qemu_put_mouse_event_current) { |
| 529 | 531 | return; |
| ... | ... | @@ -535,7 +537,16 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) |
| 535 | 537 | qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; |
| 536 | 538 | |
| 537 | 539 | if (mouse_event) { |
| 538 | - mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); | |
| 540 | + if (graphic_rotate) { | |
| 541 | + if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute) | |
| 542 | + width = 0x7fff; | |
| 543 | + else | |
| 544 | + width = graphic_width; | |
| 545 | + mouse_event(mouse_event_opaque, | |
| 546 | + width - dy, dx, dz, buttons_state); | |
| 547 | + } else | |
| 548 | + mouse_event(mouse_event_opaque, | |
| 549 | + dx, dy, dz, buttons_state); | |
| 539 | 550 | } |
| 540 | 551 | } |
| 541 | 552 | |
| ... | ... | @@ -6422,6 +6433,7 @@ void help(void) |
| 6422 | 6433 | "-m megs set virtual RAM size to megs MB [default=%d]\n" |
| 6423 | 6434 | "-smp n set the number of CPUs to 'n' [default=1]\n" |
| 6424 | 6435 | "-nographic disable graphical output and redirect serial I/Os to console\n" |
| 6436 | + "-portrait rotate graphical output 90 deg left (only PXA LCD)\n" | |
| 6425 | 6437 | #ifndef _WIN32 |
| 6426 | 6438 | "-k language use keyboard layout (for example \"fr\" for French)\n" |
| 6427 | 6439 | #endif |
| ... | ... | @@ -6556,6 +6568,7 @@ enum { |
| 6556 | 6568 | #endif |
| 6557 | 6569 | QEMU_OPTION_m, |
| 6558 | 6570 | QEMU_OPTION_nographic, |
| 6571 | + QEMU_OPTION_portrait, | |
| 6559 | 6572 | #ifdef HAS_AUDIO |
| 6560 | 6573 | QEMU_OPTION_audio_help, |
| 6561 | 6574 | QEMU_OPTION_soundhw, |
| ... | ... | @@ -6636,6 +6649,7 @@ const QEMUOption qemu_options[] = { |
| 6636 | 6649 | #endif |
| 6637 | 6650 | { "m", HAS_ARG, QEMU_OPTION_m }, |
| 6638 | 6651 | { "nographic", 0, QEMU_OPTION_nographic }, |
| 6652 | + { "portrait", 0, QEMU_OPTION_portrait }, | |
| 6639 | 6653 | { "k", HAS_ARG, QEMU_OPTION_k }, |
| 6640 | 6654 | #ifdef HAS_AUDIO |
| 6641 | 6655 | { "audio-help", 0, QEMU_OPTION_audio_help }, |
| ... | ... | @@ -7167,6 +7181,9 @@ int main(int argc, char **argv) |
| 7167 | 7181 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
| 7168 | 7182 | nographic = 1; |
| 7169 | 7183 | break; |
| 7184 | + case QEMU_OPTION_portrait: | |
| 7185 | + graphic_rotate = 1; | |
| 7186 | + break; | |
| 7170 | 7187 | case QEMU_OPTION_kernel: |
| 7171 | 7188 | kernel_filename = optarg; |
| 7172 | 7189 | break; |
| ... | ... | @@ -7658,7 +7675,7 @@ int main(int argc, char **argv) |
| 7658 | 7675 | fprintf(stderr, "qemu: could not open SD card image %s\n", |
| 7659 | 7676 | sd_filename); |
| 7660 | 7677 | } else |
| 7661 | - qemu_key_check(bs, sd_filename); | |
| 7678 | + qemu_key_check(sd_bdrv, sd_filename); | |
| 7662 | 7679 | } |
| 7663 | 7680 | |
| 7664 | 7681 | register_savevm("timer", 0, 2, timer_save, timer_load, NULL); | ... | ... |
vl.h