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