Fix IO memory access .. SB128 driver makes noises in VMWare - CMI is untested (Curren...
[AROS.git] / arch / i386-pc / exec / vesa.c
blob8d9a8515f9452eb461ac5d96db350d3131a165b8
1 /*
2 Copyright © 2007-2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Real-mode code to set VBE mode.
6 Lang: english
7 */
9 #define _IMPLEMENTATION_
11 asm ("begin:");
13 #include "vesa.h"
14 #define ABS(x) (((x) >= 0) ? (x) : -(x))
16 asm (".long getControllerInfo");
17 asm (".long getModeInfo");
18 asm (".long findMode");
19 asm (".long setVbeMode");
20 asm (".long paletteWidth");
21 asm (".long controllerinfo");
22 asm (".long modeinfo");
23 asm (".long timings");
25 short getControllerInfo(void)
27 short retval;
29 *(ULONG *)controllerinfo.signature = *(ULONG *)"VBE2";
30 asm volatile("call go16 \n\t.code16 \n\t"
31 "movw $0x4f00, %%ax\n\t"
32 "int $0x10\n\t"
33 "movw %%ax, %0\n\t"
34 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"D"(&controllerinfo):"eax","ecx","cc");
35 return retval;
38 /* In VBE 1.1 information about standard modes was optional,
39 so we use a hardcoded table here (we rely on this information) */
40 struct vesa11Info vesa11Modes[] = {
41 {640, 400, 8, 4},
42 {640, 480, 8, 4},
43 {800, 600, 4, 3},
44 {800, 600, 8, 4},
45 {1024, 768, 4, 3},
46 {1024, 768, 8, 4},
47 {1280, 1024, 4, 3},
48 {1280, 1024, 8, 4}
51 short getModeInfo(long mode)
53 short retval;
54 long i;
55 char *ptr = (char *)&modeinfo;
56 for (i = 0; i < sizeof(modeinfo); i++)
57 *ptr++ = 0;
58 asm volatile("call go16 \n\t.code16 \n\t"
59 "movw $0x4f01, %%ax\n\t"
60 "int $0x10\n\t"
61 "movw %%ax, %0\n\t"
62 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"c"(mode),"D"(&modeinfo):"eax","cc");
63 if ((controllerinfo.version < 0x0102) && (mode > 0x0FF) && (mode < 0x108)) {
64 i = mode - 0x100;
65 modeinfo.x_resolution = vesa11Modes[i].x_resolution;
66 modeinfo.y_resolution = vesa11Modes[i].y_resolution;
67 modeinfo.bits_per_pixel = vesa11Modes[i].bits_per_pixel;
68 modeinfo.memory_model = vesa11Modes[i].memory_model;
70 return retval;
73 short setVbeMode(long mode, BOOL set_refresh)
75 short retval;
77 /* Enable custom timings if possible */
78 if (set_refresh && controllerinfo.version >= 0x0300)
79 mode |= 0x800;
80 else
81 mode &= 0xf7ff;
83 asm volatile("call go16 \n\t.code16 \n\t"
84 "movw $0x4f02, %%ax\n\t"
85 "int $0x10\n\t"
86 "movw %%ax, %0\n\t"
87 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"0"(mode),"D"(&timings):"eax","ecx","cc");
88 return retval;
91 short paletteWidth(long req, unsigned char* width)
93 short retval;
94 unsigned char reswidth;
96 asm volatile("call go16\n\t.code16\n\t"
97 "movw $0x4f08, %%ax\n\t"
98 "int $0x10\n\t"
99 "movb %%bh, %1\n\t"
100 "movw %%ax, %0\n\t"
101 "DATA32 call go32\n\t.code32\n\t":"=b"(retval),"=c"(reswidth):"0"(req):"eax","cc");
102 *width = reswidth;
103 return retval;
106 /* Definitions used in CVT formula */
107 #define M 600
108 #define C 40
109 #define K 128
110 #define J 20
111 #define DUTY_CYCLE(period) \
112 (((C - J) / 2 + J) * 1000 - (M / 2 * (period) / 1000))
113 #define MIN_DUTY_CYCLE 20 /* % */
114 #define MIN_V_PORCH 3 /* lines */
115 #define MIN_V_PORCH_TIME 550 /* us */
116 #define CLOCK_STEP 250000 /* Hz */
118 /* Partial implementation of CVT formula */
119 void calcTimings(int vfreq)
121 ULONG x, y, h_period, h_freq, h_total, h_blank, h_front, h_sync, h_back,
122 v_freq, v_total, v_front, v_sync, v_back, duty_cycle, pixel_freq;
124 x = modeinfo.x_resolution;
125 y = modeinfo.y_resolution;
127 /* Get horizontal period in microseconds */
128 h_period = (1000000000 / vfreq - MIN_V_PORCH_TIME * 1000)
129 / (y + MIN_V_PORCH);
131 /* Vertical front porch is fixed */
132 v_front = MIN_V_PORCH;
134 /* Use aspect ratio to determine V-sync lines */
135 if (x == y * 4 / 3)
136 v_sync = 4;
137 else if (x == y * 16 / 9)
138 v_sync = 5;
139 else if (x == y * 16 / 10)
140 v_sync = 6;
141 else if (x == y * 5 / 4)
142 v_sync = 7;
143 else if (x == y * 15 / 9)
144 v_sync = 7;
145 else
146 v_sync = 10;
148 /* Get vertical back porch */
149 v_back = MIN_V_PORCH_TIME * 1000 / h_period + 1;
150 if (v_back < MIN_V_PORCH)
151 v_back = MIN_V_PORCH;
152 v_back -= v_sync;
154 /* Get total lines per frame */
155 v_total = y + v_front + v_sync + v_back;
157 /* Get horizontal blanking pixels */
158 duty_cycle = DUTY_CYCLE(h_period);
159 if (duty_cycle < MIN_DUTY_CYCLE)
160 duty_cycle = MIN_DUTY_CYCLE;
162 h_blank = 10 * x * duty_cycle / (100000 - duty_cycle);
163 h_blank /= 2 * 8 * 10;
164 h_blank = h_blank * (2 * 8);
166 /* Get total pixels in a line */
167 h_total = x + h_blank;
169 /* Calculate frequencies for each pixel, line and field */
170 h_freq = 1000000000 / h_period;
171 pixel_freq = h_freq * h_total / CLOCK_STEP * CLOCK_STEP;
172 h_freq = pixel_freq / h_total;
173 v_freq = 100 * h_freq / v_total;
175 /* Back porch is half of H-blank */
176 h_back = h_blank / 2;
178 /* H-sync is a fixed percentage of H-total */
179 h_sync = h_total / 100 * 8;
181 /* Front porch is whatever's left */
182 h_front = h_blank - h_sync - h_back;
184 /* Fill in VBE timings structure */
185 timings.h_total = h_total;
186 timings.h_sync_start = x + h_front;
187 timings.h_sync_end = h_total - h_back;
188 timings.v_total = v_total;
189 timings.v_sync_start = y + v_front;
190 timings.v_sync_end = v_total - v_back;
191 timings.flags = 0x4;
192 timings.pixel_clock = pixel_freq;
193 timings.refresh_rate = v_freq;
196 short findMode(int x, int y, int d, int vfreq, BOOL prioritise_depth)
198 unsigned long match, bestmatch, matchd, bestmatchd;
199 unsigned short bestmode = 0xffff, mode_attrs;
200 int bestd;
202 if (getControllerInfo() == 0x4f)
204 unsigned short *modes = (unsigned short *)
205 (((controllerinfo.video_mode & 0xffff0000) >> 12) + (controllerinfo.video_mode & 0xffff));
207 int i;
209 if (controllerinfo.version < 0x0200)
210 mode_attrs = 0x11;
211 else
212 mode_attrs = 0x91;
214 for (i=0; modes[i] != 0xffff; ++i)
216 if (getModeInfo(modes[i])!= 0x4f) continue;
217 if ((modeinfo.mode_attributes & mode_attrs) != mode_attrs) continue;
218 if ((modeinfo.memory_model != 6) && (modeinfo.memory_model != 4))
219 continue;
220 if ((modeinfo.memory_model == 4) && (modeinfo.mode_attributes & 0x20))
221 continue;
223 /* Return immediately if an exactly matching mode is found
224 * (otherwise we could potentially return a mode with the right
225 * area but different dimensions) */
226 if (modeinfo.x_resolution == x &&
227 modeinfo.y_resolution == y &&
228 modeinfo.bits_per_pixel == d)
230 bestmode = modes[i];
231 break;
234 match = ABS(modeinfo.x_resolution*modeinfo.y_resolution - x*y);
235 matchd = modeinfo.bits_per_pixel >= d ? modeinfo.bits_per_pixel-d: (d-modeinfo.bits_per_pixel)*2;
237 if (prioritise_depth)
239 /* Check if current mode is the best so far at the desired
240 * depth, or has a higher depth than previously found */
241 if (bestmode == 0xffff || (match < bestmatch
242 && modeinfo.bits_per_pixel == bestd)
243 || (bestd < d && modeinfo.bits_per_pixel > bestd
244 && modeinfo.bits_per_pixel <= d))
246 bestmode = modes[i];
247 bestmatch = match;
248 bestd = modeinfo.bits_per_pixel;
251 else
253 /* Check if current mode either has the closest resolution
254 * so far to that requested, or is equally close as the
255 * previous best but has closer colour depth */
256 if (bestmode == 0xffff || match < bestmatch
257 || (match == bestmatch && matchd < bestmatchd))
259 bestmode = modes[i];
260 bestmatch = match;
261 bestmatchd = matchd;
267 /* Set up timings to achieve the desired refresh rate */
268 if (controllerinfo.version >= 0x0300 && getModeInfo(bestmode) == 0x4f)
269 calcTimings(vfreq);
271 return bestmode;
274 asm(
275 " .code16\n\t.globl go32\n\t.type go32,@function\n"
276 "go32: DATA32 ADDR32 lgdt GDT_reg\n"
277 " movl %cr0, %eax\n"
278 " bts $0, %eax\n"
279 " movl %eax, %cr0\n"
280 " ljmp $0x08, $1f\n"
281 " .code32\n"
282 "1: movw $0x10, %ax\n"
283 " movw %ax, %ds\n"
284 " movw %ax, %es\n"
285 " movw %ax, %fs\n"
286 " movw %ax, %gs\n"
287 " movw %ax, %ss\n"
288 " movl (%esp), %ecx\n"
289 " movl stack32, %eax\n"
290 " movl %eax, %esp\n"
291 " movl %ecx, (%esp)\n"
292 " xorl %eax, %eax\n"
293 " ret\n"
294 "\n"
295 " .code32\n\t.globl go16\n\t.type go16,@function\n"
296 "go16: lgdt GDT_reg\n"
297 " movl %esp, stack32\n"
298 " movl (%esp), %eax\n"
299 " movl %eax, begin + 0xff8\n"
300 " movl $begin + 0xff8, %esp\n"
301 " movw $0x20, %ax\n"
302 " movw %ax, %ds\n"
303 " movw %ax, %es\n"
304 " movw %ax, %fs\n"
305 " movw %ax, %gs\n"
306 " movw %ax, %ss\n"
307 " ljmp $0x18, $1f\n\t.code16\n"
308 "1:\n"
309 " movl %cr0, %eax\n"
310 " btc $0, %eax\n"
311 " movl %eax, %cr0\n"
312 " DATA32 ljmp $0x00, $1f\n"
313 "1:\n"
314 " xorl %eax,%eax\n"
315 " movw %ax, %ds\n"
316 " movw %ax, %es\n"
317 " movw %ax, %fs\n"
318 " movw %ax, %gs\n"
319 " movw %ax, %ss\n"
320 " DATA32 ret\n"
321 ".code32");
323 const unsigned long long GDT_Table[] = {
324 0x0000000000000000ULL,
325 0x00cf9a000000ffffULL, /* Code32 */
326 0x00cf92000000ffffULL, /* Data32 */
327 0x00009e000000ffffULL, /* Code16 */
328 0x000092000000ffffULL /* Data16 */
331 const struct
333 unsigned short l1 __attribute__((packed));
334 const void *l3 __attribute__((packed));
336 GDT_reg = {sizeof(GDT_Table)-1, GDT_Table};
338 unsigned long stack32;
339 struct vbe_controller controllerinfo;
340 struct vbe_mode modeinfo;
341 struct CRTCInfoBlock timings;