Commit 34f64942d902de45b380afb99de5faf704121029
1 parent
5eb9fc83
initial at91 lcdc implementation
Showing
4 changed files
with
231 additions
and
2 deletions
Makefile.target
@@ -411,7 +411,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o | @@ -411,7 +411,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o | ||
411 | endif | 411 | endif |
412 | 412 | ||
413 | obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o | 413 | obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o |
414 | -obj-arm-y += pflash_atmel.o at91sam9.o spi_flash.o | 414 | +obj-arm-y += pflash_atmel.o at91sam9.o spi_flash.o at91_lcdc.o |
415 | obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o | 415 | obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o |
416 | obj-arm-y += versatile_pci.o | 416 | obj-arm-y += versatile_pci.o |
417 | obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o | 417 | obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o |
hw/at91_lcdc.c
0 → 100644
1 | +/* | ||
2 | + * AT91 SAM9 LCD Controller (LCDC) | ||
3 | + * Written by Evgeniy Dushistov | ||
4 | + * This code is licenced under the GPL. | ||
5 | + */ | ||
6 | +#include "sysbus.h" | ||
7 | +#include "console.h" | ||
8 | +#include "pixel_ops.h" | ||
9 | + | ||
10 | +#define LCDC_SIZE 0x100000 | ||
11 | + | ||
12 | +#define LCDC_DMABADDR1 0x0 | ||
13 | +#define LCDC_DMAFRMCFG 0x18 | ||
14 | +#define LCDC_DMACON 0x1C | ||
15 | +#define LCDC_LCDCON1 0x800 | ||
16 | +#define LCDC_LCDCON2 0x804 | ||
17 | +#define LCDC_LCDFRMCFG 0x810 | ||
18 | +#define LCDC_PWRCON 0x83C | ||
19 | + | ||
20 | +#define DMACON_DMAEN 1 | ||
21 | + | ||
22 | +typedef struct LCDCState { | ||
23 | + SysBusDevice busdev; | ||
24 | + qemu_irq irq; | ||
25 | + DisplayState *ds; | ||
26 | + uint32_t dmacon; | ||
27 | + uint32_t pwrcon; | ||
28 | + uint32_t dmafrmcfg; | ||
29 | + uint32_t lcdcon1; | ||
30 | + uint32_t lcdcon2; | ||
31 | + uint32_t lcdfrmcfg; | ||
32 | + uint32_t dmabaddr1; | ||
33 | +} LCDCState; | ||
34 | + | ||
35 | +#define AT91_LCDC_DEBUG | ||
36 | +#ifdef AT91_LCDC_DEBUG | ||
37 | +#define DPRINTF(fmt, ...) \ | ||
38 | + do { \ | ||
39 | + printf("AT91LCD: " fmt , ## __VA_ARGS__); \ | ||
40 | + } while (0) | ||
41 | +#else | ||
42 | +#define DPRINTF(fmt, ...) do { } while (0) | ||
43 | +#endif | ||
44 | + | ||
45 | + | ||
46 | +static uint32_t at91_lcdc_mem_read(void *opaque, target_phys_addr_t offset) | ||
47 | +{ | ||
48 | + LCDCState *s = opaque; | ||
49 | + | ||
50 | + offset &= LCDC_SIZE - 1; | ||
51 | + DPRINTF("read from %X\n", offset); | ||
52 | + switch (offset) { | ||
53 | + case LCDC_PWRCON: | ||
54 | + return s->pwrcon; | ||
55 | + case LCDC_DMACON: | ||
56 | + return s->dmacon; | ||
57 | + case LCDC_DMAFRMCFG: | ||
58 | + return s->dmafrmcfg; | ||
59 | + case LCDC_LCDCON1: | ||
60 | + return s->lcdcon1; | ||
61 | + case LCDC_LCDCON2: | ||
62 | + return s->lcdcon2; | ||
63 | + case LCDC_LCDFRMCFG: | ||
64 | + return s->lcdfrmcfg; | ||
65 | + default: | ||
66 | + DPRINTF("unsup. read\n"); | ||
67 | + return 0; | ||
68 | + } | ||
69 | +} | ||
70 | + | ||
71 | +static void at91_lcdc_mem_write(void *opaque, target_phys_addr_t offset, | ||
72 | + uint32_t value) | ||
73 | +{ | ||
74 | + LCDCState *s = opaque; | ||
75 | + offset &= LCDC_SIZE - 1; | ||
76 | + DPRINTF("write to %X: %X\n", offset, value); | ||
77 | + | ||
78 | + switch (offset) { | ||
79 | + case LCDC_DMABADDR1: | ||
80 | + s->dmabaddr1 = value; | ||
81 | + break; | ||
82 | + case LCDC_PWRCON: | ||
83 | + s->pwrcon = value; | ||
84 | + break; | ||
85 | + case LCDC_DMACON: | ||
86 | + s->dmacon = value; | ||
87 | + break; | ||
88 | + case LCDC_DMAFRMCFG: | ||
89 | + s->dmafrmcfg = value; | ||
90 | + break; | ||
91 | + case LCDC_LCDCON1: | ||
92 | + s->lcdcon1 = value; | ||
93 | + break; | ||
94 | + case LCDC_LCDCON2: | ||
95 | + DPRINTF("pixel size %u\n", (value >> 5) & 7); | ||
96 | + s->lcdcon2 = value; | ||
97 | + break; | ||
98 | + case LCDC_LCDFRMCFG: | ||
99 | + DPRINTF("lineval %u, linsize %u\n", value & 0x7FF, (value >> 21) & 0x7FF); | ||
100 | + qemu_console_resize(s->ds, ((value >> 21) & 0x7FF) + 1, (value & 0x7FF) + 1); | ||
101 | + s->lcdfrmcfg = value; | ||
102 | + break; | ||
103 | + default: | ||
104 | + DPRINTF("unsup. write\n"); | ||
105 | + } | ||
106 | +} | ||
107 | + | ||
108 | +static CPUReadMemoryFunc *at91_lcdc_readfn[] = { | ||
109 | + at91_lcdc_mem_read, | ||
110 | + at91_lcdc_mem_read, | ||
111 | + at91_lcdc_mem_read, | ||
112 | +}; | ||
113 | + | ||
114 | +static CPUWriteMemoryFunc *at91_lcdc_writefn[] = { | ||
115 | + at91_lcdc_mem_write, | ||
116 | + at91_lcdc_mem_write, | ||
117 | + at91_lcdc_mem_write, | ||
118 | +}; | ||
119 | + | ||
120 | +static void at91_lcdc_reset(void *opaque) | ||
121 | +{ | ||
122 | + LCDCState *s = opaque; | ||
123 | + s->pwrcon = 0x0000000e; | ||
124 | + s->dmacon = 0; | ||
125 | + s->dmafrmcfg = 0; | ||
126 | + s->lcdcon1 = 0x00002000; | ||
127 | + s->lcdfrmcfg = 0; | ||
128 | +} | ||
129 | + | ||
130 | +struct pixel8 { | ||
131 | + unsigned b : 2; | ||
132 | + unsigned g : 3; | ||
133 | + unsigned r : 3; | ||
134 | +}; | ||
135 | + | ||
136 | +union pixel8u { | ||
137 | + struct pixel8 p; | ||
138 | + uint8_t val; | ||
139 | +}; | ||
140 | + | ||
141 | +static void at91_lcdc_update_display(void *opaque) | ||
142 | +{ | ||
143 | + LCDCState *s = opaque; | ||
144 | + uint32_t color; | ||
145 | + int x, y; | ||
146 | + uint8_t *d; | ||
147 | + int width = ((s->lcdfrmcfg >> 21) & 0x7FF) + 1; | ||
148 | + int height = (s->lcdfrmcfg & 0x7FF) + 1; | ||
149 | + int q_bpp = (ds_get_bits_per_pixel(s->ds) + 7) >> 3; | ||
150 | + int bpp; | ||
151 | + int bpp_idx = (s->lcdcon2 >> 5) & 7; | ||
152 | + union pixel8u tmp; | ||
153 | + | ||
154 | + DPRINTF("update begin\n"); | ||
155 | + if (!(s->dmacon & DMACON_DMAEN)) | ||
156 | + return; | ||
157 | + DPRINTF("update continue\n"); | ||
158 | + switch (bpp_idx) { | ||
159 | + case 0 ... 4: | ||
160 | + bpp = 1 << bpp_idx; | ||
161 | + break; | ||
162 | + case 5 ... 6: | ||
163 | + bpp = 24; | ||
164 | + break; | ||
165 | + default: | ||
166 | + fprintf(stderr, "Unknown pixel size\n"); | ||
167 | + return;//reserved value, unknown pixel size | ||
168 | + } | ||
169 | + /*TODO: fix this restriction*/ | ||
170 | + if (bpp != 8) { | ||
171 | + fprintf(stderr, "Unsupported pixel size\n"); | ||
172 | + return; | ||
173 | + } | ||
174 | + int once = 0; | ||
175 | + for (y = 0; y < height; ++y) { | ||
176 | + for (x = 0; x < width; ++x) { | ||
177 | + cpu_physical_memory_read(s->dmabaddr1 + width * y + x, &tmp.val, 1); | ||
178 | + if (tmp.val != 0 && once == 0) { | ||
179 | + once = 1; | ||
180 | + DPRINTF("not null %X, %X, %X, bpp %d\n", (unsigned)tmp.p.r << 5, (unsigned)tmp.p.g << 5, (unsigned)tmp.p.b << 6, ds_get_bits_per_pixel(s->ds)); | ||
181 | + } | ||
182 | + switch (ds_get_bits_per_pixel(s->ds)) { | ||
183 | + case 8: | ||
184 | + color = rgb_to_pixel8(tmp.p.r, tmp.p.g, tmp.p.b); | ||
185 | + break; | ||
186 | + case 15: | ||
187 | + color = rgb_to_pixel15(tmp.p.r, tmp.p.g, tmp.p.b); | ||
188 | + break; | ||
189 | + case 16: | ||
190 | + color = rgb_to_pixel16(tmp.p.r, tmp.p.g, tmp.p.b); | ||
191 | + break; | ||
192 | + case 24: | ||
193 | + color = rgb_to_pixel24(tmp.p.r, tmp.p.g, tmp.p.b); | ||
194 | + break; | ||
195 | + case 32: | ||
196 | + color = rgb_to_pixel32((unsigned)tmp.p.r << 5, (unsigned)tmp.p.g << 5, (unsigned)tmp.p.b << 6); | ||
197 | + break; | ||
198 | + default: | ||
199 | + return; | ||
200 | + } | ||
201 | + | ||
202 | + d = ds_get_data(s->ds) + ds_get_linesize(s->ds) * y + q_bpp * x; | ||
203 | + *d = color; | ||
204 | + } | ||
205 | + } | ||
206 | + | ||
207 | + dpy_update(s->ds, 0, 0, width, height); | ||
208 | +} | ||
209 | + | ||
210 | +static void at91_lcdc_init(SysBusDevice *dev) | ||
211 | +{ | ||
212 | + LCDCState *s = FROM_SYSBUS(typeof(*s), dev); | ||
213 | + int lcdc_regs; | ||
214 | + | ||
215 | + sysbus_init_irq(dev, &s->irq); | ||
216 | + lcdc_regs = cpu_register_io_memory(at91_lcdc_readfn, | ||
217 | + at91_lcdc_writefn, s); | ||
218 | + sysbus_init_mmio(dev, LCDC_SIZE, lcdc_regs); | ||
219 | + qemu_register_reset(at91_lcdc_reset, s); | ||
220 | + s->ds = graphic_console_init(at91_lcdc_update_display, NULL, NULL, NULL, s); | ||
221 | +} | ||
222 | + | ||
223 | +static void at91_lcdc_register(void) | ||
224 | +{ | ||
225 | + sysbus_register_dev("at91,lcdc", sizeof(LCDCState), at91_lcdc_init); | ||
226 | +} | ||
227 | + | ||
228 | +device_init(at91_lcdc_register) |
hw/at91sam9.c
@@ -336,7 +336,7 @@ static void at91sam9_init(ram_addr_t ram_size, | @@ -336,7 +336,7 @@ static void at91sam9_init(ram_addr_t ram_size, | ||
336 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, AT91_EMAC_BASE); | 336 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, AT91_EMAC_BASE); |
337 | sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[21]); | 337 | sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[21]); |
338 | 338 | ||
339 | - | 339 | + sysbus_create_simple("at91,lcdc", AT91_LCDC_BASE, pic[26]); |
340 | /* | 340 | /* |
341 | we use variant of booting from external memory (NOR FLASH), | 341 | we use variant of booting from external memory (NOR FLASH), |
342 | it mapped to 0x0 at start, and also it is accessable from 0x10000000 address | 342 | it mapped to 0x0 at start, and also it is accessable from 0x10000000 address |
hw/at91sam9263_defs.h
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | #define _HW_AT91SAM9263_DEFS_H_ | 2 | #define _HW_AT91SAM9263_DEFS_H_ |
3 | 3 | ||
4 | /* base periph addresses */ | 4 | /* base periph addresses */ |
5 | +#define AT91_LCDC_BASE 0x00700000 | ||
5 | #define AT91_PERIPH_BASE 0xF0000000 | 6 | #define AT91_PERIPH_BASE 0xF0000000 |
6 | #define AT91_TC012_BASE 0xFFF7C000 | 7 | #define AT91_TC012_BASE 0xFFF7C000 |
7 | #define AT91_USART0_BASE 0xFFF8C000 | 8 | #define AT91_USART0_BASE 0xFFF8C000 |