Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / video / retz3fb.c
blob5e2c64f622cb2b9869f726e5dbf495506e88cc8c
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/slab.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 struct retz3fb_par {
60 int xres;
61 int yres;
62 int xres_vir;
63 int yres_vir;
64 int xoffset;
65 int yoffset;
66 int bpp;
68 struct fb_bitfield red;
69 struct fb_bitfield green;
70 struct fb_bitfield blue;
71 struct fb_bitfield transp;
73 int pixclock;
74 int left_margin; /* time from sync to picture */
75 int right_margin; /* time from picture to sync */
76 int upper_margin; /* time from sync to picture */
77 int lower_margin;
78 int hsync_len; /* length of horizontal sync */
79 int vsync_len; /* length of vertical sync */
80 int vmode;
82 int accel;
85 struct display_data {
86 long h_total; /* Horizontal Total */
87 long h_sstart; /* Horizontal Sync Start */
88 long h_sstop; /* Horizontal Sync Stop */
89 long h_bstart; /* Horizontal Blank Start */
90 long h_bstop; /* Horizontal Blank Stop */
91 long h_dispend; /* Horizontal Display End */
92 long v_total; /* Vertical Total */
93 long v_sstart; /* Vertical Sync Start */
94 long v_sstop; /* Vertical Sync Stop */
95 long v_bstart; /* Vertical Blank Start */
96 long v_bstop; /* Vertical Blank Stop */
97 long v_dispend; /* Horizontal Display End */
100 struct retz3_fb_info {
101 struct fb_info info;
102 unsigned char *base;
103 unsigned char *fbmem;
104 unsigned long fbsize;
105 volatile unsigned char *regs;
106 unsigned long physfbmem;
107 unsigned long physregs;
108 int current_par_valid; /* set to 0 by memset */
109 int blitbusy;
110 struct display disp;
111 struct retz3fb_par current_par;
112 unsigned char color_table [256][3];
116 static char fontname[40] __initdata = { 0 };
118 #define retz3info(info) ((struct retz3_fb_info *)(info))
119 #define fbinfo(info) ((struct fb_info *)(info))
123 * Frame Buffer Name
126 static char retz3fb_name[16] = "RetinaZ3";
130 * A small info on how to convert XFree86 timing values into fb
131 * timings - by Frank Neumann:
133 An XFree86 mode line consists of the following fields:
134 "800x600" 50 800 856 976 1040 600 637 643 666
135 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
137 The fields in the fb_var_screeninfo structure are:
138 unsigned long pixclock; * pixel clock in ps (pico seconds) *
139 unsigned long left_margin; * time from sync to picture *
140 unsigned long right_margin; * time from picture to sync *
141 unsigned long upper_margin; * time from sync to picture *
142 unsigned long lower_margin;
143 unsigned long hsync_len; * length of horizontal sync *
144 unsigned long vsync_len; * length of vertical sync *
146 1) Pixelclock:
147 xfree: in MHz
148 fb: In Picoseconds (ps)
150 pixclock = 1000000 / DCF
152 2) horizontal timings:
153 left_margin = HFL - SH2
154 right_margin = SH1 - HR
155 hsync_len = SH2 - SH1
157 3) vertical timings:
158 upper_margin = VFL - SV2
159 lower_margin = SV1 - VR
160 vsync_len = SV2 - SV1
162 Good examples for VESA timings can be found in the XFree86 source tree,
163 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
167 * Predefined Video Modes
170 static struct {
171 const char *name;
172 struct fb_var_screeninfo var;
173 } retz3fb_predefined[] __initdata = {
175 * NB: it is very important to adjust the pixel-clock to the color-depth.
179 "640x480", { /* 640x480, 8 bpp */
180 640, 480, 640, 480, 0, 0, 8, 0,
181 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
182 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
183 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
187 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
188 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
191 "800x600", { /* 800x600, 8 bpp */
192 800, 600, 800, 600, 0, 0, 8, 0,
193 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
194 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2,
195 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
199 "800x600-60", { /* 800x600, 8 bpp */
200 800, 600, 800, 600, 0, 0, 8, 0,
201 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
202 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
203 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
207 "800x600-70", { /* 800x600, 8 bpp */
208 800, 600, 800, 600, 0, 0, 8, 0,
209 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
210 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12,
211 FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
215 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
216 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
219 "1024x768i", { /* 1024x768, 8 bpp, interlaced */
220 1024, 768, 1024, 768, 0, 0, 8, 0,
221 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
222 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8,
223 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
227 "1024x768", {
228 1024, 768, 1024, 768, 0, 0, 8, 0,
229 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
230 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
231 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
235 "640x480-16", { /* 640x480, 16 bpp */
236 640, 480, 640, 480, 0, 0, 16, 0,
237 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
238 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
239 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
243 "640x480-24", { /* 640x480, 24 bpp */
244 640, 480, 640, 480, 0, 0, 24, 0,
245 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
246 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
247 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
253 #define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined)
255 static struct fb_var_screeninfo retz3fb_default;
257 static int z3fb_inverse = 0;
258 static int z3fb_mode __initdata = 0;
262 * Interface used by the world
265 int retz3fb_setup(char *options);
267 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
268 struct fb_info *info);
269 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
270 struct fb_info *info);
271 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
272 struct fb_info *info);
273 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
274 struct fb_info *info);
275 static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
276 unsigned int green, unsigned int blue,
277 unsigned int transp, struct fb_info *info);
278 static int retz3fb_blank(int blank, struct fb_info *info);
282 * Interface to the low level console driver
285 int retz3fb_init(void);
286 static int z3fb_switch(int con, struct fb_info *info);
287 static int z3fb_updatevar(int con, struct fb_info *info);
291 * Text console acceleration
294 #ifdef FBCON_HAS_CFB8
295 static struct display_switch fbcon_retz3_8;
296 #endif
300 * Accelerated Functions used by the low level console driver
303 static void retz3_bitblt(struct display *p,
304 unsigned short curx, unsigned short cury, unsigned
305 short destx, unsigned short desty, unsigned short
306 width, unsigned short height, unsigned short cmd,
307 unsigned short mask);
310 * Hardware Specific Routines
313 static int retz3_encode_fix(struct fb_info *info,
314 struct fb_fix_screeninfo *fix,
315 struct retz3fb_par *par);
316 static int retz3_decode_var(struct fb_var_screeninfo *var,
317 struct retz3fb_par *par);
318 static int retz3_encode_var(struct fb_var_screeninfo *var,
319 struct retz3fb_par *par);
320 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
321 unsigned int *green, unsigned int *blue,
322 unsigned int *transp, struct fb_info *info);
325 * Internal routines
328 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
329 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
330 static int do_fb_set_var(struct fb_info *info,
331 struct fb_var_screeninfo *var, int isactive);
332 static void retz3fb_set_disp(int con, struct fb_info *info);
333 static int get_video_mode(const char *name);
336 /* -------------------- Hardware specific routines ------------------------- */
338 static unsigned short find_fq(unsigned int freq)
340 unsigned long f;
341 long tmp;
342 long prev = 0x7fffffff;
343 long n2, n1 = 3;
344 unsigned long m;
345 unsigned short res = 0;
347 if (freq <= 31250000)
348 n2 = 3;
349 else if (freq <= 62500000)
350 n2 = 2;
351 else if (freq <= 125000000)
352 n2 = 1;
353 else if (freq <= 250000000)
354 n2 = 0;
355 else
356 return 0;
359 do {
360 f = freq >> (10 - n2);
362 m = (f * n1) / (14318180/1024);
364 if (m > 129)
365 break;
367 tmp = (((m * 14318180) >> n2) / n1) - freq;
368 if (tmp < 0)
369 tmp = -tmp;
371 if (tmp < prev) {
372 prev = tmp;
373 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
376 } while ( (++n1) <= 21);
378 return res;
382 static int retz3_set_video(struct fb_info *info,
383 struct fb_var_screeninfo *var,
384 struct retz3fb_par *par)
386 volatile unsigned char *regs = retz3info(info)->regs;
387 unsigned int freq;
389 int xres, hfront, hsync, hback;
390 int yres, vfront, vsync, vback;
391 unsigned char tmp;
392 unsigned short best_freq;
393 struct display_data data;
395 short clocksel = 0; /* Apparantly this is always zero */
397 int bpp = var->bits_per_pixel;
400 * XXX
402 if (bpp == 24)
403 return 0;
405 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
406 return -EFAULT;
408 par->xoffset = 0;
409 par->yoffset = 0;
411 xres = var->xres * bpp / 4;
412 hfront = var->right_margin * bpp / 4;
413 hsync = var->hsync_len * bpp / 4;
414 hback = var->left_margin * bpp / 4;
416 if (var->vmode & FB_VMODE_DOUBLE)
418 yres = var->yres * 2;
419 vfront = var->lower_margin * 2;
420 vsync = var->vsync_len * 2;
421 vback = var->upper_margin * 2;
423 else if (var->vmode & FB_VMODE_INTERLACED)
425 yres = (var->yres + 1) / 2;
426 vfront = (var->lower_margin + 1) / 2;
427 vsync = (var->vsync_len + 1) / 2;
428 vback = (var->upper_margin + 1) / 2;
430 else
432 yres = var->yres; /* -1 ? */
433 vfront = var->lower_margin;
434 vsync = var->vsync_len;
435 vback = var->upper_margin;
438 data.h_total = (hback / 8) + (xres / 8)
439 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
440 data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
441 data.h_bstart = xres / 8 - 1 /* + 1 */;
443 data.h_bstop = data.h_total+1 + 2 + 1;
444 data.h_sstart = (xres / 8) + (hfront / 8) + 1;
445 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
447 data.v_total = yres + vfront + vsync + vback - 1;
449 data.v_dispend = yres - 1;
450 data.v_bstart = yres - 1;
452 data.v_bstop = data.v_total;
453 data.v_sstart = yres + vfront - 1 - 2;
454 data.v_sstop = yres + vfront + vsync - 1;
456 #if 0 /* testing */
458 printk("HBS: %i\n", data.h_bstart);
459 printk("HSS: %i\n", data.h_sstart);
460 printk("HSE: %i\n", data.h_sstop);
461 printk("HBE: %i\n", data.h_bstop);
462 printk("HT: %i\n", data.h_total);
464 printk("hsync: %i\n", hsync);
465 printk("hfront: %i\n", hfront);
466 printk("hback: %i\n", hback);
468 printk("VBS: %i\n", data.v_bstart);
469 printk("VSS: %i\n", data.v_sstart);
470 printk("VSE: %i\n", data.v_sstop);
471 printk("VBE: %i\n", data.v_bstop);
472 printk("VT: %i\n", data.v_total);
474 printk("vsync: %i\n", vsync);
475 printk("vfront: %i\n", vfront);
476 printk("vback: %i\n", vback);
477 #endif
479 if (data.v_total >= 1024)
480 printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n");
482 reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
483 reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
485 seq_w(regs, SEQ_RESET, 0x00);
486 seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */
489 * CLOCKING_MODE bits:
490 * 2: This one is only set for certain text-modes, wonder if
491 * it may be for EGA-lines? (it was referred to as CLKDIV2)
492 * (The CL drivers sets it to 0x21 with the comment:
493 * FullBandwidth (video off) and 8/9 dot clock)
495 seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
497 seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
498 seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
499 seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
500 seq_w(regs, SEQ_RESET, 0x01);
501 seq_w(regs, SEQ_RESET, 0x03);
503 seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
505 seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
506 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
507 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
508 seq_w(regs, SEQ_LINEAR_0, 0x4a);
509 seq_w(regs, SEQ_LINEAR_1, 0x00);
511 seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
512 seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
513 seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
516 * The lower 4 bits (0-3) are used to set the font-width for
517 * text-mode - DON'T try to set this for gfx-mode.
519 seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
520 seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
523 * Extended Pixel Control:
524 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
525 * bit 1: (Packed/Nibble Pixel Format ?)
526 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
528 seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
530 seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
531 seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
532 seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
533 seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
534 seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
535 seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
536 seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
537 seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
538 seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
539 seq_w(regs, SEQ_CRC_CONTROL, 0x00);
540 seq_w(regs, SEQ_PERF_SELECT, 0x10);
541 seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
542 seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
543 seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
544 seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
547 /* unlock register CRT0..CRT7 */
548 crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
550 /* Zuerst zu schreibende Werte nur per printk ausgeben */
551 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
552 crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
554 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
555 crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
557 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
558 crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
560 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
561 crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
563 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
564 crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
566 tmp = (data.h_sstop & 0x1f);
567 if (data.h_bstop & 0x20)
568 tmp |= 0x80;
569 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
570 crt_w(regs, CRT_END_HOR_RETR, tmp);
572 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
573 crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
575 tmp = 0x10; /* LineCompare bit #9 */
576 if (data.v_total & 256)
577 tmp |= 0x01;
578 if (data.v_dispend & 256)
579 tmp |= 0x02;
580 if (data.v_sstart & 256)
581 tmp |= 0x04;
582 if (data.v_bstart & 256)
583 tmp |= 0x08;
584 if (data.v_total & 512)
585 tmp |= 0x20;
586 if (data.v_dispend & 512)
587 tmp |= 0x40;
588 if (data.v_sstart & 512)
589 tmp |= 0x80;
590 DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
591 crt_w(regs, CRT_OVERFLOW, tmp);
593 crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
595 tmp = 0x40; /* LineCompare bit #8 */
596 if (data.v_bstart & 512)
597 tmp |= 0x20;
598 if (var->vmode & FB_VMODE_DOUBLE)
599 tmp |= 0x80;
600 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
601 crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
603 crt_w(regs, CRT_CURSOR_START, 0x00);
604 crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
606 crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
607 crt_w(regs, CRT_START_ADDR_LOW, 0x00);
609 crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
610 crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
612 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
613 crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
615 #if 1
616 /* 5 refresh cycles per scanline */
617 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
618 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
619 #else
620 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
621 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
622 #endif
623 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
624 crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
626 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
627 crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
629 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
630 crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
632 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
633 crt_w(regs, CRT_MODE_CONTROL, 0xe3);
635 DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
636 crt_w(regs, CRT_LINE_COMPARE, 0xff);
638 tmp = (var->xres_virtual / 8) * (bpp / 8);
639 crt_w(regs, CRT_OFFSET, tmp);
641 crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
643 tmp = 0x20; /* Enable extended end bits */
644 if (data.h_total & 0x100)
645 tmp |= 0x01;
646 if ((data.h_dispend) & 0x100)
647 tmp |= 0x02;
648 if (data.h_bstart & 0x100)
649 tmp |= 0x04;
650 if (data.h_sstart & 0x100)
651 tmp |= 0x08;
652 if (var->vmode & FB_VMODE_INTERLACED)
653 tmp |= 0x10;
654 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
655 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
657 tmp = 0x00;
658 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
659 tmp |= 0x10;
660 crt_w(regs, CRT_EXT_START_ADDR, tmp);
662 tmp = 0x00;
663 if (data.h_total & 0x200)
664 tmp |= 0x01;
665 if ((data.h_dispend) & 0x200)
666 tmp |= 0x02;
667 if (data.h_bstart & 0x200)
668 tmp |= 0x04;
669 if (data.h_sstart & 0x200)
670 tmp |= 0x08;
671 tmp |= ((data.h_bstop & 0xc0) >> 2);
672 tmp |= ((data.h_sstop & 0x60) << 1);
673 crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
674 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
676 tmp = 0x10; /* Line compare bit 10 */
677 if (data.v_total & 0x400)
678 tmp |= 0x01;
679 if ((data.v_dispend) & 0x400)
680 tmp |= 0x02;
681 if (data.v_bstart & 0x400)
682 tmp |= 0x04;
683 if (data.v_sstart & 0x400)
684 tmp |= 0x08;
685 tmp |= ((data.v_bstop & 0x300) >> 3);
686 if (data.v_sstop & 0x10)
687 tmp |= 0x80;
688 crt_w(regs, CRT_EXT_VER_TIMING, tmp);
689 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
691 crt_w(regs, CRT_MONITOR_POWER, 0x00);
694 * Convert from ps to Hz.
696 freq = 2000000000 / var->pixclock;
697 freq = freq * 500;
699 best_freq = find_fq(freq);
700 pll_w(regs, 0x02, best_freq);
701 best_freq = find_fq(61000000);
702 pll_w(regs, 0x0a, best_freq);
703 pll_w(regs, 0x0e, 0x22);
705 gfx_w(regs, GFX_SET_RESET, 0x00);
706 gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
707 gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
708 gfx_w(regs, GFX_DATA_ROTATE, 0x00);
709 gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
710 gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
711 gfx_w(regs, GFX_MISC, 0x05);
712 gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
713 gfx_w(regs, GFX_BITMASK, 0xff);
715 reg_r(regs, ACT_ADDRESS_RESET);
716 attr_w(regs, ACT_PALETTE0 , 0x00);
717 attr_w(regs, ACT_PALETTE1 , 0x01);
718 attr_w(regs, ACT_PALETTE2 , 0x02);
719 attr_w(regs, ACT_PALETTE3 , 0x03);
720 attr_w(regs, ACT_PALETTE4 , 0x04);
721 attr_w(regs, ACT_PALETTE5 , 0x05);
722 attr_w(regs, ACT_PALETTE6 , 0x06);
723 attr_w(regs, ACT_PALETTE7 , 0x07);
724 attr_w(regs, ACT_PALETTE8 , 0x08);
725 attr_w(regs, ACT_PALETTE9 , 0x09);
726 attr_w(regs, ACT_PALETTE10, 0x0a);
727 attr_w(regs, ACT_PALETTE11, 0x0b);
728 attr_w(regs, ACT_PALETTE12, 0x0c);
729 attr_w(regs, ACT_PALETTE13, 0x0d);
730 attr_w(regs, ACT_PALETTE14, 0x0e);
731 attr_w(regs, ACT_PALETTE15, 0x0f);
732 reg_r(regs, ACT_ADDRESS_RESET);
734 attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
736 attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
737 attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
738 attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
739 attr_w(regs, ACT_COLOR_SELECT, 0x00);
741 reg_r(regs, ACT_ADDRESS_RESET);
742 reg_w(regs, ACT_DATA, 0x20);
744 reg_w(regs, VDAC_MASK, 0xff);
747 * Extended palette addressing ???
749 switch (bpp){
750 case 8:
751 reg_w(regs, 0x83c6, 0x00);
752 break;
753 case 16:
754 reg_w(regs, 0x83c6, 0x60);
755 break;
756 case 24:
757 reg_w(regs, 0x83c6, 0xe0);
758 break;
759 default:
760 printk(KERN_INFO "Illegal color-depth: %i\n", bpp);
763 reg_w(regs, VDAC_ADDRESS, 0x00);
765 seq_w(regs, SEQ_MAP_MASK, 0x0f );
767 return 0;
772 * This function should fill in the `fix' structure based on the
773 * values in the `par' structure.
776 static int retz3_encode_fix(struct fb_info *info,
777 struct fb_fix_screeninfo *fix,
778 struct retz3fb_par *par)
780 struct retz3_fb_info *zinfo = retz3info(info);
782 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
783 strcpy(fix->id, retz3fb_name);
784 fix->smem_start = zinfo->physfbmem;
785 fix->smem_len = zinfo->fbsize;
786 fix->mmio_start = zinfo->physregs;
787 fix->mmio_len = 0x00c00000;
789 fix->type = FB_TYPE_PACKED_PIXELS;
790 fix->type_aux = 0;
791 if (par->bpp == 8)
792 fix->visual = FB_VISUAL_PSEUDOCOLOR;
793 else
794 fix->visual = FB_VISUAL_TRUECOLOR;
796 fix->xpanstep = 0;
797 fix->ypanstep = 0;
798 fix->ywrapstep = 0;
799 fix->line_length = 0;
801 fix->accel = FB_ACCEL_NCR_77C32BLT;
803 return 0;
808 * Get the video params out of `var'. If a value doesn't fit, round
809 * it up, if it's too big, return -EINVAL.
812 static int retz3_decode_var(struct fb_var_screeninfo *var,
813 struct retz3fb_par *par)
815 par->xres = var->xres;
816 par->yres = var->yres;
817 par->xres_vir = var->xres_virtual;
818 par->yres_vir = var->yres_virtual;
819 par->bpp = var->bits_per_pixel;
820 par->pixclock = var->pixclock;
821 par->vmode = var->vmode;
823 par->red = var->red;
824 par->green = var->green;
825 par->blue = var->blue;
826 par->transp = var->transp;
828 par->left_margin = var->left_margin;
829 par->right_margin = var->right_margin;
830 par->upper_margin = var->upper_margin;
831 par->lower_margin = var->lower_margin;
832 par->hsync_len = var->hsync_len;
833 par->vsync_len = var->vsync_len;
835 if (var->accel_flags & FB_ACCELF_TEXT)
836 par->accel = FB_ACCELF_TEXT;
837 else
838 par->accel = 0;
840 return 0;
845 * Fill the `var' structure based on the values in `par' and maybe
846 * other values read out of the hardware.
849 static int retz3_encode_var(struct fb_var_screeninfo *var,
850 struct retz3fb_par *par)
852 memset(var, 0, sizeof(struct fb_var_screeninfo));
853 var->xres = par->xres;
854 var->yres = par->yres;
855 var->xres_virtual = par->xres_vir;
856 var->yres_virtual = par->yres_vir;
857 var->xoffset = 0;
858 var->yoffset = 0;
860 var->bits_per_pixel = par->bpp;
861 var->grayscale = 0;
863 var->red = par->red;
864 var->green = par->green;
865 var->blue = par->blue;
866 var->transp = par->transp;
868 var->nonstd = 0;
869 var->activate = 0;
871 var->height = -1;
872 var->width = -1;
874 var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
876 var->pixclock = par->pixclock;
878 var->sync = 0; /* ??? */
879 var->left_margin = par->left_margin;
880 var->right_margin = par->right_margin;
881 var->upper_margin = par->upper_margin;
882 var->lower_margin = par->lower_margin;
883 var->hsync_len = par->hsync_len;
884 var->vsync_len = par->vsync_len;
886 var->vmode = par->vmode;
887 return 0;
892 * Set a single color register. Return != 0 for invalid regno.
895 static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
896 unsigned int green, unsigned int blue,
897 unsigned int transp, struct fb_info *info)
899 struct retz3_fb_info *zinfo = retz3info(info);
900 volatile unsigned char *regs = zinfo->regs;
902 /* We'll get to this */
904 if (regno > 255)
905 return 1;
907 red >>= 10;
908 green >>= 10;
909 blue >>= 10;
911 zinfo->color_table[regno][0] = red;
912 zinfo->color_table[regno][1] = green;
913 zinfo->color_table[regno][2] = blue;
915 reg_w(regs, VDAC_ADDRESS_W, regno);
916 reg_w(regs, VDAC_DATA, red);
917 reg_w(regs, VDAC_DATA, green);
918 reg_w(regs, VDAC_DATA, blue);
920 return 0;
925 * Read a single color register and split it into
926 * colors/transparent. Return != 0 for invalid regno.
929 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
930 unsigned int *green, unsigned int *blue,
931 unsigned int *transp, struct fb_info *info)
933 struct retz3_fb_info *zinfo = retz3info(info);
934 int t;
936 if (regno > 255)
937 return 1;
938 t = zinfo->color_table[regno][0];
939 *red = (t<<10) | (t<<4) | (t>>2);
940 t = zinfo->color_table[regno][1];
941 *green = (t<<10) | (t<<4) | (t>>2);
942 t = zinfo->color_table[regno][2];
943 *blue = (t<<10) | (t<<4) | (t>>2);
944 *transp = 0;
945 return 0;
949 static inline void retz3_busy(struct display *p)
951 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
952 volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
953 unsigned char blt_status;
955 if (zinfo->blitbusy) {
957 blt_status = *((acm) + (ACM_START_STATUS + 2));
958 }while ((blt_status & 1) == 0);
959 zinfo->blitbusy = 0;
964 static void retz3_bitblt (struct display *p,
965 unsigned short srcx, unsigned short srcy,
966 unsigned short destx, unsigned short desty,
967 unsigned short width, unsigned short height,
968 unsigned short cmd, unsigned short mask)
970 struct fb_var_screeninfo *var = &p->var;
971 struct retz3_fb_info *zinfo = retz3info(p->fb_info);
972 volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
973 unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
975 unsigned short mod;
976 unsigned long tmp;
977 unsigned long pat, src, dst;
979 int i, xres_virtual = var->xres_virtual;
980 short bpp = (var->bits_per_pixel & 0xff);
982 if (bpp < 8)
983 bpp = 8;
985 tmp = mask | (mask << 16);
987 retz3_busy(p);
989 i = 0;
991 *pattern++ = tmp;
992 }while(i++ < bpp/4);
994 tmp = cmd << 8;
995 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
997 mod = 0xc0c2;
999 pat = 8 * PAT_MEM_OFF;
1000 dst = bpp * (destx + desty * xres_virtual);
1003 * Source is not set for clear.
1005 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
1006 src = bpp * (srcx + srcy * xres_virtual);
1008 if (destx > srcx) {
1009 mod &= ~0x8000;
1010 src += bpp * (width - 1);
1011 dst += bpp * (width - 1);
1012 pat += bpp * 2;
1014 if (desty > srcy) {
1015 mod &= ~0x4000;
1016 src += bpp * (height - 1) * xres_virtual;
1017 dst += bpp * (height - 1) * xres_virtual;
1018 pat += bpp * 4;
1021 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
1024 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
1026 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
1028 tmp = mod << 16;
1029 *(acm + ACM_CONTROL/4) = tmp;
1031 tmp = width | (height << 16);
1033 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
1035 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
1036 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
1037 zinfo->blitbusy = 1;
1040 #if 0
1042 * Move cursor to x, y
1044 static void retz3_MoveCursor (unsigned short x, unsigned short y)
1046 /* Guess we gotta deal with the cursor at some point */
1048 #endif
1052 * Fill the hardware's `par' structure.
1055 static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
1057 struct retz3_fb_info *zinfo = retz3info(info);
1059 if (zinfo->current_par_valid)
1060 *par = zinfo->current_par;
1061 else
1062 retz3_decode_var(&retz3fb_default, par);
1066 static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
1068 struct retz3_fb_info *zinfo = retz3info(info);
1070 zinfo->current_par = *par;
1071 zinfo->current_par_valid = 1;
1075 static int do_fb_set_var(struct fb_info *info,
1076 struct fb_var_screeninfo *var, int isactive)
1078 int err, activate;
1079 struct retz3fb_par par;
1080 struct retz3_fb_info *zinfo = retz3info(info);
1082 if ((err = retz3_decode_var(var, &par)))
1083 return err;
1084 activate = var->activate;
1086 /* XXX ... what to do about isactive ? */
1088 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
1089 retz3fb_set_par(info, &par);
1090 retz3_encode_var(var, &par);
1091 var->activate = activate;
1093 retz3_set_video(info, var, &zinfo->current_par);
1095 return 0;
1099 * Get the Fixed Part of the Display
1102 static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
1103 struct fb_info *info)
1105 struct retz3fb_par par;
1106 int error = 0;
1108 if (con == -1)
1109 retz3fb_get_par(info, &par);
1110 else
1111 error = retz3_decode_var(&fb_display[con].var, &par);
1112 return(error ? error : retz3_encode_fix(info, fix, &par));
1117 * Get the User Defined Part of the Display
1120 static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
1121 struct fb_info *info)
1123 struct retz3fb_par par;
1124 int error = 0;
1126 if (con == -1) {
1127 retz3fb_get_par(info, &par);
1128 error = retz3_encode_var(var, &par);
1129 } else
1130 *var = fb_display[con].var;
1131 return error;
1135 static void retz3fb_set_disp(int con, struct fb_info *info)
1137 struct fb_fix_screeninfo fix;
1138 struct display *display;
1139 struct retz3_fb_info *zinfo = retz3info(info);
1141 if (con >= 0)
1142 display = &fb_display[con];
1143 else
1144 display = &zinfo->disp; /* used during initialization */
1146 retz3fb_get_fix(&fix, con, info);
1148 if (con == -1)
1149 con = 0;
1151 display->visual = fix.visual;
1152 display->type = fix.type;
1153 display->type_aux = fix.type_aux;
1154 display->ypanstep = fix.ypanstep;
1155 display->ywrapstep = fix.ywrapstep;
1156 display->can_soft_blank = 1;
1157 display->inverse = z3fb_inverse;
1160 * This seems to be about 20% faster.
1162 display->scrollmode = SCROLL_YREDRAW;
1164 switch (display->var.bits_per_pixel) {
1165 #ifdef FBCON_HAS_CFB8
1166 case 8:
1167 if (display->var.accel_flags & FB_ACCELF_TEXT) {
1168 display->dispsw = &fbcon_retz3_8;
1169 retz3_set_video(info, &display->var, &zinfo->current_par);
1170 } else
1171 display->dispsw = &fbcon_cfb8;
1172 break;
1173 #endif
1174 #ifdef FBCON_HAS_CFB16
1175 case 16:
1176 display->dispsw = &fbcon_cfb16;
1177 break;
1178 #endif
1179 default:
1180 display->dispsw = &fbcon_dummy;
1181 break;
1187 * Set the User Defined Part of the Display
1190 static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
1191 struct fb_info *info)
1193 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
1194 struct display *display;
1195 struct retz3_fb_info *zinfo = retz3info(info);
1197 if (con >= 0)
1198 display = &fb_display[con];
1199 else
1200 display = &zinfo->disp; /* used during initialization */
1202 if ((err = do_fb_set_var(info, var, con == info->currcon)))
1203 return err;
1204 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1205 oldxres = display->var.xres;
1206 oldyres = display->var.yres;
1207 oldvxres = display->var.xres_virtual;
1208 oldvyres = display->var.yres_virtual;
1209 oldbpp = display->var.bits_per_pixel;
1210 oldaccel = display->var.accel_flags;
1211 display->var = *var;
1213 if (oldxres != var->xres || oldyres != var->yres ||
1214 oldvxres != var->xres_virtual ||
1215 oldvyres != var->yres_virtual ||
1216 oldbpp != var->bits_per_pixel ||
1217 oldaccel != var->accel_flags) {
1219 struct fb_fix_screeninfo fix;
1220 retz3fb_get_fix(&fix, con, info);
1222 display->visual = fix.visual;
1223 display->type = fix.type;
1224 display->type_aux = fix.type_aux;
1225 display->ypanstep = fix.ypanstep;
1226 display->ywrapstep = fix.ywrapstep;
1227 display->line_length = fix.line_length;
1228 display->can_soft_blank = 1;
1229 display->inverse = z3fb_inverse;
1230 switch (display->var.bits_per_pixel) {
1231 #ifdef FBCON_HAS_CFB8
1232 case 8:
1233 if (var->accel_flags & FB_ACCELF_TEXT) {
1234 display->dispsw = &fbcon_retz3_8;
1235 } else
1236 display->dispsw = &fbcon_cfb8;
1237 break;
1238 #endif
1239 #ifdef FBCON_HAS_CFB16
1240 case 16:
1241 display->dispsw = &fbcon_cfb16;
1242 break;
1243 #endif
1244 default:
1245 display->dispsw = &fbcon_dummy;
1246 break;
1249 * We still need to find a way to tell the X
1250 * server that the video mem has been fiddled with
1251 * so it redraws the entire screen when switching
1252 * between X and a text console.
1254 retz3_set_video(info, var, &zinfo->current_par);
1256 if (info->changevar)
1257 (*info->changevar)(con);
1260 if (oldbpp != var->bits_per_pixel) {
1261 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1262 return err;
1263 do_install_cmap(con, info);
1266 return 0;
1271 * Get the Colormap
1274 static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1275 struct fb_info *info)
1277 if (con == info->currcon) /* current console? */
1278 return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
1279 else if (fb_display[con].cmap.len) /* non default colormap? */
1280 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1281 else
1282 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1283 cmap, kspc ? 0 : 2);
1284 return 0;
1288 * Blank the display.
1291 static int retz3fb_blank(int blank, struct fb_info *info)
1293 struct retz3_fb_info *zinfo = retz3info(info);
1294 volatile unsigned char *regs = retz3info(info)->regs;
1295 short i;
1297 if (blank)
1298 for (i = 0; i < 256; i++){
1299 reg_w(regs, VDAC_ADDRESS_W, i);
1300 reg_w(regs, VDAC_DATA, 0);
1301 reg_w(regs, VDAC_DATA, 0);
1302 reg_w(regs, VDAC_DATA, 0);
1304 else
1305 for (i = 0; i < 256; i++){
1306 reg_w(regs, VDAC_ADDRESS_W, i);
1307 reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
1308 reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
1309 reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
1311 return 0;
1314 static struct fb_ops retz3fb_ops = {
1315 .owner = THIS_MODULE,
1316 .fb_get_fix = retz3fb_get_fix,
1317 .fb_get_var = retz3fb_get_var,
1318 .fb_set_var = retz3fb_set_var,
1319 .fb_get_cmap = retz3fb_get_cmap,
1320 .fb_set_cmap = gen_set_cmap,
1321 .fb_setcolreg = retz3fb_setcolreg,
1322 .fb_blank = retz3fb_blank,
1325 int __init retz3fb_setup(char *options)
1327 char *this_opt;
1329 if (!options || !*options)
1330 return 0;
1332 while ((this_opt = strsep(&options, ",")) != NULL) {
1333 if (!*this_opt)
1334 continue;
1335 if (!strcmp(this_opt, "inverse")) {
1336 z3fb_inverse = 1;
1337 fb_invert_cmaps();
1338 } else if (!strncmp(this_opt, "font:", 5)) {
1339 strlcpy(fontname, this_opt+5, sizeof(fontname));
1340 } else
1341 z3fb_mode = get_video_mode(this_opt);
1343 return 0;
1348 * Initialization
1351 int __init retz3fb_init(void)
1353 unsigned long board_addr, board_size;
1354 struct zorro_dev *z = NULL;
1355 volatile unsigned char *regs;
1356 struct retz3fb_par par;
1357 struct retz3_fb_info *zinfo;
1358 struct fb_info *fb_info;
1359 short i;
1360 int res = -ENXIO;
1362 while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) {
1363 board_addr = z->resource.start;
1364 board_size = z->resource.end-z->resource.start+1;
1365 if (!request_mem_region(board_addr, 0x0c00000,
1366 "ncr77c32blt")) {
1367 continue;
1368 if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
1369 0x00400000, "RAM"))
1370 release_mem_region(board_addr, 0x00c00000);
1371 continue;
1373 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
1374 GFP_KERNEL)))
1375 return -ENOMEM;
1376 memset(zinfo, 0, sizeof(struct retz3_fb_info));
1378 zinfo->base = ioremap(board_addr, board_size);
1379 zinfo->regs = zinfo->base;
1380 zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
1381 /* Get memory size - for now we asume it's a 4MB board */
1382 zinfo->fbsize = 0x00400000; /* 4 MB */
1383 zinfo->physregs = board_addr;
1384 zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
1386 fb_info = fbinfo(zinfo);
1388 for (i = 0; i < 256; i++){
1389 for (i = 0; i < 256; i++){
1390 zinfo->color_table[i][0] = i;
1391 zinfo->color_table[i][1] = i;
1392 zinfo->color_table[i][2] = i;
1396 regs = zinfo->regs;
1397 /* Disable hardware cursor */
1398 seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
1400 retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
1401 retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info);
1403 strcpy(fb_info->modename, retz3fb_name);
1404 fb_info->changevar = NULL;
1405 fb_info->fbops = &retz3fb_ops;
1406 fb_info->screen_base = zinfo->fbmem;
1407 fb_info->disp = &zinfo->disp;
1408 fb_info->currcon = -1;
1409 fb_info->switch_con = &z3fb_switch;
1410 fb_info->updatevar = &z3fb_updatevar;
1411 fb_info->flags = FBINFO_FLAG_DEFAULT;
1412 strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname));
1414 if (z3fb_mode == -1)
1415 retz3fb_default = retz3fb_predefined[0].var;
1417 retz3_decode_var(&retz3fb_default, &par);
1418 retz3_encode_var(&retz3fb_default, &par);
1420 do_fb_set_var(fb_info, &retz3fb_default, 0);
1421 retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
1423 retz3fb_set_disp(-1, fb_info);
1425 do_install_cmap(0, fb_info);
1427 if (register_framebuffer(fb_info) < 0)
1428 return -EINVAL;
1430 printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
1431 "video memory\n", fb_info->node,
1432 fb_info->modename, zinfo->fbsize>>10);
1434 /* FIXME: This driver cannot be unloaded yet */
1435 res = 0;
1437 return res;
1441 static int z3fb_switch(int con, struct fb_info *info)
1443 /* Do we have to save the colormap? */
1444 if (fb_display[info->currcon].cmap.len)
1445 fb_get_cmap(&fb_display[info->currcon].cmap, 1,
1446 retz3_getcolreg, info);
1448 do_fb_set_var(info, &fb_display[con].var, 1);
1449 info->currcon = con;
1450 /* Install new colormap */
1451 do_install_cmap(con, info);
1452 return 0;
1457 * Update the `var' structure (called by fbcon.c)
1459 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1460 * Since it's called by a kernel driver, no range checking is done.
1463 static int z3fb_updatevar(int con, struct fb_info *info)
1465 return 0;
1469 * Get a Video Mode
1472 static int __init get_video_mode(const char *name)
1474 short i;
1476 for (i = 0; i < NUM_TOTAL_MODES; i++)
1477 if (!strcmp(name, retz3fb_predefined[i].name)){
1478 retz3fb_default = retz3fb_predefined[i].var;
1479 return i;
1481 return -1;
1485 #ifdef MODULE
1486 MODULE_LICENSE("GPL");
1488 int init_module(void)
1490 return retz3fb_init();
1492 #endif
1496 * Text console acceleration
1499 #ifdef FBCON_HAS_CFB8
1500 static void retz3_8_bmove(struct display *p, int sy, int sx,
1501 int dy, int dx, int height, int width)
1503 int fontwidth = fontwidth(p);
1505 sx *= fontwidth;
1506 dx *= fontwidth;
1507 width *= fontwidth;
1509 retz3_bitblt(p,
1510 (unsigned short)sx,
1511 (unsigned short)(sy*fontheight(p)),
1512 (unsigned short)dx,
1513 (unsigned short)(dy*fontheight(p)),
1514 (unsigned short)width,
1515 (unsigned short)(height*fontheight(p)),
1516 Z3BLTcopy,
1517 0xffff);
1520 static void retz3_8_clear(struct vc_data *conp, struct display *p,
1521 int sy, int sx, int height, int width)
1523 unsigned short col;
1524 int fontwidth = fontwidth(p);
1526 sx *= fontwidth;
1527 width *= fontwidth;
1529 col = attr_bgcol_ec(p, conp);
1530 col &= 0xff;
1531 col |= (col << 8);
1533 retz3_bitblt(p,
1534 (unsigned short)sx,
1535 (unsigned short)(sy*fontheight(p)),
1536 (unsigned short)sx,
1537 (unsigned short)(sy*fontheight(p)),
1538 (unsigned short)width,
1539 (unsigned short)(height*fontheight(p)),
1540 Z3BLTset,
1541 col);
1545 static void retz3_putc(struct vc_data *conp, struct display *p, int c,
1546 int yy, int xx)
1548 retz3_busy(p);
1549 fbcon_cfb8_putc(conp, p, c, yy, xx);
1553 static void retz3_putcs(struct vc_data *conp, struct display *p,
1554 const unsigned short *s, int count,
1555 int yy, int xx)
1557 retz3_busy(p);
1558 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1562 static void retz3_revc(struct display *p, int xx, int yy)
1564 retz3_busy(p);
1565 fbcon_cfb8_revc(p, xx, yy);
1569 static void retz3_clear_margins(struct vc_data* conp, struct display* p,
1570 int bottom_only)
1572 retz3_busy(p);
1573 fbcon_cfb8_clear_margins(conp, p, bottom_only);
1577 static struct display_switch fbcon_retz3_8 = {
1578 .setup = fbcon_cfb8_setup,
1579 .bmove = retz3_8_bmove,
1580 .clear = retz3_8_clear,
1581 .putc = retz3_putc,
1582 .putcs = retz3_putcs,
1583 .revc = retz3_revc,
1584 .clear_margins = retz3_clear_margins,
1585 .fontwidthmask = FONTWIDTH(8)
1587 #endif