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