Merge branch 'topic/ctxfi' into for-linus
[linux-2.6] / arch / x86 / boot / video-vga.c
1 /* -*- linux-c -*- ------------------------------------------------------- *
2  *
3  *   Copyright (C) 1991, 1992 Linus Torvalds
4  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5  *
6  *   This file is part of the Linux kernel, and is made available under
7  *   the terms of the GNU General Public License version 2.
8  *
9  * ----------------------------------------------------------------------- */
10
11 /*
12  * Common all-VGA modes
13  */
14
15 #include "boot.h"
16 #include "video.h"
17
18 static struct mode_info vga_modes[] = {
19         { VIDEO_80x25,  80, 25, 0 },
20         { VIDEO_8POINT, 80, 50, 0 },
21         { VIDEO_80x43,  80, 43, 0 },
22         { VIDEO_80x28,  80, 28, 0 },
23         { VIDEO_80x30,  80, 30, 0 },
24         { VIDEO_80x34,  80, 34, 0 },
25         { VIDEO_80x60,  80, 60, 0 },
26 };
27
28 static struct mode_info ega_modes[] = {
29         { VIDEO_80x25,  80, 25, 0 },
30         { VIDEO_8POINT, 80, 43, 0 },
31 };
32
33 static struct mode_info cga_modes[] = {
34         { VIDEO_80x25,  80, 25, 0 },
35 };
36
37 static __videocard video_vga;
38
39 /* Set basic 80x25 mode */
40 static u8 vga_set_basic_mode(void)
41 {
42         u16 ax;
43         u8 rows;
44         u8 mode;
45
46 #ifdef CONFIG_VIDEO_400_HACK
47         if (adapter >= ADAPTER_VGA) {
48                 asm volatile(INT10
49                              : : "a" (0x1202), "b" (0x0030)
50                              : "ecx", "edx", "esi", "edi");
51         }
52 #endif
53
54         ax = 0x0f00;
55         asm volatile(INT10
56                      : "+a" (ax)
57                      : : "ebx", "ecx", "edx", "esi", "edi");
58
59         mode = (u8)ax;
60
61         set_fs(0);
62         rows = rdfs8(0x484);    /* rows minus one */
63
64 #ifndef CONFIG_VIDEO_400_HACK
65         if ((ax == 0x5003 || ax == 0x5007) &&
66             (rows == 0 || rows == 24))
67                 return mode;
68 #endif
69
70         if (mode != 3 && mode != 7)
71                 mode = 3;
72
73         /* Set the mode */
74         ax = mode;
75         asm volatile(INT10
76                      : "+a" (ax)
77                      : : "ebx", "ecx", "edx", "esi", "edi");
78         do_restore = 1;
79         return mode;
80 }
81
82 static void vga_set_8font(void)
83 {
84         /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
85
86         /* Set 8x8 font */
87         asm volatile(INT10 : : "a" (0x1112), "b" (0));
88
89         /* Use alternate print screen */
90         asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
91
92         /* Turn off cursor emulation */
93         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
94
95         /* Cursor is scan lines 6-7 */
96         asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
97 }
98
99 static void vga_set_14font(void)
100 {
101         /* Set 9x14 font - 80x28 on VGA */
102
103         /* Set 9x14 font */
104         asm volatile(INT10 : : "a" (0x1111), "b" (0));
105
106         /* Turn off cursor emulation */
107         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
108
109         /* Cursor is scan lines 11-12 */
110         asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
111 }
112
113 static void vga_set_80x43(void)
114 {
115         /* Set 80x43 mode on VGA (not EGA) */
116
117         /* Set 350 scans */
118         asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
119
120         /* Reset video mode */
121         asm volatile(INT10 : : "a" (0x0003));
122
123         vga_set_8font();
124 }
125
126 /* I/O address of the VGA CRTC */
127 u16 vga_crtc(void)
128 {
129         return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
130 }
131
132 static void vga_set_480_scanlines(void)
133 {
134         u16 crtc;               /* CRTC base address */
135         u8  csel;               /* CRTC miscellaneous output register */
136
137         crtc = vga_crtc();
138
139         out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
140         out_idx(0x0b, crtc, 0x06); /* Vertical total */
141         out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
142         out_idx(0xea, crtc, 0x10); /* Vertical sync start */
143         out_idx(0xdf, crtc, 0x12); /* Vertical display end */
144         out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
145         out_idx(0x04, crtc, 0x16); /* Vertical blank end */
146         csel = inb(0x3cc);
147         csel &= 0x0d;
148         csel |= 0xe2;
149         outb(csel, 0x3c2);
150 }
151
152 static void vga_set_vertical_end(int lines)
153 {
154         u16 crtc;               /* CRTC base address */
155         u8  ovfw;               /* CRTC overflow register */
156         int end = lines-1;
157
158         crtc = vga_crtc();
159
160         ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40);
161
162         out_idx(ovfw, crtc, 0x07); /* Vertical overflow */
163         out_idx(end,  crtc, 0x12); /* Vertical display end */
164 }
165
166 static void vga_set_80x30(void)
167 {
168         vga_set_480_scanlines();
169         vga_set_vertical_end(30*16);
170 }
171
172 static void vga_set_80x34(void)
173 {
174         vga_set_480_scanlines();
175         vga_set_14font();
176         vga_set_vertical_end(34*14);
177 }
178
179 static void vga_set_80x60(void)
180 {
181         vga_set_480_scanlines();
182         vga_set_8font();
183         vga_set_vertical_end(60*8);
184 }
185
186 static int vga_set_mode(struct mode_info *mode)
187 {
188         /* Set the basic mode */
189         vga_set_basic_mode();
190
191         /* Override a possibly broken BIOS */
192         force_x = mode->x;
193         force_y = mode->y;
194
195         switch (mode->mode) {
196         case VIDEO_80x25:
197                 break;
198         case VIDEO_8POINT:
199                 vga_set_8font();
200                 break;
201         case VIDEO_80x43:
202                 vga_set_80x43();
203                 break;
204         case VIDEO_80x28:
205                 vga_set_14font();
206                 break;
207         case VIDEO_80x30:
208                 vga_set_80x30();
209                 break;
210         case VIDEO_80x34:
211                 vga_set_80x34();
212                 break;
213         case VIDEO_80x60:
214                 vga_set_80x60();
215                 break;
216         }
217
218         return 0;
219 }
220
221 /*
222  * Note: this probe includes basic information required by all
223  * systems.  It should be executed first, by making sure
224  * video-vga.c is listed first in the Makefile.
225  */
226 static int vga_probe(void)
227 {
228         u16 ega_bx;
229
230         static const char *card_name[] = {
231                 "CGA/MDA/HGC", "EGA", "VGA"
232         };
233         static struct mode_info *mode_lists[] = {
234                 cga_modes,
235                 ega_modes,
236                 vga_modes,
237         };
238         static int mode_count[] = {
239                 sizeof(cga_modes)/sizeof(struct mode_info),
240                 sizeof(ega_modes)/sizeof(struct mode_info),
241                 sizeof(vga_modes)/sizeof(struct mode_info),
242         };
243         u8 vga_flag;
244
245         asm(INT10
246             : "=b" (ega_bx)
247             : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
248             : "ecx", "edx", "esi", "edi");
249
250 #ifndef _WAKEUP
251         boot_params.screen_info.orig_video_ega_bx = ega_bx;
252 #endif
253
254         /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
255         if ((u8)ega_bx != 0x10) {
256                 /* EGA/VGA */
257                 asm(INT10
258                     : "=a" (vga_flag)
259                     : "a" (0x1a00)
260                     : "ebx", "ecx", "edx", "esi", "edi");
261
262                 if (vga_flag == 0x1a) {
263                         adapter = ADAPTER_VGA;
264 #ifndef _WAKEUP
265                         boot_params.screen_info.orig_video_isVGA = 1;
266 #endif
267                 } else {
268                         adapter = ADAPTER_EGA;
269                 }
270         } else {
271                 adapter = ADAPTER_CGA;
272         }
273
274         video_vga.modes = mode_lists[adapter];
275         video_vga.card_name = card_name[adapter];
276         return mode_count[adapter];
277 }
278
279 static __videocard video_vga = {
280         .card_name      = "VGA",
281         .probe          = vga_probe,
282         .set_mode       = vga_set_mode,
283 };