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/slab.h>
29 #include <linux/delay.h>
31 #include <linux/zorro.h>
32 #include <linux/init.h>
34 #include <asm/uaccess.h>
35 #include <asm/system.h>
37 #include <asm/pgtable.h>
40 #include <video/fbcon.h>
41 #include <video/fbcon-cfb8.h>
42 #include <video/fbcon-cfb16.h>
46 /* #define DEBUG if(1) */
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)
67 struct fb_bitfield red;
68 struct fb_bitfield green;
69 struct fb_bitfield blue;
70 struct fb_bitfield transp;
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 */
77 int hsync_len; /* length of horizontal sync */
78 int vsync_len; /* length of vertical sync */
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 {
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 */
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))
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 *
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
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
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
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;
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);
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)
341 long prev = 0x7fffffff;
344 unsigned short res = 0;
346 if (freq <= 31250000)
348 else if (freq <= 62500000)
350 else if (freq <= 125000000)
352 else if (freq <= 250000000)
359 f = freq >> (10 - n2);
361 m = (f * n1) / (14318180/1024);
366 tmp = (((m * 14318180) >> n2) / n1) - freq;
372 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
375 } while ( (++n1) <= 21);
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;
388 int xres, hfront, hsync, hback;
389 int yres, vfront, vsync, vback;
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;
404 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
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;
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;
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);
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)
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)
577 if (data.v_dispend & 256)
579 if (data.v_sstart & 256)
581 if (data.v_bstart & 256)
583 if (data.v_total & 512)
585 if (data.v_dispend & 512)
587 if (data.v_sstart & 512)
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)
597 if (var->vmode & FB_VMODE_DOUBLE)
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));
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));
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));
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)
645 if ((data.h_dispend) & 0x100)
647 if (data.h_bstart & 0x100)
649 if (data.h_sstart & 0x100)
651 if (var->vmode & FB_VMODE_INTERLACED)
653 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
654 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
657 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
659 crt_w(regs, CRT_EXT_START_ADDR, tmp);
662 if (data.h_total & 0x200)
664 if ((data.h_dispend) & 0x200)
666 if (data.h_bstart & 0x200)
668 if (data.h_sstart & 0x200)
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)
678 if ((data.v_dispend) & 0x400)
680 if (data.v_bstart & 0x400)
682 if (data.v_sstart & 0x400)
684 tmp |= ((data.v_bstop & 0x300) >> 3);
685 if (data.v_sstop & 0x10)
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;
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 ???
750 reg_w(regs, 0x83c6, 0x00);
753 reg_w(regs, 0x83c6, 0x60);
756 reg_w(regs, 0x83c6, 0xe0);
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 );
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;
791 fix->visual = FB_VISUAL_PSEUDOCOLOR;
793 fix->visual = FB_VISUAL_TRUECOLOR;
798 fix->line_length = 0;
800 fix->accel = FB_ACCEL_NCR_77C32BLT;
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;
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;
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;
859 var->bits_per_pixel = par->bpp;
863 var->green = par->green;
864 var->blue = par->blue;
865 var->transp = par->transp;
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;
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 */
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);
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);
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);
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);
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);
976 unsigned long pat, src, dst;
978 int i, xres_virtual = var->xres_virtual;
979 short bpp = (var->bits_per_pixel & 0xff);
984 tmp = mask | (mask << 16);
994 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
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);
1009 src += bpp * (width - 1);
1010 dst += bpp * (width - 1);
1015 src += bpp * (height - 1) * xres_virtual;
1016 dst += bpp * (height - 1) * xres_virtual;
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);
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;
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 */
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;
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)
1078 struct retz3fb_par par;
1079 struct retz3_fb_info *zinfo = retz3info(info);
1081 if ((err = retz3_decode_var(var, &par)))
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);
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;
1108 retz3fb_get_par(info, &par);
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;
1126 retz3fb_get_par(info, &par);
1127 error = retz3_encode_var(var, &par);
1129 *var = fb_display[con].var;
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);
1141 display = &fb_display[con];
1143 display = &zinfo->disp; /* used during initialization */
1145 retz3fb_get_fix(&fix, con, info);
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
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);
1170 display->dispsw = &fbcon_cfb8;
1173 #ifdef FBCON_HAS_CFB16
1175 display->dispsw = &fbcon_cfb16;
1179 display->dispsw = &fbcon_dummy;
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);
1197 display = &fb_display[con];
1199 display = &zinfo->disp; /* used during initialization */
1201 if ((err = do_fb_set_var(info, var, con == info->currcon)))
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
1232 if (var->accel_flags & FB_ACCELF_TEXT) {
1233 display->dispsw = &fbcon_retz3_8;
1235 display->dispsw = &fbcon_cfb8;
1238 #ifdef FBCON_HAS_CFB16
1240 display->dispsw = &fbcon_cfb16;
1244 display->dispsw = &fbcon_dummy;
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)))
1262 do_install_cmap(con, info);
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);
1281 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
1282 cmap, kspc ? 0 : 2);
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;
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);
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]);
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)
1328 if (!options || !*options)
1331 while ((this_opt = strsep(&options, ",")) != NULL) {
1334 if (!strcmp(this_opt, "inverse")) {
1337 } else if (!strncmp(this_opt, "font:", 5)) {
1338 strlcpy(fontname, this_opt+5, sizeof(fontname));
1340 z3fb_mode = get_video_mode(this_opt);
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;
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,
1367 if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
1369 release_mem_region(board_addr, 0x00c00000);
1372 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
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;
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)
1429 printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
1430 "video memory\n", fb_info->node,
1431 fb_info->modename, zinfo->fbsize>>10);
1433 /* FIXME: This driver cannot be unloaded yet */
1440 static int z3fb_switch(int con, struct fb_info *info)
1442 /* Do we have to save the colormap? */
1443 if (fb_display[info->currcon].cmap.len)
1444 fb_get_cmap(&fb_display[info->currcon].cmap, 1,
1445 retz3_getcolreg, info);
1447 do_fb_set_var(info, &fb_display[con].var, 1);
1448 info->currcon = con;
1449 /* Install new colormap */
1450 do_install_cmap(con, info);
1456 * Update the `var' structure (called by fbcon.c)
1458 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1459 * Since it's called by a kernel driver, no range checking is done.
1462 static int z3fb_updatevar(int con, struct fb_info *info)
1471 static int __init get_video_mode(const char *name)
1475 for (i = 0; i < NUM_TOTAL_MODES; i++)
1476 if (!strcmp(name, retz3fb_predefined[i].name)){
1477 retz3fb_default = retz3fb_predefined[i].var;
1485 MODULE_LICENSE("GPL");
1487 int init_module(void)
1489 return retz3fb_init();
1495 * Text console acceleration
1498 #ifdef FBCON_HAS_CFB8
1499 static void retz3_8_bmove(struct display *p, int sy, int sx,
1500 int dy, int dx, int height, int width)
1502 int fontwidth = fontwidth(p);
1510 (unsigned short)(sy*fontheight(p)),
1512 (unsigned short)(dy*fontheight(p)),
1513 (unsigned short)width,
1514 (unsigned short)(height*fontheight(p)),
1519 static void retz3_8_clear(struct vc_data *conp, struct display *p,
1520 int sy, int sx, int height, int width)
1523 int fontwidth = fontwidth(p);
1528 col = attr_bgcol_ec(p, conp);
1534 (unsigned short)(sy*fontheight(p)),
1536 (unsigned short)(sy*fontheight(p)),
1537 (unsigned short)width,
1538 (unsigned short)(height*fontheight(p)),
1544 static void retz3_putc(struct vc_data *conp, struct display *p, int c,
1548 fbcon_cfb8_putc(conp, p, c, yy, xx);
1552 static void retz3_putcs(struct vc_data *conp, struct display *p,
1553 const unsigned short *s, int count,
1557 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1561 static void retz3_revc(struct display *p, int xx, int yy)
1564 fbcon_cfb8_revc(p, xx, yy);
1568 static void retz3_clear_margins(struct vc_data* conp, struct display* p,
1572 fbcon_cfb8_clear_margins(conp, p, bottom_only);
1576 static struct display_switch fbcon_retz3_8 = {
1577 .setup = fbcon_cfb8_setup,
1578 .bmove = retz3_8_bmove,
1579 .clear = retz3_8_clear,
1581 .putcs = retz3_putcs,
1583 .clear_margins = retz3_clear_margins,
1584 .fontwidthmask = FONTWIDTH(8)