blob: f40c172b6dc9ca20d831fb2a041930300206f123 [file] [log] [blame]
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04001// 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
Kevin O'Connor88ca7412011-12-31 04:24:20 -05008#include "stdvga.h" // stdvga_init
Kevin O'Connorc0c7df62009-05-17 18:11:33 -04009#include "ioport.h" // outb
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040010#include "farptr.h" // SET_FARVAR
Kevin O'Connorc990f272011-12-31 16:00:54 -050011#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor2bec7d62011-12-31 04:31:16 -050012#include "util.h" // memcpy_far
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040013
Kevin O'Connor414d0732009-05-31 22:42:04 -040014// TODO
15// * replace direct in/out calls with wrapper functions
16
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040017
18/****************************************************************
19 * Attribute control
20 ****************************************************************/
21
22void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050023stdvga_screen_disable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040024{
25 inb(VGAREG_ACTL_RESET);
26 outb(0x00, VGAREG_ACTL_ADDRESS);
27}
28
29void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050030stdvga_screen_enable(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -040031{
32 inb(VGAREG_ACTL_RESET);
33 outb(0x20, VGAREG_ACTL_ADDRESS);
34}
35
36void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050037stdvga_set_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040038{
39 inb(VGAREG_ACTL_RESET);
40 outb(0x00, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040041 u8 v1 = color & 0x0f;
42 if (v1 & 0x08)
43 v1 += 0x08;
44 outb(v1, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040045
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040046 u8 v2 = color & 0x10;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040047 int i;
48 for (i = 1; i < 4; i++) {
49 outb(i, VGAREG_ACTL_ADDRESS);
50
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040051 u8 cur = inb(VGAREG_ACTL_READ_DATA);
52 cur &= 0xef;
53 cur |= v2;
54 outb(cur, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040055 }
56 outb(0x20, VGAREG_ACTL_ADDRESS);
57}
58
59void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050060stdvga_set_overscan_border_color(u8 color)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040061{
62 inb(VGAREG_ACTL_RESET);
63 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040064 outb(color, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040065 outb(0x20, VGAREG_ACTL_ADDRESS);
66}
67
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040068u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -050069stdvga_get_overscan_border_color(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040070{
71 inb(VGAREG_ACTL_RESET);
72 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040073 u8 v = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040074 inb(VGAREG_ACTL_RESET);
75 outb(0x20, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040076 return v;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040077}
78
79void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050080stdvga_set_palette(u8 palid)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040081{
82 inb(VGAREG_ACTL_RESET);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040083 palid &= 0x01;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040084 int i;
85 for (i = 1; i < 4; i++) {
86 outb(i, VGAREG_ACTL_ADDRESS);
87
Kevin O'Connor8bc059e2009-05-17 21:19:36 -040088 u8 v = inb(VGAREG_ACTL_READ_DATA);
89 v &= 0xfe;
90 v |= palid;
91 outb(v, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040092 }
93 outb(0x20, VGAREG_ACTL_ADDRESS);
94}
95
96void
Kevin O'Connor88ca7412011-12-31 04:24:20 -050097stdvga_set_single_palette_reg(u8 reg, u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -040098{
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
105u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500106stdvga_get_single_palette_reg(u8 reg)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400107{
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
116void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500117stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400118{
119 inb(VGAREG_ACTL_RESET);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400120 int i;
121 for (i = 0; i < 0x10; i++) {
122 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400123 u8 val = GET_FARVAR(seg, *data_far);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400124 outb(val, VGAREG_ACTL_WRITE_DATA);
125 data_far++;
126 }
127 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400128 outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400129 outb(0x20, VGAREG_ACTL_ADDRESS);
130}
131
132void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500133stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400134{
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400135 int i;
136 for (i = 0; i < 0x10; i++) {
137 inb(VGAREG_ACTL_RESET);
138 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400139 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400140 data_far++;
141 }
142 inb(VGAREG_ACTL_RESET);
143 outb(0x11, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400144 SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400145 inb(VGAREG_ACTL_RESET);
146 outb(0x20, VGAREG_ACTL_ADDRESS);
147}
148
149void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500150stdvga_toggle_intensity(u8 flag)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400151{
152 inb(VGAREG_ACTL_RESET);
153 outb(0x10, VGAREG_ACTL_ADDRESS);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400154 u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400155 outb(val, VGAREG_ACTL_WRITE_DATA);
156 outb(0x20, VGAREG_ACTL_ADDRESS);
157}
158
159void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500160stdvga_select_video_dac_color_page(u8 flag, u8 data)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400161{
162 inb(VGAREG_ACTL_RESET);
163 outb(0x10, VGAREG_ACTL_ADDRESS);
164 u8 val = inb(VGAREG_ACTL_READ_DATA);
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400165 if (!(flag & 0x01)) {
166 // select paging mode
167 val = (val & 0x7f) | (data << 7);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400168 outb(val, VGAREG_ACTL_WRITE_DATA);
169 outb(0x20, VGAREG_ACTL_ADDRESS);
170 return;
171 }
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400172 // select page
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400173 inb(VGAREG_ACTL_RESET);
174 outb(0x14, VGAREG_ACTL_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400175 if (!(val & 0x80))
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400176 data <<= 2;
177 data &= 0x0f;
178 outb(data, VGAREG_ACTL_WRITE_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400179 outb(0x20, VGAREG_ACTL_ADDRESS);
180}
181
182void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500183stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400184{
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
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400198 *pmode = val1;
199 *curpage = val2;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400200}
201
202
203/****************************************************************
204 * DAC control
205 ****************************************************************/
206
207void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500208stdvga_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400209{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400210 outb(start, VGAREG_DAC_WRITE_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400211 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400212 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400213 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400214 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400215 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400216 outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400217 data_far++;
218 count--;
219 }
220}
221
222void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500223stdvga_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400224{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400225 outb(start, VGAREG_DAC_READ_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400226 while (count) {
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400227 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400228 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400229 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400230 data_far++;
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400231 SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400232 data_far++;
233 count--;
234 }
235}
236
237void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500238stdvga_set_pel_mask(u8 val)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400239{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400240 outb(val, VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400241}
242
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400243u8
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500244stdvga_get_pel_mask(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400245{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400246 return inb(VGAREG_PEL_MASK);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400247}
248
Kevin O'Connorca668642009-05-21 23:06:08 -0400249void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500250stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400251{
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));
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500256 stdvga_get_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400257 SET_FARVAR(seg, info->color_select, 0);
258}
259
260void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500261stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400262{
263 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500264 stdvga_set_dac_regs(seg, info->dac, 0, 256);
Kevin O'Connorca668642009-05-21 23:06:08 -0400265 outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
266}
267
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400268
269/****************************************************************
270 * Memory control
271 ****************************************************************/
272
273void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500274stdvga_sequ_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400275{
276 outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
277}
278
279void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500280stdvga_grdc_write(u8 index, u8 value)
Kevin O'Connor414d0732009-05-31 22:42:04 -0400281{
282 outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
283}
284
285void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500286stdvga_set_text_block_specifier(u8 spec)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400287{
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400288 outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400289}
290
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500291
292/****************************************************************
293 * Font loading
294 ****************************************************************/
295
296static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500297get_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400298{
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
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500308static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500309release_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400310{
311 outw(0x0100, VGAREG_SEQU_ADDRESS);
312 outw(0x0302, VGAREG_SEQU_ADDRESS);
313 outw(0x0304, VGAREG_SEQU_ADDRESS);
314 outw(0x0300, VGAREG_SEQU_ADDRESS);
Kevin O'Connor7e1d5302011-12-31 15:52:22 -0500315 u16 v = (inb(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400316 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
317 outw(0x0004, VGAREG_GRDC_ADDRESS);
318 outw(0x1005, VGAREG_GRDC_ADDRESS);
319}
320
Kevin O'Connor2bec7d62011-12-31 04:31:16 -0500321void
322stdvga_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
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400335
336/****************************************************************
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400337 * CRTC registers
338 ****************************************************************/
339
Kevin O'Connorc990f272011-12-31 16:00:54 -0500340u16
341stdvga_get_crtc(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400342{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500343 if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
344 return VGAREG_VGA_CRTC_ADDRESS;
345 return VGAREG_MDA_CRTC_ADDRESS;
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400346}
347
348void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500349stdvga_set_cursor_shape(u8 start, u8 end)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400350{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500351 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400352 outb(0x0a, crtc_addr);
353 outb(start, crtc_addr + 1);
354 outb(0x0b, crtc_addr);
355 outb(end, crtc_addr + 1);
356}
357
358void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500359stdvga_set_active_page(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400360{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500361 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400362 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
368void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500369stdvga_set_cursor_pos(u16 address)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400370{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500371 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400372 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
378void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500379stdvga_set_scan_lines(u8 lines)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400380{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500381 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400382 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
389u16
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500390stdvga_get_vde(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400391{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500392 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400393 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/****************************************************************
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400403 * Save/Restore/Set state
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400404 ****************************************************************/
405
406void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500407stdvga_save_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400408{
Kevin O'Connorc990f272011-12-31 16:00:54 -0500409 u16 crtc_addr = stdvga_get_crtc();
Kevin O'Connorca668642009-05-21 23:06:08 -0400410 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
450void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500451stdvga_restore_state(u16 seg, struct saveVideoHardware *info)
Kevin O'Connorca668642009-05-21 23:06:08 -0400452{
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}
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400504
505void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500506stdvga_set_mode(struct vgamode_s *vmode_g)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400507{
508 // Reset Attribute Ctl flip-flop
509 inb(VGAREG_ACTL_RESET);
510
511 // Set Attribute Ctl
Kevin O'Connor87233e92011-12-23 21:40:34 -0500512 u8 *regs = GET_GLOBAL(vmode_g->actl_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400513 u16 i;
514 for (i = 0; i <= 0x13; i++) {
515 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500516 outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400517 }
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);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500524 regs = GET_GLOBAL(vmode_g->sequ_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400525 for (i = 1; i <= 4; i++) {
526 outb(i, VGAREG_SEQU_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500527 outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400528 }
529
530 // Set Grafx Ctl
Kevin O'Connor87233e92011-12-23 21:40:34 -0500531 regs = GET_GLOBAL(vmode_g->grdc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400532 for (i = 0; i <= 8; i++) {
533 outb(i, VGAREG_GRDC_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500534 outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400535 }
536
537 // Set CRTC address VGA or MDA
Kevin O'Connor87233e92011-12-23 21:40:34 -0500538 u8 miscreg = GET_GLOBAL(vmode_g->miscreg);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400539 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
Kevin O'Connor87233e92011-12-23 21:40:34 -0500546 regs = GET_GLOBAL(vmode_g->crtc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400547 for (i = 0; i <= 0x18; i++) {
548 outb(i, crtc_addr);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500549 outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400550 }
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
565void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500566stdvga_enable_video_addressing(u8 disable)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400567{
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
573void
Kevin O'Connor88ca7412011-12-31 04:24:20 -0500574stdvga_init(void)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400575{
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}