blob: 1727fcaafe4ae3f27b1e9376906c4d0e7f9fc9c0 [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'Connored68e5b2011-12-31 04:15:12 -05008#include "stdvga.h" // vgahw_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'Connora0ecb052009-05-18 23:34:00 -040011#include "biosvar.h" // GET_BDA
Kevin O'Connore1e000b2011-12-31 03:30:40 -050012#include "vgabios.h" // VGAREG_*
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'Connor1ca05b02010-01-03 17:43:37 -050023vgahw_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'Connor1ca05b02010-01-03 17:43:37 -050030vgahw_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'Connor8bc059e2009-05-17 21:19:36 -040037vgahw_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'Connor8bc059e2009-05-17 21:19:36 -040060vgahw_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'Connor1ca05b02010-01-03 17:43:37 -050069vgahw_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'Connor8bc059e2009-05-17 21:19:36 -040080vgahw_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'Connor8bc059e2009-05-17 21:19:36 -040097vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400106vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400117vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400133vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400150vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400160vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400183vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400208vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400223vgahw_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'Connor8bc059e2009-05-17 21:19:36 -0400238vgahw_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'Connor1ca05b02010-01-03 17:43:37 -0500244vgahw_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
250vgahw_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 vgahw_get_dac_regs(seg, info->dac, 0, 256);
257 SET_FARVAR(seg, info->color_select, 0);
258}
259
260void
261vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
262{
263 outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
264 vgahw_set_dac_regs(seg, info->dac, 0, 256);
265 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'Connor414d0732009-05-31 22:42:04 -0400274vgahw_sequ_write(u8 index, u8 value)
275{
276 outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
277}
278
279void
280vgahw_grdc_write(u8 index, u8 value)
281{
282 outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
283}
284
285void
Kevin O'Connor8bc059e2009-05-17 21:19:36 -0400286vgahw_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
291void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500292get_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400293{
294 outw(0x0100, VGAREG_SEQU_ADDRESS);
295 outw(0x0402, VGAREG_SEQU_ADDRESS);
296 outw(0x0704, VGAREG_SEQU_ADDRESS);
297 outw(0x0300, VGAREG_SEQU_ADDRESS);
298 outw(0x0204, VGAREG_GRDC_ADDRESS);
299 outw(0x0005, VGAREG_GRDC_ADDRESS);
300 outw(0x0406, VGAREG_GRDC_ADDRESS);
301}
302
303void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500304release_font_access(void)
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400305{
306 outw(0x0100, VGAREG_SEQU_ADDRESS);
307 outw(0x0302, VGAREG_SEQU_ADDRESS);
308 outw(0x0304, VGAREG_SEQU_ADDRESS);
309 outw(0x0300, VGAREG_SEQU_ADDRESS);
310 u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
311 outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
312 outw(0x0004, VGAREG_GRDC_ADDRESS);
313 outw(0x1005, VGAREG_GRDC_ADDRESS);
314}
315
316
317/****************************************************************
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400318 * CRTC registers
319 ****************************************************************/
320
321static u16
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500322get_crtc(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400323{
324 return GET_BDA(crtc_address);
325}
326
327void
328vgahw_set_cursor_shape(u8 start, u8 end)
329{
330 u16 crtc_addr = get_crtc();
331 outb(0x0a, crtc_addr);
332 outb(start, crtc_addr + 1);
333 outb(0x0b, crtc_addr);
334 outb(end, crtc_addr + 1);
335}
336
337void
338vgahw_set_active_page(u16 address)
339{
340 u16 crtc_addr = get_crtc();
341 outb(0x0c, crtc_addr);
342 outb((address & 0xff00) >> 8, crtc_addr + 1);
343 outb(0x0d, crtc_addr);
344 outb(address & 0x00ff, crtc_addr + 1);
345}
346
347void
348vgahw_set_cursor_pos(u16 address)
349{
350 u16 crtc_addr = get_crtc();
351 outb(0x0e, crtc_addr);
352 outb((address & 0xff00) >> 8, crtc_addr + 1);
353 outb(0x0f, crtc_addr);
354 outb(address & 0x00ff, crtc_addr + 1);
355}
356
357void
358vgahw_set_scan_lines(u8 lines)
359{
360 u16 crtc_addr = get_crtc();
361 outb(0x09, crtc_addr);
362 u8 crtc_r9 = inb(crtc_addr + 1);
363 crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
364 outb(crtc_r9, crtc_addr + 1);
365}
366
367// Get vertical display end
368u16
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500369vgahw_get_vde(void)
Kevin O'Connora0ecb052009-05-18 23:34:00 -0400370{
371 u16 crtc_addr = get_crtc();
372 outb(0x12, crtc_addr);
373 u16 vde = inb(crtc_addr + 1);
374 outb(0x07, crtc_addr);
375 u8 ovl = inb(crtc_addr + 1);
376 vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
377 return vde;
378}
379
380
381/****************************************************************
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400382 * Save/Restore/Set state
Kevin O'Connorc0c7df62009-05-17 18:11:33 -0400383 ****************************************************************/
384
385void
Kevin O'Connorca668642009-05-21 23:06:08 -0400386vgahw_save_state(u16 seg, struct saveVideoHardware *info)
387{
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400388 u16 crtc_addr = get_crtc();
Kevin O'Connorca668642009-05-21 23:06:08 -0400389 SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
390 SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
391 SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
392 inb(VGAREG_ACTL_RESET);
393 u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
394 SET_FARVAR(seg, info->actl_index, ar_index);
395 SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
396
397 u16 i;
398 for (i=0; i<4; i++) {
399 outb(i+1, VGAREG_SEQU_ADDRESS);
400 SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
401 }
402 outb(0, VGAREG_SEQU_ADDRESS);
403 SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
404
405 for (i=0; i<25; i++) {
406 outb(i, crtc_addr);
407 SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
408 }
409
410 for (i=0; i<20; i++) {
411 inb(VGAREG_ACTL_RESET);
412 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
413 SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
414 }
415 inb(VGAREG_ACTL_RESET);
416
417 for (i=0; i<9; i++) {
418 outb(i, VGAREG_GRDC_ADDRESS);
419 SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
420 }
421
422 SET_FARVAR(seg, info->crtc_addr, crtc_addr);
423
424 /* XXX: read plane latches */
425 for (i=0; i<4; i++)
426 SET_FARVAR(seg, info->plane_latch[i], 0);
427}
428
429void
430vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
431{
432 // Reset Attribute Ctl flip-flop
433 inb(VGAREG_ACTL_RESET);
434
435 u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
436
437 u16 i;
438 for (i=0; i<4; i++) {
439 outb(i+1, VGAREG_SEQU_ADDRESS);
440 outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
441 }
442 outb(0, VGAREG_SEQU_ADDRESS);
443 outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
444
445 // Disable CRTC write protection
446 outw(0x0011, crtc_addr);
447 // Set CRTC regs
448 for (i=0; i<25; i++)
449 if (i != 0x11) {
450 outb(i, crtc_addr);
451 outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
452 }
453 // select crtc base address
454 u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
455 if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
456 v |= 0x01;
457 outb(v, VGAREG_WRITE_MISC_OUTPUT);
458
459 // enable write protection if needed
460 outb(0x11, crtc_addr);
461 outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
462
463 // Set Attribute Ctl
464 u16 ar_index = GET_FARVAR(seg, info->actl_index);
465 inb(VGAREG_ACTL_RESET);
466 for (i=0; i<20; i++) {
467 outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
468 outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
469 }
470 outb(ar_index, VGAREG_ACTL_ADDRESS);
471 inb(VGAREG_ACTL_RESET);
472
473 for (i=0; i<9; i++) {
474 outb(i, VGAREG_GRDC_ADDRESS);
475 outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
476 }
477
478 outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
479 outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
480 outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
481 outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
482}
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400483
484void
Kevin O'Connor87233e92011-12-23 21:40:34 -0500485vgahw_set_mode(struct vgamode_s *vmode_g)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400486{
487 // Reset Attribute Ctl flip-flop
488 inb(VGAREG_ACTL_RESET);
489
490 // Set Attribute Ctl
Kevin O'Connor87233e92011-12-23 21:40:34 -0500491 u8 *regs = GET_GLOBAL(vmode_g->actl_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400492 u16 i;
493 for (i = 0; i <= 0x13; i++) {
494 outb(i, VGAREG_ACTL_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500495 outb(GET_GLOBAL(regs[i]), VGAREG_ACTL_WRITE_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400496 }
497 outb(0x14, VGAREG_ACTL_ADDRESS);
498 outb(0x00, VGAREG_ACTL_WRITE_DATA);
499
500 // Set Sequencer Ctl
501 outb(0, VGAREG_SEQU_ADDRESS);
502 outb(0x03, VGAREG_SEQU_DATA);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500503 regs = GET_GLOBAL(vmode_g->sequ_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400504 for (i = 1; i <= 4; i++) {
505 outb(i, VGAREG_SEQU_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500506 outb(GET_GLOBAL(regs[i - 1]), VGAREG_SEQU_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400507 }
508
509 // Set Grafx Ctl
Kevin O'Connor87233e92011-12-23 21:40:34 -0500510 regs = GET_GLOBAL(vmode_g->grdc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400511 for (i = 0; i <= 8; i++) {
512 outb(i, VGAREG_GRDC_ADDRESS);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500513 outb(GET_GLOBAL(regs[i]), VGAREG_GRDC_DATA);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400514 }
515
516 // Set CRTC address VGA or MDA
Kevin O'Connor87233e92011-12-23 21:40:34 -0500517 u8 miscreg = GET_GLOBAL(vmode_g->miscreg);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400518 u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
519 if (!(miscreg & 1))
520 crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
521
522 // Disable CRTC write protection
523 outw(0x0011, crtc_addr);
524 // Set CRTC regs
Kevin O'Connor87233e92011-12-23 21:40:34 -0500525 regs = GET_GLOBAL(vmode_g->crtc_regs);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400526 for (i = 0; i <= 0x18; i++) {
527 outb(i, crtc_addr);
Kevin O'Connor87233e92011-12-23 21:40:34 -0500528 outb(GET_GLOBAL(regs[i]), crtc_addr + 1);
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400529 }
530
531 // Set the misc register
532 outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
533
534 // Enable video
535 outb(0x20, VGAREG_ACTL_ADDRESS);
536 inb(VGAREG_ACTL_RESET);
537}
538
539
540/****************************************************************
541 * Misc
542 ****************************************************************/
543
544void
545vgahw_enable_video_addressing(u8 disable)
546{
547 u8 v = (disable & 1) ? 0x00 : 0x02;
548 u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
549 outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
550}
551
552void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500553vgahw_init(void)
Kevin O'Connor124b6f72009-05-25 00:44:29 -0400554{
555 // switch to color mode and enable CPU access 480 lines
556 outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
557 // more than 64k 3C4/04
558 outb(0x04, VGAREG_SEQU_ADDRESS);
559 outb(0x02, VGAREG_SEQU_DATA);
560}