6814b1964f9dd93a93b6a985b4c9de2e45380c89
[coreboot.git] / util / x86emu / yabel / vbe.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  * All rights reserved.
5  * This program and the accompanying materials
6  * are made available under the terms of the BSD License
7  * which accompanies this distribution, and is available at
8  * http://www.opensource.org/licenses/bsd-license.php
9  *
10  * Contributors:
11  *     IBM Corporation - initial implementation
12  *****************************************************************************/
13
14 #include <string.h>
15 #include <types.h>
16 #if CONFIG_BOOTSPLASH
17 #include <boot/coreboot_tables.h>
18 #endif
19
20 #include <arch/byteorder.h>
21 #define ntohl(x) be32_to_cpu(x)
22
23 #include "debug.h"
24
25 #include <x86emu/x86emu.h>
26 #include <x86emu/regs.h>
27 #include "../x86emu/prim_ops.h"
28
29 #include "biosemu.h"
30 #include "io.h"
31 #include "mem.h"
32 #include "interrupt.h"
33 #include "device.h"
34
35 #include <cbfs.h>
36
37 #include <delay.h>
38 #include "../../src/lib/jpeg.h"
39
40 // pointer to VBEInfoBuffer, set by vbe_prepare
41 u8 *vbe_info_buffer = 0;
42
43 // virtual BIOS Memory
44 u8 *biosmem;
45 u32 biosmem_size;
46
47 // these structs are for input from and output to OF
48 typedef struct {
49         u8 display_type;        // 0=NONE, 1= analog, 2=digital
50         u16 screen_width;
51         u16 screen_height;
52         u16 screen_linebytes;   // bytes per line in framebuffer, may be more than screen_width
53         u8 color_depth; // color depth in bpp
54         u32 framebuffer_address;
55         u8 edid_block_zero[128];
56 } __attribute__ ((__packed__)) screen_info_t;
57
58 typedef struct {
59         u8 signature[4];
60         u16 size_reserved;
61         u8 monitor_number;
62         u16 max_screen_width;
63         u8 color_depth;
64 } __attribute__ ((__packed__)) screen_info_input_t;
65
66 // these structs only store a subset of the VBE defined fields
67 // only those needed.
68 typedef struct {
69         char signature[4];
70         u16 version;
71         u8 *oem_string_ptr;
72         u32 capabilities;
73         u16 video_mode_list[256];       // lets hope we never have more than 256 video modes...
74         u16 total_memory;
75 } vbe_info_t;
76
77 typedef struct {
78         u16 mode_attributes; // 00
79         u8 win_a_attributes; // 02
80         u8 win_b_attributes; // 03
81         u16 win_granularity; // 04
82         u16 win_size;        // 06
83         u16 win_a_segment;   // 08
84         u16 win_b_segment;   // 0a
85         u32 win_func_ptr;    // 0c
86         u16 bytes_per_scanline; // 10
87         u16 x_resolution;    // 12
88         u16 y_resolution;    // 14
89         u8 x_charsize;       // 16
90         u8 y_charsize;       // 17
91         u8 number_of_planes; // 18
92         u8 bits_per_pixel;   // 19
93         u8 number_of_banks;  // 20
94         u8 memory_model;     // 21
95         u8 bank_size;        // 22
96         u8 number_of_image_pages; // 23
97         u8 reserved_page;
98         u8 red_mask_size;
99         u8 red_mask_pos;
100         u8 green_mask_size;
101         u8 green_mask_pos;
102         u8 blue_mask_size;
103         u8 blue_mask_pos;
104         u8 reserved_mask_size;
105         u8 reserved_mask_pos;
106         u8 direct_color_mode_info;
107         u32 phys_base_ptr;
108         u32 offscreen_mem_offset;
109         u16 offscreen_mem_size;
110         u8 reserved[206];
111 } __attribute__ ((__packed__)) vesa_mode_info_t;
112
113 typedef struct {
114         u16 video_mode;
115         union {
116                 vesa_mode_info_t vesa;
117                 u8 mode_info_block[256];
118         };
119         // our crap
120         //u16 attributes;
121         //u16 linebytes;
122         //u16 x_resolution;
123         //u16 y_resolution;
124         //u8 x_charsize;
125         //u8 y_charsize;
126         //u8 bits_per_pixel;
127         //u8 memory_model;
128         //u32 framebuffer_address;
129 } vbe_mode_info_t;
130
131 typedef struct {
132         u8 port_number; // i.e. monitor number
133         u8 edid_transfer_time;
134         u8 ddc_level;
135         u8 edid_block_zero[128];
136 } vbe_ddc_info_t;
137
138 static inline u8
139 vbe_prepare(void)
140 {
141         vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
142         //clear buffer
143         memset(vbe_info_buffer, 0, 512);
144         //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
145         vbe_info_buffer[0] = 'V';
146         vbe_info_buffer[0] = 'B';
147         vbe_info_buffer[0] = 'E';
148         vbe_info_buffer[0] = '2';
149         // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
150         M.x86.R_EDI = 0x0;
151         M.x86.R_ES = VBE_SEGMENT;
152
153         return 0;               // successfull init
154 }
155
156 // VBE Function 00h
157 u8
158 vbe_info(vbe_info_t * info)
159 {
160         vbe_prepare();
161         // call VBE function 00h (Info Function)
162         M.x86.R_EAX = 0x4f00;
163
164         // enable trace
165         CHECK_DBG(DEBUG_TRACE_X86EMU) {
166                 X86EMU_trace_on();
167         }
168         // run VESA Interrupt
169         runInt10();
170
171         if (M.x86.R_AL != 0x4f) {
172                 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
173                                  __func__, M.x86.R_AL);
174                 return -1;
175         }
176
177         if (M.x86.R_AH != 0x0) {
178                 DEBUG_PRINTF_VBE
179                     ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
180                      __func__, M.x86.R_AH);
181                 return M.x86.R_AH;
182         }
183         //printf("VBE Info Dump:");
184         //dump(vbe_info_buffer, 64);
185
186         //offset 0: signature
187         info->signature[0] = vbe_info_buffer[0];
188         info->signature[1] = vbe_info_buffer[1];
189         info->signature[2] = vbe_info_buffer[2];
190         info->signature[3] = vbe_info_buffer[3];
191
192         // offset 4: 16bit le containing VbeVersion
193         info->version = in16le(vbe_info_buffer + 4);
194
195         // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
196         info->oem_string_ptr =
197             biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
198                        in16le(vbe_info_buffer + 6));
199
200         // offset 10: 32bit le capabilities
201         info->capabilities = in32le(vbe_info_buffer + 10);
202
203         // offset 14: 32 bit le containing segment:offset of supported video mode table
204         u16 *video_mode_ptr;
205         video_mode_ptr =
206             (u16 *) (biosmem +
207                           ((in16le(vbe_info_buffer + 16) << 4) +
208                            in16le(vbe_info_buffer + 14)));
209         u32 i = 0;
210         do {
211                 info->video_mode_list[i] = in16le(video_mode_ptr + i);
212                 i++;
213         }
214         while ((i <
215                 (sizeof(info->video_mode_list) /
216                  sizeof(info->video_mode_list[0])))
217                && (info->video_mode_list[i - 1] != 0xFFFF));
218
219         //offset 18: 16bit le total memory in 64KB blocks
220         info->total_memory = in16le(vbe_info_buffer + 18);
221
222         return 0;
223 }
224
225 // VBE Function 01h
226 u8
227 vbe_get_mode_info(vbe_mode_info_t * mode_info)
228 {
229         vbe_prepare();
230         // call VBE function 01h (Return VBE Mode Info Function)
231         M.x86.R_EAX = 0x4f01;
232         M.x86.R_CX = mode_info->video_mode;
233
234         // enable trace
235         CHECK_DBG(DEBUG_TRACE_X86EMU) {
236                 X86EMU_trace_on();
237         }
238         // run VESA Interrupt
239         runInt10();
240
241         if (M.x86.R_AL != 0x4f) {
242                 DEBUG_PRINTF_VBE
243                     ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
244                      __func__, M.x86.R_AL);
245                 return -1;
246         }
247
248         if (M.x86.R_AH != 0x0) {
249                 DEBUG_PRINTF_VBE
250                     ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
251                      __func__, mode_info->video_mode, M.x86.R_AH);
252                 return M.x86.R_AH;
253         }
254
255         //pointer to mode_info_block is in ES:DI
256         memcpy(mode_info->mode_info_block,
257                biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
258                sizeof(mode_info->mode_info_block));
259
260         //printf("Mode Info Dump:");
261         //dump(mode_info_block, 64);
262
263         return 0;
264 }
265
266 // VBE Function 02h
267 u8
268 vbe_set_mode(vbe_mode_info_t * mode_info)
269 {
270         vbe_prepare();
271         // call VBE function 02h (Set VBE Mode Function)
272         M.x86.R_EAX = 0x4f02;
273         M.x86.R_BX = mode_info->video_mode;
274         M.x86.R_BX |= 0x4000;   // set bit 14 to request linear framebuffer mode
275         M.x86.R_BX &= 0x7FFF;   // clear bit 15 to request clearing of framebuffer
276
277         DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
278                          M.x86.R_BX);
279
280         // enable trace
281         CHECK_DBG(DEBUG_TRACE_X86EMU) {
282                 X86EMU_trace_on();
283         }
284         // run VESA Interrupt
285         runInt10();
286
287         if (M.x86.R_AL != 0x4f) {
288                 DEBUG_PRINTF_VBE
289                     ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
290                      __func__, M.x86.R_AL);
291                 return -1;
292         }
293
294         if (M.x86.R_AH != 0x0) {
295                 DEBUG_PRINTF_VBE
296                     ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
297                      __func__, mode_info->video_mode, M.x86.R_AH);
298                 return M.x86.R_AH;
299         }
300         return 0;
301 }
302
303 //VBE Function 08h
304 u8
305 vbe_set_palette_format(u8 format)
306 {
307         vbe_prepare();
308         // call VBE function 09h (Set/Get Palette Data Function)
309         M.x86.R_EAX = 0x4f08;
310         M.x86.R_BL = 0x00;      // set format
311         M.x86.R_BH = format;
312
313         DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
314                          format);
315
316         // enable trace
317         CHECK_DBG(DEBUG_TRACE_X86EMU) {
318                 X86EMU_trace_on();
319         }
320         // run VESA Interrupt
321         runInt10();
322
323         if (M.x86.R_AL != 0x4f) {
324                 DEBUG_PRINTF_VBE
325                     ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
326                      __func__, M.x86.R_AL);
327                 return -1;
328         }
329
330         if (M.x86.R_AH != 0x0) {
331                 DEBUG_PRINTF_VBE
332                     ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
333                      __func__, M.x86.R_AH);
334                 return M.x86.R_AH;
335         }
336         return 0;
337 }
338
339 // VBE Function 09h
340 u8
341 vbe_set_color(u16 color_number, u32 color_value)
342 {
343         vbe_prepare();
344         // call VBE function 09h (Set/Get Palette Data Function)
345         M.x86.R_EAX = 0x4f09;
346         M.x86.R_BL = 0x00;      // set color
347         M.x86.R_CX = 0x01;      // set only one entry
348         M.x86.R_DX = color_number;
349         // ES:DI is address where color_value is stored, we store it at 2000:0000
350         M.x86.R_ES = 0x2000;
351         M.x86.R_DI = 0x0;
352
353         // store color value at ES:DI
354         out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
355
356         DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
357                          color_number, color_value);
358
359         // enable trace
360         CHECK_DBG(DEBUG_TRACE_X86EMU) {
361                 X86EMU_trace_on();
362         }
363         // run VESA Interrupt
364         runInt10();
365
366         if (M.x86.R_AL != 0x4f) {
367                 DEBUG_PRINTF_VBE
368                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
369                      __func__, M.x86.R_AL);
370                 return -1;
371         }
372
373         if (M.x86.R_AH != 0x0) {
374                 DEBUG_PRINTF_VBE
375                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
376                      __func__, M.x86.R_AH);
377                 return M.x86.R_AH;
378         }
379         return 0;
380 }
381
382 u8
383 vbe_get_color(u16 color_number, u32 * color_value)
384 {
385         vbe_prepare();
386         // call VBE function 09h (Set/Get Palette Data Function)
387         M.x86.R_EAX = 0x4f09;
388         M.x86.R_BL = 0x00;      // get color
389         M.x86.R_CX = 0x01;      // get only one entry
390         M.x86.R_DX = color_number;
391         // ES:DI is address where color_value is stored, we store it at 2000:0000
392         M.x86.R_ES = 0x2000;
393         M.x86.R_DI = 0x0;
394
395         // enable trace
396         CHECK_DBG(DEBUG_TRACE_X86EMU) {
397                 X86EMU_trace_on();
398         }
399         // run VESA Interrupt
400         runInt10();
401
402         if (M.x86.R_AL != 0x4f) {
403                 DEBUG_PRINTF_VBE
404                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
405                      __func__, M.x86.R_AL);
406                 return -1;
407         }
408
409         if (M.x86.R_AH != 0x0) {
410                 DEBUG_PRINTF_VBE
411                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
412                      __func__, M.x86.R_AH);
413                 return M.x86.R_AH;
414         }
415         // read color value from ES:DI
416         *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
417
418         DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
419                          color_number, *color_value);
420
421         return 0;
422 }
423
424 // VBE Function 15h
425 u8
426 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
427 {
428         vbe_prepare();
429         // call VBE function 15h (DDC Info Function)
430         M.x86.R_EAX = 0x4f15;
431         M.x86.R_BL = 0x00;      // get DDC Info
432         M.x86.R_CX = ddc_info->port_number;
433         M.x86.R_ES = 0x0;
434         M.x86.R_DI = 0x0;
435
436         // enable trace
437         CHECK_DBG(DEBUG_TRACE_X86EMU) {
438                 X86EMU_trace_on();
439         }
440         // run VESA Interrupt
441         runInt10();
442
443         if (M.x86.R_AL != 0x4f) {
444                 DEBUG_PRINTF_VBE
445                     ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
446                      __func__, M.x86.R_AL);
447                 return -1;
448         }
449
450         if (M.x86.R_AH != 0x0) {
451                 DEBUG_PRINTF_VBE
452                     ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
453                      __func__, ddc_info->port_number, M.x86.R_AH);
454                 return M.x86.R_AH;
455         }
456         // BH = approx. time in seconds to transfer one EDID block
457         ddc_info->edid_transfer_time = M.x86.R_BH;
458         // BL = DDC Level
459         ddc_info->ddc_level = M.x86.R_BL;
460
461         vbe_prepare();
462         // call VBE function 15h (DDC Info Function)
463         M.x86.R_EAX = 0x4f15;
464         M.x86.R_BL = 0x01;      // read EDID
465         M.x86.R_CX = ddc_info->port_number;
466         M.x86.R_DX = 0x0;       // block number
467         // ES:DI is address where EDID is stored, we store it at 2000:0000
468         M.x86.R_ES = 0x2000;
469         M.x86.R_DI = 0x0;
470
471         // enable trace
472         CHECK_DBG(DEBUG_TRACE_X86EMU) {
473                 X86EMU_trace_on();
474         }
475         // run VESA Interrupt
476         runInt10();
477
478         if (M.x86.R_AL != 0x4f) {
479                 DEBUG_PRINTF_VBE
480                     ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
481                      __func__, M.x86.R_AL);
482                 return -1;
483         }
484
485         if (M.x86.R_AH != 0x0) {
486                 DEBUG_PRINTF_VBE
487                     ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
488                      __func__, ddc_info->port_number, M.x86.R_AH);
489                 return M.x86.R_AH;
490         }
491
492         memcpy(ddc_info->edid_block_zero,
493                biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
494                sizeof(ddc_info->edid_block_zero));
495
496         return 0;
497 }
498
499 u32
500 vbe_get_info(void)
501 {
502         u8 rval;
503         int i;
504
505         // XXX FIXME these need to be filled with sane values
506
507         // get a copy of input struct...
508         screen_info_input_t input;
509         // output is pointer to the address passed as argv[4]
510         screen_info_t local_output;
511         screen_info_t *output = &local_output;
512         // zero input
513         memset(&input, 0, sizeof(screen_info_input_t));
514         // zero output
515         memset(&output, 0, sizeof(screen_info_t));
516
517         vbe_info_t info;
518         rval = vbe_info(&info);
519         if (rval != 0)
520                 return rval;
521
522         DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
523         DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
524         DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
525         DEBUG_PRINTF_VBE("Capabilities:\n");
526         DEBUG_PRINTF_VBE("\tDAC: %s\n",
527                          (info.capabilities & 0x1) ==
528                          0 ? "fixed 6bit" : "switchable 6/8bit");
529         DEBUG_PRINTF_VBE("\tVGA: %s\n",
530                          (info.capabilities & 0x2) ==
531                          0 ? "compatible" : "not compatible");
532         DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
533                          (info.capabilities & 0x4) ==
534                          0 ? "normal" : "use blank bit in Function 09h");
535
536         // argv[4] may be a pointer with enough space to return screen_info_t
537         // as input, it must contain a screen_info_input_t with the following content:
538         // byte[0:3] = "DDC\0" (zero-terminated signature header)
539         // byte[4:5] = reserved space for the return struct... just in case we ever change
540         //             the struct and dont have reserved enough memory (and let's hope the struct
541         //             never gets larger than 64KB)
542         // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
543         // byte[7:8] = max. screen width (OF may want to limit this)
544         // byte[9] = required color depth in bpp
545         if (strncmp((char *) input.signature, "DDC", 4) != 0) {
546                 printf
547                     ("%s: Invalid input signature! expected: %s, is: %s\n",
548                      __func__, "DDC", input.signature);
549                 return -1;
550         }
551         if (input.size_reserved != sizeof(screen_info_t)) {
552                 printf
553                     ("%s: Size of return struct is wrong, required: %d, available: %d\n",
554                      __func__, (int) sizeof(screen_info_t),
555                      input.size_reserved);
556                 return -1;
557         }
558
559         vbe_ddc_info_t ddc_info;
560         ddc_info.port_number = input.monitor_number;
561         vbe_get_ddc_info(&ddc_info);
562
563 #if 0
564         DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
565                          ddc_info.edid_transfer_time);
566         DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
567         DEBUG_PRINTF_VBE("DDC: EDID: \n");
568         CHECK_DBG(DEBUG_VBE) {
569                 dump(ddc_info.edid_block_zero,
570                      sizeof(ddc_info.edid_block_zero));
571         }
572 #endif
573         if (*((u64 *) ddc_info.edid_block_zero) !=
574             (u64) 0x00FFFFFFFFFFFF00) {
575                 // invalid EDID signature... probably no monitor
576
577                 output->display_type = 0x0;
578                 return 0;
579         } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
580                 // digital display
581                 output->display_type = 2;
582         } else {
583                 // analog
584                 output->display_type = 1;
585         }
586         DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
587         memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
588                sizeof(ddc_info.edid_block_zero));
589         i = 0;
590         vbe_mode_info_t mode_info;
591         vbe_mode_info_t best_mode_info;
592         // initialize best_mode to 0
593         memset(&best_mode_info, 0, sizeof(best_mode_info));
594         while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
595                 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
596                 vbe_get_mode_info(&mode_info);
597
598                 // FIXME all these values are little endian!
599
600                 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
601                                  mode_info.video_mode,
602                                  (mode_info.attributes & 0x1) ==
603                                  0 ? "not supported" : "supported");
604                 DEBUG_PRINTF_VBE("\tTTY: %s\n",
605                                  (mode_info.attributes & 0x4) ==
606                                  0 ? "no" : "yes");
607                 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
608                                  (mode_info.attributes & 0x8) ==
609                                  0 ? "monochrome" : "color",
610                                  (mode_info.attributes & 0x10) ==
611                                  0 ? "text" : "graphics");
612                 DEBUG_PRINTF_VBE("\tVGA: %s\n",
613                                  (mode_info.attributes & 0x20) ==
614                                  0 ? "compatible" : "not compatible");
615                 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
616                                  (mode_info.attributes & 0x40) ==
617                                  0 ? "yes" : "no");
618                 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
619                                  (mode_info.attributes & 0x80) ==
620                                  0 ? "no" : "yes");
621                 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
622                                  mode_info.x_resolution,
623                                  mode_info.y_resolution);
624                 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
625                                  mode_info.x_charsize, mode_info.y_charsize);
626                 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
627                                  mode_info.bits_per_pixel);
628                 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
629                                  mode_info.memory_model);
630                 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
631                                  mode_info.framebuffer_address);
632
633                 if ((mode_info.vesa.bits_per_pixel == input.color_depth)
634                     && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
635                     && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0)      // framebuffer mode
636                     && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0)      // graphics
637                     && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0)       // color
638                     && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution)))      // better than previous best_mode
639                 {
640                         // yiiiihaah... we found a new best mode
641                         memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
642                 }
643                 i++;
644         }
645
646         if (best_mode_info.video_mode != 0) {
647                 DEBUG_PRINTF_VBE
648                     ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
649                      best_mode_info.video_mode,
650                      best_mode_info.x_resolution,
651                      best_mode_info.y_resolution,
652                      best_mode_info.bits_per_pixel,
653                      best_mode_info.framebuffer_address);
654
655                 //printf("Mode Info Dump:");
656                 //dump(best_mode_info.mode_info_block, 64);
657
658                 // set the video mode
659                 vbe_set_mode(&best_mode_info);
660
661                 if ((info.capabilities & 0x1) != 0) {
662                         // switch to 8 bit palette format
663                         vbe_set_palette_format(8);
664                 }
665                 // setup a palette:
666                 // - first 216 colors are mixed colors for each component in 6 steps
667                 //   (6*6*6=216)
668                 // - then 10 shades of the three primary colors
669                 // - then 10 shades of grey
670                 // -------
671                 // = 256 colors
672                 //
673                 // - finally black is color 0 and white color FF (because SLOF expects it
674                 //   this way...)
675                 // this resembles the palette that the kernel/X Server seems to expect...
676
677                 u8 mixed_color_values[6] =
678                     { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
679                 u8 primary_color_values[10] =
680                     { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
681                         0x27
682                 };
683                 u8 mc_size = sizeof(mixed_color_values);
684                 u8 prim_size = sizeof(primary_color_values);
685
686                 u8 curr_color_index;
687                 u32 curr_color;
688
689                 u8 r, g, b;
690                 // 216 mixed colors
691                 for (r = 0; r < mc_size; r++) {
692                         for (g = 0; g < mc_size; g++) {
693                                 for (b = 0; b < mc_size; b++) {
694                                         curr_color_index =
695                                             (r * mc_size * mc_size) +
696                                             (g * mc_size) + b;
697                                         curr_color = 0;
698                                         curr_color |= ((u32) mixed_color_values[r]) << 16;      //red value
699                                         curr_color |= ((u32) mixed_color_values[g]) << 8;       //green value
700                                         curr_color |= (u32) mixed_color_values[b];      //blue value
701                                         vbe_set_color(curr_color_index,
702                                                       curr_color);
703                                 }
704                         }
705                 }
706
707                 // 10 shades of each primary color
708                 // red
709                 for (r = 0; r < prim_size; r++) {
710                         curr_color_index = mc_size * mc_size * mc_size + r;
711                         curr_color = ((u32) primary_color_values[r]) << 16;
712                         vbe_set_color(curr_color_index, curr_color);
713                 }
714                 //green
715                 for (g = 0; g < prim_size; g++) {
716                         curr_color_index =
717                             mc_size * mc_size * mc_size + prim_size + g;
718                         curr_color = ((u32) primary_color_values[g]) << 8;
719                         vbe_set_color(curr_color_index, curr_color);
720                 }
721                 //blue
722                 for (b = 0; b < prim_size; b++) {
723                         curr_color_index =
724                             mc_size * mc_size * mc_size + prim_size * 2 + b;
725                         curr_color = (u32) primary_color_values[b];
726                         vbe_set_color(curr_color_index, curr_color);
727                 }
728                 // 10 shades of grey
729                 for (i = 0; i < prim_size; i++) {
730                         curr_color_index =
731                             mc_size * mc_size * mc_size + prim_size * 3 + i;
732                         curr_color = 0;
733                         curr_color |= ((u32) primary_color_values[i]) << 16;    //red
734                         curr_color |= ((u32) primary_color_values[i]) << 8;     //green
735                         curr_color |= ((u32) primary_color_values[i]);  //blue
736                         vbe_set_color(curr_color_index, curr_color);
737                 }
738
739                 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
740                 vbe_set_color(0x00, 0x00000000);
741                 vbe_set_color(0xFF, 0x00FFFFFF);
742
743                 output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
744                 output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
745                 output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
746                 output->color_depth = best_mode_info.vesa.bits_per_pixel;
747                 output->framebuffer_address =
748                     le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
749         } else {
750                 printf("%s: No suitable video mode found!\n", __func__);
751                 //unset display_type...
752                 output->display_type = 0;
753         }
754         return 0;
755 }
756
757 #if CONFIG_BOOTSPLASH
758 vbe_mode_info_t mode_info;
759
760 void vbe_set_graphics(void)
761 {
762         u8 rval;
763         int i;
764
765         vbe_info_t info;
766         rval = vbe_info(&info);
767         if (rval != 0)
768                 return;
769
770         DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
771         DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
772         DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
773         DEBUG_PRINTF_VBE("Capabilities:\n");
774         DEBUG_PRINTF_VBE("\tDAC: %s\n",
775                          (info.capabilities & 0x1) ==
776                          0 ? "fixed 6bit" : "switchable 6/8bit");
777         DEBUG_PRINTF_VBE("\tVGA: %s\n",
778                          (info.capabilities & 0x2) ==
779                          0 ? "compatible" : "not compatible");
780         DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
781                          (info.capabilities & 0x4) ==
782                          0 ? "normal" : "use blank bit in Function 09h");
783
784         mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
785         vbe_get_mode_info(&mode_info);
786         unsigned char *framebuffer = 
787                 (unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
788         DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%08x\n", framebuffer);
789         vbe_set_mode(&mode_info);
790
791         struct jpeg_decdata *decdata;
792         decdata = malloc(sizeof(*decdata));
793
794         /* Switching Intel IGD to 1MB video memory will break this. Who
795          * cares. */
796         int imagesize = 1024*768*2;
797         
798         unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
799         if (!jpeg) { 
800                 DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
801                 return;
802         }
803         DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg);
804         dump(jpeg, 64);
805
806         int ret = 0;
807         DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
808         ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
809         DEBUG_PRINTF_VBE("returns %x\n", ret);
810 }
811
812 void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
813 {
814         framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
815
816         framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
817         framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
818         framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
819         framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
820
821         framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
822         framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
823
824         framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
825         framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
826
827         framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
828         framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
829
830         framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
831         framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
832 }
833
834 void vbe_textmode_console(void)
835 {
836         /* Wait, just a little bit more, pleeeease ;-) */
837         delay(2);
838
839         M.x86.R_EAX = 0x0003;
840         runInt10();
841 }
842
843 #endif