root / hw / syborg_fb.c @ cde844fa
History | View | Annotate | Download (13.3 kB)
1 | 4af39611 | Paul Brook | /*
|
---|---|---|---|
2 | 4af39611 | Paul Brook | * Syborg Framebuffer
|
3 | 4af39611 | Paul Brook | *
|
4 | 4af39611 | Paul Brook | * Copyright (c) 2009 CodeSourcery
|
5 | 4af39611 | Paul Brook | *
|
6 | 4af39611 | Paul Brook | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 4af39611 | Paul Brook | * of this software and associated documentation files (the "Software"), to deal
|
8 | 4af39611 | Paul Brook | * in the Software without restriction, including without limitation the rights
|
9 | 4af39611 | Paul Brook | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 4af39611 | Paul Brook | * copies of the Software, and to permit persons to whom the Software is
|
11 | 4af39611 | Paul Brook | * furnished to do so, subject to the following conditions:
|
12 | 4af39611 | Paul Brook | *
|
13 | 4af39611 | Paul Brook | * The above copyright notice and this permission notice shall be included in
|
14 | 4af39611 | Paul Brook | * all copies or substantial portions of the Software.
|
15 | 4af39611 | Paul Brook | *
|
16 | 4af39611 | Paul Brook | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 4af39611 | Paul Brook | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 4af39611 | Paul Brook | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 4af39611 | Paul Brook | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 4af39611 | Paul Brook | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 4af39611 | Paul Brook | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 4af39611 | Paul Brook | * THE SOFTWARE.
|
23 | 4af39611 | Paul Brook | */
|
24 | 4af39611 | Paul Brook | |
25 | 4af39611 | Paul Brook | #include "sysbus.h" |
26 | 4af39611 | Paul Brook | #include "console.h" |
27 | 4af39611 | Paul Brook | #include "syborg.h" |
28 | 4af39611 | Paul Brook | #include "framebuffer.h" |
29 | 4af39611 | Paul Brook | |
30 | 4af39611 | Paul Brook | //#define DEBUG_SYBORG_FB
|
31 | 4af39611 | Paul Brook | |
32 | 4af39611 | Paul Brook | #ifdef DEBUG_SYBORG_FB
|
33 | 4af39611 | Paul Brook | #define DPRINTF(fmt, ...) \
|
34 | 4af39611 | Paul Brook | do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0) |
35 | 4af39611 | Paul Brook | #define BADF(fmt, ...) \
|
36 | 4af39611 | Paul Brook | do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \ |
37 | 4af39611 | Paul Brook | exit(1);} while (0) |
38 | 4af39611 | Paul Brook | #else
|
39 | 4af39611 | Paul Brook | #define DPRINTF(fmt, ...) do {} while(0) |
40 | 4af39611 | Paul Brook | #define BADF(fmt, ...) \
|
41 | 4af39611 | Paul Brook | do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0) |
42 | 4af39611 | Paul Brook | #endif
|
43 | 4af39611 | Paul Brook | |
44 | 4af39611 | Paul Brook | enum {
|
45 | 4af39611 | Paul Brook | FB_ID = 0,
|
46 | 4af39611 | Paul Brook | FB_BASE = 1,
|
47 | 4af39611 | Paul Brook | FB_HEIGHT = 2,
|
48 | 4af39611 | Paul Brook | FB_WIDTH = 3,
|
49 | 4af39611 | Paul Brook | FB_ORIENTATION = 4,
|
50 | 4af39611 | Paul Brook | FB_BLANK = 5,
|
51 | 4af39611 | Paul Brook | FB_INT_MASK = 6,
|
52 | 4af39611 | Paul Brook | FB_INTERRUPT_CAUSE = 7,
|
53 | 4af39611 | Paul Brook | FB_BPP = 8,
|
54 | 4af39611 | Paul Brook | FB_COLOR_ORDER = 9,
|
55 | 4af39611 | Paul Brook | FB_BYTE_ORDER = 10,
|
56 | 4af39611 | Paul Brook | FB_PIXEL_ORDER = 11,
|
57 | 4af39611 | Paul Brook | FB_ROW_PITCH = 12,
|
58 | 4af39611 | Paul Brook | FB_ENABLED = 13,
|
59 | 4af39611 | Paul Brook | FB_PALETTE_START = 0x400 >> 2, |
60 | 4af39611 | Paul Brook | FB_PALETTE_END = FB_PALETTE_START+256-1, |
61 | 4af39611 | Paul Brook | }; |
62 | 4af39611 | Paul Brook | |
63 | 4af39611 | Paul Brook | #define FB_INT_VSYNC (1U << 0) |
64 | 4af39611 | Paul Brook | #define FB_INT_BASE_UPDATE_DONE (1U << 1) |
65 | 4af39611 | Paul Brook | |
66 | 4af39611 | Paul Brook | typedef struct { |
67 | 4af39611 | Paul Brook | SysBusDevice busdev; |
68 | 0520a049 | Benoît Canet | MemoryRegion iomem; |
69 | 4af39611 | Paul Brook | DisplayState *ds; |
70 | 4af39611 | Paul Brook | /*QEMUConsole *console;*/
|
71 | 4af39611 | Paul Brook | uint32_t need_update : 1;
|
72 | 4af39611 | Paul Brook | uint32_t need_int : 1;
|
73 | 4af39611 | Paul Brook | uint32_t enabled : 1;
|
74 | 4af39611 | Paul Brook | uint32_t int_status; |
75 | 4af39611 | Paul Brook | uint32_t int_enable; |
76 | 4af39611 | Paul Brook | qemu_irq irq; |
77 | 4af39611 | Paul Brook | |
78 | 4af39611 | Paul Brook | uint32_t base; |
79 | 4af39611 | Paul Brook | uint32_t pitch; |
80 | ee6847d1 | Gerd Hoffmann | uint32_t rows; |
81 | ee6847d1 | Gerd Hoffmann | uint32_t cols; |
82 | 4af39611 | Paul Brook | int blank;
|
83 | 4af39611 | Paul Brook | int bpp;
|
84 | 4af39611 | Paul Brook | int rgb; /* 0 = BGR, 1 = RGB */ |
85 | 4af39611 | Paul Brook | int endian; /* 0 = Little, 1 = Big */ |
86 | 4af39611 | Paul Brook | uint32_t raw_palette[256];
|
87 | 4af39611 | Paul Brook | uint32_t palette[256];
|
88 | 4af39611 | Paul Brook | } SyborgFBState; |
89 | 4af39611 | Paul Brook | |
90 | 4af39611 | Paul Brook | enum {
|
91 | 4af39611 | Paul Brook | BPP_SRC_1, |
92 | 4af39611 | Paul Brook | BPP_SRC_2, |
93 | 4af39611 | Paul Brook | BPP_SRC_4, |
94 | 4af39611 | Paul Brook | BPP_SRC_8, |
95 | 4af39611 | Paul Brook | BPP_SRC_16, |
96 | 4af39611 | Paul Brook | BPP_SRC_32, |
97 | 4af39611 | Paul Brook | /* TODO: Implement these. */
|
98 | 4af39611 | Paul Brook | BPP_SRC_15 = -1,
|
99 | 4af39611 | Paul Brook | BPP_SRC_24 = -2
|
100 | 4af39611 | Paul Brook | }; |
101 | 4af39611 | Paul Brook | |
102 | 4af39611 | Paul Brook | #include "pixel_ops.h" |
103 | 4af39611 | Paul Brook | |
104 | 4af39611 | Paul Brook | #define BITS 8 |
105 | 4af39611 | Paul Brook | #include "pl110_template.h" |
106 | 4af39611 | Paul Brook | #define BITS 15 |
107 | 4af39611 | Paul Brook | #include "pl110_template.h" |
108 | 4af39611 | Paul Brook | #define BITS 16 |
109 | 4af39611 | Paul Brook | #include "pl110_template.h" |
110 | 4af39611 | Paul Brook | #define BITS 24 |
111 | 4af39611 | Paul Brook | #include "pl110_template.h" |
112 | 4af39611 | Paul Brook | #define BITS 32 |
113 | 4af39611 | Paul Brook | #include "pl110_template.h" |
114 | 4af39611 | Paul Brook | |
115 | 4af39611 | Paul Brook | /* Update interrupts. */
|
116 | 4af39611 | Paul Brook | static void syborg_fb_update(SyborgFBState *s) |
117 | 4af39611 | Paul Brook | { |
118 | 4af39611 | Paul Brook | if ((s->int_status & s->int_enable) != 0) { |
119 | 4af39611 | Paul Brook | DPRINTF("Raise IRQ\n");
|
120 | 4af39611 | Paul Brook | qemu_irq_raise(s->irq); |
121 | 4af39611 | Paul Brook | } else {
|
122 | 4af39611 | Paul Brook | DPRINTF("Lower IRQ\n");
|
123 | 4af39611 | Paul Brook | qemu_irq_lower(s->irq); |
124 | 4af39611 | Paul Brook | } |
125 | 4af39611 | Paul Brook | } |
126 | 4af39611 | Paul Brook | |
127 | 4af39611 | Paul Brook | static int syborg_fb_enabled(const SyborgFBState *s) |
128 | 4af39611 | Paul Brook | { |
129 | 4af39611 | Paul Brook | return s->enabled;
|
130 | 4af39611 | Paul Brook | } |
131 | 4af39611 | Paul Brook | |
132 | 4af39611 | Paul Brook | static void syborg_fb_update_palette(SyborgFBState *s) |
133 | 4af39611 | Paul Brook | { |
134 | 4af39611 | Paul Brook | int n, i;
|
135 | 4af39611 | Paul Brook | uint32_t raw; |
136 | 4af39611 | Paul Brook | unsigned int r, g, b; |
137 | 4af39611 | Paul Brook | |
138 | 4af39611 | Paul Brook | switch (s->bpp) {
|
139 | 4af39611 | Paul Brook | case BPP_SRC_1: n = 2; break; |
140 | 4af39611 | Paul Brook | case BPP_SRC_2: n = 4; break; |
141 | 4af39611 | Paul Brook | case BPP_SRC_4: n = 16; break; |
142 | 4af39611 | Paul Brook | case BPP_SRC_8: n = 256; break; |
143 | 4af39611 | Paul Brook | default: return; |
144 | 4af39611 | Paul Brook | } |
145 | 4af39611 | Paul Brook | |
146 | 4af39611 | Paul Brook | for (i = 0; i < n; i++) { |
147 | 4af39611 | Paul Brook | raw = s->raw_palette[i]; |
148 | 4af39611 | Paul Brook | r = (raw >> 16) & 0xff; |
149 | 4af39611 | Paul Brook | g = (raw >> 8) & 0xff; |
150 | 4af39611 | Paul Brook | b = raw & 0xff;
|
151 | 4af39611 | Paul Brook | switch (ds_get_bits_per_pixel(s->ds)) {
|
152 | 4af39611 | Paul Brook | case 8: |
153 | 4af39611 | Paul Brook | s->palette[i] = rgb_to_pixel8(r, g, b); |
154 | 4af39611 | Paul Brook | break;
|
155 | 4af39611 | Paul Brook | case 15: |
156 | 4af39611 | Paul Brook | s->palette[i] = rgb_to_pixel15(r, g, b); |
157 | 4af39611 | Paul Brook | break;
|
158 | 4af39611 | Paul Brook | case 16: |
159 | 4af39611 | Paul Brook | s->palette[i] = rgb_to_pixel16(r, g, b); |
160 | 4af39611 | Paul Brook | break;
|
161 | 4af39611 | Paul Brook | case 24: |
162 | 4af39611 | Paul Brook | case 32: |
163 | 4af39611 | Paul Brook | s->palette[i] = rgb_to_pixel32(r, g, b); |
164 | 4af39611 | Paul Brook | break;
|
165 | 4af39611 | Paul Brook | default:
|
166 | 4af39611 | Paul Brook | abort(); |
167 | 4af39611 | Paul Brook | } |
168 | 4af39611 | Paul Brook | } |
169 | 4af39611 | Paul Brook | |
170 | 4af39611 | Paul Brook | } |
171 | 4af39611 | Paul Brook | |
172 | 4af39611 | Paul Brook | static void syborg_fb_update_display(void *opaque) |
173 | 4af39611 | Paul Brook | { |
174 | 4af39611 | Paul Brook | SyborgFBState *s = (SyborgFBState *)opaque; |
175 | 4af39611 | Paul Brook | drawfn* fntable; |
176 | 4af39611 | Paul Brook | drawfn fn; |
177 | 4af39611 | Paul Brook | int dest_width;
|
178 | 4af39611 | Paul Brook | int src_width;
|
179 | 4af39611 | Paul Brook | int bpp_offset;
|
180 | 4af39611 | Paul Brook | int first;
|
181 | 4af39611 | Paul Brook | int last;
|
182 | 4af39611 | Paul Brook | |
183 | 4af39611 | Paul Brook | if (!syborg_fb_enabled(s))
|
184 | 4af39611 | Paul Brook | return;
|
185 | 4af39611 | Paul Brook | |
186 | 4af39611 | Paul Brook | switch (ds_get_bits_per_pixel(s->ds)) {
|
187 | 4af39611 | Paul Brook | case 0: |
188 | 4af39611 | Paul Brook | return;
|
189 | 4af39611 | Paul Brook | case 8: |
190 | 4af39611 | Paul Brook | fntable = pl110_draw_fn_8; |
191 | 4af39611 | Paul Brook | dest_width = 1;
|
192 | 4af39611 | Paul Brook | break;
|
193 | 4af39611 | Paul Brook | case 15: |
194 | 4af39611 | Paul Brook | fntable = pl110_draw_fn_15; |
195 | 4af39611 | Paul Brook | dest_width = 2;
|
196 | 4af39611 | Paul Brook | break;
|
197 | 4af39611 | Paul Brook | case 16: |
198 | 4af39611 | Paul Brook | fntable = pl110_draw_fn_16; |
199 | 4af39611 | Paul Brook | dest_width = 2;
|
200 | 4af39611 | Paul Brook | break;
|
201 | 4af39611 | Paul Brook | case 24: |
202 | 4af39611 | Paul Brook | fntable = pl110_draw_fn_24; |
203 | 4af39611 | Paul Brook | dest_width = 3;
|
204 | 4af39611 | Paul Brook | break;
|
205 | 4af39611 | Paul Brook | case 32: |
206 | 4af39611 | Paul Brook | fntable = pl110_draw_fn_32; |
207 | 4af39611 | Paul Brook | dest_width = 4;
|
208 | 4af39611 | Paul Brook | break;
|
209 | 4af39611 | Paul Brook | default:
|
210 | 4af39611 | Paul Brook | fprintf(stderr, "syborg_fb: Bad color depth\n");
|
211 | 4af39611 | Paul Brook | exit(1);
|
212 | 4af39611 | Paul Brook | } |
213 | 4af39611 | Paul Brook | |
214 | 4af39611 | Paul Brook | if (s->need_int) {
|
215 | 4af39611 | Paul Brook | s->int_status |= FB_INT_BASE_UPDATE_DONE; |
216 | 4af39611 | Paul Brook | syborg_fb_update(s); |
217 | 4af39611 | Paul Brook | s->need_int = 0;
|
218 | 4af39611 | Paul Brook | } |
219 | 4af39611 | Paul Brook | |
220 | 4af39611 | Paul Brook | if (s->rgb) {
|
221 | 4fbf5556 | Peter Maydell | bpp_offset = 24;
|
222 | 4af39611 | Paul Brook | } else {
|
223 | 4af39611 | Paul Brook | bpp_offset = 0;
|
224 | 4af39611 | Paul Brook | } |
225 | 4af39611 | Paul Brook | if (s->endian) {
|
226 | 4fbf5556 | Peter Maydell | bpp_offset += 8;
|
227 | 4fbf5556 | Peter Maydell | } |
228 | 4fbf5556 | Peter Maydell | /* Our bpp constants mostly match the PL110/PL111 but
|
229 | 4fbf5556 | Peter Maydell | * not for the 16 bit case
|
230 | 4fbf5556 | Peter Maydell | */
|
231 | 4fbf5556 | Peter Maydell | switch (s->bpp) {
|
232 | 4fbf5556 | Peter Maydell | case BPP_SRC_16:
|
233 | 4af39611 | Paul Brook | bpp_offset += 6;
|
234 | 4fbf5556 | Peter Maydell | break;
|
235 | 4fbf5556 | Peter Maydell | default:
|
236 | 4fbf5556 | Peter Maydell | bpp_offset += s->bpp; |
237 | 4af39611 | Paul Brook | } |
238 | 4fbf5556 | Peter Maydell | fn = fntable[bpp_offset]; |
239 | 4af39611 | Paul Brook | |
240 | 4af39611 | Paul Brook | if (s->pitch) {
|
241 | 4af39611 | Paul Brook | src_width = s->pitch; |
242 | 4af39611 | Paul Brook | } else {
|
243 | 4af39611 | Paul Brook | src_width = s->cols; |
244 | 4af39611 | Paul Brook | switch (s->bpp) {
|
245 | 4af39611 | Paul Brook | case BPP_SRC_1:
|
246 | 4af39611 | Paul Brook | src_width >>= 3;
|
247 | 4af39611 | Paul Brook | break;
|
248 | 4af39611 | Paul Brook | case BPP_SRC_2:
|
249 | 4af39611 | Paul Brook | src_width >>= 2;
|
250 | 4af39611 | Paul Brook | break;
|
251 | 4af39611 | Paul Brook | case BPP_SRC_4:
|
252 | 4af39611 | Paul Brook | src_width >>= 1;
|
253 | 4af39611 | Paul Brook | break;
|
254 | 4af39611 | Paul Brook | case BPP_SRC_8:
|
255 | 4af39611 | Paul Brook | break;
|
256 | 4af39611 | Paul Brook | case BPP_SRC_15:
|
257 | 4af39611 | Paul Brook | case BPP_SRC_16:
|
258 | 4af39611 | Paul Brook | src_width <<= 1;
|
259 | 4af39611 | Paul Brook | break;
|
260 | 4af39611 | Paul Brook | case BPP_SRC_24:
|
261 | 4af39611 | Paul Brook | src_width *= 3;
|
262 | 4af39611 | Paul Brook | break;
|
263 | 4af39611 | Paul Brook | case BPP_SRC_32:
|
264 | 4af39611 | Paul Brook | src_width <<= 2;
|
265 | 4af39611 | Paul Brook | break;
|
266 | 4af39611 | Paul Brook | } |
267 | 4af39611 | Paul Brook | } |
268 | 4af39611 | Paul Brook | dest_width *= s->cols; |
269 | 4af39611 | Paul Brook | first = 0;
|
270 | 4af39611 | Paul Brook | /* TODO: Implement blanking. */
|
271 | 4af39611 | Paul Brook | if (!s->blank) {
|
272 | 4af39611 | Paul Brook | if (s->need_update && s->bpp <= BPP_SRC_8) {
|
273 | 4af39611 | Paul Brook | syborg_fb_update_palette(s); |
274 | 4af39611 | Paul Brook | } |
275 | 4af39611 | Paul Brook | framebuffer_update_display(s->ds, |
276 | 4af39611 | Paul Brook | s->base, s->cols, s->rows, |
277 | 4af39611 | Paul Brook | src_width, dest_width, 0,
|
278 | 4af39611 | Paul Brook | s->need_update, |
279 | 4af39611 | Paul Brook | fn, s->palette, |
280 | 4af39611 | Paul Brook | &first, &last); |
281 | 4af39611 | Paul Brook | if (first >= 0) { |
282 | 4af39611 | Paul Brook | dpy_update(s->ds, 0, first, s->cols, last - first + 1); |
283 | 4af39611 | Paul Brook | } |
284 | 4af39611 | Paul Brook | |
285 | 4af39611 | Paul Brook | s->int_status |= FB_INT_VSYNC; |
286 | 4af39611 | Paul Brook | syborg_fb_update(s); |
287 | 4af39611 | Paul Brook | } |
288 | 4af39611 | Paul Brook | |
289 | 4af39611 | Paul Brook | s->need_update = 0;
|
290 | 4af39611 | Paul Brook | } |
291 | 4af39611 | Paul Brook | |
292 | 4af39611 | Paul Brook | static void syborg_fb_invalidate_display(void * opaque) |
293 | 4af39611 | Paul Brook | { |
294 | 4af39611 | Paul Brook | SyborgFBState *s = (SyborgFBState *)opaque; |
295 | 4af39611 | Paul Brook | s->need_update = 1;
|
296 | 4af39611 | Paul Brook | } |
297 | 4af39611 | Paul Brook | |
298 | 0520a049 | Benoît Canet | static uint64_t syborg_fb_read(void *opaque, target_phys_addr_t offset, |
299 | 0520a049 | Benoît Canet | unsigned size)
|
300 | 4af39611 | Paul Brook | { |
301 | 4af39611 | Paul Brook | SyborgFBState *s = opaque; |
302 | 4af39611 | Paul Brook | |
303 | 4af39611 | Paul Brook | DPRINTF("read reg %d\n", (int)offset); |
304 | 4af39611 | Paul Brook | offset &= 0xfff;
|
305 | 4af39611 | Paul Brook | switch (offset >> 2) { |
306 | 4af39611 | Paul Brook | case FB_ID:
|
307 | 4af39611 | Paul Brook | return SYBORG_ID_FRAMEBUFFER;
|
308 | 4af39611 | Paul Brook | |
309 | 4af39611 | Paul Brook | case FB_BASE:
|
310 | 4af39611 | Paul Brook | return s->base;
|
311 | 4af39611 | Paul Brook | |
312 | 4af39611 | Paul Brook | case FB_HEIGHT:
|
313 | 4af39611 | Paul Brook | return s->rows;
|
314 | 4af39611 | Paul Brook | |
315 | 4af39611 | Paul Brook | case FB_WIDTH:
|
316 | 4af39611 | Paul Brook | return s->cols;
|
317 | 4af39611 | Paul Brook | |
318 | 4af39611 | Paul Brook | case FB_ORIENTATION:
|
319 | 4af39611 | Paul Brook | return 0; |
320 | 4af39611 | Paul Brook | |
321 | 4af39611 | Paul Brook | case FB_BLANK:
|
322 | 4af39611 | Paul Brook | return s->blank;
|
323 | 4af39611 | Paul Brook | |
324 | 4af39611 | Paul Brook | case FB_INT_MASK:
|
325 | 4af39611 | Paul Brook | return s->int_enable;
|
326 | 4af39611 | Paul Brook | |
327 | 4af39611 | Paul Brook | case FB_INTERRUPT_CAUSE:
|
328 | 4af39611 | Paul Brook | return s->int_status;
|
329 | 4af39611 | Paul Brook | |
330 | 4af39611 | Paul Brook | case FB_BPP:
|
331 | 4af39611 | Paul Brook | switch (s->bpp) {
|
332 | 4af39611 | Paul Brook | case BPP_SRC_1: return 1; |
333 | 4af39611 | Paul Brook | case BPP_SRC_2: return 2; |
334 | 4af39611 | Paul Brook | case BPP_SRC_4: return 4; |
335 | 4af39611 | Paul Brook | case BPP_SRC_8: return 8; |
336 | 4af39611 | Paul Brook | case BPP_SRC_15: return 15; |
337 | 4af39611 | Paul Brook | case BPP_SRC_16: return 16; |
338 | 4af39611 | Paul Brook | case BPP_SRC_24: return 24; |
339 | 4af39611 | Paul Brook | case BPP_SRC_32: return 32; |
340 | 4af39611 | Paul Brook | default: return 0; |
341 | 4af39611 | Paul Brook | } |
342 | 4af39611 | Paul Brook | |
343 | 4af39611 | Paul Brook | case FB_COLOR_ORDER:
|
344 | 4af39611 | Paul Brook | return s->rgb;
|
345 | 4af39611 | Paul Brook | |
346 | 4af39611 | Paul Brook | case FB_BYTE_ORDER:
|
347 | 4af39611 | Paul Brook | return s->endian;
|
348 | 4af39611 | Paul Brook | |
349 | 4af39611 | Paul Brook | case FB_PIXEL_ORDER:
|
350 | 4af39611 | Paul Brook | return 0; |
351 | 4af39611 | Paul Brook | |
352 | 4af39611 | Paul Brook | case FB_ROW_PITCH:
|
353 | 4af39611 | Paul Brook | return s->pitch;
|
354 | 4af39611 | Paul Brook | |
355 | 4af39611 | Paul Brook | case FB_ENABLED:
|
356 | 4af39611 | Paul Brook | return s->enabled;
|
357 | 4af39611 | Paul Brook | |
358 | 4af39611 | Paul Brook | default:
|
359 | 4af39611 | Paul Brook | if ((offset >> 2) >= FB_PALETTE_START |
360 | 4af39611 | Paul Brook | && (offset >> 2) <= FB_PALETTE_END) {
|
361 | 4af39611 | Paul Brook | return s->raw_palette[(offset >> 2) - FB_PALETTE_START]; |
362 | 4af39611 | Paul Brook | } else {
|
363 | 4af39611 | Paul Brook | cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
|
364 | 4af39611 | Paul Brook | (int)offset);
|
365 | 4af39611 | Paul Brook | } |
366 | 4af39611 | Paul Brook | return 0; |
367 | 4af39611 | Paul Brook | } |
368 | 4af39611 | Paul Brook | } |
369 | 4af39611 | Paul Brook | |
370 | c227f099 | Anthony Liguori | static void syborg_fb_write(void *opaque, target_phys_addr_t offset, |
371 | 0520a049 | Benoît Canet | uint64_t val, unsigned size)
|
372 | 4af39611 | Paul Brook | { |
373 | 4af39611 | Paul Brook | SyborgFBState *s = opaque; |
374 | 4af39611 | Paul Brook | |
375 | 4af39611 | Paul Brook | DPRINTF("write reg %d = %d\n", (int)offset, val); |
376 | 4af39611 | Paul Brook | s->need_update = 1;
|
377 | 4af39611 | Paul Brook | offset &= 0xfff;
|
378 | 4af39611 | Paul Brook | switch (offset >> 2) { |
379 | 4af39611 | Paul Brook | case FB_BASE:
|
380 | 4af39611 | Paul Brook | s->base = val; |
381 | 4af39611 | Paul Brook | s->need_int = 1;
|
382 | 4af39611 | Paul Brook | s->need_update = 1;
|
383 | 4af39611 | Paul Brook | syborg_fb_update(s); |
384 | 4af39611 | Paul Brook | break;
|
385 | 4af39611 | Paul Brook | |
386 | 4af39611 | Paul Brook | case FB_HEIGHT:
|
387 | 4af39611 | Paul Brook | s->rows = val; |
388 | 4af39611 | Paul Brook | break;
|
389 | 4af39611 | Paul Brook | |
390 | 4af39611 | Paul Brook | case FB_WIDTH:
|
391 | 4af39611 | Paul Brook | s->cols = val; |
392 | 4af39611 | Paul Brook | break;
|
393 | 4af39611 | Paul Brook | |
394 | 4af39611 | Paul Brook | case FB_ORIENTATION:
|
395 | 4af39611 | Paul Brook | /* TODO: Implement rotation. */
|
396 | 4af39611 | Paul Brook | break;
|
397 | 4af39611 | Paul Brook | |
398 | 4af39611 | Paul Brook | case FB_BLANK:
|
399 | 4af39611 | Paul Brook | s->blank = val & 1;
|
400 | 4af39611 | Paul Brook | break;
|
401 | 4af39611 | Paul Brook | |
402 | 4af39611 | Paul Brook | case FB_INT_MASK:
|
403 | 4af39611 | Paul Brook | s->int_enable = val; |
404 | 4af39611 | Paul Brook | syborg_fb_update(s); |
405 | 4af39611 | Paul Brook | break;
|
406 | 4af39611 | Paul Brook | |
407 | 4af39611 | Paul Brook | case FB_INTERRUPT_CAUSE:
|
408 | 4af39611 | Paul Brook | s->int_status &= ~val; |
409 | 4af39611 | Paul Brook | syborg_fb_update(s); |
410 | 4af39611 | Paul Brook | break;
|
411 | 4af39611 | Paul Brook | |
412 | 4af39611 | Paul Brook | case FB_BPP:
|
413 | 4af39611 | Paul Brook | switch (val) {
|
414 | 4af39611 | Paul Brook | case 1: val = BPP_SRC_1; break; |
415 | 4af39611 | Paul Brook | case 2: val = BPP_SRC_2; break; |
416 | 4af39611 | Paul Brook | case 4: val = BPP_SRC_4; break; |
417 | 4af39611 | Paul Brook | case 8: val = BPP_SRC_8; break; |
418 | 4af39611 | Paul Brook | /* case 15: val = BPP_SRC_15; break; */
|
419 | 4af39611 | Paul Brook | case 16: val = BPP_SRC_16; break; |
420 | 4af39611 | Paul Brook | /* case 24: val = BPP_SRC_24; break; */
|
421 | 4af39611 | Paul Brook | case 32: val = BPP_SRC_32; break; |
422 | 4af39611 | Paul Brook | default: val = s->bpp; break; |
423 | 4af39611 | Paul Brook | } |
424 | 4af39611 | Paul Brook | s->bpp = val; |
425 | 4af39611 | Paul Brook | break;
|
426 | 4af39611 | Paul Brook | |
427 | 4af39611 | Paul Brook | case FB_COLOR_ORDER:
|
428 | 4af39611 | Paul Brook | s->rgb = (val != 0);
|
429 | 4af39611 | Paul Brook | break;
|
430 | 4af39611 | Paul Brook | |
431 | 4af39611 | Paul Brook | case FB_BYTE_ORDER:
|
432 | 4af39611 | Paul Brook | s->endian = (val != 0);
|
433 | 4af39611 | Paul Brook | break;
|
434 | 4af39611 | Paul Brook | |
435 | 4af39611 | Paul Brook | case FB_PIXEL_ORDER:
|
436 | 4af39611 | Paul Brook | /* TODO: Implement this. */
|
437 | 4af39611 | Paul Brook | break;
|
438 | 4af39611 | Paul Brook | |
439 | 4af39611 | Paul Brook | case FB_ROW_PITCH:
|
440 | 4af39611 | Paul Brook | s->pitch = val; |
441 | 4af39611 | Paul Brook | break;
|
442 | 4af39611 | Paul Brook | |
443 | 4af39611 | Paul Brook | case FB_ENABLED:
|
444 | 4af39611 | Paul Brook | s->enabled = val; |
445 | 4af39611 | Paul Brook | break;
|
446 | 4af39611 | Paul Brook | |
447 | 4af39611 | Paul Brook | default:
|
448 | 4af39611 | Paul Brook | if ((offset >> 2) >= FB_PALETTE_START |
449 | 4af39611 | Paul Brook | && (offset >> 2) <= FB_PALETTE_END) {
|
450 | 4af39611 | Paul Brook | s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
|
451 | 4af39611 | Paul Brook | } else {
|
452 | 4af39611 | Paul Brook | cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
|
453 | 4af39611 | Paul Brook | (int)offset);
|
454 | 4af39611 | Paul Brook | } |
455 | 4af39611 | Paul Brook | break;
|
456 | 4af39611 | Paul Brook | } |
457 | 4af39611 | Paul Brook | } |
458 | 4af39611 | Paul Brook | |
459 | 0520a049 | Benoît Canet | static const MemoryRegionOps syborg_fb_ops = { |
460 | 0520a049 | Benoît Canet | .read = syborg_fb_read, |
461 | 0520a049 | Benoît Canet | .write = syborg_fb_write, |
462 | 0520a049 | Benoît Canet | .endianness = DEVICE_NATIVE_ENDIAN, |
463 | 4af39611 | Paul Brook | }; |
464 | 4af39611 | Paul Brook | |
465 | 4af39611 | Paul Brook | static void syborg_fb_save(QEMUFile *f, void *opaque) |
466 | 4af39611 | Paul Brook | { |
467 | 4af39611 | Paul Brook | SyborgFBState *s = opaque; |
468 | 4af39611 | Paul Brook | int i;
|
469 | 4af39611 | Paul Brook | |
470 | 4af39611 | Paul Brook | qemu_put_be32(f, s->need_int); |
471 | 4af39611 | Paul Brook | qemu_put_be32(f, s->int_status); |
472 | 4af39611 | Paul Brook | qemu_put_be32(f, s->int_enable); |
473 | 4af39611 | Paul Brook | qemu_put_be32(f, s->enabled); |
474 | 4af39611 | Paul Brook | qemu_put_be32(f, s->base); |
475 | 4af39611 | Paul Brook | qemu_put_be32(f, s->pitch); |
476 | 4af39611 | Paul Brook | qemu_put_be32(f, s->rows); |
477 | 4af39611 | Paul Brook | qemu_put_be32(f, s->cols); |
478 | 4af39611 | Paul Brook | qemu_put_be32(f, s->bpp); |
479 | 4af39611 | Paul Brook | qemu_put_be32(f, s->rgb); |
480 | 4af39611 | Paul Brook | for (i = 0; i < 256; i++) { |
481 | 4af39611 | Paul Brook | qemu_put_be32(f, s->raw_palette[i]); |
482 | 4af39611 | Paul Brook | } |
483 | 4af39611 | Paul Brook | } |
484 | 4af39611 | Paul Brook | |
485 | 4af39611 | Paul Brook | static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id) |
486 | 4af39611 | Paul Brook | { |
487 | 4af39611 | Paul Brook | SyborgFBState *s = opaque; |
488 | 4af39611 | Paul Brook | int i;
|
489 | 4af39611 | Paul Brook | |
490 | 4af39611 | Paul Brook | if (version_id != 1) |
491 | 4af39611 | Paul Brook | return -EINVAL;
|
492 | 4af39611 | Paul Brook | |
493 | 4af39611 | Paul Brook | s->need_int = qemu_get_be32(f); |
494 | 4af39611 | Paul Brook | s->int_status = qemu_get_be32(f); |
495 | 4af39611 | Paul Brook | s->int_enable = qemu_get_be32(f); |
496 | 4af39611 | Paul Brook | s->enabled = qemu_get_be32(f); |
497 | 4af39611 | Paul Brook | s->base = qemu_get_be32(f); |
498 | 4af39611 | Paul Brook | s->pitch = qemu_get_be32(f); |
499 | 4af39611 | Paul Brook | s->rows = qemu_get_be32(f); |
500 | 4af39611 | Paul Brook | s->cols = qemu_get_be32(f); |
501 | 4af39611 | Paul Brook | s->bpp = qemu_get_be32(f); |
502 | 4af39611 | Paul Brook | s->rgb = qemu_get_be32(f); |
503 | 4af39611 | Paul Brook | for (i = 0; i < 256; i++) { |
504 | 4af39611 | Paul Brook | s->raw_palette[i] = qemu_get_be32(f); |
505 | 4af39611 | Paul Brook | } |
506 | 4af39611 | Paul Brook | s->need_update = 1;
|
507 | 4af39611 | Paul Brook | |
508 | 4af39611 | Paul Brook | return 0; |
509 | 4af39611 | Paul Brook | } |
510 | 4af39611 | Paul Brook | |
511 | 81a322d4 | Gerd Hoffmann | static int syborg_fb_init(SysBusDevice *dev) |
512 | 4af39611 | Paul Brook | { |
513 | 4af39611 | Paul Brook | SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev); |
514 | 4af39611 | Paul Brook | |
515 | 4af39611 | Paul Brook | sysbus_init_irq(dev, &s->irq); |
516 | 0520a049 | Benoît Canet | memory_region_init_io(&s->iomem, &syborg_fb_ops, s, |
517 | 0520a049 | Benoît Canet | "framebuffer", 0x1000); |
518 | 0520a049 | Benoît Canet | sysbus_init_mmio_region(dev, &s->iomem); |
519 | 4af39611 | Paul Brook | |
520 | 4af39611 | Paul Brook | s->ds = graphic_console_init(syborg_fb_update_display, |
521 | 4af39611 | Paul Brook | syborg_fb_invalidate_display, |
522 | 4af39611 | Paul Brook | NULL, NULL, s); |
523 | 4af39611 | Paul Brook | |
524 | ee6847d1 | Gerd Hoffmann | if (s->cols != 0 && s->rows != 0) { |
525 | ee6847d1 | Gerd Hoffmann | qemu_console_resize(s->ds, s->cols, s->rows); |
526 | 4af39611 | Paul Brook | } |
527 | 4af39611 | Paul Brook | |
528 | ee6847d1 | Gerd Hoffmann | if (!s->cols)
|
529 | ee6847d1 | Gerd Hoffmann | s->cols = ds_get_width(s->ds); |
530 | ee6847d1 | Gerd Hoffmann | if (!s->rows)
|
531 | ee6847d1 | Gerd Hoffmann | s->rows = ds_get_height(s->ds); |
532 | 4af39611 | Paul Brook | |
533 | 0be71e32 | Alex Williamson | register_savevm(&dev->qdev, "syborg_framebuffer", -1, 1, |
534 | 4af39611 | Paul Brook | syborg_fb_save, syborg_fb_load, s); |
535 | 81a322d4 | Gerd Hoffmann | return 0; |
536 | 4af39611 | Paul Brook | } |
537 | 4af39611 | Paul Brook | |
538 | ee6847d1 | Gerd Hoffmann | static SysBusDeviceInfo syborg_fb_info = {
|
539 | ee6847d1 | Gerd Hoffmann | .init = syborg_fb_init, |
540 | ee6847d1 | Gerd Hoffmann | .qdev.name = "syborg,framebuffer",
|
541 | ee6847d1 | Gerd Hoffmann | .qdev.size = sizeof(SyborgFBState),
|
542 | ee6847d1 | Gerd Hoffmann | .qdev.props = (Property[]) { |
543 | c230c4e3 | Gerd Hoffmann | DEFINE_PROP_UINT32("width", SyborgFBState, cols, 0), |
544 | c230c4e3 | Gerd Hoffmann | DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0), |
545 | c230c4e3 | Gerd Hoffmann | DEFINE_PROP_END_OF_LIST(), |
546 | ee6847d1 | Gerd Hoffmann | } |
547 | ee6847d1 | Gerd Hoffmann | }; |
548 | ee6847d1 | Gerd Hoffmann | |
549 | 4af39611 | Paul Brook | static void syborg_fb_register_devices(void) |
550 | 4af39611 | Paul Brook | { |
551 | ee6847d1 | Gerd Hoffmann | sysbus_register_withprop(&syborg_fb_info); |
552 | 4af39611 | Paul Brook | } |
553 | 4af39611 | Paul Brook | |
554 | 4af39611 | Paul Brook | device_init(syborg_fb_register_devices) |