Implement new v3_memalloc romvec interface for allocating aligned memory.
[openbios.git] / drivers / vga_load_regs.c
blobdda6b798a66d08b48d1b599d7ad5aefcc7f63f95
1 #include "asm/io.h"
2 #include "drivers/vga.h"
3 #include "vga.h"
5 /*
6 * $Id$
7 * $Source$
9 * from the Linux kernel code base.
10 * orig by Ben Pfaff and Petr Vandrovec.
12 * modified by
13 * Steve M. Gehlbach <steve@kesa.com>
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.
20 * Convert the screeninfo structure to data for
21 * writing to the vga registers
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);
29 u8 read_seq_b(u16 addr) {
30 outb(addr,SEQ_I);
31 return inb(SEQ_D);
33 u8 read_gra_b(u16 addr) {
34 outb(addr,GRA_I);
35 return inb(GRA_D);
37 u8 read_crtc_b(u16 addr) {
38 outb(addr,CRT_IC);
39 return inb(CRT_DC);
41 u8 read_att_b(u16 addr) {
42 inb(IS1_RC);
43 inb(0x80);
44 outb(addr,ATT_IW);
45 return inb(ATT_R);
50 From: The Frame Buffer Device
51 by Geert Uytterhoeven <geert@linux-m68k.org>
52 in the linux kernel docs.
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.
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 +----------+---------------------------------------------+----------+-------+
94 All horizontal timings are in number of dotclocks
95 (in picoseconds, 1E-12 s), and vertical timings in number of scanlines.
97 The vga uses the following fields:
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
110 /* our display parameters per the above */
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
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
138 // ALPHA-MODE
139 // Hard coded to BIOS VGA mode 3 (alpha color text)
140 // screen size settable in screeninfo structure
142 static int vga_decode_var(const struct screeninfo *var,
143 struct vga_par *par)
145 u8 VgaAttributeTable[16] =
146 { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x014, 0x007, 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x03F};
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;
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;
162 if (vxres < xres)
163 vxres = xres;
164 if (xres + xoffset > vxres)
165 xoffset = vxres - xres;
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;
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;
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
205 if (yoffset + yres > vyres)
206 yoffset = vyres - yres;
208 if (var->vmode & VMODE_DOUBLE) {
209 yres <<= 1;
210 lower <<= 1;
211 vslen <<= 1;
212 upper <<= 1;
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;
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*/
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 */
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;
272 // put the underline off of the character, necessary in alpha color mode
273 par->crtc[CRTC_UNDERLINE] = 0x1f;
275 par->crtc[CRTC_MODE] = rMode | 0xA3; // word mode
276 par->crtc[CRTC_LINE_COMPARE] = 0xFF;
277 par->crtc[CRTC_OVERFLOW] = r7;
280 // not used ??
281 par->vss = 0x00; /* 3DA */
283 for (i = 0x00; i < 0x10; i++) {
284 par->atc[i] = VgaAttributeTable[i];
286 // GMODE <--> ALPHA-MODE
287 par->atc[ATC_MODE] = 0x0c; // text mode
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;
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;
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
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
314 // GMODE <--> ALPHA-MMODE
315 par->gdc[GDC_MISC] = 0x0e; // b0=0 ->alpha mode; memory at 0xb8000
317 par->gdc[GDC_COMPARE_MASK] = 0x00;
318 par->gdc[GDC_BIT_MASK] = 0xFF;
320 return 0;
324 // originally from the stpc web site
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
395 * From the Linux kernel.
396 * orig by Ben Pfaff and Petr Vandrovec.
397 * see the note in the vga.h for attribution.
399 * modified by
400 * Steve M. Gehlbach <steve@kesa.com>
401 * for the linuxbios project
403 * Write the data in the vga parameter structure
404 * to the vga registers, along with other default
405 * settings.
408 static int vga_set_regs(const struct vga_par *par)
410 int i;
412 /* update misc output register */
413 outb(par->misc, MIS_W);
415 /* synchronous reset on */
416 outb(0x00, SEQ_I);
417 outb(0x00, SEQ_D);
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);
427 /* synchronous reset off */
428 outb(0x00, SEQ_I);
429 outb(0x03, SEQ_D);
431 /* deprotect CRT registers 0-7 */
432 outb(0x11, CRT_IC);
433 outb(par->crtc[0x11], CRT_DC);
435 /* write CRT registers */
436 for (i = 0; i < CRTC_C; i++) {
437 outb(i, CRT_IC);
438 outb(par->crtc[i], CRT_DC);
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);
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
453 outb(par->atc[i], ATT_IW);
454 inb(0x80); //delay
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);
467 outb(0x0ff, PEL_MSK); // palette mask
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);
475 /* Wait for screen to stabilize. */
476 //for(i=0;i<1000;i++) { inb(0x80); }
478 outb(0x01, SEQ_I); // unblank display
479 outb(par->seq[1], SEQ_D);
481 // turn on display, disable access to attr palette
482 inb(IS1_RC);
483 outb(0x20, ATT_IW);
485 return 0;
488 void
489 vga_load_regs(void)
491 struct vga_par par;
493 if (vga_decode_var(&vga_settings, &par) == 0) {
494 vga_set_regs(&par);