blob: 07eb1f3abb315ce7ad021b6e7b7aa609c4adcb06 [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/******************************************************************************
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>
Stefan Reinauerc1efb902011-10-12 14:30:59 -070016#if CONFIG_FRAMEBUFFER_SET_VESA_MODE
Stefan Reinauerd650e992010-02-22 04:33:13 +000017#include <boot/coreboot_tables.h>
18#endif
19
Julius Werner9ff8f6f2015-02-23 14:31:09 -080020#include <endian.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000021
22#include "debug.h"
23
24#include <x86emu/x86emu.h>
25#include <x86emu/regs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000026#include "../x86emu/prim_ops.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000027
28#include "biosemu.h"
29#include "io.h"
30#include "mem.h"
31#include "interrupt.h"
32#include "device.h"
33
Stefan Reinauerd650e992010-02-22 04:33:13 +000034#include <cbfs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000035
Stefan Reinauerd650e992010-02-22 04:33:13 +000036#include <delay.h>
37#include "../../src/lib/jpeg.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000038
Stefan Reinauer216fa462011-10-12 14:25:07 -070039#include <vbe.h>
40
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000041// pointer to VBEInfoBuffer, set by vbe_prepare
42u8 *vbe_info_buffer = 0;
Stefan Reinauerd650e992010-02-22 04:33:13 +000043
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000044// virtual BIOS Memory
45u8 *biosmem;
46u32 biosmem_size;
47
Edward O'Callaghanc8676262014-05-18 11:28:43 +100048#if CONFIG_FRAMEBUFFER_SET_VESA_MODE
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000049static inline u8
Stefan Reinauerd650e992010-02-22 04:33:13 +000050vbe_prepare(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000051{
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// VBE Function 00h
Uwe Hermann01ce6012010-03-05 10:03:50 +000068static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000069vbe_info(vbe_info_t * info)
70{
71 vbe_prepare();
72 // call VBE function 00h (Info Function)
73 M.x86.R_EAX = 0x4f00;
74
75 // enable trace
76 CHECK_DBG(DEBUG_TRACE_X86EMU) {
77 X86EMU_trace_on();
78 }
79 // run VESA Interrupt
80 runInt10();
81
82 if (M.x86.R_AL != 0x4f) {
83 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
84 __func__, M.x86.R_AL);
85 return -1;
86 }
87
88 if (M.x86.R_AH != 0x0) {
89 DEBUG_PRINTF_VBE
90 ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
91 __func__, M.x86.R_AH);
92 return M.x86.R_AH;
93 }
94 //printf("VBE Info Dump:");
95 //dump(vbe_info_buffer, 64);
96
97 //offset 0: signature
98 info->signature[0] = vbe_info_buffer[0];
99 info->signature[1] = vbe_info_buffer[1];
100 info->signature[2] = vbe_info_buffer[2];
101 info->signature[3] = vbe_info_buffer[3];
102
103 // offset 4: 16bit le containing VbeVersion
104 info->version = in16le(vbe_info_buffer + 4);
105
Martin Roth63373ed2013-07-08 16:24:19 -0600106 // offset 6: 32bit le containing segment:offset of OEM String in virtual Mem.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000107 info->oem_string_ptr =
108 biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
109 in16le(vbe_info_buffer + 6));
110
111 // offset 10: 32bit le capabilities
112 info->capabilities = in32le(vbe_info_buffer + 10);
113
114 // offset 14: 32 bit le containing segment:offset of supported video mode table
115 u16 *video_mode_ptr;
116 video_mode_ptr =
117 (u16 *) (biosmem +
118 ((in16le(vbe_info_buffer + 16) << 4) +
119 in16le(vbe_info_buffer + 14)));
120 u32 i = 0;
121 do {
122 info->video_mode_list[i] = in16le(video_mode_ptr + i);
123 i++;
124 }
125 while ((i <
126 (sizeof(info->video_mode_list) /
127 sizeof(info->video_mode_list[0])))
128 && (info->video_mode_list[i - 1] != 0xFFFF));
129
130 //offset 18: 16bit le total memory in 64KB blocks
131 info->total_memory = in16le(vbe_info_buffer + 18);
132
133 return 0;
134}
135
Gabe Blackfb8632a2012-09-30 04:47:48 -0700136static int mode_info_valid;
137
138int vbe_mode_info_valid(void)
139{
140 return mode_info_valid;
141}
142
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000143// VBE Function 01h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000144static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000145vbe_get_mode_info(vbe_mode_info_t * mode_info)
146{
147 vbe_prepare();
148 // call VBE function 01h (Return VBE Mode Info Function)
149 M.x86.R_EAX = 0x4f01;
150 M.x86.R_CX = mode_info->video_mode;
151
152 // enable trace
153 CHECK_DBG(DEBUG_TRACE_X86EMU) {
154 X86EMU_trace_on();
155 }
156 // run VESA Interrupt
157 runInt10();
158
159 if (M.x86.R_AL != 0x4f) {
160 DEBUG_PRINTF_VBE
161 ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
162 __func__, M.x86.R_AL);
163 return -1;
164 }
165
166 if (M.x86.R_AH != 0x0) {
167 DEBUG_PRINTF_VBE
168 ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
169 __func__, mode_info->video_mode, M.x86.R_AH);
170 return M.x86.R_AH;
171 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000172
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000173 //pointer to mode_info_block is in ES:DI
174 memcpy(mode_info->mode_info_block,
175 biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
176 sizeof(mode_info->mode_info_block));
Gabe Blackfb8632a2012-09-30 04:47:48 -0700177 mode_info_valid = 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000178
179 //printf("Mode Info Dump:");
180 //dump(mode_info_block, 64);
181
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000182 return 0;
183}
184
185// VBE Function 02h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000186static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000187vbe_set_mode(vbe_mode_info_t * mode_info)
188{
189 vbe_prepare();
190 // call VBE function 02h (Set VBE Mode Function)
191 M.x86.R_EAX = 0x4f02;
192 M.x86.R_BX = mode_info->video_mode;
193 M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
194 M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
195
196 DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
197 M.x86.R_BX);
198
199 // enable trace
200 CHECK_DBG(DEBUG_TRACE_X86EMU) {
201 X86EMU_trace_on();
202 }
203 // run VESA Interrupt
204 runInt10();
205
206 if (M.x86.R_AL != 0x4f) {
207 DEBUG_PRINTF_VBE
208 ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
209 __func__, M.x86.R_AL);
210 return -1;
211 }
212
213 if (M.x86.R_AH != 0x0) {
214 DEBUG_PRINTF_VBE
215 ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
216 __func__, mode_info->video_mode, M.x86.R_AH);
217 return M.x86.R_AH;
218 }
219 return 0;
220}
221
Patrick Georgif0bf4b52011-01-21 12:45:37 +0000222#if 0
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000223//VBE Function 08h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000224static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000225vbe_set_palette_format(u8 format)
226{
227 vbe_prepare();
228 // call VBE function 09h (Set/Get Palette Data Function)
229 M.x86.R_EAX = 0x4f08;
230 M.x86.R_BL = 0x00; // set format
231 M.x86.R_BH = format;
232
233 DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
234 format);
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 Set Palette Format 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 Set Palette Format Function Return Code NOT OK! AH=%x\n",
253 __func__, M.x86.R_AH);
254 return M.x86.R_AH;
255 }
256 return 0;
257}
258
259// VBE Function 09h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000260static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000261vbe_set_color(u16 color_number, u32 color_value)
262{
263 vbe_prepare();
264 // call VBE function 09h (Set/Get Palette Data Function)
265 M.x86.R_EAX = 0x4f09;
266 M.x86.R_BL = 0x00; // set color
267 M.x86.R_CX = 0x01; // set only one entry
268 M.x86.R_DX = color_number;
269 // ES:DI is address where color_value is stored, we store it at 2000:0000
270 M.x86.R_ES = 0x2000;
271 M.x86.R_DI = 0x0;
272
273 // store color value at ES:DI
274 out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
275
276 DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
277 color_number, color_value);
278
279 // enable trace
280 CHECK_DBG(DEBUG_TRACE_X86EMU) {
281 X86EMU_trace_on();
282 }
283 // run VESA Interrupt
284 runInt10();
285
286 if (M.x86.R_AL != 0x4f) {
287 DEBUG_PRINTF_VBE
288 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
289 __func__, M.x86.R_AL);
290 return -1;
291 }
292
293 if (M.x86.R_AH != 0x0) {
294 DEBUG_PRINTF_VBE
295 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
296 __func__, M.x86.R_AH);
297 return M.x86.R_AH;
298 }
299 return 0;
300}
301
Uwe Hermann01ce6012010-03-05 10:03:50 +0000302static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000303vbe_get_color(u16 color_number, u32 * color_value)
304{
305 vbe_prepare();
306 // call VBE function 09h (Set/Get Palette Data Function)
307 M.x86.R_EAX = 0x4f09;
308 M.x86.R_BL = 0x00; // get color
309 M.x86.R_CX = 0x01; // get only one entry
310 M.x86.R_DX = color_number;
311 // ES:DI is address where color_value is stored, we store it at 2000:0000
312 M.x86.R_ES = 0x2000;
313 M.x86.R_DI = 0x0;
314
315 // enable trace
316 CHECK_DBG(DEBUG_TRACE_X86EMU) {
317 X86EMU_trace_on();
318 }
319 // run VESA Interrupt
320 runInt10();
321
322 if (M.x86.R_AL != 0x4f) {
323 DEBUG_PRINTF_VBE
324 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
325 __func__, M.x86.R_AL);
326 return -1;
327 }
328
329 if (M.x86.R_AH != 0x0) {
330 DEBUG_PRINTF_VBE
331 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
332 __func__, M.x86.R_AH);
333 return M.x86.R_AH;
334 }
335 // read color value from ES:DI
336 *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
337
338 DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
339 color_number, *color_value);
340
341 return 0;
342}
343
344// VBE Function 15h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000345static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000346vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
347{
348 vbe_prepare();
349 // call VBE function 15h (DDC Info Function)
350 M.x86.R_EAX = 0x4f15;
351 M.x86.R_BL = 0x00; // get DDC Info
352 M.x86.R_CX = ddc_info->port_number;
353 M.x86.R_ES = 0x0;
354 M.x86.R_DI = 0x0;
355
356 // enable trace
357 CHECK_DBG(DEBUG_TRACE_X86EMU) {
358 X86EMU_trace_on();
359 }
360 // run VESA Interrupt
361 runInt10();
362
363 if (M.x86.R_AL != 0x4f) {
364 DEBUG_PRINTF_VBE
365 ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
366 __func__, M.x86.R_AL);
367 return -1;
368 }
369
370 if (M.x86.R_AH != 0x0) {
371 DEBUG_PRINTF_VBE
372 ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
373 __func__, ddc_info->port_number, M.x86.R_AH);
374 return M.x86.R_AH;
375 }
376 // BH = approx. time in seconds to transfer one EDID block
377 ddc_info->edid_transfer_time = M.x86.R_BH;
378 // BL = DDC Level
379 ddc_info->ddc_level = M.x86.R_BL;
380
381 vbe_prepare();
382 // call VBE function 15h (DDC Info Function)
383 M.x86.R_EAX = 0x4f15;
384 M.x86.R_BL = 0x01; // read EDID
385 M.x86.R_CX = ddc_info->port_number;
386 M.x86.R_DX = 0x0; // block number
387 // ES:DI is address where EDID is stored, we store it at 2000:0000
388 M.x86.R_ES = 0x2000;
389 M.x86.R_DI = 0x0;
390
391 // enable trace
392 CHECK_DBG(DEBUG_TRACE_X86EMU) {
393 X86EMU_trace_on();
394 }
395 // run VESA Interrupt
396 runInt10();
397
398 if (M.x86.R_AL != 0x4f) {
399 DEBUG_PRINTF_VBE
400 ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
401 __func__, M.x86.R_AL);
402 return -1;
403 }
404
405 if (M.x86.R_AH != 0x0) {
406 DEBUG_PRINTF_VBE
407 ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
408 __func__, ddc_info->port_number, M.x86.R_AH);
409 return M.x86.R_AH;
410 }
411
412 memcpy(ddc_info->edid_block_zero,
413 biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
414 sizeof(ddc_info->edid_block_zero));
415
416 return 0;
417}
418
Uwe Hermann01ce6012010-03-05 10:03:50 +0000419static u32
Stefan Reinauerd650e992010-02-22 04:33:13 +0000420vbe_get_info(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000421{
422 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000423 int i;
424
425 // XXX FIXME these need to be filled with sane values
426
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000427 // get a copy of input struct...
Stefan Reinauerd650e992010-02-22 04:33:13 +0000428 screen_info_input_t input;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000429 // output is pointer to the address passed as argv[4]
Stefan Reinauerd650e992010-02-22 04:33:13 +0000430 screen_info_t local_output;
431 screen_info_t *output = &local_output;
432 // zero input
433 memset(&input, 0, sizeof(screen_info_input_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000434 // zero output
Stefan Reinauerd650e992010-02-22 04:33:13 +0000435 memset(&output, 0, sizeof(screen_info_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000436
437 vbe_info_t info;
438 rval = vbe_info(&info);
439 if (rval != 0)
440 return rval;
441
442 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
443 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
444 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
445 DEBUG_PRINTF_VBE("Capabilities:\n");
446 DEBUG_PRINTF_VBE("\tDAC: %s\n",
447 (info.capabilities & 0x1) ==
448 0 ? "fixed 6bit" : "switchable 6/8bit");
449 DEBUG_PRINTF_VBE("\tVGA: %s\n",
450 (info.capabilities & 0x2) ==
451 0 ? "compatible" : "not compatible");
452 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
453 (info.capabilities & 0x4) ==
454 0 ? "normal" : "use blank bit in Function 09h");
455
456 // argv[4] may be a pointer with enough space to return screen_info_t
457 // as input, it must contain a screen_info_input_t with the following content:
458 // byte[0:3] = "DDC\0" (zero-terminated signature header)
459 // byte[4:5] = reserved space for the return struct... just in case we ever change
Martin Roth63373ed2013-07-08 16:24:19 -0600460 // the struct and don't have reserved enough memory (and let's hope the struct
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000461 // never gets larger than 64KB)
462 // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
463 // byte[7:8] = max. screen width (OF may want to limit this)
464 // byte[9] = required color depth in bpp
465 if (strncmp((char *) input.signature, "DDC", 4) != 0) {
466 printf
467 ("%s: Invalid input signature! expected: %s, is: %s\n",
468 __func__, "DDC", input.signature);
469 return -1;
470 }
471 if (input.size_reserved != sizeof(screen_info_t)) {
472 printf
473 ("%s: Size of return struct is wrong, required: %d, available: %d\n",
474 __func__, (int) sizeof(screen_info_t),
475 input.size_reserved);
476 return -1;
477 }
478
479 vbe_ddc_info_t ddc_info;
480 ddc_info.port_number = input.monitor_number;
481 vbe_get_ddc_info(&ddc_info);
482
483#if 0
484 DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
485 ddc_info.edid_transfer_time);
486 DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
487 DEBUG_PRINTF_VBE("DDC: EDID: \n");
488 CHECK_DBG(DEBUG_VBE) {
489 dump(ddc_info.edid_block_zero,
490 sizeof(ddc_info.edid_block_zero));
491 }
492#endif
Myles Watsonb0259112010-03-05 18:27:19 +0000493/* This could fail because of alignment issues, so use a longer form.
494 *((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
495*/
496 if (ddc_info.edid_block_zero[0] != 0x00 ||
497 ddc_info.edid_block_zero[1] != 0xFF ||
498 ddc_info.edid_block_zero[2] != 0xFF ||
499 ddc_info.edid_block_zero[3] != 0xFF ||
500 ddc_info.edid_block_zero[4] != 0xFF ||
501 ddc_info.edid_block_zero[5] != 0xFF ||
502 ddc_info.edid_block_zero[6] != 0xFF ||
503 ddc_info.edid_block_zero[7] != 0x00 ) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000504 // invalid EDID signature... probably no monitor
505
506 output->display_type = 0x0;
507 return 0;
508 } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
509 // digital display
510 output->display_type = 2;
511 } else {
512 // analog
513 output->display_type = 1;
514 }
515 DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
516 memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
517 sizeof(ddc_info.edid_block_zero));
518 i = 0;
519 vbe_mode_info_t mode_info;
520 vbe_mode_info_t best_mode_info;
521 // initialize best_mode to 0
522 memset(&best_mode_info, 0, sizeof(best_mode_info));
523 while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
524 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
525 vbe_get_mode_info(&mode_info);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000526
527 // FIXME all these values are little endian!
528
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000529 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
530 mode_info.video_mode,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000531 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000532 0 ? "not supported" : "supported");
533 DEBUG_PRINTF_VBE("\tTTY: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000534 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000535 0 ? "no" : "yes");
536 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000537 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000538 0 ? "monochrome" : "color",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000539 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000540 0 ? "text" : "graphics");
541 DEBUG_PRINTF_VBE("\tVGA: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000542 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000543 0 ? "compatible" : "not compatible");
544 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000545 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000546 0 ? "yes" : "no");
547 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000548 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000549 0 ? "no" : "yes");
550 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000551 le16_to_cpu(mode_info.vesa.x_resolution),
552 le16_to_cpu(mode_info.vesa.y_resolution));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000553 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000554 mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000555 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000556 mode_info.vesa.bits_per_pixel);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000557 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000558 mode_info.vesa.memory_model);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000559 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000560 le32_to_cpu(mode_info.vesa.phys_base_ptr));
Stefan Reinauerd650e992010-02-22 04:33:13 +0000561
562 if ((mode_info.vesa.bits_per_pixel == input.color_depth)
563 && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
564 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
565 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
566 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
567 && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000568 {
569 // yiiiihaah... we found a new best mode
570 memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
571 }
572 i++;
573 }
574
575 if (best_mode_info.video_mode != 0) {
576 DEBUG_PRINTF_VBE
577 ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
578 best_mode_info.video_mode,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000579 best_mode_info.vesa.x_resolution,
580 best_mode_info.vesa.y_resolution,
581 best_mode_info.vesa.bits_per_pixel,
582 le32_to_cpu(best_mode_info.vesa.phys_base_ptr));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000583
584 //printf("Mode Info Dump:");
585 //dump(best_mode_info.mode_info_block, 64);
586
587 // set the video mode
588 vbe_set_mode(&best_mode_info);
589
590 if ((info.capabilities & 0x1) != 0) {
591 // switch to 8 bit palette format
592 vbe_set_palette_format(8);
593 }
594 // setup a palette:
595 // - first 216 colors are mixed colors for each component in 6 steps
596 // (6*6*6=216)
597 // - then 10 shades of the three primary colors
598 // - then 10 shades of grey
599 // -------
600 // = 256 colors
601 //
602 // - finally black is color 0 and white color FF (because SLOF expects it
603 // this way...)
604 // this resembles the palette that the kernel/X Server seems to expect...
605
606 u8 mixed_color_values[6] =
607 { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
608 u8 primary_color_values[10] =
609 { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
610 0x27
611 };
612 u8 mc_size = sizeof(mixed_color_values);
613 u8 prim_size = sizeof(primary_color_values);
614
615 u8 curr_color_index;
616 u32 curr_color;
617
618 u8 r, g, b;
619 // 216 mixed colors
620 for (r = 0; r < mc_size; r++) {
621 for (g = 0; g < mc_size; g++) {
622 for (b = 0; b < mc_size; b++) {
623 curr_color_index =
624 (r * mc_size * mc_size) +
625 (g * mc_size) + b;
626 curr_color = 0;
627 curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
628 curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
629 curr_color |= (u32) mixed_color_values[b]; //blue value
630 vbe_set_color(curr_color_index,
631 curr_color);
632 }
633 }
634 }
635
636 // 10 shades of each primary color
637 // red
638 for (r = 0; r < prim_size; r++) {
639 curr_color_index = mc_size * mc_size * mc_size + r;
640 curr_color = ((u32) primary_color_values[r]) << 16;
641 vbe_set_color(curr_color_index, curr_color);
642 }
643 //green
644 for (g = 0; g < prim_size; g++) {
645 curr_color_index =
646 mc_size * mc_size * mc_size + prim_size + g;
647 curr_color = ((u32) primary_color_values[g]) << 8;
648 vbe_set_color(curr_color_index, curr_color);
649 }
650 //blue
651 for (b = 0; b < prim_size; b++) {
652 curr_color_index =
653 mc_size * mc_size * mc_size + prim_size * 2 + b;
654 curr_color = (u32) primary_color_values[b];
655 vbe_set_color(curr_color_index, curr_color);
656 }
657 // 10 shades of grey
658 for (i = 0; i < prim_size; i++) {
659 curr_color_index =
660 mc_size * mc_size * mc_size + prim_size * 3 + i;
661 curr_color = 0;
662 curr_color |= ((u32) primary_color_values[i]) << 16; //red
663 curr_color |= ((u32) primary_color_values[i]) << 8; //green
664 curr_color |= ((u32) primary_color_values[i]); //blue
665 vbe_set_color(curr_color_index, curr_color);
666 }
667
668 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
669 vbe_set_color(0x00, 0x00000000);
670 vbe_set_color(0xFF, 0x00FFFFFF);
671
Stefan Reinauerd650e992010-02-22 04:33:13 +0000672 output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
673 output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
674 output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
675 output->color_depth = best_mode_info.vesa.bits_per_pixel;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000676 output->framebuffer_address =
Stefan Reinauerd650e992010-02-22 04:33:13 +0000677 le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000678 } else {
679 printf("%s: No suitable video mode found!\n", __func__);
680 //unset display_type...
681 output->display_type = 0;
682 }
683 return 0;
684}
Patrick Georgif0bf4b52011-01-21 12:45:37 +0000685#endif
Stefan Reinauerd650e992010-02-22 04:33:13 +0000686
Stefan Reinauerd650e992010-02-22 04:33:13 +0000687vbe_mode_info_t mode_info;
688
689void vbe_set_graphics(void)
690{
691 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000692
693 vbe_info_t info;
694 rval = vbe_info(&info);
695 if (rval != 0)
696 return;
697
698 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
699 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
700 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
701 DEBUG_PRINTF_VBE("Capabilities:\n");
702 DEBUG_PRINTF_VBE("\tDAC: %s\n",
703 (info.capabilities & 0x1) ==
704 0 ? "fixed 6bit" : "switchable 6/8bit");
705 DEBUG_PRINTF_VBE("\tVGA: %s\n",
706 (info.capabilities & 0x2) ==
707 0 ? "compatible" : "not compatible");
708 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
709 (info.capabilities & 0x4) ==
710 0 ? "normal" : "use blank bit in Function 09h");
711
712 mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
713 vbe_get_mode_info(&mode_info);
Stefan Reinauerc1efb902011-10-12 14:30:59 -0700714 vbe_set_mode(&mode_info);
715
716#if CONFIG_BOOTSPLASH
Stefan Reinauer14e22772010-04-27 06:56:47 +0000717 unsigned char *framebuffer =
Stefan Reinauerd650e992010-02-22 04:33:13 +0000718 (unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
Myles Watson8f8a51c2010-09-09 16:00:20 +0000719 DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%p\n", framebuffer);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000720
721 struct jpeg_decdata *decdata;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000722
723 /* Switching Intel IGD to 1MB video memory will break this. Who
724 * cares. */
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000725 // int imagesize = 1024*768*2;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000726
Aaron Durbin899d13d2015-05-15 23:39:23 -0500727 unsigned char *jpeg = cbfs_boot_map_with_leak("bootsplash.jpg",
728 CBFS_TYPE_BOOTSPLASH,
729 NULL);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000730 if (!jpeg) {
Stefan Reinauerd650e992010-02-22 04:33:13 +0000731 DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
732 return;
733 }
Myles Watson8f8a51c2010-09-09 16:00:20 +0000734 DEBUG_PRINTF_VBE("Splash at %p ...\n", jpeg);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000735 dump(jpeg, 64);
736
Daniele Forsi6e3712f2014-07-26 11:37:41 +0200737 decdata = malloc(sizeof(*decdata));
Stefan Reinauerd650e992010-02-22 04:33:13 +0000738 int ret = 0;
739 DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
740 ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
741 DEBUG_PRINTF_VBE("returns %x\n", ret);
Stefan Reinauerc1efb902011-10-12 14:30:59 -0700742#endif
Stefan Reinauerd650e992010-02-22 04:33:13 +0000743}
744
745void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
746{
747 framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
748
749 framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
750 framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
751 framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
752 framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
753
754 framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
755 framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
756
757 framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
758 framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
759
760 framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
761 framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
762
763 framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
764 framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
765}
766
767void vbe_textmode_console(void)
768{
769 /* Wait, just a little bit more, pleeeease ;-) */
770 delay(2);
771
772 M.x86.R_EAX = 0x0003;
773 runInt10();
774}
775
776#endif