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