|
|
1.1 root 1: #include "asm/io.h"
2: #include "drivers/vga.h"
3: #include "vga.h"
4:
5: /*
6: * $Id$
7: * $Source$
8: *
9: * from the Linux kernel code base.
10: * orig by Ben Pfaff and Petr Vandrovec.
11: *
12: * modified by
13: * Steve M. Gehlbach <[email protected]>
14: *
15: * NOTE: to change the horiz and vertical pixels,
16: * change the xres,yres,xres_virt,yres_virt setting
17: * in the screeninfo structure below. You may also need
18: * to change the border settings as well.
19: *
20: * Convert the screeninfo structure to data for
21: * writing to the vga registers
22: *
23: */
24:
25: // prototypes
26: static int vga_decode_var(const struct screeninfo *var, struct vga_par *par);
27: static int vga_set_regs(const struct vga_par *par);
28:
29: u8 read_seq_b(u16 addr) {
30: outb(addr,SEQ_I);
31: return inb(SEQ_D);
32: }
33: u8 read_gra_b(u16 addr) {
34: outb(addr,GRA_I);
35: return inb(GRA_D);
36: }
37: u8 read_crtc_b(u16 addr) {
38: outb(addr,CRT_IC);
39: return inb(CRT_DC);
40: }
41: u8 read_att_b(u16 addr) {
42: inb(IS1_RC);
43: inb(0x80);
44: outb(addr,ATT_IW);
45: return inb(ATT_R);
46: }
47:
48:
49: /*
50: From: The Frame Buffer Device
51: by Geert Uytterhoeven <[email protected]>
52: in the linux kernel docs.
53:
54: The following picture summarizes all timings. The horizontal retrace time is
55: the sum of the left margin, the right margin and the hsync length, while the
56: vertical retrace time is the sum of the upper margin, the lower margin and the
57: vsync length.
58:
59: +----------+---------------------------------------------+----------+-------+
60: | | ^ | | |
61: | | |upper_margin | | |
62: | | | | | |
63: +----------###############################################----------+-------+
64: | # ^ # | |
65: | # | # | |
66: | # | # | |
67: | # | # | |
68: | left # | # right | hsync |
69: | margin # | xres # margin | len |
70: |<-------->#<---------------+--------------------------->#<-------->|<----->|
71: | # | # | |
72: | # | # | |
73: | # | # | |
74: | # |yres # | |
75: | # | # | |
76: | # | # | |
77: | # | # | |
78: | # | # | |
79: | # | # | |
80: | # | # | |
81: | # | # | |
82: | # | # | |
83: | # | # | |
84: +----------###############################################----------+-------+
85: | | ^ | | |
86: | | |lower_margin | | |
87: | | | | | |
88: +----------+---------------------------------------------+----------+-------+
89: | | ^ | | |
90: | | |vsync_len | | |
91: | | | | | |
92: +----------+---------------------------------------------+----------+-------+
93:
94: All horizontal timings are in number of dotclocks
95: (in picoseconds, 1E-12 s), and vertical timings in number of scanlines.
96:
97: The vga uses the following fields:
98:
99: - pixclock: pixel clock in ps (pico seconds)
100: - xres,yres,xres_v,yres_v
101: - left_margin: time from sync to picture
102: - right_margin: time from picture to sync
103: - upper_margin: time from sync to picture
104: - lower_margin: time from picture to sync
105: - hsync_len: length of horizontal sync
106: - vsync_len: length of vertical sync
107:
108: */
109:
110: /* our display parameters per the above */
111:
112: static const struct screeninfo vga_settings = {
113: 640,400,640,400,/* xres,yres,xres_virt,yres_virt */
114: 0,0, /* xoffset,yoffset */
115: 4, /* bits_per_pixel NOT USED*/
116: 0, /* greyscale ? */
117: {0,0,0}, /* R */
118: {0,0,0}, /* G */
119: {0,0,0}, /* B */
120: {0,0,0}, /* transparency */
121: 0, /* standard pixel format */
122: 0, // activate now
123: -1,-1, // height and width in mm
124: 0, // accel flags
125: 39721, // pixclock: 79442 -> 12.587 Mhz (NOT USED)
126: // 70616 -> 14.161
127: // 39721 -> 25.175
128: // 35308 -> 28.322
129:
130: 48, 16, 39, 8, // margins left,right,upper,lower
131: 96, // hsync length
132: 2, // vsync length
133: 0, // sync polarity
134: 0, // non interlaced, single mode
135: {0,0,0,0,0,0} // compatibility
136: };
137:
138: // ALPHA-MODE
139: // Hard coded to BIOS VGA mode 3 (alpha color text)
140: // screen size settable in screeninfo structure
141:
142: static int vga_decode_var(const struct screeninfo *var,
143: struct vga_par *par)
144: {
145: u8 VgaAttributeTable[16] =
146: { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x014, 0x007, 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x03F};
147:
148: u32 xres, right, hslen, left, xtotal;
149: u32 yres, lower, vslen, upper, ytotal;
150: u32 vxres, xoffset, vyres, yoffset;
151: u32 pos;
152: u8 r7, rMode;
153: int i;
154:
155: xres = (var->xres + 7) & ~7;
156: vxres = (var->xres_virtual + 0xF) & ~0xF;
157: xoffset = (var->xoffset + 7) & ~7;
158: left = (var->left_margin + 7) & ~7;
159: right = (var->right_margin + 7) & ~7;
160: hslen = (var->hsync_len + 7) & ~7;
161:
162: if (vxres < xres)
163: vxres = xres;
164: if (xres + xoffset > vxres)
165: xoffset = vxres - xres;
166:
167: xres >>= 3;
168: right >>= 3;
169: hslen >>= 3;
170: left >>= 3;
171: vxres >>= 3;
172: xtotal = xres + right + hslen + left;
173: if (xtotal >= 256)
174: return VERROR; //xtotal too big
175: if (hslen > 32)
176: return VERROR; //hslen too big
177: if (right + hslen + left > 64)
178: return VERROR; //hblank too big
179: par->crtc[CRTC_H_TOTAL] = xtotal - 5;
180: par->crtc[CRTC_H_BLANK_START] = xres - 1;
181: par->crtc[CRTC_H_DISP] = xres - 1;
182: pos = xres + right;
183: par->crtc[CRTC_H_SYNC_START] = pos;
184: pos += hslen;
185: par->crtc[CRTC_H_SYNC_END] = (pos & 0x1F) | 0x20 ; //<--- stpc text mode p178
186: pos += left - 2; /* blank_end + 2 <= total + 5 */
187: par->crtc[CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
188: if (pos & 0x20)
189: par->crtc[CRTC_H_SYNC_END] |= 0x80;
190:
191: yres = var->yres;
192: lower = var->lower_margin;
193: vslen = var->vsync_len;
194: upper = var->upper_margin;
195: vyres = var->yres_virtual;
196: yoffset = var->yoffset;
197:
198: if (yres > vyres)
199: vyres = yres;
200: if (vxres * vyres > 65536) {
201: vyres = 65536 / vxres;
202: if (vyres < yres)
203: return VERROR; // out of memory
204: }
205: if (yoffset + yres > vyres)
206: yoffset = vyres - yres;
207:
208: if (var->vmode & VMODE_DOUBLE) {
209: yres <<= 1;
210: lower <<= 1;
211: vslen <<= 1;
212: upper <<= 1;
213: }
214: ytotal = yres + lower + vslen + upper;
215: if (ytotal > 1024) {
216: ytotal >>= 1;
217: yres >>= 1;
218: lower >>= 1;
219: vslen >>= 1;
220: upper >>= 1;
221: rMode = 0x04;
222: } else
223: rMode = 0x00;
224: if (ytotal > 1024)
225: return VERROR; //ytotal too big
226: if (vslen > 16)
227: return VERROR; //vslen too big
228: par->crtc[CRTC_V_TOTAL] = ytotal - 2;
229: r7 = 0x10; /* disable linecompare */
230: if (ytotal & 0x100) r7 |= 0x01;
231: if (ytotal & 0x200) r7 |= 0x20;
232: par->crtc[CRTC_PRESET_ROW] = 0;
233:
234:
235: // GMODE <--> ALPHA-MODE
236: // default using alpha mode so we need to set char rows= CHAR_HEIGHT-1
237: par->crtc[CRTC_MAX_SCAN] = 0x40 | (CHAR_HEIGHT-1); /* 16 scanlines, linecmp max*/
238:
239: if (var->vmode & VMODE_DOUBLE)
240: par->crtc[CRTC_MAX_SCAN] |= 0x80;
241: par->crtc[CRTC_CURSOR_START] = 0x00; // curs enabled, start line = 0
242: par->crtc[CRTC_CURSOR_END] = CHAR_HEIGHT-1; // end line = 12
243: pos = yoffset * vxres + (xoffset >> 3);
244: par->crtc[CRTC_START_HI] = pos >> 8;
245: par->crtc[CRTC_START_LO] = pos & 0xFF;
246: par->crtc[CRTC_CURSOR_HI] = 0x00;
247: par->crtc[CRTC_CURSOR_LO] = 0x00;
248: pos = yres - 1;
249: par->crtc[CRTC_V_DISP_END] = pos & 0xFF;
250: par->crtc[CRTC_V_BLANK_START] = pos & 0xFF;
251: if (pos & 0x100)
252: r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
253: if (pos & 0x200) {
254: r7 |= 0x40; /* 0x40 -> DISP_END */
255: par->crtc[CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
256: }
257: pos += lower;
258: par->crtc[CRTC_V_SYNC_START] = pos & 0xFF;
259: if (pos & 0x100)
260: r7 |= 0x04;
261: if (pos & 0x200)
262: r7 |= 0x80;
263: pos += vslen;
264: par->crtc[CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled reg write prot, IRQ */
265: pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
266: par->crtc[CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
267: but some SVGA chips requires all 8 bits to set */
268: if (vxres >= 512)
269: return VERROR; //vxres too long
270: par->crtc[CRTC_OFFSET] = vxres >> 1;
271:
272: // put the underline off of the character, necessary in alpha color mode
273: par->crtc[CRTC_UNDERLINE] = 0x1f;
274:
275: par->crtc[CRTC_MODE] = rMode | 0xA3; // word mode
276: par->crtc[CRTC_LINE_COMPARE] = 0xFF;
277: par->crtc[CRTC_OVERFLOW] = r7;
278:
279:
280: // not used ??
281: par->vss = 0x00; /* 3DA */
282:
283: for (i = 0x00; i < 0x10; i++) {
284: par->atc[i] = VgaAttributeTable[i];
285: }
286: // GMODE <--> ALPHA-MODE
287: par->atc[ATC_MODE] = 0x0c; // text mode
288:
289: par->atc[ATC_OVERSCAN] = 0x00; // no border
290: par->atc[ATC_PLANE_ENABLE] = 0x0F;
291: par->atc[ATC_PEL] = xoffset & 7;
292: par->atc[ATC_COLOR_PAGE] = 0x00;
293:
294: par->misc = 0x67; /* enable CPU, ports 0x3Dx, positive sync*/
295: if (var->sync & SYNC_HOR_HIGH_ACT)
296: par->misc &= ~0x40;
297: if (var->sync & SYNC_VERT_HIGH_ACT)
298: par->misc &= ~0x80;
299:
300: par->seq[SEQ_CLOCK_MODE] = 0x01; //8-bit char; 0x01=alpha mode
301: par->seq[SEQ_PLANE_WRITE] = 0x03; // just char/attr plane
302: par->seq[SEQ_CHARACTER_MAP] = 0x00;
303: par->seq[SEQ_MEMORY_MODE] = 0x02; // A/G bit not used in stpc; O/E on, C4 off
304:
305: par->gdc[GDC_SR_VALUE] = 0x00;
306: // bits set in the SR_EN regs will enable set/reset action
307: // based on the bit settings in the SR_VAL register
308: par->gdc[GDC_SR_ENABLE] = 0x00;
309: par->gdc[GDC_COMPARE_VALUE] = 0x00;
310: par->gdc[GDC_DATA_ROTATE] = 0x00;
311: par->gdc[GDC_PLANE_READ] = 0;
312: par->gdc[GDC_MODE] = 0x10; //Okay
313:
314: // GMODE <--> ALPHA-MMODE
315: par->gdc[GDC_MISC] = 0x0e; // b0=0 ->alpha mode; memory at 0xb8000
316:
317: par->gdc[GDC_COMPARE_MASK] = 0x00;
318: par->gdc[GDC_BIT_MASK] = 0xFF;
319:
320: return 0;
321: }
322:
323: //
324: // originally from the stpc web site
325: //
326: static const unsigned char VgaLookupTable[3 * 0x3f + 3] = {
327: // Red Green Blue
328: 0x000, 0x000, 0x000, // 00h
329: 0x000, 0x000, 0x02A, // 01h
330: 0x000, 0x02A, 0x000, // 02h
331: 0x000, 0x02A, 0x02A, // 03h
332: 0x02A, 0x000, 0x000, // 04h
333: 0x02A, 0x000, 0x02A, // 05h
334: 0x02A, 0x02A, 0x000, // 06h
335: 0x02A, 0x02A, 0x02A, // 07h
336: 0x000, 0x000, 0x015, // 08h
337: 0x000, 0x000, 0x03F, // 09h
338: 0x000, 0x02A, 0x015, // 0Ah
339: 0x000, 0x02A, 0x03F, // 0Bh
340: 0x02A, 0x000, 0x015, // 0Ch
341: 0x02A, 0x000, 0x03F, // 0Dh
342: 0x02A, 0x02A, 0x015, // 0Eh
343: 0x02A, 0x02A, 0x03F, // 0Fh
344: 0x000, 0x015, 0x000, // 10h
345: 0x000, 0x015, 0x02A, // 11h
346: 0x000, 0x03F, 0x000, // 12h
347: 0x000, 0x03F, 0x02A, // 13h
348: 0x02A, 0x015, 0x000, // 14h
349: 0x02A, 0x015, 0x02A, // 15h
350: 0x02A, 0x03F, 0x000, // 16h
351: 0x02A, 0x03F, 0x02A, // 17h
352: 0x000, 0x015, 0x015, // 18h
353: 0x000, 0x015, 0x03F, // 19h
354: 0x000, 0x03F, 0x015, // 1Ah
355: 0x000, 0x03F, 0x03F, // 1Bh
356: 0x02A, 0x015, 0x015, // 1Ch
357: 0x02A, 0x015, 0x03F, // 1Dh
358: 0x02A, 0x03F, 0x015, // 1Eh
359: 0x02A, 0x03F, 0x03F, // 1Fh
360: 0x015, 0x000, 0x000, // 20h
361: 0x015, 0x000, 0x02A, // 21h
362: 0x015, 0x02A, 0x000, // 22h
363: 0x015, 0x02A, 0x02A, // 23h
364: 0x03F, 0x000, 0x000, // 24h
365: 0x03F, 0x000, 0x02A, // 25h
366: 0x03F, 0x02A, 0x000, // 26h
367: 0x03F, 0x02A, 0x02A, // 27h
368: 0x015, 0x000, 0x015, // 28h
369: 0x015, 0x000, 0x03F, // 29h
370: 0x015, 0x02A, 0x015, // 2Ah
371: 0x015, 0x02A, 0x03F, // 2Bh
372: 0x03F, 0x000, 0x015, // 2Ch
373: 0x03F, 0x000, 0x03F, // 2Dh
374: 0x03F, 0x02A, 0x015, // 2Eh
375: 0x03F, 0x02A, 0x03F, // 2Fh
376: 0x015, 0x015, 0x000, // 30h
377: 0x015, 0x015, 0x02A, // 31h
378: 0x015, 0x03F, 0x000, // 32h
379: 0x015, 0x03F, 0x02A, // 33h
380: 0x03F, 0x015, 0x000, // 34h
381: 0x03F, 0x015, 0x02A, // 35h
382: 0x03F, 0x03F, 0x000, // 36h
383: 0x03F, 0x03F, 0x02A, // 37h
384: 0x015, 0x015, 0x015, // 38h
385: 0x015, 0x015, 0x03F, // 39h
386: 0x015, 0x03F, 0x015, // 3Ah
387: 0x015, 0x03F, 0x03F, // 3Bh
388: 0x03F, 0x015, 0x015, // 3Ch
389: 0x03F, 0x015, 0x03F, // 3Dh
390: 0x03F, 0x03F, 0x015, // 3Eh
391: 0x03F, 0x03F, 0x03F, // 3Fh
392: };
393:
394: /*
395: * From the Linux kernel.
396: * orig by Ben Pfaff and Petr Vandrovec.
397: * see the note in the vga.h for attribution.
398: *
399: * modified by
400: * Steve M. Gehlbach <[email protected]>
401: * for the linuxbios project
402: *
403: * Write the data in the vga parameter structure
404: * to the vga registers, along with other default
405: * settings.
406: *
407: */
408: static int vga_set_regs(const struct vga_par *par)
409: {
410: int i;
411:
412: /* update misc output register */
413: outb(par->misc, MIS_W);
414:
415: /* synchronous reset on */
416: outb(0x00, SEQ_I);
417: outb(0x00, SEQ_D);
418:
419: /* write sequencer registers */
420: outb(1, SEQ_I);
421: outb(par->seq[1] | 0x20, SEQ_D); // blank display
422: for (i = 2; i < SEQ_C; i++) {
423: outb(i, SEQ_I);
424: outb(par->seq[i], SEQ_D);
425: }
426:
427: /* synchronous reset off */
428: outb(0x00, SEQ_I);
429: outb(0x03, SEQ_D);
430:
431: /* deprotect CRT registers 0-7 */
432: outb(0x11, CRT_IC);
433: outb(par->crtc[0x11], CRT_DC);
434:
435: /* write CRT registers */
436: for (i = 0; i < CRTC_C; i++) {
437: outb(i, CRT_IC);
438: outb(par->crtc[i], CRT_DC);
439: }
440: /* write graphics controller registers */
441: for (i = 0; i < GRA_C; i++) {
442: outb(i, GRA_I);
443: outb(par->gdc[i], GRA_D);
444: }
445:
446: /* write attribute controller registers */
447: for (i = 0; i < ATT_C; i++) {
448: inb(IS1_RC); /* reset flip-flop */
449: inb(0x80); //delay
450: outb(i, ATT_IW);
451: inb(0x80); //delay
452:
453: outb(par->atc[i], ATT_IW);
454: inb(0x80); //delay
455: }
456:
457: // initialize the color table
458: outb(0, PEL_IW);
459: i = 0;
460: // length is a magic number right now
461: while ( i < (0x3f*3 + 3) ) {
462: outb(VgaLookupTable[i++], PEL_D);
463: outb(VgaLookupTable[i++], PEL_D);
464: outb(VgaLookupTable[i++], PEL_D);
465: }
466:
467: outb(0x0ff, PEL_MSK); // palette mask
468:
469: // very important
470: // turn on video, disable palette access
471: inb(IS1_RC); /* reset flip-flop */
472: inb(0x80); //delay
473: outb(0x20, ATT_IW);
474:
475: /* Wait for screen to stabilize. */
476: //for(i=0;i<1000;i++) { inb(0x80); }
477:
478: outb(0x01, SEQ_I); // unblank display
479: outb(par->seq[1], SEQ_D);
480:
481: // turn on display, disable access to attr palette
482: inb(IS1_RC);
483: outb(0x20, ATT_IW);
484:
485: return 0;
486: }
487:
488: void
489: vga_load_regs(void)
490: {
491: struct vga_par par;
492:
493: if (vga_decode_var(&vga_settings, &par) == 0) {
494: vga_set_regs(&par);
495: }
496: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.