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