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