Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / 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 "biosvar.h" // GET_GLOBAL
9 #include "farptr.h" // SET_FARVAR
10 #include "stdvga.h" // stdvga_setup
11 #include "string.h" // memset_far
12 #include "vgabios.h" // struct vgamode_s
13 #include "x86.h" // outb
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         rgb[0] = rgb[1] = rgb[2] = intensity;
127
128         stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
129     }
130     stdvga_attrindex_write(0x20);
131 }
132
133
134 /****************************************************************
135  * Memory control
136  ****************************************************************/
137
138 void
139 stdvga_set_text_block_specifier(u8 spec)
140 {
141     stdvga_sequ_write(0x03, spec);
142 }
143
144 // Enable reads and writes to the given "plane" when in planar4 mode.
145 void
146 stdvga_planar4_plane(int plane)
147 {
148     if (plane < 0) {
149         // Return to default mode (read plane0, write all planes)
150         stdvga_sequ_write(0x02, 0x0f);
151         stdvga_grdc_write(0x04, 0);
152     } else {
153         stdvga_sequ_write(0x02, 1<<plane);
154         stdvga_grdc_write(0x04, plane);
155     }
156 }
157
158
159 /****************************************************************
160  * Font loading
161  ****************************************************************/
162
163 static void
164 get_font_access(void)
165 {
166     stdvga_sequ_write(0x00, 0x01);
167     stdvga_sequ_write(0x02, 0x04);
168     stdvga_sequ_write(0x04, 0x07);
169     stdvga_sequ_write(0x00, 0x03);
170     stdvga_grdc_write(0x04, 0x02);
171     stdvga_grdc_write(0x05, 0x00);
172     stdvga_grdc_write(0x06, 0x04);
173 }
174
175 static void
176 release_font_access(void)
177 {
178     stdvga_sequ_write(0x00, 0x01);
179     stdvga_sequ_write(0x02, 0x03);
180     stdvga_sequ_write(0x04, 0x03);
181     stdvga_sequ_write(0x00, 0x03);
182     u16 v = (stdvga_misc_read() & 0x01) ? 0x0e : 0x0a;
183     stdvga_grdc_write(0x06, v);
184     stdvga_grdc_write(0x04, 0x00);
185     stdvga_grdc_write(0x05, 0x10);
186 }
187
188 void
189 stdvga_load_font(u16 seg, void *src_far, u16 count
190                  , u16 start, u8 destflags, u8 fontsize)
191 {
192     get_font_access();
193     u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
194     void *dest_far = (void*)(blockaddr + start*32);
195     u16 i;
196     for (i = 0; i < count; i++)
197         memcpy_far(SEG_GRAPH, dest_far + i*32
198                    , seg, src_far + i*fontsize, fontsize);
199     release_font_access();
200 }
201
202
203 /****************************************************************
204  * CRTC registers
205  ****************************************************************/
206
207 u16
208 stdvga_get_crtc(void)
209 {
210     if (stdvga_misc_read() & 1)
211         return VGAREG_VGA_CRTC_ADDRESS;
212     return VGAREG_MDA_CRTC_ADDRESS;
213 }
214
215 // Ratio between system visible framebuffer ram and the actual videoram used.
216 int
217 stdvga_vram_ratio(struct vgamode_s *vmode_g)
218 {
219     switch (GET_GLOBAL(vmode_g->memmodel)) {
220     case MM_TEXT:
221         return 2;
222     case MM_CGA:
223         return 4 / GET_GLOBAL(vmode_g->depth);
224     case MM_PLANAR:
225         return 4;
226     default:
227         return 1;
228     }
229 }
230
231 void
232 stdvga_set_cursor_shape(u16 cursor_type)
233 {
234     u16 crtc_addr = stdvga_get_crtc();
235     stdvga_crtc_write(crtc_addr, 0x0a, cursor_type >> 8);
236     stdvga_crtc_write(crtc_addr, 0x0b, cursor_type);
237 }
238
239 void
240 stdvga_set_cursor_pos(int address)
241 {
242     u16 crtc_addr = stdvga_get_crtc();
243     address /= 2;  // Assume we're in text mode.
244     stdvga_crtc_write(crtc_addr, 0x0e, address >> 8);
245     stdvga_crtc_write(crtc_addr, 0x0f, address);
246 }
247
248 void
249 stdvga_set_scan_lines(u8 lines)
250 {
251     stdvga_crtc_mask(stdvga_get_crtc(), 0x09, 0x1f, lines - 1);
252 }
253
254 // Get vertical display end
255 u16
256 stdvga_get_vde(void)
257 {
258     u16 crtc_addr = stdvga_get_crtc();
259     u16 vde = stdvga_crtc_read(crtc_addr, 0x12);
260     u8 ovl = stdvga_crtc_read(crtc_addr, 0x07);
261     vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
262     return vde;
263 }
264
265 int
266 stdvga_get_window(struct vgamode_s *vmode_g, int window)
267 {
268     return -1;
269 }
270
271 int
272 stdvga_set_window(struct vgamode_s *vmode_g, int window, int val)
273 {
274     return -1;
275 }
276
277 int
278 stdvga_get_linelength(struct vgamode_s *vmode_g)
279 {
280     u8 val = stdvga_crtc_read(stdvga_get_crtc(), 0x13);
281     return val * 8 / stdvga_vram_ratio(vmode_g);
282 }
283
284 int
285 stdvga_set_linelength(struct vgamode_s *vmode_g, int val)
286 {
287     val = DIV_ROUND_UP(val * stdvga_vram_ratio(vmode_g), 8);
288     stdvga_crtc_write(stdvga_get_crtc(), 0x13, val);
289     return 0;
290 }
291
292 int
293 stdvga_get_displaystart(struct vgamode_s *vmode_g)
294 {
295     u16 crtc_addr = stdvga_get_crtc();
296     int addr = (stdvga_crtc_read(crtc_addr, 0x0c) << 8
297                 | stdvga_crtc_read(crtc_addr, 0x0d));
298     return addr * 4 / stdvga_vram_ratio(vmode_g);
299 }
300
301 int
302 stdvga_set_displaystart(struct vgamode_s *vmode_g, int val)
303 {
304     u16 crtc_addr = stdvga_get_crtc();
305     val = val * stdvga_vram_ratio(vmode_g) / 4;
306     stdvga_crtc_write(crtc_addr, 0x0c, val >> 8);
307     stdvga_crtc_write(crtc_addr, 0x0d, val);
308     return 0;
309 }
310
311 int
312 stdvga_get_dacformat(struct vgamode_s *vmode_g)
313 {
314     return -1;
315 }
316
317 int
318 stdvga_set_dacformat(struct vgamode_s *vmode_g, int val)
319 {
320     return -1;
321 }
322
323
324 /****************************************************************
325  * Save/Restore state
326  ****************************************************************/
327
328 struct saveVideoHardware {
329     u8 sequ_index;
330     u8 crtc_index;
331     u8 grdc_index;
332     u8 actl_index;
333     u8 feature;
334     u8 sequ_regs[4];
335     u8 sequ0;
336     u8 crtc_regs[25];
337     u8 actl_regs[20];
338     u8 grdc_regs[9];
339     u16 crtc_addr;
340     u8 plane_latch[4];
341 } PACKED;
342
343 static void
344 stdvga_save_hw_state(u16 seg, struct saveVideoHardware *info)
345 {
346     u16 crtc_addr = stdvga_get_crtc();
347     SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
348     SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
349     SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
350     SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
351     SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
352
353     int i;
354     for (i=0; i<4; i++)
355         SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
356     SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
357
358     for (i=0; i<25; i++)
359         SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
360
361     for (i=0; i<20; i++)
362         SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
363
364     for (i=0; i<9; i++)
365         SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
366
367     SET_FARVAR(seg, info->crtc_addr, crtc_addr);
368
369     /* XXX: read plane latches */
370     for (i=0; i<4; i++)
371         SET_FARVAR(seg, info->plane_latch[i], 0);
372 }
373
374 static void
375 stdvga_restore_hw_state(u16 seg, struct saveVideoHardware *info)
376 {
377     int i;
378     for (i=0; i<4; i++)
379         stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
380     stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
381
382     // Disable CRTC write protection
383     u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
384     stdvga_crtc_write(crtc_addr, 0x11, 0x00);
385     // Set CRTC regs
386     for (i=0; i<25; i++)
387         if (i != 0x11)
388             stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
389     // select crtc base address
390     stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
391
392     // enable write protection if needed
393     stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
394
395     // Set Attribute Ctl
396     for (i=0; i<20; i++)
397         stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
398     stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
399
400     for (i=0; i<9; i++)
401         stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
402
403     outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
404     outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
405     outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
406     outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
407 }
408
409 struct saveDACcolors {
410     u8 rwmode;
411     u8 peladdr;
412     u8 pelmask;
413     u8 dac[768];
414     u8 color_select;
415 } PACKED;
416
417 static void
418 stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
419 {
420     /* XXX: check this */
421     SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
422     SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
423     SET_FARVAR(seg, info->pelmask, stdvga_pelmask_read());
424     stdvga_dac_read(seg, info->dac, 0, 256);
425     SET_FARVAR(seg, info->color_select, 0);
426 }
427
428 static void
429 stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
430 {
431     stdvga_pelmask_write(GET_FARVAR(seg, info->pelmask));
432     stdvga_dac_write(seg, info->dac, 0, 256);
433     outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
434 }
435
436 int
437 stdvga_save_restore(int cmd, u16 seg, void *data)
438 {
439     void *pos = data;
440     if (cmd & SR_HARDWARE) {
441         if (cmd & SR_SAVE)
442             stdvga_save_hw_state(seg, pos);
443         if (cmd & SR_RESTORE)
444             stdvga_restore_hw_state(seg, pos);
445         pos += sizeof(struct saveVideoHardware);
446     }
447     pos += bda_save_restore(cmd, seg, pos);
448     if (cmd & SR_DAC) {
449         if (cmd & SR_SAVE)
450             stdvga_save_dac_state(seg, pos);
451         if (cmd & SR_RESTORE)
452             stdvga_restore_dac_state(seg, pos);
453         pos += sizeof(struct saveDACcolors);
454     }
455     return pos - data;
456 }
457
458
459 /****************************************************************
460  * Misc
461  ****************************************************************/
462
463 void
464 stdvga_enable_video_addressing(u8 disable)
465 {
466     u8 v = (disable & 1) ? 0x00 : 0x02;
467     stdvga_misc_mask(0x02, v);
468 }
469
470 int
471 stdvga_setup(void)
472 {
473     // switch to color mode and enable CPU access 480 lines
474     stdvga_misc_write(0xc3);
475     // more than 64k 3C4/04
476     stdvga_sequ_write(0x04, 0x02);
477
478     return 0;
479 }