1*97873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e44b7b75SPavel Machek /* -*- linux-c -*- ------------------------------------------------------- * 3e44b7b75SPavel Machek * 4e44b7b75SPavel Machek * Copyright (C) 1991, 1992 Linus Torvalds 5e44b7b75SPavel Machek * Copyright 2007-2008 rPath, Inc. - All Rights Reserved 6e44b7b75SPavel Machek * 7e44b7b75SPavel Machek * ----------------------------------------------------------------------- */ 8e44b7b75SPavel Machek 9e44b7b75SPavel Machek /* 10e44b7b75SPavel Machek * arch/i386/boot/video-mode.c 11e44b7b75SPavel Machek * 12e44b7b75SPavel Machek * Set the video mode. This is separated out into a different 13e44b7b75SPavel Machek * file in order to be shared with the ACPI wakeup code. 14e44b7b75SPavel Machek */ 15e44b7b75SPavel Machek 16e44b7b75SPavel Machek #include "boot.h" 17e44b7b75SPavel Machek #include "video.h" 18e44b7b75SPavel Machek #include "vesa.h" 19e44b7b75SPavel Machek 2070f15287SKirill A. Shutemov #include <uapi/asm/boot.h> 2170f15287SKirill A. Shutemov 22e44b7b75SPavel Machek /* 23e44b7b75SPavel Machek * Common variables 24e44b7b75SPavel Machek */ 25e44b7b75SPavel Machek int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ 26e44b7b75SPavel Machek int force_x, force_y; /* Don't query the BIOS for cols/rows */ 27e44b7b75SPavel Machek int do_restore; /* Screen contents changed during mode flip */ 28e44b7b75SPavel Machek int graphic_mode; /* Graphic mode with linear frame buffer */ 29e44b7b75SPavel Machek 30e44b7b75SPavel Machek /* Probe the video drivers and have them generate their mode lists. */ 31e44b7b75SPavel Machek void probe_cards(int unsafe) 32e44b7b75SPavel Machek { 33e44b7b75SPavel Machek struct card_info *card; 34e44b7b75SPavel Machek static u8 probed[2]; 35e44b7b75SPavel Machek 36e44b7b75SPavel Machek if (probed[unsafe]) 37e44b7b75SPavel Machek return; 38e44b7b75SPavel Machek 39e44b7b75SPavel Machek probed[unsafe] = 1; 40e44b7b75SPavel Machek 41e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 42e44b7b75SPavel Machek if (card->unsafe == unsafe) { 43e44b7b75SPavel Machek if (card->probe) 44e44b7b75SPavel Machek card->nmodes = card->probe(); 45e44b7b75SPavel Machek else 46e44b7b75SPavel Machek card->nmodes = 0; 47e44b7b75SPavel Machek } 48e44b7b75SPavel Machek } 49e44b7b75SPavel Machek } 50e44b7b75SPavel Machek 51e44b7b75SPavel Machek /* Test if a mode is defined */ 52e44b7b75SPavel Machek int mode_defined(u16 mode) 53e44b7b75SPavel Machek { 54e44b7b75SPavel Machek struct card_info *card; 55e44b7b75SPavel Machek struct mode_info *mi; 56e44b7b75SPavel Machek int i; 57e44b7b75SPavel Machek 58e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 59e44b7b75SPavel Machek mi = card->modes; 60e44b7b75SPavel Machek for (i = 0; i < card->nmodes; i++, mi++) { 61e44b7b75SPavel Machek if (mi->mode == mode) 62e44b7b75SPavel Machek return 1; 63e44b7b75SPavel Machek } 64e44b7b75SPavel Machek } 65e44b7b75SPavel Machek 66e44b7b75SPavel Machek return 0; 67e44b7b75SPavel Machek } 68e44b7b75SPavel Machek 69e44b7b75SPavel Machek /* Set mode (without recalc) */ 70e44b7b75SPavel Machek static int raw_set_mode(u16 mode, u16 *real_mode) 71e44b7b75SPavel Machek { 72e44b7b75SPavel Machek int nmode, i; 73e44b7b75SPavel Machek struct card_info *card; 74e44b7b75SPavel Machek struct mode_info *mi; 75e44b7b75SPavel Machek 76e44b7b75SPavel Machek /* Drop the recalc bit if set */ 77e44b7b75SPavel Machek mode &= ~VIDEO_RECALC; 78e44b7b75SPavel Machek 79e44b7b75SPavel Machek /* Scan for mode based on fixed ID, position, or resolution */ 80e44b7b75SPavel Machek nmode = 0; 81e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 82e44b7b75SPavel Machek mi = card->modes; 83e44b7b75SPavel Machek for (i = 0; i < card->nmodes; i++, mi++) { 84e44b7b75SPavel Machek int visible = mi->x || mi->y; 85e44b7b75SPavel Machek 86e44b7b75SPavel Machek if ((mode == nmode && visible) || 87e44b7b75SPavel Machek mode == mi->mode || 88e44b7b75SPavel Machek mode == (mi->y << 8)+mi->x) { 89e44b7b75SPavel Machek *real_mode = mi->mode; 90e44b7b75SPavel Machek return card->set_mode(mi); 91e44b7b75SPavel Machek } 92e44b7b75SPavel Machek 93e44b7b75SPavel Machek if (visible) 94e44b7b75SPavel Machek nmode++; 95e44b7b75SPavel Machek } 96e44b7b75SPavel Machek } 97e44b7b75SPavel Machek 98e44b7b75SPavel Machek /* Nothing found? Is it an "exceptional" (unprobed) mode? */ 99e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 100e44b7b75SPavel Machek if (mode >= card->xmode_first && 101e44b7b75SPavel Machek mode < card->xmode_first+card->xmode_n) { 102e44b7b75SPavel Machek struct mode_info mix; 103e44b7b75SPavel Machek *real_mode = mix.mode = mode; 104e44b7b75SPavel Machek mix.x = mix.y = 0; 105e44b7b75SPavel Machek return card->set_mode(&mix); 106e44b7b75SPavel Machek } 107e44b7b75SPavel Machek } 108e44b7b75SPavel Machek 109e44b7b75SPavel Machek /* Otherwise, failure... */ 110e44b7b75SPavel Machek return -1; 111e44b7b75SPavel Machek } 112e44b7b75SPavel Machek 113e44b7b75SPavel Machek /* 114e44b7b75SPavel Machek * Recalculate the vertical video cutoff (hack!) 115e44b7b75SPavel Machek */ 116e44b7b75SPavel Machek static void vga_recalc_vertical(void) 117e44b7b75SPavel Machek { 118e44b7b75SPavel Machek unsigned int font_size, rows; 119e44b7b75SPavel Machek u16 crtc; 120e44b7b75SPavel Machek u8 pt, ov; 121e44b7b75SPavel Machek 122e44b7b75SPavel Machek set_fs(0); 123e44b7b75SPavel Machek font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ 124e44b7b75SPavel Machek rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ 125e44b7b75SPavel Machek 126e44b7b75SPavel Machek rows *= font_size; /* Visible scan lines */ 127e44b7b75SPavel Machek rows--; /* ... minus one */ 128e44b7b75SPavel Machek 129e44b7b75SPavel Machek crtc = vga_crtc(); 130e44b7b75SPavel Machek 131e44b7b75SPavel Machek pt = in_idx(crtc, 0x11); 132e44b7b75SPavel Machek pt &= ~0x80; /* Unlock CR0-7 */ 133e44b7b75SPavel Machek out_idx(pt, crtc, 0x11); 134e44b7b75SPavel Machek 135e44b7b75SPavel Machek out_idx((u8)rows, crtc, 0x12); /* Lower height register */ 136e44b7b75SPavel Machek 137e44b7b75SPavel Machek ov = in_idx(crtc, 0x07); /* Overflow register */ 138e44b7b75SPavel Machek ov &= 0xbd; 139e44b7b75SPavel Machek ov |= (rows >> (8-1)) & 0x02; 140e44b7b75SPavel Machek ov |= (rows >> (9-6)) & 0x40; 141e44b7b75SPavel Machek out_idx(ov, crtc, 0x07); 142e44b7b75SPavel Machek } 143e44b7b75SPavel Machek 144e44b7b75SPavel Machek /* Set mode (with recalc if specified) */ 145e44b7b75SPavel Machek int set_mode(u16 mode) 146e44b7b75SPavel Machek { 147e44b7b75SPavel Machek int rv; 148e44b7b75SPavel Machek u16 real_mode; 149e44b7b75SPavel Machek 150e44b7b75SPavel Machek /* Very special mode numbers... */ 151e44b7b75SPavel Machek if (mode == VIDEO_CURRENT_MODE) 152e44b7b75SPavel Machek return 0; /* Nothing to do... */ 153e44b7b75SPavel Machek else if (mode == NORMAL_VGA) 154e44b7b75SPavel Machek mode = VIDEO_80x25; 155e44b7b75SPavel Machek else if (mode == EXTENDED_VGA) 156e44b7b75SPavel Machek mode = VIDEO_8POINT; 157e44b7b75SPavel Machek 158e44b7b75SPavel Machek rv = raw_set_mode(mode, &real_mode); 159e44b7b75SPavel Machek if (rv) 160e44b7b75SPavel Machek return rv; 161e44b7b75SPavel Machek 162e44b7b75SPavel Machek if (mode & VIDEO_RECALC) 163e44b7b75SPavel Machek vga_recalc_vertical(); 164e44b7b75SPavel Machek 165e44b7b75SPavel Machek /* Save the canonical mode number for the kernel, not 166e44b7b75SPavel Machek an alias, size specification or menu position */ 167e44b7b75SPavel Machek #ifndef _WAKEUP 168e44b7b75SPavel Machek boot_params.hdr.vid_mode = real_mode; 169e44b7b75SPavel Machek #endif 170e44b7b75SPavel Machek return 0; 171e44b7b75SPavel Machek } 172