blob: 94a66c2d2cf528a7f9f31c1c209ef3841f6433a1 [file] [log] [blame]
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001/*
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 *
Knut Petersen9fa68ea2005-09-09 13:04:56 -070010 */
11
12#define CYBLAFB_DEBUG 0
Knut Petersen44637a12006-01-09 15:04:20 +010013#define CYBLAFB_KD_GRAPHICS_QUIRK 1
14
15#define CYBLAFB_PIXMAPSIZE 8192
Knut Petersen9fa68ea2005-09-09 13:04:56 -070016
Knut Petersen9fa68ea2005-09-09 13:04:56 -070017#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
Knut Petersen44637a12006-01-09 15:04:20 +010025#define VERSION "0.62"
Knut Petersen9fa68ea2005-09-09 13:04:56 -070026
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,
Knut Petersen44637a12006-01-09 15:04:20 +010035 .xpanstep = 1,
Knut Petersen9fa68ea2005-09-09 13:04:56 -070036 .ypanstep = 1,
Knut Petersen44637a12006-01-09 15:04:20 +010037 .ywrapstep = 1,
Knut Petersen9fa68ea2005-09-09 13:04:56 -070038 .visual = FB_VISUAL_PSEUDOCOLOR,
39 .accel = FB_ACCEL_NONE,
40};
41
42static char *mode __devinitdata = NULL;
43static int bpp __devinitdata = 8;
44static int ref __devinitdata = 75;
45static int fp __devinitdata;
46static int crt __devinitdata;
47static int memsize __devinitdata;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070048
Knut Petersen44637a12006-01-09 15:04:20 +010049static int basestride;
50static int vesafb;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070051static int nativex;
52static int center;
53static int stretch;
54static int pciwb = 1;
55static int pcirb = 1;
56static int pciwr = 1;
57static int pcirr = 1;
Knut Petersen44637a12006-01-09 15:04:20 +010058static int disabled;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070059static int verbosity;
60static int displaytype;
61
Knut Petersen44637a12006-01-09 15:04:20 +010062static void __iomem *io_virt; // iospace virtual memory address
Knut Petersen9fa68ea2005-09-09 13:04:56 -070063
Knut Petersen44637a12006-01-09 15:04:20 +010064module_param(mode, charp, 0);
65module_param(bpp, int, 0);
66module_param(ref, int, 0);
67module_param(fp, int, 0);
68module_param(crt, int, 0);
69module_param(nativex, int, 0);
70module_param(center, int, 0);
71module_param(stretch, int, 0);
72module_param(pciwb, int, 0);
73module_param(pcirb, int, 0);
74module_param(pciwr, int, 0);
75module_param(pcirr, int, 0);
76module_param(memsize, int, 0);
77module_param(verbosity, int, 0);
78
79//=========================================
80//
81// Well, we have to fix the upper layers.
82// Until this has been done, we work around
83// the bugs.
84//
85//=========================================
86
87#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
88 if (disabled) { \
89 printk("********\n");\
90 dump_stack();\
91 return val;\
92 }
93
94#elif CYBLAFB_KD_GRAPHICS_QUIRK
95#define KD_GRAPHICS_RETURN(val)\
96 if (disabled) {\
97 return val;\
98 }
99#else
100#define KD_GRAPHICS_RETURN(val)
101#endif
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700102
103//=========================================
104//
105// Port access macros for memory mapped io
106//
107//=========================================
108
Knut Petersen44637a12006-01-09 15:04:20 +0100109#define out8(r, v) writeb(v, io_virt + r)
110#define out32(r, v) writel(v, io_virt + r)
111#define in8(r) readb(io_virt + r)
112#define in32(r) readl(io_virt + r)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700113
114//======================================
115//
116// Hardware access inline functions
117//
118//======================================
119
Knut Petersen44637a12006-01-09 15:04:20 +0100120static inline u8 read3X4(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700121{
Knut Petersen44637a12006-01-09 15:04:20 +0100122 out8(0x3D4, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700123 return in8(0x3D5);
124}
125
Knut Petersen44637a12006-01-09 15:04:20 +0100126static inline u8 read3C4(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700127{
Knut Petersen44637a12006-01-09 15:04:20 +0100128 out8(0x3C4, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700129 return in8(0x3C5);
130}
131
Knut Petersen44637a12006-01-09 15:04:20 +0100132static inline u8 read3CE(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700133{
Knut Petersen44637a12006-01-09 15:04:20 +0100134 out8(0x3CE, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700135 return in8(0x3CF);
136}
137
Knut Petersen44637a12006-01-09 15:04:20 +0100138static inline void write3X4(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700139{
Knut Petersen44637a12006-01-09 15:04:20 +0100140 out8(0x3D4, reg);
141 out8(0x3D5, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700142}
143
Knut Petersen44637a12006-01-09 15:04:20 +0100144static inline void write3C4(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700145{
Knut Petersen44637a12006-01-09 15:04:20 +0100146 out8(0x3C4, reg);
147 out8(0x3C5, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700148}
149
Knut Petersen44637a12006-01-09 15:04:20 +0100150static inline void write3CE(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700151{
Knut Petersen44637a12006-01-09 15:04:20 +0100152 out8(0x3CE, reg);
153 out8(0x3CF, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700154}
155
Knut Petersen44637a12006-01-09 15:04:20 +0100156static inline void write3C0(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700157{
Knut Petersen44637a12006-01-09 15:04:20 +0100158 in8(0x3DA); // read to reset index
159 out8(0x3C0, reg);
160 out8(0x3C0, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700161}
162
163//=================================================
164//
165// Enable memory mapped io and unprotect registers
166//
167//=================================================
168
Knut Petersen44637a12006-01-09 15:04:20 +0100169static void enable_mmio(void)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700170{
Knut Petersen44637a12006-01-09 15:04:20 +0100171 u8 tmp;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700172
Knut Petersen44637a12006-01-09 15:04:20 +0100173 outb(0x0B, 0x3C4);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700174 inb(0x3C5); // Set NEW mode
Knut Petersen44637a12006-01-09 15:04:20 +0100175 outb(SR0E, 0x3C4); // write enable a lot of extended ports
176 outb(0x80, 0x3C5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700177
Knut Petersen44637a12006-01-09 15:04:20 +0100178 outb(SR11, 0x3C4); // write enable those extended ports that
179 outb(0x87, 0x3C5); // are not affected by SR0E_New
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700180
Knut Petersen44637a12006-01-09 15:04:20 +0100181 outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2
182 tmp = inb(0x3d5) & 0xBF;
183 outb(CR1E, 0x3d4);
184 outb(tmp, 0x3d5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700185
Knut Petersen44637a12006-01-09 15:04:20 +0100186 outb(CR39, 0x3D4);
187 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700188}
189
190//=================================================
191//
192// Set pixel clock VCLK1
Knut Petersen44637a12006-01-09 15:04:20 +0100193// - multipliers set elswhere
194// - freq in units of 0.01 MHz
195//
196// Hardware bug: SR18 >= 250 is broken for the
197// cyberblade/i1
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700198//
199//=================================================
200
201static void set_vclk(struct cyblafb_par *par, int freq)
202{
Knut Petersen44637a12006-01-09 15:04:20 +0100203 u32 m, n, k;
204 int f, fi, d, di;
205 u8 lo = 0, hi = 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700206
207 d = 2000;
208 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
Knut Petersen44637a12006-01-09 15:04:20 +0100209 for (m = 0; m < 64; m++)
210 for (n = 0; n < 250; n++) {
211 fi = (int)(((5864727 * (n + 8)) /
212 ((m + 2) * (1 << k))) >> 12);
213 if ((di = abs(fi - freq)) < d) {
214 d = di;
215 f = fi;
216 lo = (u8) n;
217 hi = (u8) ((k << 6) | m);
218 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700219 }
Knut Petersen44637a12006-01-09 15:04:20 +0100220 write3C4(SR19, hi);
221 write3C4(SR18, lo);
222 if (verbosity > 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700223 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
Knut Petersen44637a12006-01-09 15:04:20 +0100224 freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700225}
226
227//================================================
228//
229// Cyberblade specific Graphics Engine (GE) setup
230//
231//================================================
232
Knut Petersen44637a12006-01-09 15:04:20 +0100233static void cyblafb_setup_GE(int pitch, int bpp)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700234{
Knut Petersen44637a12006-01-09 15:04:20 +0100235 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700236
237 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100238 case 8:
239 basestride = ((pitch >> 3) << 20) | (0 << 29);
240 break;
241 case 15:
242 basestride = ((pitch >> 3) << 20) | (5 << 29);
243 break;
244 case 16:
245 basestride = ((pitch >> 3) << 20) | (1 << 29);
246 break;
247 case 24:
248 case 32:
249 basestride = ((pitch >> 3) << 20) | (2 << 29);
250 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700251 }
252
Knut Petersen44637a12006-01-09 15:04:20 +0100253 write3X4(CR36, 0x90); // reset GE
254 write3X4(CR36, 0x80); // enable GE
255 out32(GE24, 1 << 7); // reset all GE pointers by toggling
256 out32(GE24, 0); // d7 of GE24
257 write3X4(CR2D, 0x00); // GE Timinigs, no delays
258 out32(GE6C, 0); // Pattern and Style, p 129, ok
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700259}
260
261//=====================================================================
262//
Knut Petersen44637a12006-01-09 15:04:20 +0100263// Cyberblade specific syncing
264//
265// A timeout might be caused by disabled mmio.
266// Cause:
267// - bit CR39 & 1 == 0 upon return, X trident driver bug
268// - kdm bug (KD_GRAPHICS not set on first switch)
269// - kernel design flaw (it believes in the correctness
270// of kdm/X
271// First we try to sync ignoring that problem, as most of the
272// time that will succeed immediately and the enable_mmio()
273// would only degrade performance.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700274//
275//=====================================================================
276
277static int cyblafb_sync(struct fb_info *info)
278{
Knut Petersen44637a12006-01-09 15:04:20 +0100279 u32 status, i = 100000;
280
281 KD_GRAPHICS_RETURN(0);
282
283 while (((status = in32(GE20)) & 0xFe800000) && i != 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700284 i--;
285
286 if (i == 0) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700287 enable_mmio();
Knut Petersen44637a12006-01-09 15:04:20 +0100288 i = 1000000;
289 while (((status = in32(GE20)) & 0xFA800000) && i != 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700290 i--;
291 if (i == 0) {
Knut Petersen44637a12006-01-09 15:04:20 +0100292 output("GE Timeout, status: %x\n", status);
293 if (status & 0x80000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700294 output("Bresenham Engine : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100295 if (status & 0x40000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700296 output("Setup Engine : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100297 if (status & 0x20000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700298 output("SP / DPE : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100299 if (status & 0x10000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700300 output("Memory Interface : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100301 if (status & 0x08000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700302 output("Com Lst Proc : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100303 if (status & 0x04000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700304 output("Block Write : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100305 if (status & 0x02000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700306 output("Command Buffer : Full\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100307 if (status & 0x01000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700308 output("RESERVED : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100309 if (status & 0x00800000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700310 output("PCI Write Buffer : Busy\n");
311 cyblafb_setup_GE(info->var.xres,
312 info->var.bits_per_pixel);
313 }
314 }
315
316 return 0;
317}
318
319//==============================
320//
321// Cyberblade specific fillrect
322//
323//==============================
324
Knut Petersen44637a12006-01-09 15:04:20 +0100325static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700326{
Knut Petersen44637a12006-01-09 15:04:20 +0100327 u32 bpp = info->var.bits_per_pixel, col, desty, height;
328
329 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700330
331 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100332 default:
333 case 8:
334 col = fr->color;
335 col |= col << 8;
336 col |= col << 16;
337 break;
338 case 16:
339 col = ((u32 *) (info->pseudo_palette))[fr->color];
340 col |= col << 16;
341 break;
342 case 32:
343 col = ((u32 *) (info->pseudo_palette))[fr->color];
344 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700345 }
346
Knut Petersen44637a12006-01-09 15:04:20 +0100347 desty = fr->dy;
348 height = fr->height;
349 while (height) {
350 out32(GEB8, basestride | ((desty * info->var.xres_virtual *
351 bpp) >> 6));
352 out32(GE60, col);
353 out32(GE48, fr->rop ? 0x66 : ROP_S);
354 out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
355 out32(GE08, point(fr->dx, 0));
356 out32(GE0C, point(fr->dx + fr->width - 1,
357 height > 4096 ? 4095 : height - 1));
358 if (likely(height <= 4096))
359 return;
360 desty += 4096;
361 height -= 4096;
362 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700363}
364
Knut Petersen44637a12006-01-09 15:04:20 +0100365//================================================
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700366//
367// Cyberblade specific copyarea
368//
Knut Petersen44637a12006-01-09 15:04:20 +0100369// This function silently assumes that it never
370// will be called with width or height exceeding
371// 4096.
372//
373//================================================
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700374
Knut Petersen44637a12006-01-09 15:04:20 +0100375static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700376{
Knut Petersen44637a12006-01-09 15:04:20 +0100377 u32 s1, s2, d1, d2, direction;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700378
Knut Petersen44637a12006-01-09 15:04:20 +0100379 KD_GRAPHICS_RETURN();
380
381 s1 = point(ca->sx, 0);
382 s2 = point(ca->sx + ca->width - 1, ca->height - 1);
383 d1 = point(ca->dx, 0);
384 d2 = point(ca->dx + ca->width - 1, ca->height - 1);
385
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700386 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
387 direction = 0;
388 else
389 direction = 2;
390
Knut Petersen44637a12006-01-09 15:04:20 +0100391 out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
392 info->var.bits_per_pixel) >> 6));
393 out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
394 info->var.bits_per_pixel) >> 6));
395 out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
396 out32(GE00, direction ? s2 : s1);
397 out32(GE04, direction ? s1 : s2);
398 out32(GE08, direction ? d2 : d1);
399 out32(GE0C, direction ? d1 : d2);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700400}
401
402//=======================================================================
403//
404// Cyberblade specific imageblit
405//
Knut Petersen44637a12006-01-09 15:04:20 +0100406// Accelerated for the most usual case, blitting 1 - bit deep
407// character images. Everything else is passed to the generic imageblit
408// unless it is so insane that it is better to printk an alert.
409//
410// Hardware bug: _Never_ blit across pixel column 2048, that will lock
411// the system. We split those blit requests into three blitting
412// operations.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700413//
414//=======================================================================
415
416static void cyblafb_imageblit(struct fb_info *info,
417 const struct fb_image *image)
418{
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700419 u32 fgcol, bgcol;
Knut Petersen44637a12006-01-09 15:04:20 +0100420 u32 *pd = (u32 *) image->data;
421 u32 bpp = info->var.bits_per_pixel;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700422
Knut Petersen44637a12006-01-09 15:04:20 +0100423 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700424
Knut Petersen44637a12006-01-09 15:04:20 +0100425 // Used only for drawing the penguine (image->depth > 1)
426 if (image->depth != 1) {
427 cfb_imageblit(info, image);
428 return;
429 }
430 // That should never happen, but it would be fatal
431 if (image->width == 0 || image->height == 0) {
432 output("imageblit: width/height 0 detected\n");
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700433 return;
434 }
435
436 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
437 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
Knut Petersen44637a12006-01-09 15:04:20 +0100438 fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
439 bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700440 } else {
441 fgcol = image->fg_color;
442 bgcol = image->bg_color;
443 }
444
445 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100446 case 8:
447 fgcol |= fgcol << 8;
448 bgcol |= bgcol << 8;
449 case 16:
450 fgcol |= fgcol << 16;
451 bgcol |= bgcol << 16;
452 default:
453 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700454 }
455
Knut Petersen44637a12006-01-09 15:04:20 +0100456 out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
457 bpp) >> 6));
458 out32(GE60, fgcol);
459 out32(GE64, bgcol);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700460
Knut Petersen44637a12006-01-09 15:04:20 +0100461 if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
462 u32 dds = ((image->width + 31) >> 5) * image->height;
463 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
464 out32(GE08, point(image->dx, 0));
465 out32(GE0C, point(image->dx + image->width - 1,
466 image->height - 1));
467 while (dds--)
468 out32(GE9C, *pd++);
469 } else {
470 int i, j;
471 u32 ddstotal = (image->width + 31) >> 5;
472 u32 ddsleft = (2048 - image->dx + 31) >> 5;
473 u32 skipleft = ddstotal - ddsleft;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700474
Knut Petersen44637a12006-01-09 15:04:20 +0100475 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
476 out32(GE08, point(image->dx, 0));
477 out32(GE0C, point(2048 - 1, image->height - 1));
478 for (i = 0; i < image->height; i++) {
479 for (j = 0; j < ddsleft; j++)
480 out32(GE9C, *pd++);
481 pd += skipleft;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700482 }
Knut Petersen44637a12006-01-09 15:04:20 +0100483
484 if (image->dx % 32) {
485 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
486 out32(GE08, point(2048, 0));
487 if (image->width > ddsleft << 5)
488 out32(GE0C, point(image->dx + (ddsleft << 5) -
489 1, image->height - 1));
490 else
491 out32(GE0C, point(image->dx + image->width - 1,
492 image->height - 1));
493 pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
494 for (i = 0; i < image->height; i++) {
495 out32(GE9C, swab32(swab32(*pd) << ((32 -
496 (image->dx & 31)) & 31)));
497 pd += ddstotal;
498 }
499 }
500
501 if (skipleft) {
502 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
503 out32(GE08, point(image->dx + (ddsleft << 5), 0));
504 out32(GE0C, point(image->dx + image->width - 1,
505 image->height - 1));
506 pd = (u32 *) image->data;
507 for (i = 0; i < image->height; i++) {
508 pd += ddsleft;
509 for (j = 0; j < skipleft; j++)
510 out32(GE9C, *pd++);
511 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700512 }
513 }
514}
515
516//==========================================================
517//
518// Check if video mode is acceptable. We change var->??? if
519// video mode is slightly off or return error otherwise.
520// info->??? must not be changed!
521//
522//==========================================================
523
524static int cyblafb_check_var(struct fb_var_screeninfo *var,
525 struct fb_info *info)
526{
527 int bpp = var->bits_per_pixel;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700528
529 //
530 // we try to support 8, 16, 24 and 32 bpp modes,
531 // default to 8
532 //
533 // there is a 24 bpp mode, but for now we change requests to 32 bpp
534 // (This is what tridentfb does ... will be changed in the future)
535 //
536 //
Knut Petersen44637a12006-01-09 15:04:20 +0100537 if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700538 bpp = 8;
Knut Petersen44637a12006-01-09 15:04:20 +0100539 if (bpp == 24)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700540 bpp = var->bits_per_pixel = 32;
541
542 //
543 // interlaced modes are broken, fail if one is requested
544 //
545 if (var->vmode & FB_VMODE_INTERLACED)
546 return -EINVAL;
547
548 //
549 // fail if requested resolution is higher than physical
550 // flatpanel resolution
551 //
552 if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
553 return -EINVAL;
554
555 //
Knut Petersen44637a12006-01-09 15:04:20 +0100556 // we do not allow vclk to exceed 230 MHz. If the requested
557 // vclk is too high, we default to 200 MHz
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700558 //
Knut Petersen44637a12006-01-09 15:04:20 +0100559 if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
560 var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700561
562 //
Knut Petersen44637a12006-01-09 15:04:20 +0100563 // enforce (h|v)sync_len limits
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700564 //
Knut Petersen44637a12006-01-09 15:04:20 +0100565 var->hsync_len &= ~7;
566 if(var->hsync_len > 248)
567 var->hsync_len = 248;
568
569 var->vsync_len &= 15;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700570
571 //
Knut Petersen44637a12006-01-09 15:04:20 +0100572 // Enforce horizontal and vertical hardware limits.
573 // 1600x1200 is mentioned as a maximum, but higher resolutions could
574 // work with slow refresh, small margins and short sync.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700575 //
Knut Petersen44637a12006-01-09 15:04:20 +0100576 var->xres &= ~7;
577
578 if (((var->xres + var->left_margin + var->right_margin +
579 var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
580 ((var->yres + var->upper_margin + var->lower_margin +
581 var->vsync_len) > 2047))
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700582 return -EINVAL;
583
Knut Petersen44637a12006-01-09 15:04:20 +0100584 if ((var->xres > 1600) || (var->yres > 1200))
585 output("Mode %dx%d exceeds documented limits.\n",
586 var->xres, var->yres);
587 //
588 // try to be smart about (x|y)res_virtual problems.
589 //
590 if (var->xres > var->xres_virtual)
591 var->xres_virtual = var->xres;
592 if (var->yres > var->yres_virtual)
593 var->yres_virtual = var->yres;
594
595 if (bpp == 8 || bpp == 16) {
596 if (var->xres_virtual > 4088)
597 var->xres_virtual = 4088;
598 } else {
599 if (var->xres_virtual > 2040)
600 var->xres_virtual = 2040;
601 }
602 var->xres_virtual &= ~7;
603 while (var->xres_virtual * var->yres_virtual * bpp / 8 >
604 info->fix.smem_len) {
605 if (var->yres_virtual > var->yres)
606 var->yres_virtual--;
607 else if (var->xres_virtual > var->xres)
608 var->xres_virtual -= 8;
609 else
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700610 return -EINVAL;
611 }
612
Knut Petersen44637a12006-01-09 15:04:20 +0100613 switch (bpp) {
614 case 8:
615 var->red.offset = 0;
616 var->green.offset = 0;
617 var->blue.offset = 0;
618 var->red.length = 6;
619 var->green.length = 6;
620 var->blue.length = 6;
621 break;
622 case 16:
623 var->red.offset = 11;
624 var->green.offset = 5;
625 var->blue.offset = 0;
626 var->red.length = 5;
627 var->green.length = 6;
628 var->blue.length = 5;
629 break;
630 case 32:
631 var->red.offset = 16;
632 var->green.offset = 8;
633 var->blue.offset = 0;
634 var->red.length = 8;
635 var->green.length = 8;
636 var->blue.length = 8;
637 break;
638 default:
639 return -EINVAL;
640 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700641
Knut Petersen44637a12006-01-09 15:04:20 +0100642 return 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700643}
644
645//=====================================================================
646//
647// Pan the display
648//
649// The datasheets defines crt start address to be 20 bits wide and
650// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
651// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
652// it, so it is also safe to be used here. BTW: datasheet CR0E on page
653// 90 really is CR1E, the real CRE is documented on page 72.
654//
Knut Petersen44637a12006-01-09 15:04:20 +0100655// BUT:
656//
657// As of internal version 0.60 we do not use vga panning any longer.
658// Vga panning did not allow us the use of all available video memory
659// and thus prevented ywrap scrolling. We do use the "right view"
660// register now.
661//
662//
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700663//=====================================================================
664
665static int cyblafb_pan_display(struct fb_var_screeninfo *var,
666 struct fb_info *info)
667{
Knut Petersen44637a12006-01-09 15:04:20 +0100668 KD_GRAPHICS_RETURN(0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700669
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700670 info->var.xoffset = var->xoffset;
671 info->var.yoffset = var->yoffset;
Knut Petersen44637a12006-01-09 15:04:20 +0100672 out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
673 var->xres_virtual)) * var->bits_per_pixel / 32));
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700674 return 0;
675}
676
677//============================================
678//
679// This will really help in case of a bug ...
680// dump most gaphics core registers.
681//
682//============================================
683
684static void regdump(struct cyblafb_par *par)
685{
686 int i;
687
688 if (verbosity < 2)
689 return;
690
691 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100692 for (i = 0; i <= 0xff; i++) {
693 outb(i, 0x3d4);
694 printk("CR%02x=%02x ", i, inb(0x3d5));
695 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700696 printk("\n");
697 }
698
Knut Petersen44637a12006-01-09 15:04:20 +0100699 outb(0x30, 0x3ce);
700 outb(inb(0x3cf) | 0x40, 0x3cf);
701 for (i = 0; i <= 0x1f; i++) {
702 if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
703 || i == 0x16) {
704 outb(i, 0x3d4);
705 printk("CR%02x=%02x ", i, inb(0x3d5));
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700706 } else
707 printk("------- ");
Knut Petersen44637a12006-01-09 15:04:20 +0100708 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700709 printk("\n");
710 }
Knut Petersen44637a12006-01-09 15:04:20 +0100711 outb(0x30, 0x3ce);
712 outb(inb(0x3cf) & 0xbf, 0x3cf);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700713
714 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100715 for (i = 0; i <= 0x7f; i++) {
716 outb(i, 0x3ce);
717 printk("GR%02x=%02x ", i, inb(0x3cf));
718 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700719 printk("\n");
720 }
721
722 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100723 for (i = 0; i <= 0xff; i++) {
724 outb(i, 0x3c4);
725 printk("SR%02x=%02x ", i, inb(0x3c5));
726 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700727 printk("\n");
728 }
729
730 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100731 for (i = 0; i <= 0x1F; i++) {
732 inb(0x3da); // next access is index!
733 outb(i, 0x3c0);
734 printk("AR%02x=%02x ", i, inb(0x3c1));
735 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700736 printk("\n");
737 }
738 printk("\n");
739
Knut Petersen44637a12006-01-09 15:04:20 +0100740 inb(0x3DA); // reset internal flag to 3c0 index
741 outb(0x20, 0x3C0); // enable attr
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700742
743 return;
744}
745
Knut Petersen44637a12006-01-09 15:04:20 +0100746//=======================================================================
747//
748// Save State
749//
750// This function is called while a switch to KD_TEXT is in progress,
751// before any of the other functions are called.
752//
753//=======================================================================
754
755static void cyblafb_save_state(struct fb_info *info)
756{
757 struct cyblafb_par *par = info->par;
758 if (verbosity > 0)
759 output("Switching to KD_TEXT\n");
760 disabled = 0;
761 regdump(par);
762 enable_mmio();
763 return;
764}
765
766//=======================================================================
767//
768// Restore State
769//
770// This function is called while a switch to KD_GRAPHICS is in progress,
771// We have to turn on vga style panning registers again because the
772// trident driver of X does not know about GE10.
773//
774//=======================================================================
775
776static void cyblafb_restore_state(struct fb_info *info)
777{
778 if (verbosity > 0)
779 output("Switching to KD_GRAPHICS\n");
780 out32(GE10, 0);
781 disabled = 1;
782 return;
783}
784
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700785//======================================
786//
787// Set hardware to requested video mode
788//
789//======================================
790
791static int cyblafb_set_par(struct fb_info *info)
792{
793 struct cyblafb_par *par = info->par;
Knut Petersen44637a12006-01-09 15:04:20 +0100794 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
795 hblankend, preendfetch, vtotal, vdispend, vsyncstart,
796 vsyncend, vblankstart, vblankend;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700797 struct fb_var_screeninfo *var = &info->var;
798 int bpp = var->bits_per_pixel;
799 int i;
800
Knut Petersen44637a12006-01-09 15:04:20 +0100801 KD_GRAPHICS_RETURN(0);
802
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700803 if (verbosity > 0)
804 output("Switching to new mode: "
805 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
Knut Petersen44637a12006-01-09 15:04:20 +0100806 var->xres, var->yres, var->xres_virtual,
807 var->yres_virtual, var->bits_per_pixel, var->pixclock,
808 var->left_margin, var->right_margin, var->upper_margin,
809 var->lower_margin, var->hsync_len, var->vsync_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700810
811 htotal = (var->xres + var->left_margin + var->right_margin +
Knut Petersen44637a12006-01-09 15:04:20 +0100812 var->hsync_len) / 8 - 5;
813 hdispend = var->xres / 8 - 1;
814 hsyncstart = (var->xres + var->right_margin) / 8;
815 hsyncend = var->hsync_len / 8;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700816 hblankstart = hdispend + 1;
817 hblankend = htotal + 3; // should be htotal + 5, bios does it this way
Knut Petersen44637a12006-01-09 15:04:20 +0100818 preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700819
820 vtotal = var->yres + var->upper_margin + var->lower_margin +
Knut Petersen44637a12006-01-09 15:04:20 +0100821 var->vsync_len - 2;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700822 vdispend = var->yres - 1;
823 vsyncstart = var->yres + var->lower_margin;
824 vblankstart = var->yres;
825 vblankend = vtotal; // should be vtotal + 2, but bios does it this way
826 vsyncend = var->vsync_len;
827
828 enable_mmio(); // necessary! ... check X ...
829
Knut Petersen44637a12006-01-09 15:04:20 +0100830 write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700831
Knut Petersen44637a12006-01-09 15:04:20 +0100832 write3CE(GR30, 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700833
834 if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
835
836 // stretch or center ?
837
Knut Petersen44637a12006-01-09 15:04:20 +0100838 out8(0x3C2, 0xEB);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700839
Knut Petersen44637a12006-01-09 15:04:20 +0100840 write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700841
842 if (center) {
Knut Petersen44637a12006-01-09 15:04:20 +0100843 write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
844 write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
845 } else if (stretch) {
846 write3CE(GR5D, 0);
847 write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
848 write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700849 }
850
851 } else {
Knut Petersen44637a12006-01-09 15:04:20 +0100852 out8(0x3C2, 0x2B);
853 write3CE(GR30, 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700854 }
855
856 //
857 // Setup CRxx regs
858 //
859
Knut Petersen44637a12006-01-09 15:04:20 +0100860 write3X4(CR00, htotal & 0xFF);
861 write3X4(CR01, hdispend & 0xFF);
862 write3X4(CR02, hblankstart & 0xFF);
863 write3X4(CR03, hblankend & 0x1F);
864 write3X4(CR04, hsyncstart & 0xFF);
865 write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
866 write3X4(CR06, vtotal & 0xFF);
867 write3X4(CR07, (vtotal & 0x100) >> 8 |
868 (vdispend & 0x100) >> 7 |
869 (vsyncstart & 0x100) >> 6 |
870 (vblankstart & 0x100) >> 5 |
871 0x10 |
872 (vtotal & 0x200) >> 4 |
873 (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
874 write3X4(CR08, 0);
875 write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
876 ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
877 write3X4(CR0A, 0); // Init to some reasonable default
878 write3X4(CR0B, 0); // Init to some reasonable default
879 write3X4(CR0C, 0); // Offset 0
880 write3X4(CR0D, 0); // Offset 0
881 write3X4(CR0E, 0); // Init to some reasonable default
882 write3X4(CR0F, 0); // Init to some reasonable default
883 write3X4(CR10, vsyncstart & 0xFF);
884 write3X4(CR11, (vsyncend & 0x0F));
885 write3X4(CR12, vdispend & 0xFF);
886 write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
887 write3X4(CR14, 0x40); // double word mode
888 write3X4(CR15, vblankstart & 0xFF);
889 write3X4(CR16, vblankend & 0xFF);
890 write3X4(CR17, 0xE3);
891 write3X4(CR18, 0xFF);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700892 // CR19: needed for interlaced modes ... ignore it for now
Knut Petersen44637a12006-01-09 15:04:20 +0100893 write3X4(CR1A, 0x07); // Arbitration Control Counter 1
894 write3X4(CR1B, 0x07); // Arbitration Control Counter 2
895 write3X4(CR1C, 0x07); // Arbitration Control Counter 3
896 write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -)
897 write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700898 // CR1F: do not set, contains BIOS info about memsize
Knut Petersen44637a12006-01-09 15:04:20 +0100899 write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode
900 write3X4(CR21, 0x20); // enable linear memory access
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700901 // CR22: RO cpu latch readback
902 // CR23: ???
903 // CR24: RO AR flag state
904 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
905 // CR26: ???
Knut Petersen44637a12006-01-09 15:04:20 +0100906 write3X4(CR27, (vdispend & 0x400) >> 6 |
907 (vsyncstart & 0x400) >> 5 |
908 (vblankstart & 0x400) >> 4 |
909 (vtotal & 0x400) >> 3 |
910 0x8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700911 // CR28: ???
Knut Petersen44637a12006-01-09 15:04:20 +0100912 write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
913 bpp) / (4 * 16)) & 0x300) >> 4));
914 write3X4(CR2A, read3X4(CR2A) | 0x40);
915 write3X4(CR2B, (htotal & 0x100) >> 8 |
916 (hdispend & 0x100) >> 7 |
917 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
918 (hsyncstart & 0x100) >> 5 |
919 (hblankstart & 0x100) >> 4);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700920 // CR2C: ???
921 // CR2D: initialized in cyblafb_setup_GE()
Knut Petersen44637a12006-01-09 15:04:20 +0100922 write3X4(CR2F, 0x92); // conservative, better signal quality
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700923 // CR30: reserved
924 // CR31: reserved
925 // CR32: reserved
926 // CR33: reserved
927 // CR34: disabled in CR36
928 // CR35: disabled in CR36
929 // CR36: initialized in cyblafb_setup_GE
930 // CR37: i2c, ignore for now
Knut Petersen44637a12006-01-09 15:04:20 +0100931 write3X4(CR38, (bpp == 8) ? 0x00 : //
932 (bpp == 16) ? 0x05 : // highcolor
933 (bpp == 24) ? 0x29 : // packed 24bit truecolor
934 (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
935 write3X4(CR39, 0x01 | // MMIO enable
936 (pcirb ? 0x02 : 0) | // pci read burst enable
937 (pciwb ? 0x04 : 0)); // pci write burst enable
938 write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
939 (pcirr ? 0x40 : 0) | // pci read retry enable
940 (pciwr ? 0x80 : 0)); // pci write retry enable
941 write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
942 : 0);
943 write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
944 write3X4(CR58, 0x82); // Bios does this .... don't know more
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700945 //
946 // Setup SRxx regs
947 //
Knut Petersen44637a12006-01-09 15:04:20 +0100948 write3C4(SR00, 3);
949 write3C4(SR01, 1); //set char clock 8 dots wide
950 write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode
951 write3C4(SR03, 0); //no character map select
952 write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700953
Knut Petersen44637a12006-01-09 15:04:20 +0100954 out8(0x3C4, 0x0b);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700955 in8(0x3C5); // Set NEW mode
Knut Petersen44637a12006-01-09 15:04:20 +0100956 write3C4(SR0D, 0x00); // test ... check
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700957
Knut Petersen44637a12006-01-09 15:04:20 +0100958 set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
959 / info->var.pixclock); //SR18, SR19
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700960
961 //
962 // Setup GRxx regs
963 //
Knut Petersen44637a12006-01-09 15:04:20 +0100964 write3CE(GR00, 0x00); // test ... check
965 write3CE(GR01, 0x00); // test ... check
966 write3CE(GR02, 0x00); // test ... check
967 write3CE(GR03, 0x00); // test ... check
968 write3CE(GR04, 0x00); // test ... check
969 write3CE(GR05, 0x40); // no CGA compat, allow 256 col
970 write3CE(GR06, 0x05); // graphics mode
971 write3CE(GR07, 0x0F); // planes?
972 write3CE(GR08, 0xFF); // test ... check
973 write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
974 write3CE(GR20, 0xC0); // test ... check
975 write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew,
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700976
977 //
978 // Setup ARxx regs
979 //
Knut Petersen44637a12006-01-09 15:04:20 +0100980 for (i = 0; i < 0x10; i++) // set AR00 .. AR0f
981 write3C0(i, i);
982 write3C0(AR10, 0x41); // graphics mode and support 256 color modes
983 write3C0(AR12, 0x0F); // planes
984 write3C0(AR13, 0); // horizontal pel panning
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700985 in8(0x3DA); // reset internal flag to 3c0 index
Knut Petersen44637a12006-01-09 15:04:20 +0100986 out8(0x3C0, 0x20); // enable attr
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700987
988 //
989 // Setup hidden RAMDAC command register
990 //
Knut Petersen44637a12006-01-09 15:04:20 +0100991 in8(0x3C8); // these reads are
992 in8(0x3C6); // necessary to
993 in8(0x3C6); // unmask the RAMDAC
994 in8(0x3C6); // command reg, otherwise
995 in8(0x3C6); // we would write the pixelmask reg!
996 out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
997 (bpp == 15) ? 0x10 : //
998 (bpp == 16) ? 0x30 : // hicolor
999 (bpp == 24) ? 0xD0 : // truecolor
1000 (bpp == 32) ? 0xD0 : 0); // truecolor
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001001 in8(0x3C8);
1002
1003 //
1004 // GR31 is not mentioned in the datasheet
1005 //
1006 if (displaytype == DISPLAY_FP)
Knut Petersen44637a12006-01-09 15:04:20 +01001007 write3CE(GR31, (read3CE(GR31) & 0x8F) |
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001008 ((info->var.yres > 1024) ? 0x50 :
Knut Petersen44637a12006-01-09 15:04:20 +01001009 (info->var.yres > 768) ? 0x30 :
1010 (info->var.yres > 600) ? 0x20 :
1011 (info->var.yres > 480) ? 0x10 : 0));
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001012
1013 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
1014 : FB_VISUAL_TRUECOLOR;
Knut Petersen44637a12006-01-09 15:04:20 +01001015 info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
1016 info->cmap.len = (bpp == 8) ? 256 : 16;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001017
1018 //
1019 // init acceleration engine
1020 //
Knut Petersen44637a12006-01-09 15:04:20 +01001021 cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
1022
1023 //
1024 // Set/clear flags to allow proper scroll mode selection.
1025 //
1026 if (var->xres == var->xres_virtual)
1027 info->flags &= ~FBINFO_HWACCEL_XPAN;
1028 else
1029 info->flags |= FBINFO_HWACCEL_XPAN;
1030
1031 if (var->yres == var->yres_virtual)
1032 info->flags &= ~FBINFO_HWACCEL_YPAN;
1033 else
1034 info->flags |= FBINFO_HWACCEL_YPAN;
1035
1036 if (info->fix.smem_len !=
1037 var->xres_virtual * var->yres_virtual * bpp / 8)
1038 info->flags &= ~FBINFO_HWACCEL_YWRAP;
1039 else
1040 info->flags |= FBINFO_HWACCEL_YWRAP;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001041
1042 regdump(par);
1043
1044 return 0;
1045}
1046
1047//========================
1048//
1049// Set one color register
1050//
1051//========================
1052
1053static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
1054 unsigned blue, unsigned transp,
1055 struct fb_info *info)
1056{
1057 int bpp = info->var.bits_per_pixel;
1058
Knut Petersen44637a12006-01-09 15:04:20 +01001059 KD_GRAPHICS_RETURN(0);
1060
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001061 if (regno >= info->cmap.len)
1062 return 1;
1063
1064 if (bpp == 8) {
Knut Petersen44637a12006-01-09 15:04:20 +01001065 out8(0x3C6, 0xFF);
1066 out8(0x3C8, regno);
1067 out8(0x3C9, red >> 10);
1068 out8(0x3C9, green >> 10);
1069 out8(0x3C9, blue >> 10);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001070
Knut Petersen44637a12006-01-09 15:04:20 +01001071 } else if (bpp == 16) // RGB 565
1072 ((u32 *) info->pseudo_palette)[regno] =
1073 (red & 0xF800) |
1074 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
1075 else if (bpp == 32) // ARGB 8888
1076 ((u32 *) info->pseudo_palette)[regno] =
1077 ((transp & 0xFF00) << 16) |
1078 ((red & 0xFF00) << 8) |
1079 ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001080
1081 return 0;
1082}
1083
1084//==========================================================
1085//
1086// Try blanking the screen. For flat panels it does nothing
1087//
1088//==========================================================
1089
1090static int cyblafb_blank(int blank_mode, struct fb_info *info)
1091{
Knut Petersen44637a12006-01-09 15:04:20 +01001092 unsigned char PMCont, DPMSCont;
1093
1094 KD_GRAPHICS_RETURN(0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001095
1096 if (displaytype == DISPLAY_FP)
1097 return 0;
1098
Knut Petersen44637a12006-01-09 15:04:20 +01001099 out8(0x83C8, 0x04); // DPMS Control
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001100 PMCont = in8(0x83C6) & 0xFC;
1101
1102 DPMSCont = read3CE(GR23) & 0xFC;
1103
Knut Petersen44637a12006-01-09 15:04:20 +01001104 switch (blank_mode) {
1105 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
1106 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001107 PMCont |= 0x03;
1108 DPMSCont |= 0x00;
1109 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001110 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001111 PMCont |= 0x02;
1112 DPMSCont |= 0x01;
1113 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001114 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001115 PMCont |= 0x02;
1116 DPMSCont |= 0x02;
1117 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001118 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001119 PMCont |= 0x00;
1120 DPMSCont |= 0x03;
1121 break;
1122 }
1123
Knut Petersen44637a12006-01-09 15:04:20 +01001124 write3CE(GR23, DPMSCont);
1125 out8(0x83C8, 4);
1126 out8(0x83C6, PMCont);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001127 //
1128 // let fbcon do a softblank for us
1129 //
1130 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1131}
1132
1133static struct fb_ops cyblafb_ops __devinitdata = {
Knut Petersen44637a12006-01-09 15:04:20 +01001134 .owner = THIS_MODULE,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001135 .fb_setcolreg = cyblafb_setcolreg,
1136 .fb_pan_display = cyblafb_pan_display,
1137 .fb_blank = cyblafb_blank,
1138 .fb_check_var = cyblafb_check_var,
1139 .fb_set_par = cyblafb_set_par,
1140 .fb_fillrect = cyblafb_fillrect,
Knut Petersen44637a12006-01-09 15:04:20 +01001141 .fb_copyarea = cyblafb_copyarea,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001142 .fb_imageblit = cyblafb_imageblit,
Knut Petersen44637a12006-01-09 15:04:20 +01001143 .fb_sync = cyblafb_sync,
1144 .fb_restore_state = cyblafb_restore_state,
1145 .fb_save_state = cyblafb_save_state,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001146};
1147
1148//==========================================================================
1149//
1150// getstartupmode() decides about the inital video mode
1151//
1152// There is no reason to use modedb, a lot of video modes there would
1153// need altered timings to display correctly. So I decided that it is much
1154// better to provide a limited optimized set of modes plus the option of
1155// using the mode in effect at startup time (might be selected using the
1156// vga=??? paramter). After that the user might use fbset to select any
1157// mode he likes, check_var will not try to alter geometry parameters as
1158// it would be necessary otherwise.
1159//
1160//==========================================================================
1161
1162static int __devinit getstartupmode(struct fb_info *info)
1163{
Knut Petersen44637a12006-01-09 15:04:20 +01001164 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
1165 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
1166 cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
1167 cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
1168 cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001169
1170 struct modus {
Knut Petersen44637a12006-01-09 15:04:20 +01001171 int xres; int vxres; int yres; int vyres;
1172 int bpp; int pxclk;
1173 int left_margin; int right_margin;
1174 int upper_margin; int lower_margin;
1175 int hsync_len; int vsync_len;
1176 } modedb[5] = {
1177 {
1178 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1179 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1180 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1181 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1182 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001183 };
1184
Knut Petersen44637a12006-01-09 15:04:20 +01001185 outb(0x00, 0x3d4); cr00 = inb(0x3d5);
1186 outb(0x01, 0x3d4); cr01 = inb(0x3d5);
1187 outb(0x02, 0x3d4); cr02 = inb(0x3d5);
1188 outb(0x03, 0x3d4); cr03 = inb(0x3d5);
1189 outb(0x04, 0x3d4); cr04 = inb(0x3d5);
1190 outb(0x05, 0x3d4); cr05 = inb(0x3d5);
1191 outb(0x06, 0x3d4); cr06 = inb(0x3d5);
1192 outb(0x07, 0x3d4); cr07 = inb(0x3d5);
1193 outb(0x09, 0x3d4); cr09 = inb(0x3d5);
1194 outb(0x10, 0x3d4); cr10 = inb(0x3d5);
1195 outb(0x11, 0x3d4); cr11 = inb(0x3d5);
1196 outb(0x12, 0x3d4); cr12 = inb(0x3d5);
1197 outb(0x15, 0x3d4); cr15 = inb(0x3d5);
1198 outb(0x16, 0x3d4); cr16 = inb(0x3d5);
1199 outb(0x27, 0x3d4); cr27 = inb(0x3d5);
1200 outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
1201 outb(0x38, 0x3d4); cr38 = inb(0x3d5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001202
Knut Petersen44637a12006-01-09 15:04:20 +01001203 outb(0x0b, 0x3c4);
1204 inb(0x3c5);
1205
1206 outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
1207 outb(0x18, 0x3c4); sr18 = inb(0x3c5);
1208 outb(0x19, 0x3c4); sr19 = inb(0x3c5);
1209 outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
1210
1211 htotal = cr00 | (cr2b & 0x01) << 8;
1212 hdispend = cr01 | (cr2b & 0x02) << 7;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001213 hblankstart = cr02 | (cr2b & 0x10) << 4;
Knut Petersen44637a12006-01-09 15:04:20 +01001214 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1215 hsyncstart = cr04 | (cr2b & 0x08) << 5;
1216 hsyncend = cr05 & 0x1f;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001217
1218 modedb[0].xres = hblankstart * 8;
1219 modedb[0].hsync_len = hsyncend * 8;
1220 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1221 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
Knut Petersen44637a12006-01-09 15:04:20 +01001222 modedb[0].right_margin - modedb[0].hsync_len;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001223
Knut Petersen44637a12006-01-09 15:04:20 +01001224 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1225 | (cr27 & 0x80) << 3;
1226 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1227 | (cr27 & 0x10) << 6;
1228 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1229 | (cr27 & 0x20) << 5;
1230 vsyncend = cr11 & 0x0f;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001231 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
Knut Petersen44637a12006-01-09 15:04:20 +01001232 | (cr27 & 0x40) << 4;
1233 vblankend = cr16;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001234
Knut Petersen44637a12006-01-09 15:04:20 +01001235 modedb[0].yres = vdispend + 1;
1236 modedb[0].vsync_len = vsyncend;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001237 modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1238 modedb[0].upper_margin = vtotal - modedb[0].yres -
Knut Petersen44637a12006-01-09 15:04:20 +01001239 modedb[0].lower_margin - modedb[0].vsync_len + 2;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001240
1241 tmp = cr38 & 0x3c;
1242 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
Knut Petersen44637a12006-01-09 15:04:20 +01001243 tmp == 8 ? 32 : 8;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001244
Knut Petersen44637a12006-01-09 15:04:20 +01001245 fi = ((5864727 * (sr18 + 8)) /
1246 (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001247 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1248 tmp = sr0d & 0x06;
1249 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1250 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1251
1252 if (verbosity > 0)
1253 output("detected startup mode: "
1254 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
Knut Petersen44637a12006-01-09 15:04:20 +01001255 modedb[0].xres, modedb[0].yres, modedb[0].xres,
1256 modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
1257 modedb[0].right_margin, modedb[0].upper_margin,
1258 modedb[0].lower_margin, modedb[0].hsync_len,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001259 modedb[0].vsync_len);
1260
1261 //
1262 // We use this goto target in case of a failed check_var. No, I really
1263 // do not want to do it in another way!
1264 //
1265
Knut Petersen44637a12006-01-09 15:04:20 +01001266 tryagain:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001267
1268 i = (mode == NULL) ? 0 :
Knut Petersen44637a12006-01-09 15:04:20 +01001269 !strncmp(mode, "640x480", 7) ? 1 :
1270 !strncmp(mode, "800x600", 7) ? 2 :
1271 !strncmp(mode, "1024x768", 8) ? 3 :
1272 !strncmp(mode, "1280x1024", 9) ? 4 : 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001273
1274 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1275
Knut Petersen44637a12006-01-09 15:04:20 +01001276 if (i == 0) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001277 info->var.pixclock = modedb[i].pxclk;
1278 info->var.bits_per_pixel = modedb[i].bpp;
1279 } else {
1280 info->var.pixclock = (100000000 /
Knut Petersen44637a12006-01-09 15:04:20 +01001281 ((modedb[i].left_margin +
1282 modedb[i].xres +
1283 modedb[i].right_margin +
1284 modedb[i].hsync_len) *
1285 (modedb[i].upper_margin +
1286 modedb[i].yres +
1287 modedb[i].lower_margin +
1288 modedb[i].vsync_len) * ref / 10000));
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001289 info->var.bits_per_pixel = bpp;
1290 }
1291
1292 info->var.left_margin = modedb[i].left_margin;
1293 info->var.right_margin = modedb[i].right_margin;
1294 info->var.xres = modedb[i].xres;
Knut Petersen44637a12006-01-09 15:04:20 +01001295 if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
1296 info->var.xres_virtual = modedb[i].vxres;
1297 else
1298 info->var.xres_virtual = modedb[i].xres;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001299 info->var.xoffset = 0;
1300 info->var.hsync_len = modedb[i].hsync_len;
1301 info->var.upper_margin = modedb[i].upper_margin;
1302 info->var.yres = modedb[i].yres;
1303 info->var.yres_virtual = modedb[i].vyres;
1304 info->var.yoffset = 0;
1305 info->var.lower_margin = modedb[i].lower_margin;
1306 info->var.vsync_len = modedb[i].vsync_len;
1307 info->var.sync = 0;
1308 info->var.vmode = FB_VMODE_NONINTERLACED;
1309
Knut Petersen44637a12006-01-09 15:04:20 +01001310 if (cyblafb_check_var(&info->var, info)) {
1311 // 640x480 - 8@75 should really never fail. One case would
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001312 // be fp == 1 and nativex < 640 ... give up then
Knut Petersen44637a12006-01-09 15:04:20 +01001313 if (i == 1 && bpp == 8 && ref == 75) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001314 output("Can't find a valid mode :-(\n");
1315 return -EINVAL;
1316 }
1317 // Our detected mode is unlikely to fail. If it does,
Knut Petersen44637a12006-01-09 15:04:20 +01001318 // try 640x480 - 8@75 ...
1319 if (i == 0) {
1320 mode = "640x480";
1321 bpp = 8;
1322 ref = 75;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001323 output("Detected mode failed check_var! "
Knut Petersen44637a12006-01-09 15:04:20 +01001324 "Trying 640x480 - 8@75\n");
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001325 goto tryagain;
1326 }
1327 // A specified video mode failed for some reason.
1328 // Try the startup mode first
1329 output("Specified mode '%s' failed check! "
Knut Petersen44637a12006-01-09 15:04:20 +01001330 "Falling back to startup mode.\n", mode);
1331 mode = NULL;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001332 goto tryagain;
1333 }
1334
1335 return 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001336}
1337
1338//========================================================
1339//
1340// Detect activated memory size. Undefined values require
1341// memsize parameter.
1342//
1343//========================================================
1344
1345static unsigned int __devinit get_memsize(void)
1346{
1347 unsigned char tmp;
1348 unsigned int k;
1349
1350 if (memsize)
1351 k = memsize * Kb;
1352 else {
1353 tmp = read3X4(CR1F) & 0x0F;
1354 switch (tmp) {
Knut Petersen44637a12006-01-09 15:04:20 +01001355 case 0x03:
1356 k = 1 * 1024 * 1024;
1357 break;
1358 case 0x07:
1359 k = 2 * 1024 * 1024;
1360 break;
1361 case 0x0F:
1362 k = 4 * 1024 * 1024;
1363 break;
1364 case 0x04:
1365 k = 8 * 1024 * 1024;
1366 break;
1367 default:
1368 k = 1 * 1024 * 1024;
1369 output("Unknown memory size code %x in CR1F."
1370 " We default to 1 Mb for now, please"
1371 " do provide a memsize parameter!\n", tmp);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001372 }
1373 }
1374
1375 if (verbosity > 0)
Knut Petersen44637a12006-01-09 15:04:20 +01001376 output("framebuffer size = %d Kb\n", k / Kb);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001377 return k;
1378}
1379
1380//=========================================================
1381//
1382// Detect if a flat panel monitor connected to the special
1383// interface is active. Override is possible by fp and crt
1384// parameters.
1385//
1386//=========================================================
1387
1388static unsigned int __devinit get_displaytype(void)
1389{
1390 if (fp)
1391 return DISPLAY_FP;
1392 if (crt)
1393 return DISPLAY_CRT;
Knut Petersen44637a12006-01-09 15:04:20 +01001394 return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001395}
1396
1397//=====================================
1398//
1399// Get native resolution of flat panel
1400//
1401//=====================================
1402
1403static int __devinit get_nativex(void)
1404{
Knut Petersen44637a12006-01-09 15:04:20 +01001405 int x, y, tmp;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001406
1407 if (nativex)
1408 return nativex;
1409
1410 tmp = (read3CE(GR52) >> 4) & 3;
1411
1412 switch (tmp) {
Knut Petersen44637a12006-01-09 15:04:20 +01001413 case 0: x = 1280; y = 1024;
1414 break;
1415 case 2: x = 1024; y = 768;
1416 break;
1417 case 3: x = 800; y = 600;
1418 break;
1419 case 4: x = 1400; y = 1050;
1420 break;
1421 case 1:
1422 default:
1423 x = 640; y = 480;
1424 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001425 }
1426
1427 if (verbosity > 0)
Knut Petersen44637a12006-01-09 15:04:20 +01001428 output("%dx%d flat panel found\n", x, y);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001429 return x;
1430}
1431
Knut Petersen44637a12006-01-09 15:04:20 +01001432static int __devinit cybla_pci_probe(struct pci_dev *dev,
1433 const struct pci_device_id *id)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001434{
1435 struct fb_info *info;
1436 struct cyblafb_par *par;
1437
Knut Petersen44637a12006-01-09 15:04:20 +01001438 info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001439 if (!info)
Knut Petersen44637a12006-01-09 15:04:20 +01001440 goto errout_alloc_info;
1441
1442 info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
1443 if (!info->pixmap.addr) {
1444 output("allocation of pixmap buffer failed!\n");
1445 goto errout_alloc_pixmap;
1446 }
1447 info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
1448 info->pixmap.buf_align = 4;
1449 info->pixmap.access_align = 32;
1450 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1451 info->pixmap.scan_align = 4;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001452
1453 par = info->par;
1454 par->ops = cyblafb_ops;
1455
1456 info->fix = cyblafb_fix;
1457 info->fbops = &par->ops;
1458 info->fix = cyblafb_fix;
1459
1460 if (pci_enable_device(dev)) {
1461 output("could not enable device!\n");
1462 goto errout_enable;
1463 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001464 // might already be requested by vga console or vesafb,
1465 // so we do care about success
Knut Petersen44637a12006-01-09 15:04:20 +01001466 if (!request_region(0x3c0, 0x20, "cyblafb")) {
1467 output("region 0x3c0/0x20 already reserved\n");
1468 vesafb |= 1;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001469
Knut Petersen44637a12006-01-09 15:04:20 +01001470 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001471 //
1472 // Graphics Engine Registers
1473 //
Knut Petersen44637a12006-01-09 15:04:20 +01001474 if (!request_region(GEBase, 0x100, "cyblafb")) {
1475 output("region %#x/0x100 already reserved\n", GEBase);
1476 vesafb |= 2;
1477 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001478
1479 regdump(par);
1480
1481 enable_mmio();
1482
1483 // setup MMIO region
Knut Petersen44637a12006-01-09 15:04:20 +01001484 info->fix.mmio_start = pci_resource_start(dev, 1);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001485 info->fix.mmio_len = 0x20000;
1486
1487 if (!request_mem_region(info->fix.mmio_start,
Knut Petersen44637a12006-01-09 15:04:20 +01001488 info->fix.mmio_len, "cyblafb")) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001489 output("request_mem_region failed for mmio region!\n");
1490 goto errout_mmio_reqmem;
1491 }
1492
1493 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1494
1495 if (!io_virt) {
1496 output("ioremap failed for mmio region\n");
1497 goto errout_mmio_remap;
1498 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001499 // setup framebuffer memory ... might already be requested
1500 // by vesafb. Not to fail in case of an unsuccessful request
Knut Petersen44637a12006-01-09 15:04:20 +01001501 // is useful if both are loaded.
1502 info->fix.smem_start = pci_resource_start(dev, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001503 info->fix.smem_len = get_memsize();
1504
1505 if (!request_mem_region(info->fix.smem_start,
Knut Petersen44637a12006-01-09 15:04:20 +01001506 info->fix.smem_len, "cyblafb")) {
1507 output("region %#lx/%#x already reserved\n",
1508 info->fix.smem_start, info->fix.smem_len);
1509 vesafb |= 4;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001510 }
1511
1512 info->screen_base = ioremap_nocache(info->fix.smem_start,
1513 info->fix.smem_len);
1514
1515 if (!info->screen_base) {
1516 output("ioremap failed for smem region\n");
1517 goto errout_smem_remap;
1518 }
1519
1520 displaytype = get_displaytype();
1521
Knut Petersen44637a12006-01-09 15:04:20 +01001522 if (displaytype == DISPLAY_FP)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001523 nativex = get_nativex();
1524
Knut Petersen44637a12006-01-09 15:04:20 +01001525 info->flags = FBINFO_DEFAULT
1526 | FBINFO_HWACCEL_COPYAREA
1527 | FBINFO_HWACCEL_FILLRECT
1528 | FBINFO_HWACCEL_IMAGEBLIT
1529 | FBINFO_READS_FAST
1530// | FBINFO_PARTIAL_PAN_OK
1531 | FBINFO_MISC_ALWAYS_SETPAR;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001532
1533 info->pseudo_palette = par->pseudo_pal;
1534
Knut Petersen44637a12006-01-09 15:04:20 +01001535 if (getstartupmode(info))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001536 goto errout_findmode;
1537
Knut Petersen44637a12006-01-09 15:04:20 +01001538 fb_alloc_cmap(&info->cmap, 256, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001539
1540 if (register_framebuffer(info)) {
1541 output("Could not register CyBla framebuffer\n");
1542 goto errout_register;
1543 }
1544
Knut Petersen44637a12006-01-09 15:04:20 +01001545 pci_set_drvdata(dev, info);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001546
1547 //
1548 // normal exit and error paths
1549 //
1550
1551 return 0;
1552
Knut Petersen44637a12006-01-09 15:04:20 +01001553 errout_register:
1554 errout_findmode:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001555 iounmap(info->screen_base);
Knut Petersen44637a12006-01-09 15:04:20 +01001556 errout_smem_remap:
1557 if (!(vesafb & 4))
1558 release_mem_region(info->fix.smem_start, info->fix.smem_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001559 iounmap(io_virt);
Knut Petersen44637a12006-01-09 15:04:20 +01001560 errout_mmio_remap:
1561 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1562 errout_mmio_reqmem:
1563 if (!(vesafb & 1))
1564 release_region(0x3c0, 32);
1565 errout_enable:
1566 kfree(info->pixmap.addr);
1567 errout_alloc_pixmap:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001568 framebuffer_release(info);
Knut Petersen44637a12006-01-09 15:04:20 +01001569 errout_alloc_info:
1570 output("CyblaFB version %s aborting init.\n", VERSION);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001571 return -ENODEV;
1572}
1573
1574static void __devexit cybla_pci_remove(struct pci_dev *dev)
1575{
1576 struct fb_info *info = pci_get_drvdata(dev);
1577
1578 unregister_framebuffer(info);
1579 iounmap(io_virt);
1580 iounmap(info->screen_base);
Knut Petersen44637a12006-01-09 15:04:20 +01001581 if (!(vesafb & 4))
1582 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1583 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001584 fb_dealloc_cmap(&info->cmap);
Knut Petersen44637a12006-01-09 15:04:20 +01001585 if (!(vesafb & 2))
1586 release_region(GEBase, 0x100);
1587 if (!(vesafb & 1))
1588 release_region(0x3c0, 32);
1589 kfree(info->pixmap.addr);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001590 framebuffer_release(info);
Knut Petersen44637a12006-01-09 15:04:20 +01001591 output("CyblaFB version %s normal exit.\n", VERSION);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001592}
1593
1594//
1595// List of boards that we are trying to support
1596//
1597static struct pci_device_id cybla_devices[] = {
Knut Petersen44637a12006-01-09 15:04:20 +01001598 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001599 {0,}
1600};
1601
Knut Petersen44637a12006-01-09 15:04:20 +01001602MODULE_DEVICE_TABLE(pci, cybla_devices);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001603
1604static struct pci_driver cyblafb_pci_driver = {
Knut Petersen44637a12006-01-09 15:04:20 +01001605 .name = "cyblafb",
1606 .id_table = cybla_devices,
1607 .probe = cybla_pci_probe,
1608 .remove = __devexit_p(cybla_pci_remove)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001609};
1610
1611//=============================================================
1612//
1613// kernel command line example:
1614//
Knut Petersen44637a12006-01-09 15:04:20 +01001615// video=cyblafb:1280x1024, bpp=16, ref=50 ...
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001616//
1617// modprobe command line example:
1618//
1619// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1620//
1621//=============================================================
1622
1623static int __devinit cyblafb_init(void)
1624{
1625#ifndef MODULE
1626 char *options = NULL;
1627 char *opt;
1628
Knut Petersen44637a12006-01-09 15:04:20 +01001629 if (fb_get_options("cyblafb", &options))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001630 return -ENODEV;
1631
1632 if (options && *options)
Knut Petersen44637a12006-01-09 15:04:20 +01001633 while ((opt = strsep(&options, ",")) != NULL) {
1634 if (!*opt)
1635 continue;
1636 else if (!strncmp(opt, "bpp=", 4))
1637 bpp = simple_strtoul(opt + 4, NULL, 0);
1638 else if (!strncmp(opt, "ref=", 4))
1639 ref = simple_strtoul(opt + 4, NULL, 0);
1640 else if (!strncmp(opt, "fp", 2))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001641 displaytype = DISPLAY_FP;
Knut Petersen44637a12006-01-09 15:04:20 +01001642 else if (!strncmp(opt, "crt", 3))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001643 displaytype = DISPLAY_CRT;
Knut Petersen44637a12006-01-09 15:04:20 +01001644 else if (!strncmp(opt, "nativex=", 8))
1645 nativex = simple_strtoul(opt + 8, NULL, 0);
1646 else if (!strncmp(opt, "center", 6))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001647 center = 1;
Knut Petersen44637a12006-01-09 15:04:20 +01001648 else if (!strncmp(opt, "stretch", 7))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001649 stretch = 1;
Knut Petersen44637a12006-01-09 15:04:20 +01001650 else if (!strncmp(opt, "pciwb=", 6))
1651 pciwb = simple_strtoul(opt + 6, NULL, 0);
1652 else if (!strncmp(opt, "pcirb=", 6))
1653 pcirb = simple_strtoul(opt + 6, NULL, 0);
1654 else if (!strncmp(opt, "pciwr=", 6))
1655 pciwr = simple_strtoul(opt + 6, NULL, 0);
1656 else if (!strncmp(opt, "pcirr=", 6))
1657 pcirr = simple_strtoul(opt + 6, NULL, 0);
1658 else if (!strncmp(opt, "memsize=", 8))
1659 memsize = simple_strtoul(opt + 8, NULL, 0);
1660 else if (!strncmp(opt, "verbosity=", 10))
1661 verbosity = simple_strtoul(opt + 10, NULL, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001662 else
1663 mode = opt;
1664 }
1665#endif
Knut Petersen44637a12006-01-09 15:04:20 +01001666 output("CyblaFB version %s initializing\n", VERSION);
Richard Knutsson93b47682005-11-30 01:00:35 +01001667 return pci_register_driver(&cyblafb_pci_driver);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001668}
1669
1670static void __exit cyblafb_exit(void)
1671{
1672 pci_unregister_driver(&cyblafb_pci_driver);
1673}
1674
1675module_init(cyblafb_init);
1676module_exit(cyblafb_exit);
1677
1678MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1679MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1680MODULE_LICENSE("GPL");