blob: a3d736fa936aa388969aaa1d7928209a99a6977b [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>
Martin Rotha9e1a222016-01-14 14:15:24 -07004 *
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00005 * All rights reserved.
Martin Rotha9e1a222016-01-14 14:15:24 -07006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000030 *
31 * Contributors:
32 * IBM Corporation - initial implementation
33 *****************************************************************************/
34
Elyes HAOUAS0edf6a52019-10-26 18:41:47 +020035#include <boot/coreboot_tables.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000036#include <string.h>
37#include <types.h>
Stefan Reinauerd650e992010-02-22 04:33:13 +000038
Julius Werner9ff8f6f2015-02-23 14:31:09 -080039#include <endian.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000040
41#include "debug.h"
42
43#include <x86emu/x86emu.h>
44#include <x86emu/regs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000045#include "../x86emu/prim_ops.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000046
47#include "biosemu.h"
48#include "io.h"
49#include "mem.h"
50#include "interrupt.h"
51#include "device.h"
52
Stefan Reinauerd650e992010-02-22 04:33:13 +000053#include <delay.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000054
Stefan Reinauer216fa462011-10-12 14:25:07 -070055#include <vbe.h>
56
Subrata Banika2602152019-07-12 17:41:43 +053057// these structs only store a subset of the VBE defined fields
58// only those needed.
59typedef struct {
60 char signature[4];
61 u16 version;
62 u8 *oem_string_ptr;
63 u32 capabilities;
64 u16 video_mode_list[256]; // lets hope we never have more than
65 // 256 video modes...
66 u16 total_memory;
67} vbe_info_t;
68
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000069// pointer to VBEInfoBuffer, set by vbe_prepare
70u8 *vbe_info_buffer = 0;
Stefan Reinauerd650e992010-02-22 04:33:13 +000071
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000072// virtual BIOS Memory
73u8 *biosmem;
74u32 biosmem_size;
75
Julius Wernercd49cce2019-03-05 16:53:33 -080076#if CONFIG(FRAMEBUFFER_SET_VESA_MODE)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000077static inline u8
Stefan Reinauerd650e992010-02-22 04:33:13 +000078vbe_prepare(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000079{
80 vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
81 //clear buffer
82 memset(vbe_info_buffer, 0, 512);
83 //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
84 vbe_info_buffer[0] = 'V';
Hal Tsai551e1fe2018-04-19 13:52:33 +080085 vbe_info_buffer[1] = 'B';
86 vbe_info_buffer[2] = 'E';
87 vbe_info_buffer[3] = '2';
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000088 // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
89 M.x86.R_EDI = 0x0;
90 M.x86.R_ES = VBE_SEGMENT;
91
Paul Menzel484aa422018-04-20 14:40:18 +020092 return 0; // successful init
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000093}
94
95// VBE Function 00h
Uwe Hermann01ce6012010-03-05 10:03:50 +000096static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000097vbe_info(vbe_info_t * info)
98{
99 vbe_prepare();
100 // call VBE function 00h (Info Function)
101 M.x86.R_EAX = 0x4f00;
102
103 // enable trace
104 CHECK_DBG(DEBUG_TRACE_X86EMU) {
105 X86EMU_trace_on();
106 }
107 // run VESA Interrupt
108 runInt10();
109
110 if (M.x86.R_AL != 0x4f) {
111 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
112 __func__, M.x86.R_AL);
113 return -1;
114 }
115
116 if (M.x86.R_AH != 0x0) {
117 DEBUG_PRINTF_VBE
118 ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
119 __func__, M.x86.R_AH);
120 return M.x86.R_AH;
121 }
122 //printf("VBE Info Dump:");
123 //dump(vbe_info_buffer, 64);
124
125 //offset 0: signature
126 info->signature[0] = vbe_info_buffer[0];
127 info->signature[1] = vbe_info_buffer[1];
128 info->signature[2] = vbe_info_buffer[2];
129 info->signature[3] = vbe_info_buffer[3];
130
131 // offset 4: 16bit le containing VbeVersion
132 info->version = in16le(vbe_info_buffer + 4);
133
Martin Roth63373ed2013-07-08 16:24:19 -0600134 // offset 6: 32bit le containing segment:offset of OEM String in virtual Mem.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000135 info->oem_string_ptr =
136 biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
137 in16le(vbe_info_buffer + 6));
138
139 // offset 10: 32bit le capabilities
140 info->capabilities = in32le(vbe_info_buffer + 10);
141
142 // offset 14: 32 bit le containing segment:offset of supported video mode table
143 u16 *video_mode_ptr;
144 video_mode_ptr =
145 (u16 *) (biosmem +
146 ((in16le(vbe_info_buffer + 16) << 4) +
147 in16le(vbe_info_buffer + 14)));
148 u32 i = 0;
149 do {
150 info->video_mode_list[i] = in16le(video_mode_ptr + i);
151 i++;
152 }
153 while ((i <
154 (sizeof(info->video_mode_list) /
155 sizeof(info->video_mode_list[0])))
156 && (info->video_mode_list[i - 1] != 0xFFFF));
157
158 //offset 18: 16bit le total memory in 64KB blocks
159 info->total_memory = in16le(vbe_info_buffer + 18);
160
161 return 0;
162}
163
Gabe Blackfb8632a2012-09-30 04:47:48 -0700164static int mode_info_valid;
165
Aaron Durbin57e15e62017-05-16 21:50:27 -0500166static int vbe_mode_info_valid(void)
Gabe Blackfb8632a2012-09-30 04:47:48 -0700167{
168 return mode_info_valid;
169}
170
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000171// VBE Function 01h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000172static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000173vbe_get_mode_info(vbe_mode_info_t * mode_info)
174{
175 vbe_prepare();
176 // call VBE function 01h (Return VBE Mode Info Function)
177 M.x86.R_EAX = 0x4f01;
178 M.x86.R_CX = mode_info->video_mode;
179
180 // enable trace
181 CHECK_DBG(DEBUG_TRACE_X86EMU) {
182 X86EMU_trace_on();
183 }
184 // run VESA Interrupt
185 runInt10();
186
187 if (M.x86.R_AL != 0x4f) {
188 DEBUG_PRINTF_VBE
189 ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
190 __func__, M.x86.R_AL);
191 return -1;
192 }
193
194 if (M.x86.R_AH != 0x0) {
195 DEBUG_PRINTF_VBE
196 ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
197 __func__, mode_info->video_mode, M.x86.R_AH);
198 return M.x86.R_AH;
199 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000200
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000201 //pointer to mode_info_block is in ES:DI
202 memcpy(mode_info->mode_info_block,
203 biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
204 sizeof(mode_info->mode_info_block));
Gabe Blackfb8632a2012-09-30 04:47:48 -0700205 mode_info_valid = 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000206
207 //printf("Mode Info Dump:");
208 //dump(mode_info_block, 64);
209
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000210 return 0;
211}
212
213// VBE Function 02h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000214static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000215vbe_set_mode(vbe_mode_info_t * mode_info)
216{
217 vbe_prepare();
218 // call VBE function 02h (Set VBE Mode Function)
219 M.x86.R_EAX = 0x4f02;
220 M.x86.R_BX = mode_info->video_mode;
221 M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
222 M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
223
224 DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
225 M.x86.R_BX);
226
227 // enable trace
228 CHECK_DBG(DEBUG_TRACE_X86EMU) {
229 X86EMU_trace_on();
230 }
231 // run VESA Interrupt
232 runInt10();
233
234 if (M.x86.R_AL != 0x4f) {
235 DEBUG_PRINTF_VBE
236 ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
237 __func__, M.x86.R_AL);
238 return -1;
239 }
240
241 if (M.x86.R_AH != 0x0) {
242 DEBUG_PRINTF_VBE
243 ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
244 __func__, mode_info->video_mode, M.x86.R_AH);
245 return M.x86.R_AH;
246 }
247 return 0;
248}
249
Patrick Georgif0bf4b52011-01-21 12:45:37 +0000250#if 0
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000251//VBE Function 08h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000252static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000253vbe_set_palette_format(u8 format)
254{
255 vbe_prepare();
256 // call VBE function 09h (Set/Get Palette Data Function)
257 M.x86.R_EAX = 0x4f08;
258 M.x86.R_BL = 0x00; // set format
259 M.x86.R_BH = format;
260
261 DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
262 format);
263
264 // enable trace
265 CHECK_DBG(DEBUG_TRACE_X86EMU) {
266 X86EMU_trace_on();
267 }
268 // run VESA Interrupt
269 runInt10();
270
271 if (M.x86.R_AL != 0x4f) {
272 DEBUG_PRINTF_VBE
273 ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
274 __func__, M.x86.R_AL);
275 return -1;
276 }
277
278 if (M.x86.R_AH != 0x0) {
279 DEBUG_PRINTF_VBE
280 ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
281 __func__, M.x86.R_AH);
282 return M.x86.R_AH;
283 }
284 return 0;
285}
286
287// VBE Function 09h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000288static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000289vbe_set_color(u16 color_number, u32 color_value)
290{
291 vbe_prepare();
292 // call VBE function 09h (Set/Get Palette Data Function)
293 M.x86.R_EAX = 0x4f09;
294 M.x86.R_BL = 0x00; // set color
295 M.x86.R_CX = 0x01; // set only one entry
296 M.x86.R_DX = color_number;
297 // ES:DI is address where color_value is stored, we store it at 2000:0000
298 M.x86.R_ES = 0x2000;
299 M.x86.R_DI = 0x0;
300
301 // store color value at ES:DI
302 out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
303
304 DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
305 color_number, color_value);
306
307 // enable trace
308 CHECK_DBG(DEBUG_TRACE_X86EMU) {
309 X86EMU_trace_on();
310 }
311 // run VESA Interrupt
312 runInt10();
313
314 if (M.x86.R_AL != 0x4f) {
315 DEBUG_PRINTF_VBE
316 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
317 __func__, M.x86.R_AL);
318 return -1;
319 }
320
321 if (M.x86.R_AH != 0x0) {
322 DEBUG_PRINTF_VBE
323 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
324 __func__, M.x86.R_AH);
325 return M.x86.R_AH;
326 }
327 return 0;
328}
329
Uwe Hermann01ce6012010-03-05 10:03:50 +0000330static u8
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200331vbe_get_color(u16 color_number, u32 *color_value)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000332{
333 vbe_prepare();
334 // call VBE function 09h (Set/Get Palette Data Function)
335 M.x86.R_EAX = 0x4f09;
336 M.x86.R_BL = 0x00; // get color
337 M.x86.R_CX = 0x01; // get only one entry
338 M.x86.R_DX = color_number;
339 // ES:DI is address where color_value is stored, we store it at 2000:0000
340 M.x86.R_ES = 0x2000;
341 M.x86.R_DI = 0x0;
342
343 // enable trace
344 CHECK_DBG(DEBUG_TRACE_X86EMU) {
345 X86EMU_trace_on();
346 }
347 // run VESA Interrupt
348 runInt10();
349
350 if (M.x86.R_AL != 0x4f) {
351 DEBUG_PRINTF_VBE
352 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
353 __func__, M.x86.R_AL);
354 return -1;
355 }
356
357 if (M.x86.R_AH != 0x0) {
358 DEBUG_PRINTF_VBE
359 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
360 __func__, M.x86.R_AH);
361 return M.x86.R_AH;
362 }
363 // read color value from ES:DI
364 *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
365
366 DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
367 color_number, *color_value);
368
369 return 0;
370}
371
372// VBE Function 15h
Uwe Hermann01ce6012010-03-05 10:03:50 +0000373static u8
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000374vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
375{
376 vbe_prepare();
377 // call VBE function 15h (DDC Info Function)
378 M.x86.R_EAX = 0x4f15;
379 M.x86.R_BL = 0x00; // get DDC Info
380 M.x86.R_CX = ddc_info->port_number;
381 M.x86.R_ES = 0x0;
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 Get DDC Info 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 Get DDC Info 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 // BH = approx. time in seconds to transfer one EDID block
405 ddc_info->edid_transfer_time = M.x86.R_BH;
406 // BL = DDC Level
407 ddc_info->ddc_level = M.x86.R_BL;
408
409 vbe_prepare();
410 // call VBE function 15h (DDC Info Function)
411 M.x86.R_EAX = 0x4f15;
412 M.x86.R_BL = 0x01; // read EDID
413 M.x86.R_CX = ddc_info->port_number;
414 M.x86.R_DX = 0x0; // block number
415 // ES:DI is address where EDID is stored, we store it at 2000:0000
416 M.x86.R_ES = 0x2000;
417 M.x86.R_DI = 0x0;
418
419 // enable trace
420 CHECK_DBG(DEBUG_TRACE_X86EMU) {
421 X86EMU_trace_on();
422 }
423 // run VESA Interrupt
424 runInt10();
425
426 if (M.x86.R_AL != 0x4f) {
427 DEBUG_PRINTF_VBE
428 ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
429 __func__, M.x86.R_AL);
430 return -1;
431 }
432
433 if (M.x86.R_AH != 0x0) {
434 DEBUG_PRINTF_VBE
435 ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
436 __func__, ddc_info->port_number, M.x86.R_AH);
437 return M.x86.R_AH;
438 }
439
440 memcpy(ddc_info->edid_block_zero,
441 biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
442 sizeof(ddc_info->edid_block_zero));
443
444 return 0;
445}
446
Uwe Hermann01ce6012010-03-05 10:03:50 +0000447static u32
Stefan Reinauerd650e992010-02-22 04:33:13 +0000448vbe_get_info(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000449{
450 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000451 int i;
452
453 // XXX FIXME these need to be filled with sane values
454
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000455 // get a copy of input struct...
Stefan Reinauerd650e992010-02-22 04:33:13 +0000456 screen_info_input_t input;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000457 // output is pointer to the address passed as argv[4]
Stefan Reinauerd650e992010-02-22 04:33:13 +0000458 screen_info_t local_output;
459 screen_info_t *output = &local_output;
460 // zero input
461 memset(&input, 0, sizeof(screen_info_input_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000462 // zero output
Stefan Reinauerd650e992010-02-22 04:33:13 +0000463 memset(&output, 0, sizeof(screen_info_t));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000464
465 vbe_info_t info;
466 rval = vbe_info(&info);
467 if (rval != 0)
468 return rval;
469
470 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
471 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
472 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
473 DEBUG_PRINTF_VBE("Capabilities:\n");
474 DEBUG_PRINTF_VBE("\tDAC: %s\n",
475 (info.capabilities & 0x1) ==
476 0 ? "fixed 6bit" : "switchable 6/8bit");
477 DEBUG_PRINTF_VBE("\tVGA: %s\n",
478 (info.capabilities & 0x2) ==
479 0 ? "compatible" : "not compatible");
480 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
481 (info.capabilities & 0x4) ==
482 0 ? "normal" : "use blank bit in Function 09h");
483
484 // argv[4] may be a pointer with enough space to return screen_info_t
485 // as input, it must contain a screen_info_input_t with the following content:
486 // byte[0:3] = "DDC\0" (zero-terminated signature header)
487 // byte[4:5] = reserved space for the return struct... just in case we ever change
Martin Roth63373ed2013-07-08 16:24:19 -0600488 // the struct and don't have reserved enough memory (and let's hope the struct
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000489 // never gets larger than 64KB)
490 // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
491 // byte[7:8] = max. screen width (OF may want to limit this)
492 // byte[9] = required color depth in bpp
493 if (strncmp((char *) input.signature, "DDC", 4) != 0) {
494 printf
495 ("%s: Invalid input signature! expected: %s, is: %s\n",
496 __func__, "DDC", input.signature);
497 return -1;
498 }
499 if (input.size_reserved != sizeof(screen_info_t)) {
500 printf
501 ("%s: Size of return struct is wrong, required: %d, available: %d\n",
502 __func__, (int) sizeof(screen_info_t),
503 input.size_reserved);
504 return -1;
505 }
506
507 vbe_ddc_info_t ddc_info;
508 ddc_info.port_number = input.monitor_number;
509 vbe_get_ddc_info(&ddc_info);
510
511#if 0
Elyes HAOUAS394ec022018-08-07 12:23:43 +0200512 DEBUG_PRINTF_VBE("DDC: edid_transfer_time: %d\n",
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000513 ddc_info.edid_transfer_time);
514 DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
Elyes HAOUASa1ac10f2016-08-21 18:21:59 +0200515 DEBUG_PRINTF_VBE("DDC: EDID:\n");
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000516 CHECK_DBG(DEBUG_VBE) {
517 dump(ddc_info.edid_block_zero,
518 sizeof(ddc_info.edid_block_zero));
519 }
520#endif
Myles Watsonb0259112010-03-05 18:27:19 +0000521/* This could fail because of alignment issues, so use a longer form.
522 *((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
523*/
524 if (ddc_info.edid_block_zero[0] != 0x00 ||
525 ddc_info.edid_block_zero[1] != 0xFF ||
526 ddc_info.edid_block_zero[2] != 0xFF ||
527 ddc_info.edid_block_zero[3] != 0xFF ||
528 ddc_info.edid_block_zero[4] != 0xFF ||
529 ddc_info.edid_block_zero[5] != 0xFF ||
530 ddc_info.edid_block_zero[6] != 0xFF ||
531 ddc_info.edid_block_zero[7] != 0x00 ) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000532 // invalid EDID signature... probably no monitor
533
534 output->display_type = 0x0;
535 return 0;
536 } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
537 // digital display
538 output->display_type = 2;
539 } else {
540 // analog
541 output->display_type = 1;
542 }
543 DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
544 memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
545 sizeof(ddc_info.edid_block_zero));
546 i = 0;
547 vbe_mode_info_t mode_info;
548 vbe_mode_info_t best_mode_info;
549 // initialize best_mode to 0
550 memset(&best_mode_info, 0, sizeof(best_mode_info));
551 while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
552 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
553 vbe_get_mode_info(&mode_info);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000554
555 // FIXME all these values are little endian!
556
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000557 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
558 mode_info.video_mode,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000559 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000560 0 ? "not supported" : "supported");
561 DEBUG_PRINTF_VBE("\tTTY: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000562 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000563 0 ? "no" : "yes");
564 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000565 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000566 0 ? "monochrome" : "color",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000567 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000568 0 ? "text" : "graphics");
569 DEBUG_PRINTF_VBE("\tVGA: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000570 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000571 0 ? "compatible" : "not compatible");
572 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000573 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000574 0 ? "yes" : "no");
575 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000576 (le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000577 0 ? "no" : "yes");
578 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000579 le16_to_cpu(mode_info.vesa.x_resolution),
580 le16_to_cpu(mode_info.vesa.y_resolution));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000581 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000582 mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000583 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000584 mode_info.vesa.bits_per_pixel);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000585 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000586 mode_info.vesa.memory_model);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000587 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
Uwe Hermann01ce6012010-03-05 10:03:50 +0000588 le32_to_cpu(mode_info.vesa.phys_base_ptr));
Stefan Reinauerd650e992010-02-22 04:33:13 +0000589
590 if ((mode_info.vesa.bits_per_pixel == input.color_depth)
591 && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
592 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
593 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
594 && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
595 && (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 +0000596 {
597 // yiiiihaah... we found a new best mode
598 memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
599 }
600 i++;
601 }
602
603 if (best_mode_info.video_mode != 0) {
604 DEBUG_PRINTF_VBE
605 ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
606 best_mode_info.video_mode,
Uwe Hermann01ce6012010-03-05 10:03:50 +0000607 best_mode_info.vesa.x_resolution,
608 best_mode_info.vesa.y_resolution,
609 best_mode_info.vesa.bits_per_pixel,
610 le32_to_cpu(best_mode_info.vesa.phys_base_ptr));
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000611
612 //printf("Mode Info Dump:");
613 //dump(best_mode_info.mode_info_block, 64);
614
615 // set the video mode
616 vbe_set_mode(&best_mode_info);
617
618 if ((info.capabilities & 0x1) != 0) {
619 // switch to 8 bit palette format
620 vbe_set_palette_format(8);
621 }
622 // setup a palette:
623 // - first 216 colors are mixed colors for each component in 6 steps
624 // (6*6*6=216)
625 // - then 10 shades of the three primary colors
626 // - then 10 shades of grey
627 // -------
628 // = 256 colors
629 //
630 // - finally black is color 0 and white color FF (because SLOF expects it
631 // this way...)
632 // this resembles the palette that the kernel/X Server seems to expect...
633
634 u8 mixed_color_values[6] =
635 { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
636 u8 primary_color_values[10] =
637 { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
638 0x27
639 };
640 u8 mc_size = sizeof(mixed_color_values);
641 u8 prim_size = sizeof(primary_color_values);
642
643 u8 curr_color_index;
644 u32 curr_color;
645
646 u8 r, g, b;
647 // 216 mixed colors
648 for (r = 0; r < mc_size; r++) {
649 for (g = 0; g < mc_size; g++) {
650 for (b = 0; b < mc_size; b++) {
651 curr_color_index =
652 (r * mc_size * mc_size) +
653 (g * mc_size) + b;
654 curr_color = 0;
655 curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
656 curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
657 curr_color |= (u32) mixed_color_values[b]; //blue value
658 vbe_set_color(curr_color_index,
659 curr_color);
660 }
661 }
662 }
663
664 // 10 shades of each primary color
665 // red
666 for (r = 0; r < prim_size; r++) {
667 curr_color_index = mc_size * mc_size * mc_size + r;
668 curr_color = ((u32) primary_color_values[r]) << 16;
669 vbe_set_color(curr_color_index, curr_color);
670 }
671 //green
672 for (g = 0; g < prim_size; g++) {
673 curr_color_index =
674 mc_size * mc_size * mc_size + prim_size + g;
675 curr_color = ((u32) primary_color_values[g]) << 8;
676 vbe_set_color(curr_color_index, curr_color);
677 }
678 //blue
679 for (b = 0; b < prim_size; b++) {
680 curr_color_index =
681 mc_size * mc_size * mc_size + prim_size * 2 + b;
682 curr_color = (u32) primary_color_values[b];
683 vbe_set_color(curr_color_index, curr_color);
684 }
685 // 10 shades of grey
686 for (i = 0; i < prim_size; i++) {
687 curr_color_index =
688 mc_size * mc_size * mc_size + prim_size * 3 + i;
689 curr_color = 0;
690 curr_color |= ((u32) primary_color_values[i]) << 16; //red
691 curr_color |= ((u32) primary_color_values[i]) << 8; //green
692 curr_color |= ((u32) primary_color_values[i]); //blue
693 vbe_set_color(curr_color_index, curr_color);
694 }
695
696 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
697 vbe_set_color(0x00, 0x00000000);
698 vbe_set_color(0xFF, 0x00FFFFFF);
699
Stefan Reinauerd650e992010-02-22 04:33:13 +0000700 output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
701 output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
702 output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
703 output->color_depth = best_mode_info.vesa.bits_per_pixel;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000704 output->framebuffer_address =
Stefan Reinauerd650e992010-02-22 04:33:13 +0000705 le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000706 } else {
707 printf("%s: No suitable video mode found!\n", __func__);
708 //unset display_type...
709 output->display_type = 0;
710 }
711 return 0;
712}
Patrick Georgif0bf4b52011-01-21 12:45:37 +0000713#endif
Stefan Reinauerd650e992010-02-22 04:33:13 +0000714
Johanna Schanderdb7a3ae2019-07-24 10:14:26 +0200715static vbe_mode_info_t mode_info;
716
717const vbe_mode_info_t *vbe_mode_info(void)
718{
719 if (!mode_info_valid || !mode_info.vesa.phys_base_ptr)
720 return NULL;
721 return &mode_info;
722}
Stefan Reinauerd650e992010-02-22 04:33:13 +0000723
724void vbe_set_graphics(void)
725{
726 u8 rval;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000727
728 vbe_info_t info;
729 rval = vbe_info(&info);
730 if (rval != 0)
731 return;
732
733 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
734 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
735 DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
736 DEBUG_PRINTF_VBE("Capabilities:\n");
737 DEBUG_PRINTF_VBE("\tDAC: %s\n",
738 (info.capabilities & 0x1) ==
739 0 ? "fixed 6bit" : "switchable 6/8bit");
740 DEBUG_PRINTF_VBE("\tVGA: %s\n",
741 (info.capabilities & 0x2) ==
742 0 ? "compatible" : "not compatible");
743 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
744 (info.capabilities & 0x4) ==
745 0 ? "normal" : "use blank bit in Function 09h");
746
747 mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
748 vbe_get_mode_info(&mode_info);
Stefan Reinauerc1efb902011-10-12 14:30:59 -0700749 vbe_set_mode(&mode_info);
Stefan Reinauerd650e992010-02-22 04:33:13 +0000750}
751
Aaron Durbinbdb5c8f2017-05-16 21:39:50 -0500752int fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
Stefan Reinauerd650e992010-02-22 04:33:13 +0000753{
Aaron Durbinbdb5c8f2017-05-16 21:39:50 -0500754 if (!vbe_mode_info_valid())
755 return -1;
756
Stefan Reinauerd650e992010-02-22 04:33:13 +0000757 framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
758
759 framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
760 framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
761 framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
762 framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
763
764 framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
765 framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
766
767 framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
768 framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
769
770 framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
771 framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
772
773 framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
774 framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
Aaron Durbinbdb5c8f2017-05-16 21:39:50 -0500775
776 return 0;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000777}
778
779void vbe_textmode_console(void)
780{
781 /* Wait, just a little bit more, pleeeease ;-) */
782 delay(2);
783
784 M.x86.R_EAX = 0x0003;
785 runInt10();
786}
787
788#endif