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