Import 2.1.36
[davej-history.git] / arch / m68k / amiga / retz3fb.c
blob4885e48f74a32716868234fdebb39e281b4fb0db
1 /*
2 * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
3 * RetinaZ3 frame buffer device
5 * Copyright (C) 1997 Jes Sorensen
7 * This file is based on the CyberVision64 frame buffer device and
8 * the generic Cirrus Logic driver.
10 * cyberfb.c: Copyright (C) 1996 Martin Apel,
11 * Geert Uytterhoeven
12 * clgen.c: Copyright (C) 1996 Frank Neumann
14 * History:
15 * - 22 Jan 97: Initial work
16 * - 14 Feb 97: Screen initialization works somewhat, still only
17 * 8-bit packed pixel is supported.
19 * This file is subject to the terms and conditions of the GNU General Public
20 * License. See the file COPYING in the main directory of this archive
21 * for more details.
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/string.h>
28 #include <linux/mm.h>
29 #include <linux/tty.h>
30 #include <linux/malloc.h>
31 #include <linux/delay.h>
32 #include <linux/fb.h>
33 #include <asm/uaccess.h>
34 #include <asm/system.h>
35 #include <asm/irq.h>
36 #include <linux/zorro.h>
37 #include <asm/pgtable.h>
39 #include "retz3fb.h"
41 /* #define DEBUG if(1) */
42 #define DEBUG if(0)
45 * Reserve space for one pattern line.
47 * For the time being we only support 4MB boards!
50 #define PAT_MEM_SIZE 16*3
51 #define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
53 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
55 struct retz3_fb_par {
56 int xres;
57 int yres;
58 int xres_vir;
59 int yres_vir;
60 int xoffset;
61 int yoffset;
62 int bpp;
64 struct fb_bitfield red;
65 struct fb_bitfield green;
66 struct fb_bitfield blue;
67 struct fb_bitfield transp;
69 int pixclock;
70 int left_margin; /* time from sync to picture */
71 int right_margin; /* time from picture to sync */
72 int upper_margin; /* time from sync to picture */
73 int lower_margin;
74 int hsync_len; /* length of horizontal sync */
75 int vsync_len; /* length of vertical sync */
76 int vmode;
79 struct display_data {
80 long h_total; /* Horizontal Total */
81 long h_sstart; /* Horizontal Sync Start */
82 long h_sstop; /* Horizontal Sync Stop */
83 long h_bstart; /* Horizontal Blank Start */
84 long h_bstop; /* Horizontal Blank Stop */
85 long h_dispend; /* Horizontal Display End */
86 long v_total; /* Vertical Total */
87 long v_sstart; /* Vertical Sync Start */
88 long v_sstop; /* Vertical Sync Stop */
89 long v_bstart; /* Vertical Blank Start */
90 long v_bstop; /* Vertical Blank Stop */
91 long v_dispend; /* Horizontal Display End */
94 static struct retz3_fb_par current_par;
96 static int current_par_valid = 0;
97 static int currcon = 0;
99 static struct display disp[MAX_NR_CONSOLES];
100 static struct fb_info fb_info;
102 static int node; /* node of the /dev/fb?current file */
106 * Switch for Chipset Independency
109 static struct fb_hwswitch {
111 /* Initialisation */
113 int (*init)(void);
115 /* Display Control */
117 int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
118 int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
119 int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
120 int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
121 int *green, unsigned int *blue, unsigned int *transp);
122 int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
123 green, unsigned int blue, unsigned int transp);
124 void (*blank)(int blank);
125 } *fbhw;
129 * Frame Buffer Name
132 static char retz3_fb_name[16] = "RetinaZ3";
135 static int z3_key = 0;
136 static unsigned char retz3_color_table [256][4];
137 static unsigned long z3_mem;
138 static unsigned long z3_fbmem;
139 static unsigned long z3_size;
140 static volatile unsigned char *z3_regs;
142 static long *memstart;
146 * Predefined Video Mode Names
149 static char *retz3_fb_modenames[] = {
152 * Autodetect (Default) Video Mode
155 "default",
158 * Predefined Video Modes
161 "640x480", /* RetinaZ3 8 bpp */
162 "800x600", /* RetinaZ3 8 bpp */
163 "1024x768i",
164 "640x480-16", /* RetinaZ3 16 bpp */
165 "640x480-24", /* RetinaZ3 24 bpp */
168 * Dummy Video Modes
171 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
172 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
173 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
176 * User Defined Video Modes
178 * This doesn't work yet!!
181 "user0", "user1", "user2", "user3",
182 "user4", "user5", "user6", "user7"
186 * A small info on how to convert XFree86 timing values into fb
187 * timings - by Frank Neumann:
189 An XFree86 mode line consists of the following fields:
190 "800x600" 50 800 856 976 1040 600 637 643 666
191 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
193 The fields in the fb_var_screeninfo structure are:
194 unsigned long pixclock; * pixel clock in ps (pico seconds) *
195 unsigned long left_margin; * time from sync to picture *
196 unsigned long right_margin; * time from picture to sync *
197 unsigned long upper_margin; * time from sync to picture *
198 unsigned long lower_margin;
199 unsigned long hsync_len; * length of horizontal sync *
200 unsigned long vsync_len; * length of vertical sync *
202 1) Pixelclock:
203 xfree: in MHz
204 fb: In Picoseconds (ps)
206 pixclock = 1000000 / DCF
208 2) horizontal timings:
209 left_margin = HFL - SH2
210 right_margin = SH1 - HR
211 hsync_len = SH2 - SH1
213 3) vertical timings:
214 upper_margin = VFL - SV2
215 lower_margin = SV1 - VR
216 vsync_len = SV2 - SV1
218 Good examples for VESA timings can be found in the XFree86 source tree,
219 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
223 * Predefined Video Mode Definitions
226 static struct fb_var_screeninfo retz3_fb_predefined[] = {
229 * Autodetect (Default) Video Mode
232 { 0, },
235 * Predefined Video Modes
239 * NB: it is very important to adjust the pixel-clock to the color-depth.
243 640, 480, 640, 480, 0, 0, 8, 0,
244 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
245 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
246 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
249 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
250 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
253 /* 800 x 600, 8 bpp */
254 800, 600, 800, 600, 0, 0, 8, 0,
255 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
256 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
257 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
260 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
261 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
264 /* 1024 x 768, 8 bpp, interlaced */
265 1024, 768, 1024, 768, 0, 0, 8, 0,
266 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
267 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
268 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
271 640, 480, 640, 480, 0, 0, 16, 0,
272 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
273 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
274 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
277 640, 480, 640, 480, 0, 0, 24, 0,
278 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
279 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
280 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
284 * Dummy Video Modes
287 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
288 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
289 { 0, }, { 0, },
292 * User Defined Video Modes
295 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
299 #define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
300 #define NUM_PREDEF_MODES (5)
303 static int z3fb_inverse = 0;
304 static int z3fb_mode = 0;
308 * Interface used by the world
311 int retz3_probe(void);
312 void retz3_video_setup(char *options, int *ints);
314 static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
315 static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
316 static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
317 static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
318 static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
319 static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
320 static int retz3_fb_ioctl(struct inode *inode, struct file *file,
321 unsigned int cmd, unsigned long arg, int con);
325 * Interface to the low level console driver
328 struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
329 static int z3fb_switch(int con);
330 static int z3fb_updatevar(int con);
331 static void z3fb_blank(int blank);
332 static int z3fb_setcmap(struct fb_cmap *cmap, int con);
336 * Accelerated Functions used by the low level console driver
339 void retz3_bitblt(struct fb_var_screeninfo *scr,
340 unsigned short curx, unsigned short cury, unsigned
341 short destx, unsigned short desty, unsigned short
342 width, unsigned short height, unsigned short cmd,
343 unsigned short mask);
344 void retz3_fill(unsigned short x, unsigned short y, unsigned short
345 width, unsigned short height, unsigned short mode,
346 unsigned short color);
349 * Hardware Specific Routines
352 static int retz3_init(void);
353 static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
354 struct retz3_fb_par *par);
355 static int retz3_decode_var(struct fb_var_screeninfo *var,
356 struct retz3_fb_par *par);
357 static int retz3_encode_var(struct fb_var_screeninfo *var,
358 struct retz3_fb_par *par);
359 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
360 unsigned int *green, unsigned int *blue,
361 unsigned int *transp);
362 static int retz3_setcolreg(unsigned int regno, unsigned int red,
363 unsigned int green, unsigned int blue,
364 unsigned int transp);
365 static void retz3_blank(int blank);
369 * Internal routines
372 static void retz3_fb_get_par(struct retz3_fb_par *par);
373 static void retz3_fb_set_par(struct retz3_fb_par *par);
374 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
375 static struct fb_cmap *get_default_colormap(int bpp);
376 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
377 int kspc);
378 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
379 int kspc);
380 static void do_install_cmap(int con);
381 static void memcpy_fs(int fsfromto, void *to, void *from, int len);
382 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
383 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
384 static void retz3_fb_set_disp(int con);
385 static int get_video_mode(const char *name);
388 /* -------------------- Hardware specific routines -------------------------- */
390 static unsigned short find_fq(unsigned int freq)
392 unsigned long f;
393 long tmp;
394 long prev = 0x7fffffff;
395 long n2, n1 = 3;
396 unsigned long m;
397 unsigned short res = 0;
399 if (freq <= 31250000)
400 n2 = 3;
401 else if (freq <= 62500000)
402 n2 = 2;
403 else if (freq <= 125000000)
404 n2 = 1;
405 else if (freq <= 250000000)
406 n2 = 0;
407 else
408 return(0);
411 do {
412 f = freq >> (10 - n2);
414 m = (f * n1) / (14318180/1024);
416 if (m > 129)
417 break;
419 tmp = (((m * 14318180) >> n2) / n1) - freq;
420 if (tmp < 0)
421 tmp = -tmp;
423 if (tmp < prev) {
424 prev = tmp;
425 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
428 } while ( (++n1) <= 21);
430 return res;
434 static int retz3_set_video(struct fb_var_screeninfo *var,
435 struct retz3_fb_par *par)
437 float freq_f;
438 long freq;
440 int xres, hfront, hsync, hback;
441 int yres, vfront, vsync, vback;
442 unsigned char tmp;
443 unsigned short best_freq;
444 struct display_data data;
446 short clocksel = 0; /* Apparantly this is always zero */
448 int bpp = var->bits_per_pixel;
451 * XXX
453 if (bpp == 24)
454 return 0;
456 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
457 return -EFAULT;
459 par->xoffset = 0;
460 par->yoffset = 0;
462 xres = var->xres * bpp / 4;
463 hfront = var->right_margin * bpp / 4;
464 hsync = var->hsync_len * bpp / 4;
465 hback = var->left_margin * bpp / 4;
467 if (var->vmode & FB_VMODE_DOUBLE)
469 yres = var->yres * 2;
470 vfront = var->lower_margin * 2;
471 vsync = var->vsync_len * 2;
472 vback = var->upper_margin * 2;
474 else if (var->vmode & FB_VMODE_INTERLACED)
476 yres = (var->yres + 1) / 2;
477 vfront = (var->lower_margin + 1) / 2;
478 vsync = (var->vsync_len + 1) / 2;
479 vback = (var->upper_margin + 1) / 2;
481 else
483 yres = var->yres; /* -1 ? */
484 vfront = var->lower_margin;
485 vsync = var->vsync_len;
486 vback = var->upper_margin;
489 data.h_total = (hback / 8) + (xres / 8)
490 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
491 data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
492 data.h_bstart = xres / 8 /* + 1 */;
494 data.h_bstop = data.h_total+1 + 2 + 1;
495 data.h_sstart = (xres / 8) + (hfront / 8) + 1;
496 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
498 data.v_total = yres + vfront + vsync + vback - 1;
500 data.v_dispend = yres - 1;
501 data.v_bstart = yres;
503 data.v_bstop = data.v_total;
504 data.v_sstart = yres + vfront - 1 - 2;
505 data.v_sstop = yres + vfront + vsync - 1;
507 #if 0 /* testing */
509 printk("HBS: %i\n", data.h_bstart);
510 printk("HSS: %i\n", data.h_sstart);
511 printk("HSE: %i\n", data.h_sstop);
512 printk("HBE: %i\n", data.h_bstop);
513 printk("HT: %i\n", data.h_total);
515 printk("hsync: %i\n", hsync);
516 printk("hfront: %i\n", hfront);
517 printk("hback: %i\n", hback);
519 printk("VBS: %i\n", data.v_bstart);
520 printk("VSS: %i\n", data.v_sstart);
521 printk("VSE: %i\n", data.v_sstop);
522 printk("VBE: %i\n", data.v_bstop);
523 printk("VT: %i\n", data.v_total);
525 printk("vsync: %i\n", vsync);
526 printk("vfront: %i\n", vfront);
527 printk("vback: %i\n", vback);
528 #endif
530 if (data.v_total >= 1024)
531 printk("MAYDAY: v_total >= 1024; bailing out!\n");
533 reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
534 reg_w(GREG_FEATURE_CONTROL_W, 0x00);
536 seq_w(SEQ_RESET, 0x00);
537 seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
540 * CLOCKING_MODE bits:
541 * 2: This one is only set for certain text-modes, wonder if
542 * it may be for EGA-lines? (it was referred to as CLKDIV2)
543 * (The CL drivers sets it to 0x21 with the comment:
544 * FullBandwidth (video off) and 8/9 dot clock)
546 seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
548 seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
549 seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
550 seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
551 seq_w(SEQ_RESET, 0x01);
552 seq_w(SEQ_RESET, 0x03);
554 seq_w(SEQ_EXTENDED_ENABLE, 0x05);
556 seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
557 seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
558 seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
559 seq_w(SEQ_LINEAR_0, 0x4a);
560 seq_w(SEQ_LINEAR_1, 0x00);
562 seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
563 seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
564 seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
567 * The lower 4 bits (0-3) are used to set the font-width for
568 * text-mode - DON'T try to set this for gfx-mode.
570 seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
571 seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
574 * Extended Pixel Control:
575 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
576 * bit 1: (Packed/Nibble Pixel Format ?)
577 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
579 seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
581 seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
582 seq_w(SEQ_COLOR_EXP_WFG, 0x01);
583 seq_w(SEQ_COLOR_EXP_WBG, 0x00);
584 seq_w(SEQ_EXT_RW_CONTROL, 0x00);
585 seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
586 seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
587 seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
588 seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
589 seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
590 seq_w(SEQ_CRC_CONTROL, 0x00);
591 seq_w(SEQ_PERF_SELECT, 0x10);
592 seq_w(SEQ_ACM_APERTURE_1, 0x00);
593 seq_w(SEQ_ACM_APERTURE_2, 0x30);
594 seq_w(SEQ_ACM_APERTURE_3, 0x00);
595 seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
598 /* unlock register CRT0..CRT7 */
599 crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
601 /* Zuerst zu schreibende Werte nur per printk ausgeben */
602 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
603 crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
605 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
606 crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
608 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
609 crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
611 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
612 crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
614 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
615 crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
617 tmp = (data.h_sstop & 0x1f);
618 if (data.h_bstop & 0x20)
619 tmp |= 0x80;
620 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
621 crt_w(CRT_END_HOR_RETR, tmp);
623 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
624 crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
626 tmp = 0x10; /* LineCompare bit #9 */
627 if (data.v_total & 256)
628 tmp |= 0x01;
629 if (data.v_dispend & 256)
630 tmp |= 0x02;
631 if (data.v_sstart & 256)
632 tmp |= 0x04;
633 if (data.v_bstart & 256)
634 tmp |= 0x08;
635 if (data.v_total & 512)
636 tmp |= 0x20;
637 if (data.v_dispend & 512)
638 tmp |= 0x40;
639 if (data.v_sstart & 512)
640 tmp |= 0x80;
641 DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
642 crt_w(CRT_OVERFLOW, tmp);
644 crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
646 tmp = 0x40; /* LineCompare bit #8 */
647 if (data.v_bstart & 512)
648 tmp |= 0x20;
649 if (var->vmode & FB_VMODE_DOUBLE)
650 tmp |= 0x80;
651 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
652 crt_w(CRT_MAX_SCAN_LINE, tmp);
654 crt_w(CRT_CURSOR_START, 0x00);
655 crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
657 crt_w(CRT_START_ADDR_HIGH, 0x00);
658 crt_w(CRT_START_ADDR_LOW, 0x00);
660 crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
661 crt_w(CRT_CURSOR_LOC_LOW, 0x00);
663 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
664 crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
666 #if 1
667 /* 5 refresh cycles per scanline */
668 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
669 crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
670 #else
671 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
672 crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
673 #endif
674 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
675 crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
677 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
678 crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
680 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
681 crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
683 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
684 crt_w(CRT_MODE_CONTROL, 0xe3);
686 DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
687 crt_w(CRT_LINE_COMPARE, 0xff);
689 tmp = (var->xres_virtual / 8) * (bpp / 8);
690 crt_w(CRT_OFFSET, tmp);
692 crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
694 tmp = 0x20; /* Enable extended end bits */
695 if (data.h_total & 0x100)
696 tmp |= 0x01;
697 if ((data.h_dispend) & 0x100)
698 tmp |= 0x02;
699 if (data.h_bstart & 0x100)
700 tmp |= 0x04;
701 if (data.h_sstart & 0x100)
702 tmp |= 0x08;
703 if (var->vmode & FB_VMODE_INTERLACED)
704 tmp |= 0x10;
705 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
706 crt_w(CRT_EXT_HOR_TIMING1, tmp);
708 tmp = 0x00;
709 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
710 tmp |= 0x10;
711 crt_w(CRT_EXT_START_ADDR, tmp);
713 tmp = 0x00;
714 if (data.h_total & 0x200)
715 tmp |= 0x01;
716 if ((data.h_dispend) & 0x200)
717 tmp |= 0x02;
718 if (data.h_bstart & 0x200)
719 tmp |= 0x04;
720 if (data.h_sstart & 0x200)
721 tmp |= 0x08;
722 tmp |= ((data.h_bstop & 0xc0) >> 2);
723 tmp |= ((data.h_sstop & 0x60) << 1);
724 crt_w(CRT_EXT_HOR_TIMING2, tmp);
725 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
727 tmp = 0x10; /* Line compare bit 10 */
728 if (data.v_total & 0x400)
729 tmp |= 0x01;
730 if ((data.v_dispend) & 0x400)
731 tmp |= 0x02;
732 if (data.v_bstart & 0x400)
733 tmp |= 0x04;
734 if (data.v_sstart & 0x400)
735 tmp |= 0x08;
736 tmp |= ((data.v_bstop & 0x300) >> 3);
737 if (data.v_sstop & 0x10)
738 tmp |= 0x80;
739 crt_w(CRT_EXT_VER_TIMING, tmp);
740 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
742 crt_w(CRT_MONITOR_POWER, 0x00);
745 * Convert from ps to Hz.
747 freq_f = (1.0/(float)var->pixclock) * 1000000000;
748 freq = ((long)freq_f) * 1000;
750 best_freq = find_fq(freq);
751 pll_w(0x02, best_freq);
752 best_freq = find_fq(61000000);
753 pll_w(0x0a, best_freq);
754 pll_w(0x0e, 0x22);
756 gfx_w(GFX_SET_RESET, 0x00);
757 gfx_w(GFX_ENABLE_SET_RESET, 0x00);
758 gfx_w(GFX_COLOR_COMPARE, 0x00);
759 gfx_w(GFX_DATA_ROTATE, 0x00);
760 gfx_w(GFX_READ_MAP_SELECT, 0x00);
761 gfx_w(GFX_GRAPHICS_MODE, 0x00);
762 gfx_w(GFX_MISC, 0x05);
763 gfx_w(GFX_COLOR_XCARE, 0x0f);
764 gfx_w(GFX_BITMASK, 0xff);
766 reg_r(ACT_ADDRESS_RESET);
767 attr_w(ACT_PALETTE0 , 0x00);
768 attr_w(ACT_PALETTE1 , 0x01);
769 attr_w(ACT_PALETTE2 , 0x02);
770 attr_w(ACT_PALETTE3 , 0x03);
771 attr_w(ACT_PALETTE4 , 0x04);
772 attr_w(ACT_PALETTE5 , 0x05);
773 attr_w(ACT_PALETTE6 , 0x06);
774 attr_w(ACT_PALETTE7 , 0x07);
775 attr_w(ACT_PALETTE8 , 0x08);
776 attr_w(ACT_PALETTE9 , 0x09);
777 attr_w(ACT_PALETTE10, 0x0a);
778 attr_w(ACT_PALETTE11, 0x0b);
779 attr_w(ACT_PALETTE12, 0x0c);
780 attr_w(ACT_PALETTE13, 0x0d);
781 attr_w(ACT_PALETTE14, 0x0e);
782 attr_w(ACT_PALETTE15, 0x0f);
783 reg_r(ACT_ADDRESS_RESET);
785 attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
787 attr_w(ACT_OVERSCAN_COLOR, 0x00);
788 attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
789 attr_w(ACT_HOR_PEL_PANNING, 0x00);
790 attr_w(ACT_COLOR_SELECT, 0x00);
792 reg_r(ACT_ADDRESS_RESET);
793 reg_w(ACT_DATA, 0x20);
795 reg_w(VDAC_MASK, 0xff);
798 * Extended palette adressing ???
800 switch (bpp){
801 case 8:
802 reg_w(0x83c6, 0x00);
803 break;
804 case 16:
805 reg_w(0x83c6, 0x60);
806 break;
807 case 24:
808 reg_w(0x83c6, 0xe0);
809 break;
810 default:
811 printk("Illegal color-depth: %i\n", bpp);
814 reg_w(VDAC_ADDRESS, 0x00);
816 seq_w(SEQ_MAP_MASK, 0x0f );
818 return 0;
822 * Initialization
824 * Set the default video mode for this chipset. If a video mode was
825 * specified on the command line, it will override the default mode.
828 static int retz3_init(void)
830 int i;
831 #if 0
832 volatile unsigned long *CursorBase;
833 #endif
834 unsigned long board_addr, board_size;
835 struct ConfigDev *cd;
837 cd = zorro_get_board (z3_key);
838 zorro_config_board (z3_key, 0);
839 board_addr = (unsigned long)cd->cd_BoardAddr;
840 board_size = (unsigned long)cd->cd_BoardSize;
842 for (i = 0; i < 256; i++){
843 for (i = 0; i < 256; i++){
844 retz3_color_table [i][0] = i;
845 retz3_color_table [i][1] = i;
846 retz3_color_table [i][2] = i;
847 retz3_color_table [i][3] = 0;
851 *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
853 z3_mem = kernel_map (board_addr, board_size,
854 KERNELMAP_NOCACHE_SER, memstart);
856 z3_regs = (char*) z3_mem;
857 z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
859 /* Get memory size - for now we asume its a 4MB board */
861 z3_size = 0x00400000; /* 4 MB */
863 memset ((char*)z3_fbmem, 0, z3_size);
865 /* Disable hardware cursor */
867 seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
870 #if 0
871 /* Initialize hardware cursor */
872 CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
873 for (i=0; i < 8; i++){
874 *(CursorBase +(i*4)) = 0xffffff00;
875 *(CursorBase+1+(i*4)) = 0xffff0000;
876 *(CursorBase+2+(i*4)) = 0xffff0000;
877 *(CursorBase+3+(i*4)) = 0xffff0000;
879 for (i=8; i < 64; i++){
880 *(CursorBase +(i*4)) = 0xffff0000;
881 *(CursorBase+1+(i*4)) = 0xffff0000;
882 *(CursorBase+2+(i*4)) = 0xffff0000;
883 *(CursorBase+3+(i*4)) = 0xffff0000;
885 #endif
887 retz3_setcolreg (255, 56, 100, 160, 0);
888 retz3_setcolreg (254, 0, 0, 0, 0);
890 return 0;
895 * This function should fill in the `fix' structure based on the
896 * values in the `par' structure.
899 static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
900 struct retz3_fb_par *par)
902 int i;
904 strcpy(fix->id, retz3_fb_name);
905 fix->smem_start = z3_fbmem;
906 fix->smem_len = z3_size;
908 fix->type = FB_TYPE_PACKED_PIXELS;
909 fix->type_aux = 0;
910 if (par->bpp == 8)
911 fix->visual = FB_VISUAL_PSEUDOCOLOR;
912 else
913 fix->visual = FB_VISUAL_DIRECTCOLOR;
915 fix->xpanstep = 0;
916 fix->ypanstep = 0;
917 fix->ywrapstep = 0;
918 fix->line_length = 0;
920 for (i = 0; i < arraysize(fix->reserved); i++)
921 fix->reserved[i] = 0;
923 return 0;
928 * Get the video params out of `var'. If a value doesn't fit, round
929 * it up, if it's too big, return -EINVAL.
932 static int retz3_decode_var(struct fb_var_screeninfo *var,
933 struct retz3_fb_par *par)
935 par->xres = var->xres;
936 par->yres = var->yres;
937 par->xres_vir = var->xres_virtual;
938 par->yres_vir = var->yres_virtual;
939 par->bpp = var->bits_per_pixel;
940 par->pixclock = var->pixclock;
941 par->vmode = var->vmode;
943 par->red = var->red;
944 par->green = var->green;
945 par->blue = var->blue;
946 par->transp = var->transp;
948 par->left_margin = var->left_margin;
949 par->right_margin = var->right_margin;
950 par->upper_margin = var->upper_margin;
951 par->lower_margin = var->lower_margin;
952 par->hsync_len = var->hsync_len;
953 par->vsync_len = var->vsync_len;
955 return 0;
960 * Fill the `var' structure based on the values in `par' and maybe
961 * other values read out of the hardware.
964 static int retz3_encode_var(struct fb_var_screeninfo *var,
965 struct retz3_fb_par *par)
967 int i;
969 var->xres = par->xres;
970 var->yres = par->yres;
971 var->xres_virtual = par->xres_vir;
972 var->yres_virtual = par->yres_vir;
973 var->xoffset = 0;
974 var->yoffset = 0;
976 var->bits_per_pixel = par->bpp;
977 var->grayscale = 0;
979 var->red = par->red;
980 var->green = par->green;
981 var->blue = par->blue;
982 var->transp = par->transp;
984 var->nonstd = 0;
985 var->activate = 0;
987 var->height = -1;
988 var->width = -1;
990 var->accel = FB_ACCEL_RETINAZ3;
992 var->pixclock = par->pixclock;
994 var->sync = 0; /* ??? */
995 var->left_margin = par->left_margin;
996 var->right_margin = par->right_margin;
997 var->upper_margin = par->upper_margin;
998 var->lower_margin = par->lower_margin;
999 var->hsync_len = par->hsync_len;
1000 var->vsync_len = par->vsync_len;
1002 for (i = 0; i < arraysize(var->reserved); i++)
1003 var->reserved[i] = 0;
1005 var->vmode = par->vmode;
1006 return 0;
1011 * Set a single color register. The values supplied are already
1012 * rounded down to the hardware's capabilities (according to the
1013 * entries in the var structure). Return != 0 for invalid regno.
1016 static int retz3_setcolreg(unsigned int regno, unsigned int red,
1017 unsigned int green, unsigned int blue,
1018 unsigned int transp)
1020 /* We'll get to this */
1022 if (regno > 255)
1023 return 1;
1025 retz3_color_table [regno][0] = red & 0xff;
1026 retz3_color_table [regno][1] = green & 0xff;
1027 retz3_color_table [regno][2] = blue & 0xff;
1028 retz3_color_table [regno][3] = transp;
1030 reg_w(VDAC_ADDRESS_W, regno);
1031 reg_w(VDAC_DATA, (red & 0xff) >> 2);
1032 reg_w(VDAC_DATA, (green & 0xff) >> 2);
1033 reg_w(VDAC_DATA, (blue & 0xff) >> 2);
1035 return 0;
1040 * Read a single color register and split it into
1041 * colors/transparent. Return != 0 for invalid regno.
1044 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
1045 unsigned int *green, unsigned int *blue,
1046 unsigned int *transp)
1048 if (regno > 255)
1049 return 1;
1050 *red = retz3_color_table [regno][0];
1051 *green = retz3_color_table [regno][1];
1052 *blue = retz3_color_table [regno][2];
1053 *transp = retz3_color_table [regno][3];
1054 return 0;
1059 * (Un)Blank the screen
1062 void retz3_blank(int blank)
1064 int i;
1066 if (blank)
1067 for (i = 0; i < 256; i++){
1068 reg_w(VDAC_ADDRESS_W, i);
1069 reg_w(VDAC_DATA, 0);
1070 reg_w(VDAC_DATA, 0);
1071 reg_w(VDAC_DATA, 0);
1073 else
1074 for (i = 0; i < 256; i++){
1075 reg_w(VDAC_ADDRESS_W, i);
1076 reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
1077 reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
1078 reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
1083 void retz3_bitblt (struct fb_var_screeninfo *var,
1084 unsigned short srcx, unsigned short srcy, unsigned
1085 short destx, unsigned short desty, unsigned short
1086 width, unsigned short height, unsigned short cmd,
1087 unsigned short mask)
1090 volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
1091 unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
1093 unsigned short mod;
1094 unsigned long tmp;
1095 unsigned long pat, src, dst;
1096 unsigned char blt_status;
1098 int i, xres_virtual = var->xres_virtual;
1099 short bpp = (var->bits_per_pixel & 0xff);
1101 if (bpp < 8)
1102 bpp = 8;
1104 tmp = mask | (mask << 16);
1106 #if 0
1108 * Check for blitter finished before we start messing with the
1109 * pattern.
1112 blt_status = *(((volatile unsigned char *)acm) +
1113 (ACM_START_STATUS + 2));
1114 }while ((blt_status & 1) == 0);
1115 #endif
1117 i = 0;
1119 *pattern++ = tmp;
1120 }while(i++ < bpp/4);
1122 tmp = cmd << 8;
1123 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
1125 mod = 0xc0c2;
1127 pat = 8 * PAT_MEM_OFF;
1128 dst = bpp * (destx + desty * xres_virtual);
1131 * Source is not set for clear.
1133 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
1134 src = bpp * (srcx + srcy * xres_virtual);
1136 if (destx > srcx) {
1137 mod &= ~0x8000;
1138 src += bpp * (width - 1);
1139 dst += bpp * (width - 1);
1140 pat += bpp * 2;
1142 if (desty > srcy) {
1143 mod &= ~0x4000;
1144 src += bpp * (height - 1) * xres_virtual;
1145 dst += bpp * (height - 1) * xres_virtual;
1146 pat += bpp * 4;
1149 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
1152 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
1154 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
1156 tmp = mod << 16;
1157 *(acm + ACM_CONTROL/4) = tmp;
1159 tmp = width | (height << 16);
1161 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
1163 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
1164 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
1167 * No reason to wait for the blitter to finish, it is better
1168 * just to check if it has finished before we use it again.
1170 #if 1
1171 #if 0
1172 while ((*(((volatile unsigned char *)acm) +
1173 (ACM_START_STATUS + 2)) & 1) == 0);
1174 #else
1176 blt_status = *(((volatile unsigned char *)acm) +
1177 (ACM_START_STATUS + 2));
1179 while ((blt_status & 1) == 0);
1180 #endif
1181 #endif
1184 #if 0
1185 void retz3_fill (unsigned short x, unsigned short y, unsigned
1186 short width, unsigned short height,
1187 unsigned short mode, unsigned short color)
1191 #endif
1194 /**************************************************************
1195 * Move cursor to x, y
1197 void retz3_MoveCursor (unsigned short x, unsigned short y)
1199 /* Guess we gotta deal with the cursor at some point */
1203 /* -------------------- Interfaces to hardware functions -------------------- */
1206 static struct fb_hwswitch retz3_switch = {
1207 retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
1208 retz3_getcolreg, retz3_setcolreg, retz3_blank
1212 /* -------------------- Generic routines ------------------------------------ */
1216 * Fill the hardware's `par' structure.
1219 static void retz3_fb_get_par(struct retz3_fb_par *par)
1221 if (current_par_valid)
1222 *par = current_par;
1223 else
1224 fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
1228 static void retz3_fb_set_par(struct retz3_fb_par *par)
1230 current_par = *par;
1231 current_par_valid = 1;
1235 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
1237 int err, activate;
1238 struct retz3_fb_par par;
1240 if ((err = fbhw->decode_var(var, &par)))
1241 return err;
1242 activate = var->activate;
1243 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
1244 retz3_fb_set_par(&par);
1245 fbhw->encode_var(var, &par);
1246 var->activate = activate;
1248 #if 1
1249 retz3_set_video(var, &current_par);
1250 #endif
1251 return 0;
1256 * Default Colormaps
1259 static unsigned short red16[] =
1260 { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
1261 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
1262 static unsigned short green16[] =
1263 { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
1264 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
1265 static unsigned short blue16[] =
1266 { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
1267 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
1270 static struct fb_cmap default_16_colors =
1271 { 0, 16, red16, green16, blue16, NULL };
1274 static struct fb_cmap *get_default_colormap(int bpp)
1276 return &default_16_colors;
1280 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
1281 #define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
1282 ((1<<(width))-1)) : 0))
1284 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
1285 int kspc)
1287 int i, start;
1288 unsigned short *red, *green, *blue, *transp;
1289 unsigned int hred, hgreen, hblue, htransp;
1291 red = cmap->red;
1292 green = cmap->green;
1293 blue = cmap->blue;
1294 transp = cmap->transp;
1295 start = cmap->start;
1297 if (start < 0)
1298 return -EINVAL;
1299 for (i = 0; i < cmap->len; i++) {
1300 if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
1301 return 0;
1302 hred = CNVT_FROMHW(hred, var->red.length);
1303 hgreen = CNVT_FROMHW(hgreen, var->green.length);
1304 hblue = CNVT_FROMHW(hblue, var->blue.length);
1305 htransp = CNVT_FROMHW(htransp, var->transp.length);
1306 if (kspc) {
1307 *red = hred;
1308 *green = hgreen;
1309 *blue = hblue;
1310 if (transp)
1311 *transp = htransp;
1312 } else {
1313 put_user(hred, red);
1314 put_user(hgreen, green);
1315 put_user(hblue, blue);
1316 if (transp)
1317 put_user(htransp, transp);
1319 red++;
1320 green++;
1321 blue++;
1322 if (transp)
1323 transp++;
1325 return 0;
1329 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
1330 int kspc)
1332 int i, start;
1333 unsigned short *red, *green, *blue, *transp;
1334 unsigned int hred, hgreen, hblue, htransp;
1336 red = cmap->red;
1337 green = cmap->green;
1338 blue = cmap->blue;
1339 transp = cmap->transp;
1340 start = cmap->start;
1342 if (start < 0)
1343 return -EINVAL;
1344 for (i = 0; i < cmap->len; i++) {
1345 if (kspc) {
1346 hred = *red;
1347 hgreen = *green;
1348 hblue = *blue;
1349 htransp = transp ? *transp : 0;
1350 } else {
1351 get_user(hred, red);
1352 get_user(hgreen, green);
1353 get_user(hblue, blue);
1354 if (transp)
1355 get_user(htransp, transp);
1356 else
1357 htransp = 0;
1359 hred = CNVT_TOHW(hred, var->red.length);
1360 hgreen = CNVT_TOHW(hgreen, var->green.length);
1361 hblue = CNVT_TOHW(hblue, var->blue.length);
1362 htransp = CNVT_TOHW(htransp, var->transp.length);
1363 red++;
1364 green++;
1365 blue++;
1366 if (transp)
1367 transp++;
1368 if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
1369 return 0;
1371 return 0;
1375 static void do_install_cmap(int con)
1377 if (con != currcon)
1378 return;
1379 if (disp[con].cmap.len)
1380 do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
1381 else
1382 do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
1383 &disp[con].var, 1);
1387 static void memcpy_fs(int fsfromto, void *to, void *from, int len)
1389 switch (fsfromto) {
1390 case 0:
1391 memcpy(to, from, len);
1392 return;
1393 case 1:
1394 copy_from_user(to, from, len);
1395 return;
1396 case 2:
1397 copy_to_user(to, from, len);
1398 return;
1403 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
1405 int size;
1406 int tooff = 0, fromoff = 0;
1408 if (to->start > from->start)
1409 fromoff = to->start-from->start;
1410 else
1411 tooff = from->start-to->start;
1412 size = to->len-tooff;
1413 if (size > from->len-fromoff)
1414 size = from->len-fromoff;
1415 if (size < 0)
1416 return;
1417 size *= sizeof(unsigned short);
1418 memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
1419 memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
1420 memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
1421 if (from->transp && to->transp)
1422 memcpy_fs(fsfromto, to->transp+tooff,
1423 from->transp+fromoff, size);
1427 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
1429 int size = len*sizeof(unsigned short);
1431 if (cmap->len != len) {
1432 if (cmap->red)
1433 kfree(cmap->red);
1434 if (cmap->green)
1435 kfree(cmap->green);
1436 if (cmap->blue)
1437 kfree(cmap->blue);
1438 if (cmap->transp)
1439 kfree(cmap->transp);
1440 cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
1441 cmap->len = 0;
1442 if (!len)
1443 return 0;
1444 if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
1445 return -1;
1446 if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
1447 return -1;
1448 if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
1449 return -1;
1450 if (transp) {
1451 if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
1452 return -1;
1453 } else
1454 cmap->transp = NULL;
1456 cmap->start = 0;
1457 cmap->len = len;
1458 copy_cmap(get_default_colormap(len), cmap, 0);
1459 return 0;
1464 * Get the Fixed Part of the Display
1467 static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
1469 struct retz3_fb_par par;
1470 int error = 0;
1472 if (con == -1)
1473 retz3_fb_get_par(&par);
1474 else
1475 error = fbhw->decode_var(&disp[con].var, &par);
1476 return(error ? error : fbhw->encode_fix(fix, &par));
1481 * Get the User Defined Part of the Display
1484 static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
1486 struct retz3_fb_par par;
1487 int error = 0;
1489 if (con == -1) {
1490 retz3_fb_get_par(&par);
1491 error = fbhw->encode_var(var, &par);
1492 } else
1493 *var = disp[con].var;
1494 return error;
1498 static void retz3_fb_set_disp(int con)
1500 struct fb_fix_screeninfo fix;
1502 retz3_fb_get_fix(&fix, con);
1503 if (con == -1)
1504 con = 0;
1505 disp[con].screen_base = (unsigned char *)fix.smem_start;
1506 disp[con].visual = fix.visual;
1507 disp[con].type = fix.type;
1508 disp[con].type_aux = fix.type_aux;
1509 disp[con].ypanstep = fix.ypanstep;
1510 disp[con].ywrapstep = fix.ywrapstep;
1511 disp[con].can_soft_blank = 1;
1512 disp[con].inverse = z3fb_inverse;
1517 * Set the User Defined Part of the Display
1520 static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
1522 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
1524 if ((err = do_fb_set_var(var, con == currcon)))
1525 return err;
1526 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1527 oldxres = disp[con].var.xres;
1528 oldyres = disp[con].var.yres;
1529 oldvxres = disp[con].var.xres_virtual;
1530 oldvyres = disp[con].var.yres_virtual;
1531 oldbpp = disp[con].var.bits_per_pixel;
1532 disp[con].var = *var;
1533 if (oldxres != var->xres || oldyres != var->yres ||
1534 oldvxres != var->xres_virtual ||
1535 oldvyres != var->yres_virtual ||
1536 oldbpp != var->bits_per_pixel) {
1537 retz3_fb_set_disp(con);
1538 (*fb_info.changevar)(con);
1539 alloc_cmap(&disp[con].cmap, 0, 0);
1540 do_install_cmap(con);
1543 var->activate = 0;
1544 return 0;
1549 * Get the Colormap
1552 static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
1554 if (con == currcon) /* current console? */
1555 return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
1556 else if (disp[con].cmap.len) /* non default colormap? */
1557 copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
1558 else
1559 copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
1560 cmap, kspc ? 0 : 2);
1561 return 0;
1566 * Set the Colormap
1569 static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
1571 int err;
1573 if (!disp[con].cmap.len) { /* no colormap allocated? */
1574 if ((err = alloc_cmap(&disp[con].cmap,
1575 1<<disp[con].var.bits_per_pixel, 0)))
1576 return err;
1578 if (con == currcon) /* current console? */
1579 return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
1580 else
1581 copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
1582 return 0;
1587 * Pan or Wrap the Display
1589 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1592 static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
1594 return -EINVAL;
1599 * RetinaZ3 Frame Buffer Specific ioctls
1602 static int retz3_fb_ioctl(struct inode *inode, struct file *file,
1603 unsigned int cmd, unsigned long arg, int con)
1605 return -EINVAL;
1609 static struct fb_ops retz3_fb_ops = {
1610 retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
1611 retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
1615 int retz3_probe(void)
1617 z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
1618 return(z3_key);
1622 void retz3_video_setup(char *options, int *ints)
1624 char *this_opt;
1625 int i;
1627 fb_info.fontname[0] = '\0';
1629 if (!options || !*options)
1630 return;
1632 for (this_opt = strtok(options, ","); this_opt;
1633 this_opt = strtok(NULL, ",")){
1634 if (!strcmp(this_opt, "inverse")) {
1635 z3fb_inverse = 1;
1636 for (i = 0; i < 16; i++) {
1637 red16[i] = ~red16[i];
1638 green16[i] = ~green16[i];
1639 blue16[i] = ~blue16[i];
1641 } else if (!strncmp(this_opt, "font:", 5))
1642 strcpy(fb_info.fontname, this_opt+5);
1643 else
1644 z3fb_mode = get_video_mode(this_opt);
1650 * Initialization
1653 struct fb_info *retz3_fb_init(long *mem_start)
1655 int err;
1656 struct retz3_fb_par par;
1658 memstart = mem_start;
1660 fbhw = &retz3_switch;
1662 err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
1663 NUM_TOTAL_MODES, retz3_fb_predefined);
1664 if (err < 0)
1665 panic("Cannot register frame buffer\n");
1667 fbhw->init();
1669 if (z3fb_mode == -1)
1670 z3fb_mode = 1;
1672 fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
1673 fbhw->encode_var(&retz3_fb_predefined[0], &par);
1675 strcpy(fb_info.modename, retz3_fb_name);
1676 fb_info.disp = disp;
1677 fb_info.switch_con = &z3fb_switch;
1678 fb_info.updatevar = &z3fb_updatevar;
1679 fb_info.blank = &z3fb_blank;
1680 fb_info.setcmap = &z3fb_setcmap;
1682 do_fb_set_var(&retz3_fb_predefined[0], 0);
1683 retz3_fb_get_var(&disp[0].var, -1);
1684 retz3_fb_set_disp(-1);
1685 do_install_cmap(0);
1687 return &fb_info;
1691 static int z3fb_switch(int con)
1693 /* Do we have to save the colormap? */
1694 if (disp[currcon].cmap.len)
1695 do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
1697 do_fb_set_var(&disp[con].var, 1);
1698 currcon = con;
1699 /* Install new colormap */
1700 do_install_cmap(con);
1701 return 0;
1706 * Update the `var' structure (called by fbcon.c)
1708 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1709 * Since it's called by a kernel driver, no range checking is done.
1712 static int z3fb_updatevar(int con)
1714 return 0;
1719 * Blank the display.
1722 static void z3fb_blank(int blank)
1724 fbhw->blank(blank);
1729 * Set the colormap
1732 static int z3fb_setcmap(struct fb_cmap *cmap, int con)
1734 return(retz3_fb_set_cmap(cmap, 1, con));
1739 * Get a Video Mode
1742 static int get_video_mode(const char *name)
1744 int i;
1746 for (i = 1; i <= NUM_PREDEF_MODES; i++)
1747 if (!strcmp(name, retz3_fb_modenames[i])){
1748 retz3_fb_predefined[0] = retz3_fb_predefined[i];
1749 return i;
1751 return -1;
1754 * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
1755 * RetinaZ3 frame buffer device
1757 * Copyright (C) 1997 Jes Sorensen
1759 * This file is based on the CyberVision64 frame buffer device and
1760 * the generic Cirrus Logic driver.
1762 * cyberfb.c: Copyright (C) 1996 Martin Apel,
1763 * Geert Uytterhoeven
1764 * clgen.c: Copyright (C) 1996 Frank Neumann
1766 * History:
1767 * - 22 Jan 97: Initial work
1768 * - 14 Feb 97: Screen initialization works somewhat, still only
1769 * 8-bit packed pixel is supported.
1771 * This file is subject to the terms and conditions of the GNU General Public
1772 * License. See the file COPYING in the main directory of this archive
1773 * for more details.
1777 #include <linux/kernel.h>
1778 #include <linux/errno.h>
1779 #include <linux/string.h>
1780 #include <linux/mm.h>
1781 #include <linux/tty.h>
1782 #include <linux/malloc.h>
1783 #include <linux/delay.h>
1784 #include <linux/fb.h>
1785 #include <asm/uaccess.h>
1786 #include <asm/system.h>
1787 #include <asm/irq.h>
1788 #include <linux/zorro.h>
1789 #include <asm/pgtable.h>
1791 #include "retz3fb.h"
1793 /* #define DEBUG if(1) */
1794 #define DEBUG if(0)
1797 * Reserve space for one pattern line.
1799 * For the time being we only support 4MB boards!
1802 #define PAT_MEM_SIZE 16*3
1803 #define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
1805 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
1807 struct retz3_fb_par {
1808 int xres;
1809 int yres;
1810 int xres_vir;
1811 int yres_vir;
1812 int xoffset;
1813 int yoffset;
1814 int bpp;
1816 struct fb_bitfield red;
1817 struct fb_bitfield green;
1818 struct fb_bitfield blue;
1819 struct fb_bitfield transp;
1821 int pixclock;
1822 int left_margin; /* time from sync to picture */
1823 int right_margin; /* time from picture to sync */
1824 int upper_margin; /* time from sync to picture */
1825 int lower_margin;
1826 int hsync_len; /* length of horizontal sync */
1827 int vsync_len; /* length of vertical sync */
1828 int vmode;
1831 struct display_data {
1832 long h_total; /* Horizontal Total */
1833 long h_sstart; /* Horizontal Sync Start */
1834 long h_sstop; /* Horizontal Sync Stop */
1835 long h_bstart; /* Horizontal Blank Start */
1836 long h_bstop; /* Horizontal Blank Stop */
1837 long h_dispend; /* Horizontal Display End */
1838 long v_total; /* Vertical Total */
1839 long v_sstart; /* Vertical Sync Start */
1840 long v_sstop; /* Vertical Sync Stop */
1841 long v_bstart; /* Vertical Blank Start */
1842 long v_bstop; /* Vertical Blank Stop */
1843 long v_dispend; /* Horizontal Display End */
1846 static struct retz3_fb_par current_par;
1848 static int current_par_valid = 0;
1849 static int currcon = 0;
1851 static struct display disp[MAX_NR_CONSOLES];
1852 static struct fb_info fb_info;
1854 static int node; /* node of the /dev/fb?current file */
1858 * Switch for Chipset Independency
1861 static struct fb_hwswitch {
1863 /* Initialisation */
1865 int (*init)(void);
1867 /* Display Control */
1869 int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
1870 int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
1871 int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
1872 int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
1873 int *green, unsigned int *blue, unsigned int *transp);
1874 int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
1875 green, unsigned int blue, unsigned int transp);
1876 void (*blank)(int blank);
1877 } *fbhw;
1881 * Frame Buffer Name
1884 static char retz3_fb_name[16] = "RetinaZ3";
1887 static int z3_key = 0;
1888 static unsigned char retz3_color_table [256][4];
1889 static unsigned long z3_mem;
1890 static unsigned long z3_fbmem;
1891 static unsigned long z3_size;
1892 static volatile unsigned char *z3_regs;
1894 static long *memstart;
1898 * Predefined Video Mode Names
1901 static char *retz3_fb_modenames[] = {
1904 * Autodetect (Default) Video Mode
1907 "default",
1910 * Predefined Video Modes
1913 "640x480", /* RetinaZ3 8 bpp */
1914 "800x600", /* RetinaZ3 8 bpp */
1915 "1024x768i",
1916 "640x480-16", /* RetinaZ3 16 bpp */
1917 "640x480-24", /* RetinaZ3 24 bpp */
1920 * Dummy Video Modes
1923 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
1924 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
1925 "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
1928 * User Defined Video Modes
1930 * This doesn't work yet!!
1933 "user0", "user1", "user2", "user3",
1934 "user4", "user5", "user6", "user7"
1938 * A small info on how to convert XFree86 timing values into fb
1939 * timings - by Frank Neumann:
1941 An XFree86 mode line consists of the following fields:
1942 "800x600" 50 800 856 976 1040 600 637 643 666
1943 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
1945 The fields in the fb_var_screeninfo structure are:
1946 unsigned long pixclock; * pixel clock in ps (pico seconds) *
1947 unsigned long left_margin; * time from sync to picture *
1948 unsigned long right_margin; * time from picture to sync *
1949 unsigned long upper_margin; * time from sync to picture *
1950 unsigned long lower_margin;
1951 unsigned long hsync_len; * length of horizontal sync *
1952 unsigned long vsync_len; * length of vertical sync *
1954 1) Pixelclock:
1955 xfree: in MHz
1956 fb: In Picoseconds (ps)
1958 pixclock = 1000000 / DCF
1960 2) horizontal timings:
1961 left_margin = HFL - SH2
1962 right_margin = SH1 - HR
1963 hsync_len = SH2 - SH1
1965 3) vertical timings:
1966 upper_margin = VFL - SV2
1967 lower_margin = SV1 - VR
1968 vsync_len = SV2 - SV1
1970 Good examples for VESA timings can be found in the XFree86 source tree,
1971 under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
1975 * Predefined Video Mode Definitions
1978 static struct fb_var_screeninfo retz3_fb_predefined[] = {
1981 * Autodetect (Default) Video Mode
1984 { 0, },
1987 * Predefined Video Modes
1991 * NB: it is very important to adjust the pixel-clock to the color-depth.
1995 640, 480, 640, 480, 0, 0, 8, 0,
1996 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
1997 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
1998 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
2001 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
2002 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
2005 /* 800 x 600, 8 bpp */
2006 800, 600, 800, 600, 0, 0, 8, 0,
2007 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
2008 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
2009 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
2012 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
2013 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
2016 /* 1024 x 768, 8 bpp, interlaced */
2017 1024, 768, 1024, 768, 0, 0, 8, 0,
2018 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
2019 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
2020 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
2023 640, 480, 640, 480, 0, 0, 16, 0,
2024 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
2025 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
2026 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
2029 640, 480, 640, 480, 0, 0, 24, 0,
2030 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
2031 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
2032 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
2036 * Dummy Video Modes
2039 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
2040 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
2041 { 0, }, { 0, },
2044 * User Defined Video Modes
2047 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
2051 #define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
2052 #define NUM_PREDEF_MODES (5)
2055 static int z3fb_inverse = 0;
2056 static int z3fb_mode = 0;
2060 * Interface used by the world
2063 int retz3_probe(void);
2064 void retz3_video_setup(char *options, int *ints);
2066 static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
2067 static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
2068 static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
2069 static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
2070 static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
2071 static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
2072 static int retz3_fb_ioctl(struct inode *inode, struct file *file,
2073 unsigned int cmd, unsigned long arg, int con);
2077 * Interface to the low level console driver
2080 struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
2081 static int z3fb_switch(int con);
2082 static int z3fb_updatevar(int con);
2083 static void z3fb_blank(int blank);
2084 static int z3fb_setcmap(struct fb_cmap *cmap, int con);
2088 * Accelerated Functions used by the low level console driver
2091 void retz3_bitblt(struct fb_var_screeninfo *scr,
2092 unsigned short curx, unsigned short cury, unsigned
2093 short destx, unsigned short desty, unsigned short
2094 width, unsigned short height, unsigned short cmd,
2095 unsigned short mask);
2096 void retz3_fill(unsigned short x, unsigned short y, unsigned short
2097 width, unsigned short height, unsigned short mode,
2098 unsigned short color);
2101 * Hardware Specific Routines
2104 static int retz3_init(void);
2105 static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
2106 struct retz3_fb_par *par);
2107 static int retz3_decode_var(struct fb_var_screeninfo *var,
2108 struct retz3_fb_par *par);
2109 static int retz3_encode_var(struct fb_var_screeninfo *var,
2110 struct retz3_fb_par *par);
2111 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
2112 unsigned int *green, unsigned int *blue,
2113 unsigned int *transp);
2114 static int retz3_setcolreg(unsigned int regno, unsigned int red,
2115 unsigned int green, unsigned int blue,
2116 unsigned int transp);
2117 static void retz3_blank(int blank);
2121 * Internal routines
2124 static void retz3_fb_get_par(struct retz3_fb_par *par);
2125 static void retz3_fb_set_par(struct retz3_fb_par *par);
2126 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
2127 static struct fb_cmap *get_default_colormap(int bpp);
2128 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
2129 int kspc);
2130 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
2131 int kspc);
2132 static void do_install_cmap(int con);
2133 static void memcpy_fs(int fsfromto, void *to, void *from, int len);
2134 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
2135 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
2136 static void retz3_fb_set_disp(int con);
2137 static int get_video_mode(const char *name);
2140 /* -------------------- Hardware specific routines -------------------------- */
2142 static unsigned short find_fq(unsigned int freq)
2144 unsigned long f;
2145 long tmp;
2146 long prev = 0x7fffffff;
2147 long n2, n1 = 3;
2148 unsigned long m;
2149 unsigned short res = 0;
2151 if (freq <= 31250000)
2152 n2 = 3;
2153 else if (freq <= 62500000)
2154 n2 = 2;
2155 else if (freq <= 125000000)
2156 n2 = 1;
2157 else if (freq <= 250000000)
2158 n2 = 0;
2159 else
2160 return(0);
2163 do {
2164 f = freq >> (10 - n2);
2166 m = (f * n1) / (14318180/1024);
2168 if (m > 129)
2169 break;
2171 tmp = (((m * 14318180) >> n2) / n1) - freq;
2172 if (tmp < 0)
2173 tmp = -tmp;
2175 if (tmp < prev) {
2176 prev = tmp;
2177 res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
2180 } while ( (++n1) <= 21);
2182 return res;
2186 static int retz3_set_video(struct fb_var_screeninfo *var,
2187 struct retz3_fb_par *par)
2189 float freq_f;
2190 long freq;
2192 int xres, hfront, hsync, hback;
2193 int yres, vfront, vsync, vback;
2194 unsigned char tmp;
2195 unsigned short best_freq;
2196 struct display_data data;
2198 short clocksel = 0; /* Apparantly this is always zero */
2200 int bpp = var->bits_per_pixel;
2203 * XXX
2205 if (bpp == 24)
2206 return 0;
2208 if ((bpp != 8) && (bpp != 16) && (bpp != 24))
2209 return -EFAULT;
2211 par->xoffset = 0;
2212 par->yoffset = 0;
2214 xres = var->xres * bpp / 4;
2215 hfront = var->right_margin * bpp / 4;
2216 hsync = var->hsync_len * bpp / 4;
2217 hback = var->left_margin * bpp / 4;
2219 if (var->vmode & FB_VMODE_DOUBLE)
2221 yres = var->yres * 2;
2222 vfront = var->lower_margin * 2;
2223 vsync = var->vsync_len * 2;
2224 vback = var->upper_margin * 2;
2226 else if (var->vmode & FB_VMODE_INTERLACED)
2228 yres = (var->yres + 1) / 2;
2229 vfront = (var->lower_margin + 1) / 2;
2230 vsync = (var->vsync_len + 1) / 2;
2231 vback = (var->upper_margin + 1) / 2;
2233 else
2235 yres = var->yres; /* -1 ? */
2236 vfront = var->lower_margin;
2237 vsync = var->vsync_len;
2238 vback = var->upper_margin;
2241 data.h_total = (hback / 8) + (xres / 8)
2242 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
2243 data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
2244 data.h_bstart = xres / 8 /* + 1 */;
2246 data.h_bstop = data.h_total+1 + 2 + 1;
2247 data.h_sstart = (xres / 8) + (hfront / 8) + 1;
2248 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
2250 data.v_total = yres + vfront + vsync + vback - 1;
2252 data.v_dispend = yres - 1;
2253 data.v_bstart = yres;
2255 data.v_bstop = data.v_total;
2256 data.v_sstart = yres + vfront - 1 - 2;
2257 data.v_sstop = yres + vfront + vsync - 1;
2259 #if 0 /* testing */
2261 printk("HBS: %i\n", data.h_bstart);
2262 printk("HSS: %i\n", data.h_sstart);
2263 printk("HSE: %i\n", data.h_sstop);
2264 printk("HBE: %i\n", data.h_bstop);
2265 printk("HT: %i\n", data.h_total);
2267 printk("hsync: %i\n", hsync);
2268 printk("hfront: %i\n", hfront);
2269 printk("hback: %i\n", hback);
2271 printk("VBS: %i\n", data.v_bstart);
2272 printk("VSS: %i\n", data.v_sstart);
2273 printk("VSE: %i\n", data.v_sstop);
2274 printk("VBE: %i\n", data.v_bstop);
2275 printk("VT: %i\n", data.v_total);
2277 printk("vsync: %i\n", vsync);
2278 printk("vfront: %i\n", vfront);
2279 printk("vback: %i\n", vback);
2280 #endif
2282 if (data.v_total >= 1024)
2283 printk("MAYDAY: v_total >= 1024; bailing out!\n");
2285 reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
2286 reg_w(GREG_FEATURE_CONTROL_W, 0x00);
2288 seq_w(SEQ_RESET, 0x00);
2289 seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
2292 * CLOCKING_MODE bits:
2293 * 2: This one is only set for certain text-modes, wonder if
2294 * it may be for EGA-lines? (it was referred to as CLKDIV2)
2295 * (The CL drivers sets it to 0x21 with the comment:
2296 * FullBandwidth (video off) and 8/9 dot clock)
2298 seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
2300 seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
2301 seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
2302 seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
2303 seq_w(SEQ_RESET, 0x01);
2304 seq_w(SEQ_RESET, 0x03);
2306 seq_w(SEQ_EXTENDED_ENABLE, 0x05);
2308 seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
2309 seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
2310 seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
2311 seq_w(SEQ_LINEAR_0, 0x4a);
2312 seq_w(SEQ_LINEAR_1, 0x00);
2314 seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
2315 seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
2316 seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
2319 * The lower 4 bits (0-3) are used to set the font-width for
2320 * text-mode - DON'T try to set this for gfx-mode.
2322 seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
2323 seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
2326 * Extended Pixel Control:
2327 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
2328 * bit 1: (Packed/Nibble Pixel Format ?)
2329 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
2331 seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
2333 seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
2334 seq_w(SEQ_COLOR_EXP_WFG, 0x01);
2335 seq_w(SEQ_COLOR_EXP_WBG, 0x00);
2336 seq_w(SEQ_EXT_RW_CONTROL, 0x00);
2337 seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
2338 seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
2339 seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
2340 seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
2341 seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
2342 seq_w(SEQ_CRC_CONTROL, 0x00);
2343 seq_w(SEQ_PERF_SELECT, 0x10);
2344 seq_w(SEQ_ACM_APERTURE_1, 0x00);
2345 seq_w(SEQ_ACM_APERTURE_2, 0x30);
2346 seq_w(SEQ_ACM_APERTURE_3, 0x00);
2347 seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
2350 /* unlock register CRT0..CRT7 */
2351 crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
2353 /* Zuerst zu schreibende Werte nur per printk ausgeben */
2354 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
2355 crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
2357 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
2358 crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
2360 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
2361 crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
2363 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
2364 crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
2366 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
2367 crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
2369 tmp = (data.h_sstop & 0x1f);
2370 if (data.h_bstop & 0x20)
2371 tmp |= 0x80;
2372 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
2373 crt_w(CRT_END_HOR_RETR, tmp);
2375 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
2376 crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
2378 tmp = 0x10; /* LineCompare bit #9 */
2379 if (data.v_total & 256)
2380 tmp |= 0x01;
2381 if (data.v_dispend & 256)
2382 tmp |= 0x02;
2383 if (data.v_sstart & 256)
2384 tmp |= 0x04;
2385 if (data.v_bstart & 256)
2386 tmp |= 0x08;
2387 if (data.v_total & 512)
2388 tmp |= 0x20;
2389 if (data.v_dispend & 512)
2390 tmp |= 0x40;
2391 if (data.v_sstart & 512)
2392 tmp |= 0x80;
2393 DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
2394 crt_w(CRT_OVERFLOW, tmp);
2396 crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
2398 tmp = 0x40; /* LineCompare bit #8 */
2399 if (data.v_bstart & 512)
2400 tmp |= 0x20;
2401 if (var->vmode & FB_VMODE_DOUBLE)
2402 tmp |= 0x80;
2403 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
2404 crt_w(CRT_MAX_SCAN_LINE, tmp);
2406 crt_w(CRT_CURSOR_START, 0x00);
2407 crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
2409 crt_w(CRT_START_ADDR_HIGH, 0x00);
2410 crt_w(CRT_START_ADDR_LOW, 0x00);
2412 crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
2413 crt_w(CRT_CURSOR_LOC_LOW, 0x00);
2415 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
2416 crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
2418 #if 1
2419 /* 5 refresh cycles per scanline */
2420 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
2421 crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
2422 #else
2423 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
2424 crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
2425 #endif
2426 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
2427 crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
2429 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
2430 crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
2432 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
2433 crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
2435 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
2436 crt_w(CRT_MODE_CONTROL, 0xe3);
2438 DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
2439 crt_w(CRT_LINE_COMPARE, 0xff);
2441 tmp = (var->xres_virtual / 8) * (bpp / 8);
2442 crt_w(CRT_OFFSET, tmp);
2444 crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
2446 tmp = 0x20; /* Enable extended end bits */
2447 if (data.h_total & 0x100)
2448 tmp |= 0x01;
2449 if ((data.h_dispend) & 0x100)
2450 tmp |= 0x02;
2451 if (data.h_bstart & 0x100)
2452 tmp |= 0x04;
2453 if (data.h_sstart & 0x100)
2454 tmp |= 0x08;
2455 if (var->vmode & FB_VMODE_INTERLACED)
2456 tmp |= 0x10;
2457 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
2458 crt_w(CRT_EXT_HOR_TIMING1, tmp);
2460 tmp = 0x00;
2461 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
2462 tmp |= 0x10;
2463 crt_w(CRT_EXT_START_ADDR, tmp);
2465 tmp = 0x00;
2466 if (data.h_total & 0x200)
2467 tmp |= 0x01;
2468 if ((data.h_dispend) & 0x200)
2469 tmp |= 0x02;
2470 if (data.h_bstart & 0x200)
2471 tmp |= 0x04;
2472 if (data.h_sstart & 0x200)
2473 tmp |= 0x08;
2474 tmp |= ((data.h_bstop & 0xc0) >> 2);
2475 tmp |= ((data.h_sstop & 0x60) << 1);
2476 crt_w(CRT_EXT_HOR_TIMING2, tmp);
2477 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
2479 tmp = 0x10; /* Line compare bit 10 */
2480 if (data.v_total & 0x400)
2481 tmp |= 0x01;
2482 if ((data.v_dispend) & 0x400)
2483 tmp |= 0x02;
2484 if (data.v_bstart & 0x400)
2485 tmp |= 0x04;
2486 if (data.v_sstart & 0x400)
2487 tmp |= 0x08;
2488 tmp |= ((data.v_bstop & 0x300) >> 3);
2489 if (data.v_sstop & 0x10)
2490 tmp |= 0x80;
2491 crt_w(CRT_EXT_VER_TIMING, tmp);
2492 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
2494 crt_w(CRT_MONITOR_POWER, 0x00);
2497 * Convert from ps to Hz.
2499 freq_f = (1.0/(float)var->pixclock) * 1000000000;
2500 freq = ((long)freq_f) * 1000;
2502 best_freq = find_fq(freq);
2503 pll_w(0x02, best_freq);
2504 best_freq = find_fq(61000000);
2505 pll_w(0x0a, best_freq);
2506 pll_w(0x0e, 0x22);
2508 gfx_w(GFX_SET_RESET, 0x00);
2509 gfx_w(GFX_ENABLE_SET_RESET, 0x00);
2510 gfx_w(GFX_COLOR_COMPARE, 0x00);
2511 gfx_w(GFX_DATA_ROTATE, 0x00);
2512 gfx_w(GFX_READ_MAP_SELECT, 0x00);
2513 gfx_w(GFX_GRAPHICS_MODE, 0x00);
2514 gfx_w(GFX_MISC, 0x05);
2515 gfx_w(GFX_COLOR_XCARE, 0x0f);
2516 gfx_w(GFX_BITMASK, 0xff);
2518 reg_r(ACT_ADDRESS_RESET);
2519 attr_w(ACT_PALETTE0 , 0x00);
2520 attr_w(ACT_PALETTE1 , 0x01);
2521 attr_w(ACT_PALETTE2 , 0x02);
2522 attr_w(ACT_PALETTE3 , 0x03);
2523 attr_w(ACT_PALETTE4 , 0x04);
2524 attr_w(ACT_PALETTE5 , 0x05);
2525 attr_w(ACT_PALETTE6 , 0x06);
2526 attr_w(ACT_PALETTE7 , 0x07);
2527 attr_w(ACT_PALETTE8 , 0x08);
2528 attr_w(ACT_PALETTE9 , 0x09);
2529 attr_w(ACT_PALETTE10, 0x0a);
2530 attr_w(ACT_PALETTE11, 0x0b);
2531 attr_w(ACT_PALETTE12, 0x0c);
2532 attr_w(ACT_PALETTE13, 0x0d);
2533 attr_w(ACT_PALETTE14, 0x0e);
2534 attr_w(ACT_PALETTE15, 0x0f);
2535 reg_r(ACT_ADDRESS_RESET);
2537 attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
2539 attr_w(ACT_OVERSCAN_COLOR, 0x00);
2540 attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
2541 attr_w(ACT_HOR_PEL_PANNING, 0x00);
2542 attr_w(ACT_COLOR_SELECT, 0x00);
2544 reg_r(ACT_ADDRESS_RESET);
2545 reg_w(ACT_DATA, 0x20);
2547 reg_w(VDAC_MASK, 0xff);
2550 * Extended palette adressing ???
2552 switch (bpp){
2553 case 8:
2554 reg_w(0x83c6, 0x00);
2555 break;
2556 case 16:
2557 reg_w(0x83c6, 0x60);
2558 break;
2559 case 24:
2560 reg_w(0x83c6, 0xe0);
2561 break;
2562 default:
2563 printk("Illegal color-depth: %i\n", bpp);
2566 reg_w(VDAC_ADDRESS, 0x00);
2568 seq_w(SEQ_MAP_MASK, 0x0f );
2570 return 0;
2574 * Initialization
2576 * Set the default video mode for this chipset. If a video mode was
2577 * specified on the command line, it will override the default mode.
2580 static int retz3_init(void)
2582 int i;
2583 #if 0
2584 volatile unsigned long *CursorBase;
2585 #endif
2586 unsigned long board_addr, board_size;
2587 struct ConfigDev *cd;
2589 cd = zorro_get_board (z3_key);
2590 zorro_config_board (z3_key, 0);
2591 board_addr = (unsigned long)cd->cd_BoardAddr;
2592 board_size = (unsigned long)cd->cd_BoardSize;
2594 for (i = 0; i < 256; i++){
2595 for (i = 0; i < 256; i++){
2596 retz3_color_table [i][0] = i;
2597 retz3_color_table [i][1] = i;
2598 retz3_color_table [i][2] = i;
2599 retz3_color_table [i][3] = 0;
2603 *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
2605 z3_mem = kernel_map (board_addr, board_size,
2606 KERNELMAP_NOCACHE_SER, memstart);
2608 z3_regs = (char*) z3_mem;
2609 z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
2611 /* Get memory size - for now we asume its a 4MB board */
2613 z3_size = 0x00400000; /* 4 MB */
2615 memset ((char*)z3_fbmem, 0, z3_size);
2617 /* Disable hardware cursor */
2619 seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
2622 #if 0
2623 /* Initialize hardware cursor */
2624 CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
2625 for (i=0; i < 8; i++){
2626 *(CursorBase +(i*4)) = 0xffffff00;
2627 *(CursorBase+1+(i*4)) = 0xffff0000;
2628 *(CursorBase+2+(i*4)) = 0xffff0000;
2629 *(CursorBase+3+(i*4)) = 0xffff0000;
2631 for (i=8; i < 64; i++){
2632 *(CursorBase +(i*4)) = 0xffff0000;
2633 *(CursorBase+1+(i*4)) = 0xffff0000;
2634 *(CursorBase+2+(i*4)) = 0xffff0000;
2635 *(CursorBase+3+(i*4)) = 0xffff0000;
2637 #endif
2639 retz3_setcolreg (255, 56, 100, 160, 0);
2640 retz3_setcolreg (254, 0, 0, 0, 0);
2642 return 0;
2647 * This function should fill in the `fix' structure based on the
2648 * values in the `par' structure.
2651 static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
2652 struct retz3_fb_par *par)
2654 int i;
2656 strcpy(fix->id, retz3_fb_name);
2657 fix->smem_start = z3_fbmem;
2658 fix->smem_len = z3_size;
2660 fix->type = FB_TYPE_PACKED_PIXELS;
2661 fix->type_aux = 0;
2662 if (par->bpp == 8)
2663 fix->visual = FB_VISUAL_PSEUDOCOLOR;
2664 else
2665 fix->visual = FB_VISUAL_DIRECTCOLOR;
2667 fix->xpanstep = 0;
2668 fix->ypanstep = 0;
2669 fix->ywrapstep = 0;
2670 fix->line_length = 0;
2672 for (i = 0; i < arraysize(fix->reserved); i++)
2673 fix->reserved[i] = 0;
2675 return 0;
2680 * Get the video params out of `var'. If a value doesn't fit, round
2681 * it up, if it's too big, return -EINVAL.
2684 static int retz3_decode_var(struct fb_var_screeninfo *var,
2685 struct retz3_fb_par *par)
2687 par->xres = var->xres;
2688 par->yres = var->yres;
2689 par->xres_vir = var->xres_virtual;
2690 par->yres_vir = var->yres_virtual;
2691 par->bpp = var->bits_per_pixel;
2692 par->pixclock = var->pixclock;
2693 par->vmode = var->vmode;
2695 par->red = var->red;
2696 par->green = var->green;
2697 par->blue = var->blue;
2698 par->transp = var->transp;
2700 par->left_margin = var->left_margin;
2701 par->right_margin = var->right_margin;
2702 par->upper_margin = var->upper_margin;
2703 par->lower_margin = var->lower_margin;
2704 par->hsync_len = var->hsync_len;
2705 par->vsync_len = var->vsync_len;
2707 return 0;
2712 * Fill the `var' structure based on the values in `par' and maybe
2713 * other values read out of the hardware.
2716 static int retz3_encode_var(struct fb_var_screeninfo *var,
2717 struct retz3_fb_par *par)
2719 int i;
2721 var->xres = par->xres;
2722 var->yres = par->yres;
2723 var->xres_virtual = par->xres_vir;
2724 var->yres_virtual = par->yres_vir;
2725 var->xoffset = 0;
2726 var->yoffset = 0;
2728 var->bits_per_pixel = par->bpp;
2729 var->grayscale = 0;
2731 var->red = par->red;
2732 var->green = par->green;
2733 var->blue = par->blue;
2734 var->transp = par->transp;
2736 var->nonstd = 0;
2737 var->activate = 0;
2739 var->height = -1;
2740 var->width = -1;
2742 var->accel = FB_ACCEL_RETINAZ3;
2744 var->pixclock = par->pixclock;
2746 var->sync = 0; /* ??? */
2747 var->left_margin = par->left_margin;
2748 var->right_margin = par->right_margin;
2749 var->upper_margin = par->upper_margin;
2750 var->lower_margin = par->lower_margin;
2751 var->hsync_len = par->hsync_len;
2752 var->vsync_len = par->vsync_len;
2754 for (i = 0; i < arraysize(var->reserved); i++)
2755 var->reserved[i] = 0;
2757 var->vmode = par->vmode;
2758 return 0;
2763 * Set a single color register. The values supplied are already
2764 * rounded down to the hardware's capabilities (according to the
2765 * entries in the var structure). Return != 0 for invalid regno.
2768 static int retz3_setcolreg(unsigned int regno, unsigned int red,
2769 unsigned int green, unsigned int blue,
2770 unsigned int transp)
2772 /* We'll get to this */
2774 if (regno > 255)
2775 return 1;
2777 retz3_color_table [regno][0] = red & 0xff;
2778 retz3_color_table [regno][1] = green & 0xff;
2779 retz3_color_table [regno][2] = blue & 0xff;
2780 retz3_color_table [regno][3] = transp;
2782 reg_w(VDAC_ADDRESS_W, regno);
2783 reg_w(VDAC_DATA, (red & 0xff) >> 2);
2784 reg_w(VDAC_DATA, (green & 0xff) >> 2);
2785 reg_w(VDAC_DATA, (blue & 0xff) >> 2);
2787 return 0;
2792 * Read a single color register and split it into
2793 * colors/transparent. Return != 0 for invalid regno.
2796 static int retz3_getcolreg(unsigned int regno, unsigned int *red,
2797 unsigned int *green, unsigned int *blue,
2798 unsigned int *transp)
2800 if (regno > 255)
2801 return 1;
2802 *red = retz3_color_table [regno][0];
2803 *green = retz3_color_table [regno][1];
2804 *blue = retz3_color_table [regno][2];
2805 *transp = retz3_color_table [regno][3];
2806 return 0;
2811 * (Un)Blank the screen
2814 void retz3_blank(int blank)
2816 int i;
2818 if (blank)
2819 for (i = 0; i < 256; i++){
2820 reg_w(VDAC_ADDRESS_W, i);
2821 reg_w(VDAC_DATA, 0);
2822 reg_w(VDAC_DATA, 0);
2823 reg_w(VDAC_DATA, 0);
2825 else
2826 for (i = 0; i < 256; i++){
2827 reg_w(VDAC_ADDRESS_W, i);
2828 reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
2829 reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
2830 reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
2835 void retz3_bitblt (struct fb_var_screeninfo *var,
2836 unsigned short srcx, unsigned short srcy, unsigned
2837 short destx, unsigned short desty, unsigned short
2838 width, unsigned short height, unsigned short cmd,
2839 unsigned short mask)
2842 volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
2843 unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
2845 unsigned short mod;
2846 unsigned long tmp;
2847 unsigned long pat, src, dst;
2848 unsigned char blt_status;
2850 int i, xres_virtual = var->xres_virtual;
2851 short bpp = (var->bits_per_pixel & 0xff);
2853 if (bpp < 8)
2854 bpp = 8;
2856 tmp = mask | (mask << 16);
2858 #if 0
2860 * Check for blitter finished before we start messing with the
2861 * pattern.
2864 blt_status = *(((volatile unsigned char *)acm) +
2865 (ACM_START_STATUS + 2));
2866 }while ((blt_status & 1) == 0);
2867 #endif
2869 i = 0;
2871 *pattern++ = tmp;
2872 }while(i++ < bpp/4);
2874 tmp = cmd << 8;
2875 *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
2877 mod = 0xc0c2;
2879 pat = 8 * PAT_MEM_OFF;
2880 dst = bpp * (destx + desty * xres_virtual);
2883 * Source is not set for clear.
2885 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
2886 src = bpp * (srcx + srcy * xres_virtual);
2888 if (destx > srcx) {
2889 mod &= ~0x8000;
2890 src += bpp * (width - 1);
2891 dst += bpp * (width - 1);
2892 pat += bpp * 2;
2894 if (desty > srcy) {
2895 mod &= ~0x4000;
2896 src += bpp * (height - 1) * xres_virtual;
2897 dst += bpp * (height - 1) * xres_virtual;
2898 pat += bpp * 4;
2901 *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
2904 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
2906 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
2908 tmp = mod << 16;
2909 *(acm + ACM_CONTROL/4) = tmp;
2911 tmp = width | (height << 16);
2913 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
2915 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
2916 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
2919 * No reason to wait for the blitter to finish, it is better
2920 * just to check if it has finished before we use it again.
2922 #if 1
2923 #if 0
2924 while ((*(((volatile unsigned char *)acm) +
2925 (ACM_START_STATUS + 2)) & 1) == 0);
2926 #else
2928 blt_status = *(((volatile unsigned char *)acm) +
2929 (ACM_START_STATUS + 2));
2931 while ((blt_status & 1) == 0);
2932 #endif
2933 #endif
2936 #if 0
2937 void retz3_fill (unsigned short x, unsigned short y, unsigned
2938 short width, unsigned short height,
2939 unsigned short mode, unsigned short color)
2943 #endif
2946 /**************************************************************
2947 * Move cursor to x, y
2949 void retz3_MoveCursor (unsigned short x, unsigned short y)
2951 /* Guess we gotta deal with the cursor at some point */
2955 /* -------------------- Interfaces to hardware functions -------------------- */
2958 static struct fb_hwswitch retz3_switch = {
2959 retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
2960 retz3_getcolreg, retz3_setcolreg, retz3_blank
2964 /* -------------------- Generic routines ------------------------------------ */
2968 * Fill the hardware's `par' structure.
2971 static void retz3_fb_get_par(struct retz3_fb_par *par)
2973 if (current_par_valid)
2974 *par = current_par;
2975 else
2976 fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
2980 static void retz3_fb_set_par(struct retz3_fb_par *par)
2982 current_par = *par;
2983 current_par_valid = 1;
2987 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
2989 int err, activate;
2990 struct retz3_fb_par par;
2992 if ((err = fbhw->decode_var(var, &par)))
2993 return err;
2994 activate = var->activate;
2995 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
2996 retz3_fb_set_par(&par);
2997 fbhw->encode_var(var, &par);
2998 var->activate = activate;
3000 #if 1
3001 retz3_set_video(var, &current_par);
3002 #endif
3003 return 0;
3008 * Default Colormaps
3011 static unsigned short red16[] =
3012 { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
3013 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
3014 static unsigned short green16[] =
3015 { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
3016 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
3017 static unsigned short blue16[] =
3018 { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
3019 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
3022 static struct fb_cmap default_16_colors =
3023 { 0, 16, red16, green16, blue16, NULL };
3026 static struct fb_cmap *get_default_colormap(int bpp)
3028 return &default_16_colors;
3032 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
3033 #define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
3034 ((1<<(width))-1)) : 0))
3036 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
3037 int kspc)
3039 int i, start;
3040 unsigned short *red, *green, *blue, *transp;
3041 unsigned int hred, hgreen, hblue, htransp;
3043 red = cmap->red;
3044 green = cmap->green;
3045 blue = cmap->blue;
3046 transp = cmap->transp;
3047 start = cmap->start;
3049 if (start < 0)
3050 return -EINVAL;
3051 for (i = 0; i < cmap->len; i++) {
3052 if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
3053 return 0;
3054 hred = CNVT_FROMHW(hred, var->red.length);
3055 hgreen = CNVT_FROMHW(hgreen, var->green.length);
3056 hblue = CNVT_FROMHW(hblue, var->blue.length);
3057 htransp = CNVT_FROMHW(htransp, var->transp.length);
3058 if (kspc) {
3059 *red = hred;
3060 *green = hgreen;
3061 *blue = hblue;
3062 if (transp)
3063 *transp = htransp;
3064 } else {
3065 put_user(hred, red);
3066 put_user(hgreen, green);
3067 put_user(hblue, blue);
3068 if (transp)
3069 put_user(htransp, transp);
3071 red++;
3072 green++;
3073 blue++;
3074 if (transp)
3075 transp++;
3077 return 0;
3081 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
3082 int kspc)
3084 int i, start;
3085 unsigned short *red, *green, *blue, *transp;
3086 unsigned int hred, hgreen, hblue, htransp;
3088 red = cmap->red;
3089 green = cmap->green;
3090 blue = cmap->blue;
3091 transp = cmap->transp;
3092 start = cmap->start;
3094 if (start < 0)
3095 return -EINVAL;
3096 for (i = 0; i < cmap->len; i++) {
3097 if (kspc) {
3098 hred = *red;
3099 hgreen = *green;
3100 hblue = *blue;
3101 htransp = transp ? *transp : 0;
3102 } else {
3103 get_user(hred, red);
3104 get_user(hgreen, green);
3105 get_user(hblue, blue);
3106 if (transp)
3107 get_user(htransp, transp);
3108 else
3109 htransp = 0;
3111 hred = CNVT_TOHW(hred, var->red.length);
3112 hgreen = CNVT_TOHW(hgreen, var->green.length);
3113 hblue = CNVT_TOHW(hblue, var->blue.length);
3114 htransp = CNVT_TOHW(htransp, var->transp.length);
3115 red++;
3116 green++;
3117 blue++;
3118 if (transp)
3119 transp++;
3120 if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
3121 return 0;
3123 return 0;
3127 static void do_install_cmap(int con)
3129 if (con != currcon)
3130 return;
3131 if (disp[con].cmap.len)
3132 do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
3133 else
3134 do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
3135 &disp[con].var, 1);
3139 static void memcpy_fs(int fsfromto, void *to, void *from, int len)
3141 switch (fsfromto) {
3142 case 0:
3143 memcpy(to, from, len);
3144 return;
3145 case 1:
3146 copy_from_user(to, from, len);
3147 return;
3148 case 2:
3149 copy_to_user(to, from, len);
3150 return;
3155 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
3157 int size;
3158 int tooff = 0, fromoff = 0;
3160 if (to->start > from->start)
3161 fromoff = to->start-from->start;
3162 else
3163 tooff = from->start-to->start;
3164 size = to->len-tooff;
3165 if (size > from->len-fromoff)
3166 size = from->len-fromoff;
3167 if (size < 0)
3168 return;
3169 size *= sizeof(unsigned short);
3170 memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
3171 memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
3172 memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
3173 if (from->transp && to->transp)
3174 memcpy_fs(fsfromto, to->transp+tooff,
3175 from->transp+fromoff, size);
3179 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
3181 int size = len*sizeof(unsigned short);
3183 if (cmap->len != len) {
3184 if (cmap->red)
3185 kfree(cmap->red);
3186 if (cmap->green)
3187 kfree(cmap->green);
3188 if (cmap->blue)
3189 kfree(cmap->blue);
3190 if (cmap->transp)
3191 kfree(cmap->transp);
3192 cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
3193 cmap->len = 0;
3194 if (!len)
3195 return 0;
3196 if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
3197 return -1;
3198 if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
3199 return -1;
3200 if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
3201 return -1;
3202 if (transp) {
3203 if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
3204 return -1;
3205 } else
3206 cmap->transp = NULL;
3208 cmap->start = 0;
3209 cmap->len = len;
3210 copy_cmap(get_default_colormap(len), cmap, 0);
3211 return 0;
3216 * Get the Fixed Part of the Display
3219 static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
3221 struct retz3_fb_par par;
3222 int error = 0;
3224 if (con == -1)
3225 retz3_fb_get_par(&par);
3226 else
3227 error = fbhw->decode_var(&disp[con].var, &par);
3228 return(error ? error : fbhw->encode_fix(fix, &par));
3233 * Get the User Defined Part of the Display
3236 static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
3238 struct retz3_fb_par par;
3239 int error = 0;
3241 if (con == -1) {
3242 retz3_fb_get_par(&par);
3243 error = fbhw->encode_var(var, &par);
3244 } else
3245 *var = disp[con].var;
3246 return error;
3250 static void retz3_fb_set_disp(int con)
3252 struct fb_fix_screeninfo fix;
3254 retz3_fb_get_fix(&fix, con);
3255 if (con == -1)
3256 con = 0;
3257 disp[con].screen_base = (unsigned char *)fix.smem_start;
3258 disp[con].visual = fix.visual;
3259 disp[con].type = fix.type;
3260 disp[con].type_aux = fix.type_aux;
3261 disp[con].ypanstep = fix.ypanstep;
3262 disp[con].ywrapstep = fix.ywrapstep;
3263 disp[con].can_soft_blank = 1;
3264 disp[con].inverse = z3fb_inverse;
3269 * Set the User Defined Part of the Display
3272 static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
3274 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
3276 if ((err = do_fb_set_var(var, con == currcon)))
3277 return err;
3278 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
3279 oldxres = disp[con].var.xres;
3280 oldyres = disp[con].var.yres;
3281 oldvxres = disp[con].var.xres_virtual;
3282 oldvyres = disp[con].var.yres_virtual;
3283 oldbpp = disp[con].var.bits_per_pixel;
3284 disp[con].var = *var;
3285 if (oldxres != var->xres || oldyres != var->yres ||
3286 oldvxres != var->xres_virtual ||
3287 oldvyres != var->yres_virtual ||
3288 oldbpp != var->bits_per_pixel) {
3289 retz3_fb_set_disp(con);
3290 (*fb_info.changevar)(con);
3291 alloc_cmap(&disp[con].cmap, 0, 0);
3292 do_install_cmap(con);
3295 var->activate = 0;
3296 return 0;
3301 * Get the Colormap
3304 static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
3306 if (con == currcon) /* current console? */
3307 return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
3308 else if (disp[con].cmap.len) /* non default colormap? */
3309 copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
3310 else
3311 copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
3312 cmap, kspc ? 0 : 2);
3313 return 0;
3318 * Set the Colormap
3321 static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
3323 int err;
3325 if (!disp[con].cmap.len) { /* no colormap allocated? */
3326 if ((err = alloc_cmap(&disp[con].cmap,
3327 1<<disp[con].var.bits_per_pixel, 0)))
3328 return err;
3330 if (con == currcon) /* current console? */
3331 return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
3332 else
3333 copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
3334 return 0;
3339 * Pan or Wrap the Display
3341 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3344 static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
3346 return -EINVAL;
3351 * RetinaZ3 Frame Buffer Specific ioctls
3354 static int retz3_fb_ioctl(struct inode *inode, struct file *file,
3355 unsigned int cmd, unsigned long arg, int con)
3357 return -EINVAL;
3361 static struct fb_ops retz3_fb_ops = {
3362 retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
3363 retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
3367 int retz3_probe(void)
3369 z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
3370 return(z3_key);
3374 void retz3_video_setup(char *options, int *ints)
3376 char *this_opt;
3377 int i;
3379 fb_info.fontname[0] = '\0';
3381 if (!options || !*options)
3382 return;
3384 for (this_opt = strtok(options, ","); this_opt;
3385 this_opt = strtok(NULL, ",")){
3386 if (!strcmp(this_opt, "inverse")) {
3387 z3fb_inverse = 1;
3388 for (i = 0; i < 16; i++) {
3389 red16[i] = ~red16[i];
3390 green16[i] = ~green16[i];
3391 blue16[i] = ~blue16[i];
3393 } else if (!strncmp(this_opt, "font:", 5))
3394 strcpy(fb_info.fontname, this_opt+5);
3395 else
3396 z3fb_mode = get_video_mode(this_opt);
3402 * Initialization
3405 struct fb_info *retz3_fb_init(long *mem_start)
3407 int err;
3408 struct retz3_fb_par par;
3410 memstart = mem_start;
3412 fbhw = &retz3_switch;
3414 err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
3415 NUM_TOTAL_MODES, retz3_fb_predefined);
3416 if (err < 0)
3417 panic("Cannot register frame buffer\n");
3419 fbhw->init();
3421 if (z3fb_mode == -1)
3422 z3fb_mode = 1;
3424 fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
3425 fbhw->encode_var(&retz3_fb_predefined[0], &par);
3427 strcpy(fb_info.modename, retz3_fb_name);
3428 fb_info.disp = disp;
3429 fb_info.switch_con = &z3fb_switch;
3430 fb_info.updatevar = &z3fb_updatevar;
3431 fb_info.blank = &z3fb_blank;
3432 fb_info.setcmap = &z3fb_setcmap;
3434 do_fb_set_var(&retz3_fb_predefined[0], 0);
3435 retz3_fb_get_var(&disp[0].var, -1);
3436 retz3_fb_set_disp(-1);
3437 do_install_cmap(0);
3439 return &fb_info;
3443 static int z3fb_switch(int con)
3445 /* Do we have to save the colormap? */
3446 if (disp[currcon].cmap.len)
3447 do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
3449 do_fb_set_var(&disp[con].var, 1);
3450 currcon = con;
3451 /* Install new colormap */
3452 do_install_cmap(con);
3453 return 0;
3458 * Update the `var' structure (called by fbcon.c)
3460 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
3461 * Since it's called by a kernel driver, no range checking is done.
3464 static int z3fb_updatevar(int con)
3466 return 0;
3471 * Blank the display.
3474 static void z3fb_blank(int blank)
3476 fbhw->blank(blank);
3481 * Set the colormap
3484 static int z3fb_setcmap(struct fb_cmap *cmap, int con)
3486 return(retz3_fb_set_cmap(cmap, 1, con));
3491 * Get a Video Mode
3494 static int get_video_mode(const char *name)
3496 int i;
3498 for (i = 1; i <= NUM_PREDEF_MODES; i++)
3499 if (!strcmp(name, retz3_fb_modenames[i])){
3500 retz3_fb_predefined[0] = retz3_fb_predefined[i];
3501 return i;
3503 return -1;