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