- Set up the real-mode IDT.
[AROS.git] / arch / all-pc / bootstrap / vesa.c
blobe6f0d2e5bb93b01b3c9f04d59f4bc3fa8bd633d2
1 /*
2 Copyright © 2007-2012, 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 controllerinfo.signature[0] = 'V';
30 controllerinfo.signature[1] = 'B';
31 controllerinfo.signature[2] = 'E';
32 controllerinfo.signature[3] = '2';
33 asm volatile("call go16 \n\t.code16 \n\t"
34 "movw $0x4f00, %%ax\n\t"
35 "int $0x10\n\t"
36 "movw %%ax, %0\n\t"
37 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"D"(&controllerinfo):"eax","ecx","cc");
38 return retval;
41 /* In VBE 1.1 information about standard modes was optional,
42 so we use a hardcoded table here (we rely on this information) */
43 struct vesa11Info vesa11Modes[] = {
44 {640, 400, 8, 4},
45 {640, 480, 8, 4},
46 {800, 600, 4, 3},
47 {800, 600, 8, 4},
48 {1024, 768, 4, 3},
49 {1024, 768, 8, 4},
50 {1280, 1024, 4, 3},
51 {1280, 1024, 8, 4}
54 short getModeInfo(long mode)
56 short retval;
57 long i;
58 char *ptr = (char *)&modeinfo;
59 for (i = 0; i < sizeof(modeinfo); i++)
60 *ptr++ = 0;
61 asm volatile("call go16 \n\t.code16 \n\t"
62 "movw $0x4f01, %%ax\n\t"
63 "int $0x10\n\t"
64 "movw %%ax, %0\n\t"
65 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"c"(mode),"D"(&modeinfo):"eax","cc");
66 if ((controllerinfo.version < 0x0102) && (mode > 0x0FF) && (mode < 0x108)) {
67 i = mode - 0x100;
68 modeinfo.x_resolution = vesa11Modes[i].x_resolution;
69 modeinfo.y_resolution = vesa11Modes[i].y_resolution;
70 modeinfo.bits_per_pixel = vesa11Modes[i].bits_per_pixel;
71 modeinfo.memory_model = vesa11Modes[i].memory_model;
73 return retval;
76 short setVbeMode(long mode, BOOL set_refresh)
78 short retval;
80 /* Enable custom timings if possible */
81 if (set_refresh && controllerinfo.version >= 0x0300)
82 mode |= 0x800;
83 else
84 mode &= 0xf7ff;
86 asm volatile("call go16 \n\t.code16 \n\t"
87 "movw $0x4f02, %%ax\n\t"
88 "int $0x10\n\t"
89 "movw %%ax, %0\n\t"
90 "DATA32 call go32\n\t.code32\n\t":"=b"(retval):"0"(mode),"D"(&timings):"eax","ecx","cc");
91 return retval;
94 short paletteWidth(long req, unsigned char* width)
96 short retval;
97 unsigned char reswidth;
99 asm volatile("call go16\n\t.code16\n\t"
100 "movw $0x4f08, %%ax\n\t"
101 "int $0x10\n\t"
102 "movb %%bh, %1\n\t"
103 "movw %%ax, %0\n\t"
104 "DATA32 call go32\n\t.code32\n\t":"=b"(retval),"=c"(reswidth):"0"(req):"eax","cc");
105 *width = reswidth;
106 return retval;
109 /* Definitions used in CVT formula */
110 #define M 600
111 #define C 40
112 #define K 128
113 #define J 20
114 #define DUTY_CYCLE(period) \
115 (((C - J) / 2 + J) * 1000 - (M / 2 * (period) / 1000))
116 #define MIN_DUTY_CYCLE 20 /* % */
117 #define MIN_V_PORCH 3 /* lines */
118 #define MIN_V_PORCH_TIME 550 /* us */
119 #define CLOCK_STEP 250000 /* Hz */
121 /* Partial implementation of CVT formula */
122 void calcTimings(int vfreq)
124 ULONG x, y, h_period, h_freq, h_total, h_blank, h_front, h_sync, h_back,
125 v_freq, v_total, v_front, v_sync, v_back, duty_cycle, pixel_freq;
127 x = modeinfo.x_resolution;
128 y = modeinfo.y_resolution;
130 /* Get horizontal period in microseconds */
131 h_period = (1000000000 / vfreq - MIN_V_PORCH_TIME * 1000)
132 / (y + MIN_V_PORCH);
134 /* Vertical front porch is fixed */
135 v_front = MIN_V_PORCH;
137 /* Use aspect ratio to determine V-sync lines */
138 if (x == y * 4 / 3)
139 v_sync = 4;
140 else if (x == y * 16 / 9)
141 v_sync = 5;
142 else if (x == y * 16 / 10)
143 v_sync = 6;
144 else if (x == y * 5 / 4)
145 v_sync = 7;
146 else if (x == y * 15 / 9)
147 v_sync = 7;
148 else
149 v_sync = 10;
151 /* Get vertical back porch */
152 v_back = MIN_V_PORCH_TIME * 1000 / h_period + 1;
153 if (v_back < MIN_V_PORCH)
154 v_back = MIN_V_PORCH;
155 v_back -= v_sync;
157 /* Get total lines per frame */
158 v_total = y + v_front + v_sync + v_back;
160 /* Get horizontal blanking pixels */
161 duty_cycle = DUTY_CYCLE(h_period);
162 if (duty_cycle < MIN_DUTY_CYCLE)
163 duty_cycle = MIN_DUTY_CYCLE;
165 h_blank = 10 * x * duty_cycle / (100000 - duty_cycle);
166 h_blank /= 2 * 8 * 10;
167 h_blank = h_blank * (2 * 8);
169 /* Get total pixels in a line */
170 h_total = x + h_blank;
172 /* Calculate frequencies for each pixel, line and field */
173 h_freq = 1000000000 / h_period;
174 pixel_freq = h_freq * h_total / CLOCK_STEP * CLOCK_STEP;
175 h_freq = pixel_freq / h_total;
176 v_freq = 100 * h_freq / v_total;
178 /* Back porch is half of H-blank */
179 h_back = h_blank / 2;
181 /* H-sync is a fixed percentage of H-total */
182 h_sync = h_total / 100 * 8;
184 /* Front porch is whatever's left */
185 h_front = h_blank - h_sync - h_back;
187 /* Fill in VBE timings structure */
188 timings.h_total = h_total;
189 timings.h_sync_start = x + h_front;
190 timings.h_sync_end = h_total - h_back;
191 timings.v_total = v_total;
192 timings.v_sync_start = y + v_front;
193 timings.v_sync_end = v_total - v_back;
194 timings.flags = 0x4;
195 timings.pixel_clock = pixel_freq;
196 timings.refresh_rate = v_freq;
199 short findMode(int x, int y, int d, int vfreq, BOOL prioritise_depth)
201 unsigned long match, bestmatch = 0, matchd, bestmatchd = 0;
202 unsigned short bestmode = 0xffff, mode_attrs;
203 int bestd = 0;
205 if (getControllerInfo() == 0x4f)
207 unsigned short *modes = (unsigned short *)
208 (((controllerinfo.video_mode & 0xffff0000) >> 12) + (controllerinfo.video_mode & 0xffff));
210 int i;
212 if (controllerinfo.version < 0x0200)
213 mode_attrs = 0x11;
214 else
215 mode_attrs = 0x91;
217 for (i=0; modes[i] != 0xffff; ++i)
219 if (getModeInfo(modes[i])!= 0x4f) continue;
220 if ((modeinfo.mode_attributes & mode_attrs) != mode_attrs) continue;
221 if ((modeinfo.memory_model != 6) && (modeinfo.memory_model != 4))
222 continue;
223 if ((modeinfo.memory_model == 4) && (modeinfo.mode_attributes & 0x20))
224 continue;
226 /* Return immediately if an exactly matching mode is found
227 * (otherwise we could potentially return a mode with the right
228 * area but different dimensions) */
229 if (modeinfo.x_resolution == x &&
230 modeinfo.y_resolution == y &&
231 modeinfo.bits_per_pixel == d)
233 bestmode = modes[i];
234 break;
237 match = ABS(modeinfo.x_resolution*modeinfo.y_resolution - x*y);
238 matchd = modeinfo.bits_per_pixel >= d ? modeinfo.bits_per_pixel-d: (d-modeinfo.bits_per_pixel)*2;
240 if (prioritise_depth)
242 /* Check if current mode is the best so far at the desired
243 * depth, or has a higher depth than previously found */
244 if (bestmode == 0xffff || (match < bestmatch
245 && modeinfo.bits_per_pixel == bestd)
246 || (bestd < d && modeinfo.bits_per_pixel > bestd
247 && modeinfo.bits_per_pixel <= d))
249 bestmode = modes[i];
250 bestmatch = match;
251 bestd = modeinfo.bits_per_pixel;
254 else
256 /* Check if current mode either has the closest resolution
257 * so far to that requested, or is equally close as the
258 * previous best but has closer colour depth */
259 if (bestmode == 0xffff || match < bestmatch
260 || (match == bestmatch && matchd < bestmatchd))
262 bestmode = modes[i];
263 bestmatch = match;
264 bestmatchd = matchd;
270 /* Set up timings to achieve the desired refresh rate */
271 if (controllerinfo.version >= 0x0300 && getModeInfo(bestmode) == 0x4f)
272 calcTimings(vfreq);
274 return bestmode;
277 asm(
278 " .code16\n\t.globl go32\n\t.type go32,@function\n"
279 "go32: DATA32 ADDR32 lgdt GDT_reg\n"
280 " movl %cr0, %eax\n"
281 " bts $0, %eax\n"
282 " movl %eax, %cr0\n"
283 " ljmp $0x08, $1f\n"
284 " .code32\n"
285 "1: movw $0x10, %ax\n"
286 " movw %ax, %ds\n"
287 " movw %ax, %es\n"
288 " movw %ax, %fs\n"
289 " movw %ax, %gs\n"
290 " movw %ax, %ss\n"
291 " movl (%esp), %ecx\n"
292 " movl stack32, %eax\n"
293 " movl %eax, %esp\n"
294 " movl %ecx, (%esp)\n"
295 " xorl %eax, %eax\n"
296 " sidt IDT_reg16\n"
297 " lidt IDT_reg32\n"
298 " ret\n"
299 "\n"
300 " .code32\n\t.globl go16\n\t.type go16,@function\n"
301 "go16: lgdt GDT_reg\n"
302 " sidt IDT_reg32\n"
303 " lidt IDT_reg16\n"
304 " movl %esp, stack32\n"
305 " movl (%esp), %eax\n"
306 " movl %eax, scratch + 63\n"
307 " movl $scratch + 63, %esp\n"
308 " movw $0x20, %ax\n"
309 " movw %ax, %ds\n"
310 " movw %ax, %es\n"
311 " movw %ax, %fs\n"
312 " movw %ax, %gs\n"
313 " movw %ax, %ss\n"
314 " ljmp $0x18, $1f\n\t.code16\n"
315 "1:\n"
316 " movl %cr0, %eax\n"
317 " btc $0, %eax\n"
318 " movl %eax, %cr0\n"
319 " DATA32 ljmp $0x00, $1f\n"
320 "1:\n"
321 " xorl %eax,%eax\n"
322 " movw %ax, %ds\n"
323 " movw %ax, %es\n"
324 " movw %ax, %fs\n"
325 " movw %ax, %gs\n"
326 " movw %ax, %ss\n"
327 " DATA32 ret\n"
328 ".code32");
330 const unsigned long long GDT_Table[] = {
331 0x0000000000000000ULL,
332 0x00cf9a000000ffffULL, /* Code32 */
333 0x00cf92000000ffffULL, /* Data32 */
334 0x00009e000000ffffULL, /* Code16 */
335 0x000092000000ffffULL /* Data16 */
338 const struct
340 unsigned short l1 __attribute__((packed));
341 const void *l3 __attribute__((packed));
343 GDT_reg = {sizeof(GDT_Table)-1, GDT_Table},
344 IDT_reg16 = {0x400, 0},
345 IDT_reg32;
347 unsigned long stack32;
348 unsigned long scratch[64];
349 struct vbe_controller controllerinfo;
350 struct vbe_mode modeinfo;
351 struct CRTCInfoBlock timings;