1/*
2 * vreset.c
3 *
4 * Initialize the VGA control registers to 80x25 text mode.
5 *
6 * Adapted from a program by:
7 *                                      Steve Sellgren
8 *                                      San Francisco Indigo Company
9 *                                      sfindigo!sellgren@uunet.uu.net
10 *
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:
16 *                                      Takeshi Ishimoto
17 * Multi-console support:
18 *                                      Terje Malmedal <terje.malmedal@usit.uio.no>
19 */
20
21#include "iso_font.h"
22#include "nonstdio.h"
23
24extern char *vidmem;
25extern int lines, cols;
26struct VaRegs;
27
28/*
29 * VGA Register
30 */
31struct VgaRegs
32{
33	unsigned short io_port;
34	unsigned char  io_index;
35	unsigned char  io_value;
36};
37
38void unlockVideo(int slot);
39void setTextRegs(struct VgaRegs *svp);
40void setTextCLUT(int shift);
41void clearVideoMemory(void);
42void loadFont(unsigned char *ISA_mem);
43
44static void mdelay(int ms)
45{
46	for (; ms > 0; --ms)
47		udelay(1000);
48}
49
50/*
51 * Default console text mode registers  used to reset
52 * graphics adapter.
53 */
54#define NREGS 54
55#define ENDMK  0xFFFF  /* End marker */
56
57#define S3Vendor	0x5333
58#define CirrusVendor    0x1013
59#define DiamondVendor   0x100E
60#define MatroxVendor    0x102B
61#define ParadiseVendor  0x101C
62
63struct VgaRegs GenVgaTextRegs[NREGS+1] = {
64	/* port		index	value  */
65	/* SR Regs */
66	{ 0x3c4,	0x1,	0x0 },
67	{ 0x3c4,	0x2,	0x3 },
68	{ 0x3c4,	0x3,	0x0 },
69	{ 0x3c4,	0x4,	0x2 },
70	 /* CR Regs */
71	{ 0x3d4,	0x0,	0x5f },
72	{ 0x3d4,	0x1,	0x4f },
73	{ 0x3d4,	0x2,	0x50 },
74	{ 0x3d4,	0x3,	0x82 },
75	{ 0x3d4,	0x4,	0x55 },
76	{ 0x3d4,	0x5,	0x81 },
77	{ 0x3d4,	0x6,	0xbf },
78	{ 0x3d4,	0x7,	0x1f },
79	{ 0x3d4,	0x8,	0x00 },
80	{ 0x3d4,	0x9,	0x4f },
81	{ 0x3d4,	0xa,	0x0d },
82	{ 0x3d4,	0xb,	0x0e },
83	{ 0x3d4,	0xc,	0x00 },
84	{ 0x3d4,	0xd,	0x00 },
85	{ 0x3d4,	0xe,	0x00 },
86	{ 0x3d4,	0xf,	0x00 },
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 },
95	 /* GR Regs */
96	{ 0x3ce,	0x0,	0x0 },
97	{ 0x3ce,	0x1,	0x0 },
98	{ 0x3ce,	0x2,	0x0 },
99	{ 0x3ce,	0x3,	0x0 },
100	{ 0x3ce,	0x4,	0x0 },
101	{ 0x3ce,	0x5,	0x10 },
102	{ 0x3ce,	0x6,	0xe },
103	{ 0x3ce,	0x7,	0x0 },
104	{ 0x3ce,	0x8,	0xff },
105	{ ENDMK }
106};
107
108struct RGBColors
109{
110  unsigned char r, g, b;
111};
112
113/*
114 * Default console text mode color table.
115 * These values were obtained by booting Linux with
116 * text mode firmware & then dumping the registers.
117 */
118struct RGBColors TextCLUT[256] =
119{
120	/* red	green	blue  */
121	{ 0x0,	0x0,	0x0 },
122	{ 0x0,	0x0,	0x2a },
123	{ 0x0,	0x2a,	0x0 },
124	{ 0x0,	0x2a,	0x2a },
125	{ 0x2a,	0x0,	0x0 },
126	{ 0x2a,	0x0,	0x2a },
127	{ 0x2a,	0x2a,	0x0 },
128	{ 0x2a,	0x2a,	0x2a },
129	{ 0x0,	0x0,	0x15 },
130	{ 0x0,	0x0,	0x3f },
131	{ 0x0,	0x2a,	0x15 },
132	{ 0x0,	0x2a,	0x3f },
133	{ 0x2a,	0x0,	0x15 },
134	{ 0x2a,	0x0,	0x3f },
135	{ 0x2a,	0x2a,	0x15 },
136	{ 0x2a,	0x2a,	0x3f },
137	{ 0x0,	0x15,	0x0 },
138	{ 0x0,	0x15,	0x2a },
139	{ 0x0,	0x3f,	0x0 },
140	{ 0x0,	0x3f,	0x2a },
141	{ 0x2a,	0x15,	0x0 },
142	{ 0x2a,	0x15,	0x2a },
143	{ 0x2a,	0x3f,	0x0 },
144	{ 0x2a,	0x3f,	0x2a },
145	{ 0x0,	0x15,	0x15 },
146	{ 0x0,	0x15,	0x3f },
147	{ 0x0,	0x3f,	0x15 },
148	{ 0x0,	0x3f,	0x3f },
149	{ 0x2a,	0x15,	0x15 },
150	{ 0x2a,	0x15,	0x3f },
151	{ 0x2a,	0x3f,	0x15 },
152	{ 0x2a,	0x3f,	0x3f },
153	{ 0x15,	0x0,	0x0 },
154	{ 0x15,	0x0,	0x2a },
155	{ 0x15,	0x2a,	0x0 },
156	{ 0x15,	0x2a,	0x2a },
157	{ 0x3f,	0x0,	0x0 },
158	{ 0x3f,	0x0,	0x2a },
159	{ 0x3f,	0x2a,	0x0 },
160	{ 0x3f,	0x2a,	0x2a },
161	{ 0x15,	0x0,	0x15 },
162	{ 0x15,	0x0,	0x3f },
163	{ 0x15,	0x2a,	0x15 },
164	{ 0x15,	0x2a,	0x3f },
165	{ 0x3f,	0x0,	0x15 },
166	{ 0x3f,	0x0,	0x3f },
167	{ 0x3f,	0x2a,	0x15 },
168	{ 0x3f,	0x2a,	0x3f },
169	{ 0x15,	0x15,	0x0 },
170	{ 0x15,	0x15,	0x2a },
171	{ 0x15,	0x3f,	0x0 },
172	{ 0x15,	0x3f,	0x2a },
173	{ 0x3f,	0x15,	0x0 },
174	{ 0x3f,	0x15,	0x2a },
175	{ 0x3f,	0x3f,	0x0 },
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 },
185	{ 0x39,	0xc,	0x5 },
186	{ 0x15,	0x2c,	0xf },
187	{ 0x26,	0x10,	0x3d },
188	{ 0x29,	0x29,	0x38 },
189	{ 0x4,	0x1a,	0xe },
190	{ 0x2,	0x1e,	0x3a },
191	{ 0x3c,	0x25,	0x33 },
192	{ 0x3c,	0xc,	0x2c },
193	{ 0x3f,	0x3,	0x2b },
194	{ 0x1c,	0x9,	0x13 },
195	{ 0x25,	0x2a,	0x35 },
196	{ 0x1e,	0xa,	0x38 },
197	{ 0x24,	0x8,	0x3 },
198	{ 0x3,	0xe,	0x36 },
199	{ 0xc,	0x6,	0x2a },
200	{ 0x26,	0x3,	0x32 },
201	{ 0x5,	0x2f,	0x33 },
202	{ 0x3c,	0x35,	0x2f },
203	{ 0x2d,	0x26,	0x3e },
204	{ 0xd,	0xa,	0x10 },
205	{ 0x25,	0x3c,	0x11 },
206	{ 0xd,	0x4,	0x2e },
207	{ 0x5,	0x19,	0x3e },
208	{ 0xc,	0x13,	0x34 },
209	{ 0x2b,	0x6,	0x24 },
210	{ 0x4,	0x3,	0xd },
211	{ 0x2f,	0x3c,	0xc },
212	{ 0x2a,	0x37,	0x1f },
213	{ 0xf,	0x12,	0x38 },
214	{ 0x38,	0xe,	0x2a },
215	{ 0x12,	0x2f,	0x19 },
216	{ 0x29,	0x2e,	0x31 },
217	{ 0x25,	0x13,	0x3e },
218	{ 0x33,	0x3e,	0x33 },
219	{ 0x1d,	0x2c,	0x25 },
220	{ 0x15,	0x15,	0x5 },
221	{ 0x32,	0x25,	0x39 },
222	{ 0x1a,	0x7,	0x1f },
223	{ 0x13,	0xe,	0x1d },
224	{ 0x36,	0x17,	0x34 },
225	{ 0xf,	0x15,	0x23 },
226	{ 0x2,	0x35,	0xd },
227	{ 0x15,	0x3f,	0xc },
228	{ 0x14,	0x2f,	0xf },
229	{ 0x19,	0x21,	0x3e },
230	{ 0x27,	0x11,	0x2f },
231	{ 0x38,	0x3f,	0x3c },
232	{ 0x36,	0x2d,	0x15 },
233	{ 0x16,	0x17,	0x2 },
234	{ 0x1,	0xa,	0x3d },
235	{ 0x1b,	0x11,	0x3f },
236	{ 0x21,	0x3c,	0xd },
237	{ 0x1a,	0x39,	0x3d },
238	{ 0x8,	0xe,	0xe },
239	{ 0x22,	0x21,	0x23 },
240	{ 0x1e,	0x30,	0x5 },
241	{ 0x1f,	0x22,	0x3d },
242	{ 0x1e,	0x2f,	0xa },
243	{ 0x0,	0x1c,	0xe },
244	{ 0x0,	0x1c,	0x15 },
245	{ 0x0,	0x1c,	0x1c },
246	{ 0x0,	0x15,	0x1c },
247	{ 0x0,	0xe,	0x1c },
248	{ 0x0,	0x7,	0x1c },
249	{ 0xe,	0xe,	0x1c },
250	{ 0x11,	0xe,	0x1c },
251	{ 0x15,	0xe,	0x1c },
252	{ 0x18,	0xe,	0x1c },
253	{ 0x1c,	0xe,	0x1c },
254	{ 0x1c,	0xe,	0x18 },
255	{ 0x1c,	0xe,	0x15 },
256	{ 0x1c,	0xe,	0x11 },
257	{ 0x1c,	0xe,	0xe },
258	{ 0x1c,	0x11,	0xe },
259	{ 0x1c,	0x15,	0xe },
260	{ 0x1c,	0x18,	0xe },
261	{ 0x1c,	0x1c,	0xe },
262	{ 0x18,	0x1c,	0xe },
263	{ 0x15,	0x1c,	0xe },
264	{ 0x11,	0x1c,	0xe },
265	{ 0xe,	0x1c,	0xe },
266	{ 0xe,	0x1c,	0x11 },
267	{ 0xe,	0x1c,	0x15 },
268	{ 0xe,	0x1c,	0x18 },
269	{ 0xe,	0x1c,	0x1c },
270	{ 0xe,	0x18,	0x1c },
271	{ 0xe,	0x15,	0x1c },
272	{ 0xe,	0x11,	0x1c },
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 },
297	{ 0x0,	0x0,	0x10 },
298	{ 0x4,	0x0,	0x10 },
299	{ 0x8,	0x0,	0x10 },
300	{ 0xc,	0x0,	0x10 },
301	{ 0x10,	0x0,	0x10 },
302	{ 0x10,	0x0,	0xc },
303	{ 0x10,	0x0,	0x8 },
304	{ 0x10,	0x0,	0x4 },
305	{ 0x10,	0x0,	0x0 },
306	{ 0x10,	0x4,	0x0 },
307	{ 0x10,	0x8,	0x0 },
308	{ 0x10,	0xc,	0x0 },
309	{ 0x10,	0x10,	0x0 },
310	{ 0xc,	0x10,	0x0 },
311	{ 0x8,	0x10,	0x0 },
312	{ 0x4,	0x10,	0x0 },
313	{ 0x0,	0x10,	0x0 },
314	{ 0x0,	0x10,	0x4 },
315	{ 0x0,	0x10,	0x8 },
316	{ 0x0,	0x10,	0xc },
317	{ 0x0,	0x10,	0x10 },
318	{ 0x0,	0xc,	0x10 },
319	{ 0x0,	0x8,	0x10 },
320	{ 0x0,	0x4,	0x10 },
321	{ 0x8,	0x8,	0x10 },
322	{ 0xa,	0x8,	0x10 },
323	{ 0xc,	0x8,	0x10 },
324	{ 0xe,	0x8,	0x10 },
325	{ 0x10,	0x8,	0x10 },
326	{ 0x10,	0x8,	0xe },
327	{ 0x10,	0x8,	0xc },
328	{ 0x10,	0x8,	0xa },
329	{ 0x10,	0x8,	0x8 },
330	{ 0x10,	0xa,	0x8 },
331	{ 0x10,	0xc,	0x8 },
332	{ 0x10,	0xe,	0x8 },
333	{ 0x10,	0x10,	0x8 },
334	{ 0xe,	0x10,	0x8 },
335	{ 0xc,	0x10,	0x8 },
336	{ 0xa,	0x10,	0x8 },
337	{ 0x8,	0x10,	0x8 },
338	{ 0x8,	0x10,	0xa },
339	{ 0x8,	0x10,	0xc },
340	{ 0x8,	0x10,	0xe },
341	{ 0x8,	0x10,	0x10 },
342	{ 0x8,	0xe,	0x10 },
343	{ 0x8,	0xc,	0x10 },
344	{ 0x8,	0xa,	0x10 },
345	{ 0xb,	0xb,	0x10 },
346	{ 0xc,	0xb,	0x10 },
347	{ 0xd,	0xb,	0x10 },
348	{ 0xf,	0xb,	0x10 },
349	{ 0x10,	0xb,	0x10 },
350	{ 0x10,	0xb,	0xf },
351	{ 0x10,	0xb,	0xd },
352	{ 0x10,	0xb,	0xc },
353	{ 0x10,	0xb,	0xb },
354	{ 0x10,	0xc,	0xb },
355	{ 0x10,	0xd,	0xb },
356	{ 0x10,	0xf,	0xb },
357	{ 0x10,	0x10,	0xb },
358	{ 0xf,	0x10,	0xb },
359	{ 0xd,	0x10,	0xb },
360	{ 0xc,	0x10,	0xb },
361	{ 0xb,	0x10,	0xb },
362	{ 0xb,	0x10,	0xc },
363	{ 0xb,	0x10,	0xd },
364	{ 0xb,	0x10,	0xf },
365	{ 0xb,	0x10,	0x10 },
366	{ 0xb,	0xf,	0x10 },
367	{ 0xb,	0xd,	0x10 },
368	{ 0xb,	0xc,	0x10 },
369	{ 0x0,	0x0,	0x0 },
370	{ 0x0,	0x0,	0x0 },
371	{ 0x0,	0x0,	0x0 },
372	{ 0x0,	0x0,	0x0 },
373	{ 0x0,	0x0,	0x0 },
374	{ 0x0,	0x0,	0x0 },
375	{ 0x0,	0x0,	0x0 }
376};
377
378unsigned 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};
382
383static int scanPCI(int start_slt);
384static int PCIVendor(int);
385#ifdef DEBUG
386static void printslots(void);
387#endif
388extern void puthex(unsigned long);
389extern void puts(const char *);
390static void unlockS3(void);
391
392static inline void
393outw(int port, unsigned short val)
394{
395	outb(port, val >> 8);
396	outb(port+1, val);
397}
398
399int
400vga_init(unsigned char *ISA_mem)
401{
402	int slot;
403	struct VgaRegs *VgaTextRegs;
404
405	/* See if VGA already in TEXT mode - exit if so! */
406	outb(0x3CE, 0x06);
407	if ((inb(0x3CF) & 0x01) == 0){
408		puts("VGA already in text mode\n");
409		return 0;
410	}
411
412	/* If no VGA responding in text mode, then we have some work to do...
413	 */
414	slot = -1;
415	while((slot = scanPCI(slot)) > -1) { /* find video card in use  */
416		unlockVideo(slot);           /* enable I/O to card      */
417		VgaTextRegs = GenVgaTextRegs;
418
419		switch (PCIVendor(slot)) {
420		default:
421			break;
422		case(S3Vendor):
423			unlockS3();
424			break;
425
426		case(CirrusVendor):
427			outw(0x3C4, 0x0612);       /* unlock ext regs */
428			outw(0x3C4, 0x0700);       /* reset ext sequence mode */
429			break;
430
431		case(ParadiseVendor):                 /* IBM Portable 850 */
432			outw(0x3ce, 0x0f05);      /* unlock pardise registers */
433			outw(0x3c4, 0x0648);
434			outw(0x3d4, 0x2985);
435			outw(0x3d4, 0x34a6);
436			outb(0x3ce, 0x0b);       /* disable linear addressing */
437			outb(0x3cf, inb(0x3cf) & ~0x30);
438			outw(0x3c4, 0x1400);
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)) {
443				outb(0x3d4, 0x33);
444				outb(0x3d5, inb(0x3d5) & ~0x90);
445				outb(0x3d4, 0x32);
446				outb(0x3d5, inb(0x3d5) | 0x04);
447				outw(0x3d4, 0x0250);
448				outw(0x3d4, 0x07ba);
449				outw(0x3d4, 0x0900);
450				outw(0x3d4, 0x15e7);
451				outw(0x3d4, 0x2a95);
452			}
453			outw(0x3d4, 0x34a0);
454			break;
455
456	#if 0 /* Untested - probably doesn't work */
457		case(MatroxVendor):
458		case(DiamondVendor):
459			puts("VGA Chip Vendor ID: ");
460			puthex(PCIVendor(slot));
461			puts("\n");
462			mdelay(1000);
463	#endif
464		};
465
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            */
472		clearVideoMemory();
473
474		if (PCIVendor(slot) == S3Vendor) {
475			outb(0x3c2, 0x63);                  /* MISC */
476		} /* endif */
477
478	#ifdef DEBUG
479		printslots();
480		mdelay(5000);
481	#endif
482
483		mdelay(1000);	/* give time for the video monitor to come up */
484        }
485	return (1);  /* 'CRT' I/O supported */
486}
487
488/*
489 * Write to VGA Attribute registers.
490 */
491void
492writeAttr(unsigned char index, unsigned char data, unsigned char videoOn)
493{
494	unsigned char v;
495	v = inb(0x3da);   /* reset attr. address toggle */
496	if (videoOn)
497		outb(0x3c0, (index & 0x1F) | 0x20);
498	else
499		outb(0x3c0, (index & 0x1F));
500	outb(0x3c0, data);
501}
502
503void
504setTextRegs(struct VgaRegs *svp)
505{
506	int i;
507
508	/*
509	 *  saved settings
510	 */
511	while( svp->io_port != ENDMK ) {
512		outb(svp->io_port,   svp->io_index);
513		outb(svp->io_port+1, svp->io_value);
514		svp++;
515	}
516
517	outb(0x3c2, 0x67);  /* MISC */
518	outb(0x3c6, 0xff);  /* MASK */
519
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  */
527}
528
529void
530setTextCLUT(int shift)
531{
532	int i;
533
534	outb(0x3C6, 0xFF);
535	i = inb(0x3C7);
536	outb(0x3C8, 0);
537	i = inb(0x3C7);
538
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);
543	}
544}
545
546void
547loadFont(unsigned char *ISA_mem)
548{
549	int i, j;
550	unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
551
552	outb(0x3C2, 0x67);
553	/*
554	 * Load font
555	 */
556	i = inb(0x3DA);  /* Reset Attr toggle */
557
558	outb(0x3C0,0x30);
559	outb(0x3C0, 0x01);      /* graphics mode */
560
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 */
568
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];
573		}
574	}
575}
576
577static void
578unlockS3(void)
579{
580        int s3_device_id;
581	outw(0x3d4, 0x3848);
582	outw(0x3d4, 0x39a5);
583	outb(0x3d4, 0x2d);
584	s3_device_id = inb(0x3d5) << 8;
585	outb(0x3d4, 0x2e);
586	s3_device_id |= inb(0x3d5);
587
588	if (s3_device_id != 0x8812) {
589		/* From the S3 manual */
590		outb(0x46E8, 0x10);  /* Put into setup mode */
591		outb(0x3C3, 0x10);
592		outb(0x102, 0x01);   /* Enable registers */
593		outb(0x46E8, 0x08);  /* Enable video */
594		outb(0x3C3, 0x08);
595		outb(0x4AE8, 0x00);
596
597
598		outb(0x3D4, 0x38);  /* Unlock all registers */
599		outb(0x3D5, 0x48);
600		outb(0x3D4, 0x39);
601		outb(0x3D5, 0xA5);
602		outb(0x3D4, 0x40);
603		outb(0x3D5, inb(0x3D5)|0x01);
604		outb(0x3D4, 0x33);
605		outb(0x3D5, inb(0x3D5)&~0x52);
606		outb(0x3D4, 0x35);
607		outb(0x3D5, inb(0x3D5)&~0x30);
608		outb(0x3D4, 0x3A);
609		outb(0x3D5, 0x00);
610		outb(0x3D4, 0x53);
611		outb(0x3D5, 0x00);
612		outb(0x3D4, 0x31);
613		outb(0x3D5, inb(0x3D5)&~0x4B);
614		outb(0x3D4, 0x58);
615
616		outb(0x3D5, 0);
617
618		outb(0x3D4, 0x54);
619		outb(0x3D5, 0x38);
620		outb(0x3D4, 0x60);
621		outb(0x3D5, 0x07);
622		outb(0x3D4, 0x61);
623		outb(0x3D5, 0x80);
624		outb(0x3D4, 0x62);
625		outb(0x3D5, 0xA1);
626		outb(0x3D4, 0x69);  /* High order bits for cursor address */
627		outb(0x3D5, 0);
628
629		outb(0x3D4, 0x32);
630		outb(0x3D5, inb(0x3D5)&~0x10);
631	} else {
632                outw(0x3c4, 0x0806);            /* IBM Portable 860 */
633                outw(0x3c4, 0x1041);
634                outw(0x3c4, 0x1128);
635                outw(0x3d4, 0x4000);
636                outw(0x3d4, 0x3100);
637                outw(0x3d4, 0x3a05);
638                outw(0x3d4, 0x6688);
639                outw(0x3d4, 0x5800);            /* disable linear addressing */
640                outw(0x3d4, 0x4500);            /* disable H/W cursor */
641                outw(0x3c4, 0x5410);            /* enable auto-centering */
642                outw(0x3c4, 0x561f);
643                outw(0x3c4, 0x1b80);            /* lock DCLK selection */
644                outw(0x3d4, 0x3900);            /* lock S3 registers */
645                outw(0x3d4, 0x3800);
646	} /* endif */
647}
648
649/*
650 * cursor() sets an offset (0-1999) into the 80x25 text area.
651 */
652void
653cursor(int x, int y)
654{
655	int pos = (y*cols)+x;
656	outb(0x3D4, 14);
657	outb(0x3D5, pos >> 8);
658	outb(0x3D4, 15);
659	outb(0x3D5, pos);
660}
661
662void
663clearVideoMemory(void)
664{
665	int i, j;
666	for (i = 0;  i < lines;  i++) {
667		for (j = 0;  j < cols;  j++) {
668			vidmem[((i*cols)+j)*2] = 0x20;	/* fill with space character */
669			vidmem[((i*cols)+j)*2+1] = 0x07;  /* set bg & fg attributes */
670		}
671	}
672}
673
674/* ============ */
675
676
677#define NSLOTS 8
678#define NPCIREGS  5
679
680
681/*
682 should use devfunc number/indirect method to be totally safe on
683 all machines, this works for now on 3 slot Moto boxes
684*/
685
686struct PCI_ConfigInfo {
687  unsigned long * config_addr;
688  unsigned long regs[NPCIREGS];
689} PCI_slots [NSLOTS] = {
690
691    { (unsigned long *)0x80808000, {0xDEADBEEF,} },   /* onboard */
692    { (unsigned long *)0x80800800, {0xDEADBEEF,} },   /* onboard */
693    { (unsigned long *)0x80801000, {0xDEADBEEF,} },   /* onboard */
694    { (unsigned long *)0x80802000, {0xDEADBEEF,} },   /* onboard */
695    { (unsigned long *)0x80804000, {0xDEADBEEF,} },   /* onboard */
696    { (unsigned long *)0x80810000, {0xDEADBEEF,} },   /* slot A/1 */
697    { (unsigned long *)0x80820000, {0xDEADBEEF,} },   /* slot B/2 */
698    { (unsigned long *)0x80840000, {0xDEADBEEF,} }    /* slot C/3 */
699};
700
701
702
703/*
704 * The following code modifies the PCI Command register
705 * to enable memory and I/O accesses.
706 */
707void
708unlockVideo(int slot)
709{
710       volatile unsigned char * ppci;
711
712        ppci =  (unsigned char * )PCI_slots[slot].config_addr;
713	ppci[4] = 0x0003;         /* enable memory and I/O accesses */
714	ppci[0x10] = 0x00000;     /* turn off memory mapping */
715	ppci[0x11] = 0x00000;     /* mem_base = 0 */
716	ppci[0x12] = 0x00000;
717	ppci[0x13] = 0x00000;
718	__asm__ volatile("eieio");
719
720	outb(0x3d4, 0x11);
721	outb(0x3d5, 0x0e);   /* unlock CR0-CR7 */
722}
723
724long
725SwapBytes(long lv)   /* turn little endian into big indian long */
726{
727    long t;
728    t  = (lv&0x000000FF) << 24;
729    t |= (lv&0x0000FF00) << 8;
730    t |= (lv&0x00FF0000) >> 8;
731    t |= (lv&0xFF000000) >> 24;
732    return(t);
733}
734
735
736#define DEVID   0
737#define CMD     1
738#define CLASS   2
739#define MEMBASE 4
740
741int
742scanPCI(int start_slt)
743{
744	int slt, r;
745	struct PCI_ConfigInfo *pslot;
746	int theSlot = -1;
747	int highVgaSlot = 0;
748
749	for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
750		pslot = &PCI_slots[slt];
751		for ( r = 0; r < NPCIREGS; r++) {
752			pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
753		}
754		/* card in slot ? */
755		if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
756			/* VGA ? */
757			if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
758			     ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
759				highVgaSlot = slt;
760				/* did firmware enable it ? */
761				if ( (pslot->regs[CMD] & 0x03) ) {
762					theSlot = slt;
763					break;
764				}
765			}
766		}
767	}
768
769	return ( theSlot );
770}
771
772/* return Vendor ID of card in the slot */
773static
774int PCIVendor(int slotnum) {
775 struct PCI_ConfigInfo *pslot;
776
777 pslot = &PCI_slots[slotnum];
778
779return (pslot->regs[DEVID] & 0xFFFF);
780}
781
782#ifdef DEBUG
783static
784void printslots(void)
785{
786	int i;
787	for(i=0; i < NSLOTS; i++) {
788		puts("PCI Slot number: "); puthex(i);
789		puts(" Vendor ID: ");
790		puthex(PCIVendor(i)); puts("\n");
791	}
792}
793#endif /* DEBUG */
794