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