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,
11 * clgen.c: Copyright (C) 1996 Frank Neumann
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
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
28 #include <linux/tty.h>
29 #include <linux/slab.h>
30 #include <linux/delay.h>
32 #include <linux/zorro.h>
33 #include <linux/init.h>
35 #include <asm/uaccess.h>
36 #include <asm/system.h>
38 #include <asm/pgtable.h>
41 #include <video/fbcon.h>
42 #include <video/fbcon-cfb8.h>
43 #include <video/fbcon-cfb16.h>
47 /* #define DEBUG if(1) */
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)
68 struct fb_bitfield red;
69 struct fb_bitfield green;
70 struct fb_bitfield blue;
71 struct fb_bitfield transp;
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 */
78 int hsync_len; /* length of horizontal sync */
79 int vsync_len; /* length of vertical sync */
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 {
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 */
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))
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 *
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
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
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
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;
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);
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)
342 long prev = 0x7fffffff;
345 unsigned short res = 0;
347 if (freq <= 31250000)
349 else if (freq <= 62500000)
351 else if (freq <= 125000000)
353 else if (freq <= 250000000)
360 f = freq >> (10 - n2);
362 m = (f * n1) / (14318180/1024);
367 tmp = (((m * 14318180) >> n2) / n1) - freq;
373 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
376 } while ( (++n1) <= 21);
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;
389 int xres, hfront, hsync, hback;
390 int yres, vfront, vsync, vback;
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;
405 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
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;
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;
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);
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)
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)
578 if (data.v_dispend & 256)
580 if (data.v_sstart & 256)
582 if (data.v_bstart & 256)
584 if (data.v_total & 512)
586 if (data.v_dispend & 512)
588 if (data.v_sstart & 512)
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)
598 if (var->vmode & FB_VMODE_DOUBLE)
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));
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));
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));
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)
646 if ((data.h_dispend) & 0x100)
648 if (data.h_bstart & 0x100)
650 if (data.h_sstart & 0x100)
652 if (var->vmode & FB_VMODE_INTERLACED)
654 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
655 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
658 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
660 crt_w(regs, CRT_EXT_START_ADDR, tmp);
663 if (data.h_total & 0x200)
665 if ((data.h_dispend) & 0x200)
667 if (data.h_bstart & 0x200)
669 if (data.h_sstart & 0x200)
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)
679 if ((data.v_dispend) & 0x400)
681 if (data.v_bstart & 0x400)
683 if (data.v_sstart & 0x400)
685 tmp |= ((data.v_bstop & 0x300) >> 3);
686 if (data.v_sstop & 0x10)
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;
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 ???
751 reg_w(regs, 0x83c6, 0x00);
754 reg_w(regs, 0x83c6, 0x60);
757 reg_w(regs, 0x83c6, 0xe0);
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 );
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;
792 fix->visual = FB_VISUAL_PSEUDOCOLOR;
794 fix->visual = FB_VISUAL_TRUECOLOR;
799 fix->line_length = 0;
801 fix->accel = FB_ACCEL_NCR_77C32BLT;
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;
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;
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;
860 var->bits_per_pixel = par->bpp;
864 var->green = par->green;
865 var->blue = par->blue;
866 var->transp = par->transp;
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;
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 */
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);
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);
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);
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);
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);
977 unsigned long pat, src, dst;
979 int i, xres_virtual = var->xres_virtual;
980 short bpp = (var->bits_per_pixel & 0xff);
985 tmp = mask | (mask << 16);
995 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
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);
1010 src += bpp * (width - 1);
1011 dst += bpp * (width - 1);
1016 src += bpp * (height - 1) * xres_virtual;
1017 dst += bpp * (height - 1) * xres_virtual;
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);
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;
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 */
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;
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)
1079 struct retz3fb_par par;
1080 struct retz3_fb_info *zinfo = retz3info(info);
1082 if ((err = retz3_decode_var(var, &par)))
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);
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;
1109 retz3fb_get_par(info, &par);
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;
1127 retz3fb_get_par(info, &par);
1128 error = retz3_encode_var(var, &par);
1130 *var = fb_display[con].var;
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);
1142 display = &fb_display[con];
1144 display = &zinfo->disp; /* used during initialization */
1146 retz3fb_get_fix(&fix, con, info);
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
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);
1171 display->dispsw = &fbcon_cfb8;
1174 #ifdef FBCON_HAS_CFB16
1176 display->dispsw = &fbcon_cfb16;
1180 display->dispsw = &fbcon_dummy;
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);
1198 display = &fb_display[con];
1200 display = &zinfo->disp; /* used during initialization */
1202 if ((err = do_fb_set_var(info, var, con == info->currcon)))
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
1233 if (var->accel_flags & FB_ACCELF_TEXT) {
1234 display->dispsw = &fbcon_retz3_8;
1236 display->dispsw = &fbcon_cfb8;
1239 #ifdef FBCON_HAS_CFB16
1241 display->dispsw = &fbcon_cfb16;
1245 display->dispsw = &fbcon_dummy;
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)))
1263 do_install_cmap(con, info);
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);
1282 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1283 cmap, kspc ? 0 : 2);
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;
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);
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]);
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)
1329 if (!options || !*options)
1332 while ((this_opt = strsep(&options, ",")) != NULL) {
1335 if (!strcmp(this_opt, "inverse")) {
1338 } else if (!strncmp(this_opt, "font:", 5)) {
1339 strlcpy(fontname, this_opt+5, sizeof(fontname));
1341 z3fb_mode = get_video_mode(this_opt);
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;
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,
1368 if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
1370 release_mem_region(board_addr, 0x00c00000);
1373 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
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;
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)
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 */
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);
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)
1472 static int __init get_video_mode(const char *name)
1476 for (i = 0; i < NUM_TOTAL_MODES; i++)
1477 if (!strcmp(name, retz3fb_predefined[i].name)){
1478 retz3fb_default = retz3fb_predefined[i].var;
1486 MODULE_LICENSE("GPL");
1488 int init_module(void)
1490 return retz3fb_init();
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);
1511 (unsigned short)(sy*fontheight(p)),
1513 (unsigned short)(dy*fontheight(p)),
1514 (unsigned short)width,
1515 (unsigned short)(height*fontheight(p)),
1520 static void retz3_8_clear(struct vc_data *conp, struct display *p,
1521 int sy, int sx, int height, int width)
1524 int fontwidth = fontwidth(p);
1529 col = attr_bgcol_ec(p, conp);
1535 (unsigned short)(sy*fontheight(p)),
1537 (unsigned short)(sy*fontheight(p)),
1538 (unsigned short)width,
1539 (unsigned short)(height*fontheight(p)),
1545 static void retz3_putc(struct vc_data *conp, struct display *p, int c,
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,
1558 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1562 static void retz3_revc(struct display *p, int xx, int yy)
1565 fbcon_cfb8_revc(p, xx, yy);
1569 static void retz3_clear_margins(struct vc_data* conp, struct display* 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,
1582 .putcs = retz3_putcs,
1584 .clear_margins = retz3_clear_margins,
1585 .fontwidthmask = FONTWIDTH(8)