Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / qemu-palcode / vgaio.c
1 // VGA io port access
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "protos.h"
9 #include "ioport.h"
10 #include "pci.h"
11 #include "pci_regs.h"
12 #include "pci_ids.h"
13 #include "vgatables.h"
14
15 #define GET_FARVAR(seg, ofs)            (ofs)
16 #define SET_FARVAR(seg, ofs, val)       ((ofs) = (val))
17
18 static struct saveBDAstate BDA;
19
20 #define GET_BDA(field)                  (BDA.field)
21 #define GET_GLOBAL(val)                 (val)
22
23 // TODO
24 //  * replace direct in/out calls with wrapper functions
25
26
27 /****************************************************************
28  * Attribute control
29  ****************************************************************/
30
31 void
32 vgahw_screen_disable(void)
33 {
34     inb(VGAREG_ACTL_RESET);
35     outb(0x00, VGAREG_ACTL_ADDRESS);
36 }
37
38 void
39 vgahw_screen_enable(void)
40 {
41     inb(VGAREG_ACTL_RESET);
42     outb(0x20, VGAREG_ACTL_ADDRESS);
43 }
44
45 void
46 vgahw_set_border_color(u8 color)
47 {
48     inb(VGAREG_ACTL_RESET);
49     outb(0x00, VGAREG_ACTL_ADDRESS);
50     u8 v1 = color & 0x0f;
51     if (v1 & 0x08)
52         v1 += 0x08;
53     outb(v1, VGAREG_ACTL_WRITE_DATA);
54
55     u8 v2 = color & 0x10;
56     int i;
57     for (i = 1; i < 4; i++) {
58         outb(i, VGAREG_ACTL_ADDRESS);
59
60         u8 cur = inb(VGAREG_ACTL_READ_DATA);
61         cur &= 0xef;
62         cur |= v2;
63         outb(cur, VGAREG_ACTL_WRITE_DATA);
64     }
65     outb(0x20, VGAREG_ACTL_ADDRESS);
66 }
67
68 void
69 vgahw_set_overscan_border_color(u8 color)
70 {
71     inb(VGAREG_ACTL_RESET);
72     outb(0x11, VGAREG_ACTL_ADDRESS);
73     outb(color, VGAREG_ACTL_WRITE_DATA);
74     outb(0x20, VGAREG_ACTL_ADDRESS);
75 }
76
77 u8
78 vgahw_get_overscan_border_color(void)
79 {
80     inb(VGAREG_ACTL_RESET);
81     outb(0x11, VGAREG_ACTL_ADDRESS);
82     u8 v = inb(VGAREG_ACTL_READ_DATA);
83     inb(VGAREG_ACTL_RESET);
84     outb(0x20, VGAREG_ACTL_ADDRESS);
85     return v;
86 }
87
88 void
89 vgahw_set_palette(u8 palid)
90 {
91     inb(VGAREG_ACTL_RESET);
92     palid &= 0x01;
93     int i;
94     for (i = 1; i < 4; i++) {
95         outb(i, VGAREG_ACTL_ADDRESS);
96
97         u8 v = inb(VGAREG_ACTL_READ_DATA);
98         v &= 0xfe;
99         v |= palid;
100         outb(v, VGAREG_ACTL_WRITE_DATA);
101     }
102     outb(0x20, VGAREG_ACTL_ADDRESS);
103 }
104
105 void
106 vgahw_set_single_palette_reg(u8 reg, u8 val)
107 {
108     inb(VGAREG_ACTL_RESET);
109     outb(reg, VGAREG_ACTL_ADDRESS);
110     outb(val, VGAREG_ACTL_WRITE_DATA);
111     outb(0x20, VGAREG_ACTL_ADDRESS);
112 }
113
114 u8
115 vgahw_get_single_palette_reg(u8 reg)
116 {
117     inb(VGAREG_ACTL_RESET);
118     outb(reg, VGAREG_ACTL_ADDRESS);
119     u8 v = inb(VGAREG_ACTL_READ_DATA);
120     inb(VGAREG_ACTL_RESET);
121     outb(0x20, VGAREG_ACTL_ADDRESS);
122     return v;
123 }
124
125 void
126 vgahw_set_all_palette_reg(u8 *data_far)
127 {
128     inb(VGAREG_ACTL_RESET);
129     int i;
130     for (i = 0; i < 0x10; i++) {
131         outb(i, VGAREG_ACTL_ADDRESS);
132         u8 val = GET_FARVAR(seg, *data_far);
133         outb(val, VGAREG_ACTL_WRITE_DATA);
134         data_far++;
135     }
136     outb(0x11, VGAREG_ACTL_ADDRESS);
137     outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
138     outb(0x20, VGAREG_ACTL_ADDRESS);
139 }
140
141 void
142 vgahw_get_all_palette_reg(u8 *data_far)
143 {
144     int i;
145     for (i = 0; i < 0x10; i++) {
146         inb(VGAREG_ACTL_RESET);
147         outb(i, VGAREG_ACTL_ADDRESS);
148         SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
149         data_far++;
150     }
151     inb(VGAREG_ACTL_RESET);
152     outb(0x11, VGAREG_ACTL_ADDRESS);
153     SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
154     inb(VGAREG_ACTL_RESET);
155     outb(0x20, VGAREG_ACTL_ADDRESS);
156 }
157
158 void
159 vgahw_toggle_intensity(u8 flag)
160 {
161     inb(VGAREG_ACTL_RESET);
162     outb(0x10, VGAREG_ACTL_ADDRESS);
163     u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
164     outb(val, VGAREG_ACTL_WRITE_DATA);
165     outb(0x20, VGAREG_ACTL_ADDRESS);
166 }
167
168 void
169 vgahw_select_video_dac_color_page(u8 flag, u8 data)
170 {
171     inb(VGAREG_ACTL_RESET);
172     outb(0x10, VGAREG_ACTL_ADDRESS);
173     u8 val = inb(VGAREG_ACTL_READ_DATA);
174     if (!(flag & 0x01)) {
175         // select paging mode
176         val = (val & 0x7f) | (data << 7);
177         outb(val, VGAREG_ACTL_WRITE_DATA);
178         outb(0x20, VGAREG_ACTL_ADDRESS);
179         return;
180     }
181     // select page
182     inb(VGAREG_ACTL_RESET);
183     outb(0x14, VGAREG_ACTL_ADDRESS);
184     if (!(val & 0x80))
185         data <<= 2;
186     data &= 0x0f;
187     outb(data, VGAREG_ACTL_WRITE_DATA);
188     outb(0x20, VGAREG_ACTL_ADDRESS);
189 }
190
191 void
192 vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
193 {
194     inb(VGAREG_ACTL_RESET);
195     outb(0x10, VGAREG_ACTL_ADDRESS);
196     u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
197
198     inb(VGAREG_ACTL_RESET);
199     outb(0x14, VGAREG_ACTL_ADDRESS);
200     u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
201     if (!(val1 & 0x01))
202         val2 >>= 2;
203
204     inb(VGAREG_ACTL_RESET);
205     outb(0x20, VGAREG_ACTL_ADDRESS);
206
207     *pmode = val1;
208     *curpage = val2;
209 }
210
211
212 /****************************************************************
213  * DAC control
214  ****************************************************************/
215
216 void
217 vgahw_set_dac_regs(u8 *data_far, u8 start, int count)
218 {
219     outb(start, VGAREG_DAC_WRITE_ADDRESS);
220     while (count) {
221         outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
222         data_far++;
223         outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
224         data_far++;
225         outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
226         data_far++;
227         count--;
228     }
229 }
230
231 void
232 vgahw_get_dac_regs(u8 *data_far, u8 start, int count)
233 {
234     outb(start, VGAREG_DAC_READ_ADDRESS);
235     while (count) {
236         SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
237         data_far++;
238         SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
239         data_far++;
240         SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
241         data_far++;
242         count--;
243     }
244 }
245
246 void
247 vgahw_set_pel_mask(u8 val)
248 {
249     outb(val, VGAREG_PEL_MASK);
250 }
251
252 u8
253 vgahw_get_pel_mask(void)
254 {
255     return inb(VGAREG_PEL_MASK);
256 }
257
258 void
259 vgahw_save_dac_state(struct saveDACcolors *info)
260 {
261     /* XXX: check this */
262     SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
263     SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
264     SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
265     vgahw_get_dac_regs(info->dac, 0, 256);
266     SET_FARVAR(seg, info->color_select, 0);
267 }
268
269 void
270 vgahw_restore_dac_state(struct saveDACcolors *info)
271 {
272     outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
273     vgahw_set_dac_regs(info->dac, 0, 256);
274     outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
275 }
276
277
278 /****************************************************************
279  * Memory control
280  ****************************************************************/
281
282 void
283 vgahw_sequ_write(u8 index, u8 value)
284 {
285     outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
286 }
287
288 void
289 vgahw_grdc_write(u8 index, u8 value)
290 {
291     outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
292 }
293
294 void
295 vgahw_set_text_block_specifier(u8 spec)
296 {
297     outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
298 }
299
300 void
301 get_font_access(void)
302 {
303     outw(0x0100, VGAREG_SEQU_ADDRESS);
304     outw(0x0402, VGAREG_SEQU_ADDRESS);
305     outw(0x0704, VGAREG_SEQU_ADDRESS);
306     outw(0x0300, VGAREG_SEQU_ADDRESS);
307     outw(0x0204, VGAREG_GRDC_ADDRESS);
308     outw(0x0005, VGAREG_GRDC_ADDRESS);
309     outw(0x0406, VGAREG_GRDC_ADDRESS);
310 }
311
312 void
313 release_font_access(void)
314 {
315     outw(0x0100, VGAREG_SEQU_ADDRESS);
316     outw(0x0302, VGAREG_SEQU_ADDRESS);
317     outw(0x0304, VGAREG_SEQU_ADDRESS);
318     outw(0x0300, VGAREG_SEQU_ADDRESS);
319     u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
320     outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
321     outw(0x0004, VGAREG_GRDC_ADDRESS);
322     outw(0x1005, VGAREG_GRDC_ADDRESS);
323 }
324
325
326 /****************************************************************
327  * CRTC registers
328  ****************************************************************/
329
330 static u16
331 get_crtc(void)
332 {
333     return GET_BDA(crtc_address);
334 }
335
336 void
337 vgahw_set_cursor_shape(u8 start, u8 end)
338 {
339     u16 crtc_addr = get_crtc();
340     outb(0x0a, crtc_addr);
341     outb(start, crtc_addr + 1);
342     outb(0x0b, crtc_addr);
343     outb(end, crtc_addr + 1);
344 }
345
346 void
347 vgahw_set_active_page(u16 address)
348 {
349     u16 crtc_addr = get_crtc();
350     outb(0x0c, crtc_addr);
351     outb((address & 0xff00) >> 8, crtc_addr + 1);
352     outb(0x0d, crtc_addr);
353     outb(address & 0x00ff, crtc_addr + 1);
354 }
355
356 void
357 vgahw_set_cursor_pos(u16 address)
358 {
359     u16 crtc_addr = get_crtc();
360     outb(0x0e, crtc_addr);
361     outb((address & 0xff00) >> 8, crtc_addr + 1);
362     outb(0x0f, crtc_addr);
363     outb(address & 0x00ff, crtc_addr + 1);
364 }
365
366 void
367 vgahw_set_scan_lines(u8 lines)
368 {
369     u16 crtc_addr = get_crtc();
370     outb(0x09, crtc_addr);
371     u8 crtc_r9 = inb(crtc_addr + 1);
372     crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
373     outb(crtc_r9, crtc_addr + 1);
374 }
375
376 // Get vertical display end
377 u16
378 vgahw_get_vde(void)
379 {
380     u16 crtc_addr = get_crtc();
381     outb(0x12, crtc_addr);
382     u16 vde = inb(crtc_addr + 1);
383     outb(0x07, crtc_addr);
384     u8 ovl = inb(crtc_addr + 1);
385     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
386     return vde;
387 }
388
389
390 /****************************************************************
391  * Save/Restore/Set state
392  ****************************************************************/
393
394 void
395 vgahw_save_state(struct saveVideoHardware *info)
396 {
397     u16 crtc_addr = get_crtc();
398     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
399     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
400     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
401     inb(VGAREG_ACTL_RESET);
402     u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
403     SET_FARVAR(seg, info->actl_index, ar_index);
404     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
405
406     u16 i;
407     for (i=0; i<4; i++) {
408         outb(i+1, VGAREG_SEQU_ADDRESS);
409         SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
410     }
411     outb(0, VGAREG_SEQU_ADDRESS);
412     SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
413
414     for (i=0; i<25; i++) {
415         outb(i, crtc_addr);
416         SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
417     }
418
419     for (i=0; i<20; i++) {
420         inb(VGAREG_ACTL_RESET);
421         outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
422         SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
423     }
424     inb(VGAREG_ACTL_RESET);
425
426     for (i=0; i<9; i++) {
427         outb(i, VGAREG_GRDC_ADDRESS);
428         SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
429     }
430
431     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
432
433     /* XXX: read plane latches */
434     for (i=0; i<4; i++)
435         SET_FARVAR(seg, info->plane_latch[i], 0);
436 }
437
438 void
439 vgahw_restore_state(struct saveVideoHardware *info)
440 {
441     // Reset Attribute Ctl flip-flop
442     inb(VGAREG_ACTL_RESET);
443
444     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
445
446     u16 i;
447     for (i=0; i<4; i++) {
448         outb(i+1, VGAREG_SEQU_ADDRESS);
449         outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
450     }
451     outb(0, VGAREG_SEQU_ADDRESS);
452     outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
453
454     // Disable CRTC write protection
455     outw(0x0011, crtc_addr);
456     // Set CRTC regs
457     for (i=0; i<25; i++)
458         if (i != 0x11) {
459             outb(i, crtc_addr);
460             outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
461         }
462     // select crtc base address
463     u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
464     if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
465         v |= 0x01;
466     outb(v, VGAREG_WRITE_MISC_OUTPUT);
467
468     // enable write protection if needed
469     outb(0x11, crtc_addr);
470     outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
471
472     // Set Attribute Ctl
473     u16 ar_index = GET_FARVAR(seg, info->actl_index);
474     inb(VGAREG_ACTL_RESET);
475     for (i=0; i<20; i++) {
476         outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
477         outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
478     }
479     outb(ar_index, VGAREG_ACTL_ADDRESS);
480     inb(VGAREG_ACTL_RESET);
481
482     for (i=0; i<9; i++) {
483         outb(i, VGAREG_GRDC_ADDRESS);
484         outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
485     }
486
487     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
488     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
489     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
490     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
491 }
492
493 void
494 vgahw_set_mode(struct VideoParam_s *vparam_g)
495 {
496     // Reset Attribute Ctl flip-flop
497     inb(VGAREG_ACTL_RESET);
498
499     // Set Attribute Ctl
500     u16 i;
501     for (i = 0; i <= 0x13; i++) {
502         outb(i, VGAREG_ACTL_ADDRESS);
503         outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
504     }
505     outb(0x14, VGAREG_ACTL_ADDRESS);
506     outb(0x00, VGAREG_ACTL_WRITE_DATA);
507
508     // Set Sequencer Ctl
509     outb(0, VGAREG_SEQU_ADDRESS);
510     outb(0x03, VGAREG_SEQU_DATA);
511     for (i = 1; i <= 4; i++) {
512         outb(i, VGAREG_SEQU_ADDRESS);
513         outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
514     }
515
516     // Set Grafx Ctl
517     for (i = 0; i <= 8; i++) {
518         outb(i, VGAREG_GRDC_ADDRESS);
519         outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
520     }
521
522     // Set CRTC address VGA or MDA
523     u8 miscreg = GET_GLOBAL(vparam_g->miscreg);
524     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
525     if (!(miscreg & 1))
526         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
527
528     // Disable CRTC write protection
529     outw(0x0011, crtc_addr);
530     // Set CRTC regs
531     for (i = 0; i <= 0x18; i++) {
532         outb(i, crtc_addr);
533         outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
534     }
535
536     // Set the misc register
537     outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
538
539     // Enable video
540     outb(0x20, VGAREG_ACTL_ADDRESS);
541     inb(VGAREG_ACTL_RESET);
542 }
543
544
545 /****************************************************************
546  * Misc
547  ****************************************************************/
548
549 void
550 vgahw_enable_video_addressing(u8 disable)
551 {
552     u8 v = (disable & 1) ? 0x00 : 0x02;
553     u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
554     outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
555 }
556
557 void
558 vgahw_init(void)
559 {
560   struct vgamode_s *vmode_g;
561   int bdf, max;
562
563   foreachpci(bdf, max)
564     {
565       uint16_t class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
566       if (class == PCI_CLASS_DISPLAY_VGA)
567         goto found;
568     }
569   return;
570
571  found:
572   have_vga = 1;
573
574   vmode_g = find_vga_entry(3);
575
576   vgahw_sequ_write(0, 1);       // Assert sync reset
577   
578   // Switch to color mode and enable CPU access 480 lines
579   outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
580
581   vgahw_sequ_write(0, 3);       // De-assert sync reset
582
583   vgahw_set_mode(vmode_g->vparam);
584
585   vgahw_sequ_write(4, 0x06); // disable odd/even + chain4
586   vgahw_sequ_write(1, vmode_g->vparam->sequ_regs[1] | 0x20); // disable video
587   vgahw_grdc_write(5, vmode_g->vparam->grdc_regs[5] & 0xef); // disable odd/even
588   vgahw_grdc_write(6, 0x05); // set mem map to 0xa0000 and graphics mode
589   vgahw_sequ_write(2, 0x04); // enable write plane 2
590
591   {
592     unsigned char *font_ptr = pci_mem_base + SEG_GRAPH*16;
593     int i;
594
595     for (i = 0; i < 0x100; i++)
596       __builtin_memcpy(font_ptr + i*32, vgafont16 + i*16, 16);
597   }
598
599   {
600     int i = vmode_g->dacsize / 3;
601     vgahw_set_dac_regs(vmode_g->dac, 0, i);
602   }
603
604   vgahw_sequ_write(4, 0x2); // enable odd/even
605   vgahw_set_mode(vmode_g->vparam);
606 }