2 #include "drivers/vga.h"
9 * from the Linux kernel code base.
10 * orig by Ben Pfaff and Petr Vandrovec.
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
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
) {
33 u8
read_gra_b(u16 addr
) {
37 u8
read_crtc_b(u16 addr
) {
41 u8
read_att_b(u16 addr
) {
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
59 +----------+---------------------------------------------+----------+-------+
61 | | |upper_margin | | |
63 +----------###############################################----------+-------+
68 | left # | # right | hsync |
69 | margin # | xres # margin | len |
70 |<-------->#<---------------+--------------------------->#<-------->|<----->|
84 +----------###############################################----------+-------+
86 | | |lower_margin | | |
88 +----------+---------------------------------------------+----------+-------+
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*/
120 {0,0,0}, /* transparency */
121 0, /* standard pixel format */
123 -1,-1, // height and width in mm
125 39721, // pixclock: 79442 -> 12.587 Mhz (NOT USED)
130 48, 16, 39, 8, // margins left,right,upper,lower
134 0, // non interlaced, single mode
135 {0,0,0,0,0,0} // compatibility
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
,
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
;
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;
164 if (xres
+ xoffset
> vxres
)
165 xoffset
= vxres
- xres
;
172 xtotal
= xres
+ right
+ hslen
+ left
;
174 return VERROR
; //xtotal too big
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;
183 par
->crtc
[CRTC_H_SYNC_START
] = pos
;
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;
189 par
->crtc
[CRTC_H_SYNC_END
] |= 0x80;
192 lower
= var
->lower_margin
;
193 vslen
= var
->vsync_len
;
194 upper
= var
->upper_margin
;
195 vyres
= var
->yres_virtual
;
196 yoffset
= var
->yoffset
;
200 if (vxres
* vyres
> 65536) {
201 vyres
= 65536 / vxres
;
203 return VERROR
; // out of memory
205 if (yoffset
+ yres
> vyres
)
206 yoffset
= vyres
- yres
;
208 if (var
->vmode
& VMODE_DOUBLE
) {
214 ytotal
= yres
+ lower
+ vslen
+ upper
;
225 return VERROR
; //ytotal too big
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;
249 par
->crtc
[CRTC_V_DISP_END
] = pos
& 0xFF;
250 par
->crtc
[CRTC_V_BLANK_START
] = pos
& 0xFF;
252 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
254 r7
|= 0x40; /* 0x40 -> DISP_END */
255 par
->crtc
[CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
258 par
->crtc
[CRTC_V_SYNC_START
] = pos
& 0xFF;
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 */
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
;
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
)
297 if (var
->sync
& SYNC_VERT_HIGH_ACT
)
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;
324 // originally from the stpc web site
326 static const unsigned char VgaLookupTable
[3 * 0x3f + 3] = {
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.
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
408 static int vga_set_regs(const struct vga_par
*par
)
412 /* update misc output register */
413 outb(par
->misc
, MIS_W
);
415 /* synchronous reset on */
419 /* write sequencer registers */
421 outb(par
->seq
[1] | 0x20, SEQ_D
); // blank display
422 for (i
= 2; i
< SEQ_C
; i
++) {
424 outb(par
->seq
[i
], SEQ_D
);
427 /* synchronous reset off */
431 /* deprotect CRT registers 0-7 */
433 outb(par
->crtc
[0x11], CRT_DC
);
435 /* write CRT registers */
436 for (i
= 0; i
< CRTC_C
; i
++) {
438 outb(par
->crtc
[i
], CRT_DC
);
440 /* write graphics controller registers */
441 for (i
= 0; i
< GRA_C
; 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 */
453 outb(par
->atc
[i
], ATT_IW
);
457 // initialize the color table
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
470 // turn on video, disable palette access
471 inb(IS1_RC
); /* reset flip-flop */
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
493 if (vga_decode_var(&vga_settings
, &par
) == 0) {