vgabios: Introduce stdvga_get_crtc() and use it consistently.
[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" // stdvga_init
9 #include "ioport.h" // outb
10 #include "farptr.h" // SET_FARVAR
11 #include "biosvar.h" // GET_GLOBAL
12 #include "util.h" // memcpy_far
13
14 // TODO
15 //  * replace direct in/out calls with wrapper functions
16
17
18 /****************************************************************
19  * Attribute control
20  ****************************************************************/
21
22 void
23 stdvga_screen_disable(void)
24 {
25     inb(VGAREG_ACTL_RESET);
26     outb(0x00, VGAREG_ACTL_ADDRESS);
27 }
28
29 void
30 stdvga_screen_enable(void)
31 {
32     inb(VGAREG_ACTL_RESET);
33     outb(0x20, VGAREG_ACTL_ADDRESS);
34 }
35
36 void
37 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_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 stdvga_set_pel_mask(u8 val)
239 {
240     outb(val, VGAREG_PEL_MASK);
241 }
242
243 u8
244 stdvga_get_pel_mask(void)
245 {
246     return inb(VGAREG_PEL_MASK);
247 }
248
249 void
250 stdvga_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     stdvga_get_dac_regs(seg, info->dac, 0, 256);
257     SET_FARVAR(seg, info->color_select, 0);
258 }
259
260 void
261 stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
262 {
263     outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
264     stdvga_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 stdvga_sequ_write(u8 index, u8 value)
275 {
276     outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
277 }
278
279 void
280 stdvga_grdc_write(u8 index, u8 value)
281 {
282     outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
283 }
284
285 void
286 stdvga_set_text_block_specifier(u8 spec)
287 {
288     outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
289 }
290
291
292 /****************************************************************
293  * Font loading
294  ****************************************************************/
295
296 static void
297 get_font_access(void)
298 {
299     outw(0x0100, VGAREG_SEQU_ADDRESS);
300     outw(0x0402, VGAREG_SEQU_ADDRESS);
301     outw(0x0704, VGAREG_SEQU_ADDRESS);
302     outw(0x0300, VGAREG_SEQU_ADDRESS);
303     outw(0x0204, VGAREG_GRDC_ADDRESS);
304     outw(0x0005, VGAREG_GRDC_ADDRESS);
305     outw(0x0406, VGAREG_GRDC_ADDRESS);
306 }
307
308 static void
309 release_font_access(void)
310 {
311     outw(0x0100, VGAREG_SEQU_ADDRESS);
312     outw(0x0302, VGAREG_SEQU_ADDRESS);
313     outw(0x0304, VGAREG_SEQU_ADDRESS);
314     outw(0x0300, VGAREG_SEQU_ADDRESS);
315     u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
316     outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
317     outw(0x0004, VGAREG_GRDC_ADDRESS);
318     outw(0x1005, VGAREG_GRDC_ADDRESS);
319 }
320
321 void
322 stdvga_load_font(u16 seg, void *src_far, u16 count
323                  , u16 start, u8 destflags, u8 fontsize)
324 {
325     get_font_access();
326     u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
327     void *dest_far = (void*)(blockaddr + start*32);
328     u16 i;
329     for (i = 0; i < count; i++)
330         memcpy_far(SEG_GRAPH, dest_far + i*32
331                    , seg, src_far + i*fontsize, fontsize);
332     release_font_access();
333 }
334
335
336 /****************************************************************
337  * CRTC registers
338  ****************************************************************/
339
340 u16
341 stdvga_get_crtc(void)
342 {
343     if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
344         return VGAREG_VGA_CRTC_ADDRESS;
345     return VGAREG_MDA_CRTC_ADDRESS;
346 }
347
348 void
349 stdvga_set_cursor_shape(u8 start, u8 end)
350 {
351     u16 crtc_addr = stdvga_get_crtc();
352     outb(0x0a, crtc_addr);
353     outb(start, crtc_addr + 1);
354     outb(0x0b, crtc_addr);
355     outb(end, crtc_addr + 1);
356 }
357
358 void
359 stdvga_set_active_page(u16 address)
360 {
361     u16 crtc_addr = stdvga_get_crtc();
362     outb(0x0c, crtc_addr);
363     outb((address & 0xff00) >> 8, crtc_addr + 1);
364     outb(0x0d, crtc_addr);
365     outb(address & 0x00ff, crtc_addr + 1);
366 }
367
368 void
369 stdvga_set_cursor_pos(u16 address)
370 {
371     u16 crtc_addr = stdvga_get_crtc();
372     outb(0x0e, crtc_addr);
373     outb((address & 0xff00) >> 8, crtc_addr + 1);
374     outb(0x0f, crtc_addr);
375     outb(address & 0x00ff, crtc_addr + 1);
376 }
377
378 void
379 stdvga_set_scan_lines(u8 lines)
380 {
381     u16 crtc_addr = stdvga_get_crtc();
382     outb(0x09, crtc_addr);
383     u8 crtc_r9 = inb(crtc_addr + 1);
384     crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
385     outb(crtc_r9, crtc_addr + 1);
386 }
387
388 // Get vertical display end
389 u16
390 stdvga_get_vde(void)
391 {
392     u16 crtc_addr = stdvga_get_crtc();
393     outb(0x12, crtc_addr);
394     u16 vde = inb(crtc_addr + 1);
395     outb(0x07, crtc_addr);
396     u8 ovl = inb(crtc_addr + 1);
397     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
398     return vde;
399 }
400
401
402 /****************************************************************
403  * Save/Restore/Set state
404  ****************************************************************/
405
406 void
407 stdvga_save_state(u16 seg, struct saveVideoHardware *info)
408 {
409     u16 crtc_addr = stdvga_get_crtc();
410     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
411     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
412     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
413     inb(VGAREG_ACTL_RESET);
414     u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
415     SET_FARVAR(seg, info->actl_index, ar_index);
416     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
417
418     u16 i;
419     for (i=0; i<4; i++) {
420         outb(i+1, VGAREG_SEQU_ADDRESS);
421         SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
422     }
423     outb(0, VGAREG_SEQU_ADDRESS);
424     SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
425
426     for (i=0; i<25; i++) {
427         outb(i, crtc_addr);
428         SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
429     }
430
431     for (i=0; i<20; i++) {
432         inb(VGAREG_ACTL_RESET);
433         outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
434         SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
435     }
436     inb(VGAREG_ACTL_RESET);
437
438     for (i=0; i<9; i++) {
439         outb(i, VGAREG_GRDC_ADDRESS);
440         SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
441     }
442
443     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
444
445     /* XXX: read plane latches */
446     for (i=0; i<4; i++)
447         SET_FARVAR(seg, info->plane_latch[i], 0);
448 }
449
450 void
451 stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
452 {
453     // Reset Attribute Ctl flip-flop
454     inb(VGAREG_ACTL_RESET);
455
456     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
457
458     u16 i;
459     for (i=0; i<4; i++) {
460         outb(i+1, VGAREG_SEQU_ADDRESS);
461         outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
462     }
463     outb(0, VGAREG_SEQU_ADDRESS);
464     outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
465
466     // Disable CRTC write protection
467     outw(0x0011, crtc_addr);
468     // Set CRTC regs
469     for (i=0; i<25; i++)
470         if (i != 0x11) {
471             outb(i, crtc_addr);
472             outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
473         }
474     // select crtc base address
475     u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
476     if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
477         v |= 0x01;
478     outb(v, VGAREG_WRITE_MISC_OUTPUT);
479
480     // enable write protection if needed
481     outb(0x11, crtc_addr);
482     outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
483
484     // Set Attribute Ctl
485     u16 ar_index = GET_FARVAR(seg, info->actl_index);
486     inb(VGAREG_ACTL_RESET);
487     for (i=0; i<20; i++) {
488         outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
489         outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
490     }
491     outb(ar_index, VGAREG_ACTL_ADDRESS);
492     inb(VGAREG_ACTL_RESET);
493
494     for (i=0; i<9; i++) {
495         outb(i, VGAREG_GRDC_ADDRESS);
496         outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
497     }
498
499     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
500     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
501     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
502     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
503 }
504
505 void
506 stdvga_set_mode(struct vgamode_s *vmode_g)
507 {
508     // Reset Attribute Ctl flip-flop
509     inb(VGAREG_ACTL_RESET);
510
511     // Set Attribute Ctl
512     u8 *regs = GET_GLOBAL(vmode_g->actl_regs);
513     u16 i;
514     for (i = 0; i <= 0x13; i++) {
515         outb(i, VGAREG_ACTL_ADDRESS);
516         outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
517     }
518     outb(0x14, VGAREG_ACTL_ADDRESS);
519     outb(0x00, VGAREG_ACTL_WRITE_DATA);
520
521     // Set Sequencer Ctl
522     outb(0, VGAREG_SEQU_ADDRESS);
523     outb(0x03, VGAREG_SEQU_DATA);
524     regs = GET_GLOBAL(vmode_g->sequ_regs);
525     for (i = 1; i <= 4; i++) {
526         outb(i, VGAREG_SEQU_ADDRESS);
527         outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
528     }
529
530     // Set Grafx Ctl
531     regs = GET_GLOBAL(vmode_g->grdc_regs);
532     for (i = 0; i <= 8; i++) {
533         outb(i, VGAREG_GRDC_ADDRESS);
534         outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
535     }
536
537     // Set CRTC address VGA or MDA
538     u8 miscreg = GET_GLOBAL(vmode_g->miscreg);
539     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
540     if (!(miscreg & 1))
541         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
542
543     // Disable CRTC write protection
544     outw(0x0011, crtc_addr);
545     // Set CRTC regs
546     regs = GET_GLOBAL(vmode_g->crtc_regs);
547     for (i = 0; i <= 0x18; i++) {
548         outb(i, crtc_addr);
549         outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
550     }
551
552     // Set the misc register
553     outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
554
555     // Enable video
556     outb(0x20, VGAREG_ACTL_ADDRESS);
557     inb(VGAREG_ACTL_RESET);
558 }
559
560
561 /****************************************************************
562  * Misc
563  ****************************************************************/
564
565 void
566 stdvga_enable_video_addressing(u8 disable)
567 {
568     u8 v = (disable & 1) ? 0x00 : 0x02;
569     u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
570     outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
571 }
572
573 void
574 stdvga_init(void)
575 {
576     // switch to color mode and enable CPU access 480 lines
577     outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
578     // more than 64k 3C4/04
579     outb(0x04, VGAREG_SEQU_ADDRESS);
580     outb(0x02, VGAREG_SEQU_DATA);
581 }