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