1 /* $NetBSD: vbe.c,v 1.8 2013/05/31 15:11:07 tsutsui Exp $ */
4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * VESA BIOS Extensions routines
33 #include <lib/libsa/stand.h>
34 #include <lib/libkern/libkern.h>
35 #include <machine/bootinfo.h>
39 extern const uint8_t rasops_cmap
[];
40 static uint8_t *vbe_edid
= NULL
;
41 static int vbe_edid_valid
= 0;
43 static struct _vbestate
{
49 vbe_mode_is_supported(struct modeinfoblock
*mi
)
51 if ((mi
->ModeAttributes
& 0x01) == 0)
52 return 0; /* mode not supported by hardware */
53 if ((mi
->ModeAttributes
& 0x08) == 0)
54 return 0; /* linear fb not available */
55 if ((mi
->ModeAttributes
& 0x10) == 0)
56 return 0; /* text mode */
57 if (mi
->NumberOfPlanes
!= 1)
58 return 0; /* planar mode not supported */
59 if (mi
->MemoryModel
!= 0x04 /* Packed pixel */ &&
60 mi
->MemoryModel
!= 0x06 /* Direct Color */)
61 return 0; /* unsupported pixel format */
68 if (!vbestate
.available
) {
69 printf("VBE not available\n");
78 struct vbeinfoblock vbe
;
80 memset(&vbe
, 0, sizeof(vbe
));
81 memcpy(vbe
.VbeSignature
, "VBE2", 4);
82 if (biosvbe_info(&vbe
) != 0x004f)
84 if (memcmp(vbe
.VbeSignature
, "VESA", 4) != 0)
87 vbestate
.available
= 1;
94 return vbestate
.available
;
98 vbe_set_palette(const uint8_t *cmap
, int slot
)
100 struct paletteentry pe
;
106 pe
.Blue
= cmap
[2] >> 2;
107 pe
.Green
= cmap
[1] >> 2;
108 pe
.Red
= cmap
[0] >> 2;
111 ret
= biosvbe_palette_data(0x0600, slot
, &pe
);
113 return ret
== 0x004f ? 0 : 1;
117 vbe_set_mode(int modenum
)
119 struct modeinfoblock mi
;
120 struct btinfo_framebuffer fb
;
126 ret
= biosvbe_get_mode_info(modenum
, &mi
);
128 printf("mode 0x%x invalid\n", modenum
);
132 if (!vbe_mode_is_supported(&mi
)) {
133 printf("mode 0x%x not supported\n", modenum
);
137 ret
= biosvbe_set_mode(modenum
);
139 printf("mode 0x%x could not be set\n", modenum
);
143 /* Setup palette for packed pixel mode */
144 if (mi
.MemoryModel
== 0x04)
145 for (i
= 0; i
< 256; i
++)
146 vbe_set_palette(&rasops_cmap
[i
* 3], i
);
148 fb
.physaddr
= (uint64_t)mi
.PhysBasePtr
& 0xffffffff;
149 fb
.width
= mi
.XResolution
;
150 fb
.height
= mi
.YResolution
;
151 fb
.stride
= mi
.BytesPerScanLine
;
152 fb
.depth
= mi
.BitsPerPixel
;
154 fb
.rnum
= mi
.RedMaskSize
;
155 fb
.rpos
= mi
.RedFieldPosition
;
156 fb
.gnum
= mi
.GreenMaskSize
;
157 fb
.gpos
= mi
.GreenFieldPosition
;
158 fb
.bnum
= mi
.BlueMaskSize
;
159 fb
.bpos
= mi
.BlueFieldPosition
;
160 fb
.vbemode
= modenum
;
162 framebuffer_configure(&fb
);
172 if (vbestate
.modenum
> 0) {
173 ret
= vbe_set_mode(vbestate
.modenum
);
175 printf("WARNING: failed to set VBE mode 0x%x\n",
184 vbe_farptr(uint32_t farptr
)
186 return VBEPHYPTR((((farptr
& 0xffff0000) >> 12) + (farptr
& 0xffff)));
190 vbe_parse_mode_str(char *str
, int *x
, int *y
, int *depth
)
195 *x
= strtoul(p
, NULL
, 0);
202 *y
= strtoul(p
, NULL
, 0);
210 *depth
= strtoul(p
, NULL
, 0);
219 vbe_find_mode_xyd(int x
, int y
, int depth
)
221 struct vbeinfoblock vbe
;
222 struct modeinfoblock mi
;
227 memset(&vbe
, 0, sizeof(vbe
));
228 memcpy(vbe
.VbeSignature
, "VBE2", 4);
229 if (biosvbe_info(&vbe
) != 0x004f)
231 if (memcmp(vbe
.VbeSignature
, "VESA", 4) != 0)
233 farptr
= vbe
.VideoModePtr
;
237 while ((mode
= *(uint16_t *)vbe_farptr(farptr
)) != 0xffff) {
242 if (biosvbe_get_mode_info(mode
, &mi
) != 0x004f)
244 /* we only care about linear modes here */
245 if (vbe_mode_is_supported(&mi
) == 0)
248 if (mi
.XResolution
== x
&&
249 mi
.YResolution
== y
&&
250 mi
.BitsPerPixel
== depth
)
258 vbe_find_mode(char *str
)
262 if (!vbe_parse_mode_str(str
, &x
, &y
, &depth
))
265 return vbe_find_mode_xyd(x
, y
, depth
);
269 vbe_dump_mode(int modenum
, struct modeinfoblock
*mi
)
271 printf("0x%x=%dx%dx%d", modenum
,
272 mi
->XResolution
, mi
->YResolution
, mi
->BitsPerPixel
);
276 vbe_get_edid(int *pwidth
, int *pheight
)
278 const uint8_t magic
[] = EDID_MAGIC
;
281 ddc_caps
= biosvbe_ddc_caps();
286 if (vbe_edid
== NULL
) {
287 vbe_edid
= alloc(128);
289 if (vbe_edid_valid
== 0) {
290 ret
= biosvbe_ddc_read_edid(0, vbe_edid
);
293 if (memcmp(vbe_edid
, magic
, sizeof(magic
)) != 0)
298 *pwidth
= vbe_edid
[EDID_DESC_BLOCK
+ 2] |
299 (((int)vbe_edid
[EDID_DESC_BLOCK
+ 4] & 0xf0) << 4);
300 *pheight
= vbe_edid
[EDID_DESC_BLOCK
+ 5] |
301 (((int)vbe_edid
[EDID_DESC_BLOCK
+ 7] & 0xf0) << 4);
309 struct vbeinfoblock vbe
;
310 struct modeinfoblock mi
;
313 int nmodes
= 0, safety
= 0;
314 int ddc_caps
, edid_width
, edid_height
;
319 ddc_caps
= biosvbe_ddc_caps();
327 if (vbe_get_edid(&edid_width
, &edid_height
) != 0)
328 printf(": no EDID information\n");
330 printf(": EDID %dx%d\n", edid_width
, edid_height
);
334 memset(&vbe
, 0, sizeof(vbe
));
335 memcpy(vbe
.VbeSignature
, "VBE2", 4);
336 if (biosvbe_info(&vbe
) != 0x004f)
338 if (memcmp(vbe
.VbeSignature
, "VESA", 4) != 0)
340 farptr
= vbe
.VideoModePtr
;
344 while ((mode
= *(uint16_t *)vbe_farptr(farptr
)) != 0xffff) {
351 if (biosvbe_get_mode_info(mode
, &mi
) != 0x004f)
353 /* we only care about linear modes here */
354 if (vbe_mode_is_supported(&mi
) == 0)
361 vbe_dump_mode(mode
, &mi
);
367 printf("none found");
372 command_vesa(char *cmd
)
375 int modenum
, edid_width
, edid_height
;
380 strlcpy(arg
, cmd
, sizeof(arg
));
382 if (strcmp(arg
, "list") == 0) {
387 if (strcmp(arg
, "disabled") == 0 || strcmp(arg
, "off") == 0) {
388 vbestate
.modenum
= 0;
392 if (strcmp(arg
, "enabled") == 0 || strcmp(arg
, "on") == 0) {
393 if (vbe_get_edid(&edid_width
, &edid_height
) != 0) {
394 modenum
= VBE_DEFAULT_MODE
;
396 modenum
= vbe_find_mode_xyd(edid_width
, edid_height
, 8);
398 modenum
= VBE_DEFAULT_MODE
;
400 } else if (strncmp(arg
, "0x", 2) == 0) {
401 modenum
= strtoul(arg
, NULL
, 0);
402 } else if (strchr(arg
, 'x') != NULL
) {
403 modenum
= vbe_find_mode(arg
);
405 printf("mode %s not supported by firmware\n", arg
);
412 if (modenum
>= 0x100) {
413 vbestate
.modenum
= modenum
;
417 printf("invalid flag, must be 'on', 'off', 'list', "
418 "a display mode, or a VBE mode number\n");