1 | /* |
2 | * QEMU EDID generator. |
3 | * |
4 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
5 | * See the COPYING file in the top-level directory. |
6 | */ |
7 | #include "qemu/osdep.h" |
8 | #include "qemu/bswap.h" |
9 | #include "hw/display/edid.h" |
10 | |
11 | static const struct edid_mode { |
12 | uint32_t xres; |
13 | uint32_t yres; |
14 | uint32_t byte; |
15 | uint32_t xtra3; |
16 | uint32_t bit; |
17 | uint32_t dta; |
18 | } modes[] = { |
19 | /* dea/dta extension timings (all @ 50 Hz) */ |
20 | { .xres = 5120, .yres = 2160, .dta = 125 }, |
21 | { .xres = 4096, .yres = 2160, .dta = 101 }, |
22 | { .xres = 3840, .yres = 2160, .dta = 96 }, |
23 | { .xres = 2560, .yres = 1080, .dta = 89 }, |
24 | { .xres = 2048, .yres = 1152 }, |
25 | { .xres = 1920, .yres = 1080, .dta = 31 }, |
26 | |
27 | /* additional standard timings 3 (all @ 60Hz) */ |
28 | { .xres = 1920, .yres = 1440, .xtra3 = 11, .bit = 5 }, |
29 | { .xres = 1920, .yres = 1200, .xtra3 = 10, .bit = 0 }, |
30 | { .xres = 1856, .yres = 1392, .xtra3 = 10, .bit = 3 }, |
31 | { .xres = 1792, .yres = 1344, .xtra3 = 10, .bit = 5 }, |
32 | { .xres = 1600, .yres = 1200, .xtra3 = 9, .bit = 2 }, |
33 | { .xres = 1680, .yres = 1050, .xtra3 = 9, .bit = 5 }, |
34 | { .xres = 1440, .yres = 1050, .xtra3 = 8, .bit = 1 }, |
35 | { .xres = 1440, .yres = 900, .xtra3 = 8, .bit = 5 }, |
36 | { .xres = 1360, .yres = 768, .xtra3 = 8, .bit = 7 }, |
37 | { .xres = 1280, .yres = 1024, .xtra3 = 7, .bit = 1 }, |
38 | { .xres = 1280, .yres = 960, .xtra3 = 7, .bit = 3 }, |
39 | { .xres = 1280, .yres = 768, .xtra3 = 7, .bit = 6 }, |
40 | |
41 | /* established timings (all @ 60Hz) */ |
42 | { .xres = 1024, .yres = 768, .byte = 36, .bit = 3 }, |
43 | { .xres = 800, .yres = 600, .byte = 35, .bit = 0 }, |
44 | { .xres = 640, .yres = 480, .byte = 35, .bit = 5 }, |
45 | }; |
46 | |
47 | static void edid_ext_dta(uint8_t *dta) |
48 | { |
49 | dta[0] = 0x02; |
50 | dta[1] = 0x03; |
51 | dta[2] = 0x05; |
52 | dta[3] = 0x00; |
53 | |
54 | /* video data block */ |
55 | dta[4] = 0x40; |
56 | } |
57 | |
58 | static void edid_ext_dta_mode(uint8_t *dta, uint8_t nr) |
59 | { |
60 | dta[dta[2]] = nr; |
61 | dta[2]++; |
62 | dta[4]++; |
63 | } |
64 | |
65 | static int edid_std_mode(uint8_t *mode, uint32_t xres, uint32_t yres) |
66 | { |
67 | uint32_t aspect; |
68 | |
69 | if (xres == 0 || yres == 0) { |
70 | mode[0] = 0x01; |
71 | mode[1] = 0x01; |
72 | return 0; |
73 | |
74 | } else if (xres * 10 == yres * 16) { |
75 | aspect = 0; |
76 | } else if (xres * 3 == yres * 4) { |
77 | aspect = 1; |
78 | } else if (xres * 4 == yres * 5) { |
79 | aspect = 2; |
80 | } else if (xres * 9 == yres * 16) { |
81 | aspect = 3; |
82 | } else { |
83 | return -1; |
84 | } |
85 | |
86 | if ((xres / 8) - 31 > 255) { |
87 | return -1; |
88 | } |
89 | |
90 | mode[0] = (xres / 8) - 31; |
91 | mode[1] = ((aspect << 6) | (60 - 60)); |
92 | return 0; |
93 | } |
94 | |
95 | static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta, |
96 | uint32_t maxx, uint32_t maxy) |
97 | { |
98 | const struct edid_mode *mode; |
99 | int std = 38; |
100 | int rc, i; |
101 | |
102 | for (i = 0; i < ARRAY_SIZE(modes); i++) { |
103 | mode = modes + i; |
104 | |
105 | if ((maxx && mode->xres > maxx) || |
106 | (maxy && mode->yres > maxy)) { |
107 | continue; |
108 | } |
109 | |
110 | if (mode->byte) { |
111 | edid[mode->byte] |= (1 << mode->bit); |
112 | } else if (mode->xtra3 && xtra3) { |
113 | xtra3[mode->xtra3] |= (1 << mode->bit); |
114 | } else if (std < 54) { |
115 | rc = edid_std_mode(edid + std, mode->xres, mode->yres); |
116 | if (rc == 0) { |
117 | std += 2; |
118 | } |
119 | } |
120 | |
121 | if (dta && mode->dta) { |
122 | edid_ext_dta_mode(dta, mode->dta); |
123 | } |
124 | } |
125 | |
126 | while (std < 54) { |
127 | edid_std_mode(edid + std, 0, 0); |
128 | std += 2; |
129 | } |
130 | } |
131 | |
132 | static void edid_checksum(uint8_t *edid) |
133 | { |
134 | uint32_t sum = 0; |
135 | int i; |
136 | |
137 | for (i = 0; i < 127; i++) { |
138 | sum += edid[i]; |
139 | } |
140 | sum &= 0xff; |
141 | if (sum) { |
142 | edid[127] = 0x100 - sum; |
143 | } |
144 | } |
145 | |
146 | static void edid_desc_type(uint8_t *desc, uint8_t type) |
147 | { |
148 | desc[0] = 0; |
149 | desc[1] = 0; |
150 | desc[2] = 0; |
151 | desc[3] = type; |
152 | desc[4] = 0; |
153 | } |
154 | |
155 | static void edid_desc_text(uint8_t *desc, uint8_t type, |
156 | const char *text) |
157 | { |
158 | size_t len; |
159 | |
160 | edid_desc_type(desc, type); |
161 | memset(desc + 5, ' ', 13); |
162 | |
163 | len = strlen(text); |
164 | if (len > 12) { |
165 | len = 12; |
166 | } |
167 | memcpy(desc + 5, text, len); |
168 | desc[5 + len] = '\n'; |
169 | } |
170 | |
171 | static void edid_desc_ranges(uint8_t *desc) |
172 | { |
173 | edid_desc_type(desc, 0xfd); |
174 | |
175 | /* vertical (50 -> 125 Hz) */ |
176 | desc[5] = 50; |
177 | desc[6] = 125; |
178 | |
179 | /* horizontal (30 -> 160 kHz) */ |
180 | desc[7] = 30; |
181 | desc[8] = 160; |
182 | |
183 | /* max dot clock (1200 MHz) */ |
184 | desc[9] = 1200 / 10; |
185 | |
186 | /* no extended timing information */ |
187 | desc[10] = 0x01; |
188 | |
189 | /* padding */ |
190 | desc[11] = '\n'; |
191 | memset(desc + 12, ' ', 6); |
192 | } |
193 | |
194 | /* additional standard timings 3 */ |
195 | static void edid_desc_xtra3_std(uint8_t *desc) |
196 | { |
197 | edid_desc_type(desc, 0xf7); |
198 | desc[5] = 10; |
199 | } |
200 | |
201 | static void edid_desc_dummy(uint8_t *desc) |
202 | { |
203 | edid_desc_type(desc, 0x10); |
204 | } |
205 | |
206 | static void edid_desc_timing(uint8_t *desc, |
207 | uint32_t xres, uint32_t yres, |
208 | uint32_t dpi) |
209 | { |
210 | /* physical display size */ |
211 | uint32_t xmm = xres * dpi / 254; |
212 | uint32_t ymm = yres * dpi / 254; |
213 | |
214 | /* pull some realistic looking timings out of thin air */ |
215 | uint32_t xfront = xres * 25 / 100; |
216 | uint32_t xsync = xres * 3 / 100; |
217 | uint32_t xblank = xres * 35 / 100; |
218 | |
219 | uint32_t yfront = yres * 5 / 1000; |
220 | uint32_t ysync = yres * 5 / 1000; |
221 | uint32_t yblank = yres * 35 / 1000; |
222 | |
223 | uint32_t clock = 75 * (xres + xblank) * (yres + yblank); |
224 | |
225 | stl_le_p(desc, clock / 10000); |
226 | |
227 | desc[2] = xres & 0xff; |
228 | desc[3] = xblank & 0xff; |
229 | desc[4] = (((xres & 0xf00) >> 4) | |
230 | ((xblank & 0xf00) >> 8)); |
231 | |
232 | desc[5] = yres & 0xff; |
233 | desc[6] = yblank & 0xff; |
234 | desc[7] = (((yres & 0xf00) >> 4) | |
235 | ((yblank & 0xf00) >> 8)); |
236 | |
237 | desc[8] = xfront & 0xff; |
238 | desc[9] = xsync & 0xff; |
239 | |
240 | desc[10] = (((yfront & 0x00f) << 4) | |
241 | ((ysync & 0x00f) << 0)); |
242 | desc[11] = (((xfront & 0x300) >> 2) | |
243 | ((xsync & 0x300) >> 4) | |
244 | ((yfront & 0x030) >> 2) | |
245 | ((ysync & 0x030) >> 4)); |
246 | |
247 | desc[12] = xmm & 0xff; |
248 | desc[13] = ymm & 0xff; |
249 | desc[14] = (((xmm & 0xf00) >> 4) | |
250 | ((ymm & 0xf00) >> 8)); |
251 | |
252 | desc[17] = 0x18; |
253 | } |
254 | |
255 | static uint32_t edid_to_10bit(float value) |
256 | { |
257 | return (uint32_t)(value * 1024 + 0.5); |
258 | } |
259 | |
260 | static void edid_colorspace(uint8_t *edid, |
261 | float rx, float ry, |
262 | float gx, float gy, |
263 | float bx, float by, |
264 | float wx, float wy) |
265 | { |
266 | uint32_t red_x = edid_to_10bit(rx); |
267 | uint32_t red_y = edid_to_10bit(ry); |
268 | uint32_t green_x = edid_to_10bit(gx); |
269 | uint32_t green_y = edid_to_10bit(gy); |
270 | uint32_t blue_x = edid_to_10bit(bx); |
271 | uint32_t blue_y = edid_to_10bit(by); |
272 | uint32_t white_x = edid_to_10bit(wx); |
273 | uint32_t white_y = edid_to_10bit(wy); |
274 | |
275 | edid[25] = (((red_x & 0x03) << 6) | |
276 | ((red_y & 0x03) << 4) | |
277 | ((green_x & 0x03) << 2) | |
278 | ((green_y & 0x03) << 0)); |
279 | edid[26] = (((blue_x & 0x03) << 6) | |
280 | ((blue_y & 0x03) << 4) | |
281 | ((white_x & 0x03) << 2) | |
282 | ((white_y & 0x03) << 0)); |
283 | edid[27] = red_x >> 2; |
284 | edid[28] = red_y >> 2; |
285 | edid[29] = green_x >> 2; |
286 | edid[30] = green_y >> 2; |
287 | edid[31] = blue_x >> 2; |
288 | edid[32] = blue_y >> 2; |
289 | edid[33] = white_x >> 2; |
290 | edid[34] = white_y >> 2; |
291 | } |
292 | |
293 | void qemu_edid_generate(uint8_t *edid, size_t size, |
294 | qemu_edid_info *info) |
295 | { |
296 | uint32_t desc = 54; |
297 | uint8_t *xtra3 = NULL; |
298 | uint8_t *dta = NULL; |
299 | |
300 | /* =============== set defaults =============== */ |
301 | |
302 | if (!info->vendor || strlen(info->vendor) != 3) { |
303 | info->vendor = "RHT" ; |
304 | } |
305 | if (!info->name) { |
306 | info->name = "QEMU Monitor" ; |
307 | } |
308 | if (!info->dpi) { |
309 | info->dpi = 100; |
310 | } |
311 | if (!info->prefx) { |
312 | info->prefx = 1024; |
313 | } |
314 | if (!info->prefy) { |
315 | info->prefy = 768; |
316 | } |
317 | |
318 | /* =============== extensions =============== */ |
319 | |
320 | if (size >= 256) { |
321 | dta = edid + 128; |
322 | edid[126]++; |
323 | edid_ext_dta(dta); |
324 | } |
325 | |
326 | /* =============== header information =============== */ |
327 | |
328 | /* fixed */ |
329 | edid[0] = 0x00; |
330 | edid[1] = 0xff; |
331 | edid[2] = 0xff; |
332 | edid[3] = 0xff; |
333 | edid[4] = 0xff; |
334 | edid[5] = 0xff; |
335 | edid[6] = 0xff; |
336 | edid[7] = 0x00; |
337 | |
338 | /* manufacturer id, product code, serial number */ |
339 | uint16_t vendor_id = ((((info->vendor[0] - '@') & 0x1f) << 10) | |
340 | (((info->vendor[1] - '@') & 0x1f) << 5) | |
341 | (((info->vendor[2] - '@') & 0x1f) << 0)); |
342 | uint16_t model_nr = 0x1234; |
343 | uint32_t serial_nr = info->serial ? atoi(info->serial) : 0; |
344 | stw_be_p(edid + 8, vendor_id); |
345 | stw_le_p(edid + 10, model_nr); |
346 | stl_le_p(edid + 12, serial_nr); |
347 | |
348 | /* manufacture week and year */ |
349 | edid[16] = 42; |
350 | edid[17] = 2014 - 1990; |
351 | |
352 | /* edid version */ |
353 | edid[18] = 1; |
354 | edid[19] = 4; |
355 | |
356 | |
357 | /* =============== basic display parameters =============== */ |
358 | |
359 | /* video input: digital, 8bpc, displayport */ |
360 | edid[20] = 0xa5; |
361 | |
362 | /* screen size: undefined */ |
363 | edid[21] = info->prefx * info->dpi / 2540; |
364 | edid[22] = info->prefy * info->dpi / 2540; |
365 | |
366 | /* display gamma: 2.2 */ |
367 | edid[23] = 220 - 100; |
368 | |
369 | /* supported features bitmap: std sRGB, preferred timing */ |
370 | edid[24] = 0x06; |
371 | |
372 | |
373 | /* =============== chromaticity coordinates =============== */ |
374 | |
375 | /* standard sRGB colorspace */ |
376 | edid_colorspace(edid, |
377 | 0.6400, 0.3300, /* red */ |
378 | 0.3000, 0.6000, /* green */ |
379 | 0.1500, 0.0600, /* blue */ |
380 | 0.3127, 0.3290); /* white point */ |
381 | |
382 | /* =============== established timing bitmap =============== */ |
383 | /* =============== standard timing information =============== */ |
384 | |
385 | /* both filled by edid_fill_modes() */ |
386 | |
387 | |
388 | /* =============== descriptor blocks =============== */ |
389 | |
390 | edid_desc_timing(edid + desc, info->prefx, info->prefy, info->dpi); |
391 | desc += 18; |
392 | |
393 | edid_desc_ranges(edid + desc); |
394 | desc += 18; |
395 | |
396 | if (info->name) { |
397 | edid_desc_text(edid + desc, 0xfc, info->name); |
398 | desc += 18; |
399 | } |
400 | |
401 | if (info->serial) { |
402 | edid_desc_text(edid + desc, 0xff, info->serial); |
403 | desc += 18; |
404 | } |
405 | |
406 | if (desc < 126) { |
407 | xtra3 = edid + desc; |
408 | edid_desc_xtra3_std(xtra3); |
409 | desc += 18; |
410 | } |
411 | |
412 | while (desc < 126) { |
413 | edid_desc_dummy(edid + desc); |
414 | desc += 18; |
415 | } |
416 | |
417 | /* =============== finish up =============== */ |
418 | |
419 | edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); |
420 | edid_checksum(edid); |
421 | if (dta) { |
422 | edid_checksum(dta); |
423 | } |
424 | } |
425 | |
426 | size_t qemu_edid_size(uint8_t *edid) |
427 | { |
428 | uint32_t exts; |
429 | |
430 | if (edid[0] != 0x00 || |
431 | edid[1] != 0xff) { |
432 | /* doesn't look like a valid edid block */ |
433 | return 0; |
434 | } |
435 | |
436 | exts = edid[126]; |
437 | return 128 * (exts + 1); |
438 | } |
439 | |