vreset.c revision 1.7 1 /* $NetBSD: vreset.c,v 1.7 2008/04/28 20:23:33 martin Exp $ */
2 /*-
3 * Copyright (c) 2006 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Tim Rightnour
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef VGA_RESET
32 #include <lib/libsa/stand.h>
33 #include "boot.h"
34 #include "iso_font.h"
35
36 #define VGA_SR_PORT 0x3c4
37 #define VGA_CR_PORT 0x3d4
38 #define VGA_CR_DATA 0x3d5
39 #define VGA_GR_PORT 0x3ce
40 #define VGA_GR_DATA 0x3cf
41 #define SRREGS 4
42 #define CRREGS 24
43 #define GRREGS 9
44 #define LINES 25
45 #define COLS 80
46 #define PCI_VENDOR_S3 0x5333
47 #define PCI_VENDOR_CIRRUS 0x1013
48 #define PCI_VENDOR_DIAMOND 0x100E
49 #define PCI_VENDOR_MATROX 0x102B
50 #define PCI_VENDOR_PARADISE 0x101C
51
52 static void write_attr(u_int8_t, u_int8_t, u_int8_t);
53 static void set_text_regs(void);
54 static void set_text_clut(int);
55 static void load_font(u_int8_t *);
56 static void unlock_S3(void);
57 static void clear_video_memory(void);
58
59 extern char *videomem;
60
61 typedef struct vga_reg {
62 u_int8_t idx;
63 u_int8_t val;
64 } vga_reg_t;
65
66 static vga_reg_t SR_regs[SRREGS] = {
67 /* idx val */
68 { 0x1, 0x0 }, /* 01: clocking mode */
69 { 0x2, 0x3 }, /* 02: map mask */
70 { 0x3, 0x0 }, /* 03: character map select */
71 { 0x4, 0x2 } /* 04: memory mode */
72 };
73
74 static vga_reg_t CR_regs[CRREGS] = {
75 /* idx val */
76 { 0x0, 0x61 }, /* 00: horizontal total */
77 { 0x1, 0x4f }, /* 01: horizontal display-enable end */
78 { 0x2, 0x50 }, /* 02: start horizontal blanking */
79 { 0x3, 0x82 }, /* 03: display skew control / end horizontal blanking */ { 0x4, 0x55 }, /* 04: start horizontal retrace pulse */
80 { 0x5, 0x81 }, /* 05: horizontal retrace delay / end horiz. retrace */
81 { 0x6, 0xf0 }, /* 06: vertical total */
82 { 0x7, 0x1f }, /* 07: overflow register */
83 { 0x8, 0x00 }, /* 08: preset row scan */
84 { 0x9, 0x4f }, /* 09: overflow / maximum scan line */
85 { 0xa, 0x0d }, /* 0A: cursor off / cursor start */
86 { 0xb, 0x0e }, /* 0B: cursor skew / cursor end */
87 { 0xc, 0x00 }, /* 0C: start regenerative buffer address high */
88 { 0xd, 0x00 }, /* 0D: start regenerative buffer address low */
89 { 0xe, 0x00 }, /* 0E: cursor location high */
90 { 0xf, 0x00 }, /* 0F: cursor location low */
91 { 0x10, 0x9a }, /* 10: vertical retrace start */
92 { 0x11, 0x8c }, /* 11: vertical interrupt / vertical retrace end */
93 { 0x12, 0x8f }, /* 12: vertical display enable end */
94 { 0x13, 0x28 }, /* 13: logical line width */
95 { 0x14, 0x1f }, /* 14: underline location */
96 { 0x15, 0x97 }, /* 15: start vertical blanking */
97 { 0x16, 0x00 }, /* 16: end vertical blanking */
98 { 0x17, 0xa3 }, /* 17: CRT mode control */
99 };
100
101 static vga_reg_t GR_regs[GRREGS] = {
102 /* idx val */
103 { 0x0, 0x00 }, /* 00: set/reset map */
104 { 0x1, 0x00 }, /* 01: enable set/reset */
105 { 0x2, 0x00 }, /* 02: color compare */
106 { 0x3, 0x00 }, /* 03: data rotate */
107 { 0x4, 0x00 }, /* 04: read map select */
108 { 0x5, 0x10 }, /* 05: graphics mode */
109 { 0x6, 0x0e }, /* 06: miscellaneous */
110 { 0x7, 0x00 }, /* 07: color don't care */
111 { 0x8, 0xff }, /* 08: bit mask */
112 };
113
114 /* video DAC palette registers */
115 /* XXX only set up 16 colors used by internal palette in ATC regsters */
116 static const u_int8_t vga_dacpal[] = {
117 /* R G B */
118 0x00, 0x00, 0x00, /* BLACK */
119 0x00, 0x00, 0x2a, /* BLUE */
120 0x00, 0x2a, 0x00, /* GREEN */
121 0x00, 0x2a, 0x2a, /* CYAN */
122 0x2a, 0x00, 0x00, /* RED */
123 0x2a, 0x00, 0x2a, /* MAGENTA */
124 0x2a, 0x15, 0x00, /* BROWN */
125 0x2a, 0x2a, 0x2a, /* LIGHTGREY */
126 0x15, 0x15, 0x15, /* DARKGREY */
127 0x15, 0x15, 0x3f, /* LIGHTBLUE */
128 0x15, 0x3f, 0x15, /* LIGHTGREEN */
129 0x15, 0x3f, 0x3f, /* LIGHTCYAN */
130 0x3f, 0x15, 0x15, /* LIGHTRED */
131 0x3f, 0x15, 0x3f, /* LIGHTMAGENTA */
132 0x3f, 0x3f, 0x15, /* YELLOW */
133 0x3f, 0x3f, 0x3f /* WHITE */
134 };
135
136 static const u_int8_t vga_atc[] = {
137 0x00, /* 00: internal palette 0 */
138 0x01, /* 01: internal palette 1 */
139 0x02, /* 02: internal palette 2 */
140 0x03, /* 03: internal palette 3 */
141 0x04, /* 04: internal palette 4 */
142 0x05, /* 05: internal palette 5 */
143 0x14, /* 06: internal palette 6 */
144 0x07, /* 07: internal palette 7 */
145 0x38, /* 08: internal palette 8 */
146 0x39, /* 09: internal palette 9 */
147 0x3a, /* 0A: internal palette 10 */
148 0x3b, /* 0B: internal palette 11 */
149 0x3c, /* 0C: internal palette 12 */
150 0x3d, /* 0D: internal palette 13 */
151 0x3e, /* 0E: internal palette 14 */
152 0x3f, /* 0F: internal palette 15 */
153 0x0c, /* 10: attribute mode control */
154 0x00, /* 11: overscan color */
155 0x0f, /* 12: color plane enable */
156 0x08, /* 13: horizontal PEL panning */
157 0x00 /* 14: color select */
158 };
159
160 void
161 vga_reset(u_char *ISA_mem)
162 {
163 int slot, cardfound;
164
165 /* check if we are in text mode, if so, punt */
166 outb(VGA_GR_PORT, 0x06);
167 if ((inb(VGA_GR_DATA) & 0x01) == 0)
168 return;
169
170 /* guess not, we lose. */
171 slot = -1;
172 while ((slot = scan_PCI(slot)) > -1) {
173 cardfound = 0;
174 switch (PCI_vendor(slot)) {
175 case PCI_VENDOR_CIRRUS:
176 unlockVideo(slot);
177 outw(VGA_SR_PORT, 0x0612); /* unlock ext regs */
178 outw(VGA_SR_PORT, 0x0700); /* reset ext sequence mode */
179 cardfound++;
180 break;
181 case PCI_VENDOR_PARADISE:
182 unlockVideo(slot);
183 outw(VGA_GR_PORT, 0x0f05); /* unlock registers */
184 outw(VGA_SR_PORT, 0x0648);
185 outw(VGA_CR_PORT, 0x2985);
186 outw(VGA_CR_PORT, 0x34a6);
187 outb(VGA_GR_PORT, 0x0b); /* disable linear addressing */
188 outb(VGA_GR_DATA, inb(VGA_GR_DATA) & ~0x30);
189 outw(VGA_SR_PORT, 0x1400);
190 outb(VGA_GR_PORT, 0x0e); /* disable 256 color mode */
191 outb(VGA_GR_DATA, inb(VGA_GR_DATA) & ~0x01);
192 outb(0xd00, 0xff); /* enable auto-centering */
193 if (!(inb(0xd01) & 0x03)) {
194 outb(VGA_CR_PORT, 0x33);
195 outb(VGA_CR_DATA, inb(VGA_CR_DATA) & ~0x90);
196 outb(VGA_CR_PORT, 0x32);
197 outb(VGA_CR_DATA, inb(VGA_CR_DATA) | 0x04);
198 outw(VGA_CR_PORT, 0x0250);
199 outw(VGA_CR_PORT, 0x07ba);
200 outw(VGA_CR_PORT, 0x0900);
201 outw(VGA_CR_PORT, 0x15e7);
202 outw(VGA_CR_PORT, 0x2a95);
203 }
204 outw(VGA_CR_PORT, 0x34a0);
205 cardfound++;
206 break;
207 case PCI_VENDOR_S3:
208 unlockVideo(slot);
209 unlock_S3();
210 cardfound++;
211 break;
212 default:
213 break;
214 }
215 if (cardfound) {
216 outw(VGA_SR_PORT, 0x0120); /* disable video */
217 set_text_regs();
218 set_text_clut(0);
219 load_font(ISA_mem);
220 set_text_regs();
221 outw(VGA_SR_PORT, 0x0100); /* re-enable video */
222 clear_video_memory();
223
224 if (PCI_vendor(slot) == PCI_VENDOR_S3)
225 outb(0x3c2, 0x63); /* ??? */
226 delay(1000);
227 }
228 }
229 return;
230 }
231
232 /* write something to a VGA attribute register */
233 static void
234 write_attr(u_int8_t index, u_int8_t data, u_int8_t videoOn)
235 {
236 u_int8_t v;
237
238 v = inb(0x3da); /* reset attr addr toggle */
239 if (videoOn)
240 outb(0x3c0, (index & 0x1F) | 0x20);
241 else
242 outb(0x3c0, (index & 0x1F));
243 outb(0x3c0, data);
244 }
245
246 static void
247 set_text_regs(void)
248 {
249 int i;
250
251 for (i = 0; i < SRREGS; i++) {
252 outb(VGA_SR_PORT, SR_regs[i].idx);
253 outb(VGA_SR_PORT + 1, SR_regs[i].val);
254 }
255 for (i = 0; i < CRREGS; i++) {
256 outb(VGA_CR_PORT, CR_regs[i].idx);
257 outb(VGA_CR_PORT + 1, CR_regs[i].val);
258 }
259 for (i = 0; i < GRREGS; i++) {
260 outb(VGA_GR_PORT, GR_regs[i].idx);
261 outb(VGA_GR_PORT + 1, GR_regs[i].val);
262 }
263
264 outb(0x3c2, 0x67); /* MISC */
265 outb(0x3c6, 0xff); /* MASK */
266
267 for (i = 0; i < 0x14; i++)
268 write_attr(i, vga_atc[i], 0);
269 write_attr(0x14, 0x00, 1); /* color select; video on */
270 }
271
272 static void
273 set_text_clut(int shift)
274 {
275 int i;
276
277 outb(0x3C6, 0xFF);
278 inb(0x3C7);
279 outb(0x3C8, 0);
280 inb(0x3C7);
281
282 for (i = 0; i < (16 * 3); ) {
283 outb(0x3c9, vga_dacpal[i++] << shift);
284 outb(0x3c9, vga_dacpal[i++] << shift);
285 outb(0x3c9, vga_dacpal[i++] << shift);
286 }
287 }
288
289 static void
290 load_font(u_int8_t *ISA_mem)
291 {
292 int i, j;
293 u_int8_t *font_page = (u_int8_t *)&ISA_mem[0xA0000];
294
295 outb(0x3C2, 0x67);
296 inb(0x3DA); /* Reset Attr toggle */
297
298 outb(0x3C0, 0x30);
299 outb(0x3C0, 0x01); /* graphics mode */
300 outw(0x3C4, 0x0001); /* reset sequencer */
301 outw(0x3C4, 0x0204); /* write to plane 2 */
302 outw(0x3C4, 0x0406); /* enable plane graphics */
303 outw(0x3C4, 0x0003); /* reset sequencer */
304 outw(0x3CE, 0x0402); /* read plane 2 */
305 outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
306 outw(0x3CE, 0x0605); /* set graphics mode */
307
308 for (i = 0; i < sizeof(font); i += 16) {
309 for (j = 0; j < 16; j++) {
310 __asm__ volatile("eieio");
311 font_page[(2*i)+j] = font[i+j];
312 }
313 }
314 }
315
316 static void
317 unlock_S3(void)
318 {
319 int s3_devid;
320
321 outw(VGA_CR_PORT, 0x3848);
322 outw(VGA_CR_PORT, 0x39a5);
323 outb(VGA_CR_PORT, 0x2d);
324 s3_devid = inb(VGA_CR_DATA) << 8;
325 outb(VGA_CR_PORT, 0x2e);
326 s3_devid |= inb(VGA_CR_DATA);
327
328 if (s3_devid != 0x8812) {
329 /* from the S3 manual */
330 outb(0x46E8, 0x10); /* Put into setup mode */
331 outb(0x3C3, 0x10);
332 outb(0x102, 0x01); /* Enable registers */
333 outb(0x46E8, 0x08); /* Enable video */
334 outb(0x3C3, 0x08);
335 outb(0x4AE8, 0x00);
336 outb(VGA_CR_PORT, 0x38); /* Unlock all registers */
337 outb(VGA_CR_DATA, 0x48);
338 outb(VGA_CR_PORT, 0x39);
339 outb(VGA_CR_DATA, 0xA5);
340 outb(VGA_CR_PORT, 0x40);
341 outb(VGA_CR_DATA, inb(0x3D5)|0x01);
342 outb(VGA_CR_PORT, 0x33);
343 outb(VGA_CR_DATA, inb(0x3D5)&~0x52);
344 outb(VGA_CR_PORT, 0x35);
345 outb(VGA_CR_DATA, inb(0x3D5)&~0x30);
346 outb(VGA_CR_PORT, 0x3A);
347 outb(VGA_CR_DATA, 0x00);
348 outb(VGA_CR_PORT, 0x53);
349 outb(VGA_CR_DATA, 0x00);
350 outb(VGA_CR_PORT, 0x31);
351 outb(VGA_CR_DATA, inb(0x3D5)&~0x4B);
352 outb(VGA_CR_PORT, 0x58);
353
354 outb(VGA_CR_DATA, 0);
355
356 outb(VGA_CR_PORT, 0x54);
357 outb(VGA_CR_DATA, 0x38);
358 outb(VGA_CR_PORT, 0x60);
359 outb(VGA_CR_DATA, 0x07);
360 outb(VGA_CR_PORT, 0x61);
361 outb(VGA_CR_DATA, 0x80);
362 outb(VGA_CR_PORT, 0x62);
363 outb(VGA_CR_DATA, 0xA1);
364 outb(VGA_CR_PORT, 0x69); /* High order bits for cursor address */
365 outb(VGA_CR_DATA, 0);
366
367 outb(VGA_CR_PORT, 0x32);
368 outb(VGA_CR_DATA, inb(0x3D5)&~0x10);
369 } else {
370 /* IBM Portable 860 */
371 outw(VGA_SR_PORT, 0x0806);
372 outw(VGA_SR_PORT, 0x1041);
373 outw(VGA_SR_PORT, 0x1128);
374 outw(VGA_CR_PORT, 0x4000);
375 outw(VGA_CR_PORT, 0x3100);
376 outw(VGA_CR_PORT, 0x3a05);
377 outw(VGA_CR_PORT, 0x6688);
378 outw(VGA_CR_PORT, 0x5800); /* disable linear addressing */
379 outw(VGA_CR_PORT, 0x4500); /* disable H/W cursor */
380 outw(VGA_SR_PORT, 0x5410); /* enable auto-centering */
381 outw(VGA_SR_PORT, 0x561f);
382 outw(VGA_SR_PORT, 0x1b80); /* lock DCLK selection */
383 outw(VGA_CR_PORT, 0x3900); /* lock S3 registers */
384 outw(VGA_CR_PORT, 0x3800);
385 }
386 }
387
388 static void
389 clear_video_memory(void)
390 {
391 int i, j;
392
393 for (i = 0; i < LINES; i++) {
394 for (j = 0; j < COLS; j++) {
395 videomem[((i * COLS)+j) * 2] = 0x20; /* space */
396 videomem[((i * COLS)+j) * 2 + 1] = 0x07; /* fg/bg */
397 }
398 }
399 }
400
401 #endif /* VGA_RESET */
402