video-vesa.c (6756B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 * Copyright 2007 rPath, Inc. - All Rights Reserved 6 * Copyright 2009 Intel Corporation; author H. Peter Anvin 7 * 8 * ----------------------------------------------------------------------- */ 9 10/* 11 * VESA text modes 12 */ 13 14#include "boot.h" 15#include "video.h" 16#include "vesa.h" 17#include "string.h" 18 19/* VESA information */ 20static struct vesa_general_info vginfo; 21static struct vesa_mode_info vminfo; 22 23static __videocard video_vesa; 24 25#ifndef _WAKEUP 26static void vesa_store_mode_params_graphics(void); 27#else /* _WAKEUP */ 28static inline void vesa_store_mode_params_graphics(void) {} 29#endif /* _WAKEUP */ 30 31static int vesa_probe(void) 32{ 33 struct biosregs ireg, oreg; 34 u16 mode; 35 addr_t mode_ptr; 36 struct mode_info *mi; 37 int nmodes = 0; 38 39 video_vesa.modes = GET_HEAP(struct mode_info, 0); 40 41 initregs(&ireg); 42 ireg.ax = 0x4f00; 43 ireg.di = (size_t)&vginfo; 44 intcall(0x10, &ireg, &oreg); 45 46 if (oreg.ax != 0x004f || 47 vginfo.signature != VESA_MAGIC || 48 vginfo.version < 0x0102) 49 return 0; /* Not present */ 50 51 set_fs(vginfo.video_mode_ptr.seg); 52 mode_ptr = vginfo.video_mode_ptr.off; 53 54 while ((mode = rdfs16(mode_ptr)) != 0xffff) { 55 mode_ptr += 2; 56 57 if (!heap_free(sizeof(struct mode_info))) 58 break; /* Heap full, can't save mode info */ 59 60 if (mode & ~0x1ff) 61 continue; 62 63 memset(&vminfo, 0, sizeof(vminfo)); /* Just in case... */ 64 65 ireg.ax = 0x4f01; 66 ireg.cx = mode; 67 ireg.di = (size_t)&vminfo; 68 intcall(0x10, &ireg, &oreg); 69 70 if (oreg.ax != 0x004f) 71 continue; 72 73 if ((vminfo.mode_attr & 0x15) == 0x05) { 74 /* Text Mode, TTY BIOS supported, 75 supported by hardware */ 76 mi = GET_HEAP(struct mode_info, 1); 77 mi->mode = mode + VIDEO_FIRST_VESA; 78 mi->depth = 0; /* text */ 79 mi->x = vminfo.h_res; 80 mi->y = vminfo.v_res; 81 nmodes++; 82 } else if ((vminfo.mode_attr & 0x99) == 0x99 && 83 (vminfo.memory_layout == 4 || 84 vminfo.memory_layout == 6) && 85 vminfo.memory_planes == 1) { 86#ifdef CONFIG_BOOT_VESA_SUPPORT 87 /* Graphics mode, color, linear frame buffer 88 supported. Only register the mode if 89 if framebuffer is configured, however, 90 otherwise the user will be left without a screen. */ 91 mi = GET_HEAP(struct mode_info, 1); 92 mi->mode = mode + VIDEO_FIRST_VESA; 93 mi->depth = vminfo.bpp; 94 mi->x = vminfo.h_res; 95 mi->y = vminfo.v_res; 96 nmodes++; 97#endif 98 } 99 } 100 101 return nmodes; 102} 103 104static int vesa_set_mode(struct mode_info *mode) 105{ 106 struct biosregs ireg, oreg; 107 int is_graphic; 108 u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; 109 110 memset(&vminfo, 0, sizeof(vminfo)); /* Just in case... */ 111 112 initregs(&ireg); 113 ireg.ax = 0x4f01; 114 ireg.cx = vesa_mode; 115 ireg.di = (size_t)&vminfo; 116 intcall(0x10, &ireg, &oreg); 117 118 if (oreg.ax != 0x004f) 119 return -1; 120 121 if ((vminfo.mode_attr & 0x15) == 0x05) { 122 /* It's a supported text mode */ 123 is_graphic = 0; 124#ifdef CONFIG_BOOT_VESA_SUPPORT 125 } else if ((vminfo.mode_attr & 0x99) == 0x99) { 126 /* It's a graphics mode with linear frame buffer */ 127 is_graphic = 1; 128 vesa_mode |= 0x4000; /* Request linear frame buffer */ 129#endif 130 } else { 131 return -1; /* Invalid mode */ 132 } 133 134 135 initregs(&ireg); 136 ireg.ax = 0x4f02; 137 ireg.bx = vesa_mode; 138 intcall(0x10, &ireg, &oreg); 139 140 if (oreg.ax != 0x004f) 141 return -1; 142 143 graphic_mode = is_graphic; 144 if (!is_graphic) { 145 /* Text mode */ 146 force_x = mode->x; 147 force_y = mode->y; 148 do_restore = 1; 149 } else { 150 /* Graphics mode */ 151 vesa_store_mode_params_graphics(); 152 } 153 154 return 0; 155} 156 157 158#ifndef _WAKEUP 159 160/* Switch DAC to 8-bit mode */ 161static void vesa_dac_set_8bits(void) 162{ 163 struct biosregs ireg, oreg; 164 u8 dac_size = 6; 165 166 /* If possible, switch the DAC to 8-bit mode */ 167 if (vginfo.capabilities & 1) { 168 initregs(&ireg); 169 ireg.ax = 0x4f08; 170 ireg.bh = 0x08; 171 intcall(0x10, &ireg, &oreg); 172 if (oreg.ax == 0x004f) 173 dac_size = oreg.bh; 174 } 175 176 /* Set the color sizes to the DAC size, and offsets to 0 */ 177 boot_params.screen_info.red_size = dac_size; 178 boot_params.screen_info.green_size = dac_size; 179 boot_params.screen_info.blue_size = dac_size; 180 boot_params.screen_info.rsvd_size = dac_size; 181 182 boot_params.screen_info.red_pos = 0; 183 boot_params.screen_info.green_pos = 0; 184 boot_params.screen_info.blue_pos = 0; 185 boot_params.screen_info.rsvd_pos = 0; 186} 187 188/* Save the VESA protected mode info */ 189static void vesa_store_pm_info(void) 190{ 191 struct biosregs ireg, oreg; 192 193 initregs(&ireg); 194 ireg.ax = 0x4f0a; 195 intcall(0x10, &ireg, &oreg); 196 197 if (oreg.ax != 0x004f) 198 return; 199 200 boot_params.screen_info.vesapm_seg = oreg.es; 201 boot_params.screen_info.vesapm_off = oreg.di; 202} 203 204/* 205 * Save video mode parameters for graphics mode 206 */ 207static void vesa_store_mode_params_graphics(void) 208{ 209 /* Tell the kernel we're in VESA graphics mode */ 210 boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB; 211 212 /* Mode parameters */ 213 boot_params.screen_info.vesa_attributes = vminfo.mode_attr; 214 boot_params.screen_info.lfb_linelength = vminfo.logical_scan; 215 boot_params.screen_info.lfb_width = vminfo.h_res; 216 boot_params.screen_info.lfb_height = vminfo.v_res; 217 boot_params.screen_info.lfb_depth = vminfo.bpp; 218 boot_params.screen_info.pages = vminfo.image_planes; 219 boot_params.screen_info.lfb_base = vminfo.lfb_ptr; 220 memcpy(&boot_params.screen_info.red_size, 221 &vminfo.rmask, 8); 222 223 /* General parameters */ 224 boot_params.screen_info.lfb_size = vginfo.total_memory; 225 226 if (vminfo.bpp <= 8) 227 vesa_dac_set_8bits(); 228 229 vesa_store_pm_info(); 230} 231 232/* 233 * Save EDID information for the kernel; this is invoked, separately, 234 * after mode-setting. 235 */ 236void vesa_store_edid(void) 237{ 238#ifdef CONFIG_FIRMWARE_EDID 239 struct biosregs ireg, oreg; 240 241 /* Apparently used as a nonsense token... */ 242 memset(&boot_params.edid_info, 0x13, sizeof(boot_params.edid_info)); 243 244 if (vginfo.version < 0x0200) 245 return; /* EDID requires VBE 2.0+ */ 246 247 initregs(&ireg); 248 ireg.ax = 0x4f15; /* VBE DDC */ 249 /* ireg.bx = 0x0000; */ /* Report DDC capabilities */ 250 /* ireg.cx = 0; */ /* Controller 0 */ 251 ireg.es = 0; /* ES:DI must be 0 by spec */ 252 intcall(0x10, &ireg, &oreg); 253 254 if (oreg.ax != 0x004f) 255 return; /* No EDID */ 256 257 /* BH = time in seconds to transfer EDD information */ 258 /* BL = DDC level supported */ 259 260 ireg.ax = 0x4f15; /* VBE DDC */ 261 ireg.bx = 0x0001; /* Read EDID */ 262 /* ireg.cx = 0; */ /* Controller 0 */ 263 /* ireg.dx = 0; */ /* EDID block number */ 264 ireg.es = ds(); 265 ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */ 266 intcall(0x10, &ireg, &oreg); 267#endif /* CONFIG_FIRMWARE_EDID */ 268} 269 270#endif /* not _WAKEUP */ 271 272static __videocard video_vesa = 273{ 274 .card_name = "VESA", 275 .probe = vesa_probe, 276 .set_mode = vesa_set_mode, 277 .xmode_first = VIDEO_FIRST_VESA, 278 .xmode_n = 0x200, 279};