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 | 411 | endif |
412 | 412 | |
413 | 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 | 415 | obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o |
416 | 416 | obj-arm-y += versatile_pci.o |
417 | 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 | 336 | sysbus_mmio_map(sysbus_from_qdev(dev), 0, AT91_EMAC_BASE); |
337 | 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 | 341 | we use variant of booting from external memory (NOR FLASH), |
342 | 342 | it mapped to 0x0 at start, and also it is accessable from 0x10000000 address | ... | ... |
hw/at91sam9263_defs.h