1 /*
2 Laguna chipset driver for cirrus logic 5462, 5464, 5465
3
4 Only tested on 5464.
5 Problems:
6 mouse cursor does not work.
7 secondary (mmio only) not tested.
8 fifo threshold needs more tuning.
9 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include "vga.h"
15 #include "libvga.h"
16 #include "driver.h"
17 #include "timing.h"
18 #include "vgaregs.h"
19 #include "interface.h"
20 #include "accel.h"
21 #include "vgapci.h"
22
23 struct lagunahw {
24 unsigned char crt[5];
25 unsigned char gra[3];
26 unsigned char seq[3];
27 unsigned char pal_state;
28 unsigned char bclk;
29 unsigned char tile;
30 unsigned short tiling_control;
31 unsigned short control;
32 unsigned short format;
33 unsigned short cur_x;
34 unsigned short cur_y;
35 unsigned short cur_preset;
36 unsigned short cur_misc;
37 unsigned short cur_address;
38 unsigned short disp_thresh;
39 unsigned int pcifc;
40 };
41
42 #define LAGUNAREG_SAVE(i) (VGA_TOTAL_REGS+i)
43 #define LAGUNA_TOTAL_REGS (VGA_TOTAL_REGS + sizeof(struct lagunahw))
44
45 enum {
46 L5462=0, L5464, L5465
47 };
48
49 static int laguna_init(int, int, int);
50 static void laguna_unlock(void);
51 static void laguna_lock(void);
52
53 void __svgalib_lagunaaccel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);
54
55 static int laguna_memory, laguna_chiptype;
56 static int laguna_is_linear, laguna_linear_base, laguna_mmio_base;
57
58 static CardSpecs *cardspecs;
59
laguna_readb(int a)60 static inline unsigned int laguna_readb(int a) {
61 return *(MMIO_POINTER+a);
62 }
63
laguna_readw(int a)64 static inline unsigned int laguna_readw(int a) {
65 return *(unsigned short *)(MMIO_POINTER+a);
66 }
67
laguna_readl(int a)68 static inline unsigned int laguna_readl(int a) {
69 return *(unsigned int *)(MMIO_POINTER+a);
70 }
71
laguna_writeb(int a,unsigned int d)72 static inline void laguna_writeb(int a, unsigned int d) {
73 *(MMIO_POINTER+a)=d;
74 }
75
laguna_writew(int a,unsigned int d)76 static inline void laguna_writew(int a, unsigned int d) {
77 *(unsigned short *)(MMIO_POINTER+a)=d;
78 }
79
laguna_writel(int a,unsigned int d)80 static inline void laguna_writel(int a, unsigned int d) {
81 *(unsigned int *)(MMIO_POINTER+a)=d;
82 }
83
laguna_setpage(int page)84 static void laguna_setpage(int page)
85 {
86 __svgalib_outgra(0x09,page*4);
87 }
88
__svgalib_laguna_inlinearmode(void)89 static int __svgalib_laguna_inlinearmode(void)
90 {
91 return laguna_is_linear;
92 }
93
94 /* Fill in chipset specific mode information */
95
laguna_getmodeinfo(int mode,vga_modeinfo * modeinfo)96 static void laguna_getmodeinfo(int mode, vga_modeinfo *modeinfo)
97 {
98
99 if(modeinfo->colors==16)return;
100
101 modeinfo->maxpixels = laguna_memory*1024/modeinfo->bytesperpixel;
102 modeinfo->maxlogicalwidth = 4088;
103 modeinfo->startaddressrange = laguna_memory * 1024 - 1;
104 modeinfo->haveblit = 0;
105 modeinfo->flags &= ~HAVE_RWPAGE;
106
107 if (modeinfo->bytesperpixel >= 1) {
108 if(laguna_linear_base)modeinfo->flags |= CAPABLE_LINEAR;
109 if (__svgalib_laguna_inlinearmode())
110 modeinfo->flags |= IS_LINEAR;
111 }
112 }
113
114 /* Read and save chipset-specific registers */
115
laguna_saveregs(unsigned char regs[])116 static int laguna_saveregs(unsigned char regs[])
117 {
118 struct lagunahw *l=(struct lagunahw *)(regs+VGA_TOTAL_REGS);
119
120 laguna_unlock();
121
122 l->crt[0]= __svgalib_incrtc(0x19);
123 l->crt[1]= __svgalib_incrtc(0x1a);
124 l->crt[2]= __svgalib_incrtc(0x1b);
125 l->crt[3]= __svgalib_incrtc(0x1d);
126 l->crt[4]= __svgalib_incrtc(0x1e);
127
128 l->gra[0]= __svgalib_ingra(0x09);
129 l->gra[1]= __svgalib_ingra(0x0a);
130 l->gra[2]= __svgalib_ingra(0x0b);
131
132 l->seq[0]= __svgalib_inseq(0x0e);
133 l->seq[1]= __svgalib_inseq(0x1e);
134 l->seq[2]= __svgalib_inseq(0x07);
135
136 if(laguna_chiptype==L5465)
137 l->tiling_control=laguna_readw(0x2c4);
138 l->control=laguna_readw(0x402);
139 if(laguna_chiptype==L5465)
140 l->bclk=laguna_readb(0x2c0);
141 else l->bclk=laguna_readb(0x8c);
142 l->tile=laguna_readb(0x407);
143 l->pal_state=laguna_readb(0xb0);
144 l->format=laguna_readw(0xc0);
145 l->cur_x=laguna_readw(0xe0);
146 l->cur_y=laguna_readw(0xe2);
147 l->cur_preset=laguna_readw(0xe4);
148 l->cur_misc=laguna_readw(0xe6);
149 l->cur_address=laguna_readw(0xe8);
150 l->disp_thresh=laguna_readw(0xea);
151 l->pcifc=laguna_readl(0x3fc);
152
153 return LAGUNA_TOTAL_REGS - VGA_TOTAL_REGS;
154 }
155
156 /* Set chipset-specific registers */
157
laguna_setregs(const unsigned char regs[],int mode)158 static void laguna_setregs(const unsigned char regs[], int mode)
159 {
160 struct lagunahw *l=(struct lagunahw *)(regs+VGA_TOTAL_REGS);
161
162 laguna_unlock();
163
164 __svgalib_outcrtc(0x19,l->crt[0]);
165 __svgalib_outcrtc(0x1a,l->crt[1]);
166 __svgalib_outcrtc(0x1b,l->crt[2]);
167 __svgalib_outcrtc(0x1d,l->crt[3]);
168 __svgalib_outcrtc(0x1e,l->crt[4]);
169
170 __svgalib_outgra(0x09,l->gra[0]);
171 __svgalib_outgra(0x0a,l->gra[1]);
172 __svgalib_outgra(0x0b,l->gra[2]);
173
174 __svgalib_outseq(0x0e,l->seq[0]);
175 __svgalib_outseq(0x1e,l->seq[1]);
176 __svgalib_outseq(0x07,l->seq[2]);
177
178 if(laguna_chiptype==L5465)
179 laguna_writew(0x2c4,l->tiling_control);
180 laguna_writew(0x402,l->control);
181 if(laguna_chiptype==L5465)
182 laguna_writeb(0x2c0,l->bclk);
183 else laguna_writeb(0x8c,l->bclk);
184 laguna_writew(0x407,l->tile);
185 laguna_writew(0xb0,l->pal_state);
186 laguna_writew(0xc0,l->format);
187 laguna_writew(0xe0,l->cur_x);
188 laguna_writew(0xe2,l->cur_y);
189 laguna_writew(0xe4,l->cur_preset);
190 laguna_writew(0xe6,l->cur_misc);
191 laguna_writew(0xe8,l->cur_address);
192 laguna_writew(0xea,l->disp_thresh);
193 laguna_writel(0x3fc,l->pcifc);
194 }
195
196
197 /* Return nonzero if mode is available */
198
laguna_modeavailable(int mode)199 static int laguna_modeavailable(int mode)
200 {
201 struct info *info;
202 ModeTiming *modetiming;
203 ModeInfo *modeinfo;
204
205 if ((mode < G640x480x256 )
206 || mode == G720x348x2)
207 return __svgalib_vga_driverspecs.modeavailable(mode);
208
209 info = &__svgalib_infotable[mode];
210 if (laguna_memory * 1024 < info->ydim * info->xbytes)
211 return 0;
212
213 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
214
215 modetiming = malloc(sizeof(ModeTiming));
216 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
217 free(modetiming);
218 free(modeinfo);
219 return 0;
220 }
221 free(modetiming);
222 free(modeinfo);
223
224 return SVGADRV;
225 }
226
227 /* Local, called by laguna_setmode(). */
228
229 #define REF 14318
230
laguna_findclock(int clock,int * on,int * om,int * op,int * opp)231 static int laguna_findclock(int clock, int *on, int *om, int *op, int *opp)
232 {
233 int n, m, diff, best, bestm;
234
235 *opp=0;
236 while(clock<20000) {
237 clock*=2;
238 *opp=+1;
239 }
240
241 if(clock<40000) {
242 clock *= 2;
243 *op=1;
244 } else *op=0;
245
246 best=clock;
247 bestm=5;
248 for(m=6; m<30;m++) {
249 n=clock*m/REF;
250 if((n<64)||(n>127)) continue;
251 diff=clock-(n*REF/m);
252 if(diff<0)diff=-diff;
253 if(diff<best) {
254 best=diff;
255 bestm=m;
256 }
257 }
258
259 if((best==0) || (clock/best>100)) {
260 *on=clock*bestm/REF;
261 *om=bestm;
262 return 0;
263 } else {
264 fprintf(stderr,"Can't find clock %iKHz.\n",clock);
265 return -1;
266 }
267 }
268
laguna_initializemode(unsigned char * moderegs,ModeTiming * modetiming,ModeInfo * modeinfo,int mode)269 static void laguna_initializemode(unsigned char *moderegs,
270 ModeTiming * modetiming, ModeInfo * modeinfo, int mode)
271 {
272 struct lagunahw *l=(struct lagunahw *)(moderegs+VGA_TOTAL_REGS);
273 int hd, htot, hss, hse, hbs, hbe;
274 int vd, vtot, vss, vse, vbs, vbe;
275 int offset;
276 int n,m,p,pp;
277
278 __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo);
279
280
281 if(laguna_chiptype==L5465) {
282 l->tiling_control=laguna_readw(0x2c4);
283 l->tiling_control &= ~0x80; /* disable tiling */
284 }
285
286 l->control=laguna_readw(0x402) & 0x87ff; /* narrow tiles */
287 l->control |= 0x1000; /* disable tiling */
288
289 l->disp_thresh=laguna_readw(0xea)&0xffe0;
290 l->disp_thresh &= 0x3fbf; /* 1-way interleave and narrow tiles */
291 switch(modeinfo->bitsPerPixel) {
292 case 8:
293 case 15:
294 case 16:
295 l->disp_thresh |= 0x10;
296 break;
297 case 24:
298 case 32:
299 l->disp_thresh |= 0x20;
300 break;
301 default:
302 l->disp_thresh |= 0x18;
303 }
304
305 l->pcifc=laguna_readl(0x3fc);
306 l->pcifc |= 0x10000000;
307
308 if(laguna_chiptype==L5465)
309 l->bclk=laguna_readb(0x2c0);
310 else l->bclk=laguna_readb(0x8c);
311
312 l->tile=laguna_readb(0x407) & 0x3f; /* no interleave */
313
314 offset = modeinfo->lineWidth >> 3;
315
316 moderegs[0x13]=offset&0xff;
317
318 hd = (modetiming->CrtcHDisplay >> 3) - 1;
319 htot = (modetiming->CrtcHTotal >> 3) - 5;
320 hss = (modetiming->CrtcHSyncStart >> 3);
321 hse = (modetiming->CrtcHSyncEnd >> 3);
322 hbs = (modetiming->CrtcHSyncStart >> 3) - 1;
323 hbe = (modetiming->CrtcHSyncEnd >> 3);
324 vd = modetiming->CrtcVDisplay - 1;
325 vtot = modetiming->CrtcVTotal - 2;
326 vss = modetiming->CrtcVSyncStart;
327 vse = modetiming->CrtcVSyncEnd;
328 vbs = modetiming->CrtcVSyncStart - 1;
329 vbe = modetiming->CrtcVSyncEnd;
330
331 l->crt[0] = htot>>1;
332 l->crt[1] = ((vbe>>2)&0xf0) | /* vertical blank end overflow */
333 2; /* double buffered display start */
334 if (modetiming->flags & INTERLACED) l->crt[1] |= 0x1;
335 l->crt[2] = 0x22 | /* extended address and no border*/
336 ((offset&0x100)>>4);
337 l->crt[3]=(offset&0x200)>>9;
338 l->crt[4] = ((htot&0x100)>>1) |
339 ((hd&0x100)>>2) |
340 ((hbs&0x100)>>3) |
341 ((hss&0x100)>>4) |
342 ((vtot&0x400)>>7) |
343 ((vd&0x400)>>8) |
344 ((vbs&0x400)>>9) |
345 ((vss&0x400)>>10);
346
347 l->gra[0]=0;
348 l->gra[2]=32; /* use 16KB granularity, only one bank */
349
350 if(laguna_findclock(modetiming->pixelClock,&n,&m,&p,&pp)) {
351 /* should not happen */
352 exit(4);
353 }
354 l->seq[0]=(m<<1)|p;
355 l->seq[1]=n;
356 l->seq[2]=1;
357
358 l->pal_state=0;
359 l->format=pp>>14;
360 switch(modeinfo->bitsPerPixel) {
361 case 8:
362 l->format|=0;
363 l->control |= 0;
364 break;
365 case 15:
366 case 16: if(modeinfo->greenWeight==5)
367 l->format|=0x1600; else
368 l->format|=0x1400;
369 l->control |= 0x2000;
370 break;
371 case 24:
372 l->format|=0x2400;
373 l->control |= 0x4000;
374 break;
375 case 32:
376 l->format|=0x3400;
377 l->control |= 0x6000;
378 break;
379 }
380
381 l->cur_misc=0; /* disable cursor */
382 l->cur_preset=0;
383
384 moderegs[59] |= 0x0c;
385
386 return;
387 }
388
389
laguna_setmode(int mode,int prv_mode)390 static int laguna_setmode(int mode, int prv_mode)
391 {
392 unsigned char *moderegs;
393 ModeTiming *modetiming;
394 ModeInfo *modeinfo;
395
396 if ((mode < G640x480x256)||(mode==G720x348x2)) {
397 laguna_writeb(0xe6,0);
398 __svgalib_outseq(0x07,0);
399 return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
400 }
401 if (!laguna_modeavailable(mode))
402 return 1;
403
404 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
405
406 modetiming = malloc(sizeof(ModeTiming));
407 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
408 free(modetiming);
409 free(modeinfo);
410 return 1;
411 }
412
413 moderegs = malloc(LAGUNA_TOTAL_REGS);
414
415 laguna_initializemode(moderegs, modetiming, modeinfo, mode);
416 free(modetiming);
417
418 __svgalib_setregs(moderegs); /* Set standard regs. */
419 laguna_setregs(moderegs, mode); /* Set extended regs. */
420 free(moderegs);
421
422 __svgalib_InitializeAcceleratorInterface(modeinfo);
423
424 free(modeinfo);
425 return 0;
426 }
427
428
429 /* Unlock chipset-specific registers */
430
laguna_unlock(void)431 static void laguna_unlock(void)
432 {
433 __svgalib_outcrtc(0x11,__svgalib_incrtc(0x11)&0x7f);
434 }
435
laguna_lock(void)436 static void laguna_lock(void)
437 {
438 }
439
440 #define VENDOR_ID 0x1013
441
442 /* Indentify chipset, initialize and return non-zero if detected */
443
laguna_test(void)444 static int laguna_test(void)
445 {
446 int found;
447 unsigned long buf[64];
448
449 found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0);
450
451 if(!found&&
452 ((((buf[0]>>16)&0xffff)==0x00d0)||
453 (((buf[0]>>16)&0xffff)==0x00d4)||
454 (((buf[0]>>16)&0xffff)==0x00d6))){
455 laguna_init(0,0,0);
456 return 1;
457 };
458 return 0;
459 }
460
461
462 /* Set display start address (not for 16 color modes) */
463 /* Cirrus supports any address in video memory (up to 2Mb) */
464
laguna_setdisplaystart(int address)465 static void laguna_setdisplaystart(int address)
466 {
467 address=address >> 2;
468 __svgalib_outcrtc(0x0c,(address & 0xFF00)>>8);
469 __svgalib_outcrtc(0x0d, address & 0xFF);
470 __svgalib_outcrtc(0x1b, (__svgalib_incrtc(0x1b)&0xf2) | ((address&0x100)>>8) | ((address&0x600)>>7));
471 __svgalib_outcrtc(0x1d, (__svgalib_incrtc(0x1b)&0xe7) | ((address&0x1800)>>8) );
472
473 }
474
475
476 /* Set logical scanline length (usually multiple of 8) */
477 /* Cirrus supports multiples of 8, up to 4088 */
478
laguna_setlogicalwidth(int width)479 static void laguna_setlogicalwidth(int width)
480 {
481 int offset = width >> 3;
482
483 __svgalib_outcrtc(0x13,offset&0xff);
484 __svgalib_outcrtc(0x1b, (__svgalib_incrtc(0x1b)&0xef)| ((offset&0x100)>>4));
485 __svgalib_outcrtc(0x1d, (__svgalib_incrtc(0x1b)&0xfe)| ((offset&0x200)>>9));
486 }
487
laguna_linear(int op,int param)488 static int laguna_linear(int op, int param)
489 {
490 if (op==LINEAR_ENABLE){laguna_is_linear=1; return 0;};
491 if (op==LINEAR_DISABLE){laguna_is_linear=0; return 0;};
492 if (op==LINEAR_QUERY_BASE) return laguna_linear_base;
493 if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */
494 else return -1; /* Unknown function. */
495 }
496
laguna_match_programmable_clock(int clock)497 static int laguna_match_programmable_clock(int clock)
498 {
499 return clock ;
500 }
501
laguna_map_clock(int bpp,int clock)502 static int laguna_map_clock(int bpp, int clock)
503 {
504 return clock ;
505 }
506
laguna_map_horizontal_crtc(int bpp,int pixelclock,int htiming)507 static int laguna_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
508 {
509 return htiming;
510 }
511
512 /* Function table (exported) */
513
514 DriverSpecs __svgalib_laguna_driverspecs =
515 {
516 laguna_saveregs,
517 laguna_setregs,
518 laguna_unlock,
519 laguna_lock,
520 laguna_test,
521 laguna_init,
522 laguna_setpage,
523 NULL,
524 NULL,
525 laguna_setmode,
526 laguna_modeavailable,
527 laguna_setdisplaystart,
528 laguna_setlogicalwidth,
529 laguna_getmodeinfo,
530 0, /* old blit funcs */
531 0,
532 0,
533 0,
534 0,
535 0, /* ext_set */
536 0, /* accel */
537 laguna_linear,
538 0, /* accelspecs, filled in during init. */
539 NULL, /* Emulation */
540 };
541
542 /* Initialize chipset (called after detection) */
543
laguna_init(int force,int par1,int par2)544 static int laguna_init(int force, int par1, int par2)
545 {
546 unsigned long buf[64];
547 int found=0;
548 char *chipnames[]={"5462", "5464", "5465"};
549
550 laguna_unlock();
551 if (force) {
552 laguna_memory = par1;
553 laguna_chiptype = par2;
554 } else {
555
556 };
557
558 found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0);
559 laguna_linear_base=0;
560 if (!found){
561 laguna_mmio_base=buf[4]&0xffffff00;
562 laguna_linear_base=buf[5]&0xffffff00;
563 switch(buf[0]>>16) {
564 case 0xd0:
565 laguna_chiptype=L5462;
566 break;
567 case 0xd4:
568 laguna_chiptype=L5464;
569 break;
570 case 0xd6:
571 laguna_chiptype=L5465;
572 break;
573 }
574 laguna_memory=((__svgalib_inseq(0x14)&0x07)+1)*1024;
575 } else return -1;
576
577 if (__svgalib_driver_report) {
578 printf("Using LAGUNA driver, %s with %iKB video ram found.\n",
579 chipnames[laguna_chiptype],laguna_memory);
580 };
581
582 cardspecs = malloc(sizeof(CardSpecs));
583 cardspecs->videoMemory = laguna_memory;
584 cardspecs->maxPixelClock4bpp = 170000;
585 switch(laguna_chiptype) {
586 case L5462:
587 cardspecs->maxPixelClock8bpp = 170000;
588 cardspecs->maxPixelClock16bpp = 135100;
589 cardspecs->maxPixelClock24bpp = 135100;
590 cardspecs->maxPixelClock32bpp = 85500;
591 case L5464:
592 cardspecs->maxPixelClock8bpp = 230000;
593 cardspecs->maxPixelClock16bpp = 170000;
594 cardspecs->maxPixelClock24bpp = 170000;
595 cardspecs->maxPixelClock32bpp = 135100;
596 case L5465:
597 cardspecs->maxPixelClock8bpp = 250000;
598 cardspecs->maxPixelClock16bpp = 170000;
599 cardspecs->maxPixelClock24bpp = 170000;
600 cardspecs->maxPixelClock32bpp = 135100;
601 }
602 cardspecs->flags = INTERLACE_DIVIDE_VERT | CLOCK_PROGRAMMABLE;
603 cardspecs->maxHorizontalCrtc = 4088;
604 cardspecs->nClocks =0;
605 cardspecs->mapClock = laguna_map_clock;
606 cardspecs->mapHorizontalCrtc = laguna_map_horizontal_crtc;
607 cardspecs->matchProgrammableClock=laguna_match_programmable_clock;
608 __svgalib_driverspecs = &__svgalib_laguna_driverspecs;
609 __svgalib_banked_mem_base=0xa0000;
610 __svgalib_banked_mem_size=0x10000;
611 __svgalib_linear_mem_base=laguna_linear_base;
612 __svgalib_linear_mem_size=laguna_memory*0x400;
613 __svgalib_mmio_base=laguna_mmio_base;
614 __svgalib_mmio_size=4096;
615 return 0;
616 }
617