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,6 +63,12 @@ | ||
63 | struct pxa2xx_pic_state_s; | 63 | struct pxa2xx_pic_state_s; |
64 | qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); | 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 | /* pxa2xx_gpio.c */ | 72 | /* pxa2xx_gpio.c */ |
67 | struct pxa2xx_gpio_info_s; | 73 | struct pxa2xx_gpio_info_s; |
68 | struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, | 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,6 +87,29 @@ struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base, | ||
81 | qemu_irq irq); | 87 | qemu_irq irq); |
82 | void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on); | 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 | /* pxa2xx.c */ | 113 | /* pxa2xx.c */ |
85 | struct pxa2xx_ssp_s; | 114 | struct pxa2xx_ssp_s; |
86 | void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, | 115 | void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, |
@@ -95,7 +124,10 @@ struct pxa2xx_state_s { | @@ -95,7 +124,10 @@ struct pxa2xx_state_s { | ||
95 | qemu_irq *pic; | 124 | qemu_irq *pic; |
96 | struct pxa2xx_dma_state_s *dma; | 125 | struct pxa2xx_dma_state_s *dma; |
97 | struct pxa2xx_gpio_info_s *gpio; | 126 | struct pxa2xx_gpio_info_s *gpio; |
127 | + struct pxa2xx_lcdc_s *lcd; | ||
98 | struct pxa2xx_ssp_s **ssp; | 128 | struct pxa2xx_ssp_s **ssp; |
129 | + struct pxa2xx_mmci_s *mmc; | ||
130 | + struct pxa2xx_pcmcia_s *pcmcia[2]; | ||
99 | struct pxa2xx_i2s_s *i2s; | 131 | struct pxa2xx_i2s_s *i2s; |
100 | struct pxa2xx_fir_s *fir; | 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,8 +1531,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) | ||
1531 | 1531 | ||
1532 | s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); | 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 | s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); | 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 | for (i = 0; pxa270_serial[i].io_base; i ++) | 1541 | for (i = 0; pxa270_serial[i].io_base; i ++) |
1537 | if (serial_hds[i]) | 1542 | if (serial_hds[i]) |
1538 | serial_mm_init(pxa270_serial[i].io_base, 2, | 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,6 +1548,9 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) | ||
1543 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], | 1548 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], |
1544 | s->dma, serial_hds[i]); | 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 | s->cm_base = 0x41300000; | 1554 | s->cm_base = 0x41300000; |
1547 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ | 1555 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ |
1548 | s->clkcfg = 0x00000009; /* Turbo mode active */ | 1556 | s->clkcfg = 0x00000009; /* Turbo mode active */ |
@@ -1575,6 +1583,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) | @@ -1575,6 +1583,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) | ||
1575 | cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); | 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 | s->rtc_base = 0x40900000; | 1593 | s->rtc_base = 0x40900000; |
1579 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, | 1594 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, |
1580 | pxa2xx_rtc_writefn, s); | 1595 | pxa2xx_rtc_writefn, s); |
@@ -1609,8 +1624,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | @@ -1609,8 +1624,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | ||
1609 | 1624 | ||
1610 | s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); | 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 | s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); | 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 | for (i = 0; pxa255_serial[i].io_base; i ++) | 1633 | for (i = 0; pxa255_serial[i].io_base; i ++) |
1615 | if (serial_hds[i]) | 1634 | if (serial_hds[i]) |
1616 | serial_mm_init(pxa255_serial[i].io_base, 2, | 1635 | serial_mm_init(pxa255_serial[i].io_base, 2, |
@@ -1621,6 +1640,9 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | @@ -1621,6 +1640,9 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | ||
1621 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], | 1640 | s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], |
1622 | s->dma, serial_hds[i]); | 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 | s->cm_base = 0x41300000; | 1646 | s->cm_base = 0x41300000; |
1625 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ | 1647 | s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ |
1626 | s->clkcfg = 0x00000009; /* Turbo mode active */ | 1648 | s->clkcfg = 0x00000009; /* Turbo mode active */ |
@@ -1653,6 +1675,13 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | @@ -1653,6 +1675,13 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) | ||
1653 | cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); | 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 | s->rtc_base = 0x40900000; | 1685 | s->rtc_base = 0x40900000; |
1657 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, | 1686 | iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, |
1658 | pxa2xx_rtc_writefn, s); | 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,6 +188,7 @@ const char *vnc_display; | ||
188 | int acpi_enabled = 1; | 188 | int acpi_enabled = 1; |
189 | int fd_bootchk = 1; | 189 | int fd_bootchk = 1; |
190 | int no_reboot = 0; | 190 | int no_reboot = 0; |
191 | +int graphic_rotate = 0; | ||
191 | int daemonize = 0; | 192 | int daemonize = 0; |
192 | const char *option_rom[MAX_OPTION_ROMS]; | 193 | const char *option_rom[MAX_OPTION_ROMS]; |
193 | int nb_option_roms; | 194 | int nb_option_roms; |
@@ -524,6 +525,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | @@ -524,6 +525,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | ||
524 | { | 525 | { |
525 | QEMUPutMouseEvent *mouse_event; | 526 | QEMUPutMouseEvent *mouse_event; |
526 | void *mouse_event_opaque; | 527 | void *mouse_event_opaque; |
528 | + int width; | ||
527 | 529 | ||
528 | if (!qemu_put_mouse_event_current) { | 530 | if (!qemu_put_mouse_event_current) { |
529 | return; | 531 | return; |
@@ -535,7 +537,16 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | @@ -535,7 +537,16 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | ||
535 | qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; | 537 | qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; |
536 | 538 | ||
537 | if (mouse_event) { | 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,6 +6433,7 @@ void help(void) | ||
6422 | "-m megs set virtual RAM size to megs MB [default=%d]\n" | 6433 | "-m megs set virtual RAM size to megs MB [default=%d]\n" |
6423 | "-smp n set the number of CPUs to 'n' [default=1]\n" | 6434 | "-smp n set the number of CPUs to 'n' [default=1]\n" |
6424 | "-nographic disable graphical output and redirect serial I/Os to console\n" | 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 | #ifndef _WIN32 | 6437 | #ifndef _WIN32 |
6426 | "-k language use keyboard layout (for example \"fr\" for French)\n" | 6438 | "-k language use keyboard layout (for example \"fr\" for French)\n" |
6427 | #endif | 6439 | #endif |
@@ -6556,6 +6568,7 @@ enum { | @@ -6556,6 +6568,7 @@ enum { | ||
6556 | #endif | 6568 | #endif |
6557 | QEMU_OPTION_m, | 6569 | QEMU_OPTION_m, |
6558 | QEMU_OPTION_nographic, | 6570 | QEMU_OPTION_nographic, |
6571 | + QEMU_OPTION_portrait, | ||
6559 | #ifdef HAS_AUDIO | 6572 | #ifdef HAS_AUDIO |
6560 | QEMU_OPTION_audio_help, | 6573 | QEMU_OPTION_audio_help, |
6561 | QEMU_OPTION_soundhw, | 6574 | QEMU_OPTION_soundhw, |
@@ -6636,6 +6649,7 @@ const QEMUOption qemu_options[] = { | @@ -6636,6 +6649,7 @@ const QEMUOption qemu_options[] = { | ||
6636 | #endif | 6649 | #endif |
6637 | { "m", HAS_ARG, QEMU_OPTION_m }, | 6650 | { "m", HAS_ARG, QEMU_OPTION_m }, |
6638 | { "nographic", 0, QEMU_OPTION_nographic }, | 6651 | { "nographic", 0, QEMU_OPTION_nographic }, |
6652 | + { "portrait", 0, QEMU_OPTION_portrait }, | ||
6639 | { "k", HAS_ARG, QEMU_OPTION_k }, | 6653 | { "k", HAS_ARG, QEMU_OPTION_k }, |
6640 | #ifdef HAS_AUDIO | 6654 | #ifdef HAS_AUDIO |
6641 | { "audio-help", 0, QEMU_OPTION_audio_help }, | 6655 | { "audio-help", 0, QEMU_OPTION_audio_help }, |
@@ -7167,6 +7181,9 @@ int main(int argc, char **argv) | @@ -7167,6 +7181,9 @@ int main(int argc, char **argv) | ||
7167 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | 7181 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
7168 | nographic = 1; | 7182 | nographic = 1; |
7169 | break; | 7183 | break; |
7184 | + case QEMU_OPTION_portrait: | ||
7185 | + graphic_rotate = 1; | ||
7186 | + break; | ||
7170 | case QEMU_OPTION_kernel: | 7187 | case QEMU_OPTION_kernel: |
7171 | kernel_filename = optarg; | 7188 | kernel_filename = optarg; |
7172 | break; | 7189 | break; |
@@ -7658,7 +7675,7 @@ int main(int argc, char **argv) | @@ -7658,7 +7675,7 @@ int main(int argc, char **argv) | ||
7658 | fprintf(stderr, "qemu: could not open SD card image %s\n", | 7675 | fprintf(stderr, "qemu: could not open SD card image %s\n", |
7659 | sd_filename); | 7676 | sd_filename); |
7660 | } else | 7677 | } else |
7661 | - qemu_key_check(bs, sd_filename); | 7678 | + qemu_key_check(sd_bdrv, sd_filename); |
7662 | } | 7679 | } |
7663 | 7680 | ||
7664 | register_savevm("timer", 0, 2, timer_save, timer_load, NULL); | 7681 | register_savevm("timer", 0, 2, timer_save, timer_load, NULL); |
vl.h
@@ -158,6 +158,7 @@ extern int kqemu_allowed; | @@ -158,6 +158,7 @@ extern int kqemu_allowed; | ||
158 | extern int win2k_install_hack; | 158 | extern int win2k_install_hack; |
159 | extern int usb_enabled; | 159 | extern int usb_enabled; |
160 | extern int smp_cpus; | 160 | extern int smp_cpus; |
161 | +extern int graphic_rotate; | ||
161 | extern int no_quit; | 162 | extern int no_quit; |
162 | extern int semihosting_enabled; | 163 | extern int semihosting_enabled; |
163 | extern int autostart; | 164 | extern int autostart; |