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