[PATCH] fbdev driver for S3 Trio/Virge
[linux-2.6/cjktty.git] / drivers / video / retz3fb.c
blobbc7ffc84e1855cf0276b1a6e0470a26cf8abb184
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/slab.h>
29 #include <linux/delay.h>
30 #include <linux/fb.h>
31 #include <linux/zorro.h>
32 #include <linux/init.h>
34 #include <asm/uaccess.h>
35 #include <asm/system.h>
36 #include <asm/irq.h>
37 #include <asm/pgtable.h>
38 #include <asm/io.h>
40 #include <video/fbcon.h>
41 #include <video/fbcon-cfb8.h>
42 #include <video/fbcon-cfb16.h>
44 #include "retz3fb.h"
46 /* #define DEBUG if(1) */
47 #define DEBUG if(0)
50 * Reserve space for one pattern line.
52 * For the time being we only support 4MB boards!
55 #define PAT_MEM_SIZE 16*3
56 #define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
58 struct retz3fb_par {
59 int xres;
60 int yres;
61 int xres_vir;
62 int yres_vir;
63 int xoffset;
64 int yoffset;
65 int bpp;
67 struct fb_bitfield red;
68 struct fb_bitfield green;
69 struct fb_bitfield blue;
70 struct fb_bitfield transp;
72 int pixclock;
73 int left_margin; /* time from sync to picture */
74 int right_margin; /* time from picture to sync */
75 int upper_margin; /* time from sync to picture */
76 int lower_margin;
77 int hsync_len; /* length of horizontal sync */
78 int vsync_len; /* length of vertical sync */
79 int vmode;
81 int accel;
84 struct display_data {
85 long h_total; /* Horizontal Total */
86 long h_sstart; /* Horizontal Sync Start */
87 long h_sstop; /* Horizontal Sync Stop */
88 long h_bstart; /* Horizontal Blank Start */
89 long h_bstop; /* Horizontal Blank Stop */
90 long h_dispend; /* Horizontal Display End */
91 long v_total; /* Vertical Total */
92 long v_sstart; /* Vertical Sync Start */
93 long v_sstop; /* Vertical Sync Stop */
94 long v_bstart; /* Vertical Blank Start */
95 long v_bstop; /* Vertical Blank Stop */
96 long v_dispend; /* Horizontal Display End */
99 struct retz3_fb_info {
100 struct fb_info info;
101 unsigned char *base;
102 unsigned char *fbmem;
103 unsigned long fbsize;
104 volatile unsigned char *regs;
105 unsigned long physfbmem;
106 unsigned long physregs;
107 int current_par_valid; /* set to 0 by memset */
108 int blitbusy;
109 struct display disp;
110 struct retz3fb_par current_par;
111 unsigned char color_table [256][3];
115 static char fontname[40] __initdata = { 0 };
117 #define retz3info(info) ((struct retz3_fb_info *)(info))
118 #define fbinfo(info) ((struct fb_info *)(info))
122 * Frame Buffer Name
125 static char retz3fb_name[16] = "RetinaZ3";
129 * A small info on how to convert XFree86 timing values into fb
130 * timings - by Frank Neumann:
132 An XFree86 mode line consists of the following fields:
133 "800x600" 50 800 856 976 1040 600 637 643 666
134 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
136 The fields in the fb_var_screeninfo structure are:
137 unsigned long pixclock; * pixel clock in ps (pico seconds) *
138 unsigned long left_margin; * time from sync to picture *
139 unsigned long right_margin; * time from picture to sync *
140 unsigned long upper_margin; * time from sync to picture *
141 unsigned long lower_margin;
142 unsigned long hsync_len; * length of horizontal sync *
143 unsigned long vsync_len; * length of vertical sync *
145 1) Pixelclock:
146 xfree: in MHz
147 fb: In Picoseconds (ps)
149 pixclock = 1000000 / DCF
151 2) horizontal timings:
152 left_margin = HFL - SH2
153 right_margin = SH1 - HR
154 hsync_len = SH2 - SH1
156 3) vertical timings:
157 upper_margin = VFL - SV2
158 lower_margin = SV1 - VR
159 vsync_len = SV2 - SV1
161 Good examples for VESA timings can be found in the XFree86 source tree,
162 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
166 * Predefined Video Modes
169 static struct {
170 const char *name;
171 struct fb_var_screeninfo var;
172 } 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 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
182 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
186 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
187 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
190 "800x600", { /* 800x600, 8 bpp */
191 800, 600, 800, 600, 0, 0, 8, 0,
192 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
193 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2,
194 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
198 "800x600-60", { /* 800x600, 8 bpp */
199 800, 600, 800, 600, 0, 0, 8, 0,
200 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
201 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
202 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
206 "800x600-70", { /* 800x600, 8 bpp */
207 800, 600, 800, 600, 0, 0, 8, 0,
208 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
209 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12,
210 FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
214 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
215 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
218 "1024x768i", { /* 1024x768, 8 bpp, interlaced */
219 1024, 768, 1024, 768, 0, 0, 8, 0,
220 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
221 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8,
222 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
226 "1024x768", {
227 1024, 768, 1024, 768, 0, 0, 8, 0,
228 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
229 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
230 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
234 "640x480-16", { /* 640x480, 16 bpp */
235 640, 480, 640, 480, 0, 0, 16, 0,
236 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
237 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
238 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
242 "640x480-24", { /* 640x480, 24 bpp */
243 640, 480, 640, 480, 0, 0, 24, 0,
244 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
245 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
246 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
252 #define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined)
254 static struct fb_var_screeninfo retz3fb_default;
256 static int z3fb_inverse = 0;
257 static int z3fb_mode __initdata = 0;
261 * Interface used by the world
264 int retz3fb_setup(char *options);
266 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
267 struct fb_info *info);
268 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
269 struct fb_info *info);
270 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
271 struct fb_info *info);
272 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
273 struct fb_info *info);
274 static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
275 unsigned int green, unsigned int blue,
276 unsigned int transp, struct fb_info *info);
277 static int retz3fb_blank(int blank, struct fb_info *info);
281 * Interface to the low level console driver
284 int retz3fb_init(void);
285 static int z3fb_switch(int con, struct fb_info *info);
286 static int z3fb_updatevar(int con, struct fb_info *info);
290 * Text console acceleration
293 #ifdef FBCON_HAS_CFB8
294 static struct display_switch fbcon_retz3_8;
295 #endif
299 * Accelerated Functions used by the low level console driver
302 static void retz3_bitblt(struct display *p,
303 unsigned short curx, unsigned short cury, unsigned
304 short destx, unsigned short desty, unsigned short
305 width, unsigned short height, unsigned short cmd,
306 unsigned short mask);
309 * Hardware Specific Routines
312 static int retz3_encode_fix(struct fb_info *info,
313 struct fb_fix_screeninfo *fix,
314 struct retz3fb_par *par);
315 static int retz3_decode_var(struct fb_var_screeninfo *var,
316 struct retz3fb_par *par);
317 static int retz3_encode_var(struct fb_var_screeninfo *var,
318 struct retz3fb_par *par);
319 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
320 unsigned int *green, unsigned int *blue,
321 unsigned int *transp, struct fb_info *info);
324 * Internal routines
327 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
328 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
329 static int do_fb_set_var(struct fb_info *info,
330 struct fb_var_screeninfo *var, int isactive);
331 static void retz3fb_set_disp(int con, struct fb_info *info);
332 static int get_video_mode(const char *name);
335 /* -------------------- Hardware specific routines ------------------------- */
337 static unsigned short find_fq(unsigned int freq)
339 unsigned long f;
340 long tmp;
341 long prev = 0x7fffffff;
342 long n2, n1 = 3;
343 unsigned long m;
344 unsigned short res = 0;
346 if (freq <= 31250000)
347 n2 = 3;
348 else if (freq <= 62500000)
349 n2 = 2;
350 else if (freq <= 125000000)
351 n2 = 1;
352 else if (freq <= 250000000)
353 n2 = 0;
354 else
355 return 0;
358 do {
359 f = freq >> (10 - n2);
361 m = (f * n1) / (14318180/1024);
363 if (m > 129)
364 break;
366 tmp = (((m * 14318180) >> n2) / n1) - freq;
367 if (tmp < 0)
368 tmp = -tmp;
370 if (tmp < prev) {
371 prev = tmp;
372 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
375 } while ( (++n1) <= 21);
377 return res;
381 static int retz3_set_video(struct fb_info *info,
382 struct fb_var_screeninfo *var,
383 struct retz3fb_par *par)
385 volatile unsigned char *regs = retz3info(info)->regs;
386 unsigned int freq;
388 int xres, hfront, hsync, hback;
389 int yres, vfront, vsync, vback;
390 unsigned char tmp;
391 unsigned short best_freq;
392 struct display_data data;
394 short clocksel = 0; /* Apparantly this is always zero */
396 int bpp = var->bits_per_pixel;
399 * XXX
401 if (bpp == 24)
402 return 0;
404 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
405 return -EFAULT;
407 par->xoffset = 0;
408 par->yoffset = 0;
410 xres = var->xres * bpp / 4;
411 hfront = var->right_margin * bpp / 4;
412 hsync = var->hsync_len * bpp / 4;
413 hback = var->left_margin * bpp / 4;
415 if (var->vmode & FB_VMODE_DOUBLE)
417 yres = var->yres * 2;
418 vfront = var->lower_margin * 2;
419 vsync = var->vsync_len * 2;
420 vback = var->upper_margin * 2;
422 else if (var->vmode & FB_VMODE_INTERLACED)
424 yres = (var->yres + 1) / 2;
425 vfront = (var->lower_margin + 1) / 2;
426 vsync = (var->vsync_len + 1) / 2;
427 vback = (var->upper_margin + 1) / 2;
429 else
431 yres = var->yres; /* -1 ? */
432 vfront = var->lower_margin;
433 vsync = var->vsync_len;
434 vback = var->upper_margin;
437 data.h_total = (hback / 8) + (xres / 8)
438 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
439 data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
440 data.h_bstart = xres / 8 - 1 /* + 1 */;
442 data.h_bstop = data.h_total+1 + 2 + 1;
443 data.h_sstart = (xres / 8) + (hfront / 8) + 1;
444 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
446 data.v_total = yres + vfront + vsync + vback - 1;
448 data.v_dispend = yres - 1;
449 data.v_bstart = yres - 1;
451 data.v_bstop = data.v_total;
452 data.v_sstart = yres + vfront - 1 - 2;
453 data.v_sstop = yres + vfront + vsync - 1;
455 #if 0 /* testing */
457 printk("HBS: %i\n", data.h_bstart);
458 printk("HSS: %i\n", data.h_sstart);
459 printk("HSE: %i\n", data.h_sstop);
460 printk("HBE: %i\n", data.h_bstop);
461 printk("HT: %i\n", data.h_total);
463 printk("hsync: %i\n", hsync);
464 printk("hfront: %i\n", hfront);
465 printk("hback: %i\n", hback);
467 printk("VBS: %i\n", data.v_bstart);
468 printk("VSS: %i\n", data.v_sstart);
469 printk("VSE: %i\n", data.v_sstop);
470 printk("VBE: %i\n", data.v_bstop);
471 printk("VT: %i\n", data.v_total);
473 printk("vsync: %i\n", vsync);
474 printk("vfront: %i\n", vfront);
475 printk("vback: %i\n", vback);
476 #endif
478 if (data.v_total >= 1024)
479 printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n");
481 reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
482 reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
484 seq_w(regs, SEQ_RESET, 0x00);
485 seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */
488 * CLOCKING_MODE bits:
489 * 2: This one is only set for certain text-modes, wonder if
490 * it may be for EGA-lines? (it was referred to as CLKDIV2)
491 * (The CL drivers sets it to 0x21 with the comment:
492 * FullBandwidth (video off) and 8/9 dot clock)
494 seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
496 seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
497 seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
498 seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
499 seq_w(regs, SEQ_RESET, 0x01);
500 seq_w(regs, SEQ_RESET, 0x03);
502 seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
504 seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
505 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
506 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
507 seq_w(regs, SEQ_LINEAR_0, 0x4a);
508 seq_w(regs, SEQ_LINEAR_1, 0x00);
510 seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
511 seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
512 seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
515 * The lower 4 bits (0-3) are used to set the font-width for
516 * text-mode - DON'T try to set this for gfx-mode.
518 seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
519 seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
522 * Extended Pixel Control:
523 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
524 * bit 1: (Packed/Nibble Pixel Format ?)
525 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
527 seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
529 seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
530 seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
531 seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
532 seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
533 seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
534 seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
535 seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
536 seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
537 seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
538 seq_w(regs, SEQ_CRC_CONTROL, 0x00);
539 seq_w(regs, SEQ_PERF_SELECT, 0x10);
540 seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
541 seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
542 seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
543 seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
546 /* unlock register CRT0..CRT7 */
547 crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
549 /* Zuerst zu schreibende Werte nur per printk ausgeben */
550 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
551 crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
553 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
554 crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
556 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
557 crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
559 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
560 crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
562 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
563 crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
565 tmp = (data.h_sstop & 0x1f);
566 if (data.h_bstop & 0x20)
567 tmp |= 0x80;
568 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
569 crt_w(regs, CRT_END_HOR_RETR, tmp);
571 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
572 crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
574 tmp = 0x10; /* LineCompare bit #9 */
575 if (data.v_total & 256)
576 tmp |= 0x01;
577 if (data.v_dispend & 256)
578 tmp |= 0x02;
579 if (data.v_sstart & 256)
580 tmp |= 0x04;
581 if (data.v_bstart & 256)
582 tmp |= 0x08;
583 if (data.v_total & 512)
584 tmp |= 0x20;
585 if (data.v_dispend & 512)
586 tmp |= 0x40;
587 if (data.v_sstart & 512)
588 tmp |= 0x80;
589 DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
590 crt_w(regs, CRT_OVERFLOW, tmp);
592 crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
594 tmp = 0x40; /* LineCompare bit #8 */
595 if (data.v_bstart & 512)
596 tmp |= 0x20;
597 if (var->vmode & FB_VMODE_DOUBLE)
598 tmp |= 0x80;
599 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
600 crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
602 crt_w(regs, CRT_CURSOR_START, 0x00);
603 crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
605 crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
606 crt_w(regs, CRT_START_ADDR_LOW, 0x00);
608 crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
609 crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
611 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
612 crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
614 #if 1
615 /* 5 refresh cycles per scanline */
616 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
617 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
618 #else
619 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
620 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
621 #endif
622 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
623 crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
625 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
626 crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
628 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
629 crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
631 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
632 crt_w(regs, CRT_MODE_CONTROL, 0xe3);
634 DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
635 crt_w(regs, CRT_LINE_COMPARE, 0xff);
637 tmp = (var->xres_virtual / 8) * (bpp / 8);
638 crt_w(regs, CRT_OFFSET, tmp);
640 crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
642 tmp = 0x20; /* Enable extended end bits */
643 if (data.h_total & 0x100)
644 tmp |= 0x01;
645 if ((data.h_dispend) & 0x100)
646 tmp |= 0x02;
647 if (data.h_bstart & 0x100)
648 tmp |= 0x04;
649 if (data.h_sstart & 0x100)
650 tmp |= 0x08;
651 if (var->vmode & FB_VMODE_INTERLACED)
652 tmp |= 0x10;
653 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
654 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
656 tmp = 0x00;
657 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
658 tmp |= 0x10;
659 crt_w(regs, CRT_EXT_START_ADDR, tmp);
661 tmp = 0x00;
662 if (data.h_total & 0x200)
663 tmp |= 0x01;
664 if ((data.h_dispend) & 0x200)
665 tmp |= 0x02;
666 if (data.h_bstart & 0x200)
667 tmp |= 0x04;
668 if (data.h_sstart & 0x200)
669 tmp |= 0x08;
670 tmp |= ((data.h_bstop & 0xc0) >> 2);
671 tmp |= ((data.h_sstop & 0x60) << 1);
672 crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
673 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
675 tmp = 0x10; /* Line compare bit 10 */
676 if (data.v_total & 0x400)
677 tmp |= 0x01;
678 if ((data.v_dispend) & 0x400)
679 tmp |= 0x02;
680 if (data.v_bstart & 0x400)
681 tmp |= 0x04;
682 if (data.v_sstart & 0x400)
683 tmp |= 0x08;
684 tmp |= ((data.v_bstop & 0x300) >> 3);
685 if (data.v_sstop & 0x10)
686 tmp |= 0x80;
687 crt_w(regs, CRT_EXT_VER_TIMING, tmp);
688 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
690 crt_w(regs, CRT_MONITOR_POWER, 0x00);
693 * Convert from ps to Hz.
695 freq = 2000000000 / var->pixclock;
696 freq = freq * 500;
698 best_freq = find_fq(freq);
699 pll_w(regs, 0x02, best_freq);
700 best_freq = find_fq(61000000);
701 pll_w(regs, 0x0a, best_freq);
702 pll_w(regs, 0x0e, 0x22);
704 gfx_w(regs, GFX_SET_RESET, 0x00);
705 gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
706 gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
707 gfx_w(regs, GFX_DATA_ROTATE, 0x00);
708 gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
709 gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
710 gfx_w(regs, GFX_MISC, 0x05);
711 gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
712 gfx_w(regs, GFX_BITMASK, 0xff);
714 reg_r(regs, ACT_ADDRESS_RESET);
715 attr_w(regs, ACT_PALETTE0 , 0x00);
716 attr_w(regs, ACT_PALETTE1 , 0x01);
717 attr_w(regs, ACT_PALETTE2 , 0x02);
718 attr_w(regs, ACT_PALETTE3 , 0x03);
719 attr_w(regs, ACT_PALETTE4 , 0x04);
720 attr_w(regs, ACT_PALETTE5 , 0x05);
721 attr_w(regs, ACT_PALETTE6 , 0x06);
722 attr_w(regs, ACT_PALETTE7 , 0x07);
723 attr_w(regs, ACT_PALETTE8 , 0x08);
724 attr_w(regs, ACT_PALETTE9 , 0x09);
725 attr_w(regs, ACT_PALETTE10, 0x0a);
726 attr_w(regs, ACT_PALETTE11, 0x0b);
727 attr_w(regs, ACT_PALETTE12, 0x0c);
728 attr_w(regs, ACT_PALETTE13, 0x0d);
729 attr_w(regs, ACT_PALETTE14, 0x0e);
730 attr_w(regs, ACT_PALETTE15, 0x0f);
731 reg_r(regs, ACT_ADDRESS_RESET);
733 attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
735 attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
736 attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
737 attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
738 attr_w(regs, ACT_COLOR_SELECT, 0x00);
740 reg_r(regs, ACT_ADDRESS_RESET);
741 reg_w(regs, ACT_DATA, 0x20);
743 reg_w(regs, VDAC_MASK, 0xff);
746 * Extended palette addressing ???
748 switch (bpp){
749 case 8:
750 reg_w(regs, 0x83c6, 0x00);
751 break;
752 case 16:
753 reg_w(regs, 0x83c6, 0x60);
754 break;
755 case 24:
756 reg_w(regs, 0x83c6, 0xe0);
757 break;
758 default:
759 printk(KERN_INFO "Illegal color-depth: %i\n", bpp);
762 reg_w(regs, VDAC_ADDRESS, 0x00);
764 seq_w(regs, SEQ_MAP_MASK, 0x0f );
766 return 0;
771 * This function should fill in the `fix' structure based on the
772 * values in the `par' structure.
775 static int retz3_encode_fix(struct fb_info *info,
776 struct fb_fix_screeninfo *fix,
777 struct retz3fb_par *par)
779 struct retz3_fb_info *zinfo = retz3info(info);
781 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
782 strcpy(fix->id, retz3fb_name);
783 fix->smem_start = zinfo->physfbmem;
784 fix->smem_len = zinfo->fbsize;
785 fix->mmio_start = zinfo->physregs;
786 fix->mmio_len = 0x00c00000;
788 fix->type = FB_TYPE_PACKED_PIXELS;
789 fix->type_aux = 0;
790 if (par->bpp == 8)
791 fix->visual = FB_VISUAL_PSEUDOCOLOR;
792 else
793 fix->visual = FB_VISUAL_TRUECOLOR;
795 fix->xpanstep = 0;
796 fix->ypanstep = 0;
797 fix->ywrapstep = 0;
798 fix->line_length = 0;
800 fix->accel = FB_ACCEL_NCR_77C32BLT;
802 return 0;
807 * Get the video params out of `var'. If a value doesn't fit, round
808 * it up, if it's too big, return -EINVAL.
811 static int retz3_decode_var(struct fb_var_screeninfo *var,
812 struct retz3fb_par *par)
814 par->xres = var->xres;
815 par->yres = var->yres;
816 par->xres_vir = var->xres_virtual;
817 par->yres_vir = var->yres_virtual;
818 par->bpp = var->bits_per_pixel;
819 par->pixclock = var->pixclock;
820 par->vmode = var->vmode;
822 par->red = var->red;
823 par->green = var->green;
824 par->blue = var->blue;
825 par->transp = var->transp;
827 par->left_margin = var->left_margin;
828 par->right_margin = var->right_margin;
829 par->upper_margin = var->upper_margin;
830 par->lower_margin = var->lower_margin;
831 par->hsync_len = var->hsync_len;
832 par->vsync_len = var->vsync_len;
834 if (var->accel_flags & FB_ACCELF_TEXT)
835 par->accel = FB_ACCELF_TEXT;
836 else
837 par->accel = 0;
839 return 0;
844 * Fill the `var' structure based on the values in `par' and maybe
845 * other values read out of the hardware.
848 static int retz3_encode_var(struct fb_var_screeninfo *var,
849 struct retz3fb_par *par)
851 memset(var, 0, sizeof(struct fb_var_screeninfo));
852 var->xres = par->xres;
853 var->yres = par->yres;
854 var->xres_virtual = par->xres_vir;
855 var->yres_virtual = par->yres_vir;
856 var->xoffset = 0;
857 var->yoffset = 0;
859 var->bits_per_pixel = par->bpp;
860 var->grayscale = 0;
862 var->red = par->red;
863 var->green = par->green;
864 var->blue = par->blue;
865 var->transp = par->transp;
867 var->nonstd = 0;
868 var->activate = 0;
870 var->height = -1;
871 var->width = -1;
873 var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
875 var->pixclock = par->pixclock;
877 var->sync = 0; /* ??? */
878 var->left_margin = par->left_margin;
879 var->right_margin = par->right_margin;
880 var->upper_margin = par->upper_margin;
881 var->lower_margin = par->lower_margin;
882 var->hsync_len = par->hsync_len;
883 var->vsync_len = par->vsync_len;
885 var->vmode = par->vmode;
886 return 0;
891 * Set a single color register. Return != 0 for invalid regno.
894 static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
895 unsigned int green, unsigned int blue,
896 unsigned int transp, struct fb_info *info)
898 struct retz3_fb_info *zinfo = retz3info(info);
899 volatile unsigned char *regs = zinfo->regs;
901 /* We'll get to this */
903 if (regno > 255)
904 return 1;
906 red >>= 10;
907 green >>= 10;
908 blue >>= 10;
910 zinfo->color_table[regno][0] = red;
911 zinfo->color_table[regno][1] = green;
912 zinfo->color_table[regno][2] = blue;
914 reg_w(regs, VDAC_ADDRESS_W, regno);
915 reg_w(regs, VDAC_DATA, red);
916 reg_w(regs, VDAC_DATA, green);
917 reg_w(regs, VDAC_DATA, blue);
919 return 0;
924 * Read a single color register and split it into
925 * colors/transparent. Return != 0 for invalid regno.
928 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
929 unsigned int *green, unsigned int *blue,
930 unsigned int *transp, struct fb_info *info)
932 struct retz3_fb_info *zinfo = retz3info(info);
933 int t;
935 if (regno > 255)
936 return 1;
937 t = zinfo->color_table[regno][0];
938 *red = (t<<10) | (t<<4) | (t>>2);
939 t = zinfo->color_table[regno][1];
940 *green = (t<<10) | (t<<4) | (t>>2);
941 t = zinfo->color_table[regno][2];
942 *blue = (t<<10) | (t<<4) | (t>>2);
943 *transp = 0;
944 return 0;
948 static inline void retz3_busy(struct display *p)
950 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
951 volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
952 unsigned char blt_status;
954 if (zinfo->blitbusy) {
956 blt_status = *((acm) + (ACM_START_STATUS + 2));
957 }while ((blt_status & 1) == 0);
958 zinfo->blitbusy = 0;
963 static void retz3_bitblt (struct display *p,
964 unsigned short srcx, unsigned short srcy,
965 unsigned short destx, unsigned short desty,
966 unsigned short width, unsigned short height,
967 unsigned short cmd, unsigned short mask)
969 struct fb_var_screeninfo *var = &p->var;
970 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
971 volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
972 unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
974 unsigned short mod;
975 unsigned long tmp;
976 unsigned long pat, src, dst;
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 retz3_busy(p);
988 i = 0;
990 *pattern++ = tmp;
991 }while(i++ < bpp/4);
993 tmp = cmd << 8;
994 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
996 mod = 0xc0c2;
998 pat = 8 * PAT_MEM_OFF;
999 dst = bpp * (destx + desty * xres_virtual);
1002 * Source is not set for clear.
1004 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
1005 src = bpp * (srcx + srcy * xres_virtual);
1007 if (destx > srcx) {
1008 mod &= ~0x8000;
1009 src += bpp * (width - 1);
1010 dst += bpp * (width - 1);
1011 pat += bpp * 2;
1013 if (desty > srcy) {
1014 mod &= ~0x4000;
1015 src += bpp * (height - 1) * xres_virtual;
1016 dst += bpp * (height - 1) * xres_virtual;
1017 pat += bpp * 4;
1020 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
1023 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
1025 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
1027 tmp = mod << 16;
1028 *(acm + ACM_CONTROL/4) = tmp;
1030 tmp = width | (height << 16);
1032 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
1034 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
1035 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
1036 zinfo->blitbusy = 1;
1039 #if 0
1041 * Move cursor to x, y
1043 static void retz3_MoveCursor (unsigned short x, unsigned short y)
1045 /* Guess we gotta deal with the cursor at some point */
1047 #endif
1051 * Fill the hardware's `par' structure.
1054 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
1056 struct retz3_fb_info *zinfo = retz3info(info);
1058 if (zinfo->current_par_valid)
1059 *par = zinfo->current_par;
1060 else
1061 retz3_decode_var(&retz3fb_default, par);
1065 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
1067 struct retz3_fb_info *zinfo = retz3info(info);
1069 zinfo->current_par = *par;
1070 zinfo->current_par_valid = 1;
1074 static int do_fb_set_var(struct fb_info *info,
1075 struct fb_var_screeninfo *var, int isactive)
1077 int err, activate;
1078 struct retz3fb_par par;
1079 struct retz3_fb_info *zinfo = retz3info(info);
1081 if ((err = retz3_decode_var(var, &par)))
1082 return err;
1083 activate = var->activate;
1085 /* XXX ... what to do about isactive ? */
1087 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
1088 retz3fb_set_par(info, &par);
1089 retz3_encode_var(var, &par);
1090 var->activate = activate;
1092 retz3_set_video(info, var, &zinfo->current_par);
1094 return 0;
1098 * Get the Fixed Part of the Display
1101 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
1102 struct fb_info *info)
1104 struct retz3fb_par par;
1105 int error = 0;
1107 if (con == -1)
1108 retz3fb_get_par(info, &par);
1109 else
1110 error = retz3_decode_var(&fb_display[con].var, &par);
1111 return(error ? error : retz3_encode_fix(info, fix, &par));
1116 * Get the User Defined Part of the Display
1119 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
1120 struct fb_info *info)
1122 struct retz3fb_par par;
1123 int error = 0;
1125 if (con == -1) {
1126 retz3fb_get_par(info, &par);
1127 error = retz3_encode_var(var, &par);
1128 } else
1129 *var = fb_display[con].var;
1130 return error;
1134 static void retz3fb_set_disp(int con, struct fb_info *info)
1136 struct fb_fix_screeninfo fix;
1137 struct display *display;
1138 struct retz3_fb_info *zinfo = retz3info(info);
1140 if (con >= 0)
1141 display = &fb_display[con];
1142 else
1143 display = &zinfo->disp; /* used during initialization */
1145 retz3fb_get_fix(&fix, con, info);
1147 if (con == -1)
1148 con = 0;
1150 display->visual = fix.visual;
1151 display->type = fix.type;
1152 display->type_aux = fix.type_aux;
1153 display->ypanstep = fix.ypanstep;
1154 display->ywrapstep = fix.ywrapstep;
1155 display->can_soft_blank = 1;
1156 display->inverse = z3fb_inverse;
1159 * This seems to be about 20% faster.
1161 display->scrollmode = SCROLL_YREDRAW;
1163 switch (display->var.bits_per_pixel) {
1164 #ifdef FBCON_HAS_CFB8
1165 case 8:
1166 if (display->var.accel_flags & FB_ACCELF_TEXT) {
1167 display->dispsw = &fbcon_retz3_8;
1168 retz3_set_video(info, &display->var, &zinfo->current_par);
1169 } else
1170 display->dispsw = &fbcon_cfb8;
1171 break;
1172 #endif
1173 #ifdef FBCON_HAS_CFB16
1174 case 16:
1175 display->dispsw = &fbcon_cfb16;
1176 break;
1177 #endif
1178 default:
1179 display->dispsw = &fbcon_dummy;
1180 break;
1186 * Set the User Defined Part of the Display
1189 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
1190 struct fb_info *info)
1192 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
1193 struct display *display;
1194 struct retz3_fb_info *zinfo = retz3info(info);
1196 if (con >= 0)
1197 display = &fb_display[con];
1198 else
1199 display = &zinfo->disp; /* used during initialization */
1201 if ((err = do_fb_set_var(info, var, con == info->currcon)))
1202 return err;
1203 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1204 oldxres = display->var.xres;
1205 oldyres = display->var.yres;
1206 oldvxres = display->var.xres_virtual;
1207 oldvyres = display->var.yres_virtual;
1208 oldbpp = display->var.bits_per_pixel;
1209 oldaccel = display->var.accel_flags;
1210 display->var = *var;
1212 if (oldxres != var->xres || oldyres != var->yres ||
1213 oldvxres != var->xres_virtual ||
1214 oldvyres != var->yres_virtual ||
1215 oldbpp != var->bits_per_pixel ||
1216 oldaccel != var->accel_flags) {
1218 struct fb_fix_screeninfo fix;
1219 retz3fb_get_fix(&fix, con, info);
1221 display->visual = fix.visual;
1222 display->type = fix.type;
1223 display->type_aux = fix.type_aux;
1224 display->ypanstep = fix.ypanstep;
1225 display->ywrapstep = fix.ywrapstep;
1226 display->line_length = fix.line_length;
1227 display->can_soft_blank = 1;
1228 display->inverse = z3fb_inverse;
1229 switch (display->var.bits_per_pixel) {
1230 #ifdef FBCON_HAS_CFB8
1231 case 8:
1232 if (var->accel_flags & FB_ACCELF_TEXT) {
1233 display->dispsw = &fbcon_retz3_8;
1234 } else
1235 display->dispsw = &fbcon_cfb8;
1236 break;
1237 #endif
1238 #ifdef FBCON_HAS_CFB16
1239 case 16:
1240 display->dispsw = &fbcon_cfb16;
1241 break;
1242 #endif
1243 default:
1244 display->dispsw = &fbcon_dummy;
1245 break;
1248 * We still need to find a way to tell the X
1249 * server that the video mem has been fiddled with
1250 * so it redraws the entire screen when switching
1251 * between X and a text console.
1253 retz3_set_video(info, var, &zinfo->current_par);
1255 if (info->changevar)
1256 (*info->changevar)(con);
1259 if (oldbpp != var->bits_per_pixel) {
1260 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1261 return err;
1262 do_install_cmap(con, info);
1265 return 0;
1270 * Get the Colormap
1273 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1274 struct fb_info *info)
1276 if (con == info->currcon) /* current console? */
1277 return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
1278 else if (fb_display[con].cmap.len) /* non default colormap? */
1279 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1280 else
1281 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1282 cmap, kspc ? 0 : 2);
1283 return 0;
1287 * Blank the display.
1290 static int retz3fb_blank(int blank, struct fb_info *info)
1292 struct retz3_fb_info *zinfo = retz3info(info);
1293 volatile unsigned char *regs = retz3info(info)->regs;
1294 short i;
1296 if (blank)
1297 for (i = 0; i < 256; i++){
1298 reg_w(regs, VDAC_ADDRESS_W, i);
1299 reg_w(regs, VDAC_DATA, 0);
1300 reg_w(regs, VDAC_DATA, 0);
1301 reg_w(regs, VDAC_DATA, 0);
1303 else
1304 for (i = 0; i < 256; i++){
1305 reg_w(regs, VDAC_ADDRESS_W, i);
1306 reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
1307 reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
1308 reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
1310 return 0;
1313 static struct fb_ops retz3fb_ops = {
1314 .owner = THIS_MODULE,
1315 .fb_get_fix = retz3fb_get_fix,
1316 .fb_get_var = retz3fb_get_var,
1317 .fb_set_var = retz3fb_set_var,
1318 .fb_get_cmap = retz3fb_get_cmap,
1319 .fb_set_cmap = gen_set_cmap,
1320 .fb_setcolreg = retz3fb_setcolreg,
1321 .fb_blank = retz3fb_blank,
1324 int __init retz3fb_setup(char *options)
1326 char *this_opt;
1328 if (!options || !*options)
1329 return 0;
1331 while ((this_opt = strsep(&options, ",")) != NULL) {
1332 if (!*this_opt)
1333 continue;
1334 if (!strcmp(this_opt, "inverse")) {
1335 z3fb_inverse = 1;
1336 fb_invert_cmaps();
1337 } else if (!strncmp(this_opt, "font:", 5)) {
1338 strlcpy(fontname, this_opt+5, sizeof(fontname));
1339 } else
1340 z3fb_mode = get_video_mode(this_opt);
1342 return 0;
1347 * Initialization
1350 int __init retz3fb_init(void)
1352 unsigned long board_addr, board_size;
1353 struct zorro_dev *z = NULL;
1354 volatile unsigned char *regs;
1355 struct retz3fb_par par;
1356 struct retz3_fb_info *zinfo;
1357 struct fb_info *fb_info;
1358 short i;
1359 int res = -ENXIO;
1361 while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) {
1362 board_addr = z->resource.start;
1363 board_size = z->resource.end-z->resource.start+1;
1364 if (!request_mem_region(board_addr, 0x0c00000,
1365 "ncr77c32blt")) {
1366 continue;
1367 if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
1368 0x00400000, "RAM"))
1369 release_mem_region(board_addr, 0x00c00000);
1370 continue;
1372 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
1373 GFP_KERNEL)))
1374 return -ENOMEM;
1375 memset(zinfo, 0, sizeof(struct retz3_fb_info));
1377 zinfo->base = ioremap(board_addr, board_size);
1378 zinfo->regs = zinfo->base;
1379 zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
1380 /* Get memory size - for now we asume it's a 4MB board */
1381 zinfo->fbsize = 0x00400000; /* 4 MB */
1382 zinfo->physregs = board_addr;
1383 zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
1385 fb_info = fbinfo(zinfo);
1387 for (i = 0; i < 256; i++){
1388 for (i = 0; i < 256; i++){
1389 zinfo->color_table[i][0] = i;
1390 zinfo->color_table[i][1] = i;
1391 zinfo->color_table[i][2] = i;
1395 regs = zinfo->regs;
1396 /* Disable hardware cursor */
1397 seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
1399 retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
1400 retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info);
1402 strcpy(fb_info->modename, retz3fb_name);
1403 fb_info->changevar = NULL;
1404 fb_info->fbops = &retz3fb_ops;
1405 fb_info->screen_base = zinfo->fbmem;
1406 fb_info->disp = &zinfo->disp;
1407 fb_info->currcon = -1;
1408 fb_info->switch_con = &z3fb_switch;
1409 fb_info->updatevar = &z3fb_updatevar;
1410 fb_info->flags = FBINFO_FLAG_DEFAULT;
1411 strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname));
1413 if (z3fb_mode == -1)
1414 retz3fb_default = retz3fb_predefined[0].var;
1416 retz3_decode_var(&retz3fb_default, &par);
1417 retz3_encode_var(&retz3fb_default, &par);
1419 do_fb_set_var(fb_info, &retz3fb_default, 0);
1420 retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
1422 retz3fb_set_disp(-1, fb_info);
1424 do_install_cmap(0, fb_info);
1426 if (register_framebuffer(fb_info) < 0) {
1427 iounmap(zinfo->base);
1428 return -EINVAL;
1431 printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
1432 "video memory\n", fb_info->node,
1433 fb_info->modename, zinfo->fbsize>>10);
1435 /* FIXME: This driver cannot be unloaded yet */
1436 res = 0;
1438 return res;
1442 static int z3fb_switch(int con, struct fb_info *info)
1444 /* Do we have to save the colormap? */
1445 if (fb_display[info->currcon].cmap.len)
1446 fb_get_cmap(&fb_display[info->currcon].cmap, 1,
1447 retz3_getcolreg, info);
1449 do_fb_set_var(info, &fb_display[con].var, 1);
1450 info->currcon = con;
1451 /* Install new colormap */
1452 do_install_cmap(con, info);
1453 return 0;
1458 * Update the `var' structure (called by fbcon.c)
1460 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1461 * Since it's called by a kernel driver, no range checking is done.
1464 static int z3fb_updatevar(int con, struct fb_info *info)
1466 return 0;
1470 * Get a Video Mode
1473 static int __init get_video_mode(const char *name)
1475 short i;
1477 for (i = 0; i < NUM_TOTAL_MODES; i++)
1478 if (!strcmp(name, retz3fb_predefined[i].name)){
1479 retz3fb_default = retz3fb_predefined[i].var;
1480 return i;
1482 return -1;
1486 #ifdef MODULE
1487 MODULE_LICENSE("GPL");
1489 int init_module(void)
1491 return retz3fb_init();
1493 #endif
1497 * Text console acceleration
1500 #ifdef FBCON_HAS_CFB8
1501 static void retz3_8_bmove(struct display *p, int sy, int sx,
1502 int dy, int dx, int height, int width)
1504 int fontwidth = fontwidth(p);
1506 sx *= fontwidth;
1507 dx *= fontwidth;
1508 width *= fontwidth;
1510 retz3_bitblt(p,
1511 (unsigned short)sx,
1512 (unsigned short)(sy*fontheight(p)),
1513 (unsigned short)dx,
1514 (unsigned short)(dy*fontheight(p)),
1515 (unsigned short)width,
1516 (unsigned short)(height*fontheight(p)),
1517 Z3BLTcopy,
1518 0xffff);
1521 static void retz3_8_clear(struct vc_data *conp, struct display *p,
1522 int sy, int sx, int height, int width)
1524 unsigned short col;
1525 int fontwidth = fontwidth(p);
1527 sx *= fontwidth;
1528 width *= fontwidth;
1530 col = attr_bgcol_ec(p, conp);
1531 col &= 0xff;
1532 col |= (col << 8);
1534 retz3_bitblt(p,
1535 (unsigned short)sx,
1536 (unsigned short)(sy*fontheight(p)),
1537 (unsigned short)sx,
1538 (unsigned short)(sy*fontheight(p)),
1539 (unsigned short)width,
1540 (unsigned short)(height*fontheight(p)),
1541 Z3BLTset,
1542 col);
1546 static void retz3_putc(struct vc_data *conp, struct display *p, int c,
1547 int yy, int xx)
1549 retz3_busy(p);
1550 fbcon_cfb8_putc(conp, p, c, yy, xx);
1554 static void retz3_putcs(struct vc_data *conp, struct display *p,
1555 const unsigned short *s, int count,
1556 int yy, int xx)
1558 retz3_busy(p);
1559 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1563 static void retz3_revc(struct display *p, int xx, int yy)
1565 retz3_busy(p);
1566 fbcon_cfb8_revc(p, xx, yy);
1570 static void retz3_clear_margins(struct vc_data* conp, struct display* p,
1571 int bottom_only)
1573 retz3_busy(p);
1574 fbcon_cfb8_clear_margins(conp, p, bottom_only);
1578 static struct display_switch fbcon_retz3_8 = {
1579 .setup = fbcon_cfb8_setup,
1580 .bmove = retz3_8_bmove,
1581 .clear = retz3_8_clear,
1582 .putc = retz3_putc,
1583 .putcs = retz3_putcs,
1584 .revc = retz3_revc,
1585 .clear_margins = retz3_clear_margins,
1586 .fontwidthmask = FONTWIDTH(8)
1588 #endif