aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKnut Petersen <Knut_Petersen@t-online.de>2005-09-09 16:04:56 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:58:02 -0400
commit9fa68eae9f8291a98bfe00b94b78f72eb253165a (patch)
treef3619e7302871a5d56264f6df4076c30857483ce /drivers
parent6062bfa1644f401c08e78d5c8a161f7d11c5c830 (diff)
[PATCH] framebuffer: new driver for cyberblade/i1 graphics core
This is a framebuffer driver for the Cyberblade/i1 graphics core. Currently tridenfb claims to support the cyberblade/i1 graphics core. This is of very limited truth. Even vesafb is faster and provides more working modes and a much better quality of the video signal. There is a great number of bugs in tridentfb ... but most often it is impossible to decide if these bugs are real bugs or if fixing them for the cyberblade/i1 core would break support for one of the other supported chips. Tridentfb seems to be unmaintained,and documentation for most of the supported chips is not available. So "fixing" cyberblade/i1 support inside of tridentfb was not an option, it would have caused numerous if(CYBERBLADEi1) else ... cases and would have rendered the code to be almost unmaintainable. A first version of this driver was published on 2005-07-31. A fix for a bug reported by Jochen Hein was integrated as well as some changes requested by Antonino A. Daplas. A message has been added to tridentfb to inform current users of tridentfb to switch to cyblafb if the cyberblade/i1 graphics core is detected. This patch is one logical change, but because of the included documentation it is bigger than 70kb. Therefore it is not sent to lkml and linux-fbdev-devel, Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de> Cc: Muli Ben-Yehuda <mulix@mulix.org> Acked-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/Kconfig31
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/cyblafb.c1456
-rw-r--r--drivers/video/tridentfb.c5
4 files changed, 1493 insertions, 2 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e906b5421795..e27aefd49ea3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1177,6 +1177,32 @@ config FB_VOODOO1
1177 Please read the <file:Documentation/fb/README-sstfb.txt> for supported 1177 Please read the <file:Documentation/fb/README-sstfb.txt> for supported
1178 options and other important info support. 1178 options and other important info support.
1179 1179
1180config FB_CYBLA
1181 tristate "Cyberblade/i1 support"
1182 depends on FB && PCI
1183 select FB_CFB_IMAGEBLIT
1184 select FB_SOFT_CURSOR
1185 select VIDEO_SELECT
1186 ---help---
1187 This driver is supposed to support the Trident Cyberblade/i1
1188 graphics core integrated in the VIA VT8601A North Bridge,
1189 also known as VIA Apollo PLE133.
1190
1191 Status:
1192 - Developed, tested and working on EPIA 5000 and EPIA 800.
1193 - Does work reliable on all systems with CRT/LCD connected to
1194 normal VGA ports.
1195 - Should work on systems that do use the internal LCD port, but
1196 this is absolutely not tested.
1197
1198 Character imageblit, copyarea and rectangle fill are hw accelerated,
1199 ypan scrolling is used by default.
1200
1201 Please do read <file:Documentation/fb/cyblafb/*>.
1202
1203 To compile this driver as a module, choose M here: the
1204 module will be called cyblafb.
1205
1180config FB_TRIDENT 1206config FB_TRIDENT
1181 tristate "Trident support" 1207 tristate "Trident support"
1182 depends on FB && PCI 1208 depends on FB && PCI
@@ -1190,8 +1216,12 @@ config FB_TRIDENT
1190 but also on some motherboards. For more information, read 1216 but also on some motherboards. For more information, read
1191 <file:Documentation/fb/tridentfb.txt> 1217 <file:Documentation/fb/tridentfb.txt>
1192 1218
1219 Cyberblade/i1 support will be removed soon, use the cyblafb driver
1220 instead.
1221
1193 Say Y if you have such a graphics board. 1222 Say Y if you have such a graphics board.
1194 1223
1224
1195 To compile this driver as a module, choose M here: the 1225 To compile this driver as a module, choose M here: the
1196 module will be called tridentfb. 1226 module will be called tridentfb.
1197 1227
@@ -1202,7 +1232,6 @@ config FB_TRIDENT_ACCEL
1202 This will compile the Trident frame buffer device with 1232 This will compile the Trident frame buffer device with
1203 acceleration functions. 1233 acceleration functions.
1204 1234
1205
1206config FB_PM3 1235config FB_PM3
1207 tristate "Permedia3 support" 1236 tristate "Permedia3 support"
1208 depends on FB && PCI && BROKEN 1237 depends on FB && PCI && BROKEN
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b018df4e95c8..8478d217aaf0 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -50,7 +50,8 @@ obj-$(CONFIG_FB_CT65550) += chipsfb.o
50obj-$(CONFIG_FB_IMSTT) += imsttfb.o 50obj-$(CONFIG_FB_IMSTT) += imsttfb.o
51obj-$(CONFIG_FB_S3TRIO) += S3triofb.o 51obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
52obj-$(CONFIG_FB_FM2) += fm2fb.o 52obj-$(CONFIG_FB_FM2) += fm2fb.o
53obj-$(CONFIG_FB_TRIDENT) += tridentfb.o 53obj-$(CONFIG_FB_CYBLA) += cyblafb.o
54obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
54obj-$(CONFIG_FB_STI) += stifb.o 55obj-$(CONFIG_FB_STI) += stifb.o
55obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o 56obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
56obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o 57obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
new file mode 100644
index 000000000000..ae2762cb5608
--- /dev/null
+++ b/drivers/video/cyblafb.c
@@ -0,0 +1,1456 @@
1/*
2 * Frame buffer driver for Trident Cyberblade/i1 graphics core
3 *
4 * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
5 *
6 * CREDITS:
7 * tridentfb.c by Jani Monoses
8 * see files above for further credits
9 *
10 * TODO:
11 *
12 */
13
14#define CYBLAFB_DEBUG 0
15
16#include <linux/config.h>
17#include <linux/module.h>
18#include <linux/string.h>
19#include <linux/fb.h>
20#include <linux/init.h>
21#include <linux/pci.h>
22#include <asm/types.h>
23#include <video/cyblafb.h>
24
25#define VERSION "0.54"
26
27struct cyblafb_par {
28 u32 pseudo_pal[16];
29 struct fb_ops ops;
30};
31
32static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
33 .id = "CyBla",
34 .type = FB_TYPE_PACKED_PIXELS,
35 .ypanstep = 1,
36 .visual = FB_VISUAL_PSEUDOCOLOR,
37 .accel = FB_ACCEL_NONE,
38};
39
40static char *mode __devinitdata = NULL;
41static int bpp __devinitdata = 8;
42static int ref __devinitdata = 75;
43static int fp __devinitdata;
44static int crt __devinitdata;
45static int memsize __devinitdata;
46static int vesafb __devinitdata;
47
48static int nativex;
49static int center;
50static int stretch;
51static int pciwb = 1;
52static int pcirb = 1;
53static int pciwr = 1;
54static int pcirr = 1;
55static int verbosity;
56static int displaytype;
57
58static void __iomem * io_virt; // iospace virtual memory address
59
60module_param(mode,charp,0);
61module_param(bpp,int,0);
62module_param(ref,int,0);
63module_param(fp,int,0);
64module_param(crt,int,0);
65module_param(nativex,int,0);
66module_param(center,int,0);
67module_param(stretch,int,0);
68module_param(pciwb,int,0);
69module_param(pcirb,int,0);
70module_param(pciwr,int,0);
71module_param(pcirr,int,0);
72module_param(memsize,int,0);
73module_param(verbosity,int,0);
74module_param(vesafb,int,0);
75
76//=========================================
77//
78// Port access macros for memory mapped io
79//
80//=========================================
81
82#define out8(r,v) writeb(v,io_virt+r)
83#define out32(r,v) writel(v,io_virt+r)
84#define in8(r) readb(io_virt+r)
85#define in32(r) readl(io_virt+r)
86
87//======================================
88//
89// Hardware access inline functions
90//
91//======================================
92
93static inline unsigned char read3X4(int reg)
94{
95 out8(0x3D4,reg);
96 return in8(0x3D5);
97}
98
99static inline unsigned char read3C4(int reg)
100{
101 out8(0x3C4,reg);
102 return in8(0x3C5);
103}
104
105static inline unsigned char read3CE(int reg)
106{
107 out8(0x3CE,reg);
108 return in8(0x3CF);
109}
110
111static inline void write3X4(int reg,unsigned char val)
112{
113 out8(0x3D4,reg);
114 out8(0x3D5,val);
115}
116
117static inline void write3C4(int reg,unsigned char val)
118{
119 out8(0x3C4,reg);
120 out8(0x3C5,val);
121}
122
123static inline void write3CE(int reg,unsigned char val)
124{
125 out8(0x3CE,reg);
126 out8(0x3CF,val);
127}
128
129static inline void write3C0(int reg,unsigned char val)
130{
131 in8(0x3DA); // read to reset index
132 out8(0x3C0,reg);
133 out8(0x3C0,val);
134}
135
136//=================================================
137//
138// Enable memory mapped io and unprotect registers
139//
140//=================================================
141
142static inline void enable_mmio(void)
143{
144 int tmp;
145
146 outb(0x0B,0x3C4);
147 inb(0x3C5); // Set NEW mode
148 outb(SR0E,0x3C4); // write enable a lot of extended ports
149 outb(0x80,0x3C5);
150
151 outb(SR11,0x3C4); // write enable those extended ports that
152 outb(0x87,0x3C5); // are not affected by SR0E_New
153
154 outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2
155 tmp=inb(0x3d5) & 0xBF;
156 outb(CR1E,0x3d4);
157 outb(tmp,0x3d5);
158
159 outb(CR39,0x3D4);
160 outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
161}
162
163//=================================================
164//
165// Set pixel clock VCLK1
166// - multipliers set elswhere
167// - freq in units of 0.01 MHz
168//
169//=================================================
170
171static void set_vclk(struct cyblafb_par *par, int freq)
172{
173 u32 m,n,k;
174 int f,fi,d,di;
175 u8 lo=0,hi=0;
176
177 d = 2000;
178 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
179 for(m = 0;m<64;m++)
180 for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
181 fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
182 if ((di = abs(fi - freq)) < d) {
183 d = di;
184 f = fi;
185 lo = (u8) n;
186 hi = (u8) ((k<<6) | m);
187 }
188 }
189 write3C4(SR19,hi);
190 write3C4(SR18,lo);
191 if(verbosity > 1)
192 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
193 freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
194}
195
196//================================================
197//
198// Cyberblade specific Graphics Engine (GE) setup
199//
200//================================================
201
202static void cyblafb_setup_GE(int pitch,int bpp)
203{
204 int base = (pitch>>3)<<20;
205
206 switch (bpp) {
207 case 8: base |= (0<<29); break;
208 case 15: base |= (5<<29); break;
209 case 16: base |= (1<<29); break;
210 case 24:
211 case 32: base |= (2<<29); break;
212 }
213
214 write3X4(CR36,0x90); // reset GE
215 write3X4(CR36,0x80); // enable GE
216
217 out32(GE24,1<<7); // reset all GE pointers
218 out32(GE24,0);
219
220 write3X4(CR2D,0x00); // GE Timinigs, no delays
221
222 out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
223 out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
224 out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
225 out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
226 out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
227 out32(GECC,base); // Source Stride / Buffer Base 1, p 133
228 out32(GED0,base); // Source Stride / Buffer Base 2, p 133
229 out32(GED4,base); // Source Stride / Buffer Base 3, p 133
230 out32(GE6C,0); // Pattern and Style, p 129, ok
231}
232
233//=====================================================================
234//
235// Although this is a .fb_sync function that could be enabled in
236// cyblafb_ops, we do not include it there. We sync immediately before
237// new GE operations to improve performance.
238//
239//=====================================================================
240
241static int cyblafb_sync(struct fb_info *info)
242{
243 int status, i=100000;
244 while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
245 i--;
246
247 if (i == 0) {
248 // The timeout might be caused by disabled mmio.
249 // Cause:
250 // - bit CR39 & 1 == 0 upon return, X trident driver bug
251 // - kdm bug (KD_GRAPHICS not set on first switch)
252 // - kernel design flaw (it believes in the correctness
253 // of kdm/X
254 // So we make sure that mmio is enabled first ...
255 enable_mmio();
256// show_trace(NULL,&status);
257 i=1000000;
258 while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
259 i--;
260 if (i == 0) {
261 output("GE Timeout, status: %x\n",status);
262 if(status & 0x80000000)
263 output("Bresenham Engine : Busy\n");
264 if(status & 0x40000000)
265 output("Setup Engine : Busy\n");
266 if(status & 0x20000000)
267 output("SP / DPE : Busy\n");
268 if(status & 0x10000000)
269 output("Memory Interface : Busy\n");
270 if(status & 0x08000000)
271 output("Com Lst Proc : Busy\n");
272 if(status & 0x04000000)
273 output("Block Write : Busy\n");
274 if(status & 0x02000000)
275 output("Command Buffer : Full\n");
276 if(status & 0x01000000)
277 output("RESERVED : Busy\n");
278 if(status & 0x00800000)
279 output("PCI Write Buffer : Busy\n");
280 cyblafb_setup_GE(info->var.xres,
281 info->var.bits_per_pixel);
282 }
283 }
284
285 return 0;
286}
287
288//==============================
289//
290// Cyberblade specific fillrect
291//
292//==============================
293
294static void cyblafb_fillrect(struct fb_info * info,
295 const struct fb_fillrect *fr)
296{
297 int bpp = info->var.bits_per_pixel;
298 int col;
299
300 switch (bpp) {
301 default:
302 case 8: col = fr->color;
303 col |= col <<8;
304 col |= col <<16;
305 break;
306 case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
307 col |= col <<16;
308 break;
309 case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
310 break;
311 }
312
313 cyblafb_sync(info);
314
315 out32(GE60,col);
316 out32(GE48,fr->rop ? 0x66:ROP_S);
317 out32(GE44,0x20000000|1<<19|1<<4|2<<2);
318 out32(GE08,point(fr->dx,fr->dy));
319 out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
320
321}
322
323//==============================
324//
325// Cyberblade specific copyarea
326//
327//==============================
328
329static void cyblafb_copyarea(struct fb_info *info,
330 const struct fb_copyarea *ca)
331{
332 __u32 s1,s2,d1,d2;
333 int direction;
334
335 s1 = point(ca->sx,ca->sy);
336 s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
337 d1 = point(ca->dx,ca->dy);
338 d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
339 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
340 direction = 0;
341 else
342 direction = 2;
343
344 cyblafb_sync(info);
345
346 out32(GE44,0xa0000000|1<<19|1<<2|direction);
347 out32(GE00,direction?s2:s1);
348 out32(GE04,direction?s1:s2);
349 out32(GE08,direction?d2:d1);
350 out32(GE0C,direction?d1:d2);
351
352}
353
354//=======================================================================
355//
356// Cyberblade specific imageblit
357//
358// Accelerated for the most usual case, blitting 1-bit deep character
359// character images. Everything else is passed to the generic imageblit.
360//
361//=======================================================================
362
363static void cyblafb_imageblit(struct fb_info *info,
364 const struct fb_image *image)
365{
366
367 u32 fgcol, bgcol;
368
369 int i;
370 int bpp = info->var.bits_per_pixel;
371 int index = 0;
372 int index_end=image->height * image->width / 8;
373 int width_dds=image->width / 32;
374 int width_dbs=image->width % 32;
375
376 if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
377 image->width % 8 != 0 || image->width == 0 || image->height == 0) {
378 cfb_imageblit(info,image);
379 return;
380 }
381
382 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
383 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
384 fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
385 bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
386 } else {
387 fgcol = image->fg_color;
388 bgcol = image->bg_color;
389 }
390
391 switch (bpp) {
392 case 8:
393 fgcol |= fgcol <<8; fgcol |= fgcol <<16;
394 bgcol |= bgcol <<8; bgcol |= bgcol <<16;
395 break;
396 case 16:
397 fgcol |= fgcol <<16;
398 bgcol |= bgcol <<16;
399 break;
400 default:
401 break;
402 }
403
404 cyblafb_sync(info);
405
406 out32(GE60,fgcol);
407 out32(GE64,bgcol);
408 out32(GE44,0xa0000000 | 1<<20 | 1<<19);
409 out32(GE08,point(image->dx,image->dy));
410 out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
411
412 while(index < index_end) {
413 for(i=0;i<width_dds;i++) {
414 out32(GE9C,*((u32*) ((u32)image->data + index)));
415 index+=4;
416 }
417 switch(width_dbs) {
418 case 0: break;
419 case 8: out32(GE9C,*((u8*)((u32)image->data+index)));
420 index+=1;
421 break;
422 case 16: out32(GE9C,*((u16*)((u32)image->data+index)));
423 index+=2;
424 break;
425 case 24: out32(GE9C,(u32)(*((u16*)((u32)image->data+index))) |
426 (u32)(*((u8*)((u32)image->data+index+2)))<<16);
427 index+=3;
428 break;
429 }
430 }
431}
432
433//==========================================================
434//
435// Check if video mode is acceptable. We change var->??? if
436// video mode is slightly off or return error otherwise.
437// info->??? must not be changed!
438//
439//==========================================================
440
441static int cyblafb_check_var(struct fb_var_screeninfo *var,
442 struct fb_info *info)
443{
444 int bpp = var->bits_per_pixel;
445 int s,t,maxvyres;
446
447 //
448 // we try to support 8, 16, 24 and 32 bpp modes,
449 // default to 8
450 //
451 // there is a 24 bpp mode, but for now we change requests to 32 bpp
452 // (This is what tridentfb does ... will be changed in the future)
453 //
454 //
455 if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
456 bpp = 8;
457 if (bpp == 24 )
458 bpp = var->bits_per_pixel = 32;
459
460 //
461 // interlaced modes are broken, fail if one is requested
462 //
463 if (var->vmode & FB_VMODE_INTERLACED)
464 return -EINVAL;
465
466 //
467 // fail if requested resolution is higher than physical
468 // flatpanel resolution
469 //
470 if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
471 return -EINVAL;
472
473 //
474 // xres != xres_virtual is broken, fail if such an
475 // unusual mode is requested
476 //
477 if (var->xres != var->xres_virtual)
478 return -EINVAL;
479
480 //
481 // we do not allow vclk to exceed 230 MHz
482 //
483 if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
484 return -EINVAL;
485
486 //
487 // calc max yres_virtual that would fit in memory
488 // and max yres_virtual that could be used for scrolling
489 // and use minimum of the results as maxvyres
490 //
491 // adjust vyres_virtual to maxvyres if necessary
492 // fail if requested yres is bigger than maxvyres
493 //
494 s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
495 t = info->fix.smem_len / (var->xres * bpp/8);
496 maxvyres = t < s ? t : s;
497 if (maxvyres < var->yres_virtual)
498 var->yres_virtual=maxvyres;
499 if (maxvyres < var->yres)
500 return -EINVAL;
501
502 switch (bpp) {
503 case 8:
504 var->red.offset = 0;
505 var->green.offset = 0;
506 var->blue.offset = 0;
507 var->red.length = 6;
508 var->green.length = 6;
509 var->blue.length = 6;
510 break;
511 case 16:
512 var->red.offset = 11;
513 var->green.offset = 5;
514 var->blue.offset = 0;
515 var->red.length = 5;
516 var->green.length = 6;
517 var->blue.length = 5;
518 break;
519 case 32:
520 var->red.offset = 16;
521 var->green.offset = 8;
522 var->blue.offset = 0;
523 var->red.length = 8;
524 var->green.length = 8;
525 var->blue.length = 8;
526 break;
527 default:
528 return -EINVAL;
529 }
530
531 return 0;
532
533}
534
535//=====================================================================
536//
537// Pan the display
538//
539// The datasheets defines crt start address to be 20 bits wide and
540// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
541// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
542// it, so it is also safe to be used here. BTW: datasheet CR0E on page
543// 90 really is CR1E, the real CRE is documented on page 72.
544//
545//=====================================================================
546
547static int cyblafb_pan_display(struct fb_var_screeninfo *var,
548 struct fb_info *info)
549{
550 unsigned int offset;
551
552 offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
553 info->var.xoffset = var->xoffset;
554 info->var.yoffset = var->yoffset;
555
556 write3X4(CR0D,offset & 0xFF);
557 write3X4(CR0C,(offset & 0xFF00) >> 8);
558 write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
559 write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
560 write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
561
562 return 0;
563}
564
565//============================================
566//
567// This will really help in case of a bug ...
568// dump most gaphics core registers.
569//
570//============================================
571
572static void regdump(struct cyblafb_par *par)
573{
574 int i;
575
576 if (verbosity < 2)
577 return;
578
579 printk("\n");
580 for(i=0; i<=0xff; i++) {
581 outb(i,0x3d4);
582 printk("CR%02x=%02x ",i,inb(0x3d5));
583 if (i%16==15)
584 printk("\n");
585 }
586
587 outb(0x30,0x3ce);
588 outb(inb(0x3cf) | 0x40,0x3cf);
589 for(i=0; i<=0x1f; i++) {
590 if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
591 outb(i,0x3d4);
592 printk("CR%02x=%02x ",i,inb(0x3d5));
593 } else
594 printk("------- ");
595 if (i%16==15)
596 printk("\n");
597 }
598 outb(0x30,0x3ce);
599 outb(inb(0x3cf) & 0xbf,0x3cf);
600
601 printk("\n");
602 for(i=0; i<=0x7f; i++) {
603 outb(i,0x3ce);
604 printk("GR%02x=%02x ",i,inb(0x3cf));
605 if (i%16==15)
606 printk("\n");
607 }
608
609 printk("\n");
610 for(i=0; i<=0xff; i++) {
611 outb(i,0x3c4);
612 printk("SR%02x=%02x ",i,inb(0x3c5));
613 if (i%16==15)
614 printk("\n");
615 }
616
617 printk("\n");
618 for(i=0; i <= 0x1F; i++) {
619 inb(0x3da); // next access is index!
620 outb(i,0x3c0);
621 printk("AR%02x=%02x ",i,inb(0x3c1));
622 if (i%16==15)
623 printk("\n");
624 }
625 printk("\n");
626
627 inb(0x3DA); // reset internal flag to 3c0 index
628 outb(0x20,0x3C0); // enable attr
629
630 return;
631}
632
633//======================================
634//
635// Set hardware to requested video mode
636//
637//======================================
638
639static int cyblafb_set_par(struct fb_info *info)
640{
641 struct cyblafb_par *par = info->par;
642 u32
643 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
644 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
645 struct fb_var_screeninfo *var = &info->var;
646 int bpp = var->bits_per_pixel;
647 int i;
648
649 if (verbosity > 0)
650 output("Switching to new mode: "
651 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
652 var->xres,var->yres,var->xres_virtual,
653 var->yres_virtual,var->bits_per_pixel,var->pixclock,
654 var->left_margin,var->right_margin,var->upper_margin,
655 var->lower_margin,var->hsync_len,var->vsync_len);
656
657 htotal = (var->xres + var->left_margin + var->right_margin +
658 var->hsync_len) / 8 - 5;
659 hdispend = var->xres/8 - 1;
660 hsyncstart = (var->xres + var->right_margin)/8;
661 hsyncend = var->hsync_len/8;
662 hblankstart = hdispend + 1;
663 hblankend = htotal + 3; // should be htotal + 5, bios does it this way
664 preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
665
666 vtotal = var->yres + var->upper_margin + var->lower_margin +
667 var->vsync_len - 2;
668 vdispend = var->yres - 1;
669 vsyncstart = var->yres + var->lower_margin;
670 vblankstart = var->yres;
671 vblankend = vtotal; // should be vtotal + 2, but bios does it this way
672 vsyncend = var->vsync_len;
673
674 enable_mmio(); // necessary! ... check X ...
675
676 write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
677
678 write3CE(GR30,8);
679
680 if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
681
682 // stretch or center ?
683
684 out8(0x3C2,0xEB);
685
686 write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
687
688 if (center) {
689 write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
690 write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
691 }
692 else if (stretch) {
693 write3CE(GR5D,0);
694 write3CE(GR52,(read3CE(GR52) & 0x7C) | 1);
695 write3CE(GR53,(read3CE(GR53) & 0x7C) | 1);
696 }
697
698 } else {
699 out8(0x3C2,0x2B);
700 write3CE(GR30,8);
701 }
702
703 //
704 // Setup CRxx regs
705 //
706
707 write3X4(CR00,htotal & 0xFF);
708 write3X4(CR01,hdispend & 0xFF);
709 write3X4(CR02,hblankstart & 0xFF);
710 write3X4(CR03,hblankend & 0x1F);
711 write3X4(CR04,hsyncstart & 0xFF);
712 write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
713 write3X4(CR06,vtotal & 0xFF);
714 write3X4(CR07,(vtotal & 0x100) >> 8 |
715 (vdispend & 0x100) >> 7 |
716 (vsyncstart & 0x100) >> 6 |
717 (vblankstart & 0x100) >> 5 |
718 0x10 |
719 (vtotal & 0x200) >> 4 |
720 (vdispend & 0x200) >> 3 |
721 (vsyncstart & 0x200) >> 2);
722 write3X4(CR08,0);
723 write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
724 ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
725 write3X4(CR0A,0); // Init to some reasonable default
726 write3X4(CR0B,0); // Init to some reasonable default
727 write3X4(CR0C,0); // Offset 0
728 write3X4(CR0D,0); // Offset 0
729 write3X4(CR0E,0); // Init to some reasonable default
730 write3X4(CR0F,0); // Init to some reasonable default
731 write3X4(CR10,vsyncstart & 0xFF);
732 write3X4(CR11,(vsyncend & 0x0F));
733 write3X4(CR12,vdispend & 0xFF);
734 write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF);
735 write3X4(CR14,0x40); // double word mode
736 write3X4(CR15,vblankstart & 0xFF);
737 write3X4(CR16,vblankend & 0xFF);
738 write3X4(CR17,0xC3);
739 write3X4(CR18,0xFF);
740 // CR19: needed for interlaced modes ... ignore it for now
741 write3X4(CR1A,0x07); // Arbitration Control Counter 1
742 write3X4(CR1B,0x07); // Arbitration Control Counter 2
743 write3X4(CR1C,0x07); // Arbitration Control Counter 3
744 write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-)
745 write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
746 // CR1F: do not set, contains BIOS info about memsize
747 write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode
748 write3X4(CR21,0x20); // enable linear memory access
749 // CR22: RO cpu latch readback
750 // CR23: ???
751 // CR24: RO AR flag state
752 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
753 // CR26: ???
754 write3X4(CR27,(vdispend & 0x400) >> 6 |
755 (vsyncstart & 0x400) >> 5 |
756 (vblankstart & 0x400) >> 4 |
757 (vtotal & 0x400) >> 3 |
758 0x8);
759 // CR28: ???
760 write3X4(CR29,(read3X4(CR29) & 0xCF) |
761 ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4));
762 write3X4(CR2A,read3X4(CR2A) | 0x40);
763 write3X4(CR2B,(htotal & 0x100) >> 8 |
764 (hdispend & 0x100) >> 7 |
765 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
766 (hsyncstart & 0x100) >> 5 |
767 (hblankstart & 0x100) >> 4);
768 // CR2C: ???
769 // CR2D: initialized in cyblafb_setup_GE()
770 write3X4(CR2F,0x92); // conservative, better signal quality
771 // CR30: reserved
772 // CR31: reserved
773 // CR32: reserved
774 // CR33: reserved
775 // CR34: disabled in CR36
776 // CR35: disabled in CR36
777 // CR36: initialized in cyblafb_setup_GE
778 // CR37: i2c, ignore for now
779 write3X4(CR38,(bpp == 8) ? 0x00 : //
780 (bpp == 16) ? 0x05 : // highcolor
781 (bpp == 24) ? 0x29 : // packed 24bit truecolor
782 (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
783 write3X4(CR39,0x01 | // MMIO enable
784 (pcirb ? 0x02 : 0) | // pci read burst enable
785 (pciwb ? 0x04 : 0)); // pci write burst enable
786 write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase
787 (pcirr ? 0x40 : 0) | // pci read retry enable
788 (pciwr ? 0x80 : 0)); // pci write retry enable
789 write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0);
790 write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
791 write3X4(CR58,0x82); // Bios does this .... don't know more
792 //
793 // Setup SRxx regs
794 //
795 write3C4(SR00,3);
796 write3C4(SR01,1); //set char clock 8 dots wide
797 write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode
798 write3C4(SR03,0); //no character map select
799 write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4
800
801 out8(0x3C4,0x0b);
802 in8(0x3C5); // Set NEW mode
803 write3C4(SR0D,0x00); // test ... check
804
805 set_vclk(par,(bpp==32 ? 200000000 : 100000000)/
806 info->var.pixclock); //SR18,SR19
807
808 //
809 // Setup GRxx regs
810 //
811 write3CE(GR00,0x00); // test ... check
812 write3CE(GR01,0x00); // test ... check
813 write3CE(GR02,0x00); // test ... check
814 write3CE(GR03,0x00); // test ... check
815 write3CE(GR04,0x00); // test ... check
816 write3CE(GR05,0x40); // no CGA compat,allow 256 col
817 write3CE(GR06,0x05); // graphics mode
818 write3CE(GR07,0x0F); // planes?
819 write3CE(GR08,0xFF); // test ... check
820 write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4
821 write3CE(GR20,0xC0); // test ... check
822 write3CE(GR2F,0xA0); // PCLK = VCLK, no skew,
823
824 //
825 // Setup ARxx regs
826 //
827 for(i = 0;i < 0x10;i++) // set AR00 .. AR0f
828 write3C0(i,i);
829 write3C0(AR10,0x41); // graphics mode and support 256 color modes
830 write3C0(AR12,0x0F); // planes
831 write3C0(AR13,0); // horizontal pel panning
832 in8(0x3DA); // reset internal flag to 3c0 index
833 out8(0x3C0,0x20); // enable attr
834
835 //
836 // Setup hidden RAMDAC command register
837 //
838 in8(0x3C8); // these reads are
839 in8(0x3C6); // necessary to
840 in8(0x3C6); // unmask the RAMDAC
841 in8(0x3C6); // command reg, otherwise
842 in8(0x3C6); // we would write the pixelmask reg!
843 out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors
844 (bpp == 15) ? 0x10 : //
845 (bpp == 16) ? 0x30 : // hicolor
846 (bpp == 24) ? 0xD0 : // truecolor
847 (bpp == 32) ? 0xD0 : 0); // truecolor
848 in8(0x3C8);
849
850 //
851 // GR31 is not mentioned in the datasheet
852 //
853 if (displaytype == DISPLAY_FP)
854 write3CE(GR31,(read3CE(GR31) & 0x8F) |
855 ((info->var.yres > 1024) ? 0x50 :
856 (info->var.yres > 768) ? 0x30 :
857 (info->var.yres > 600) ? 0x20 :
858 (info->var.yres > 480) ? 0x10 : 0));
859
860 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
861 : FB_VISUAL_TRUECOLOR;
862 info->fix.line_length = info->var.xres * (bpp >> 3);
863 info->cmap.len = (bpp == 8) ? 256: 16;
864
865 //
866 // init acceleration engine
867 //
868 cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel);
869
870 regdump(par);
871
872 return 0;
873}
874
875//========================
876//
877// Set one color register
878//
879//========================
880
881static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
882 unsigned blue, unsigned transp,
883 struct fb_info *info)
884{
885 int bpp = info->var.bits_per_pixel;
886
887 if (regno >= info->cmap.len)
888 return 1;
889
890 if (bpp == 8) {
891 out8(0x3C6,0xFF);
892 out8(0x3C8,regno);
893 out8(0x3C9,red>>10);
894 out8(0x3C9,green>>10);
895 out8(0x3C9,blue>>10);
896
897 } else if (bpp == 16) // RGB 565
898 ((u32*)info->pseudo_palette)[regno] =
899 (red & 0xF800) |
900 ((green & 0xFC00) >> 5) |
901 ((blue & 0xF800) >> 11);
902 else if (bpp == 32) // ARGB 8888
903 ((u32*)info->pseudo_palette)[regno] =
904 ((transp & 0xFF00) <<16) |
905 ((red & 0xFF00) << 8) |
906 ((green & 0xFF00)) |
907 ((blue & 0xFF00)>>8);
908
909 return 0;
910}
911
912//==========================================================
913//
914// Try blanking the screen. For flat panels it does nothing
915//
916//==========================================================
917
918static int cyblafb_blank(int blank_mode, struct fb_info *info)
919{
920 unsigned char PMCont,DPMSCont;
921
922 if (displaytype == DISPLAY_FP)
923 return 0;
924
925 out8(0x83C8,0x04); // DPMS Control
926 PMCont = in8(0x83C6) & 0xFC;
927
928 DPMSCont = read3CE(GR23) & 0xFC;
929
930 switch (blank_mode)
931 {
932 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
933 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
934 PMCont |= 0x03;
935 DPMSCont |= 0x00;
936 break;
937 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
938 PMCont |= 0x02;
939 DPMSCont |= 0x01;
940 break;
941 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
942 PMCont |= 0x02;
943 DPMSCont |= 0x02;
944 break;
945 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
946 PMCont |= 0x00;
947 DPMSCont |= 0x03;
948 break;
949 }
950
951 write3CE(GR23,DPMSCont);
952 out8(0x83C8,4);
953 out8(0x83C6,PMCont);
954 //
955 // let fbcon do a softblank for us
956 //
957 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
958}
959
960static struct fb_ops cyblafb_ops __devinitdata = {
961 .owner = THIS_MODULE,
962 .fb_setcolreg = cyblafb_setcolreg,
963 .fb_pan_display = cyblafb_pan_display,
964 .fb_blank = cyblafb_blank,
965 .fb_check_var = cyblafb_check_var,
966 .fb_set_par = cyblafb_set_par,
967 .fb_fillrect = cyblafb_fillrect,
968 .fb_copyarea= cyblafb_copyarea,
969 .fb_imageblit = cyblafb_imageblit,
970 .fb_cursor = soft_cursor,
971};
972
973//==========================================================================
974//
975// getstartupmode() decides about the inital video mode
976//
977// There is no reason to use modedb, a lot of video modes there would
978// need altered timings to display correctly. So I decided that it is much
979// better to provide a limited optimized set of modes plus the option of
980// using the mode in effect at startup time (might be selected using the
981// vga=??? paramter). After that the user might use fbset to select any
982// mode he likes, check_var will not try to alter geometry parameters as
983// it would be necessary otherwise.
984//
985//==========================================================================
986
987static int __devinit getstartupmode(struct fb_info *info)
988{
989 u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
990 vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend,
991 cr00,cr01,cr02,cr03,cr04,cr05,cr2b,
992 cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27,
993 cr38,
994 sr0d,sr18,sr19,
995 gr0f,
996 fi,pxclkdiv,vclkdiv,tmp,i;
997
998 struct modus {
999 int xres; int yres; int vyres; int bpp; int pxclk;
1000 int left_margin; int right_margin; int upper_margin;
1001 int lower_margin; int hsync_len; int vsync_len;
1002 } modedb[5] = {
1003 { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0},
1004 { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3},
1005 { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11},
1006 {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3},
1007 {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3}
1008 };
1009
1010 outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5);
1011 outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5);
1012 outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5);
1013 outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5);
1014 outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5);
1015 outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5);
1016 outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5);
1017 outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5);
1018 outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5);
1019 outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5);
1020 outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf);
1021
1022 htotal = cr00 | (cr2b & 0x01) << 8;
1023 hdispend = cr01 | (cr2b & 0x02) << 7;
1024 hblankstart = cr02 | (cr2b & 0x10) << 4;
1025 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1026 hsyncstart = cr04 | (cr2b & 0x08) << 5;
1027 hsyncend = cr05 & 0x1f;
1028
1029 modedb[0].xres = hblankstart * 8;
1030 modedb[0].hsync_len = hsyncend * 8;
1031 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1032 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
1033 modedb[0].right_margin - modedb[0].hsync_len;
1034
1035 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1036 | (cr27 & 0x80) << 3;
1037 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1038 | (cr27 & 0x10) << 6;
1039 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1040 | (cr27 & 0x20) << 5;
1041 vsyncend = cr11 & 0x0f;
1042 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
1043 | (cr27 & 0x40) << 4;
1044 vblankend = cr16;
1045
1046 modedb[0].yres = vdispend + 1;
1047 modedb[0].vsync_len = vsyncend;
1048 modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1049 modedb[0].upper_margin = vtotal - modedb[0].yres -
1050 modedb[0].lower_margin - modedb[0].vsync_len + 2;
1051
1052 tmp = cr38 & 0x3c;
1053 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
1054 tmp == 8 ? 32 : 8;
1055
1056 fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12;
1057 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1058 tmp = sr0d & 0x06;
1059 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1060 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1061
1062 if (verbosity > 0)
1063 output("detected startup mode: "
1064 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
1065 modedb[0].xres,modedb[0].yres,modedb[0].xres,
1066 modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin,
1067 modedb[0].right_margin,modedb[0].upper_margin,
1068 modedb[0].lower_margin,modedb[0].hsync_len,
1069 modedb[0].vsync_len);
1070
1071 //
1072 // We use this goto target in case of a failed check_var. No, I really
1073 // do not want to do it in another way!
1074 //
1075
1076 tryagain:
1077
1078 i = (mode == NULL) ? 0 :
1079 !strncmp(mode,"640x480",7) ? 1 :
1080 !strncmp(mode,"800x600",7) ? 2 :
1081 !strncmp(mode,"1024x768",8) ? 3 :
1082 !strncmp(mode,"1280x1024",9) ? 4 : 0;
1083
1084 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1085
1086 if(i==0) {
1087 info->var.pixclock = modedb[i].pxclk;
1088 info->var.bits_per_pixel = modedb[i].bpp;
1089 } else {
1090 info->var.pixclock = (100000000 /
1091 ((modedb[i].left_margin + modedb[i].xres +
1092 modedb[i].right_margin + modedb[i].hsync_len
1093 ) * (
1094 modedb[i].upper_margin + modedb[i].yres +
1095 modedb[i].lower_margin + modedb[i].vsync_len
1096 ) *
1097 ref / 10000
1098 ));
1099 info->var.bits_per_pixel = bpp;
1100 }
1101
1102 info->var.left_margin = modedb[i].left_margin;
1103 info->var.right_margin = modedb[i].right_margin;
1104 info->var.xres = modedb[i].xres;
1105 info->var.xres_virtual = modedb[i].xres;
1106 info->var.xoffset = 0;
1107 info->var.hsync_len = modedb[i].hsync_len;
1108 info->var.upper_margin = modedb[i].upper_margin;
1109 info->var.yres = modedb[i].yres;
1110 info->var.yres_virtual = modedb[i].vyres;
1111 info->var.yoffset = 0;
1112 info->var.lower_margin = modedb[i].lower_margin;
1113 info->var.vsync_len = modedb[i].vsync_len;
1114 info->var.sync = 0;
1115 info->var.vmode = FB_VMODE_NONINTERLACED;
1116
1117 if(cyblafb_check_var(&info->var,info)) {
1118 // 640x480-8@75 should really never fail. One case would
1119 // be fp == 1 and nativex < 640 ... give up then
1120 if(i==1 && bpp == 8 && ref == 75){
1121 output("Can't find a valid mode :-(\n");
1122 return -EINVAL;
1123 }
1124 // Our detected mode is unlikely to fail. If it does,
1125 // try 640x480-8@75 ...
1126 if(i==0) {
1127 mode="640x480";
1128 bpp=8;
1129 ref=75;
1130 output("Detected mode failed check_var! "
1131 "Trying 640x480-8@75\n");
1132 goto tryagain;
1133 }
1134 // A specified video mode failed for some reason.
1135 // Try the startup mode first
1136 output("Specified mode '%s' failed check! "
1137 "Falling back to startup mode.\n",mode);
1138 mode=NULL;
1139 goto tryagain;
1140 }
1141
1142 return 0;
1143
1144}
1145
1146//========================================================
1147//
1148// Detect activated memory size. Undefined values require
1149// memsize parameter.
1150//
1151//========================================================
1152
1153static unsigned int __devinit get_memsize(void)
1154{
1155 unsigned char tmp;
1156 unsigned int k;
1157
1158 if (memsize)
1159 k = memsize * Kb;
1160 else {
1161 tmp = read3X4(CR1F) & 0x0F;
1162 switch (tmp) {
1163 case 0x03: k = 1 * Mb; break;
1164 case 0x07: k = 2 * Mb; break;
1165 case 0x0F: k = 4 * Mb; break;
1166 case 0x04: k = 8 * Mb; break;
1167 default:
1168 k = 1 * Mb;
1169 output("Unknown memory size code %x in CR1F."
1170 " We default to 1 Mb for now, please"
1171 " do provide a memsize parameter!\n",
1172 tmp);
1173 }
1174 }
1175
1176 if (verbosity > 0)
1177 output("framebuffer size = %d Kb\n",k/Kb);
1178 return k;
1179}
1180
1181//=========================================================
1182//
1183// Detect if a flat panel monitor connected to the special
1184// interface is active. Override is possible by fp and crt
1185// parameters.
1186//
1187//=========================================================
1188
1189static unsigned int __devinit get_displaytype(void)
1190{
1191 if (fp)
1192 return DISPLAY_FP;
1193 if (crt)
1194 return DISPLAY_CRT;
1195 return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
1196}
1197
1198//=====================================
1199//
1200// Get native resolution of flat panel
1201//
1202//=====================================
1203
1204static int __devinit get_nativex(void)
1205{
1206 int x,y,tmp;
1207
1208 if (nativex)
1209 return nativex;
1210
1211 tmp = (read3CE(GR52) >> 4) & 3;
1212
1213 switch (tmp) {
1214 case 0: x = 1280; y = 1024; break;
1215 case 2: x = 1024; y = 768; break;
1216 case 3: x = 800; y = 600; break;
1217 case 4: x = 1400; y = 1050; break;
1218 case 1:
1219 default: x = 640; y = 480; break;
1220 }
1221
1222 if (verbosity > 0)
1223 output("%dx%d flat panel found\n",x,y);
1224 return x;
1225}
1226
1227static int __devinit cybla_pci_probe(struct pci_dev * dev,
1228 const struct pci_device_id * id)
1229{
1230 struct fb_info *info;
1231 struct cyblafb_par *par;
1232
1233 info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev);
1234
1235 if (!info)
1236 goto errout_alloc;
1237
1238 par = info->par;
1239 par->ops = cyblafb_ops;
1240
1241 info->fix = cyblafb_fix;
1242 info->fbops = &par->ops;
1243 info->fix = cyblafb_fix;
1244
1245 if (pci_enable_device(dev)) {
1246 output("could not enable device!\n");
1247 goto errout_enable;
1248 }
1249
1250 // might already be requested by vga console or vesafb,
1251 // so we do care about success
1252 request_region(0x3c0,32,"cyblafb");
1253
1254 //
1255 // Graphics Engine Registers
1256 //
1257 request_region(GEBase,0x100,"cyblafb");
1258
1259 regdump(par);
1260
1261 enable_mmio();
1262
1263 // setup MMIO region
1264 info->fix.mmio_start = pci_resource_start(dev,1);
1265 info->fix.mmio_len = 0x20000;
1266
1267 if (!request_mem_region(info->fix.mmio_start,
1268 info->fix.mmio_len,"cyblafb")) {
1269 output("request_mem_region failed for mmio region!\n");
1270 goto errout_mmio_reqmem;
1271 }
1272
1273 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1274
1275 if (!io_virt) {
1276 output("ioremap failed for mmio region\n");
1277 goto errout_mmio_remap;
1278 }
1279
1280 // setup framebuffer memory ... might already be requested
1281 // by vesafb. Not to fail in case of an unsuccessful request
1282 // is useful for the development cycle
1283 info->fix.smem_start = pci_resource_start(dev,0);
1284 info->fix.smem_len = get_memsize();
1285
1286 if (!request_mem_region(info->fix.smem_start,
1287 info->fix.smem_len,"cyblafb")) {
1288 output("request_mem_region failed for smem region!\n");
1289 if (!vesafb)
1290 goto errout_smem_req;
1291 }
1292
1293 info->screen_base = ioremap_nocache(info->fix.smem_start,
1294 info->fix.smem_len);
1295
1296 if (!info->screen_base) {
1297 output("ioremap failed for smem region\n");
1298 goto errout_smem_remap;
1299 }
1300
1301 displaytype = get_displaytype();
1302
1303 if(displaytype == DISPLAY_FP)
1304 nativex = get_nativex();
1305
1306 //
1307 // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
1308 // FBINFO_PARTIAL_PAN_OK .... is not ok
1309 // FBINFO_READS_FAST .... is necessary for optimal scrolling
1310 //
1311 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
1312 | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
1313 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST;
1314
1315 info->pseudo_palette = par->pseudo_pal;
1316
1317 if(getstartupmode(info))
1318 goto errout_findmode;
1319
1320 fb_alloc_cmap(&info->cmap,256,0);
1321
1322 if (register_framebuffer(info)) {
1323 output("Could not register CyBla framebuffer\n");
1324 goto errout_register;
1325 }
1326
1327 pci_set_drvdata(dev,info);
1328
1329 //
1330 // normal exit and error paths
1331 //
1332
1333 return 0;
1334
1335 errout_register:
1336 errout_findmode:
1337 iounmap(info->screen_base);
1338 errout_smem_remap:
1339 release_mem_region(info->fix.smem_start,
1340 info->fix.smem_len);
1341 errout_smem_req:
1342 iounmap(io_virt);
1343 errout_mmio_remap:
1344 release_mem_region(info->fix.mmio_start,
1345 info->fix.mmio_len);
1346 errout_mmio_reqmem:
1347// release_region(0x3c0,32);
1348 errout_enable:
1349 framebuffer_release(info);
1350 errout_alloc:
1351 output("CyblaFB version %s aborting init.\n",VERSION);
1352 return -ENODEV;
1353}
1354
1355static void __devexit cybla_pci_remove(struct pci_dev *dev)
1356{
1357 struct fb_info *info = pci_get_drvdata(dev);
1358
1359 unregister_framebuffer(info);
1360 iounmap(io_virt);
1361 iounmap(info->screen_base);
1362 release_mem_region(info->fix.smem_start,info->fix.smem_len);
1363 release_mem_region(info->fix.mmio_start,info->fix.mmio_len);
1364 fb_dealloc_cmap(&info->cmap);
1365 framebuffer_release(info);
1366 output("CyblaFB version %s normal exit.\n",VERSION);
1367}
1368
1369//
1370// List of boards that we are trying to support
1371//
1372static struct pci_device_id cybla_devices[] = {
1373 {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
1374 {0,}
1375};
1376
1377MODULE_DEVICE_TABLE(pci,cybla_devices);
1378
1379static struct pci_driver cyblafb_pci_driver = {
1380 .name = "cyblafb",
1381 .id_table = cybla_devices,
1382 .probe = cybla_pci_probe,
1383 .remove = __devexit_p(cybla_pci_remove)
1384};
1385
1386//=============================================================
1387//
1388// kernel command line example:
1389//
1390// video=cyblafb:1280x1024,bpp=16,ref=50 ...
1391//
1392// modprobe command line example:
1393//
1394// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1395//
1396//=============================================================
1397
1398static int __devinit cyblafb_init(void)
1399{
1400#ifndef MODULE
1401 char *options = NULL;
1402 char *opt;
1403
1404 if (fb_get_options("cyblafb",&options))
1405 return -ENODEV;
1406
1407 if (options && *options)
1408 while((opt = strsep(&options,",")) != NULL ) {
1409 if (!*opt) continue;
1410 else if (!strncmp(opt,"bpp=",4))
1411 bpp = simple_strtoul(opt+4,NULL,0);
1412 else if (!strncmp(opt,"ref=",4))
1413 ref = simple_strtoul(opt+4,NULL,0);
1414 else if (!strncmp(opt,"fp",2))
1415 displaytype = DISPLAY_FP;
1416 else if (!strncmp(opt,"crt",3))
1417 displaytype = DISPLAY_CRT;
1418 else if (!strncmp(opt,"nativex=",8))
1419 nativex = simple_strtoul(opt+8,NULL,0);
1420 else if (!strncmp(opt,"center",6))
1421 center = 1;
1422 else if (!strncmp(opt,"stretch",7))
1423 stretch = 1;
1424 else if (!strncmp(opt,"pciwb=",6))
1425 pciwb = simple_strtoul(opt+6,NULL,0);
1426 else if (!strncmp(opt,"pcirb=",6))
1427 pcirb = simple_strtoul(opt+6,NULL,0);
1428 else if (!strncmp(opt,"pciwr=",6))
1429 pciwr = simple_strtoul(opt+6,NULL,0);
1430 else if (!strncmp(opt,"pcirr=",6))
1431 pcirr = simple_strtoul(opt+6,NULL,0);
1432 else if (!strncmp(opt,"memsize=",8))
1433 memsize = simple_strtoul(opt+8,NULL,0);
1434 else if (!strncmp(opt,"verbosity=",10))
1435 verbosity = simple_strtoul(opt+10,NULL,0);
1436 else if (!strncmp(opt,"vesafb",6))
1437 vesafb = 1;
1438 else
1439 mode = opt;
1440 }
1441#endif
1442 output("CyblaFB version %s initializing\n",VERSION);
1443 return pci_module_init(&cyblafb_pci_driver);
1444}
1445
1446static void __exit cyblafb_exit(void)
1447{
1448 pci_unregister_driver(&cyblafb_pci_driver);
1449}
1450
1451module_init(cyblafb_init);
1452module_exit(cyblafb_exit);
1453
1454MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1455MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1456MODULE_LICENSE("GPL");
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 698ca9232e73..81a6d9f188cf 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -1061,6 +1061,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
1061 1061
1062 chip_id = id->device; 1062 chip_id = id->device;
1063 1063
1064 if(chip_id == CYBERBLADEi1)
1065 output("*** Please do use cyblafb, Cyberblade/i1 support "
1066 "will soon be removed from tridentfb!\n");
1067
1068
1064 /* If PCI id is 0x9660 then further detect chip type */ 1069 /* If PCI id is 0x9660 then further detect chip type */
1065 1070
1066 if (chip_id == TGUI9660) { 1071 if (chip_id == TGUI9660) {