Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / drivers / vga_load_regs.c
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 <steve@kesa.com>
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 <geert@linux-m68k.org>
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 <steve@kesa.com>
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 }