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); /* palette */
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");