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