vgabios: Move save/restore state code from vgabios.c to stdvga.c.
[seabios.git] / vgasrc / stdvga.c
1 // Standard VGA driver code
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 "vgabios.h" // struct vgamode_s
9 #include "stdvga.h" // stdvga_init
10 #include "ioport.h" // outb
11 #include "farptr.h" // SET_FARVAR
12 #include "biosvar.h" // GET_GLOBAL
13 #include "util.h" // memcpy_far
14
15
16 /****************************************************************
17  * Attribute control
18  ****************************************************************/
19
20 void
21 stdvga_set_border_color(u8 color)
22 {
23     u8 v1 = color & 0x0f;
24     if (v1 & 0x08)
25         v1 += 0x08;
26     stdvga_attr_write(0x00, v1);
27
28     int i;
29     for (i = 1; i < 4; i++)
30         stdvga_attr_mask(i, 0x10, color & 0x10);
31 }
32
33 void
34 stdvga_set_overscan_border_color(u8 color)
35 {
36     stdvga_attr_write(0x11, color);
37 }
38
39 u8
40 stdvga_get_overscan_border_color(void)
41 {
42     return stdvga_attr_read(0x11);
43 }
44
45 void
46 stdvga_set_palette(u8 palid)
47 {
48     int i;
49     for (i = 1; i < 4; i++)
50         stdvga_attr_mask(i, 0x01, palid & 0x01);
51 }
52
53 void
54 stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
55 {
56     int i;
57     for (i = 0; i < 0x10; i++) {
58         stdvga_attr_write(i, GET_FARVAR(seg, *data_far));
59         data_far++;
60     }
61     stdvga_attr_write(0x11, GET_FARVAR(seg, *data_far));
62 }
63
64 void
65 stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
66 {
67     int i;
68     for (i = 0; i < 0x10; i++) {
69         SET_FARVAR(seg, *data_far, stdvga_attr_read(i));
70         data_far++;
71     }
72     SET_FARVAR(seg, *data_far, stdvga_attr_read(0x11));
73 }
74
75 void
76 stdvga_toggle_intensity(u8 flag)
77 {
78     stdvga_attr_mask(0x10, 0x08, (flag & 0x01) << 3);
79 }
80
81 void
82 stdvga_select_video_dac_color_page(u8 flag, u8 data)
83 {
84     if (!(flag & 0x01)) {
85         // select paging mode
86         stdvga_attr_mask(0x10, 0x80, data << 7);
87         return;
88     }
89     // select page
90     u8 val = stdvga_attr_read(0x10);
91     if (!(val & 0x80))
92         data <<= 2;
93     data &= 0x0f;
94     stdvga_attr_write(0x14, data);
95 }
96
97 void
98 stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
99 {
100     u8 val1 = stdvga_attr_read(0x10) >> 7;
101     u8 val2 = stdvga_attr_read(0x14) & 0x0f;
102     if (!(val1 & 0x01))
103         val2 >>= 2;
104     *pmode = val1;
105     *curpage = val2;
106 }
107
108
109 /****************************************************************
110  * DAC control
111  ****************************************************************/
112
113 void
114 stdvga_perform_gray_scale_summing(u16 start, u16 count)
115 {
116     stdvga_attrindex_write(0x00);
117     int i;
118     for (i = start; i < start+count; i++) {
119         u8 rgb[3];
120         stdvga_dac_read(GET_SEG(SS), rgb, i, 1);
121
122         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
123         u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
124         if (intensity > 0x3f)
125             intensity = 0x3f;
126
127         stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
128     }
129     stdvga_attrindex_write(0x20);
130 }
131
132
133 /****************************************************************
134  * Memory control
135  ****************************************************************/
136
137 void
138 stdvga_set_text_block_specifier(u8 spec)
139 {
140     stdvga_sequ_write(0x03, spec);
141 }
142
143 // Enable reads and writes to the given "plane" when in planar4 mode.
144 void
145 stdvga_planar4_plane(int plane)
146 {
147     if (plane < 0) {
148         // Return to default mode (read plane0, write all planes)
149         stdvga_sequ_write(0x02, 0x0f);
150         stdvga_grdc_write(0x04, 0);
151     } else {
152         stdvga_sequ_write(0x02, 1<<plane);
153         stdvga_grdc_write(0x04, plane);
154     }
155 }
156
157
158 /****************************************************************
159  * Font loading
160  ****************************************************************/
161
162 static void
163 get_font_access(void)
164 {
165     stdvga_sequ_write(0x00, 0x01);
166     stdvga_sequ_write(0x02, 0x04);
167     stdvga_sequ_write(0x04, 0x07);
168     stdvga_sequ_write(0x00, 0x03);
169     stdvga_grdc_write(0x04, 0x02);
170     stdvga_grdc_write(0x05, 0x00);
171     stdvga_grdc_write(0x06, 0x04);
172 }
173
174 static void
175 release_font_access(void)
176 {
177     stdvga_sequ_write(0x00, 0x01);
178     stdvga_sequ_write(0x02, 0x03);
179     stdvga_sequ_write(0x04, 0x03);
180     stdvga_sequ_write(0x00, 0x03);
181     u16 v = (stdvga_misc_read() & 0x01) ? 0x0e : 0x0a;
182     stdvga_grdc_write(0x06, v);
183     stdvga_grdc_write(0x04, 0x00);
184     stdvga_grdc_write(0x05, 0x10);
185 }
186
187 void
188 stdvga_load_font(u16 seg, void *src_far, u16 count
189                  , u16 start, u8 destflags, u8 fontsize)
190 {
191     get_font_access();
192     u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
193     void *dest_far = (void*)(blockaddr + start*32);
194     u16 i;
195     for (i = 0; i < count; i++)
196         memcpy_far(SEG_GRAPH, dest_far + i*32
197                    , seg, src_far + i*fontsize, fontsize);
198     release_font_access();
199 }
200
201
202 /****************************************************************
203  * CRTC registers
204  ****************************************************************/
205
206 u16
207 stdvga_get_crtc(void)
208 {
209     if (stdvga_misc_read() & 1)
210         return VGAREG_VGA_CRTC_ADDRESS;
211     return VGAREG_MDA_CRTC_ADDRESS;
212 }
213
214 // Return the multiplication factor needed for the vga offset register.
215 int
216 stdvga_bpp_factor(struct vgamode_s *vmode_g)
217 {
218     switch (GET_GLOBAL(vmode_g->memmodel)) {
219     case MM_TEXT:
220         return 2;
221     case MM_CGA:
222         return GET_GLOBAL(vmode_g->depth);
223     case MM_PLANAR:
224         return 1;
225     default:
226         return 4;
227     }
228 }
229
230 void
231 stdvga_set_cursor_shape(u8 start, u8 end)
232 {
233     u16 crtc_addr = stdvga_get_crtc();
234     stdvga_crtc_write(crtc_addr, 0x0a, start);
235     stdvga_crtc_write(crtc_addr, 0x0b, end);
236 }
237
238 void
239 stdvga_set_cursor_pos(int address)
240 {
241     u16 crtc_addr = stdvga_get_crtc();
242     address /= 2;  // Assume we're in text mode.
243     stdvga_crtc_write(crtc_addr, 0x0e, address >> 8);
244     stdvga_crtc_write(crtc_addr, 0x0f, address);
245 }
246
247 void
248 stdvga_set_scan_lines(u8 lines)
249 {
250     stdvga_crtc_mask(stdvga_get_crtc(), 0x09, 0x1f, lines - 1);
251 }
252
253 // Get vertical display end
254 u16
255 stdvga_get_vde(void)
256 {
257     u16 crtc_addr = stdvga_get_crtc();
258     u16 vde = stdvga_crtc_read(crtc_addr, 0x12);
259     u8 ovl = stdvga_crtc_read(crtc_addr, 0x07);
260     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
261     return vde;
262 }
263
264 int
265 stdvga_get_window(struct vgamode_s *vmode_g, int window)
266 {
267     return -1;
268 }
269
270 int
271 stdvga_set_window(struct vgamode_s *vmode_g, int window, int val)
272 {
273     return -1;
274 }
275
276 int
277 stdvga_get_linelength(struct vgamode_s *vmode_g)
278 {
279     u8 val = stdvga_crtc_read(stdvga_get_crtc(), 0x13);
280     return val * stdvga_bpp_factor(vmode_g) * 2;
281 }
282
283 int
284 stdvga_set_linelength(struct vgamode_s *vmode_g, int val)
285 {
286     int factor = stdvga_bpp_factor(vmode_g) * 2;
287     stdvga_crtc_write(stdvga_get_crtc(), 0x13, DIV_ROUND_UP(val, factor));
288     return 0;
289 }
290
291 int
292 stdvga_get_displaystart(struct vgamode_s *vmode_g)
293 {
294     u16 crtc_addr = stdvga_get_crtc();
295     int addr = (stdvga_crtc_read(crtc_addr, 0x0c) << 8
296                 | stdvga_crtc_read(crtc_addr, 0x0d));
297     return addr * stdvga_bpp_factor(vmode_g);
298 }
299
300 int
301 stdvga_set_displaystart(struct vgamode_s *vmode_g, int val)
302 {
303     u16 crtc_addr = stdvga_get_crtc();
304     val /= stdvga_bpp_factor(vmode_g);
305     stdvga_crtc_write(crtc_addr, 0x0c, val >> 8);
306     stdvga_crtc_write(crtc_addr, 0x0d, val);
307     return 0;
308 }
309
310 int
311 stdvga_get_dacformat(struct vgamode_s *vmode_g)
312 {
313     return -1;
314 }
315
316 int
317 stdvga_set_dacformat(struct vgamode_s *vmode_g, int val)
318 {
319     return -1;
320 }
321
322
323 /****************************************************************
324  * Save/Restore state
325  ****************************************************************/
326
327 struct saveVideoHardware {
328     u8 sequ_index;
329     u8 crtc_index;
330     u8 grdc_index;
331     u8 actl_index;
332     u8 feature;
333     u8 sequ_regs[4];
334     u8 sequ0;
335     u8 crtc_regs[25];
336     u8 actl_regs[20];
337     u8 grdc_regs[9];
338     u16 crtc_addr;
339     u8 plane_latch[4];
340 };
341
342 static void
343 stdvga_save_hw_state(u16 seg, struct saveVideoHardware *info)
344 {
345     u16 crtc_addr = stdvga_get_crtc();
346     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
347     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
348     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
349     SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
350     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
351
352     int i;
353     for (i=0; i<4; i++)
354         SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
355     SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
356
357     for (i=0; i<25; i++)
358         SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
359
360     for (i=0; i<20; i++)
361         SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
362
363     for (i=0; i<9; i++)
364         SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
365
366     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
367
368     /* XXX: read plane latches */
369     for (i=0; i<4; i++)
370         SET_FARVAR(seg, info->plane_latch[i], 0);
371 }
372
373 static void
374 stdvga_restore_hw_state(u16 seg, struct saveVideoHardware *info)
375 {
376     int i;
377     for (i=0; i<4; i++)
378         stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
379     stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
380
381     // Disable CRTC write protection
382     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
383     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
384     // Set CRTC regs
385     for (i=0; i<25; i++)
386         if (i != 0x11)
387             stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
388     // select crtc base address
389     stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
390
391     // enable write protection if needed
392     stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
393
394     // Set Attribute Ctl
395     for (i=0; i<20; i++)
396         stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
397     stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
398
399     for (i=0; i<9; i++)
400         stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
401
402     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
403     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
404     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
405     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
406 }
407
408 struct saveDACcolors {
409     u8 rwmode;
410     u8 peladdr;
411     u8 pelmask;
412     u8 dac[768];
413     u8 color_select;
414 };
415
416 static void
417 stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
418 {
419     /* XXX: check this */
420     SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
421     SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
422     SET_FARVAR(seg, info->pelmask, stdvga_pelmask_read());
423     stdvga_dac_read(seg, info->dac, 0, 256);
424     SET_FARVAR(seg, info->color_select, 0);
425 }
426
427 static void
428 stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
429 {
430     stdvga_pelmask_write(GET_FARVAR(seg, info->pelmask));
431     stdvga_dac_write(seg, info->dac, 0, 256);
432     outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
433 }
434
435 int
436 stdvga_size_state(int states)
437 {
438     int size = 0;
439     if (states & 1)
440         size += sizeof(struct saveVideoHardware);
441     if (states & 2)
442         size += sizeof(struct saveBDAstate);
443     if (states & 4)
444         size += sizeof(struct saveDACcolors);
445     return size;
446 }
447
448 int
449 stdvga_save_state(u16 seg, void *data, int states)
450 {
451     if (states & 1) {
452         stdvga_save_hw_state(seg, data);
453         data += sizeof(struct saveVideoHardware);
454     }
455     if (states & 2) {
456         save_bda_state(seg, data);
457         data += sizeof(struct saveBDAstate);
458     }
459     if (states & 4)
460         stdvga_save_dac_state(seg, data);
461     return 0;
462 }
463
464 int
465 stdvga_restore_state(u16 seg, void *data, int states)
466 {
467     if (states & 1) {
468         stdvga_restore_hw_state(seg, data);
469         data += sizeof(struct saveVideoHardware);
470     }
471     if (states & 2) {
472         restore_bda_state(seg, data);
473         data += sizeof(struct saveBDAstate);
474     }
475     if (states & 4)
476         stdvga_restore_dac_state(seg, data);
477     return 0;
478 }
479
480
481 /****************************************************************
482  * Misc
483  ****************************************************************/
484
485 void
486 stdvga_enable_video_addressing(u8 disable)
487 {
488     u8 v = (disable & 1) ? 0x00 : 0x02;
489     stdvga_misc_mask(0x02, v);
490 }
491
492 int
493 stdvga_init(void)
494 {
495     // switch to color mode and enable CPU access 480 lines
496     stdvga_misc_write(0xc3);
497     // more than 64k 3C4/04
498     stdvga_sequ_write(0x04, 0x02);
499
500     return 0;
501 }