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