* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / video / retz3fb.c
blobdbc6eb022723e4528d834e6fcd9e682b9776311b
1 /*
2 * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device
4 * Copyright (C) 1997 Jes Sorensen
6 * This file is based on the CyberVision64 frame buffer device and
7 * the generic Cirrus Logic driver.
9 * cyberfb.c: Copyright (C) 1996 Martin Apel,
10 * Geert Uytterhoeven
11 * clgen.c: Copyright (C) 1996 Frank Neumann
13 * History:
14 * - 22 Jan 97: Initial work
15 * - 14 Feb 97: Screen initialization works somewhat, still only
16 * 8-bit packed pixel is supported.
18 * This file is subject to the terms and conditions of the GNU General Public
19 * License. See the file COPYING in the main directory of this archive
20 * for more details.
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/mm.h>
28 #include <linux/tty.h>
29 #include <linux/malloc.h>
30 #include <linux/delay.h>
31 #include <linux/fb.h>
32 #include <linux/zorro.h>
33 #include <linux/init.h>
35 #include <asm/uaccess.h>
36 #include <asm/system.h>
37 #include <asm/irq.h>
38 #include <asm/pgtable.h>
39 #include <asm/io.h>
41 #include <video/fbcon.h>
42 #include <video/fbcon-cfb8.h>
43 #include <video/fbcon-cfb16.h>
45 #include "retz3fb.h"
47 /* #define DEBUG if(1) */
48 #define DEBUG if(0)
51 * Reserve space for one pattern line.
53 * For the time being we only support 4MB boards!
56 #define PAT_MEM_SIZE 16*3
57 #define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
59 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
61 struct retz3fb_par {
62 int xres;
63 int yres;
64 int xres_vir;
65 int yres_vir;
66 int xoffset;
67 int yoffset;
68 int bpp;
70 struct fb_bitfield red;
71 struct fb_bitfield green;
72 struct fb_bitfield blue;
73 struct fb_bitfield transp;
75 int pixclock;
76 int left_margin; /* time from sync to picture */
77 int right_margin; /* time from picture to sync */
78 int upper_margin; /* time from sync to picture */
79 int lower_margin;
80 int hsync_len; /* length of horizontal sync */
81 int vsync_len; /* length of vertical sync */
82 int vmode;
84 int accel;
87 struct display_data {
88 long h_total; /* Horizontal Total */
89 long h_sstart; /* Horizontal Sync Start */
90 long h_sstop; /* Horizontal Sync Stop */
91 long h_bstart; /* Horizontal Blank Start */
92 long h_bstop; /* Horizontal Blank Stop */
93 long h_dispend; /* Horizontal Display End */
94 long v_total; /* Vertical Total */
95 long v_sstart; /* Vertical Sync Start */
96 long v_sstop; /* Vertical Sync Stop */
97 long v_bstart; /* Vertical Blank Start */
98 long v_bstop; /* Vertical Blank Stop */
99 long v_dispend; /* Horizontal Display End */
102 struct retz3_fb_info {
103 struct fb_info info;
104 unsigned char *base;
105 unsigned char *fbmem;
106 unsigned long fbsize;
107 volatile unsigned char *regs;
108 unsigned long physfbmem;
109 unsigned long physregs;
110 int currcon;
111 int current_par_valid; /* set to 0 by memset */
112 int blitbusy;
113 struct display disp;
114 struct retz3fb_par current_par;
115 unsigned char color_table [256][3];
119 static char fontname[40] __initdata = { 0 };
121 #define retz3info(info) ((struct retz3_fb_info *)(info))
122 #define fbinfo(info) ((struct fb_info *)(info))
126 * Frame Buffer Name
129 static char retz3fb_name[16] = "RetinaZ3";
133 * A small info on how to convert XFree86 timing values into fb
134 * timings - by Frank Neumann:
136 An XFree86 mode line consists of the following fields:
137 "800x600" 50 800 856 976 1040 600 637 643 666
138 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
140 The fields in the fb_var_screeninfo structure are:
141 unsigned long pixclock; * pixel clock in ps (pico seconds) *
142 unsigned long left_margin; * time from sync to picture *
143 unsigned long right_margin; * time from picture to sync *
144 unsigned long upper_margin; * time from sync to picture *
145 unsigned long lower_margin;
146 unsigned long hsync_len; * length of horizontal sync *
147 unsigned long vsync_len; * length of vertical sync *
149 1) Pixelclock:
150 xfree: in MHz
151 fb: In Picoseconds (ps)
153 pixclock = 1000000 / DCF
155 2) horizontal timings:
156 left_margin = HFL - SH2
157 right_margin = SH1 - HR
158 hsync_len = SH2 - SH1
160 3) vertical timings:
161 upper_margin = VFL - SV2
162 lower_margin = SV1 - VR
163 vsync_len = SV2 - SV1
165 Good examples for VESA timings can be found in the XFree86 source tree,
166 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
170 * Predefined Video Modes
173 static struct {
174 const char *name;
175 struct fb_var_screeninfo var;
176 } retz3fb_predefined[] __initdata = {
178 * NB: it is very important to adjust the pixel-clock to the color-depth.
182 "640x480", { /* 640x480, 8 bpp */
183 640, 480, 640, 480, 0, 0, 8, 0,
184 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
185 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
186 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
190 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
191 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
194 "800x600", { /* 800x600, 8 bpp */
195 800, 600, 800, 600, 0, 0, 8, 0,
196 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
197 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2,
198 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
202 "800x600-60", { /* 800x600, 8 bpp */
203 800, 600, 800, 600, 0, 0, 8, 0,
204 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
205 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
206 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
210 "800x600-70", { /* 800x600, 8 bpp */
211 800, 600, 800, 600, 0, 0, 8, 0,
212 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
213 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12,
214 FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
218 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
219 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
222 "1024x768i", { /* 1024x768, 8 bpp, interlaced */
223 1024, 768, 1024, 768, 0, 0, 8, 0,
224 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
225 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8,
226 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
230 "1024x768", {
231 1024, 768, 1024, 768, 0, 0, 8, 0,
232 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
233 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
234 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
238 "640x480-16", { /* 640x480, 16 bpp */
239 640, 480, 640, 480, 0, 0, 16, 0,
240 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
241 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
242 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
246 "640x480-24", { /* 640x480, 24 bpp */
247 640, 480, 640, 480, 0, 0, 24, 0,
248 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
249 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
250 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
256 #define NUM_TOTAL_MODES arraysize(retz3fb_predefined)
258 static struct fb_var_screeninfo retz3fb_default;
260 static int z3fb_inverse = 0;
261 static int z3fb_mode __initdata = 0;
265 * Interface used by the world
268 int retz3fb_setup(char *options);
270 static int retz3fb_open(struct fb_info *info, int user);
271 static int retz3fb_release(struct fb_info *info, int user);
272 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
273 struct fb_info *info);
274 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
275 struct fb_info *info);
276 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
277 struct fb_info *info);
278 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
279 struct fb_info *info);
280 static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
281 struct fb_info *info);
282 static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
283 struct fb_info *info);
284 static int retz3fb_ioctl(struct inode *inode, struct file *file,
285 unsigned int cmd, unsigned long arg, int con,
286 struct fb_info *info);
290 * Interface to the low level console driver
293 int retz3fb_init(void);
294 static int z3fb_switch(int con, struct fb_info *info);
295 static int z3fb_updatevar(int con, struct fb_info *info);
296 static void z3fb_blank(int blank, struct fb_info *info);
300 * Text console acceleration
303 #ifdef FBCON_HAS_CFB8
304 static struct display_switch fbcon_retz3_8;
305 #endif
309 * Accelerated Functions used by the low level console driver
312 static void retz3_bitblt(struct display *p,
313 unsigned short curx, unsigned short cury, unsigned
314 short destx, unsigned short desty, unsigned short
315 width, unsigned short height, unsigned short cmd,
316 unsigned short mask);
319 * Hardware Specific Routines
322 static int retz3_encode_fix(struct fb_info *info,
323 struct fb_fix_screeninfo *fix,
324 struct retz3fb_par *par);
325 static int retz3_decode_var(struct fb_var_screeninfo *var,
326 struct retz3fb_par *par);
327 static int retz3_encode_var(struct fb_var_screeninfo *var,
328 struct retz3fb_par *par);
329 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
330 unsigned int *green, unsigned int *blue,
331 unsigned int *transp, struct fb_info *info);
332 static int retz3_setcolreg(unsigned int regno, unsigned int red,
333 unsigned int green, unsigned int blue,
334 unsigned int transp, struct fb_info *info);
337 * Internal routines
340 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
341 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
342 static int do_fb_set_var(struct fb_info *info,
343 struct fb_var_screeninfo *var, int isactive);
344 static void do_install_cmap(int con, struct fb_info *info);
345 static void retz3fb_set_disp(int con, struct fb_info *info);
346 static int get_video_mode(const char *name);
349 /* -------------------- Hardware specific routines ------------------------- */
351 static unsigned short find_fq(unsigned int freq)
353 unsigned long f;
354 long tmp;
355 long prev = 0x7fffffff;
356 long n2, n1 = 3;
357 unsigned long m;
358 unsigned short res = 0;
360 if (freq <= 31250000)
361 n2 = 3;
362 else if (freq <= 62500000)
363 n2 = 2;
364 else if (freq <= 125000000)
365 n2 = 1;
366 else if (freq <= 250000000)
367 n2 = 0;
368 else
369 return 0;
372 do {
373 f = freq >> (10 - n2);
375 m = (f * n1) / (14318180/1024);
377 if (m > 129)
378 break;
380 tmp = (((m * 14318180) >> n2) / n1) - freq;
381 if (tmp < 0)
382 tmp = -tmp;
384 if (tmp < prev) {
385 prev = tmp;
386 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
389 } while ( (++n1) <= 21);
391 return res;
395 static int retz3_set_video(struct fb_info *info,
396 struct fb_var_screeninfo *var,
397 struct retz3fb_par *par)
399 volatile unsigned char *regs = retz3info(info)->regs;
400 unsigned int freq;
402 int xres, hfront, hsync, hback;
403 int yres, vfront, vsync, vback;
404 unsigned char tmp;
405 unsigned short best_freq;
406 struct display_data data;
408 short clocksel = 0; /* Apparantly this is always zero */
410 int bpp = var->bits_per_pixel;
413 * XXX
415 if (bpp == 24)
416 return 0;
418 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
419 return -EFAULT;
421 par->xoffset = 0;
422 par->yoffset = 0;
424 xres = var->xres * bpp / 4;
425 hfront = var->right_margin * bpp / 4;
426 hsync = var->hsync_len * bpp / 4;
427 hback = var->left_margin * bpp / 4;
429 if (var->vmode & FB_VMODE_DOUBLE)
431 yres = var->yres * 2;
432 vfront = var->lower_margin * 2;
433 vsync = var->vsync_len * 2;
434 vback = var->upper_margin * 2;
436 else if (var->vmode & FB_VMODE_INTERLACED)
438 yres = (var->yres + 1) / 2;
439 vfront = (var->lower_margin + 1) / 2;
440 vsync = (var->vsync_len + 1) / 2;
441 vback = (var->upper_margin + 1) / 2;
443 else
445 yres = var->yres; /* -1 ? */
446 vfront = var->lower_margin;
447 vsync = var->vsync_len;
448 vback = var->upper_margin;
451 data.h_total = (hback / 8) + (xres / 8)
452 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
453 data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
454 data.h_bstart = xres / 8 - 1 /* + 1 */;
456 data.h_bstop = data.h_total+1 + 2 + 1;
457 data.h_sstart = (xres / 8) + (hfront / 8) + 1;
458 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
460 data.v_total = yres + vfront + vsync + vback - 1;
462 data.v_dispend = yres - 1;
463 data.v_bstart = yres - 1;
465 data.v_bstop = data.v_total;
466 data.v_sstart = yres + vfront - 1 - 2;
467 data.v_sstop = yres + vfront + vsync - 1;
469 #if 0 /* testing */
471 printk("HBS: %i\n", data.h_bstart);
472 printk("HSS: %i\n", data.h_sstart);
473 printk("HSE: %i\n", data.h_sstop);
474 printk("HBE: %i\n", data.h_bstop);
475 printk("HT: %i\n", data.h_total);
477 printk("hsync: %i\n", hsync);
478 printk("hfront: %i\n", hfront);
479 printk("hback: %i\n", hback);
481 printk("VBS: %i\n", data.v_bstart);
482 printk("VSS: %i\n", data.v_sstart);
483 printk("VSE: %i\n", data.v_sstop);
484 printk("VBE: %i\n", data.v_bstop);
485 printk("VT: %i\n", data.v_total);
487 printk("vsync: %i\n", vsync);
488 printk("vfront: %i\n", vfront);
489 printk("vback: %i\n", vback);
490 #endif
492 if (data.v_total >= 1024)
493 printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n");
495 reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
496 reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
498 seq_w(regs, SEQ_RESET, 0x00);
499 seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */
502 * CLOCKING_MODE bits:
503 * 2: This one is only set for certain text-modes, wonder if
504 * it may be for EGA-lines? (it was referred to as CLKDIV2)
505 * (The CL drivers sets it to 0x21 with the comment:
506 * FullBandwidth (video off) and 8/9 dot clock)
508 seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
510 seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
511 seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
512 seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
513 seq_w(regs, SEQ_RESET, 0x01);
514 seq_w(regs, SEQ_RESET, 0x03);
516 seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
518 seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
519 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
520 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
521 seq_w(regs, SEQ_LINEAR_0, 0x4a);
522 seq_w(regs, SEQ_LINEAR_1, 0x00);
524 seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
525 seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
526 seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
529 * The lower 4 bits (0-3) are used to set the font-width for
530 * text-mode - DON'T try to set this for gfx-mode.
532 seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
533 seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
536 * Extended Pixel Control:
537 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
538 * bit 1: (Packed/Nibble Pixel Format ?)
539 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
541 seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
543 seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
544 seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
545 seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
546 seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
547 seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
548 seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
549 seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
550 seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
551 seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
552 seq_w(regs, SEQ_CRC_CONTROL, 0x00);
553 seq_w(regs, SEQ_PERF_SELECT, 0x10);
554 seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
555 seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
556 seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
557 seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
560 /* unlock register CRT0..CRT7 */
561 crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
563 /* Zuerst zu schreibende Werte nur per printk ausgeben */
564 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
565 crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
567 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
568 crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
570 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
571 crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
573 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
574 crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
576 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
577 crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
579 tmp = (data.h_sstop & 0x1f);
580 if (data.h_bstop & 0x20)
581 tmp |= 0x80;
582 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
583 crt_w(regs, CRT_END_HOR_RETR, tmp);
585 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
586 crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
588 tmp = 0x10; /* LineCompare bit #9 */
589 if (data.v_total & 256)
590 tmp |= 0x01;
591 if (data.v_dispend & 256)
592 tmp |= 0x02;
593 if (data.v_sstart & 256)
594 tmp |= 0x04;
595 if (data.v_bstart & 256)
596 tmp |= 0x08;
597 if (data.v_total & 512)
598 tmp |= 0x20;
599 if (data.v_dispend & 512)
600 tmp |= 0x40;
601 if (data.v_sstart & 512)
602 tmp |= 0x80;
603 DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
604 crt_w(regs, CRT_OVERFLOW, tmp);
606 crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
608 tmp = 0x40; /* LineCompare bit #8 */
609 if (data.v_bstart & 512)
610 tmp |= 0x20;
611 if (var->vmode & FB_VMODE_DOUBLE)
612 tmp |= 0x80;
613 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
614 crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
616 crt_w(regs, CRT_CURSOR_START, 0x00);
617 crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
619 crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
620 crt_w(regs, CRT_START_ADDR_LOW, 0x00);
622 crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
623 crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
625 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
626 crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
628 #if 1
629 /* 5 refresh cycles per scanline */
630 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
631 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
632 #else
633 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
634 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
635 #endif
636 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
637 crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
639 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
640 crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
642 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
643 crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
645 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
646 crt_w(regs, CRT_MODE_CONTROL, 0xe3);
648 DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
649 crt_w(regs, CRT_LINE_COMPARE, 0xff);
651 tmp = (var->xres_virtual / 8) * (bpp / 8);
652 crt_w(regs, CRT_OFFSET, tmp);
654 crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
656 tmp = 0x20; /* Enable extended end bits */
657 if (data.h_total & 0x100)
658 tmp |= 0x01;
659 if ((data.h_dispend) & 0x100)
660 tmp |= 0x02;
661 if (data.h_bstart & 0x100)
662 tmp |= 0x04;
663 if (data.h_sstart & 0x100)
664 tmp |= 0x08;
665 if (var->vmode & FB_VMODE_INTERLACED)
666 tmp |= 0x10;
667 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
668 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
670 tmp = 0x00;
671 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
672 tmp |= 0x10;
673 crt_w(regs, CRT_EXT_START_ADDR, tmp);
675 tmp = 0x00;
676 if (data.h_total & 0x200)
677 tmp |= 0x01;
678 if ((data.h_dispend) & 0x200)
679 tmp |= 0x02;
680 if (data.h_bstart & 0x200)
681 tmp |= 0x04;
682 if (data.h_sstart & 0x200)
683 tmp |= 0x08;
684 tmp |= ((data.h_bstop & 0xc0) >> 2);
685 tmp |= ((data.h_sstop & 0x60) << 1);
686 crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
687 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
689 tmp = 0x10; /* Line compare bit 10 */
690 if (data.v_total & 0x400)
691 tmp |= 0x01;
692 if ((data.v_dispend) & 0x400)
693 tmp |= 0x02;
694 if (data.v_bstart & 0x400)
695 tmp |= 0x04;
696 if (data.v_sstart & 0x400)
697 tmp |= 0x08;
698 tmp |= ((data.v_bstop & 0x300) >> 3);
699 if (data.v_sstop & 0x10)
700 tmp |= 0x80;
701 crt_w(regs, CRT_EXT_VER_TIMING, tmp);
702 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
704 crt_w(regs, CRT_MONITOR_POWER, 0x00);
707 * Convert from ps to Hz.
709 freq = 2000000000 / var->pixclock;
710 freq = freq * 500;
712 best_freq = find_fq(freq);
713 pll_w(regs, 0x02, best_freq);
714 best_freq = find_fq(61000000);
715 pll_w(regs, 0x0a, best_freq);
716 pll_w(regs, 0x0e, 0x22);
718 gfx_w(regs, GFX_SET_RESET, 0x00);
719 gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
720 gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
721 gfx_w(regs, GFX_DATA_ROTATE, 0x00);
722 gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
723 gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
724 gfx_w(regs, GFX_MISC, 0x05);
725 gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
726 gfx_w(regs, GFX_BITMASK, 0xff);
728 reg_r(regs, ACT_ADDRESS_RESET);
729 attr_w(regs, ACT_PALETTE0 , 0x00);
730 attr_w(regs, ACT_PALETTE1 , 0x01);
731 attr_w(regs, ACT_PALETTE2 , 0x02);
732 attr_w(regs, ACT_PALETTE3 , 0x03);
733 attr_w(regs, ACT_PALETTE4 , 0x04);
734 attr_w(regs, ACT_PALETTE5 , 0x05);
735 attr_w(regs, ACT_PALETTE6 , 0x06);
736 attr_w(regs, ACT_PALETTE7 , 0x07);
737 attr_w(regs, ACT_PALETTE8 , 0x08);
738 attr_w(regs, ACT_PALETTE9 , 0x09);
739 attr_w(regs, ACT_PALETTE10, 0x0a);
740 attr_w(regs, ACT_PALETTE11, 0x0b);
741 attr_w(regs, ACT_PALETTE12, 0x0c);
742 attr_w(regs, ACT_PALETTE13, 0x0d);
743 attr_w(regs, ACT_PALETTE14, 0x0e);
744 attr_w(regs, ACT_PALETTE15, 0x0f);
745 reg_r(regs, ACT_ADDRESS_RESET);
747 attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
749 attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
750 attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
751 attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
752 attr_w(regs, ACT_COLOR_SELECT, 0x00);
754 reg_r(regs, ACT_ADDRESS_RESET);
755 reg_w(regs, ACT_DATA, 0x20);
757 reg_w(regs, VDAC_MASK, 0xff);
760 * Extended palette addressing ???
762 switch (bpp){
763 case 8:
764 reg_w(regs, 0x83c6, 0x00);
765 break;
766 case 16:
767 reg_w(regs, 0x83c6, 0x60);
768 break;
769 case 24:
770 reg_w(regs, 0x83c6, 0xe0);
771 break;
772 default:
773 printk(KERN_INFO "Illegal color-depth: %i\n", bpp);
776 reg_w(regs, VDAC_ADDRESS, 0x00);
778 seq_w(regs, SEQ_MAP_MASK, 0x0f );
780 return 0;
785 * This function should fill in the `fix' structure based on the
786 * values in the `par' structure.
789 static int retz3_encode_fix(struct fb_info *info,
790 struct fb_fix_screeninfo *fix,
791 struct retz3fb_par *par)
793 struct retz3_fb_info *zinfo = retz3info(info);
795 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
796 strcpy(fix->id, retz3fb_name);
797 fix->smem_start = zinfo->physfbmem;
798 fix->smem_len = zinfo->fbsize;
799 fix->mmio_start = zinfo->physregs;
800 fix->mmio_len = 0x00c00000;
802 fix->type = FB_TYPE_PACKED_PIXELS;
803 fix->type_aux = 0;
804 if (par->bpp == 8)
805 fix->visual = FB_VISUAL_PSEUDOCOLOR;
806 else
807 fix->visual = FB_VISUAL_TRUECOLOR;
809 fix->xpanstep = 0;
810 fix->ypanstep = 0;
811 fix->ywrapstep = 0;
812 fix->line_length = 0;
814 fix->accel = FB_ACCEL_NCR_77C32BLT;
816 return 0;
821 * Get the video params out of `var'. If a value doesn't fit, round
822 * it up, if it's too big, return -EINVAL.
825 static int retz3_decode_var(struct fb_var_screeninfo *var,
826 struct retz3fb_par *par)
828 par->xres = var->xres;
829 par->yres = var->yres;
830 par->xres_vir = var->xres_virtual;
831 par->yres_vir = var->yres_virtual;
832 par->bpp = var->bits_per_pixel;
833 par->pixclock = var->pixclock;
834 par->vmode = var->vmode;
836 par->red = var->red;
837 par->green = var->green;
838 par->blue = var->blue;
839 par->transp = var->transp;
841 par->left_margin = var->left_margin;
842 par->right_margin = var->right_margin;
843 par->upper_margin = var->upper_margin;
844 par->lower_margin = var->lower_margin;
845 par->hsync_len = var->hsync_len;
846 par->vsync_len = var->vsync_len;
848 if (var->accel_flags & FB_ACCELF_TEXT)
849 par->accel = FB_ACCELF_TEXT;
850 else
851 par->accel = 0;
853 return 0;
858 * Fill the `var' structure based on the values in `par' and maybe
859 * other values read out of the hardware.
862 static int retz3_encode_var(struct fb_var_screeninfo *var,
863 struct retz3fb_par *par)
865 memset(var, 0, sizeof(struct fb_var_screeninfo));
866 var->xres = par->xres;
867 var->yres = par->yres;
868 var->xres_virtual = par->xres_vir;
869 var->yres_virtual = par->yres_vir;
870 var->xoffset = 0;
871 var->yoffset = 0;
873 var->bits_per_pixel = par->bpp;
874 var->grayscale = 0;
876 var->red = par->red;
877 var->green = par->green;
878 var->blue = par->blue;
879 var->transp = par->transp;
881 var->nonstd = 0;
882 var->activate = 0;
884 var->height = -1;
885 var->width = -1;
887 var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
889 var->pixclock = par->pixclock;
891 var->sync = 0; /* ??? */
892 var->left_margin = par->left_margin;
893 var->right_margin = par->right_margin;
894 var->upper_margin = par->upper_margin;
895 var->lower_margin = par->lower_margin;
896 var->hsync_len = par->hsync_len;
897 var->vsync_len = par->vsync_len;
899 var->vmode = par->vmode;
900 return 0;
905 * Set a single color register. Return != 0 for invalid regno.
908 static int retz3_setcolreg(unsigned int regno, unsigned int red,
909 unsigned int green, unsigned int blue,
910 unsigned int transp, struct fb_info *info)
912 struct retz3_fb_info *zinfo = retz3info(info);
913 volatile unsigned char *regs = zinfo->regs;
915 /* We'll get to this */
917 if (regno > 255)
918 return 1;
920 red >>= 10;
921 green >>= 10;
922 blue >>= 10;
924 zinfo->color_table[regno][0] = red;
925 zinfo->color_table[regno][1] = green;
926 zinfo->color_table[regno][2] = blue;
928 reg_w(regs, VDAC_ADDRESS_W, regno);
929 reg_w(regs, VDAC_DATA, red);
930 reg_w(regs, VDAC_DATA, green);
931 reg_w(regs, VDAC_DATA, blue);
933 return 0;
938 * Read a single color register and split it into
939 * colors/transparent. Return != 0 for invalid regno.
942 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
943 unsigned int *green, unsigned int *blue,
944 unsigned int *transp, struct fb_info *info)
946 struct retz3_fb_info *zinfo = retz3info(info);
947 int t;
949 if (regno > 255)
950 return 1;
951 t = zinfo->color_table[regno][0];
952 *red = (t<<10) | (t<<4) | (t>>2);
953 t = zinfo->color_table[regno][1];
954 *green = (t<<10) | (t<<4) | (t>>2);
955 t = zinfo->color_table[regno][2];
956 *blue = (t<<10) | (t<<4) | (t>>2);
957 *transp = 0;
958 return 0;
962 static inline void retz3_busy(struct display *p)
964 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
965 volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
966 unsigned char blt_status;
968 if (zinfo->blitbusy) {
970 blt_status = *((acm) + (ACM_START_STATUS + 2));
971 }while ((blt_status & 1) == 0);
972 zinfo->blitbusy = 0;
977 static void retz3_bitblt (struct display *p,
978 unsigned short srcx, unsigned short srcy,
979 unsigned short destx, unsigned short desty,
980 unsigned short width, unsigned short height,
981 unsigned short cmd, unsigned short mask)
983 struct fb_var_screeninfo *var = &p->var;
984 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
985 volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
986 unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
988 unsigned short mod;
989 unsigned long tmp;
990 unsigned long pat, src, dst;
992 int i, xres_virtual = var->xres_virtual;
993 short bpp = (var->bits_per_pixel & 0xff);
995 if (bpp < 8)
996 bpp = 8;
998 tmp = mask | (mask << 16);
1000 retz3_busy(p);
1002 i = 0;
1004 *pattern++ = tmp;
1005 }while(i++ < bpp/4);
1007 tmp = cmd << 8;
1008 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
1010 mod = 0xc0c2;
1012 pat = 8 * PAT_MEM_OFF;
1013 dst = bpp * (destx + desty * xres_virtual);
1016 * Source is not set for clear.
1018 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
1019 src = bpp * (srcx + srcy * xres_virtual);
1021 if (destx > srcx) {
1022 mod &= ~0x8000;
1023 src += bpp * (width - 1);
1024 dst += bpp * (width - 1);
1025 pat += bpp * 2;
1027 if (desty > srcy) {
1028 mod &= ~0x4000;
1029 src += bpp * (height - 1) * xres_virtual;
1030 dst += bpp * (height - 1) * xres_virtual;
1031 pat += bpp * 4;
1034 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
1037 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
1039 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
1041 tmp = mod << 16;
1042 *(acm + ACM_CONTROL/4) = tmp;
1044 tmp = width | (height << 16);
1046 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
1048 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
1049 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
1050 zinfo->blitbusy = 1;
1053 #if 0
1055 * Move cursor to x, y
1057 static void retz3_MoveCursor (unsigned short x, unsigned short y)
1059 /* Guess we gotta deal with the cursor at some point */
1061 #endif
1065 * Fill the hardware's `par' structure.
1068 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
1070 struct retz3_fb_info *zinfo = retz3info(info);
1072 if (zinfo->current_par_valid)
1073 *par = zinfo->current_par;
1074 else
1075 retz3_decode_var(&retz3fb_default, par);
1079 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
1081 struct retz3_fb_info *zinfo = retz3info(info);
1083 zinfo->current_par = *par;
1084 zinfo->current_par_valid = 1;
1088 static int do_fb_set_var(struct fb_info *info,
1089 struct fb_var_screeninfo *var, int isactive)
1091 int err, activate;
1092 struct retz3fb_par par;
1093 struct retz3_fb_info *zinfo = retz3info(info);
1095 if ((err = retz3_decode_var(var, &par)))
1096 return err;
1097 activate = var->activate;
1099 /* XXX ... what to do about isactive ? */
1101 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
1102 retz3fb_set_par(info, &par);
1103 retz3_encode_var(var, &par);
1104 var->activate = activate;
1106 retz3_set_video(info, var, &zinfo->current_par);
1108 return 0;
1112 static void do_install_cmap(int con, struct fb_info *info)
1114 struct retz3_fb_info *zinfo = retz3info(info);
1116 if (con != zinfo->currcon)
1117 return;
1118 if (fb_display[con].cmap.len)
1119 fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info);
1120 else
1121 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1122 1, retz3_setcolreg, info);
1127 * Open/Release the frame buffer device
1130 static int retz3fb_open(struct fb_info *info, int user)
1133 * Nothing, only a usage count for the moment
1136 MOD_INC_USE_COUNT;
1137 return 0;
1140 static int retz3fb_release(struct fb_info *info, int user)
1142 MOD_DEC_USE_COUNT;
1143 return 0;
1148 * Get the Fixed Part of the Display
1151 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
1152 struct fb_info *info)
1154 struct retz3fb_par par;
1155 int error = 0;
1157 if (con == -1)
1158 retz3fb_get_par(info, &par);
1159 else
1160 error = retz3_decode_var(&fb_display[con].var, &par);
1161 return(error ? error : retz3_encode_fix(info, fix, &par));
1166 * Get the User Defined Part of the Display
1169 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
1170 struct fb_info *info)
1172 struct retz3fb_par par;
1173 int error = 0;
1175 if (con == -1) {
1176 retz3fb_get_par(info, &par);
1177 error = retz3_encode_var(var, &par);
1178 } else
1179 *var = fb_display[con].var;
1180 return error;
1184 static void retz3fb_set_disp(int con, struct fb_info *info)
1186 struct fb_fix_screeninfo fix;
1187 struct display *display;
1188 struct retz3_fb_info *zinfo = retz3info(info);
1190 if (con >= 0)
1191 display = &fb_display[con];
1192 else
1193 display = &zinfo->disp; /* used during initialization */
1195 retz3fb_get_fix(&fix, con, info);
1197 if (con == -1)
1198 con = 0;
1200 display->screen_base = zinfo->fbmem;
1201 display->visual = fix.visual;
1202 display->type = fix.type;
1203 display->type_aux = fix.type_aux;
1204 display->ypanstep = fix.ypanstep;
1205 display->ywrapstep = fix.ywrapstep;
1206 display->can_soft_blank = 1;
1207 display->inverse = z3fb_inverse;
1210 * This seems to be about 20% faster.
1212 display->scrollmode = SCROLL_YREDRAW;
1214 switch (display->var.bits_per_pixel) {
1215 #ifdef FBCON_HAS_CFB8
1216 case 8:
1217 if (display->var.accel_flags & FB_ACCELF_TEXT) {
1218 display->dispsw = &fbcon_retz3_8;
1219 retz3_set_video(info, &display->var, &zinfo->current_par);
1220 } else
1221 display->dispsw = &fbcon_cfb8;
1222 break;
1223 #endif
1224 #ifdef FBCON_HAS_CFB16
1225 case 16:
1226 display->dispsw = &fbcon_cfb16;
1227 break;
1228 #endif
1229 default:
1230 display->dispsw = &fbcon_dummy;
1231 break;
1237 * Set the User Defined Part of the Display
1240 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
1241 struct fb_info *info)
1243 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
1244 struct display *display;
1245 struct retz3_fb_info *zinfo = retz3info(info);
1247 if (con >= 0)
1248 display = &fb_display[con];
1249 else
1250 display = &zinfo->disp; /* used during initialization */
1252 if ((err = do_fb_set_var(info, var, con == zinfo->currcon)))
1253 return err;
1254 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1255 oldxres = display->var.xres;
1256 oldyres = display->var.yres;
1257 oldvxres = display->var.xres_virtual;
1258 oldvyres = display->var.yres_virtual;
1259 oldbpp = display->var.bits_per_pixel;
1260 oldaccel = display->var.accel_flags;
1261 display->var = *var;
1263 if (oldxres != var->xres || oldyres != var->yres ||
1264 oldvxres != var->xres_virtual ||
1265 oldvyres != var->yres_virtual ||
1266 oldbpp != var->bits_per_pixel ||
1267 oldaccel != var->accel_flags) {
1269 struct fb_fix_screeninfo fix;
1270 retz3fb_get_fix(&fix, con, info);
1272 display->screen_base = zinfo->fbmem;
1273 display->visual = fix.visual;
1274 display->type = fix.type;
1275 display->type_aux = fix.type_aux;
1276 display->ypanstep = fix.ypanstep;
1277 display->ywrapstep = fix.ywrapstep;
1278 display->line_length = fix.line_length;
1279 display->can_soft_blank = 1;
1280 display->inverse = z3fb_inverse;
1281 switch (display->var.bits_per_pixel) {
1282 #ifdef FBCON_HAS_CFB8
1283 case 8:
1284 if (var->accel_flags & FB_ACCELF_TEXT) {
1285 display->dispsw = &fbcon_retz3_8;
1286 } else
1287 display->dispsw = &fbcon_cfb8;
1288 break;
1289 #endif
1290 #ifdef FBCON_HAS_CFB16
1291 case 16:
1292 display->dispsw = &fbcon_cfb16;
1293 break;
1294 #endif
1295 default:
1296 display->dispsw = &fbcon_dummy;
1297 break;
1300 * We still need to find a way to tell the X
1301 * server that the video mem has been fiddled with
1302 * so it redraws the entire screen when switching
1303 * between X and a text console.
1305 retz3_set_video(info, var, &zinfo->current_par);
1307 if (info->changevar)
1308 (*info->changevar)(con);
1311 if (oldbpp != var->bits_per_pixel) {
1312 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1313 return err;
1314 do_install_cmap(con, info);
1317 return 0;
1322 * Get the Colormap
1325 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1326 struct fb_info *info)
1328 struct retz3_fb_info *zinfo = retz3info(info);
1330 if (con == zinfo->currcon) /* current console? */
1331 return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
1332 else if (fb_display[con].cmap.len) /* non default colormap? */
1333 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1334 else
1335 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1336 cmap, kspc ? 0 : 2);
1337 return 0;
1342 * Set the Colormap
1345 static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1346 struct fb_info *info)
1348 int err;
1349 struct retz3_fb_info *zinfo = retz3info(info);
1351 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
1352 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1353 1<<fb_display[con].var.bits_per_pixel,
1354 0)))
1355 return err;
1357 if (con == zinfo->currcon) /* current console? */
1358 return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info));
1359 else
1360 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1361 return 0;
1366 * Pan or Wrap the Display
1368 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1371 static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
1372 struct fb_info *info)
1374 return -EINVAL;
1379 * RetinaZ3 Frame Buffer Specific ioctls
1382 static int retz3fb_ioctl(struct inode *inode, struct file *file,
1383 unsigned int cmd, unsigned long arg, int con,
1384 struct fb_info *info)
1386 return -EINVAL;
1390 static struct fb_ops retz3fb_ops = {
1391 retz3fb_open, retz3fb_release, retz3fb_get_fix, retz3fb_get_var,
1392 retz3fb_set_var, retz3fb_get_cmap, retz3fb_set_cmap,
1393 retz3fb_pan_display, retz3fb_ioctl
1397 int __init retz3fb_setup(char *options)
1399 char *this_opt;
1401 if (!options || !*options)
1402 return 0;
1404 for (this_opt = strtok(options, ","); this_opt;
1405 this_opt = strtok(NULL, ",")){
1406 if (!strcmp(this_opt, "inverse")) {
1407 z3fb_inverse = 1;
1408 fb_invert_cmaps();
1409 } else if (!strncmp(this_opt, "font:", 5)) {
1410 strncpy(fontname, this_opt+5, 39);
1411 fontname[39] = '\0';
1412 } else
1413 z3fb_mode = get_video_mode(this_opt);
1415 return 0;
1420 * Initialization
1423 int __init retz3fb_init(void)
1425 unsigned long board_addr, board_size;
1426 unsigned int key;
1427 const struct ConfigDev *cd;
1428 volatile unsigned char *regs;
1429 struct retz3fb_par par;
1430 struct retz3_fb_info *zinfo;
1431 struct fb_info *fb_info;
1432 short i;
1434 if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
1435 return -ENXIO;
1437 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL)))
1438 return -ENOMEM;
1439 memset(zinfo, 0, sizeof(struct retz3_fb_info));
1441 cd = zorro_get_board (key);
1442 zorro_config_board (key, 0);
1443 board_addr = (unsigned long)cd->cd_BoardAddr;
1444 board_size = (unsigned long)cd->cd_BoardSize;
1446 zinfo->base = ioremap(board_addr, board_size);
1447 zinfo->regs = zinfo->base;
1448 zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
1449 /* Get memory size - for now we asume its a 4MB board */
1450 zinfo->fbsize = 0x00400000; /* 4 MB */
1451 zinfo->physregs = board_addr;
1452 zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
1454 fb_info = fbinfo(zinfo);
1456 for (i = 0; i < 256; i++){
1457 for (i = 0; i < 256; i++){
1458 zinfo->color_table[i][0] = i;
1459 zinfo->color_table[i][1] = i;
1460 zinfo->color_table[i][2] = i;
1464 regs = zinfo->regs;
1465 /* Disable hardware cursor */
1466 seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
1468 retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
1469 retz3_setcolreg (254, 0, 0, 0, 0, fb_info);
1471 strcpy(fb_info->modename, retz3fb_name);
1472 fb_info->changevar = NULL;
1473 fb_info->node = -1;
1474 fb_info->fbops = &retz3fb_ops;
1475 fb_info->disp = &zinfo->disp;
1476 fb_info->switch_con = &z3fb_switch;
1477 fb_info->updatevar = &z3fb_updatevar;
1478 fb_info->blank = &z3fb_blank;
1479 fb_info->flags = FBINFO_FLAG_DEFAULT;
1480 strncpy(fb_info->fontname, fontname, 40);
1482 if (z3fb_mode == -1)
1483 retz3fb_default = retz3fb_predefined[0].var;
1485 retz3_decode_var(&retz3fb_default, &par);
1486 retz3_encode_var(&retz3fb_default, &par);
1488 do_fb_set_var(fb_info, &retz3fb_default, 0);
1489 retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
1491 retz3fb_set_disp(-1, fb_info);
1493 do_install_cmap(0, fb_info);
1495 if (register_framebuffer(fb_info) < 0)
1496 return -EINVAL;
1498 printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n",
1499 GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10);
1501 /* TODO: This driver cannot be unloaded yet */
1502 MOD_INC_USE_COUNT;
1504 return 0;
1508 static int z3fb_switch(int con, struct fb_info *info)
1510 struct retz3_fb_info *zinfo = retz3info(info);
1512 /* Do we have to save the colormap? */
1513 if (fb_display[zinfo->currcon].cmap.len)
1514 fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1,
1515 retz3_getcolreg, info);
1517 do_fb_set_var(info, &fb_display[con].var, 1);
1518 zinfo->currcon = con;
1519 /* Install new colormap */
1520 do_install_cmap(con, info);
1521 return 0;
1526 * Update the `var' structure (called by fbcon.c)
1528 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1529 * Since it's called by a kernel driver, no range checking is done.
1532 static int z3fb_updatevar(int con, struct fb_info *info)
1534 return 0;
1539 * Blank the display.
1542 static void z3fb_blank(int blank, struct fb_info *info)
1544 struct retz3_fb_info *zinfo = retz3info(info);
1545 volatile unsigned char *regs = retz3info(info)->regs;
1546 short i;
1548 if (blank)
1549 for (i = 0; i < 256; i++){
1550 reg_w(regs, VDAC_ADDRESS_W, i);
1551 reg_w(regs, VDAC_DATA, 0);
1552 reg_w(regs, VDAC_DATA, 0);
1553 reg_w(regs, VDAC_DATA, 0);
1555 else
1556 for (i = 0; i < 256; i++){
1557 reg_w(regs, VDAC_ADDRESS_W, i);
1558 reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
1559 reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
1560 reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
1566 * Get a Video Mode
1569 static int __init get_video_mode(const char *name)
1571 short i;
1573 for (i = 0; i < NUM_TOTAL_MODES; i++)
1574 if (!strcmp(name, retz3fb_predefined[i].name)){
1575 retz3fb_default = retz3fb_predefined[i].var;
1576 return i;
1578 return -1;
1582 #ifdef MODULE
1583 int init_module(void)
1585 return retz3fb_init();
1588 void cleanup_module(void)
1591 * Not reached because the usecount will never
1592 * be decremented to zero
1594 unregister_framebuffer(&fb_info);
1595 /* TODO: clean up ... */
1597 #endif
1601 * Text console acceleration
1604 #ifdef FBCON_HAS_CFB8
1605 static void retz3_8_bmove(struct display *p, int sy, int sx,
1606 int dy, int dx, int height, int width)
1608 int fontwidth = fontwidth(p);
1610 sx *= fontwidth;
1611 dx *= fontwidth;
1612 width *= fontwidth;
1614 retz3_bitblt(p,
1615 (unsigned short)sx,
1616 (unsigned short)(sy*fontheight(p)),
1617 (unsigned short)dx,
1618 (unsigned short)(dy*fontheight(p)),
1619 (unsigned short)width,
1620 (unsigned short)(height*fontheight(p)),
1621 Z3BLTcopy,
1622 0xffff);
1625 static void retz3_8_clear(struct vc_data *conp, struct display *p,
1626 int sy, int sx, int height, int width)
1628 unsigned short col;
1629 int fontwidth = fontwidth(p);
1631 sx *= fontwidth;
1632 width *= fontwidth;
1634 col = attr_bgcol_ec(p, conp);
1635 col &= 0xff;
1636 col |= (col << 8);
1638 retz3_bitblt(p,
1639 (unsigned short)sx,
1640 (unsigned short)(sy*fontheight(p)),
1641 (unsigned short)sx,
1642 (unsigned short)(sy*fontheight(p)),
1643 (unsigned short)width,
1644 (unsigned short)(height*fontheight(p)),
1645 Z3BLTset,
1646 col);
1650 static void retz3_putc(struct vc_data *conp, struct display *p, int c,
1651 int yy, int xx)
1653 retz3_busy(p);
1654 fbcon_cfb8_putc(conp, p, c, yy, xx);
1658 static void retz3_putcs(struct vc_data *conp, struct display *p,
1659 const unsigned short *s, int count,
1660 int yy, int xx)
1662 retz3_busy(p);
1663 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1667 static void retz3_revc(struct display *p, int xx, int yy)
1669 retz3_busy(p);
1670 fbcon_cfb8_revc(p, xx, yy);
1674 static void retz3_clear_margins(struct vc_data* conp, struct display* p,
1675 int bottom_only)
1677 retz3_busy(p);
1678 fbcon_cfb8_clear_margins(conp, p, bottom_only);
1682 static struct display_switch fbcon_retz3_8 = {
1683 fbcon_cfb8_setup, retz3_8_bmove, retz3_8_clear,
1684 retz3_putc, retz3_putcs, retz3_revc, NULL, NULL,
1685 retz3_clear_margins, FONTWIDTH(8)
1687 #endif