1 /*
2 At3d (at25) driver - Matan Ziv-Av zivav@cs.bgu.ac.il
3 please report problems to me,
4
5 If you have an alliance promotion 6422, it should
6 be easy to make the driver work on it.
7
8 This driver is based on the XFREE86 apm driver, developed by
9 Kent Hamilton and by Henrik Harmsen.
10
11 I used the file cirrus.c in this directory as a skeleton.
12
13 there are still the following problems:
14 * pageflipping (in threeDKit) does not work.
15 * no acceleration (is there a program that uses it anyway?).
16 * The clocks for 320x200 modes are _not easy_ for the driver.
17 if you have a problem with those modes, please contact me.
18 * 24 bits modes don't work on AT24.
19
20 */
21
22
23 #include <stdlib.h>
24 #include <stdio.h> /* for printf */
25 #include <string.h> /* for memset */
26 #include <unistd.h>
27 #include "vga.h"
28 #include "libvga.h"
29 #include "driver.h"
30
31
32 /* New style driver interface. */
33 #include "timing.h"
34 #include "vgaregs.h"
35 #include "interface.h"
36 #include "accel.h"
37
38 #define APMREG_SAVE(i) (VGA_TOTAL_REGS+i)
39 #define APM_TOTAL_REGS (VGA_TOTAL_REGS + 38)
40
41
42 static int apm_init(int, int, int);
43 static void apm_unlock(void);
44
45 void __svgalib_apmaccel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);
46
47 static int apm_memory,apm_chiptype;
48 static int apm_is_linear,apm_xbase;
49
50 static CardSpecs *cardspecs;
51
outXR(int index,unsigned char d)52 static void outXR(int index,unsigned char d)
53 {
54 __svgalib_outbSR(0x1d,index>>2);
55 outb(apm_xbase,d);
56 }
57
outwXR(int index,unsigned short d)58 static void outwXR(int index,unsigned short d)
59 {
60 __svgalib_outbSR(0x1d,index>>2);
61 outw(apm_xbase,d);
62 }
63
outlXR(int index,unsigned long d)64 static void outlXR(int index,unsigned long d)
65 {
66 __svgalib_outbSR(0x1d,index>>2);
67 outl(apm_xbase,d);
68 }
69
inXR(int index)70 static unsigned char inXR(int index)
71 {
72 __svgalib_outbSR(0x1d,index>>2);
73 return inb(apm_xbase);
74 }
75
76 #if 0
77 /* currently not used */
78 static unsigned short inwXR(int index)
79 {
80 __svgalib_outbSR(0x1d,index>>2);
81 return inw(apm_xbase);
82 }
83 #endif
84
inlXR(int index)85 static unsigned long inlXR(int index)
86 {
87 __svgalib_outbSR(0x1d,index>>2);
88 return inl(apm_xbase);
89 }
90
91 enum {
92 AT6420 = 0, AT6422, AT24, AT3D
93 };
94
apm_setpage(int page)95 static void apm_setpage(int page)
96 {
97 /* default 4K granularity */
98 outwXR(0xc0,page << 4);
99 }
100
__svgalib_apm_inlinearmode(void)101 static int __svgalib_apm_inlinearmode(void)
102 {
103 return apm_is_linear;
104 }
105
106 /* Fill in chipset specific mode information */
107
apm_getmodeinfo(int mode,vga_modeinfo * modeinfo)108 static void apm_getmodeinfo(int mode, vga_modeinfo *modeinfo)
109 {
110
111 if(modeinfo->colors==16)return;
112
113 modeinfo->maxpixels = apm_memory*1024/modeinfo->bytesperpixel;
114 modeinfo->maxlogicalwidth = 4088;
115 modeinfo->startaddressrange = apm_memory * 1024 - 1;
116 modeinfo->haveblit = 0;
117 modeinfo->flags &= ~HAVE_RWPAGE;
118
119 if (modeinfo->bytesperpixel >= 1) {
120 modeinfo->flags |= CAPABLE_LINEAR;
121 if (__svgalib_apm_inlinearmode())
122 modeinfo->flags |= IS_LINEAR;
123 }
124 }
125
126 /* Read and save chipset-specific registers */
127
apm_saveregs(unsigned char regs[])128 static int apm_saveregs(unsigned char regs[])
129 { unsigned long k;
130
131 apm_unlock(); /* May be locked again by other programs (e.g. X) */
132 regs[APMREG_SAVE(2)] = __svgalib_inCR(0x19);
133 regs[APMREG_SAVE(3)] = __svgalib_inCR(0x1A);
134 regs[APMREG_SAVE(4)] = __svgalib_inCR(0x1B);
135 regs[APMREG_SAVE(5)] = __svgalib_inCR(0x1C);
136 regs[APMREG_SAVE(6)] = __svgalib_inCR(0x1D);
137 regs[APMREG_SAVE(7)] = __svgalib_inCR(0x1E);
138
139 regs[APMREG_SAVE(0)] = __svgalib_inSR(0x1B);
140 regs[APMREG_SAVE(1)] = __svgalib_inSR(0x1C);
141
142 regs[APMREG_SAVE(8)] = inXR(0x80) ;
143 regs[APMREG_SAVE(9)] = inXR(0xc0) ;
144 k = inlXR(0xe8) ;
145 regs[APMREG_SAVE(10)] = k&0xff;
146 regs[APMREG_SAVE(11)] = (k >> 8)&0xff;
147 regs[APMREG_SAVE(12)] = (k >> 16) & 0xff ;
148 regs[APMREG_SAVE(13)] = ( k >> 24 ) & 0xff ;
149 k = inlXR(0xec) ;
150 regs[APMREG_SAVE(14)] = k&0xff;
151 regs[APMREG_SAVE(15)] = (k >> 8)&0xff;
152 regs[APMREG_SAVE(16)] = (k >> 16) & 0xff ;
153 regs[APMREG_SAVE(17)] = ( k >> 24 ) & 0xff ;
154 regs[APMREG_SAVE(18)] = inlXR(0xf0) ;
155 regs[APMREG_SAVE(22)] = inlXR(0xf4) ;
156 regs[APMREG_SAVE(26)] = inlXR(0x140) ;
157 regs[APMREG_SAVE(30)] = inlXR(0x144) ;
158 regs[APMREG_SAVE(32)] = inXR(0x148) ;
159 regs[APMREG_SAVE(36)] = inXR(0x14c) ;
160
161 return APM_TOTAL_REGS - VGA_TOTAL_REGS;
162 }
163
164 /* Set chipset-specific registers */
165
apm_setregs(const unsigned char regs[],int mode)166 static void apm_setregs(const unsigned char regs[], int mode)
167 { unsigned long k ;
168
169 apm_unlock(); /* May be locked again by other programs (eg. X) */
170 apm_setpage(0);
171
172 __svgalib_outSR(0x1b,regs[APMREG_SAVE(0)]);
173 __svgalib_outSR(0x1c,regs[APMREG_SAVE(1)]);
174 __svgalib_outCR(0x19,regs[APMREG_SAVE(2)]);
175 __svgalib_outCR(0x1a,regs[APMREG_SAVE(3)]);
176 __svgalib_outCR(0x1b,regs[APMREG_SAVE(4)]);
177 __svgalib_outCR(0x1c,regs[APMREG_SAVE(5)]);
178 __svgalib_outCR(0x1d,regs[APMREG_SAVE(6)]);
179 __svgalib_outCR(0x1e,regs[APMREG_SAVE(7)]);
180
181 if(apm_chiptype==AT3D) {
182 k=regs[APMREG_SAVE(10)]+(regs[APMREG_SAVE(11)] << 8)+(regs[APMREG_SAVE(12)] << 16)+(regs[APMREG_SAVE(13)] << 24);
183 outlXR(0xe8,k) ;
184 };
185
186 k=regs[APMREG_SAVE(14)]+(regs[APMREG_SAVE(15)] << 8)+(regs[APMREG_SAVE(16)] << 16)+(regs[APMREG_SAVE(17)] << 24);
187 outlXR(0xec,k & ~(1 << 7)) ;
188 outlXR(0xec,k | (1 << 7)) ;
189
190 outXR(0x80,regs[APMREG_SAVE(8)]) ;
191
192 }
193
194
195 /* Return nonzero if mode is available */
196
apm_modeavailable(int mode)197 static int apm_modeavailable(int mode)
198 {
199 struct info *info;
200 ModeTiming *modetiming;
201 ModeInfo *modeinfo;
202
203 if ((mode < G640x480x256 )
204 || mode == G720x348x2)
205 return __svgalib_vga_driverspecs.modeavailable(mode);
206
207 info = &__svgalib_infotable[mode];
208 if (apm_memory * 1024 < info->ydim * info->xbytes)
209 return 0;
210
211 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
212
213 if((modeinfo->bitsPerPixel==24)&&(apm_chiptype==AT24)) {
214 free(modeinfo);
215 return 0;
216 }
217
218 modetiming = malloc(sizeof(ModeTiming));
219 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
220 free(modetiming);
221 free(modeinfo);
222 return 0;
223 }
224 free(modetiming);
225 free(modeinfo);
226
227 return SVGADRV;
228 }
229
230
231 static unsigned comp_lmn(unsigned clock) ;
232 /* Set a mode */
233
234 /* Local, called by apm_setmode(). */
235
apm_initializemode(unsigned char * moderegs,ModeTiming * modetiming,ModeInfo * modeinfo,int mode)236 static void apm_initializemode(unsigned char *moderegs,
237 ModeTiming * modetiming, ModeInfo * modeinfo, int mode)
238 { long k;
239
240 apm_saveregs(moderegs);
241 __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo);
242
243 {
244 int offset;
245 offset = modeinfo->lineWidth >> 3;
246 moderegs[0x13] = offset;
247 /* Bit 8 resides at CR1C bits 7:4. */
248 moderegs[APMREG_SAVE(5)] = (offset & 0xf00) >> 4;
249 }
250
251 /* Set pixel depth. */
252 switch(modeinfo->bitsPerPixel)
253 {
254 case 8:
255 moderegs[APMREG_SAVE(8)] = 0x42;
256 break;
257 case 16:
258 moderegs[APMREG_SAVE(8)] = modeinfo->greenWeight+7;
259 break;
260 case 24:
261 moderegs[APMREG_SAVE(8)] = 0xe;
262 break;
263 case 32:
264 moderegs[APMREG_SAVE(8)] = 0x0f;
265 break;
266 default:
267 break;
268 }
269
270 /*
271 * Enable VESA Super VGA memory organisation.
272 * Also enable Linear Addressing.
273 */
274 moderegs[APMREG_SAVE(0)] = 0;
275 moderegs[APMREG_SAVE(1)] = 21;
276 /* Set banking register to zero. */
277 moderegs[APMREG_SAVE(9)] = 0;
278
279 /* Handle the CRTC overflow bits. */
280 {
281 unsigned char val;
282 /* Vertical Overflow. */
283 val = 0;
284 if ((modetiming->CrtcVTotal - 2) & 0x400)
285 val |= 0x01;
286 if ((modetiming->CrtcVDisplay - 1) & 0x400)
287 val |= 0x02;
288 /* VBlankStart is equal to VSyncStart + 1. */
289 if (modetiming->CrtcVSyncStart & 0x400)
290 val |= 0x04;
291 /* VRetraceStart is equal to VSyncStart + 1. */
292 if (modetiming->CrtcVSyncStart & 0x400)
293 val |= 0x08;
294 moderegs[APMREG_SAVE(3)] = val;
295
296 /* Horizontal Overflow. */
297 val = 0;
298 if ((modetiming->CrtcHTotal / 8 - 5) & 0x100)
299 val |= 1;
300 if ((modetiming->CrtcHDisplay / 8 - 1) & 0x100)
301 val |= 2;
302 /* HBlankStart is equal to HSyncStart - 1. */
303 if ((modetiming->CrtcHSyncStart / 8 - 1) & 0x100)
304 val |= 4;
305 /* HRetraceStart is equal to HSyncStart. */
306 if ((modetiming->CrtcHSyncStart / 8) & 0x100)
307 val |= 8;
308 moderegs[APMREG_SAVE(4)] = val;
309 }
310 moderegs[APMREG_SAVE(7)]= 1; /* disable autoreset feature */
311
312 k = comp_lmn(modetiming->pixelClock);
313 if (k==0){
314 k = comp_lmn(modetiming->pixelClock*2);
315 if(k>0)moderegs[VGA_SR1] |= 8 ; /* Sequencer1 - clock halving */
316 };
317 moderegs[APMREG_SAVE(14)]=k&0xff;
318 moderegs[APMREG_SAVE(15)]=(k >> 8)&0xff;
319 moderegs[APMREG_SAVE(16)]=(k >> 16)&0xff;
320 moderegs[APMREG_SAVE(17)]=(k >> 24)&0xff;
321 moderegs[MIS] |= 0xc;
322 moderegs[MIS]=0xef;
323 /* Set up the RAMDAC registers. */
324
325 if (modeinfo->bitsPerPixel > 8)
326 /* Get rid of white border. */
327 {moderegs[VGA_AR11] = 0;} else
328 { int p,q,r;
329
330 moderegs[VGA_AR11]=0xff;
331 p=moderegs[1]+((moderegs[APMREG_SAVE(4)]&2)<<7);
332 moderegs[2]=p&0xff;
333 moderegs[APMREG_SAVE(4)]&=0xfd;
334 moderegs[APMREG_SAVE(4)]|=(p&0x100)>>7;
335 q=moderegs[4]+((moderegs[APMREG_SAVE(4)]&8)<<5);
336 r=moderegs[0]+4;
337 moderegs[3]&=0xe0;
338 moderegs[3]|=(r&0x1f);
339 moderegs[5]&=0x7f;
340 moderegs[5]|=(r&0x20)<<2;
341
342 p=moderegs[0x12]+((moderegs[0x7]&2)<<7)+((moderegs[7]&0x40)<<3)+((moderegs[APMREG_SAVE(3)]&2)<<9);
343 moderegs[0x15]=p&0xff;
344 moderegs[0x7]&=0xf7;
345 moderegs[0x7]|=(p&0x100)>>5;
346 moderegs[0x9]&=0xdf;
347 moderegs[0x9]|=(p&0x200)>>4;
348 moderegs[APMREG_SAVE(3)]&=0xfb;
349 moderegs[APMREG_SAVE(3)]|=(p&0x400)>>7;
350 moderegs[0x16]=moderegs[6]+1;
351 }
352 moderegs[APMREG_SAVE(10)] = 0xe8;
353 moderegs[APMREG_SAVE(11)] = 0x01;
354 moderegs[APMREG_SAVE(12)] = 0x1f;
355 moderegs[APMREG_SAVE(13)] = 0x07;
356
357
358 apm_is_linear=0;
359
360 return ;
361
362 }
363
364
365
apm_setmode(int mode,int prv_mode)366 static int apm_setmode(int mode, int prv_mode)
367 {
368 unsigned char *moderegs;
369 ModeTiming *modetiming;
370 ModeInfo *modeinfo;
371
372 if ((mode < G640x480x256 /*&& mode != G320x200x256*/)
373 || mode == G720x348x2) {
374
375 /* __svgalib_clear_accelspecs(__svgalib_driverspecs->accelspecs);
376 */
377 /* Let the standard VGA driver set standard VGA modes */
378 /* But first reset an Cirrus extended register that */
379 /* an old XFree86 Trident probe corrupts. */
380 return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
381 }
382 if (!apm_modeavailable(mode))
383 return 1;
384
385 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
386
387 modetiming = malloc(sizeof(ModeTiming));
388 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
389 free(modetiming);
390 free(modeinfo);
391 return 1;
392 }
393
394 moderegs = malloc(APM_TOTAL_REGS);
395
396 apm_initializemode(moderegs, modetiming, modeinfo, mode);
397 free(modetiming);
398
399 __svgalib_setregs(moderegs); /* Set standard regs. */
400 apm_setregs(moderegs, mode); /* Set extended regs. */
401 free(moderegs);
402
403 __svgalib_InitializeAcceleratorInterface(modeinfo);
404
405
406 free(modeinfo);
407 return 0;
408 }
409
410
411 /* Unlock chipset-specific registers */
412
apm_unlock(void)413 static void apm_unlock(void)
414 {
415 int vgaIOBase, temp;
416
417 vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
418 outb(vgaIOBase + 4, 0x11);
419 temp = inb(vgaIOBase + 5);
420 outb(vgaIOBase + 5, temp & 0x7F);
421
422 __svgalib_outSR(0x10, 0x12);
423 }
424
425
426 /* Relock chipset-specific registers */
427 /* (currently not used) */
428
apm_lock(void)429 static void apm_lock(void)
430 {
431 }
432
433
434 /* Indentify chipset, initialize and return non-zero if detected */
435
apm_test(void)436 static int apm_test(void)
437 {
438 int i;
439 int oldSEQ10;
440
441 /* To remove annoying "unused..." warning
442 char id_ap6420[] = "Pro6420";
443 char id_ap6422[] = "Pro6422";
444 */
445 char id_at24[] = "Pro6424";
446 char id_at3d[] = "ProAT3D"; /* Yeah, the manual could have been
447 correct... */
448 char idstring[] = " ";
449
450 if ((getenv("IOPERM") == NULL) && (iopl(3) < 0)) {
451 printf("svgalib(apm): Cannot get I/O permissions.\n");
452 exit(-1);
453 }
454
455 /*
456 * Warning! A fully compliant VGA will most probably interprete this as
457 * __svgalib_outbSR(0x00, 0x02), hence stop the sequencer, to play safe
458 * we keep the old setting.
459 */
460
461 oldSEQ10 = __svgalib_inSR(0x10);
462 __svgalib_outSR(0x10, 0x12);
463
464 for (i = 0; i < 7; i++)
465 idstring[i] = __svgalib_inSR(0x11+i);
466
467 /* reset iopl, apm_init will raise it again */
468 if (getenv("IOPERM") == NULL)
469 iopl(0);
470
471 /*
472 * Just in case, restore any old setting & select SEQ00:
473 */
474 __svgalib_outSR(0x10, oldSEQ10);
475 __svgalib_inSR(0);
476
477 if (!memcmp(id_at3d, idstring, 7) || !memcmp(id_at24,idstring,7))
478 { apm_init(0,0,0) ; return 1; }
479 return 0;
480 }
481
482
483 /* No r/w paging */
apm_setrdpage(int page)484 static void apm_setrdpage(int page)
485 {
486 }
apm_setwrpage(int page)487 static void apm_setwrpage(int page)
488 {
489 }
490
491
492 /* Set display start address (not for 16 color modes) */
493 /* Cirrus supports any address in video memory (up to 2Mb) */
494
apm_setdisplaystart(int address)495 static void apm_setdisplaystart(int address)
496 { int i;
497 outw(0x3d4, (address & 0x00FF00) | 0x0C);
498 outw(0x3d4, ((address & 0x00FF) << 8) | 0x0D);
499
500 /*
501 * Here the high-order bits are masked and shifted, and put into
502 * the appropriate extended registers.
503 */
504 outb(0x3d4,0x1c);
505 i=(inb(0x3d5)&0xf0)|((address & 0x0f0000) >> 16);
506 __svgalib_outCR(0x1c,i);
507 /* modinx(vgaIOBase + 4, 0x1c, 0x0f, (address & 0x0f0000) >> 16); */
508
509 }
510
511
512 /* Set logical scanline length (usually multiple of 8) */
513 /* Cirrus supports multiples of 8, up to 4088 */
514
apm_setlogicalwidth(int width)515 static void apm_setlogicalwidth(int width)
516 {
517 }
518
apm_linear(int op,int param)519 static int apm_linear(int op, int param)
520 {
521 if (op==LINEAR_ENABLE || op==LINEAR_DISABLE){ apm_is_linear=1-apm_is_linear; return 0;}
522 if (op==LINEAR_QUERY_BASE) {__svgalib_outSR(0x1d,0x193>>2); return inb(apm_xbase+3)<<24 ;}
523 if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */
524 else return -1; /* Unknown function. */
525 }
526
apm_match_programmable_clock(int clock)527 static int apm_match_programmable_clock(int clock)
528 {
529 return clock ;
530 }
apm_map_clock(int bpp,int clock)531 static int apm_map_clock(int bpp, int clock)
532 {
533 return clock ;
534 }
apm_map_horizontal_crtc(int bpp,int pixelclock,int htiming)535 static int apm_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
536 {
537 return htiming;
538 }
539 /* Function table (exported) */
540
541 DriverSpecs __svgalib_apm_driverspecs =
542 {
543 apm_saveregs,
544 apm_setregs,
545 apm_unlock,
546 apm_lock,
547 apm_test,
548 apm_init,
549 apm_setpage,
550 apm_setrdpage,
551 apm_setwrpage,
552 apm_setmode,
553 apm_modeavailable,
554 apm_setdisplaystart,
555 apm_setlogicalwidth,
556 apm_getmodeinfo,
557 0, /* old blit funcs */
558 0,
559 0,
560 0,
561 0,
562 0, /* ext_set */
563 0, /* accel */
564 apm_linear,
565 0, /* accelspecs, filled in during init. */
566 NULL, /* Emulation */
567 };
568
569 /* Initialize chipset (called after detection) */
570
apm_init(int force,int par1,int par2)571 static int apm_init(int force, int par1, int par2)
572 {
573 char idstring[] = " ";
574
575 /* Get I/O priviledge */
576 if ((getenv("IOPERM") == NULL) && (iopl(3) < 0)) {
577 printf("svgalib(apm): Cannot get I/O permissions.\n");
578 exit(-1);
579 }
580
581 apm_unlock();
582 if (force) {
583 apm_memory = par1;
584 apm_chiptype = par2;
585 } else {
586 int i;
587 char id_ap6420[] = "Pro6420";
588 char id_ap6422[] = "Pro6422";
589 char id_at24[] = "Pro6424";
590 char id_at3d[] = "ProAT3D"; /* Yeah, the manual could have been
591 correct... */
592
593 __svgalib_outSR(0x10, 0x12);
594
595 for (i = 0; i < 7; i++)
596 idstring[i] = __svgalib_inSR(0x11+i);
597 if (!memcmp(id_ap6420, idstring, 7))
598 {
599 apm_chiptype=AT6420;
600 return 1;
601 }
602 else if (!memcmp(id_ap6422, idstring, 7))
603 {
604 apm_chiptype=AT6422;
605 return 1;
606 }
607 else if (!memcmp(id_at24, idstring, 7))
608 {
609 apm_chiptype=AT24;
610 }
611 else if (!memcmp(id_at3d, idstring, 7))
612 {
613 apm_chiptype=AT3D;
614 }
615 /*else return 1;*/
616 apm_memory=__svgalib_inSR(0x20)*64-34; /* maybe will support accel some day */
617 };
618 if (__svgalib_driver_report) {
619 printf("Using Alliance driver, %.7s, %iKB.\n",idstring, apm_memory);
620 }
621
622 apm_xbase= (__svgalib_inSR(0x1f) << 8 ) + __svgalib_inSR(0x1e);
623
624 cardspecs = malloc(sizeof(CardSpecs));
625 cardspecs->videoMemory = apm_memory;
626 cardspecs->maxPixelClock4bpp = 75000;
627 cardspecs->maxPixelClock8bpp = 175500;
628 if(apm_chiptype==AT24)cardspecs->maxPixelClock8bpp = 160000;
629 cardspecs->maxPixelClock16bpp = 144000;
630 cardspecs->maxPixelClock24bpp = 75000;
631 cardspecs->maxPixelClock32bpp = 94500;
632 cardspecs->flags = CLOCK_PROGRAMMABLE | INTERLACE_DIVIDE_VERT;
633 cardspecs->maxHorizontalCrtc = 4088;
634 cardspecs->maxPixelClock4bpp = 0;
635 cardspecs->nClocks =0;
636 cardspecs->clocks = NULL;
637 cardspecs->mapClock = apm_map_clock;
638 cardspecs->mapHorizontalCrtc = apm_map_horizontal_crtc;
639 cardspecs->matchProgrammableClock=apm_match_programmable_clock;
640 __svgalib_driverspecs = &__svgalib_apm_driverspecs;
641 __svgalib_banked_mem_base=0xa0000;
642 __svgalib_banked_mem_size=0x10000;
643 __svgalib_outSR(0x1d,0x193>>2);
644 __svgalib_linear_mem_base=inb(apm_xbase+3)<<24 ;
645 __svgalib_linear_mem_size=apm_memory*0x400;
646 return 0;
647 }
648
649 #define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2)))
650
651 static unsigned
comp_lmn(unsigned clock)652 comp_lmn(unsigned clock)
653 {
654 int n, m, l, f;
655 double fvco;
656 double fout;
657 double fmax;
658 double fref;
659 double fvco_goal;
660 double k, c;
661
662 if(apm_chiptype==AT3D)fmax = 400000.0; else fmax=265000.0;
663 /* The XFree86 driver says the max for AT24 is 250000,
664 but there is a much use clock (65MHZ), that is use 260000 fvco,
665 and the VESA bios on the card uses this clock, upped the max */
666
667 fref = 14318.0;
668
669 for (m = 1; m <= 5; m++)
670 {
671 for (l = 3; l >= 0; l--)
672 {
673 for (n = 8; n <= 127; n++)
674 {
675 fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l));
676 fvco_goal = (double)clock * (double)(1 << l);
677 fvco = fout * (double)(1 << l);
678 if (!WITHIN(fvco, 0.995*fvco_goal, 1.005*fvco_goal))
679 continue;
680 if (!WITHIN(fvco, 125000.0, fmax))
681 continue;
682 if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0))
683 continue;
684 if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0))
685 continue;
686
687 {
688 k = 7.0 / (175.0 - 380.0);
689 c = -k * 380.0;
690 f = (int)(k * fvco/1000.0 + c + 0.5);
691 if (f > 7) f = 7;
692 if (f < 0) f = 0;
693 }
694 /*printf("clock=%i l=%i f=%i m=%i n=%i\n",clock,l,f,m,n);*/
695 return (n << 16) | (m << 8) | (l << 2) | (f << 4);
696 }
697 }
698 }
699 /*printf("Can't do clock=%i\n",clock);*/
700 return 0;
701 }
702
703
704