4 * Initialize the VGA control registers to 80x25 text mode.
6 * Adapted from a program by:
8 * San Francisco Indigo Company
9 * sfindigo!sellgren@uunet.uu.net
11 * Original concept by:
12 * Gary Thomas <gdt@linuxppc.org>
13 * Adapted for Moto boxes by:
14 * Pat Kane & Mark Scott, 1996
15 * Adapted for IBM portables by:
17 * Multi-console support:
18 * Terje Malmedal <terje.malmedal@usit.uio.no>
25 extern int lines, cols;
33 unsigned short io_port;
34 unsigned char io_index;
35 unsigned char io_value;
38 void unlockVideo(int slot);
39 void setTextRegs(struct VgaRegs *svp);
40 void setTextCLUT(int shift);
41 void clearVideoMemory(void);
42 void loadFont(unsigned char *ISA_mem);
44 static void mdelay(int ms)
51 * Default console text mode registers used to reset
55 #define ENDMK 0xFFFF /* End marker */
57 #define S3Vendor 0x5333
58 #define CirrusVendor 0x1013
59 #define DiamondVendor 0x100E
60 #define MatroxVendor 0x102B
61 #define ParadiseVendor 0x101C
63 struct VgaRegs GenVgaTextRegs[NREGS+1] = {
64 /* port index value */
87 { 0x3d4, 0x10, 0x9c },
88 { 0x3d4, 0x11, 0x8e },
89 { 0x3d4, 0x12, 0x8f },
90 { 0x3d4, 0x13, 0x28 },
91 { 0x3d4, 0x14, 0x1f },
92 { 0x3d4, 0x15, 0x96 },
93 { 0x3d4, 0x16, 0xb9 },
94 { 0x3d4, 0x17, 0xa3 },
101 { 0x3ce, 0x5, 0x10 },
104 { 0x3ce, 0x8, 0xff },
110 unsigned char r, g, b;
114 * Default console text mode color table.
115 * These values were obtained by booting Linux with
116 * text mode firmware & then dumping the registers.
118 struct RGBColors TextCLUT[256] =
128 { 0x2a, 0x2a, 0x2a },
135 { 0x2a, 0x2a, 0x15 },
136 { 0x2a, 0x2a, 0x3f },
142 { 0x2a, 0x15, 0x2a },
144 { 0x2a, 0x3f, 0x2a },
149 { 0x2a, 0x15, 0x15 },
150 { 0x2a, 0x15, 0x3f },
151 { 0x2a, 0x3f, 0x15 },
152 { 0x2a, 0x3f, 0x3f },
156 { 0x15, 0x2a, 0x2a },
160 { 0x3f, 0x2a, 0x2a },
163 { 0x15, 0x2a, 0x15 },
164 { 0x15, 0x2a, 0x3f },
167 { 0x3f, 0x2a, 0x15 },
168 { 0x3f, 0x2a, 0x3f },
170 { 0x15, 0x15, 0x2a },
172 { 0x15, 0x3f, 0x2a },
174 { 0x3f, 0x15, 0x2a },
176 { 0x3f, 0x3f, 0x2a },
177 { 0x15, 0x15, 0x15 },
178 { 0x15, 0x15, 0x3f },
179 { 0x15, 0x3f, 0x15 },
180 { 0x15, 0x3f, 0x3f },
181 { 0x3f, 0x15, 0x15 },
182 { 0x3f, 0x15, 0x3f },
183 { 0x3f, 0x3f, 0x15 },
184 { 0x3f, 0x3f, 0x3f },
187 { 0x26, 0x10, 0x3d },
188 { 0x29, 0x29, 0x38 },
191 { 0x3c, 0x25, 0x33 },
195 { 0x25, 0x2a, 0x35 },
202 { 0x3c, 0x35, 0x2f },
203 { 0x2d, 0x26, 0x3e },
205 { 0x25, 0x3c, 0x11 },
212 { 0x2a, 0x37, 0x1f },
215 { 0x12, 0x2f, 0x19 },
216 { 0x29, 0x2e, 0x31 },
217 { 0x25, 0x13, 0x3e },
218 { 0x33, 0x3e, 0x33 },
219 { 0x1d, 0x2c, 0x25 },
221 { 0x32, 0x25, 0x39 },
224 { 0x36, 0x17, 0x34 },
229 { 0x19, 0x21, 0x3e },
230 { 0x27, 0x11, 0x2f },
231 { 0x38, 0x3f, 0x3c },
232 { 0x36, 0x2d, 0x15 },
235 { 0x1b, 0x11, 0x3f },
237 { 0x1a, 0x39, 0x3d },
239 { 0x22, 0x21, 0x23 },
241 { 0x1f, 0x22, 0x3d },
273 { 0x14, 0x14, 0x1c },
274 { 0x16, 0x14, 0x1c },
275 { 0x18, 0x14, 0x1c },
276 { 0x1a, 0x14, 0x1c },
277 { 0x1c, 0x14, 0x1c },
278 { 0x1c, 0x14, 0x1a },
279 { 0x1c, 0x14, 0x18 },
280 { 0x1c, 0x14, 0x16 },
281 { 0x1c, 0x14, 0x14 },
282 { 0x1c, 0x16, 0x14 },
283 { 0x1c, 0x18, 0x14 },
284 { 0x1c, 0x1a, 0x14 },
285 { 0x1c, 0x1c, 0x14 },
286 { 0x1a, 0x1c, 0x14 },
287 { 0x18, 0x1c, 0x14 },
288 { 0x16, 0x1c, 0x14 },
289 { 0x14, 0x1c, 0x14 },
290 { 0x14, 0x1c, 0x16 },
291 { 0x14, 0x1c, 0x18 },
292 { 0x14, 0x1c, 0x1a },
293 { 0x14, 0x1c, 0x1c },
294 { 0x14, 0x1a, 0x1c },
295 { 0x14, 0x18, 0x1c },
296 { 0x14, 0x16, 0x1c },
378 unsigned char AC[21] = {
379 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
380 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
381 0x0C, 0x00, 0x0F, 0x08, 0x00};
383 static int scanPCI(int start_slt);
384 static int PCIVendor(int);
386 static void printslots(void);
388 extern void puthex(unsigned long);
389 extern void puts(const char *);
390 static void unlockS3(void);
393 outw(int port, unsigned short val)
395 outb(port, val >> 8);
400 vga_init(unsigned char *ISA_mem)
403 struct VgaRegs *VgaTextRegs;
405 /* See if VGA already in TEXT mode - exit if so! */
407 if ((inb(0x3CF) & 0x01) == 0){
408 puts("VGA already in text mode\n");
412 /* If no VGA responding in text mode, then we have some work to do...
415 while((slot = scanPCI(slot)) > -1) { /* find video card in use */
416 unlockVideo(slot); /* enable I/O to card */
417 VgaTextRegs = GenVgaTextRegs;
419 switch (PCIVendor(slot)) {
427 outw(0x3C4, 0x0612); /* unlock ext regs */
428 outw(0x3C4, 0x0700); /* reset ext sequence mode */
431 case(ParadiseVendor): /* IBM Portable 850 */
432 outw(0x3ce, 0x0f05); /* unlock pardise registers */
436 outb(0x3ce, 0x0b); /* disable linear addressing */
437 outb(0x3cf, inb(0x3cf) & ~0x30);
439 outb(0x3ce, 0x0e); /* disable 256 color mode */
440 outb(0x3cf, inb(0x3cf) & ~0x01);
441 outb(0xd00, 0xff); /* enable auto-centering */
442 if (!(inb(0xd01) & 0x03)) {
444 outb(0x3d5, inb(0x3d5) & ~0x90);
446 outb(0x3d5, inb(0x3d5) | 0x04);
456 #if 0 /* Untested - probably doesn't work */
459 puts("VGA Chip Vendor ID: ");
460 puthex(PCIVendor(slot));
466 outw(0x3C4, 0x0120); /* disable video */
467 setTextRegs(VgaTextRegs); /* initial register setup */
468 setTextCLUT(0); /* load color lookup table */
469 loadFont(ISA_mem); /* load font */
470 setTextRegs(VgaTextRegs); /* reload registers */
471 outw(0x3C4, 0x0100); /* re-enable video */
474 if (PCIVendor(slot) == S3Vendor) {
475 outb(0x3c2, 0x63); /* MISC */
483 mdelay(1000); /* give time for the video monitor to come up */
485 return (1); /* 'CRT' I/O supported */
489 * Write to VGA Attribute registers.
492 writeAttr(unsigned char index, unsigned char data, unsigned char videoOn)
495 v = inb(0x3da); /* reset attr. address toggle */
497 outb(0x3c0, (index & 0x1F) | 0x20);
499 outb(0x3c0, (index & 0x1F));
504 setTextRegs(struct VgaRegs *svp)
511 while( svp->io_port != ENDMK ) {
512 outb(svp->io_port, svp->io_index);
513 outb(svp->io_port+1, svp->io_value);
517 outb(0x3c2, 0x67); /* MISC */
518 outb(0x3c6, 0xff); /* MASK */
520 for ( i = 0; i < 0x10; i++)
521 writeAttr(i, AC[i], 0); /* pallete */
522 writeAttr(0x10, 0x0c, 0); /* text mode */
523 writeAttr(0x11, 0x00, 0); /* overscan color (border) */
524 writeAttr(0x12, 0x0f, 0); /* plane enable */
525 writeAttr(0x13, 0x08, 0); /* pixel panning */
526 writeAttr(0x14, 0x00, 1); /* color select; video on */
530 setTextCLUT(int shift)
539 for ( i = 0; i < 256; i++) {
540 outb(0x3C9, TextCLUT[i].r << shift);
541 outb(0x3C9, TextCLUT[i].g << shift);
542 outb(0x3C9, TextCLUT[i].b << shift);
547 loadFont(unsigned char *ISA_mem)
550 unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
556 i = inb(0x3DA); /* Reset Attr toggle */
559 outb(0x3C0, 0x01); /* graphics mode */
561 outw(0x3C4, 0x0001); /* reset sequencer */
562 outw(0x3C4, 0x0204); /* write to plane 2 */
563 outw(0x3C4, 0x0406); /* enable plane graphics */
564 outw(0x3C4, 0x0003); /* reset sequencer */
565 outw(0x3CE, 0x0402); /* read plane 2 */
566 outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
567 outw(0x3CE, 0x0605); /* set graphics mode */
569 for (i = 0; i < sizeof(font); i += 16) {
570 for (j = 0; j < 16; j++) {
571 __asm__ volatile("eieio");
572 font_page[(2*i)+j] = font[i+j];
584 s3_device_id = inb(0x3d5) << 8;
586 s3_device_id |= inb(0x3d5);
588 if (s3_device_id != 0x8812) {
589 /* From the S3 manual */
590 outb(0x46E8, 0x10); /* Put into setup mode */
592 outb(0x102, 0x01); /* Enable registers */
593 outb(0x46E8, 0x08); /* Enable video */
598 outb(0x42E8, 0x80); /* Reset graphics engine? */
601 outb(0x3D4, 0x38); /* Unlock all registers */
606 outb(0x3D5, inb(0x3D5)|0x01);
608 outb(0x3D5, inb(0x3D5)&~0x52);
610 outb(0x3D5, inb(0x3D5)&~0x30);
616 outb(0x3D5, inb(0x3D5)&~0x4B);
629 outb(0x3D4, 0x69); /* High order bits for cursor address */
633 outb(0x3D5, inb(0x3D5)&~0x10);
635 outw(0x3c4, 0x0806); /* IBM Portable 860 */
642 outw(0x3d4, 0x5800); /* disable linear addressing */
643 outw(0x3d4, 0x4500); /* disable H/W cursor */
644 outw(0x3c4, 0x5410); /* enable auto-centering */
646 outw(0x3c4, 0x1b80); /* lock DCLK selection */
647 outw(0x3d4, 0x3900); /* lock S3 registers */
653 * cursor() sets an offset (0-1999) into the 80x25 text area.
658 int pos = (y*cols)+x;
660 outb(0x3D5, pos >> 8);
666 clearVideoMemory(void)
669 for (i = 0; i < lines; i++) {
670 for (j = 0; j < cols; j++) {
671 vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */
672 vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */
685 should use devfunc number/indirect method to be totally safe on
686 all machines, this works for now on 3 slot Moto boxes
689 struct PCI_ConfigInfo {
690 unsigned long * config_addr;
691 unsigned long regs[NPCIREGS];
692 } PCI_slots [NSLOTS] = {
694 { (unsigned long *)0x80808000, {0xDEADBEEF,} }, /* onboard */
695 { (unsigned long *)0x80800800, {0xDEADBEEF,} }, /* onboard */
696 { (unsigned long *)0x80801000, {0xDEADBEEF,} }, /* onboard */
697 { (unsigned long *)0x80802000, {0xDEADBEEF,} }, /* onboard */
698 { (unsigned long *)0x80804000, {0xDEADBEEF,} }, /* onboard */
699 { (unsigned long *)0x80810000, {0xDEADBEEF,} }, /* slot A/1 */
700 { (unsigned long *)0x80820000, {0xDEADBEEF,} }, /* slot B/2 */
701 { (unsigned long *)0x80840000, {0xDEADBEEF,} } /* slot C/3 */
707 * The following code modifies the PCI Command register
708 * to enable memory and I/O accesses.
711 unlockVideo(int slot)
713 volatile unsigned char * ppci;
715 ppci = (unsigned char * )PCI_slots[slot].config_addr;
716 ppci[4] = 0x0003; /* enable memory and I/O accesses */
717 ppci[0x10] = 0x00000; /* turn off memory mapping */
718 ppci[0x11] = 0x00000; /* mem_base = 0 */
719 ppci[0x12] = 0x00000;
720 ppci[0x13] = 0x00000;
721 __asm__ volatile("eieio");
724 outb(0x3d5, 0x0e); /* unlock CR0-CR7 */
728 SwapBytes(long lv) /* turn little endian into big indian long */
731 t = (lv&0x000000FF) << 24;
732 t |= (lv&0x0000FF00) << 8;
733 t |= (lv&0x00FF0000) >> 8;
734 t |= (lv&0xFF000000) >> 24;
745 scanPCI(int start_slt)
748 struct PCI_ConfigInfo *pslot;
752 for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
753 pslot = &PCI_slots[slt];
754 for ( r = 0; r < NPCIREGS; r++) {
755 pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
758 if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
760 if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
761 ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
763 /* did firmware enable it ? */
764 if ( (pslot->regs[CMD] & 0x03) ) {
775 /* return Vendor ID of card in the slot */
777 int PCIVendor(int slotnum) {
778 struct PCI_ConfigInfo *pslot;
780 pslot = &PCI_slots[slotnum];
782 return (pslot->regs[DEVID] & 0xFFFF);
787 void printslots(void)
791 struct PCI_ConfigInfo *pslot;
793 for(i=0; i < NSLOTS; i++) {
795 pslot = &PCI_slots[i];
796 printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
797 i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
799 puts("PCI Slot number: "); puthex(i);
800 puts(" Vendor ID: ");
801 puthex(PCIVendor(i)); puts("\n");