2.2.0-final
[davej-history.git] / drivers / video / retz3fb.c
blob995e86506d4c7dbdacaf1c891adb0d6c90012f25
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 long base;
105 unsigned long 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 struct display disp;
113 struct retz3fb_par current_par;
114 unsigned char color_table [256][3];
118 static char fontname[40] __initdata = { 0 };
120 #define retz3info(info) ((struct retz3_fb_info *)(info))
121 #define fbinfo(info) ((struct fb_info *)(info))
125 * Frame Buffer Name
128 static char retz3fb_name[16] = "RetinaZ3";
132 * A small info on how to convert XFree86 timing values into fb
133 * timings - by Frank Neumann:
135 An XFree86 mode line consists of the following fields:
136 "800x600" 50 800 856 976 1040 600 637 643 666
137 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
139 The fields in the fb_var_screeninfo structure are:
140 unsigned long pixclock; * pixel clock in ps (pico seconds) *
141 unsigned long left_margin; * time from sync to picture *
142 unsigned long right_margin; * time from picture to sync *
143 unsigned long upper_margin; * time from sync to picture *
144 unsigned long lower_margin;
145 unsigned long hsync_len; * length of horizontal sync *
146 unsigned long vsync_len; * length of vertical sync *
148 1) Pixelclock:
149 xfree: in MHz
150 fb: In Picoseconds (ps)
152 pixclock = 1000000 / DCF
154 2) horizontal timings:
155 left_margin = HFL - SH2
156 right_margin = SH1 - HR
157 hsync_len = SH2 - SH1
159 3) vertical timings:
160 upper_margin = VFL - SV2
161 lower_margin = SV1 - VR
162 vsync_len = SV2 - SV1
164 Good examples for VESA timings can be found in the XFree86 source tree,
165 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
169 * Predefined Video Modes
172 static struct fb_videomode retz3fb_predefined[] __initdata = {
174 * NB: it is very important to adjust the pixel-clock to the color-depth.
178 "640x480", { /* 640x480, 8 bpp */
179 640, 480, 640, 480, 0, 0, 8, 0,
180 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
181 #if 1
182 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
183 #else
184 0, 0, -1, -1, FB_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
185 #endif
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 void retz3fb_setup(char *options, int *ints);
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 void 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("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("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 = (char *)(zinfo->physfbmem);
798 fix->smem_len = zinfo->fbsize;
799 fix->mmio_start = (char *)(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 void retz3_bitblt (struct display *p,
963 unsigned short srcx, unsigned short srcy,
964 unsigned short destx, unsigned short desty,
965 unsigned short width, unsigned short height,
966 unsigned short cmd, unsigned short mask)
968 struct fb_var_screeninfo *var = &p->var;
969 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
970 volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
971 unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
973 unsigned short mod;
974 unsigned long tmp;
975 unsigned long pat, src, dst;
976 unsigned char blt_status;
978 int i, xres_virtual = var->xres_virtual;
979 short bpp = (var->bits_per_pixel & 0xff);
981 if (bpp < 8)
982 bpp = 8;
984 tmp = mask | (mask << 16);
986 #if 0
988 * Check for blitter finished before we start messing with the
989 * pattern.
992 blt_status = *(((volatile unsigned char *)acm) +
993 (ACM_START_STATUS + 2));
994 }while ((blt_status & 1) == 0);
995 #endif
997 i = 0;
999 *pattern++ = tmp;
1000 }while(i++ < bpp/4);
1002 tmp = cmd << 8;
1003 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
1005 mod = 0xc0c2;
1007 pat = 8 * PAT_MEM_OFF;
1008 dst = bpp * (destx + desty * xres_virtual);
1011 * Source is not set for clear.
1013 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
1014 src = bpp * (srcx + srcy * xres_virtual);
1016 if (destx > srcx) {
1017 mod &= ~0x8000;
1018 src += bpp * (width - 1);
1019 dst += bpp * (width - 1);
1020 pat += bpp * 2;
1022 if (desty > srcy) {
1023 mod &= ~0x4000;
1024 src += bpp * (height - 1) * xres_virtual;
1025 dst += bpp * (height - 1) * xres_virtual;
1026 pat += bpp * 4;
1029 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
1032 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
1034 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
1036 tmp = mod << 16;
1037 *(acm + ACM_CONTROL/4) = tmp;
1039 tmp = width | (height << 16);
1041 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
1043 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
1044 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
1047 * No reason to wait for the blitter to finish, it is better
1048 * just to check if it has finished before we use it again.
1050 #if 1
1051 #if 0
1052 while ((*(((volatile unsigned char *)acm) +
1053 (ACM_START_STATUS + 2)) & 1) == 0);
1054 #else
1056 blt_status = *(((volatile unsigned char *)acm) +
1057 (ACM_START_STATUS + 2));
1059 while ((blt_status & 1) == 0);
1060 #endif
1061 #endif
1064 #if 0
1066 * Move cursor to x, y
1068 static void retz3_MoveCursor (unsigned short x, unsigned short y)
1070 /* Guess we gotta deal with the cursor at some point */
1072 #endif
1076 * Fill the hardware's `par' structure.
1079 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
1081 struct retz3_fb_info *zinfo = retz3info(info);
1083 if (zinfo->current_par_valid)
1084 *par = zinfo->current_par;
1085 else
1086 retz3_decode_var(&retz3fb_default, par);
1090 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
1092 struct retz3_fb_info *zinfo = retz3info(info);
1094 zinfo->current_par = *par;
1095 zinfo->current_par_valid = 1;
1099 static int do_fb_set_var(struct fb_info *info,
1100 struct fb_var_screeninfo *var, int isactive)
1102 int err, activate;
1103 struct retz3fb_par par;
1104 struct retz3_fb_info *zinfo = retz3info(info);
1106 if ((err = retz3_decode_var(var, &par)))
1107 return err;
1108 activate = var->activate;
1110 /* XXX ... what to do about isactive ? */
1112 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
1113 retz3fb_set_par(info, &par);
1114 retz3_encode_var(var, &par);
1115 var->activate = activate;
1117 retz3_set_video(info, var, &zinfo->current_par);
1119 return 0;
1123 static void do_install_cmap(int con, struct fb_info *info)
1125 struct retz3_fb_info *zinfo = retz3info(info);
1127 if (con != zinfo->currcon)
1128 return;
1129 if (fb_display[con].cmap.len)
1130 fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info);
1131 else
1132 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1133 1, retz3_setcolreg, info);
1138 * Open/Release the frame buffer device
1141 static int retz3fb_open(struct fb_info *info, int user)
1144 * Nothing, only a usage count for the moment
1147 MOD_INC_USE_COUNT;
1148 return 0;
1151 static int retz3fb_release(struct fb_info *info, int user)
1153 MOD_DEC_USE_COUNT;
1154 return 0;
1159 * Get the Fixed Part of the Display
1162 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
1163 struct fb_info *info)
1165 struct retz3fb_par par;
1166 int error = 0;
1168 if (con == -1)
1169 retz3fb_get_par(info, &par);
1170 else
1171 error = retz3_decode_var(&fb_display[con].var, &par);
1172 return(error ? error : retz3_encode_fix(info, fix, &par));
1177 * Get the User Defined Part of the Display
1180 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
1181 struct fb_info *info)
1183 struct retz3fb_par par;
1184 int error = 0;
1186 if (con == -1) {
1187 retz3fb_get_par(info, &par);
1188 error = retz3_encode_var(var, &par);
1189 } else
1190 *var = fb_display[con].var;
1191 return error;
1195 #if 1
1196 static void retz3fb_set_disp(int con, struct fb_info *info)
1198 struct fb_fix_screeninfo fix;
1199 struct display *display;
1200 struct retz3_fb_info *zinfo = retz3info(info);
1202 if (con >= 0)
1203 display = &fb_display[con];
1204 else
1205 display = &zinfo->disp; /* used during initialization */
1207 retz3fb_get_fix(&fix, con, info);
1209 if (con == -1)
1210 con = 0;
1212 display->screen_base = (char *)zinfo->fbmem;
1213 display->visual = fix.visual;
1214 display->type = fix.type;
1215 display->type_aux = fix.type_aux;
1216 display->ypanstep = fix.ypanstep;
1217 display->ywrapstep = fix.ywrapstep;
1218 display->can_soft_blank = 1;
1219 display->inverse = z3fb_inverse;
1222 * This seems to be about 20% faster.
1224 display->scrollmode = SCROLL_YREDRAW;
1226 switch (display->var.bits_per_pixel) {
1227 #ifdef FBCON_HAS_CFB8
1228 case 8:
1229 if (display->var.accel_flags & FB_ACCELF_TEXT) {
1230 display->dispsw = &fbcon_retz3_8;
1231 retz3_set_video(info, &display->var, &zinfo->current_par);
1232 } else
1233 display->dispsw = &fbcon_cfb8;
1234 break;
1235 #endif
1236 #ifdef FBCON_HAS_CFB16
1237 case 16:
1238 display->dispsw = &fbcon_cfb16;
1239 break;
1240 #endif
1241 default:
1242 display->dispsw = &fbcon_dummy;
1243 break;
1246 #endif
1250 * Set the User Defined Part of the Display
1253 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
1254 struct fb_info *info)
1256 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
1257 struct display *display;
1258 struct retz3_fb_info *zinfo = retz3info(info);
1260 if (con >= 0)
1261 display = &fb_display[con];
1262 else
1263 display = &zinfo->disp; /* used during initialization */
1265 if ((err = do_fb_set_var(info, var, con == zinfo->currcon)))
1266 return err;
1267 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1268 oldxres = display->var.xres;
1269 oldyres = display->var.yres;
1270 oldvxres = display->var.xres_virtual;
1271 oldvyres = display->var.yres_virtual;
1272 oldbpp = display->var.bits_per_pixel;
1273 oldaccel = display->var.accel_flags;
1274 display->var = *var;
1276 if (oldxres != var->xres || oldyres != var->yres ||
1277 oldvxres != var->xres_virtual ||
1278 oldvyres != var->yres_virtual ||
1279 oldbpp != var->bits_per_pixel ||
1280 oldaccel != var->accel_flags) {
1282 struct fb_fix_screeninfo fix;
1283 retz3fb_get_fix(&fix, con, info);
1285 display->screen_base = (char *)zinfo->fbmem;
1286 display->visual = fix.visual;
1287 display->type = fix.type;
1288 display->type_aux = fix.type_aux;
1289 display->ypanstep = fix.ypanstep;
1290 display->ywrapstep = fix.ywrapstep;
1291 display->line_length = fix.line_length;
1292 display->can_soft_blank = 1;
1293 display->inverse = z3fb_inverse;
1294 switch (display->var.bits_per_pixel) {
1295 #ifdef FBCON_HAS_CFB8
1296 case 8:
1297 if (var->accel_flags & FB_ACCELF_TEXT) {
1298 display->dispsw = &fbcon_retz3_8;
1299 } else
1300 display->dispsw = &fbcon_cfb8;
1301 break;
1302 #endif
1303 #ifdef FBCON_HAS_CFB16
1304 case 16:
1305 display->dispsw = &fbcon_cfb16;
1306 break;
1307 #endif
1308 default:
1309 display->dispsw = &fbcon_dummy;
1310 break;
1313 * We still need to find a way to tell the X
1314 * server that the video mem has been fiddled with
1315 * so it redraws the entire screen when switching
1316 * between X and a text console.
1318 retz3_set_video(info, var, &zinfo->current_par);
1320 if (info->changevar)
1321 (*info->changevar)(con);
1324 if (oldbpp != var->bits_per_pixel) {
1325 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1326 return err;
1327 do_install_cmap(con, info);
1330 return 0;
1335 * Get the Colormap
1338 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1339 struct fb_info *info)
1341 struct retz3_fb_info *zinfo = retz3info(info);
1343 if (con == zinfo->currcon) /* current console? */
1344 return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
1345 else if (fb_display[con].cmap.len) /* non default colormap? */
1346 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1347 else
1348 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1349 cmap, kspc ? 0 : 2);
1350 return 0;
1355 * Set the Colormap
1358 static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1359 struct fb_info *info)
1361 int err;
1362 struct retz3_fb_info *zinfo = retz3info(info);
1364 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
1365 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1366 1<<fb_display[con].var.bits_per_pixel,
1367 0)))
1368 return err;
1370 if (con == zinfo->currcon) /* current console? */
1371 return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info));
1372 else
1373 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1374 return 0;
1379 * Pan or Wrap the Display
1381 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1384 static int retz3fb_pan_display(struct fb_var_screeninfo *var, int con,
1385 struct fb_info *info)
1387 return -EINVAL;
1392 * RetinaZ3 Frame Buffer Specific ioctls
1395 static int retz3fb_ioctl(struct inode *inode, struct file *file,
1396 unsigned int cmd, unsigned long arg, int con,
1397 struct fb_info *info)
1399 return -EINVAL;
1403 static struct fb_ops retz3fb_ops = {
1404 retz3fb_open, retz3fb_release, retz3fb_get_fix, retz3fb_get_var,
1405 retz3fb_set_var, retz3fb_get_cmap, retz3fb_set_cmap,
1406 retz3fb_pan_display, retz3fb_ioctl
1410 __initfunc(void retz3fb_setup(char *options, int *ints))
1412 char *this_opt;
1414 if (!options || !*options)
1415 return;
1417 for (this_opt = strtok(options, ","); this_opt;
1418 this_opt = strtok(NULL, ",")){
1419 if (!strcmp(this_opt, "inverse")) {
1420 z3fb_inverse = 1;
1421 fb_invert_cmaps();
1422 } else if (!strncmp(this_opt, "font:", 5)) {
1423 strncpy(fontname, this_opt+5, 39);
1424 fontname[39] = '\0';
1425 }else
1426 z3fb_mode = get_video_mode(this_opt);
1432 * Initialization
1435 __initfunc(void retz3fb_init(void))
1437 unsigned long board_addr, board_size;
1438 unsigned int key;
1439 const struct ConfigDev *cd;
1440 volatile unsigned char *regs;
1441 struct retz3fb_par par;
1442 struct retz3_fb_info *zinfo;
1443 struct fb_info *fb_info;
1444 short i;
1446 if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0)))
1447 return;
1449 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL)))
1450 return;
1451 memset(zinfo, 0, sizeof(struct retz3_fb_info));
1453 cd = zorro_get_board (key);
1454 zorro_config_board (key, 0);
1455 board_addr = (unsigned long)cd->cd_BoardAddr;
1456 board_size = (unsigned long)cd->cd_BoardSize;
1458 zinfo->base = ioremap(board_addr, board_size);
1459 zinfo->regs = (unsigned char *)(zinfo->base);
1460 zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
1461 /* Get memory size - for now we asume its a 4MB board */
1462 zinfo->fbsize = 0x00400000; /* 4 MB */
1463 zinfo->physregs = board_addr;
1464 zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
1466 fb_info = fbinfo(zinfo);
1468 for (i = 0; i < 256; i++){
1469 for (i = 0; i < 256; i++){
1470 zinfo->color_table[i][0] = i;
1471 zinfo->color_table[i][1] = i;
1472 zinfo->color_table[i][2] = i;
1476 regs = zinfo->regs;
1477 /* Disable hardware cursor */
1478 seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
1480 retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
1481 retz3_setcolreg (254, 0, 0, 0, 0, fb_info);
1483 strcpy(fb_info->modename, retz3fb_name);
1484 fb_info->changevar = NULL;
1485 fb_info->node = -1;
1486 fb_info->fbops = &retz3fb_ops;
1487 fb_info->disp = &zinfo->disp;
1488 fb_info->switch_con = &z3fb_switch;
1489 fb_info->updatevar = &z3fb_updatevar;
1490 fb_info->blank = &z3fb_blank;
1491 fb_info->flags = FBINFO_FLAG_DEFAULT;
1492 strncpy(fb_info->fontname, fontname, 40);
1494 if (z3fb_mode == -1)
1495 retz3fb_default = retz3fb_predefined[0].var;
1497 retz3_decode_var(&retz3fb_default, &par);
1498 retz3_encode_var(&retz3fb_default, &par);
1500 do_fb_set_var(fb_info, &retz3fb_default, 0);
1501 retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
1503 retz3fb_set_disp(-1, fb_info);
1505 do_install_cmap(0, fb_info);
1507 if (register_framebuffer(fb_info) < 0)
1508 return;
1510 printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
1511 GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10);
1513 /* TODO: This driver cannot be unloaded yet */
1514 MOD_INC_USE_COUNT;
1518 static int z3fb_switch(int con, struct fb_info *info)
1520 struct retz3_fb_info *zinfo = retz3info(info);
1522 /* Do we have to save the colormap? */
1523 if (fb_display[zinfo->currcon].cmap.len)
1524 fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1,
1525 retz3_getcolreg, info);
1527 do_fb_set_var(info, &fb_display[con].var, 1);
1528 zinfo->currcon = con;
1529 /* Install new colormap */
1530 do_install_cmap(con, info);
1531 return 0;
1536 * Update the `var' structure (called by fbcon.c)
1538 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1539 * Since it's called by a kernel driver, no range checking is done.
1542 static int z3fb_updatevar(int con, struct fb_info *info)
1544 return 0;
1549 * Blank the display.
1552 static void z3fb_blank(int blank, struct fb_info *info)
1554 struct retz3_fb_info *zinfo = retz3info(info);
1555 volatile unsigned char *regs = retz3info(info)->regs;
1556 short i;
1558 if (blank)
1559 for (i = 0; i < 256; i++){
1560 reg_w(regs, VDAC_ADDRESS_W, i);
1561 reg_w(regs, VDAC_DATA, 0);
1562 reg_w(regs, VDAC_DATA, 0);
1563 reg_w(regs, VDAC_DATA, 0);
1565 else
1566 for (i = 0; i < 256; i++){
1567 reg_w(regs, VDAC_ADDRESS_W, i);
1568 reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
1569 reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
1570 reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
1576 * Get a Video Mode
1579 __initfunc(static int get_video_mode(const char *name))
1581 short i;
1583 for (i = 0; i <= NUM_TOTAL_MODES; i++)
1584 if (!strcmp(name, retz3fb_predefined[i].name)){
1585 retz3fb_default = retz3fb_predefined[i].var;
1586 return i;
1588 return -1;
1592 #ifdef MODULE
1593 int init_module(void)
1595 retz3fb_init();
1596 return 0;
1599 void cleanup_module(void)
1602 * Not reached because the usecount will never
1603 * be decremented to zero
1605 unregister_framebuffer(&fb_info);
1606 /* TODO: clean up ... */
1608 #endif
1612 * Text console acceleration
1615 #ifdef FBCON_HAS_CFB8
1616 static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
1617 int dy, int dx, int height, int width)
1619 int fontwidth = fontwidth(p);
1621 sx *= fontwidth;
1622 dx *= fontwidth;
1623 width *= fontwidth;
1625 retz3_bitblt(p,
1626 (unsigned short)sx,
1627 (unsigned short)(sy*fontheight(p)),
1628 (unsigned short)dx,
1629 (unsigned short)(dy*fontheight(p)),
1630 (unsigned short)width,
1631 (unsigned short)(height*fontheight(p)),
1632 Z3BLTcopy,
1633 0xffff);
1636 static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
1637 int sy, int sx, int height, int width)
1639 unsigned short col;
1640 int fontwidth = fontwidth(p);
1642 sx *= fontwidth;
1643 width *= fontwidth;
1645 col = attr_bgcol_ec(p, conp);
1646 col &= 0xff;
1647 col |= (col << 8);
1649 retz3_bitblt(p,
1650 (unsigned short)sx,
1651 (unsigned short)(sy*fontheight(p)),
1652 (unsigned short)sx,
1653 (unsigned short)(sy*fontheight(p)),
1654 (unsigned short)width,
1655 (unsigned short)(height*fontheight(p)),
1656 Z3BLTset,
1657 col);
1660 static struct display_switch fbcon_retz3_8 = {
1661 fbcon_cfb8_setup, fbcon_retz3_8_bmove, fbcon_retz3_8_clear,
1662 fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL,
1663 fbcon_cfb8_clear_margins, FONTWIDTH(8)
1665 #endif