blob: 0ae0a97b0fed05c5ea8129b018d2179eecac87bc [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
17#include <linux/config.h>
18#include <linux/module.h>
19#include <linux/string.h>
20#include <linux/fb.h>
21#include <linux/init.h>
22#include <linux/pci.h>
23#include <asm/types.h>
24#include <video/cyblafb.h>
25
Knut Petersen44637a12006-01-09 15:04:20 +010026#define VERSION "0.62"
Knut Petersen9fa68ea2005-09-09 13:04:56 -070027
28struct cyblafb_par {
29 u32 pseudo_pal[16];
30 struct fb_ops ops;
31};
32
33static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
34 .id = "CyBla",
35 .type = FB_TYPE_PACKED_PIXELS,
Knut Petersen44637a12006-01-09 15:04:20 +010036 .xpanstep = 1,
Knut Petersen9fa68ea2005-09-09 13:04:56 -070037 .ypanstep = 1,
Knut Petersen44637a12006-01-09 15:04:20 +010038 .ywrapstep = 1,
Knut Petersen9fa68ea2005-09-09 13:04:56 -070039 .visual = FB_VISUAL_PSEUDOCOLOR,
40 .accel = FB_ACCEL_NONE,
41};
42
43static char *mode __devinitdata = NULL;
44static int bpp __devinitdata = 8;
45static int ref __devinitdata = 75;
46static int fp __devinitdata;
47static int crt __devinitdata;
48static int memsize __devinitdata;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070049
Knut Petersen44637a12006-01-09 15:04:20 +010050static int basestride;
51static int vesafb;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070052static int nativex;
53static int center;
54static int stretch;
55static int pciwb = 1;
56static int pcirb = 1;
57static int pciwr = 1;
58static int pcirr = 1;
Knut Petersen44637a12006-01-09 15:04:20 +010059static int disabled;
Knut Petersen9fa68ea2005-09-09 13:04:56 -070060static int verbosity;
61static int displaytype;
62
Knut Petersen44637a12006-01-09 15:04:20 +010063static void __iomem *io_virt; // iospace virtual memory address
Knut Petersen9fa68ea2005-09-09 13:04:56 -070064
Knut Petersen44637a12006-01-09 15:04:20 +010065module_param(mode, charp, 0);
66module_param(bpp, int, 0);
67module_param(ref, int, 0);
68module_param(fp, int, 0);
69module_param(crt, int, 0);
70module_param(nativex, int, 0);
71module_param(center, int, 0);
72module_param(stretch, int, 0);
73module_param(pciwb, int, 0);
74module_param(pcirb, int, 0);
75module_param(pciwr, int, 0);
76module_param(pcirr, int, 0);
77module_param(memsize, int, 0);
78module_param(verbosity, int, 0);
79
80//=========================================
81//
82// Well, we have to fix the upper layers.
83// Until this has been done, we work around
84// the bugs.
85//
86//=========================================
87
88#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
89 if (disabled) { \
90 printk("********\n");\
91 dump_stack();\
92 return val;\
93 }
94
95#elif CYBLAFB_KD_GRAPHICS_QUIRK
96#define KD_GRAPHICS_RETURN(val)\
97 if (disabled) {\
98 return val;\
99 }
100#else
101#define KD_GRAPHICS_RETURN(val)
102#endif
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700103
104//=========================================
105//
106// Port access macros for memory mapped io
107//
108//=========================================
109
Knut Petersen44637a12006-01-09 15:04:20 +0100110#define out8(r, v) writeb(v, io_virt + r)
111#define out32(r, v) writel(v, io_virt + r)
112#define in8(r) readb(io_virt + r)
113#define in32(r) readl(io_virt + r)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700114
115//======================================
116//
117// Hardware access inline functions
118//
119//======================================
120
Knut Petersen44637a12006-01-09 15:04:20 +0100121static inline u8 read3X4(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700122{
Knut Petersen44637a12006-01-09 15:04:20 +0100123 out8(0x3D4, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700124 return in8(0x3D5);
125}
126
Knut Petersen44637a12006-01-09 15:04:20 +0100127static inline u8 read3C4(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700128{
Knut Petersen44637a12006-01-09 15:04:20 +0100129 out8(0x3C4, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700130 return in8(0x3C5);
131}
132
Knut Petersen44637a12006-01-09 15:04:20 +0100133static inline u8 read3CE(u32 reg)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700134{
Knut Petersen44637a12006-01-09 15:04:20 +0100135 out8(0x3CE, reg);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700136 return in8(0x3CF);
137}
138
Knut Petersen44637a12006-01-09 15:04:20 +0100139static inline void write3X4(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700140{
Knut Petersen44637a12006-01-09 15:04:20 +0100141 out8(0x3D4, reg);
142 out8(0x3D5, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700143}
144
Knut Petersen44637a12006-01-09 15:04:20 +0100145static inline void write3C4(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700146{
Knut Petersen44637a12006-01-09 15:04:20 +0100147 out8(0x3C4, reg);
148 out8(0x3C5, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700149}
150
Knut Petersen44637a12006-01-09 15:04:20 +0100151static inline void write3CE(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700152{
Knut Petersen44637a12006-01-09 15:04:20 +0100153 out8(0x3CE, reg);
154 out8(0x3CF, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700155}
156
Knut Petersen44637a12006-01-09 15:04:20 +0100157static inline void write3C0(u32 reg, u8 val)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700158{
Knut Petersen44637a12006-01-09 15:04:20 +0100159 in8(0x3DA); // read to reset index
160 out8(0x3C0, reg);
161 out8(0x3C0, val);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700162}
163
164//=================================================
165//
166// Enable memory mapped io and unprotect registers
167//
168//=================================================
169
Knut Petersen44637a12006-01-09 15:04:20 +0100170static void enable_mmio(void)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700171{
Knut Petersen44637a12006-01-09 15:04:20 +0100172 u8 tmp;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700173
Knut Petersen44637a12006-01-09 15:04:20 +0100174 outb(0x0B, 0x3C4);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700175 inb(0x3C5); // Set NEW mode
Knut Petersen44637a12006-01-09 15:04:20 +0100176 outb(SR0E, 0x3C4); // write enable a lot of extended ports
177 outb(0x80, 0x3C5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700178
Knut Petersen44637a12006-01-09 15:04:20 +0100179 outb(SR11, 0x3C4); // write enable those extended ports that
180 outb(0x87, 0x3C5); // are not affected by SR0E_New
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700181
Knut Petersen44637a12006-01-09 15:04:20 +0100182 outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2
183 tmp = inb(0x3d5) & 0xBF;
184 outb(CR1E, 0x3d4);
185 outb(tmp, 0x3d5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700186
Knut Petersen44637a12006-01-09 15:04:20 +0100187 outb(CR39, 0x3D4);
188 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700189}
190
191//=================================================
192//
193// Set pixel clock VCLK1
Knut Petersen44637a12006-01-09 15:04:20 +0100194// - multipliers set elswhere
195// - freq in units of 0.01 MHz
196//
197// Hardware bug: SR18 >= 250 is broken for the
198// cyberblade/i1
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700199//
200//=================================================
201
202static void set_vclk(struct cyblafb_par *par, int freq)
203{
Knut Petersen44637a12006-01-09 15:04:20 +0100204 u32 m, n, k;
205 int f, fi, d, di;
206 u8 lo = 0, hi = 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700207
208 d = 2000;
209 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
Knut Petersen44637a12006-01-09 15:04:20 +0100210 for (m = 0; m < 64; m++)
211 for (n = 0; n < 250; n++) {
212 fi = (int)(((5864727 * (n + 8)) /
213 ((m + 2) * (1 << k))) >> 12);
214 if ((di = abs(fi - freq)) < d) {
215 d = di;
216 f = fi;
217 lo = (u8) n;
218 hi = (u8) ((k << 6) | m);
219 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700220 }
Knut Petersen44637a12006-01-09 15:04:20 +0100221 write3C4(SR19, hi);
222 write3C4(SR18, lo);
223 if (verbosity > 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700224 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
Knut Petersen44637a12006-01-09 15:04:20 +0100225 freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700226}
227
228//================================================
229//
230// Cyberblade specific Graphics Engine (GE) setup
231//
232//================================================
233
Knut Petersen44637a12006-01-09 15:04:20 +0100234static void cyblafb_setup_GE(int pitch, int bpp)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700235{
Knut Petersen44637a12006-01-09 15:04:20 +0100236 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700237
238 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100239 case 8:
240 basestride = ((pitch >> 3) << 20) | (0 << 29);
241 break;
242 case 15:
243 basestride = ((pitch >> 3) << 20) | (5 << 29);
244 break;
245 case 16:
246 basestride = ((pitch >> 3) << 20) | (1 << 29);
247 break;
248 case 24:
249 case 32:
250 basestride = ((pitch >> 3) << 20) | (2 << 29);
251 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700252 }
253
Knut Petersen44637a12006-01-09 15:04:20 +0100254 write3X4(CR36, 0x90); // reset GE
255 write3X4(CR36, 0x80); // enable GE
256 out32(GE24, 1 << 7); // reset all GE pointers by toggling
257 out32(GE24, 0); // d7 of GE24
258 write3X4(CR2D, 0x00); // GE Timinigs, no delays
259 out32(GE6C, 0); // Pattern and Style, p 129, ok
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700260}
261
262//=====================================================================
263//
Knut Petersen44637a12006-01-09 15:04:20 +0100264// Cyberblade specific syncing
265//
266// A timeout might be caused by disabled mmio.
267// Cause:
268// - bit CR39 & 1 == 0 upon return, X trident driver bug
269// - kdm bug (KD_GRAPHICS not set on first switch)
270// - kernel design flaw (it believes in the correctness
271// of kdm/X
272// First we try to sync ignoring that problem, as most of the
273// time that will succeed immediately and the enable_mmio()
274// would only degrade performance.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700275//
276//=====================================================================
277
278static int cyblafb_sync(struct fb_info *info)
279{
Knut Petersen44637a12006-01-09 15:04:20 +0100280 u32 status, i = 100000;
281
282 KD_GRAPHICS_RETURN(0);
283
284 while (((status = in32(GE20)) & 0xFe800000) && i != 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700285 i--;
286
287 if (i == 0) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700288 enable_mmio();
Knut Petersen44637a12006-01-09 15:04:20 +0100289 i = 1000000;
290 while (((status = in32(GE20)) & 0xFA800000) && i != 0)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700291 i--;
292 if (i == 0) {
Knut Petersen44637a12006-01-09 15:04:20 +0100293 output("GE Timeout, status: %x\n", status);
294 if (status & 0x80000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700295 output("Bresenham Engine : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100296 if (status & 0x40000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700297 output("Setup Engine : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100298 if (status & 0x20000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700299 output("SP / DPE : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100300 if (status & 0x10000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700301 output("Memory Interface : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100302 if (status & 0x08000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700303 output("Com Lst Proc : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100304 if (status & 0x04000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700305 output("Block Write : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100306 if (status & 0x02000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700307 output("Command Buffer : Full\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100308 if (status & 0x01000000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700309 output("RESERVED : Busy\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100310 if (status & 0x00800000)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700311 output("PCI Write Buffer : Busy\n");
312 cyblafb_setup_GE(info->var.xres,
313 info->var.bits_per_pixel);
314 }
315 }
316
317 return 0;
318}
319
320//==============================
321//
322// Cyberblade specific fillrect
323//
324//==============================
325
Knut Petersen44637a12006-01-09 15:04:20 +0100326static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700327{
Knut Petersen44637a12006-01-09 15:04:20 +0100328 u32 bpp = info->var.bits_per_pixel, col, desty, height;
329
330 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700331
332 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100333 default:
334 case 8:
335 col = fr->color;
336 col |= col << 8;
337 col |= col << 16;
338 break;
339 case 16:
340 col = ((u32 *) (info->pseudo_palette))[fr->color];
341 col |= col << 16;
342 break;
343 case 32:
344 col = ((u32 *) (info->pseudo_palette))[fr->color];
345 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700346 }
347
Knut Petersen44637a12006-01-09 15:04:20 +0100348 desty = fr->dy;
349 height = fr->height;
350 while (height) {
351 out32(GEB8, basestride | ((desty * info->var.xres_virtual *
352 bpp) >> 6));
353 out32(GE60, col);
354 out32(GE48, fr->rop ? 0x66 : ROP_S);
355 out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
356 out32(GE08, point(fr->dx, 0));
357 out32(GE0C, point(fr->dx + fr->width - 1,
358 height > 4096 ? 4095 : height - 1));
359 if (likely(height <= 4096))
360 return;
361 desty += 4096;
362 height -= 4096;
363 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700364}
365
Knut Petersen44637a12006-01-09 15:04:20 +0100366//================================================
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700367//
368// Cyberblade specific copyarea
369//
Knut Petersen44637a12006-01-09 15:04:20 +0100370// This function silently assumes that it never
371// will be called with width or height exceeding
372// 4096.
373//
374//================================================
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700375
Knut Petersen44637a12006-01-09 15:04:20 +0100376static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700377{
Knut Petersen44637a12006-01-09 15:04:20 +0100378 u32 s1, s2, d1, d2, direction;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700379
Knut Petersen44637a12006-01-09 15:04:20 +0100380 KD_GRAPHICS_RETURN();
381
382 s1 = point(ca->sx, 0);
383 s2 = point(ca->sx + ca->width - 1, ca->height - 1);
384 d1 = point(ca->dx, 0);
385 d2 = point(ca->dx + ca->width - 1, ca->height - 1);
386
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700387 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
388 direction = 0;
389 else
390 direction = 2;
391
Knut Petersen44637a12006-01-09 15:04:20 +0100392 out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
393 info->var.bits_per_pixel) >> 6));
394 out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
395 info->var.bits_per_pixel) >> 6));
396 out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
397 out32(GE00, direction ? s2 : s1);
398 out32(GE04, direction ? s1 : s2);
399 out32(GE08, direction ? d2 : d1);
400 out32(GE0C, direction ? d1 : d2);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700401}
402
403//=======================================================================
404//
405// Cyberblade specific imageblit
406//
Knut Petersen44637a12006-01-09 15:04:20 +0100407// Accelerated for the most usual case, blitting 1 - bit deep
408// character images. Everything else is passed to the generic imageblit
409// unless it is so insane that it is better to printk an alert.
410//
411// Hardware bug: _Never_ blit across pixel column 2048, that will lock
412// the system. We split those blit requests into three blitting
413// operations.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700414//
415//=======================================================================
416
417static void cyblafb_imageblit(struct fb_info *info,
418 const struct fb_image *image)
419{
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700420 u32 fgcol, bgcol;
Knut Petersen44637a12006-01-09 15:04:20 +0100421 u32 *pd = (u32 *) image->data;
422 u32 bpp = info->var.bits_per_pixel;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700423
Knut Petersen44637a12006-01-09 15:04:20 +0100424 KD_GRAPHICS_RETURN();
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700425
Knut Petersen44637a12006-01-09 15:04:20 +0100426 // Used only for drawing the penguine (image->depth > 1)
427 if (image->depth != 1) {
428 cfb_imageblit(info, image);
429 return;
430 }
431 // That should never happen, but it would be fatal
432 if (image->width == 0 || image->height == 0) {
433 output("imageblit: width/height 0 detected\n");
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700434 return;
435 }
436
437 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
438 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
Knut Petersen44637a12006-01-09 15:04:20 +0100439 fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
440 bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700441 } else {
442 fgcol = image->fg_color;
443 bgcol = image->bg_color;
444 }
445
446 switch (bpp) {
Knut Petersen44637a12006-01-09 15:04:20 +0100447 case 8:
448 fgcol |= fgcol << 8;
449 bgcol |= bgcol << 8;
450 case 16:
451 fgcol |= fgcol << 16;
452 bgcol |= bgcol << 16;
453 default:
454 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700455 }
456
Knut Petersen44637a12006-01-09 15:04:20 +0100457 out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
458 bpp) >> 6));
459 out32(GE60, fgcol);
460 out32(GE64, bgcol);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700461
Knut Petersen44637a12006-01-09 15:04:20 +0100462 if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
463 u32 dds = ((image->width + 31) >> 5) * image->height;
464 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
465 out32(GE08, point(image->dx, 0));
466 out32(GE0C, point(image->dx + image->width - 1,
467 image->height - 1));
468 while (dds--)
469 out32(GE9C, *pd++);
470 } else {
471 int i, j;
472 u32 ddstotal = (image->width + 31) >> 5;
473 u32 ddsleft = (2048 - image->dx + 31) >> 5;
474 u32 skipleft = ddstotal - ddsleft;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700475
Knut Petersen44637a12006-01-09 15:04:20 +0100476 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
477 out32(GE08, point(image->dx, 0));
478 out32(GE0C, point(2048 - 1, image->height - 1));
479 for (i = 0; i < image->height; i++) {
480 for (j = 0; j < ddsleft; j++)
481 out32(GE9C, *pd++);
482 pd += skipleft;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700483 }
Knut Petersen44637a12006-01-09 15:04:20 +0100484
485 if (image->dx % 32) {
486 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
487 out32(GE08, point(2048, 0));
488 if (image->width > ddsleft << 5)
489 out32(GE0C, point(image->dx + (ddsleft << 5) -
490 1, image->height - 1));
491 else
492 out32(GE0C, point(image->dx + image->width - 1,
493 image->height - 1));
494 pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
495 for (i = 0; i < image->height; i++) {
496 out32(GE9C, swab32(swab32(*pd) << ((32 -
497 (image->dx & 31)) & 31)));
498 pd += ddstotal;
499 }
500 }
501
502 if (skipleft) {
503 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
504 out32(GE08, point(image->dx + (ddsleft << 5), 0));
505 out32(GE0C, point(image->dx + image->width - 1,
506 image->height - 1));
507 pd = (u32 *) image->data;
508 for (i = 0; i < image->height; i++) {
509 pd += ddsleft;
510 for (j = 0; j < skipleft; j++)
511 out32(GE9C, *pd++);
512 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700513 }
514 }
515}
516
517//==========================================================
518//
519// Check if video mode is acceptable. We change var->??? if
520// video mode is slightly off or return error otherwise.
521// info->??? must not be changed!
522//
523//==========================================================
524
525static int cyblafb_check_var(struct fb_var_screeninfo *var,
526 struct fb_info *info)
527{
528 int bpp = var->bits_per_pixel;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700529
530 //
531 // we try to support 8, 16, 24 and 32 bpp modes,
532 // default to 8
533 //
534 // there is a 24 bpp mode, but for now we change requests to 32 bpp
535 // (This is what tridentfb does ... will be changed in the future)
536 //
537 //
Knut Petersen44637a12006-01-09 15:04:20 +0100538 if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700539 bpp = 8;
Knut Petersen44637a12006-01-09 15:04:20 +0100540 if (bpp == 24)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700541 bpp = var->bits_per_pixel = 32;
542
543 //
544 // interlaced modes are broken, fail if one is requested
545 //
546 if (var->vmode & FB_VMODE_INTERLACED)
547 return -EINVAL;
548
549 //
550 // fail if requested resolution is higher than physical
551 // flatpanel resolution
552 //
553 if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
554 return -EINVAL;
555
556 //
Knut Petersen44637a12006-01-09 15:04:20 +0100557 // we do not allow vclk to exceed 230 MHz. If the requested
558 // vclk is too high, we default to 200 MHz
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700559 //
Knut Petersen44637a12006-01-09 15:04:20 +0100560 if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
561 var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700562
563 //
Knut Petersen44637a12006-01-09 15:04:20 +0100564 // enforce (h|v)sync_len limits
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700565 //
Knut Petersen44637a12006-01-09 15:04:20 +0100566 var->hsync_len &= ~7;
567 if(var->hsync_len > 248)
568 var->hsync_len = 248;
569
570 var->vsync_len &= 15;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700571
572 //
Knut Petersen44637a12006-01-09 15:04:20 +0100573 // Enforce horizontal and vertical hardware limits.
574 // 1600x1200 is mentioned as a maximum, but higher resolutions could
575 // work with slow refresh, small margins and short sync.
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700576 //
Knut Petersen44637a12006-01-09 15:04:20 +0100577 var->xres &= ~7;
578
579 if (((var->xres + var->left_margin + var->right_margin +
580 var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
581 ((var->yres + var->upper_margin + var->lower_margin +
582 var->vsync_len) > 2047))
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700583 return -EINVAL;
584
Knut Petersen44637a12006-01-09 15:04:20 +0100585 if ((var->xres > 1600) || (var->yres > 1200))
586 output("Mode %dx%d exceeds documented limits.\n",
587 var->xres, var->yres);
588 //
589 // try to be smart about (x|y)res_virtual problems.
590 //
591 if (var->xres > var->xres_virtual)
592 var->xres_virtual = var->xres;
593 if (var->yres > var->yres_virtual)
594 var->yres_virtual = var->yres;
595
596 if (bpp == 8 || bpp == 16) {
597 if (var->xres_virtual > 4088)
598 var->xres_virtual = 4088;
599 } else {
600 if (var->xres_virtual > 2040)
601 var->xres_virtual = 2040;
602 }
603 var->xres_virtual &= ~7;
604 while (var->xres_virtual * var->yres_virtual * bpp / 8 >
605 info->fix.smem_len) {
606 if (var->yres_virtual > var->yres)
607 var->yres_virtual--;
608 else if (var->xres_virtual > var->xres)
609 var->xres_virtual -= 8;
610 else
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700611 return -EINVAL;
612 }
613
Knut Petersen44637a12006-01-09 15:04:20 +0100614 switch (bpp) {
615 case 8:
616 var->red.offset = 0;
617 var->green.offset = 0;
618 var->blue.offset = 0;
619 var->red.length = 6;
620 var->green.length = 6;
621 var->blue.length = 6;
622 break;
623 case 16:
624 var->red.offset = 11;
625 var->green.offset = 5;
626 var->blue.offset = 0;
627 var->red.length = 5;
628 var->green.length = 6;
629 var->blue.length = 5;
630 break;
631 case 32:
632 var->red.offset = 16;
633 var->green.offset = 8;
634 var->blue.offset = 0;
635 var->red.length = 8;
636 var->green.length = 8;
637 var->blue.length = 8;
638 break;
639 default:
640 return -EINVAL;
641 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700642
Knut Petersen44637a12006-01-09 15:04:20 +0100643 return 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700644}
645
646//=====================================================================
647//
648// Pan the display
649//
650// The datasheets defines crt start address to be 20 bits wide and
651// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
652// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
653// it, so it is also safe to be used here. BTW: datasheet CR0E on page
654// 90 really is CR1E, the real CRE is documented on page 72.
655//
Knut Petersen44637a12006-01-09 15:04:20 +0100656// BUT:
657//
658// As of internal version 0.60 we do not use vga panning any longer.
659// Vga panning did not allow us the use of all available video memory
660// and thus prevented ywrap scrolling. We do use the "right view"
661// register now.
662//
663//
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700664//=====================================================================
665
666static int cyblafb_pan_display(struct fb_var_screeninfo *var,
667 struct fb_info *info)
668{
Knut Petersen44637a12006-01-09 15:04:20 +0100669 KD_GRAPHICS_RETURN(0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700670
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700671 info->var.xoffset = var->xoffset;
672 info->var.yoffset = var->yoffset;
Knut Petersen44637a12006-01-09 15:04:20 +0100673 out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
674 var->xres_virtual)) * var->bits_per_pixel / 32));
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700675 return 0;
676}
677
678//============================================
679//
680// This will really help in case of a bug ...
681// dump most gaphics core registers.
682//
683//============================================
684
685static void regdump(struct cyblafb_par *par)
686{
687 int i;
688
689 if (verbosity < 2)
690 return;
691
692 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100693 for (i = 0; i <= 0xff; i++) {
694 outb(i, 0x3d4);
695 printk("CR%02x=%02x ", i, inb(0x3d5));
696 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700697 printk("\n");
698 }
699
Knut Petersen44637a12006-01-09 15:04:20 +0100700 outb(0x30, 0x3ce);
701 outb(inb(0x3cf) | 0x40, 0x3cf);
702 for (i = 0; i <= 0x1f; i++) {
703 if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
704 || i == 0x16) {
705 outb(i, 0x3d4);
706 printk("CR%02x=%02x ", i, inb(0x3d5));
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700707 } else
708 printk("------- ");
Knut Petersen44637a12006-01-09 15:04:20 +0100709 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700710 printk("\n");
711 }
Knut Petersen44637a12006-01-09 15:04:20 +0100712 outb(0x30, 0x3ce);
713 outb(inb(0x3cf) & 0xbf, 0x3cf);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700714
715 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100716 for (i = 0; i <= 0x7f; i++) {
717 outb(i, 0x3ce);
718 printk("GR%02x=%02x ", i, inb(0x3cf));
719 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700720 printk("\n");
721 }
722
723 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100724 for (i = 0; i <= 0xff; i++) {
725 outb(i, 0x3c4);
726 printk("SR%02x=%02x ", i, inb(0x3c5));
727 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700728 printk("\n");
729 }
730
731 printk("\n");
Knut Petersen44637a12006-01-09 15:04:20 +0100732 for (i = 0; i <= 0x1F; i++) {
733 inb(0x3da); // next access is index!
734 outb(i, 0x3c0);
735 printk("AR%02x=%02x ", i, inb(0x3c1));
736 if (i % 16 == 15)
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700737 printk("\n");
738 }
739 printk("\n");
740
Knut Petersen44637a12006-01-09 15:04:20 +0100741 inb(0x3DA); // reset internal flag to 3c0 index
742 outb(0x20, 0x3C0); // enable attr
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700743
744 return;
745}
746
Knut Petersen44637a12006-01-09 15:04:20 +0100747//=======================================================================
748//
749// Save State
750//
751// This function is called while a switch to KD_TEXT is in progress,
752// before any of the other functions are called.
753//
754//=======================================================================
755
756static void cyblafb_save_state(struct fb_info *info)
757{
758 struct cyblafb_par *par = info->par;
759 if (verbosity > 0)
760 output("Switching to KD_TEXT\n");
761 disabled = 0;
762 regdump(par);
763 enable_mmio();
764 return;
765}
766
767//=======================================================================
768//
769// Restore State
770//
771// This function is called while a switch to KD_GRAPHICS is in progress,
772// We have to turn on vga style panning registers again because the
773// trident driver of X does not know about GE10.
774//
775//=======================================================================
776
777static void cyblafb_restore_state(struct fb_info *info)
778{
779 if (verbosity > 0)
780 output("Switching to KD_GRAPHICS\n");
781 out32(GE10, 0);
782 disabled = 1;
783 return;
784}
785
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700786//======================================
787//
788// Set hardware to requested video mode
789//
790//======================================
791
792static int cyblafb_set_par(struct fb_info *info)
793{
794 struct cyblafb_par *par = info->par;
Knut Petersen44637a12006-01-09 15:04:20 +0100795 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
796 hblankend, preendfetch, vtotal, vdispend, vsyncstart,
797 vsyncend, vblankstart, vblankend;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700798 struct fb_var_screeninfo *var = &info->var;
799 int bpp = var->bits_per_pixel;
800 int i;
801
Knut Petersen44637a12006-01-09 15:04:20 +0100802 KD_GRAPHICS_RETURN(0);
803
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700804 if (verbosity > 0)
805 output("Switching to new mode: "
806 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
Knut Petersen44637a12006-01-09 15:04:20 +0100807 var->xres, var->yres, var->xres_virtual,
808 var->yres_virtual, var->bits_per_pixel, var->pixclock,
809 var->left_margin, var->right_margin, var->upper_margin,
810 var->lower_margin, var->hsync_len, var->vsync_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700811
812 htotal = (var->xres + var->left_margin + var->right_margin +
Knut Petersen44637a12006-01-09 15:04:20 +0100813 var->hsync_len) / 8 - 5;
814 hdispend = var->xres / 8 - 1;
815 hsyncstart = (var->xres + var->right_margin) / 8;
816 hsyncend = var->hsync_len / 8;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700817 hblankstart = hdispend + 1;
818 hblankend = htotal + 3; // should be htotal + 5, bios does it this way
Knut Petersen44637a12006-01-09 15:04:20 +0100819 preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700820
821 vtotal = var->yres + var->upper_margin + var->lower_margin +
Knut Petersen44637a12006-01-09 15:04:20 +0100822 var->vsync_len - 2;
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700823 vdispend = var->yres - 1;
824 vsyncstart = var->yres + var->lower_margin;
825 vblankstart = var->yres;
826 vblankend = vtotal; // should be vtotal + 2, but bios does it this way
827 vsyncend = var->vsync_len;
828
829 enable_mmio(); // necessary! ... check X ...
830
Knut Petersen44637a12006-01-09 15:04:20 +0100831 write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700832
Knut Petersen44637a12006-01-09 15:04:20 +0100833 write3CE(GR30, 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700834
835 if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
836
837 // stretch or center ?
838
Knut Petersen44637a12006-01-09 15:04:20 +0100839 out8(0x3C2, 0xEB);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700840
Knut Petersen44637a12006-01-09 15:04:20 +0100841 write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700842
843 if (center) {
Knut Petersen44637a12006-01-09 15:04:20 +0100844 write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
845 write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
846 } else if (stretch) {
847 write3CE(GR5D, 0);
848 write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
849 write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700850 }
851
852 } else {
Knut Petersen44637a12006-01-09 15:04:20 +0100853 out8(0x3C2, 0x2B);
854 write3CE(GR30, 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700855 }
856
857 //
858 // Setup CRxx regs
859 //
860
Knut Petersen44637a12006-01-09 15:04:20 +0100861 write3X4(CR00, htotal & 0xFF);
862 write3X4(CR01, hdispend & 0xFF);
863 write3X4(CR02, hblankstart & 0xFF);
864 write3X4(CR03, hblankend & 0x1F);
865 write3X4(CR04, hsyncstart & 0xFF);
866 write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
867 write3X4(CR06, vtotal & 0xFF);
868 write3X4(CR07, (vtotal & 0x100) >> 8 |
869 (vdispend & 0x100) >> 7 |
870 (vsyncstart & 0x100) >> 6 |
871 (vblankstart & 0x100) >> 5 |
872 0x10 |
873 (vtotal & 0x200) >> 4 |
874 (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
875 write3X4(CR08, 0);
876 write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
877 ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
878 write3X4(CR0A, 0); // Init to some reasonable default
879 write3X4(CR0B, 0); // Init to some reasonable default
880 write3X4(CR0C, 0); // Offset 0
881 write3X4(CR0D, 0); // Offset 0
882 write3X4(CR0E, 0); // Init to some reasonable default
883 write3X4(CR0F, 0); // Init to some reasonable default
884 write3X4(CR10, vsyncstart & 0xFF);
885 write3X4(CR11, (vsyncend & 0x0F));
886 write3X4(CR12, vdispend & 0xFF);
887 write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
888 write3X4(CR14, 0x40); // double word mode
889 write3X4(CR15, vblankstart & 0xFF);
890 write3X4(CR16, vblankend & 0xFF);
891 write3X4(CR17, 0xE3);
892 write3X4(CR18, 0xFF);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700893 // CR19: needed for interlaced modes ... ignore it for now
Knut Petersen44637a12006-01-09 15:04:20 +0100894 write3X4(CR1A, 0x07); // Arbitration Control Counter 1
895 write3X4(CR1B, 0x07); // Arbitration Control Counter 2
896 write3X4(CR1C, 0x07); // Arbitration Control Counter 3
897 write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -)
898 write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700899 // CR1F: do not set, contains BIOS info about memsize
Knut Petersen44637a12006-01-09 15:04:20 +0100900 write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode
901 write3X4(CR21, 0x20); // enable linear memory access
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700902 // CR22: RO cpu latch readback
903 // CR23: ???
904 // CR24: RO AR flag state
905 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
906 // CR26: ???
Knut Petersen44637a12006-01-09 15:04:20 +0100907 write3X4(CR27, (vdispend & 0x400) >> 6 |
908 (vsyncstart & 0x400) >> 5 |
909 (vblankstart & 0x400) >> 4 |
910 (vtotal & 0x400) >> 3 |
911 0x8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700912 // CR28: ???
Knut Petersen44637a12006-01-09 15:04:20 +0100913 write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
914 bpp) / (4 * 16)) & 0x300) >> 4));
915 write3X4(CR2A, read3X4(CR2A) | 0x40);
916 write3X4(CR2B, (htotal & 0x100) >> 8 |
917 (hdispend & 0x100) >> 7 |
918 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
919 (hsyncstart & 0x100) >> 5 |
920 (hblankstart & 0x100) >> 4);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700921 // CR2C: ???
922 // CR2D: initialized in cyblafb_setup_GE()
Knut Petersen44637a12006-01-09 15:04:20 +0100923 write3X4(CR2F, 0x92); // conservative, better signal quality
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700924 // CR30: reserved
925 // CR31: reserved
926 // CR32: reserved
927 // CR33: reserved
928 // CR34: disabled in CR36
929 // CR35: disabled in CR36
930 // CR36: initialized in cyblafb_setup_GE
931 // CR37: i2c, ignore for now
Knut Petersen44637a12006-01-09 15:04:20 +0100932 write3X4(CR38, (bpp == 8) ? 0x00 : //
933 (bpp == 16) ? 0x05 : // highcolor
934 (bpp == 24) ? 0x29 : // packed 24bit truecolor
935 (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
936 write3X4(CR39, 0x01 | // MMIO enable
937 (pcirb ? 0x02 : 0) | // pci read burst enable
938 (pciwb ? 0x04 : 0)); // pci write burst enable
939 write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
940 (pcirr ? 0x40 : 0) | // pci read retry enable
941 (pciwr ? 0x80 : 0)); // pci write retry enable
942 write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
943 : 0);
944 write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
945 write3X4(CR58, 0x82); // Bios does this .... don't know more
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700946 //
947 // Setup SRxx regs
948 //
Knut Petersen44637a12006-01-09 15:04:20 +0100949 write3C4(SR00, 3);
950 write3C4(SR01, 1); //set char clock 8 dots wide
951 write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode
952 write3C4(SR03, 0); //no character map select
953 write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700954
Knut Petersen44637a12006-01-09 15:04:20 +0100955 out8(0x3C4, 0x0b);
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700956 in8(0x3C5); // Set NEW mode
Knut Petersen44637a12006-01-09 15:04:20 +0100957 write3C4(SR0D, 0x00); // test ... check
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700958
Knut Petersen44637a12006-01-09 15:04:20 +0100959 set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
960 / info->var.pixclock); //SR18, SR19
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700961
962 //
963 // Setup GRxx regs
964 //
Knut Petersen44637a12006-01-09 15:04:20 +0100965 write3CE(GR00, 0x00); // test ... check
966 write3CE(GR01, 0x00); // test ... check
967 write3CE(GR02, 0x00); // test ... check
968 write3CE(GR03, 0x00); // test ... check
969 write3CE(GR04, 0x00); // test ... check
970 write3CE(GR05, 0x40); // no CGA compat, allow 256 col
971 write3CE(GR06, 0x05); // graphics mode
972 write3CE(GR07, 0x0F); // planes?
973 write3CE(GR08, 0xFF); // test ... check
974 write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
975 write3CE(GR20, 0xC0); // test ... check
976 write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew,
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700977
978 //
979 // Setup ARxx regs
980 //
Knut Petersen44637a12006-01-09 15:04:20 +0100981 for (i = 0; i < 0x10; i++) // set AR00 .. AR0f
982 write3C0(i, i);
983 write3C0(AR10, 0x41); // graphics mode and support 256 color modes
984 write3C0(AR12, 0x0F); // planes
985 write3C0(AR13, 0); // horizontal pel panning
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700986 in8(0x3DA); // reset internal flag to 3c0 index
Knut Petersen44637a12006-01-09 15:04:20 +0100987 out8(0x3C0, 0x20); // enable attr
Knut Petersen9fa68ea2005-09-09 13:04:56 -0700988
989 //
990 // Setup hidden RAMDAC command register
991 //
Knut Petersen44637a12006-01-09 15:04:20 +0100992 in8(0x3C8); // these reads are
993 in8(0x3C6); // necessary to
994 in8(0x3C6); // unmask the RAMDAC
995 in8(0x3C6); // command reg, otherwise
996 in8(0x3C6); // we would write the pixelmask reg!
997 out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
998 (bpp == 15) ? 0x10 : //
999 (bpp == 16) ? 0x30 : // hicolor
1000 (bpp == 24) ? 0xD0 : // truecolor
1001 (bpp == 32) ? 0xD0 : 0); // truecolor
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001002 in8(0x3C8);
1003
1004 //
1005 // GR31 is not mentioned in the datasheet
1006 //
1007 if (displaytype == DISPLAY_FP)
Knut Petersen44637a12006-01-09 15:04:20 +01001008 write3CE(GR31, (read3CE(GR31) & 0x8F) |
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001009 ((info->var.yres > 1024) ? 0x50 :
Knut Petersen44637a12006-01-09 15:04:20 +01001010 (info->var.yres > 768) ? 0x30 :
1011 (info->var.yres > 600) ? 0x20 :
1012 (info->var.yres > 480) ? 0x10 : 0));
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001013
1014 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
1015 : FB_VISUAL_TRUECOLOR;
Knut Petersen44637a12006-01-09 15:04:20 +01001016 info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
1017 info->cmap.len = (bpp == 8) ? 256 : 16;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001018
1019 //
1020 // init acceleration engine
1021 //
Knut Petersen44637a12006-01-09 15:04:20 +01001022 cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
1023
1024 //
1025 // Set/clear flags to allow proper scroll mode selection.
1026 //
1027 if (var->xres == var->xres_virtual)
1028 info->flags &= ~FBINFO_HWACCEL_XPAN;
1029 else
1030 info->flags |= FBINFO_HWACCEL_XPAN;
1031
1032 if (var->yres == var->yres_virtual)
1033 info->flags &= ~FBINFO_HWACCEL_YPAN;
1034 else
1035 info->flags |= FBINFO_HWACCEL_YPAN;
1036
1037 if (info->fix.smem_len !=
1038 var->xres_virtual * var->yres_virtual * bpp / 8)
1039 info->flags &= ~FBINFO_HWACCEL_YWRAP;
1040 else
1041 info->flags |= FBINFO_HWACCEL_YWRAP;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001042
1043 regdump(par);
1044
1045 return 0;
1046}
1047
1048//========================
1049//
1050// Set one color register
1051//
1052//========================
1053
1054static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
1055 unsigned blue, unsigned transp,
1056 struct fb_info *info)
1057{
1058 int bpp = info->var.bits_per_pixel;
1059
Knut Petersen44637a12006-01-09 15:04:20 +01001060 KD_GRAPHICS_RETURN(0);
1061
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001062 if (regno >= info->cmap.len)
1063 return 1;
1064
1065 if (bpp == 8) {
Knut Petersen44637a12006-01-09 15:04:20 +01001066 out8(0x3C6, 0xFF);
1067 out8(0x3C8, regno);
1068 out8(0x3C9, red >> 10);
1069 out8(0x3C9, green >> 10);
1070 out8(0x3C9, blue >> 10);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001071
Knut Petersen44637a12006-01-09 15:04:20 +01001072 } else if (bpp == 16) // RGB 565
1073 ((u32 *) info->pseudo_palette)[regno] =
1074 (red & 0xF800) |
1075 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
1076 else if (bpp == 32) // ARGB 8888
1077 ((u32 *) info->pseudo_palette)[regno] =
1078 ((transp & 0xFF00) << 16) |
1079 ((red & 0xFF00) << 8) |
1080 ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001081
1082 return 0;
1083}
1084
1085//==========================================================
1086//
1087// Try blanking the screen. For flat panels it does nothing
1088//
1089//==========================================================
1090
1091static int cyblafb_blank(int blank_mode, struct fb_info *info)
1092{
Knut Petersen44637a12006-01-09 15:04:20 +01001093 unsigned char PMCont, DPMSCont;
1094
1095 KD_GRAPHICS_RETURN(0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001096
1097 if (displaytype == DISPLAY_FP)
1098 return 0;
1099
Knut Petersen44637a12006-01-09 15:04:20 +01001100 out8(0x83C8, 0x04); // DPMS Control
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001101 PMCont = in8(0x83C6) & 0xFC;
1102
1103 DPMSCont = read3CE(GR23) & 0xFC;
1104
Knut Petersen44637a12006-01-09 15:04:20 +01001105 switch (blank_mode) {
1106 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
1107 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001108 PMCont |= 0x03;
1109 DPMSCont |= 0x00;
1110 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001111 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001112 PMCont |= 0x02;
1113 DPMSCont |= 0x01;
1114 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001115 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001116 PMCont |= 0x02;
1117 DPMSCont |= 0x02;
1118 break;
Knut Petersen44637a12006-01-09 15:04:20 +01001119 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001120 PMCont |= 0x00;
1121 DPMSCont |= 0x03;
1122 break;
1123 }
1124
Knut Petersen44637a12006-01-09 15:04:20 +01001125 write3CE(GR23, DPMSCont);
1126 out8(0x83C8, 4);
1127 out8(0x83C6, PMCont);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001128 //
1129 // let fbcon do a softblank for us
1130 //
1131 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1132}
1133
1134static struct fb_ops cyblafb_ops __devinitdata = {
Knut Petersen44637a12006-01-09 15:04:20 +01001135 .owner = THIS_MODULE,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001136 .fb_setcolreg = cyblafb_setcolreg,
1137 .fb_pan_display = cyblafb_pan_display,
1138 .fb_blank = cyblafb_blank,
1139 .fb_check_var = cyblafb_check_var,
1140 .fb_set_par = cyblafb_set_par,
1141 .fb_fillrect = cyblafb_fillrect,
Knut Petersen44637a12006-01-09 15:04:20 +01001142 .fb_copyarea = cyblafb_copyarea,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001143 .fb_imageblit = cyblafb_imageblit,
Knut Petersen44637a12006-01-09 15:04:20 +01001144 .fb_sync = cyblafb_sync,
1145 .fb_restore_state = cyblafb_restore_state,
1146 .fb_save_state = cyblafb_save_state,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001147};
1148
1149//==========================================================================
1150//
1151// getstartupmode() decides about the inital video mode
1152//
1153// There is no reason to use modedb, a lot of video modes there would
1154// need altered timings to display correctly. So I decided that it is much
1155// better to provide a limited optimized set of modes plus the option of
1156// using the mode in effect at startup time (might be selected using the
1157// vga=??? paramter). After that the user might use fbset to select any
1158// mode he likes, check_var will not try to alter geometry parameters as
1159// it would be necessary otherwise.
1160//
1161//==========================================================================
1162
1163static int __devinit getstartupmode(struct fb_info *info)
1164{
Knut Petersen44637a12006-01-09 15:04:20 +01001165 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
1166 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
1167 cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
1168 cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
1169 cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001170
1171 struct modus {
Knut Petersen44637a12006-01-09 15:04:20 +01001172 int xres; int vxres; int yres; int vyres;
1173 int bpp; int pxclk;
1174 int left_margin; int right_margin;
1175 int upper_margin; int lower_margin;
1176 int hsync_len; int vsync_len;
1177 } modedb[5] = {
1178 {
1179 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1180 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1181 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1182 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1183 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001184 };
1185
Knut Petersen44637a12006-01-09 15:04:20 +01001186 outb(0x00, 0x3d4); cr00 = inb(0x3d5);
1187 outb(0x01, 0x3d4); cr01 = inb(0x3d5);
1188 outb(0x02, 0x3d4); cr02 = inb(0x3d5);
1189 outb(0x03, 0x3d4); cr03 = inb(0x3d5);
1190 outb(0x04, 0x3d4); cr04 = inb(0x3d5);
1191 outb(0x05, 0x3d4); cr05 = inb(0x3d5);
1192 outb(0x06, 0x3d4); cr06 = inb(0x3d5);
1193 outb(0x07, 0x3d4); cr07 = inb(0x3d5);
1194 outb(0x09, 0x3d4); cr09 = inb(0x3d5);
1195 outb(0x10, 0x3d4); cr10 = inb(0x3d5);
1196 outb(0x11, 0x3d4); cr11 = inb(0x3d5);
1197 outb(0x12, 0x3d4); cr12 = inb(0x3d5);
1198 outb(0x15, 0x3d4); cr15 = inb(0x3d5);
1199 outb(0x16, 0x3d4); cr16 = inb(0x3d5);
1200 outb(0x27, 0x3d4); cr27 = inb(0x3d5);
1201 outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
1202 outb(0x38, 0x3d4); cr38 = inb(0x3d5);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001203
Knut Petersen44637a12006-01-09 15:04:20 +01001204 outb(0x0b, 0x3c4);
1205 inb(0x3c5);
1206
1207 outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
1208 outb(0x18, 0x3c4); sr18 = inb(0x3c5);
1209 outb(0x19, 0x3c4); sr19 = inb(0x3c5);
1210 outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
1211
1212 htotal = cr00 | (cr2b & 0x01) << 8;
1213 hdispend = cr01 | (cr2b & 0x02) << 7;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001214 hblankstart = cr02 | (cr2b & 0x10) << 4;
Knut Petersen44637a12006-01-09 15:04:20 +01001215 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1216 hsyncstart = cr04 | (cr2b & 0x08) << 5;
1217 hsyncend = cr05 & 0x1f;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001218
1219 modedb[0].xres = hblankstart * 8;
1220 modedb[0].hsync_len = hsyncend * 8;
1221 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1222 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
Knut Petersen44637a12006-01-09 15:04:20 +01001223 modedb[0].right_margin - modedb[0].hsync_len;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001224
Knut Petersen44637a12006-01-09 15:04:20 +01001225 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1226 | (cr27 & 0x80) << 3;
1227 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1228 | (cr27 & 0x10) << 6;
1229 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1230 | (cr27 & 0x20) << 5;
1231 vsyncend = cr11 & 0x0f;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001232 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
Knut Petersen44637a12006-01-09 15:04:20 +01001233 | (cr27 & 0x40) << 4;
1234 vblankend = cr16;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001235
Knut Petersen44637a12006-01-09 15:04:20 +01001236 modedb[0].yres = vdispend + 1;
1237 modedb[0].vsync_len = vsyncend;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001238 modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1239 modedb[0].upper_margin = vtotal - modedb[0].yres -
Knut Petersen44637a12006-01-09 15:04:20 +01001240 modedb[0].lower_margin - modedb[0].vsync_len + 2;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001241
1242 tmp = cr38 & 0x3c;
1243 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
Knut Petersen44637a12006-01-09 15:04:20 +01001244 tmp == 8 ? 32 : 8;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001245
Knut Petersen44637a12006-01-09 15:04:20 +01001246 fi = ((5864727 * (sr18 + 8)) /
1247 (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001248 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1249 tmp = sr0d & 0x06;
1250 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1251 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1252
1253 if (verbosity > 0)
1254 output("detected startup mode: "
1255 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
Knut Petersen44637a12006-01-09 15:04:20 +01001256 modedb[0].xres, modedb[0].yres, modedb[0].xres,
1257 modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
1258 modedb[0].right_margin, modedb[0].upper_margin,
1259 modedb[0].lower_margin, modedb[0].hsync_len,
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001260 modedb[0].vsync_len);
1261
1262 //
1263 // We use this goto target in case of a failed check_var. No, I really
1264 // do not want to do it in another way!
1265 //
1266
Knut Petersen44637a12006-01-09 15:04:20 +01001267 tryagain:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001268
1269 i = (mode == NULL) ? 0 :
Knut Petersen44637a12006-01-09 15:04:20 +01001270 !strncmp(mode, "640x480", 7) ? 1 :
1271 !strncmp(mode, "800x600", 7) ? 2 :
1272 !strncmp(mode, "1024x768", 8) ? 3 :
1273 !strncmp(mode, "1280x1024", 9) ? 4 : 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001274
1275 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1276
Knut Petersen44637a12006-01-09 15:04:20 +01001277 if (i == 0) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001278 info->var.pixclock = modedb[i].pxclk;
1279 info->var.bits_per_pixel = modedb[i].bpp;
1280 } else {
1281 info->var.pixclock = (100000000 /
Knut Petersen44637a12006-01-09 15:04:20 +01001282 ((modedb[i].left_margin +
1283 modedb[i].xres +
1284 modedb[i].right_margin +
1285 modedb[i].hsync_len) *
1286 (modedb[i].upper_margin +
1287 modedb[i].yres +
1288 modedb[i].lower_margin +
1289 modedb[i].vsync_len) * ref / 10000));
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001290 info->var.bits_per_pixel = bpp;
1291 }
1292
1293 info->var.left_margin = modedb[i].left_margin;
1294 info->var.right_margin = modedb[i].right_margin;
1295 info->var.xres = modedb[i].xres;
Knut Petersen44637a12006-01-09 15:04:20 +01001296 if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
1297 info->var.xres_virtual = modedb[i].vxres;
1298 else
1299 info->var.xres_virtual = modedb[i].xres;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001300 info->var.xoffset = 0;
1301 info->var.hsync_len = modedb[i].hsync_len;
1302 info->var.upper_margin = modedb[i].upper_margin;
1303 info->var.yres = modedb[i].yres;
1304 info->var.yres_virtual = modedb[i].vyres;
1305 info->var.yoffset = 0;
1306 info->var.lower_margin = modedb[i].lower_margin;
1307 info->var.vsync_len = modedb[i].vsync_len;
1308 info->var.sync = 0;
1309 info->var.vmode = FB_VMODE_NONINTERLACED;
1310
Knut Petersen44637a12006-01-09 15:04:20 +01001311 if (cyblafb_check_var(&info->var, info)) {
1312 // 640x480 - 8@75 should really never fail. One case would
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001313 // be fp == 1 and nativex < 640 ... give up then
Knut Petersen44637a12006-01-09 15:04:20 +01001314 if (i == 1 && bpp == 8 && ref == 75) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001315 output("Can't find a valid mode :-(\n");
1316 return -EINVAL;
1317 }
1318 // Our detected mode is unlikely to fail. If it does,
Knut Petersen44637a12006-01-09 15:04:20 +01001319 // try 640x480 - 8@75 ...
1320 if (i == 0) {
1321 mode = "640x480";
1322 bpp = 8;
1323 ref = 75;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001324 output("Detected mode failed check_var! "
Knut Petersen44637a12006-01-09 15:04:20 +01001325 "Trying 640x480 - 8@75\n");
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001326 goto tryagain;
1327 }
1328 // A specified video mode failed for some reason.
1329 // Try the startup mode first
1330 output("Specified mode '%s' failed check! "
Knut Petersen44637a12006-01-09 15:04:20 +01001331 "Falling back to startup mode.\n", mode);
1332 mode = NULL;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001333 goto tryagain;
1334 }
1335
1336 return 0;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001337}
1338
1339//========================================================
1340//
1341// Detect activated memory size. Undefined values require
1342// memsize parameter.
1343//
1344//========================================================
1345
1346static unsigned int __devinit get_memsize(void)
1347{
1348 unsigned char tmp;
1349 unsigned int k;
1350
1351 if (memsize)
1352 k = memsize * Kb;
1353 else {
1354 tmp = read3X4(CR1F) & 0x0F;
1355 switch (tmp) {
Knut Petersen44637a12006-01-09 15:04:20 +01001356 case 0x03:
1357 k = 1 * 1024 * 1024;
1358 break;
1359 case 0x07:
1360 k = 2 * 1024 * 1024;
1361 break;
1362 case 0x0F:
1363 k = 4 * 1024 * 1024;
1364 break;
1365 case 0x04:
1366 k = 8 * 1024 * 1024;
1367 break;
1368 default:
1369 k = 1 * 1024 * 1024;
1370 output("Unknown memory size code %x in CR1F."
1371 " We default to 1 Mb for now, please"
1372 " do provide a memsize parameter!\n", tmp);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001373 }
1374 }
1375
1376 if (verbosity > 0)
Knut Petersen44637a12006-01-09 15:04:20 +01001377 output("framebuffer size = %d Kb\n", k / Kb);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001378 return k;
1379}
1380
1381//=========================================================
1382//
1383// Detect if a flat panel monitor connected to the special
1384// interface is active. Override is possible by fp and crt
1385// parameters.
1386//
1387//=========================================================
1388
1389static unsigned int __devinit get_displaytype(void)
1390{
1391 if (fp)
1392 return DISPLAY_FP;
1393 if (crt)
1394 return DISPLAY_CRT;
Knut Petersen44637a12006-01-09 15:04:20 +01001395 return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001396}
1397
1398//=====================================
1399//
1400// Get native resolution of flat panel
1401//
1402//=====================================
1403
1404static int __devinit get_nativex(void)
1405{
Knut Petersen44637a12006-01-09 15:04:20 +01001406 int x, y, tmp;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001407
1408 if (nativex)
1409 return nativex;
1410
1411 tmp = (read3CE(GR52) >> 4) & 3;
1412
1413 switch (tmp) {
Knut Petersen44637a12006-01-09 15:04:20 +01001414 case 0: x = 1280; y = 1024;
1415 break;
1416 case 2: x = 1024; y = 768;
1417 break;
1418 case 3: x = 800; y = 600;
1419 break;
1420 case 4: x = 1400; y = 1050;
1421 break;
1422 case 1:
1423 default:
1424 x = 640; y = 480;
1425 break;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001426 }
1427
1428 if (verbosity > 0)
Knut Petersen44637a12006-01-09 15:04:20 +01001429 output("%dx%d flat panel found\n", x, y);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001430 return x;
1431}
1432
Knut Petersen44637a12006-01-09 15:04:20 +01001433static int __devinit cybla_pci_probe(struct pci_dev *dev,
1434 const struct pci_device_id *id)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001435{
1436 struct fb_info *info;
1437 struct cyblafb_par *par;
1438
Knut Petersen44637a12006-01-09 15:04:20 +01001439 info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001440 if (!info)
Knut Petersen44637a12006-01-09 15:04:20 +01001441 goto errout_alloc_info;
1442
1443 info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
1444 if (!info->pixmap.addr) {
1445 output("allocation of pixmap buffer failed!\n");
1446 goto errout_alloc_pixmap;
1447 }
1448 info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
1449 info->pixmap.buf_align = 4;
1450 info->pixmap.access_align = 32;
1451 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1452 info->pixmap.scan_align = 4;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001453
1454 par = info->par;
1455 par->ops = cyblafb_ops;
1456
1457 info->fix = cyblafb_fix;
1458 info->fbops = &par->ops;
1459 info->fix = cyblafb_fix;
1460
1461 if (pci_enable_device(dev)) {
1462 output("could not enable device!\n");
1463 goto errout_enable;
1464 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001465 // might already be requested by vga console or vesafb,
1466 // so we do care about success
Knut Petersen44637a12006-01-09 15:04:20 +01001467 if (!request_region(0x3c0, 0x20, "cyblafb")) {
1468 output("region 0x3c0/0x20 already reserved\n");
1469 vesafb |= 1;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001470
Knut Petersen44637a12006-01-09 15:04:20 +01001471 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001472 //
1473 // Graphics Engine Registers
1474 //
Knut Petersen44637a12006-01-09 15:04:20 +01001475 if (!request_region(GEBase, 0x100, "cyblafb")) {
1476 output("region %#x/0x100 already reserved\n", GEBase);
1477 vesafb |= 2;
1478 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001479
1480 regdump(par);
1481
1482 enable_mmio();
1483
1484 // setup MMIO region
Knut Petersen44637a12006-01-09 15:04:20 +01001485 info->fix.mmio_start = pci_resource_start(dev, 1);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001486 info->fix.mmio_len = 0x20000;
1487
1488 if (!request_mem_region(info->fix.mmio_start,
Knut Petersen44637a12006-01-09 15:04:20 +01001489 info->fix.mmio_len, "cyblafb")) {
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001490 output("request_mem_region failed for mmio region!\n");
1491 goto errout_mmio_reqmem;
1492 }
1493
1494 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1495
1496 if (!io_virt) {
1497 output("ioremap failed for mmio region\n");
1498 goto errout_mmio_remap;
1499 }
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001500 // setup framebuffer memory ... might already be requested
1501 // by vesafb. Not to fail in case of an unsuccessful request
Knut Petersen44637a12006-01-09 15:04:20 +01001502 // is useful if both are loaded.
1503 info->fix.smem_start = pci_resource_start(dev, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001504 info->fix.smem_len = get_memsize();
1505
1506 if (!request_mem_region(info->fix.smem_start,
Knut Petersen44637a12006-01-09 15:04:20 +01001507 info->fix.smem_len, "cyblafb")) {
1508 output("region %#lx/%#x already reserved\n",
1509 info->fix.smem_start, info->fix.smem_len);
1510 vesafb |= 4;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001511 }
1512
1513 info->screen_base = ioremap_nocache(info->fix.smem_start,
1514 info->fix.smem_len);
1515
1516 if (!info->screen_base) {
1517 output("ioremap failed for smem region\n");
1518 goto errout_smem_remap;
1519 }
1520
1521 displaytype = get_displaytype();
1522
Knut Petersen44637a12006-01-09 15:04:20 +01001523 if (displaytype == DISPLAY_FP)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001524 nativex = get_nativex();
1525
Knut Petersen44637a12006-01-09 15:04:20 +01001526 info->flags = FBINFO_DEFAULT
1527 | FBINFO_HWACCEL_COPYAREA
1528 | FBINFO_HWACCEL_FILLRECT
1529 | FBINFO_HWACCEL_IMAGEBLIT
1530 | FBINFO_READS_FAST
1531// | FBINFO_PARTIAL_PAN_OK
1532 | FBINFO_MISC_ALWAYS_SETPAR;
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001533
1534 info->pseudo_palette = par->pseudo_pal;
1535
Knut Petersen44637a12006-01-09 15:04:20 +01001536 if (getstartupmode(info))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001537 goto errout_findmode;
1538
Knut Petersen44637a12006-01-09 15:04:20 +01001539 fb_alloc_cmap(&info->cmap, 256, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001540
1541 if (register_framebuffer(info)) {
1542 output("Could not register CyBla framebuffer\n");
1543 goto errout_register;
1544 }
1545
Knut Petersen44637a12006-01-09 15:04:20 +01001546 pci_set_drvdata(dev, info);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001547
1548 //
1549 // normal exit and error paths
1550 //
1551
1552 return 0;
1553
Knut Petersen44637a12006-01-09 15:04:20 +01001554 errout_register:
1555 errout_findmode:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001556 iounmap(info->screen_base);
Knut Petersen44637a12006-01-09 15:04:20 +01001557 errout_smem_remap:
1558 if (!(vesafb & 4))
1559 release_mem_region(info->fix.smem_start, info->fix.smem_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001560 iounmap(io_virt);
Knut Petersen44637a12006-01-09 15:04:20 +01001561 errout_mmio_remap:
1562 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1563 errout_mmio_reqmem:
1564 if (!(vesafb & 1))
1565 release_region(0x3c0, 32);
1566 errout_enable:
1567 kfree(info->pixmap.addr);
1568 errout_alloc_pixmap:
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001569 framebuffer_release(info);
Knut Petersen44637a12006-01-09 15:04:20 +01001570 errout_alloc_info:
1571 output("CyblaFB version %s aborting init.\n", VERSION);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001572 return -ENODEV;
1573}
1574
1575static void __devexit cybla_pci_remove(struct pci_dev *dev)
1576{
1577 struct fb_info *info = pci_get_drvdata(dev);
1578
1579 unregister_framebuffer(info);
1580 iounmap(io_virt);
1581 iounmap(info->screen_base);
Knut Petersen44637a12006-01-09 15:04:20 +01001582 if (!(vesafb & 4))
1583 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1584 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001585 fb_dealloc_cmap(&info->cmap);
Knut Petersen44637a12006-01-09 15:04:20 +01001586 if (!(vesafb & 2))
1587 release_region(GEBase, 0x100);
1588 if (!(vesafb & 1))
1589 release_region(0x3c0, 32);
1590 kfree(info->pixmap.addr);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001591 framebuffer_release(info);
Knut Petersen44637a12006-01-09 15:04:20 +01001592 output("CyblaFB version %s normal exit.\n", VERSION);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001593}
1594
1595//
1596// List of boards that we are trying to support
1597//
1598static struct pci_device_id cybla_devices[] = {
Knut Petersen44637a12006-01-09 15:04:20 +01001599 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001600 {0,}
1601};
1602
Knut Petersen44637a12006-01-09 15:04:20 +01001603MODULE_DEVICE_TABLE(pci, cybla_devices);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001604
1605static struct pci_driver cyblafb_pci_driver = {
Knut Petersen44637a12006-01-09 15:04:20 +01001606 .name = "cyblafb",
1607 .id_table = cybla_devices,
1608 .probe = cybla_pci_probe,
1609 .remove = __devexit_p(cybla_pci_remove)
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001610};
1611
1612//=============================================================
1613//
1614// kernel command line example:
1615//
Knut Petersen44637a12006-01-09 15:04:20 +01001616// video=cyblafb:1280x1024, bpp=16, ref=50 ...
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001617//
1618// modprobe command line example:
1619//
1620// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1621//
1622//=============================================================
1623
1624static int __devinit cyblafb_init(void)
1625{
1626#ifndef MODULE
1627 char *options = NULL;
1628 char *opt;
1629
Knut Petersen44637a12006-01-09 15:04:20 +01001630 if (fb_get_options("cyblafb", &options))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001631 return -ENODEV;
1632
1633 if (options && *options)
Knut Petersen44637a12006-01-09 15:04:20 +01001634 while ((opt = strsep(&options, ",")) != NULL) {
1635 if (!*opt)
1636 continue;
1637 else if (!strncmp(opt, "bpp=", 4))
1638 bpp = simple_strtoul(opt + 4, NULL, 0);
1639 else if (!strncmp(opt, "ref=", 4))
1640 ref = simple_strtoul(opt + 4, NULL, 0);
1641 else if (!strncmp(opt, "fp", 2))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001642 displaytype = DISPLAY_FP;
Knut Petersen44637a12006-01-09 15:04:20 +01001643 else if (!strncmp(opt, "crt", 3))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001644 displaytype = DISPLAY_CRT;
Knut Petersen44637a12006-01-09 15:04:20 +01001645 else if (!strncmp(opt, "nativex=", 8))
1646 nativex = simple_strtoul(opt + 8, NULL, 0);
1647 else if (!strncmp(opt, "center", 6))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001648 center = 1;
Knut Petersen44637a12006-01-09 15:04:20 +01001649 else if (!strncmp(opt, "stretch", 7))
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001650 stretch = 1;
Knut Petersen44637a12006-01-09 15:04:20 +01001651 else if (!strncmp(opt, "pciwb=", 6))
1652 pciwb = simple_strtoul(opt + 6, NULL, 0);
1653 else if (!strncmp(opt, "pcirb=", 6))
1654 pcirb = simple_strtoul(opt + 6, NULL, 0);
1655 else if (!strncmp(opt, "pciwr=", 6))
1656 pciwr = simple_strtoul(opt + 6, NULL, 0);
1657 else if (!strncmp(opt, "pcirr=", 6))
1658 pcirr = simple_strtoul(opt + 6, NULL, 0);
1659 else if (!strncmp(opt, "memsize=", 8))
1660 memsize = simple_strtoul(opt + 8, NULL, 0);
1661 else if (!strncmp(opt, "verbosity=", 10))
1662 verbosity = simple_strtoul(opt + 10, NULL, 0);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001663 else
1664 mode = opt;
1665 }
1666#endif
Knut Petersen44637a12006-01-09 15:04:20 +01001667 output("CyblaFB version %s initializing\n", VERSION);
Richard Knutsson93b47682005-11-30 01:00:35 +01001668 return pci_register_driver(&cyblafb_pci_driver);
Knut Petersen9fa68ea2005-09-09 13:04:56 -07001669}
1670
1671static void __exit cyblafb_exit(void)
1672{
1673 pci_unregister_driver(&cyblafb_pci_driver);
1674}
1675
1676module_init(cyblafb_init);
1677module_exit(cyblafb_exit);
1678
1679MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1680MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1681MODULE_LICENSE("GPL");