blob: d80a97acc6b9bcd565dcd9a99a47a35e053839ec [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 Reinauerd650e992010-02-22 04:33:13 +000016#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)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000022
23#include "debug.h"
24
25#include <x86emu/x86emu.h>
26#include <x86emu/regs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000027#include "../x86emu/prim_ops.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000028
29#include "biosemu.h"
30#include "io.h"
31#include "mem.h"
32#include "interrupt.h"
33#include "device.h"
Stefan Reinauer3c486f82010-03-17 04:04:20 +000034#include "vbe.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000035
Stefan Reinauerd650e992010-02-22 04:33:13 +000036#include <cbfs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000037
Stefan Reinauerd650e992010-02-22 04:33:13 +000038#include <delay.h>
39#include "../../src/lib/jpeg.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000040
41// 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
48// these structs are for input from and output to OF
49typedef 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
59typedef 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.
69typedef 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
78typedef struct {
Stefan Reinauerd650e992010-02-22 04:33:13 +000079 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
114typedef struct {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000115 u16 video_mode;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000116 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;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000130} vbe_mode_info_t;
131
132typedef 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
139static inline u8
Stefan Reinauerd650e992010-02-22 04:33:13 +0000140vbe_prepare(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000141{
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
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000157#if CONFIG_BOOTSPLASH || CONFIG_EXPERT
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000158// VBE Function 00h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000159static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000160vbe_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
Uwe Hermann01ce6012010-03-05 10:03:50 +0000228static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000229vbe_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 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000256
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000257 //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
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000265 return 0;
266}
267
268// VBE Function 02h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000269static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000270vbe_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}
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000304#endif
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000305
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000306#if CONFIG_EXPERT
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000307//VBE Function 08h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000308static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000309vbe_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
Uwe Hermann01ce6012010-03-05 10:03:50 +0000344static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000345vbe_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
Uwe Hermann01ce6012010-03-05 10:03:50 +0000386static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000387vbe_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
Uwe Hermann01ce6012010-03-05 10:03:50 +0000429static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000430vbe_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
Uwe Hermann01ce6012010-03-05 10:03:50 +0000503static u32
Stefan Reinauerd650e992010-02-22 04:33:13 +0000504vbe_get_info(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000505{
506 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000507 int i;
508
509 // XXX FIXME these need to be filled with sane values
510
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000511 // get a copy of input struct...
Stefan Reinauerd650e992010-02-22 04:33:13 +0000512 screen_info_input_t input;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000513 // output is pointer to the address passed as argv[4]
Stefan Reinauerd650e992010-02-22 04:33:13 +0000514 screen_info_t local_output;
515 screen_info_t *output = &local_output;
516 // zero input
517 memset(&input, 0, sizeof(screen_info_input_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000518 // zero output
Stefan Reinauerd650e992010-02-22 04:33:13 +0000519 memset(&output, 0, sizeof(screen_info_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000520
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
Myles Watsonb0259112010-03-05 18:27:19 +0000577/* 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 ) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000588 // 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);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000610
611 // FIXME all these values are little endian!
612
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000613 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
614 mode_info.video_mode,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000615 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000616 0 ? "not supported" : "supported");
617 DEBUG_PRINTF_VBE("\tTTY: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000618 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000619 0 ? "no" : "yes");
620 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000621 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000622 0 ? "monochrome" : "color",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000623 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000624 0 ? "text" : "graphics");
625 DEBUG_PRINTF_VBE("\tVGA: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000626 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000627 0 ? "compatible" : "not compatible");
628 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000629 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000630 0 ? "yes" : "no");
631 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000632 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000633 0 ? "no" : "yes");
634 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000635 le16_to_cpu(mode_info.vesa.x_resolution),
636 le16_to_cpu(mode_info.vesa.y_resolution));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000637 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000638 mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000639 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000640 mode_info.vesa.bits_per_pixel);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000641 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000642 mode_info.vesa.memory_model);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000643 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000644 le32_to_cpu(mode_info.vesa.phys_base_ptr));
Stefan Reinauerd650e992010-02-22 04:33:13 +0000645
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
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000652 {
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,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000663 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));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000667
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
Stefan Reinauerd650e992010-02-22 04:33:13 +0000756 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;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000760 output->framebuffer_address =
Stefan Reinauerd650e992010-02-22 04:33:13 +0000761 le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000762 } 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}
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000769#endif
Stefan Reinauerd650e992010-02-22 04:33:13 +0000770
771#if CONFIG_BOOTSPLASH
772vbe_mode_info_t mode_info;
773
774void vbe_set_graphics(void)
775{
776 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000777
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. */
Stefan Reinauer3c486f82010-03-17 04:04:20 +0000809 // int imagesize = 1024*768*2;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000810
Stefan Reinauer800379f2010-03-01 08:34:19 +0000811 unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
812 if (!jpeg) {
Stefan Reinauerd650e992010-02-22 04:33:13 +0000813 DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
814 return;
815 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000816 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
825void 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
847void 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