x86, setup: fix the setting of 480-line VGA modes
[pandora-kernel.git] / 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(int lines)
133 {
134         u16 crtc;               /* CRTC base address */
135         u8  csel;               /* CRTC miscellaneous output register */
136         u8  ovfw;               /* CRTC overflow register */
137         int end = lines-1;
138
139         crtc = vga_crtc();
140
141         ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40);
142
143         out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
144         out_idx(0x0b, crtc, 0x06); /* Vertical total */
145         out_idx(ovfw, crtc, 0x07); /* Vertical overflow */
146         out_idx(0xea, crtc, 0x10); /* Vertical sync start */
147         out_idx(end,  crtc, 0x12); /* Vertical display end */
148         out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
149         out_idx(0x04, crtc, 0x16); /* Vertical blank end */
150         csel = inb(0x3cc);
151         csel &= 0x0d;
152         csel |= 0xe2;
153         outb(csel, 0x3c2);
154 }
155
156 static void vga_set_80x30(void)
157 {
158         vga_set_480_scanlines(30*16);
159 }
160
161 static void vga_set_80x34(void)
162 {
163         vga_set_14font();
164         vga_set_480_scanlines(34*14);
165 }
166
167 static void vga_set_80x60(void)
168 {
169         vga_set_8font();
170         vga_set_480_scanlines(60*8);
171 }
172
173 static int vga_set_mode(struct mode_info *mode)
174 {
175         /* Set the basic mode */
176         vga_set_basic_mode();
177
178         /* Override a possibly broken BIOS */
179         force_x = mode->x;
180         force_y = mode->y;
181
182         switch (mode->mode) {
183         case VIDEO_80x25:
184                 break;
185         case VIDEO_8POINT:
186                 vga_set_8font();
187                 break;
188         case VIDEO_80x43:
189                 vga_set_80x43();
190                 break;
191         case VIDEO_80x28:
192                 vga_set_14font();
193                 break;
194         case VIDEO_80x30:
195                 vga_set_80x30();
196                 break;
197         case VIDEO_80x34:
198                 vga_set_80x34();
199                 break;
200         case VIDEO_80x60:
201                 vga_set_80x60();
202                 break;
203         }
204
205         return 0;
206 }
207
208 /*
209  * Note: this probe includes basic information required by all
210  * systems.  It should be executed first, by making sure
211  * video-vga.c is listed first in the Makefile.
212  */
213 static int vga_probe(void)
214 {
215         u16 ega_bx;
216
217         static const char *card_name[] = {
218                 "CGA/MDA/HGC", "EGA", "VGA"
219         };
220         static struct mode_info *mode_lists[] = {
221                 cga_modes,
222                 ega_modes,
223                 vga_modes,
224         };
225         static int mode_count[] = {
226                 sizeof(cga_modes)/sizeof(struct mode_info),
227                 sizeof(ega_modes)/sizeof(struct mode_info),
228                 sizeof(vga_modes)/sizeof(struct mode_info),
229         };
230         u8 vga_flag;
231
232         asm(INT10
233             : "=b" (ega_bx)
234             : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
235             : "ecx", "edx", "esi", "edi");
236
237 #ifndef _WAKEUP
238         boot_params.screen_info.orig_video_ega_bx = ega_bx;
239 #endif
240
241         /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
242         if ((u8)ega_bx != 0x10) {
243                 /* EGA/VGA */
244                 asm(INT10
245                     : "=a" (vga_flag)
246                     : "a" (0x1a00)
247                     : "ebx", "ecx", "edx", "esi", "edi");
248
249                 if (vga_flag == 0x1a) {
250                         adapter = ADAPTER_VGA;
251 #ifndef _WAKEUP
252                         boot_params.screen_info.orig_video_isVGA = 1;
253 #endif
254                 } else {
255                         adapter = ADAPTER_EGA;
256                 }
257         } else {
258                 adapter = ADAPTER_CGA;
259         }
260
261         video_vga.modes = mode_lists[adapter];
262         video_vga.card_name = card_name[adapter];
263         return mode_count[adapter];
264 }
265
266 static __videocard video_vga = {
267         .card_name      = "VGA",
268         .probe          = vga_probe,
269         .set_mode       = vga_set_mode,
270 };