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