xref: /openbmc/linux/arch/x86/boot/video-bios.c (revision 97873a3d)
197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner  *
496ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
6cf06de7bSH. Peter Anvin  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
796ae6ea0SThomas Gleixner  *
896ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
996ae6ea0SThomas Gleixner 
1096ae6ea0SThomas Gleixner /*
1196ae6ea0SThomas Gleixner  * Standard video BIOS modes
1296ae6ea0SThomas Gleixner  *
1396ae6ea0SThomas Gleixner  * We have two options for this; silent and scanned.
1496ae6ea0SThomas Gleixner  */
1596ae6ea0SThomas Gleixner 
1696ae6ea0SThomas Gleixner #include "boot.h"
1796ae6ea0SThomas Gleixner #include "video.h"
1896ae6ea0SThomas Gleixner 
198bcad30fSroel kluin static __videocard video_bios;
2096ae6ea0SThomas Gleixner 
2196ae6ea0SThomas Gleixner /* Set a conventional BIOS mode */
2296ae6ea0SThomas Gleixner static int set_bios_mode(u8 mode);
2396ae6ea0SThomas Gleixner 
bios_set_mode(struct mode_info * mi)2496ae6ea0SThomas Gleixner static int bios_set_mode(struct mode_info *mi)
2596ae6ea0SThomas Gleixner {
2696ae6ea0SThomas Gleixner 	return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
2796ae6ea0SThomas Gleixner }
2896ae6ea0SThomas Gleixner 
set_bios_mode(u8 mode)2996ae6ea0SThomas Gleixner static int set_bios_mode(u8 mode)
3096ae6ea0SThomas Gleixner {
31cf06de7bSH. Peter Anvin 	struct biosregs ireg, oreg;
3296ae6ea0SThomas Gleixner 	u8 new_mode;
3396ae6ea0SThomas Gleixner 
34cf06de7bSH. Peter Anvin 	initregs(&ireg);
35cf06de7bSH. Peter Anvin 	ireg.al = mode;		/* AH=0x00 Set Video Mode */
36cf06de7bSH. Peter Anvin 	intcall(0x10, &ireg, NULL);
3796ae6ea0SThomas Gleixner 
38cf06de7bSH. Peter Anvin 	ireg.ah = 0x0f;		/* Get Current Video Mode */
39cf06de7bSH. Peter Anvin 	intcall(0x10, &ireg, &oreg);
4096ae6ea0SThomas Gleixner 
4196ae6ea0SThomas Gleixner 	do_restore = 1;		/* Assume video contents were lost */
42cf06de7bSH. Peter Anvin 
43cf06de7bSH. Peter Anvin 	/* Not all BIOSes are clean with the top bit */
44febe04deSAkinobu Mita 	new_mode = oreg.al & 0x7f;
4596ae6ea0SThomas Gleixner 
4696ae6ea0SThomas Gleixner 	if (new_mode == mode)
4796ae6ea0SThomas Gleixner 		return 0;	/* Mode change OK */
4896ae6ea0SThomas Gleixner 
49e44b7b75SPavel Machek #ifndef _WAKEUP
5096ae6ea0SThomas Gleixner 	if (new_mode != boot_params.screen_info.orig_video_mode) {
5196ae6ea0SThomas Gleixner 		/* Mode setting failed, but we didn't end up where we
5296ae6ea0SThomas Gleixner 		   started.  That's bad.  Try to revert to the original
5396ae6ea0SThomas Gleixner 		   video mode. */
54cf06de7bSH. Peter Anvin 		ireg.ax = boot_params.screen_info.orig_video_mode;
55cf06de7bSH. Peter Anvin 		intcall(0x10, &ireg, NULL);
5696ae6ea0SThomas Gleixner 	}
57e44b7b75SPavel Machek #endif
5896ae6ea0SThomas Gleixner 	return -1;
5996ae6ea0SThomas Gleixner }
6096ae6ea0SThomas Gleixner 
bios_probe(void)6196ae6ea0SThomas Gleixner static int bios_probe(void)
6296ae6ea0SThomas Gleixner {
6396ae6ea0SThomas Gleixner 	u8 mode;
64e44b7b75SPavel Machek #ifdef _WAKEUP
65e44b7b75SPavel Machek 	u8 saved_mode = 0x03;
66e44b7b75SPavel Machek #else
6796ae6ea0SThomas Gleixner 	u8 saved_mode = boot_params.screen_info.orig_video_mode;
68e44b7b75SPavel Machek #endif
6996ae6ea0SThomas Gleixner 	u16 crtc;
7096ae6ea0SThomas Gleixner 	struct mode_info *mi;
7196ae6ea0SThomas Gleixner 	int nmodes = 0;
7296ae6ea0SThomas Gleixner 
7396ae6ea0SThomas Gleixner 	if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
7496ae6ea0SThomas Gleixner 		return 0;
7596ae6ea0SThomas Gleixner 
7696ae6ea0SThomas Gleixner 	set_fs(0);
7796ae6ea0SThomas Gleixner 	crtc = vga_crtc();
7896ae6ea0SThomas Gleixner 
7996ae6ea0SThomas Gleixner 	video_bios.modes = GET_HEAP(struct mode_info, 0);
8096ae6ea0SThomas Gleixner 
8196ae6ea0SThomas Gleixner 	for (mode = 0x14; mode <= 0x7f; mode++) {
82e6e1ace9SH. Peter Anvin 		if (!heap_free(sizeof(struct mode_info)))
8396ae6ea0SThomas Gleixner 			break;
8496ae6ea0SThomas Gleixner 
8596ae6ea0SThomas Gleixner 		if (mode_defined(VIDEO_FIRST_BIOS+mode))
8696ae6ea0SThomas Gleixner 			continue;
8796ae6ea0SThomas Gleixner 
8896ae6ea0SThomas Gleixner 		if (set_bios_mode(mode))
8996ae6ea0SThomas Gleixner 			continue;
9096ae6ea0SThomas Gleixner 
9196ae6ea0SThomas Gleixner 		/* Try to verify that it's a text mode. */
9296ae6ea0SThomas Gleixner 
9396ae6ea0SThomas Gleixner 		/* Attribute Controller: make graphics controller disabled */
9496ae6ea0SThomas Gleixner 		if (in_idx(0x3c0, 0x10) & 0x01)
9596ae6ea0SThomas Gleixner 			continue;
9696ae6ea0SThomas Gleixner 
9796ae6ea0SThomas Gleixner 		/* Graphics Controller: verify Alpha addressing enabled */
9896ae6ea0SThomas Gleixner 		if (in_idx(0x3ce, 0x06) & 0x01)
9996ae6ea0SThomas Gleixner 			continue;
10096ae6ea0SThomas Gleixner 
10196ae6ea0SThomas Gleixner 		/* CRTC cursor location low should be zero(?) */
10296ae6ea0SThomas Gleixner 		if (in_idx(crtc, 0x0f))
10396ae6ea0SThomas Gleixner 			continue;
10496ae6ea0SThomas Gleixner 
10596ae6ea0SThomas Gleixner 		mi = GET_HEAP(struct mode_info, 1);
10696ae6ea0SThomas Gleixner 		mi->mode = VIDEO_FIRST_BIOS+mode;
1071cac5004SH. Peter Anvin 		mi->depth = 0;	/* text */
10896ae6ea0SThomas Gleixner 		mi->x = rdfs16(0x44a);
10996ae6ea0SThomas Gleixner 		mi->y = rdfs8(0x484)+1;
11096ae6ea0SThomas Gleixner 		nmodes++;
11196ae6ea0SThomas Gleixner 	}
11296ae6ea0SThomas Gleixner 
11396ae6ea0SThomas Gleixner 	set_bios_mode(saved_mode);
11496ae6ea0SThomas Gleixner 
11596ae6ea0SThomas Gleixner 	return nmodes;
11696ae6ea0SThomas Gleixner }
11796ae6ea0SThomas Gleixner 
1188bcad30fSroel kluin static __videocard video_bios =
11996ae6ea0SThomas Gleixner {
1201cac5004SH. Peter Anvin 	.card_name	= "BIOS",
12196ae6ea0SThomas Gleixner 	.probe		= bios_probe,
12296ae6ea0SThomas Gleixner 	.set_mode	= bios_set_mode,
12396ae6ea0SThomas Gleixner 	.unsafe		= 1,
12496ae6ea0SThomas Gleixner 	.xmode_first	= VIDEO_FIRST_BIOS,
12596ae6ea0SThomas Gleixner 	.xmode_n	= 0x80,
12696ae6ea0SThomas Gleixner };
127