1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/config.h>
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/string.h>
38#include <linux/mm.h>
39#include <linux/tty.h>
40#include <linux/slab.h>
41#include <linux/delay.h>
42#include <linux/fb.h>
43#include <linux/pci.h>
44#include <linux/init.h>
45
46#include <asm/io.h>
47#include <asm/irq.h>
48#include <asm/pgtable.h>
49#include <asm/system.h>
50#include <asm/uaccess.h>
51
52#include <video/fbcon.h>
53#include <video/fbcon-cfb8.h>
54#include <video/fbcon-cfb16.h>
55#include <video/fbcon-cfb24.h>
56#include <video/fbcon-cfb32.h>
57
58
59
60
61
62
63#include "cyber2000fb.h"
64
65struct cfb_info {
66 struct fb_info fb;
67 struct display_switch *dispsw;
68 struct pci_dev *dev;
69 unsigned char *region;
70 unsigned char *regs;
71 signed int currcon;
72 int func_use_count;
73 u_long ref_ps;
74
75
76
77
78 u_int divisors[4];
79
80 struct {
81 u8 red, green, blue;
82 } palette[NR_PALETTE];
83
84 u_char mem_ctl1;
85 u_char mem_ctl2;
86 u_char mclk_mult;
87 u_char mclk_div;
88};
89
90static char default_font_storage[40];
91static char *default_font = "Acorn8x8";
92MODULE_PARM(default_font, "s");
93MODULE_PARM_DESC(default_font, "Default font name");
94
95
96
97
98#define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg))
99#define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg))
100#define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg))
101
102#define cyber2000fb_readb(reg,cfb) readb((cfb)->regs + (reg))
103
104static inline void
105cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
106{
107 cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
108}
109
110static inline void
111cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
112{
113 cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
114}
115
116static inline unsigned int
117cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
118{
119 cyber2000fb_writeb(reg, 0x3ce, cfb);
120 return cyber2000fb_readb(0x3cf, cfb);
121}
122
123static inline void
124cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
125{
126 cyber2000fb_readb(0x3da, cfb);
127 cyber2000fb_writeb(reg, 0x3c0, cfb);
128 cyber2000fb_readb(0x3c1, cfb);
129 cyber2000fb_writeb(val, 0x3c0, cfb);
130}
131
132static inline void
133cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
134{
135 cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
136}
137
138
139
140
141
142
143static void cyber2000_accel_wait(struct cfb_info *cfb)
144{
145 int count = 100000;
146
147 while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
148 if (!count--) {
149 debug_printf("accel_wait timed out\n");
150 cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
151 return;
152 }
153 udelay(1);
154 }
155}
156
157static void cyber2000_accel_setup(struct display *p)
158{
159 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
160
161 cfb->dispsw->setup(p);
162}
163
164static void
165cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
166 int height, int width)
167{
168 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
169 struct fb_var_screeninfo *var = &p->fb_info->var;
170 u_long src, dst;
171 u_int fh, fw;
172 int cmd = CO_CMD_L_PATTERN_FGCOL;
173
174 fw = fontwidth(p);
175 sx *= fw;
176 dx *= fw;
177 width *= fw;
178 width -= 1;
179
180 if (sx < dx) {
181 sx += width;
182 dx += width;
183 cmd |= CO_CMD_L_INC_LEFT;
184 }
185
186 fh = fontheight(p);
187 sy *= fh;
188 dy *= fh;
189 height *= fh;
190 height -= 1;
191
192 if (sy < dy) {
193 sy += height;
194 dy += height;
195 cmd |= CO_CMD_L_INC_UP;
196 }
197
198 src = sx + sy * var->xres_virtual;
199 dst = dx + dy * var->xres_virtual;
200
201 cyber2000_accel_wait(cfb);
202 cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
203 cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb);
204 cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
205
206 if (var->bits_per_pixel != 24) {
207 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
208 cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
209 } else {
210 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
211 cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
212 cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
213 }
214
215 cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
216 cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
217 cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
218}
219
220static void
221cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
222 int height, int width)
223{
224 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
225 struct fb_var_screeninfo *var = &p->fb_info->var;
226 u_long dst;
227 u_int fw, fh;
228 u32 bgx = attr_bgcol_ec(p, conp);
229
230 fw = fontwidth(p);
231 fh = fontheight(p);
232
233 dst = sx * fw + sy * var->xres_virtual * fh;
234 width = width * fw - 1;
235 height = height * fh - 1;
236
237 cyber2000_accel_wait(cfb);
238 cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
239 cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb);
240 cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
241 cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
242
243 switch (var->bits_per_pixel) {
244 case 15:
245 case 16:
246 bgx = ((u16 *)p->dispsw_data)[bgx];
247 case 8:
248 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
249 break;
250
251 case 24:
252 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
253 cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
254 bgx = ((u32 *)p->dispsw_data)[bgx];
255 break;
256
257 case 32:
258 bgx = ((u32 *)p->dispsw_data)[bgx];
259 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
260 break;
261 }
262
263 cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
264 cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
265 cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
266}
267
268static void
269cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
270 int yy, int xx)
271{
272 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
273
274 cyber2000_accel_wait(cfb);
275 cfb->dispsw->putc(conp, p, c, yy, xx);
276}
277
278static void
279cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
280 const unsigned short *s, int count, int yy, int xx)
281{
282 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
283
284 cyber2000_accel_wait(cfb);
285 cfb->dispsw->putcs(conp, p, s, count, yy, xx);
286}
287
288static void cyber2000_accel_revc(struct display *p, int xx, int yy)
289{
290 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
291
292 cyber2000_accel_wait(cfb);
293 cfb->dispsw->revc(p, xx, yy);
294}
295
296static void
297cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
298 int bottom_only)
299{
300 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
301
302 cfb->dispsw->clear_margins(conp, p, bottom_only);
303}
304
305static struct display_switch fbcon_cyber_accel = {
306 setup: cyber2000_accel_setup,
307 bmove: cyber2000_accel_bmove,
308 clear: cyber2000_accel_clear,
309 putc: cyber2000_accel_putc,
310 putcs: cyber2000_accel_putcs,
311 revc: cyber2000_accel_revc,
312 clear_margins: cyber2000_accel_clear_margins,
313 fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
314};
315
316
317
318
319static int
320cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
321 u_int transp, struct fb_info *info)
322{
323 struct cfb_info *cfb = (struct cfb_info *)info;
324
325 u_int alpha = transp ^ 0xFFFF;
326
327 if (regno >= NR_PALETTE)
328 return 1;
329
330 red >>= 8;
331 green >>= 8;
332 blue >>= 8;
333 alpha >>= 8;
334
335 cfb->palette[regno].red = red;
336 cfb->palette[regno].green = green;
337 cfb->palette[regno].blue = blue;
338
339 switch (cfb->fb.var.bits_per_pixel) {
340#ifdef FBCON_HAS_CFB8
341 case 8:
342 cyber2000fb_writeb(regno, 0x3c8, cfb);
343 cyber2000fb_writeb(red, 0x3c9, cfb);
344 cyber2000fb_writeb(green, 0x3c9, cfb);
345 cyber2000fb_writeb(blue, 0x3c9, cfb);
346 break;
347#endif
348
349#ifdef FBCON_HAS_CFB16
350 case 16:
351#ifndef CFB16_IS_CFB15
352 if (regno < 64) {
353
354 cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
355 cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
356 cyber2000fb_writeb(green, 0x3c9, cfb);
357 cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
358 }
359
360 if (regno < 32) {
361
362 cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
363 cyber2000fb_writeb(red, 0x3c9, cfb);
364 cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
365 cyber2000fb_writeb(blue, 0x3c9, cfb);
366 }
367
368 if (regno < 16)
369 ((u16 *)cfb->fb.pseudo_palette)[regno] =
370 ((red << 8) & 0xf800) |
371 ((green << 3) & 0x07e0) |
372 ((blue >> 3));
373 break;
374#endif
375
376 case 15:
377 if (regno < 32) {
378 cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
379 cyber2000fb_writeb(red, 0x3c9, cfb);
380 cyber2000fb_writeb(green, 0x3c9, cfb);
381 cyber2000fb_writeb(blue, 0x3c9, cfb);
382 }
383 if (regno < 16)
384 ((u16 *)cfb->fb.pseudo_palette)[regno] =
385 ((red << 7) & 0x7c00) |
386 ((green << 2) & 0x03e0) |
387 ((blue >> 3));
388 break;
389
390#endif
391
392#ifdef FBCON_HAS_CFB24
393 case 24:
394 cyber2000fb_writeb(regno, 0x3c8, cfb);
395 cyber2000fb_writeb(red, 0x3c9, cfb);
396 cyber2000fb_writeb(green, 0x3c9, cfb);
397 cyber2000fb_writeb(blue, 0x3c9, cfb);
398
399 if (regno < 16)
400 ((u32 *)cfb->fb.pseudo_palette)[regno] =
401 (red << 16) | (green << 8) | blue;
402 break;
403#endif
404
405#ifdef FBCON_HAS_CFB32
406 case 32:
407 cyber2000fb_writeb(regno, 0x3c8, cfb);
408 cyber2000fb_writeb(red, 0x3c9, cfb);
409 cyber2000fb_writeb(green, 0x3c9, cfb);
410 cyber2000fb_writeb(blue, 0x3c9, cfb);
411
412 if (regno < 16)
413 ((u32 *)cfb->fb.pseudo_palette)[regno] =
414 (alpha << 24) | (red << 16) | (green << 8) | blue;
415 break;
416#endif
417
418 default:
419 return 1;
420 }
421
422 return 0;
423}
424
425struct par_info {
426
427
428
429 u_char clock_mult;
430 u_char clock_div;
431 u_char visualid;
432 u_char pixformat;
433 u_char crtc_ofl;
434 u_char crtc[19];
435 u_int width;
436 u_int pitch;
437 u_int fetch;
438
439
440
441
442 u_char palette_ctrl;
443 u_int vmode;
444};
445
446static const u_char crtc_idx[] = {
447 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
448 0x08, 0x09,
449 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
450};
451
452static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
453{
454 u_int i;
455
456
457
458
459 for (i = 0; i < NR_PALETTE; i++) {
460 cyber2000fb_writeb(i, 0x3c8, cfb);
461 cyber2000fb_writeb(0, 0x3c9, cfb);
462 cyber2000fb_writeb(0, 0x3c9, cfb);
463 cyber2000fb_writeb(0, 0x3c9, cfb);
464 }
465
466 cyber2000fb_writeb(0xef, 0x3c2, cfb);
467 cyber2000_crtcw(0x11, 0x0b, cfb);
468 cyber2000_attrw(0x11, 0x00, cfb);
469
470 cyber2000_seqw(0x00, 0x01, cfb);
471 cyber2000_seqw(0x01, 0x01, cfb);
472 cyber2000_seqw(0x02, 0x0f, cfb);
473 cyber2000_seqw(0x03, 0x00, cfb);
474 cyber2000_seqw(0x04, 0x0e, cfb);
475 cyber2000_seqw(0x00, 0x03, cfb);
476
477 for (i = 0; i < sizeof(crtc_idx); i++)
478 cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
479
480 for (i = 0x0a; i < 0x10; i++)
481 cyber2000_crtcw(i, 0, cfb);
482
483 cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
484 cyber2000_grphw(0x00, 0x00, cfb);
485 cyber2000_grphw(0x01, 0x00, cfb);
486 cyber2000_grphw(0x02, 0x00, cfb);
487 cyber2000_grphw(0x03, 0x00, cfb);
488 cyber2000_grphw(0x04, 0x00, cfb);
489 cyber2000_grphw(0x05, 0x60, cfb);
490 cyber2000_grphw(0x06, 0x05, cfb);
491 cyber2000_grphw(0x07, 0x0f, cfb);
492 cyber2000_grphw(0x08, 0xff, cfb);
493
494
495 for (i = 0; i < 16; i++)
496 cyber2000_attrw(i, i, cfb);
497
498 cyber2000_attrw(0x10, 0x01, cfb);
499 cyber2000_attrw(0x11, 0x00, cfb);
500 cyber2000_attrw(0x12, 0x0f, cfb);
501 cyber2000_attrw(0x13, 0x00, cfb);
502 cyber2000_attrw(0x14, 0x00, cfb);
503
504
505
506 cyber2000fb_writeb(0x11, 0x3ce, cfb);
507 i = cyber2000fb_readb(0x3cf, cfb);
508 if (hw->vmode == FB_VMODE_INTERLACED)
509 i |= 0x20;
510 else
511 i &= ~0x20;
512 cyber2000fb_writeb(i, 0x3cf, cfb);
513
514
515 cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
516 cyber2000_grphw(DCLK_DIV, hw->clock_div, cfb);
517 cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
518 cyber2000_grphw(MCLK_DIV, cfb->mclk_div, cfb);
519 cyber2000_grphw(0x90, 0x01, cfb);
520 cyber2000_grphw(0xb9, 0x80, cfb);
521 cyber2000_grphw(0xb9, 0x00, cfb);
522
523 cyber2000fb_writeb(0x56, 0x3ce, cfb);
524 i = cyber2000fb_readb(0x3cf, cfb);
525 cyber2000fb_writeb(i | 4, 0x3cf, cfb);
526 cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
527 cyber2000fb_writeb(i, 0x3cf, cfb);
528
529 cyber2000fb_writeb(0x20, 0x3c0, cfb);
530 cyber2000fb_writeb(0xff, 0x3c6, cfb);
531
532 cyber2000_grphw(0x14, hw->fetch, cfb);
533 cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
534 ((hw->pitch >> 4) & 0x30), cfb);
535 cyber2000_grphw(0x77, hw->visualid, cfb);
536
537
538 cyber2000_grphw(0x33, 0x0d, cfb);
539
540
541
542
543 cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
544 cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
545 cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
546}
547
548static inline int
549cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
550{
551 u_int base;
552
553 base = var->yoffset * var->xres_virtual + var->xoffset;
554
555
556
557 base *= (var->bits_per_pixel + 7) >> 3;
558
559 base >>= 2;
560
561 if (base >= 1 << 20)
562 return -EINVAL;
563
564 cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
565 cyber2000_crtcw(0x0c, base >> 8, cfb);
566 cyber2000_crtcw(0x0d, base, cfb);
567
568 return 0;
569}
570
571
572
573
574static int
575cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
576 struct fb_info *info)
577{
578 struct cfb_info *cfb = (struct cfb_info *)info;
579 struct fb_cmap *dcmap = &fb_display[con].cmap;
580 int err = 0;
581
582
583 if (!dcmap->len) {
584 int size;
585
586 if (cfb->fb.var.bits_per_pixel == 16)
587 size = 32;
588 else
589 size = 256;
590
591 err = fb_alloc_cmap(dcmap, size, 0);
592 }
593
594
595
596
597
598 if (!err && con == cfb->currcon) {
599 err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
600 dcmap = &cfb->fb.cmap;
601 }
602
603 if (!err)
604 fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
605
606 return err;
607}
608
609static int
610cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
611 struct fb_var_screeninfo *var)
612{
613 u_int Htotal, Hblankend, Hsyncend;
614 u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
615#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
616
617 hw->crtc[13] = hw->pitch;
618 hw->crtc[17] = 0xe3;
619 hw->crtc[14] = 0;
620 hw->crtc[8] = 0;
621
622 Htotal = var->xres + var->right_margin +
623 var->hsync_len + var->left_margin;
624
625 if (Htotal > 2080)
626 return -EINVAL;
627
628 hw->crtc[0] = (Htotal >> 3) - 5;
629 hw->crtc[1] = (var->xres >> 3) - 1;
630 hw->crtc[2] = var->xres >> 3;
631 hw->crtc[4] = (var->xres + var->right_margin) >> 3;
632
633 Hblankend = (Htotal - 4*8) >> 3;
634
635 hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) |
636 BIT(1, 0, 0x01, 7);
637
638 Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
639
640 hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) |
641 BIT(Hblankend, 5, 0x01, 7);
642
643 Vdispend = var->yres - 1;
644 Vsyncstart = var->yres + var->lower_margin;
645 Vsyncend = var->yres + var->lower_margin + var->vsync_len;
646 Vtotal = var->yres + var->lower_margin + var->vsync_len +
647 var->upper_margin - 2;
648
649 if (Vtotal > 2047)
650 return -EINVAL;
651
652 Vblankstart = var->yres + 6;
653 Vblankend = Vtotal - 10;
654
655 hw->crtc[6] = Vtotal;
656 hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
657 BIT(Vdispend, 8, 0x01, 1) |
658 BIT(Vsyncstart, 8, 0x01, 2) |
659 BIT(Vblankstart,8, 0x01, 3) |
660 BIT(1, 0, 0x01, 4) |
661 BIT(Vtotal, 9, 0x01, 5) |
662 BIT(Vdispend, 9, 0x01, 6) |
663 BIT(Vsyncstart, 9, 0x01, 7);
664 hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
665 BIT(Vblankstart,9, 0x01, 5) |
666 BIT(1, 0, 0x01, 6);
667 hw->crtc[10] = Vsyncstart;
668 hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
669 BIT(1, 0, 0x01, 7);
670 hw->crtc[12] = Vdispend;
671 hw->crtc[15] = Vblankstart;
672 hw->crtc[16] = Vblankend;
673 hw->crtc[18] = 0xff;
674
675
676
677
678
679 hw->crtc_ofl =
680 BIT(Vtotal, 10, 0x01, 0) |
681 BIT(Vdispend, 10, 0x01, 1) |
682 BIT(Vsyncstart, 10, 0x01, 2) |
683 BIT(Vblankstart,10, 0x01, 3) |
684 1 << 4;
685
686 return 0;
687}
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704static int
705cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
706 struct fb_var_screeninfo *var)
707{
708 u_long pll_ps = var->pixclock;
709 const u_long ref_ps = cfb->ref_ps;
710 u_int div2, t_div1, best_div1, best_mult;
711 int best_diff;
712 int vco;
713
714
715
716
717
718
719 for (div2 = 0; div2 < 4; div2++) {
720 u_long new_pll;
721
722 new_pll = pll_ps / cfb->divisors[div2];
723 if (8696 > new_pll && new_pll > 3846) {
724 pll_ps = new_pll;
725 break;
726 }
727 }
728
729 if (div2 == 4)
730 return -EINVAL;
731
732
733
734
735
736
737
738
739 best_diff = 0x7fffffff;
740 best_mult = 32;
741 best_div1 = 255;
742 for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
743 u_int rr, t_mult, t_pll_ps;
744 int diff;
745
746
747
748
749 rr = ref_ps * t_div1;
750 t_mult = (rr + pll_ps / 2) / pll_ps;
751
752
753
754
755 if (t_mult > 256 || t_mult < 2)
756 continue;
757
758
759
760
761
762 t_pll_ps = (rr + t_mult / 2) / t_mult;
763 diff = pll_ps - t_pll_ps;
764 if (diff < 0)
765 diff = -diff;
766
767 if (diff < best_diff) {
768 best_diff = diff;
769 best_mult = t_mult;
770 best_div1 = t_div1;
771 }
772
773
774
775
776 if (diff == 0)
777 break;
778 }
779
780
781
782
783
784 hw->clock_mult = best_mult - 1;
785 hw->clock_div = div2 << 6 | (best_div1 - 1);
786
787 vco = ref_ps * best_div1 / best_mult;
788 if ((ref_ps == 40690) && (vco < 5556))
789
790 hw->clock_div |= DCLK_DIV_VFSEL;
791
792 return 0;
793}
794
795
796
797
798
799
800static int
801cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
802 struct par_info *hw)
803{
804 int err;
805
806 hw->width = var->xres_virtual;
807 hw->palette_ctrl = 0x06;
808 hw->vmode = var->vmode;
809
810 switch (var->bits_per_pixel) {
811#ifdef FBCON_HAS_CFB8
812 case 8:
813 hw->pixformat = PIXFORMAT_8BPP;
814 hw->visualid = VISUALID_256;
815 hw->pitch = hw->width >> 3;
816 break;
817#endif
818#ifdef FBCON_HAS_CFB16
819 case 16:
820#ifndef CFB16_IS_CFB15
821 hw->pixformat = PIXFORMAT_16BPP;
822 hw->visualid = VISUALID_64K;
823 hw->pitch = hw->width >> 2;
824 hw->palette_ctrl |= 0x10;
825 break;
826#endif
827 case 15:
828 hw->pixformat = PIXFORMAT_16BPP;
829 hw->visualid = VISUALID_32K;
830 hw->pitch = hw->width >> 2;
831 hw->palette_ctrl |= 0x10;
832 break;
833
834#endif
835#ifdef FBCON_HAS_CFB24
836 case 24:
837 hw->pixformat = PIXFORMAT_24BPP;
838 hw->visualid = VISUALID_16M;
839 hw->width *= 3;
840 hw->pitch = hw->width >> 3;
841 hw->palette_ctrl |= 0x10;
842 break;
843#endif
844#ifdef FBCON_HAS_CFB32
845 case 32:
846 hw->pixformat = PIXFORMAT_32BPP;
847 hw->visualid = VISUALID_16M_32;
848 hw->pitch = hw->width >> 1;
849 hw->palette_ctrl |= 0x10;
850 break;
851#endif
852 default:
853 return -EINVAL;
854 }
855
856 err = cyber2000fb_decode_clock(hw, cfb, var);
857 if (err)
858 return err;
859
860 err = cyber2000fb_decode_crtc(hw, cfb, var);
861 if (err)
862 return err;
863
864 hw->width -= 1;
865 hw->fetch = hw->pitch;
866 if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
867 hw->fetch <<= 1;
868 hw->fetch += 1;
869
870 return 0;
871}
872
873
874
875
876static int
877cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
878 struct fb_info *info)
879{
880 struct cfb_info *cfb = (struct cfb_info *)info;
881 struct display *display;
882 struct par_info hw;
883 int err, chgvar = 0;
884
885
886
887
888
889 if (var->vmode & FB_VMODE_CONUPDATE) {
890 var->vmode |= FB_VMODE_YWRAP;
891 var->xoffset = cfb->fb.var.xoffset;
892 var->yoffset = cfb->fb.var.yoffset;
893 }
894
895 err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
896 if (err)
897 return err;
898
899 if (var->activate & FB_ACTIVATE_TEST)
900 return 0;
901
902 if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
903 return -EINVAL;
904
905 if (cfb->fb.var.xres != var->xres)
906 chgvar = 1;
907 if (cfb->fb.var.yres != var->yres)
908 chgvar = 1;
909 if (cfb->fb.var.xres_virtual != var->xres_virtual)
910 chgvar = 1;
911 if (cfb->fb.var.yres_virtual != var->yres_virtual)
912 chgvar = 1;
913 if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
914 chgvar = 1;
915
916 if (con < 0) {
917 display = cfb->fb.disp;
918 chgvar = 0;
919 } else {
920 display = fb_display + con;
921 }
922
923 var->red.msb_right = 0;
924 var->green.msb_right = 0;
925 var->blue.msb_right = 0;
926
927 switch (var->bits_per_pixel) {
928#ifdef FBCON_HAS_CFB8
929 case 8:
930 var->red.offset = 0;
931 var->red.length = 8;
932 var->green.offset = 0;
933 var->green.length = 8;
934 var->blue.offset = 0;
935 var->blue.length = 8;
936
937 cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
938 cfb->dispsw = &fbcon_cfb8;
939 display->dispsw_data = NULL;
940 display->next_line = var->xres_virtual;
941 break;
942#endif
943#ifdef FBCON_HAS_CFB16
944 case 16:
945#ifndef CFB16_IS_CFB15
946 var->red.offset = 11;
947 var->red.length = 5;
948 var->green.offset = 5;
949 var->green.length = 6;
950 var->blue.offset = 0;
951 var->blue.length = 5;
952
953 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
954 cfb->dispsw = &fbcon_cfb16;
955 display->dispsw_data = cfb->fb.pseudo_palette;
956 display->next_line = var->xres_virtual * 2;
957 break;
958#endif
959 case 15:
960 var->bits_per_pixel = 15;
961 var->red.offset = 10;
962 var->red.length = 5;
963 var->green.offset = 5;
964 var->green.length = 5;
965 var->blue.offset = 0;
966 var->blue.length = 5;
967
968 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
969 cfb->dispsw = &fbcon_cfb16;
970 display->dispsw_data = cfb->fb.pseudo_palette;
971 display->next_line = var->xres_virtual * 2;
972 break;
973#endif
974#ifdef FBCON_HAS_CFB24
975 case 24:
976 var->red.offset = 16;
977 var->red.length = 8;
978 var->green.offset = 8;
979 var->green.length = 8;
980 var->blue.offset = 0;
981 var->blue.length = 8;
982
983 cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
984 cfb->dispsw = &fbcon_cfb24;
985 display->dispsw_data = cfb->fb.pseudo_palette;
986 display->next_line = var->xres_virtual * 3;
987 break;
988#endif
989#ifdef FBCON_HAS_CFB32
990 case 32:
991 var->transp.offset = 24;
992 var->transp.length = 8;
993 var->red.offset = 16;
994 var->red.length = 8;
995 var->green.offset = 8;
996 var->green.length = 8;
997 var->blue.offset = 0;
998 var->blue.length = 8;
999
1000 cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
1001 cfb->dispsw = &fbcon_cfb32;
1002 display->dispsw_data = cfb->fb.pseudo_palette;
1003 display->next_line = var->xres_virtual * 4;
1004 break;
1005#endif
1006 default:
1007 printk(KERN_WARNING "%s: no support for %dbpp\n",
1008 cfb->fb.fix.id, var->bits_per_pixel);
1009 cfb->dispsw = &fbcon_dummy;
1010 break;
1011 }
1012
1013 if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
1014 display->dispsw = &fbcon_cyber_accel;
1015 else
1016 display->dispsw = cfb->dispsw;
1017
1018 cfb->fb.fix.line_length = display->next_line;
1019
1020 display->screen_base = cfb->fb.screen_base;
1021 display->line_length = cfb->fb.fix.line_length;
1022 display->visual = cfb->fb.fix.visual;
1023 display->type = cfb->fb.fix.type;
1024 display->type_aux = cfb->fb.fix.type_aux;
1025 display->ypanstep = cfb->fb.fix.ypanstep;
1026 display->ywrapstep = cfb->fb.fix.ywrapstep;
1027 display->can_soft_blank = 1;
1028 display->inverse = 0;
1029
1030 cfb->fb.var = *var;
1031 cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
1032
1033
1034
1035
1036
1037
1038 display->var = cfb->fb.var;
1039
1040
1041
1042
1043
1044 if (var->activate & FB_ACTIVATE_ALL)
1045 cfb->fb.disp->var = cfb->fb.var;
1046
1047 if (chgvar && info && cfb->fb.changevar)
1048 cfb->fb.changevar(con);
1049
1050 cyber2000fb_update_start(cfb, var);
1051 cyber2000fb_set_timing(cfb, &hw);
1052 fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
1053
1054 return 0;
1055}
1056
1057
1058
1059
1060
1061static int
1062cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
1063 struct fb_info *info)
1064{
1065 struct cfb_info *cfb = (struct cfb_info *)info;
1066 u_int y_bottom;
1067
1068 y_bottom = var->yoffset;
1069
1070 if (!(var->vmode & FB_VMODE_YWRAP))
1071 y_bottom += var->yres;
1072
1073 if (var->xoffset > (var->xres_virtual - var->xres))
1074 return -EINVAL;
1075 if (y_bottom > cfb->fb.var.yres_virtual)
1076 return -EINVAL;
1077
1078 if (cyber2000fb_update_start(cfb, var))
1079 return -EINVAL;
1080
1081 cfb->fb.var.xoffset = var->xoffset;
1082 cfb->fb.var.yoffset = var->yoffset;
1083 if (var->vmode & FB_VMODE_YWRAP) {
1084 cfb->fb.var.vmode |= FB_VMODE_YWRAP;
1085 } else {
1086 cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
1087 }
1088
1089 return 0;
1090}
1091
1092
1093
1094
1095
1096
1097
1098
1099static int cyber2000fb_updatevar(int con, struct fb_info *info)
1100{
1101 struct cfb_info *cfb = (struct cfb_info *)info;
1102
1103 return cyber2000fb_update_start(cfb, &fb_display[con].var);
1104}
1105
1106static int cyber2000fb_switch(int con, struct fb_info *info)
1107{
1108 struct cfb_info *cfb = (struct cfb_info *)info;
1109 struct display *disp;
1110 struct fb_cmap *cmap;
1111
1112 if (cfb->currcon >= 0) {
1113 disp = fb_display + cfb->currcon;
1114
1115
1116
1117
1118 disp->var = cfb->fb.var;
1119 if (disp->cmap.len)
1120 fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
1121 }
1122
1123 cfb->currcon = con;
1124 disp = fb_display + con;
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135 if (disp->cmap.len)
1136 cmap = &disp->cmap;
1137 else
1138 cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1139
1140 fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
1141
1142 cfb->fb.var = disp->var;
1143 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1144
1145 cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
1146
1147 return 0;
1148}
1149
1150
1151
1152
1153static void cyber2000fb_blank(int blank, struct fb_info *info)
1154{
1155 struct cfb_info *cfb = (struct cfb_info *)info;
1156 int i;
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 switch (blank) {
1175 case 4:
1176 cyber2000_grphw(0x16, 0x05, cfb);
1177 break;
1178 case 3:
1179 cyber2000_grphw(0x16, 0x01, cfb);
1180 break;
1181 case 2:
1182 cyber2000_grphw(0x16, 0x04, cfb);
1183 break;
1184 case 1:
1185 cyber2000_grphw(0x16, 0x00, cfb);
1186 for (i = 0; i < NR_PALETTE; i++) {
1187 cyber2000fb_writeb(i, 0x3c8, cfb);
1188 cyber2000fb_writeb(0, 0x3c9, cfb);
1189 cyber2000fb_writeb(0, 0x3c9, cfb);
1190 cyber2000fb_writeb(0, 0x3c9, cfb);
1191 }
1192 break;
1193 default:
1194 cyber2000_grphw(0x16, 0x00, cfb);
1195 for (i = 0; i < NR_PALETTE; i++) {
1196 cyber2000fb_writeb(i, 0x3c8, cfb);
1197 cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
1198 cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
1199 cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
1200 }
1201 break;
1202 }
1203}
1204
1205
1206
1207
1208static int
1209gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1210{
1211 fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
1212 return 0;
1213}
1214
1215
1216
1217
1218static int
1219gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1220{
1221 *fix = info->fix;
1222 return 0;
1223}
1224
1225
1226
1227
1228static int
1229gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1230{
1231 *var = info->var;
1232 return 0;
1233}
1234
1235static struct fb_ops cyber2000fb_ops = {
1236 owner: THIS_MODULE,
1237 fb_set_var: cyber2000fb_set_var,
1238 fb_set_cmap: cyber2000fb_set_cmap,
1239 fb_pan_display: cyber2000fb_pan_display,
1240 fb_get_fix: gen_get_fix,
1241 fb_get_var: gen_get_var,
1242 fb_get_cmap: gen_get_cmap,
1243};
1244
1245
1246
1247
1248static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
1249{
1250 cfb->func_use_count += 1;
1251
1252 if (cfb->func_use_count == 1) {
1253 int old;
1254
1255 old = cyber2000_grphr(FUNC_CTL, cfb);
1256 cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
1257 }
1258}
1259
1260
1261
1262
1263static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
1264{
1265 if (cfb->func_use_count == 1) {
1266 int old;
1267
1268 old = cyber2000_grphr(FUNC_CTL, cfb);
1269 cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
1270 }
1271
1272 cfb->func_use_count -= 1;
1273}
1274
1275
1276
1277
1278
1279
1280static struct cfb_info *int_cfb_info;
1281
1282
1283
1284
1285int cyber2000fb_attach(struct cyberpro_info *info, int idx)
1286{
1287 if (int_cfb_info != NULL) {
1288 info->dev = int_cfb_info->dev;
1289 info->regs = int_cfb_info->regs;
1290 info->fb = int_cfb_info->fb.screen_base;
1291 info->fb_size = int_cfb_info->fb.fix.smem_len;
1292 info->enable_extregs = cyber2000fb_enable_extregs;
1293 info->disable_extregs = cyber2000fb_disable_extregs;
1294 info->info = int_cfb_info;
1295
1296 strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
1297
1298 MOD_INC_USE_COUNT;
1299 }
1300
1301 return int_cfb_info != NULL;
1302}
1303
1304
1305
1306
1307void cyber2000fb_detach(int idx)
1308{
1309 MOD_DEC_USE_COUNT;
1310}
1311
1312EXPORT_SYMBOL(cyber2000fb_attach);
1313EXPORT_SYMBOL(cyber2000fb_detach);
1314
1315
1316
1317
1318
1319static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
1320 refresh: 60,
1321 xres: 640,
1322 yres: 480,
1323 pixclock: 39722,
1324 left_margin: 56,
1325 right_margin: 16,
1326 upper_margin: 34,
1327 lower_margin: 9,
1328 hsync_len: 88,
1329 vsync_len: 2,
1330 sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1331 vmode: FB_VMODE_NONINTERLACED
1332};
1333
1334static char igs_regs[] __devinitdata = {
1335 0x12, 0x00, 0x13, 0x00,
1336 0x16, 0x00,
1337 0x31, 0x00, 0x32, 0x00,
1338 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
1339 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
1340 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
1341 0x70, 0x0b, 0x73, 0x30,
1342 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8
1343};
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
1360{
1361 int i;
1362
1363
1364
1365
1366#ifdef __sparc__
1367#ifdef __sparc_v9__
1368#error "You loose, consult DaveM."
1369#else
1370
1371
1372
1373
1374
1375 {
1376 unsigned char *iop;
1377
1378 iop = ioremap(0x3000000, 0x5000);
1379 if (iop == NULL) {
1380 prom_printf("iga5000: cannot map I/O\n");
1381 return -ENOMEM;
1382 }
1383
1384 writeb(0x18, iop + 0x46e8);
1385 writeb(0x01, iop + 0x102);
1386 writeb(0x08, iop + 0x46e8);
1387 writeb(0x33, iop + 0x3ce);
1388 writeb(0x01, iop + 0x3cf);
1389
1390 iounmap((void *)iop);
1391 }
1392#endif
1393
1394 if (at_boot) {
1395
1396
1397
1398
1399
1400 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1401 cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb);
1402 }
1403#endif
1404#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
1405
1406
1407
1408
1409 outb(0x18, 0x46e8);
1410 outb(0x01, 0x102);
1411 outb(0x08, 0x46e8);
1412 outb(0x33, 0x3ce);
1413 outb(0x01, 0x3cf);
1414
1415 if (at_boot) {
1416
1417
1418
1419
1420
1421 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1422 cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb);
1423 }
1424#endif
1425#ifdef __arm__
1426 cyber2000fb_writeb(0x18, 0x46e8, cfb);
1427 cyber2000fb_writeb(0x01, 0x102, cfb);
1428 cyber2000fb_writeb(0x08, 0x46e8, cfb);
1429 cyber2000fb_writeb(0x33, 0x3ce, cfb);
1430 cyber2000fb_writeb(0x01, 0x3cf, cfb);
1431
1432
1433
1434
1435 cfb->mclk_mult = 0xdb;
1436 cfb->mclk_div = 0x54;
1437#endif
1438
1439
1440
1441
1442 for (i = 0; i < sizeof(igs_regs); i += 2)
1443 cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
1444
1445 if (at_boot) {
1446
1447
1448
1449
1450
1451 cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
1452 cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
1453 } else {
1454
1455
1456
1457 cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
1458 cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
1459 }
1460
1461
1462
1463
1464
1465
1466 cyber2000fb_writeb(0xba, 0x3ce, cfb);
1467 cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
1468}
1469
1470static struct cfb_info * __devinit
1471cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
1472{
1473 struct cfb_info *cfb;
1474
1475 cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
1476 sizeof(u32) * 16, GFP_KERNEL);
1477
1478 if (!cfb)
1479 return NULL;
1480
1481 memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
1482
1483 cfb->currcon = -1;
1484 cfb->dev = dev;
1485
1486 if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
1487 cfb->ref_ps = 40690;
1488 else
1489 cfb->ref_ps = 69842;
1490
1491 cfb->divisors[0] = 1;
1492 cfb->divisors[1] = 2;
1493 cfb->divisors[2] = 4;
1494
1495 if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
1496 cfb->divisors[3] = 8;
1497 else
1498 cfb->divisors[3] = 6;
1499
1500 strcpy(cfb->fb.fix.id, name);
1501
1502 cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1503 cfb->fb.fix.type_aux = 0;
1504 cfb->fb.fix.xpanstep = 0;
1505 cfb->fb.fix.ypanstep = 1;
1506 cfb->fb.fix.ywrapstep = 0;
1507 cfb->fb.fix.accel = id->driver_data;
1508
1509 cfb->fb.var.nonstd = 0;
1510 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1511 cfb->fb.var.height = -1;
1512 cfb->fb.var.width = -1;
1513 cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
1514
1515 strcpy(cfb->fb.modename, cfb->fb.fix.id);
1516 strcpy(cfb->fb.fontname, default_font);
1517
1518 cfb->fb.fbops = &cyber2000fb_ops;
1519 cfb->fb.changevar = NULL;
1520 cfb->fb.switch_con = cyber2000fb_switch;
1521 cfb->fb.updatevar = cyber2000fb_updatevar;
1522 cfb->fb.blank = cyber2000fb_blank;
1523 cfb->fb.flags = FBINFO_FLAG_DEFAULT;
1524 cfb->fb.disp = (struct display *)(cfb + 1);
1525 cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1);
1526
1527 fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
1528
1529 return cfb;
1530}
1531
1532static void __devinit
1533cyberpro_free_fb_info(struct cfb_info *cfb)
1534{
1535 if (cfb) {
1536
1537
1538
1539 fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
1540
1541 kfree(cfb);
1542 }
1543}
1544
1545
1546
1547
1548
1549int
1550cyber2000fb_setup(char *options)
1551{
1552 char *opt;
1553
1554 if (!options || !*options)
1555 return 0;
1556
1557 while ((opt = strsep(&options, ",")) != NULL) {
1558 if (!*opt)
1559 continue;
1560
1561 if (strncmp(opt, "font:", 5) == 0) {
1562 strncpy(default_font_storage, opt + 5, sizeof(default_font_storage));
1563 default_font = default_font_storage;
1564 continue;
1565 }
1566
1567 printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
1568 }
1569 return 0;
1570}
1571
1572static int __devinit
1573cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
1574{
1575 struct cfb_info *cfb;
1576 u_int h_sync, v_sync;
1577 u_long smem_size;
1578 char name[16];
1579 int err;
1580
1581 sprintf(name, "CyberPro%4X", id->device);
1582
1583 err = pci_enable_device(dev);
1584 if (err)
1585 return err;
1586
1587 err = pci_request_regions(dev, name);
1588 if (err)
1589 return err;
1590
1591 err = -ENOMEM;
1592 cfb = cyberpro_alloc_fb_info(dev, id, name);
1593 if (!cfb)
1594 goto failed_release;
1595
1596 cfb->region = ioremap(pci_resource_start(dev, 0),
1597 pci_resource_len(dev, 0));
1598 if (!cfb->region)
1599 goto failed_ioremap;
1600
1601 cfb->regs = cfb->region + MMIO_OFFSET;
1602
1603 cyberpro_init_hw(cfb, 1);
1604
1605 switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1606 case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
1607 case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
1608 default: smem_size = 0x00100000; break;
1609 }
1610
1611
1612
1613
1614
1615 cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
1616 cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
1617 cfb->fb.fix.mmio_len = MMIO_SIZE;
1618 cfb->fb.fix.smem_len = smem_size;
1619 cfb->fb.screen_base = cfb->region;
1620
1621 if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1622 &cyber2000fb_default_mode, 8)) {
1623 printk("%s: no valid mode found\n", cfb->fb.fix.id);
1624 goto failed;
1625 }
1626
1627 cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
1628 (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
1629
1630 if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
1631 cfb->fb.var.yres_virtual = cfb->fb.var.yres;
1632
1633 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1634
1635
1636
1637
1638
1639
1640
1641 h_sync = 1953125000 / cfb->fb.var.pixclock;
1642 h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
1643 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
1644 v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
1645 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
1646
1647 printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1648 cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
1649 cfb->fb.var.xres, cfb->fb.var.yres,
1650 h_sync / 1000, h_sync % 1000, v_sync);
1651
1652 err = register_framebuffer(&cfb->fb);
1653 if (err < 0)
1654 goto failed;
1655
1656
1657
1658
1659 pci_set_drvdata(dev, cfb);
1660 if (int_cfb_info == NULL)
1661 int_cfb_info = cfb;
1662
1663 return 0;
1664
1665failed:
1666 iounmap(cfb->region);
1667failed_ioremap:
1668 cyberpro_free_fb_info(cfb);
1669failed_release:
1670 pci_release_regions(dev);
1671
1672 return err;
1673}
1674
1675static void __devexit cyberpro_remove(struct pci_dev *dev)
1676{
1677 struct cfb_info *cfb = pci_get_drvdata(dev);
1678
1679 if (cfb) {
1680
1681
1682
1683
1684
1685 if (unregister_framebuffer(&cfb->fb))
1686 printk(KERN_WARNING "%s: danger Will Robinson, "
1687 "danger danger! Oopsen imminent!\n",
1688 cfb->fb.fix.id);
1689 iounmap(cfb->region);
1690 cyberpro_free_fb_info(cfb);
1691
1692
1693
1694
1695
1696 pci_set_drvdata(dev, NULL);
1697 if (cfb == int_cfb_info)
1698 int_cfb_info = NULL;
1699
1700 pci_release_regions(dev);
1701 }
1702}
1703
1704static int cyberpro_suspend(struct pci_dev *dev, u32 state)
1705{
1706 return 0;
1707}
1708
1709
1710
1711
1712static int cyberpro_resume(struct pci_dev *dev)
1713{
1714 struct cfb_info *cfb = pci_get_drvdata(dev);
1715
1716 if (cfb) {
1717 cyberpro_init_hw(cfb, 0);
1718
1719
1720
1721
1722
1723 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1724 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1725 }
1726
1727 return 0;
1728}
1729
1730static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
1731 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
1732 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
1733 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
1734 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
1735 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
1736 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
1737 { 0, }
1738};
1739
1740static struct pci_driver cyberpro_driver = {
1741 name: "CyberPro",
1742 probe: cyberpro_probe,
1743 remove: __devexit_p(cyberpro_remove),
1744 suspend: cyberpro_suspend,
1745 resume: cyberpro_resume,
1746 id_table: cyberpro_pci_table
1747};
1748
1749
1750
1751
1752
1753
1754int __init cyber2000fb_init(void)
1755{
1756 return pci_module_init(&cyberpro_driver);
1757}
1758
1759static void __exit cyberpro_exit(void)
1760{
1761 pci_unregister_driver(&cyberpro_driver);
1762}
1763
1764#ifdef MODULE
1765module_init(cyber2000fb_init);
1766#endif
1767module_exit(cyberpro_exit);
1768
1769MODULE_AUTHOR("Russell King");
1770MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
1771MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
1772MODULE_LICENSE("GPL");
1773