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,
12 * clgen.c: Copyright (C) 1996 Frank Neumann
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
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/string.h>
29 #include <linux/tty.h>
30 #include <linux/malloc.h>
31 #include <linux/delay.h>
33 #include <asm/uaccess.h>
34 #include <asm/system.h>
36 #include <linux/zorro.h>
37 #include <asm/pgtable.h>
41 /* #define DEBUG if(1) */
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)))
64 struct fb_bitfield red
;
65 struct fb_bitfield green
;
66 struct fb_bitfield blue
;
67 struct fb_bitfield transp
;
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 */
74 int hsync_len
; /* length of horizontal sync */
75 int vsync_len
; /* length of vertical sync */
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
{
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
);
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
158 * Predefined Video Modes
161 "640x480", /* RetinaZ3 8 bpp */
162 "800x600", /* RetinaZ3 8 bpp */
164 "640x480-16", /* RetinaZ3 16 bpp */
165 "640x480-24", /* RetinaZ3 24 bpp */
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 *
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
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
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
287 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
288 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 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
);
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
,
378 static int do_fb_set_cmap(struct fb_cmap
*cmap
, struct fb_var_screeninfo
*var
,
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
)
394 long prev
= 0x7fffffff;
397 unsigned short res
= 0;
399 if (freq
<= 31250000)
401 else if (freq
<= 62500000)
403 else if (freq
<= 125000000)
405 else if (freq
<= 250000000)
412 f
= freq
>> (10 - n2
);
414 m
= (f
* n1
) / (14318180/1024);
419 tmp
= (((m
* 14318180) >> n2
) / n1
) - freq
;
425 res
= (((n2
<< 5) | (n1
-2)) << 8) | (m
-2);
428 } while ( (++n1
) <= 21);
434 static int retz3_set_video(struct fb_var_screeninfo
*var
,
435 struct retz3_fb_par
*par
)
440 int xres
, hfront
, hsync
, hback
;
441 int yres
, vfront
, vsync
, vback
;
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
;
456 if ((bpp
!= 8) && (bpp
!= 16) && (bpp
!= 24))
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;
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;
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
);
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)
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)
629 if (data
.v_dispend
& 256)
631 if (data
.v_sstart
& 256)
633 if (data
.v_bstart
& 256)
635 if (data
.v_total
& 512)
637 if (data
.v_dispend
& 512)
639 if (data
.v_sstart
& 512)
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)
649 if (var
->vmode
& FB_VMODE_DOUBLE
)
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));
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));
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));
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)
697 if ((data
.h_dispend
) & 0x100)
699 if (data
.h_bstart
& 0x100)
701 if (data
.h_sstart
& 0x100)
703 if (var
->vmode
& FB_VMODE_INTERLACED
)
705 DEBUG
printk("CRT_EXT_HOR_TIMING1: %d\n", tmp
);
706 crt_w(CRT_EXT_HOR_TIMING1
, tmp
);
709 if (((var
->xres_virtual
/ 8) * (bpp
/ 8)) & 0x100)
711 crt_w(CRT_EXT_START_ADDR
, tmp
);
714 if (data
.h_total
& 0x200)
716 if ((data
.h_dispend
) & 0x200)
718 if (data
.h_bstart
& 0x200)
720 if (data
.h_sstart
& 0x200)
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)
730 if ((data
.v_dispend
) & 0x400)
732 if (data
.v_bstart
& 0x400)
734 if (data
.v_sstart
& 0x400)
736 tmp
|= ((data
.v_bstop
& 0x300) >> 3);
737 if (data
.v_sstop
& 0x10)
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
);
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 ???
811 printk("Illegal color-depth: %i\n", bpp
);
814 reg_w(VDAC_ADDRESS
, 0x00);
816 seq_w(SEQ_MAP_MASK
, 0x0f );
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)
832 volatile unsigned long *CursorBase
;
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);
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;
887 retz3_setcolreg (255, 56, 100, 160, 0);
888 retz3_setcolreg (254, 0, 0, 0, 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
)
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
;
911 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
913 fix
->visual
= FB_VISUAL_DIRECTCOLOR
;
918 fix
->line_length
= 0;
920 for (i
= 0; i
< arraysize(fix
->reserved
); i
++)
921 fix
->reserved
[i
] = 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
;
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
;
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
)
969 var
->xres
= par
->xres
;
970 var
->yres
= par
->yres
;
971 var
->xres_virtual
= par
->xres_vir
;
972 var
->yres_virtual
= par
->yres_vir
;
976 var
->bits_per_pixel
= par
->bpp
;
980 var
->green
= par
->green
;
981 var
->blue
= par
->blue
;
982 var
->transp
= par
->transp
;
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
;
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 */
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);
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
)
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];
1059 * (Un)Blank the screen
1062 void retz3_blank(int 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);
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
);
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);
1104 tmp
= mask
| (mask
<< 16);
1108 * Check for blitter finished before we start messing with the
1112 blt_status
= *(((volatile unsigned char *)acm
) +
1113 (ACM_START_STATUS
+ 2));
1114 }while ((blt_status
& 1) == 0);
1120 }while(i
++ < bpp
/4);
1123 *(acm
+ ACM_RASTEROP_ROTATION
/4) = tmp
;
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
);
1138 src
+= bpp
* (width
- 1);
1139 dst
+= bpp
* (width
- 1);
1144 src
+= bpp
* (height
- 1) * xres_virtual
;
1145 dst
+= bpp
* (height
- 1) * xres_virtual
;
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
);
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.
1172 while ((*(((volatile unsigned char *)acm
) +
1173 (ACM_START_STATUS
+ 2)) & 1) == 0);
1176 blt_status
= *(((volatile unsigned char *)acm
) +
1177 (ACM_START_STATUS
+ 2));
1179 while ((blt_status
& 1) == 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
)
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
)
1224 fbhw
->decode_var(&retz3_fb_predefined
[z3fb_mode
], par
);
1228 static void retz3_fb_set_par(struct retz3_fb_par
*par
)
1231 current_par_valid
= 1;
1235 static int do_fb_set_var(struct fb_var_screeninfo
*var
, int isactive
)
1238 struct retz3_fb_par par
;
1240 if ((err
= fbhw
->decode_var(var
, &par
)))
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
;
1249 retz3_set_video(var
, ¤t_par
);
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
,
1288 unsigned short *red
, *green
, *blue
, *transp
;
1289 unsigned int hred
, hgreen
, hblue
, htransp
;
1292 green
= cmap
->green
;
1294 transp
= cmap
->transp
;
1295 start
= cmap
->start
;
1299 for (i
= 0; i
< cmap
->len
; i
++) {
1300 if (fbhw
->getcolreg(start
++, &hred
, &hgreen
, &hblue
, &htransp
))
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
);
1313 put_user(hred
, red
);
1314 put_user(hgreen
, green
);
1315 put_user(hblue
, blue
);
1317 put_user(htransp
, transp
);
1329 static int do_fb_set_cmap(struct fb_cmap
*cmap
, struct fb_var_screeninfo
*var
,
1333 unsigned short *red
, *green
, *blue
, *transp
;
1334 unsigned int hred
, hgreen
, hblue
, htransp
;
1337 green
= cmap
->green
;
1339 transp
= cmap
->transp
;
1340 start
= cmap
->start
;
1344 for (i
= 0; i
< cmap
->len
; i
++) {
1349 htransp
= transp
? *transp
: 0;
1351 get_user(hred
, red
);
1352 get_user(hgreen
, green
);
1353 get_user(hblue
, blue
);
1355 get_user(htransp
, transp
);
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
);
1368 if (fbhw
->setcolreg(start
++, hred
, hgreen
, hblue
, htransp
))
1375 static void do_install_cmap(int con
)
1379 if (disp
[con
].cmap
.len
)
1380 do_fb_set_cmap(&disp
[con
].cmap
, &disp
[con
].var
, 1);
1382 do_fb_set_cmap(get_default_colormap(disp
[con
].var
.bits_per_pixel
),
1387 static void memcpy_fs(int fsfromto
, void *to
, void *from
, int len
)
1391 memcpy(to
, from
, len
);
1394 copy_from_user(to
, from
, len
);
1397 copy_to_user(to
, from
, len
);
1403 static void copy_cmap(struct fb_cmap
*from
, struct fb_cmap
*to
, int fsfromto
)
1406 int tooff
= 0, fromoff
= 0;
1408 if (to
->start
> from
->start
)
1409 fromoff
= to
->start
-from
->start
;
1411 tooff
= from
->start
-to
->start
;
1412 size
= to
->len
-tooff
;
1413 if (size
> from
->len
-fromoff
)
1414 size
= from
->len
-fromoff
;
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
) {
1439 kfree(cmap
->transp
);
1440 cmap
->red
= cmap
->green
= cmap
->blue
= cmap
->transp
= NULL
;
1444 if (!(cmap
->red
= kmalloc(size
, GFP_ATOMIC
)))
1446 if (!(cmap
->green
= kmalloc(size
, GFP_ATOMIC
)))
1448 if (!(cmap
->blue
= kmalloc(size
, GFP_ATOMIC
)))
1451 if (!(cmap
->transp
= kmalloc(size
, GFP_ATOMIC
)))
1454 cmap
->transp
= NULL
;
1458 copy_cmap(get_default_colormap(len
), cmap
, 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
;
1473 retz3_fb_get_par(&par
);
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
;
1490 retz3_fb_get_par(&par
);
1491 error
= fbhw
->encode_var(var
, &par
);
1493 *var
= disp
[con
].var
;
1498 static void retz3_fb_set_disp(int con
)
1500 struct fb_fix_screeninfo fix
;
1502 retz3_fb_get_fix(&fix
, con
);
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
)))
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
);
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);
1559 copy_cmap(get_default_colormap(disp
[con
].var
.bits_per_pixel
),
1560 cmap
, kspc
? 0 : 2);
1569 static int retz3_fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
)
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)))
1578 if (con
== currcon
) /* current console? */
1579 return(do_fb_set_cmap(cmap
, &disp
[con
].var
, kspc
));
1581 copy_cmap(cmap
, &disp
[con
].cmap
, kspc
? 0 : 1);
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
)
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
)
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);
1622 void retz3_video_setup(char *options
, int *ints
)
1627 fb_info
.fontname
[0] = '\0';
1629 if (!options
|| !*options
)
1632 for (this_opt
= strtok(options
, ","); this_opt
;
1633 this_opt
= strtok(NULL
, ",")){
1634 if (!strcmp(this_opt
, "inverse")) {
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);
1644 z3fb_mode
= get_video_mode(this_opt
);
1653 struct fb_info
*retz3_fb_init(long *mem_start
)
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
);
1665 panic("Cannot register frame buffer\n");
1669 if (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);
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);
1699 /* Install new colormap */
1700 do_install_cmap(con
);
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
)
1719 * Blank the display.
1722 static void z3fb_blank(int blank
)
1732 static int z3fb_setcmap(struct fb_cmap
*cmap
, int con
)
1734 return(retz3_fb_set_cmap(cmap
, 1, con
));
1742 static int get_video_mode(const char *name
)
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
];
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
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
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) */
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
{
1816 struct fb_bitfield red
;
1817 struct fb_bitfield green
;
1818 struct fb_bitfield blue
;
1819 struct fb_bitfield transp
;
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 */
1826 int hsync_len
; /* length of horizontal sync */
1827 int vsync_len
; /* length of vertical sync */
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 */
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
);
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
1910 * Predefined Video Modes
1913 "640x480", /* RetinaZ3 8 bpp */
1914 "800x600", /* RetinaZ3 8 bpp */
1916 "640x480-16", /* RetinaZ3 16 bpp */
1917 "640x480-24", /* RetinaZ3 24 bpp */
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 *
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
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
2039 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
2040 { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 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
);
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
,
2130 static int do_fb_set_cmap(struct fb_cmap
*cmap
, struct fb_var_screeninfo
*var
,
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
)
2146 long prev
= 0x7fffffff;
2149 unsigned short res
= 0;
2151 if (freq
<= 31250000)
2153 else if (freq
<= 62500000)
2155 else if (freq
<= 125000000)
2157 else if (freq
<= 250000000)
2164 f
= freq
>> (10 - n2
);
2166 m
= (f
* n1
) / (14318180/1024);
2171 tmp
= (((m
* 14318180) >> n2
) / n1
) - freq
;
2177 res
= (((n2
<< 5) | (n1
-2)) << 8) | (m
-2);
2180 } while ( (++n1
) <= 21);
2186 static int retz3_set_video(struct fb_var_screeninfo
*var
,
2187 struct retz3_fb_par
*par
)
2192 int xres
, hfront
, hsync
, hback
;
2193 int yres
, vfront
, vsync
, vback
;
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
;
2208 if ((bpp
!= 8) && (bpp
!= 16) && (bpp
!= 24))
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;
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;
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
);
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)
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)
2381 if (data
.v_dispend
& 256)
2383 if (data
.v_sstart
& 256)
2385 if (data
.v_bstart
& 256)
2387 if (data
.v_total
& 512)
2389 if (data
.v_dispend
& 512)
2391 if (data
.v_sstart
& 512)
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)
2401 if (var
->vmode
& FB_VMODE_DOUBLE
)
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));
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));
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));
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)
2449 if ((data
.h_dispend
) & 0x100)
2451 if (data
.h_bstart
& 0x100)
2453 if (data
.h_sstart
& 0x100)
2455 if (var
->vmode
& FB_VMODE_INTERLACED
)
2457 DEBUG
printk("CRT_EXT_HOR_TIMING1: %d\n", tmp
);
2458 crt_w(CRT_EXT_HOR_TIMING1
, tmp
);
2461 if (((var
->xres_virtual
/ 8) * (bpp
/ 8)) & 0x100)
2463 crt_w(CRT_EXT_START_ADDR
, tmp
);
2466 if (data
.h_total
& 0x200)
2468 if ((data
.h_dispend
) & 0x200)
2470 if (data
.h_bstart
& 0x200)
2472 if (data
.h_sstart
& 0x200)
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)
2482 if ((data
.v_dispend
) & 0x400)
2484 if (data
.v_bstart
& 0x400)
2486 if (data
.v_sstart
& 0x400)
2488 tmp
|= ((data
.v_bstop
& 0x300) >> 3);
2489 if (data
.v_sstop
& 0x10)
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
);
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 ???
2554 reg_w(0x83c6, 0x00);
2557 reg_w(0x83c6, 0x60);
2560 reg_w(0x83c6, 0xe0);
2563 printk("Illegal color-depth: %i\n", bpp
);
2566 reg_w(VDAC_ADDRESS
, 0x00);
2568 seq_w(SEQ_MAP_MASK
, 0x0f );
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)
2584 volatile unsigned long *CursorBase
;
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);
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;
2639 retz3_setcolreg (255, 56, 100, 160, 0);
2640 retz3_setcolreg (254, 0, 0, 0, 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
)
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
;
2663 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
2665 fix
->visual
= FB_VISUAL_DIRECTCOLOR
;
2670 fix
->line_length
= 0;
2672 for (i
= 0; i
< arraysize(fix
->reserved
); i
++)
2673 fix
->reserved
[i
] = 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
;
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
)
2721 var
->xres
= par
->xres
;
2722 var
->yres
= par
->yres
;
2723 var
->xres_virtual
= par
->xres_vir
;
2724 var
->yres_virtual
= par
->yres_vir
;
2728 var
->bits_per_pixel
= par
->bpp
;
2731 var
->red
= par
->red
;
2732 var
->green
= par
->green
;
2733 var
->blue
= par
->blue
;
2734 var
->transp
= par
->transp
;
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
;
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 */
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);
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
)
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];
2811 * (Un)Blank the screen
2814 void retz3_blank(int 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);
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
);
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);
2856 tmp
= mask
| (mask
<< 16);
2860 * Check for blitter finished before we start messing with the
2864 blt_status
= *(((volatile unsigned char *)acm
) +
2865 (ACM_START_STATUS
+ 2));
2866 }while ((blt_status
& 1) == 0);
2872 }while(i
++ < bpp
/4);
2875 *(acm
+ ACM_RASTEROP_ROTATION
/4) = tmp
;
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
);
2890 src
+= bpp
* (width
- 1);
2891 dst
+= bpp
* (width
- 1);
2896 src
+= bpp
* (height
- 1) * xres_virtual
;
2897 dst
+= bpp
* (height
- 1) * xres_virtual
;
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
);
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.
2924 while ((*(((volatile unsigned char *)acm
) +
2925 (ACM_START_STATUS
+ 2)) & 1) == 0);
2928 blt_status
= *(((volatile unsigned char *)acm
) +
2929 (ACM_START_STATUS
+ 2));
2931 while ((blt_status
& 1) == 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
)
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
)
2976 fbhw
->decode_var(&retz3_fb_predefined
[z3fb_mode
], par
);
2980 static void retz3_fb_set_par(struct retz3_fb_par
*par
)
2983 current_par_valid
= 1;
2987 static int do_fb_set_var(struct fb_var_screeninfo
*var
, int isactive
)
2990 struct retz3_fb_par par
;
2992 if ((err
= fbhw
->decode_var(var
, &par
)))
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
;
3001 retz3_set_video(var
, ¤t_par
);
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
,
3040 unsigned short *red
, *green
, *blue
, *transp
;
3041 unsigned int hred
, hgreen
, hblue
, htransp
;
3044 green
= cmap
->green
;
3046 transp
= cmap
->transp
;
3047 start
= cmap
->start
;
3051 for (i
= 0; i
< cmap
->len
; i
++) {
3052 if (fbhw
->getcolreg(start
++, &hred
, &hgreen
, &hblue
, &htransp
))
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
);
3065 put_user(hred
, red
);
3066 put_user(hgreen
, green
);
3067 put_user(hblue
, blue
);
3069 put_user(htransp
, transp
);
3081 static int do_fb_set_cmap(struct fb_cmap
*cmap
, struct fb_var_screeninfo
*var
,
3085 unsigned short *red
, *green
, *blue
, *transp
;
3086 unsigned int hred
, hgreen
, hblue
, htransp
;
3089 green
= cmap
->green
;
3091 transp
= cmap
->transp
;
3092 start
= cmap
->start
;
3096 for (i
= 0; i
< cmap
->len
; i
++) {
3101 htransp
= transp
? *transp
: 0;
3103 get_user(hred
, red
);
3104 get_user(hgreen
, green
);
3105 get_user(hblue
, blue
);
3107 get_user(htransp
, transp
);
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
);
3120 if (fbhw
->setcolreg(start
++, hred
, hgreen
, hblue
, htransp
))
3127 static void do_install_cmap(int con
)
3131 if (disp
[con
].cmap
.len
)
3132 do_fb_set_cmap(&disp
[con
].cmap
, &disp
[con
].var
, 1);
3134 do_fb_set_cmap(get_default_colormap(disp
[con
].var
.bits_per_pixel
),
3139 static void memcpy_fs(int fsfromto
, void *to
, void *from
, int len
)
3143 memcpy(to
, from
, len
);
3146 copy_from_user(to
, from
, len
);
3149 copy_to_user(to
, from
, len
);
3155 static void copy_cmap(struct fb_cmap
*from
, struct fb_cmap
*to
, int fsfromto
)
3158 int tooff
= 0, fromoff
= 0;
3160 if (to
->start
> from
->start
)
3161 fromoff
= to
->start
-from
->start
;
3163 tooff
= from
->start
-to
->start
;
3164 size
= to
->len
-tooff
;
3165 if (size
> from
->len
-fromoff
)
3166 size
= from
->len
-fromoff
;
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
) {
3191 kfree(cmap
->transp
);
3192 cmap
->red
= cmap
->green
= cmap
->blue
= cmap
->transp
= NULL
;
3196 if (!(cmap
->red
= kmalloc(size
, GFP_ATOMIC
)))
3198 if (!(cmap
->green
= kmalloc(size
, GFP_ATOMIC
)))
3200 if (!(cmap
->blue
= kmalloc(size
, GFP_ATOMIC
)))
3203 if (!(cmap
->transp
= kmalloc(size
, GFP_ATOMIC
)))
3206 cmap
->transp
= NULL
;
3210 copy_cmap(get_default_colormap(len
), cmap
, 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
;
3225 retz3_fb_get_par(&par
);
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
;
3242 retz3_fb_get_par(&par
);
3243 error
= fbhw
->encode_var(var
, &par
);
3245 *var
= disp
[con
].var
;
3250 static void retz3_fb_set_disp(int con
)
3252 struct fb_fix_screeninfo fix
;
3254 retz3_fb_get_fix(&fix
, con
);
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
)))
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
);
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);
3311 copy_cmap(get_default_colormap(disp
[con
].var
.bits_per_pixel
),
3312 cmap
, kspc
? 0 : 2);
3321 static int retz3_fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
)
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)))
3330 if (con
== currcon
) /* current console? */
3331 return(do_fb_set_cmap(cmap
, &disp
[con
].var
, kspc
));
3333 copy_cmap(cmap
, &disp
[con
].cmap
, kspc
? 0 : 1);
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
)
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
)
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);
3374 void retz3_video_setup(char *options
, int *ints
)
3379 fb_info
.fontname
[0] = '\0';
3381 if (!options
|| !*options
)
3384 for (this_opt
= strtok(options
, ","); this_opt
;
3385 this_opt
= strtok(NULL
, ",")){
3386 if (!strcmp(this_opt
, "inverse")) {
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);
3396 z3fb_mode
= get_video_mode(this_opt
);
3405 struct fb_info
*retz3_fb_init(long *mem_start
)
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
);
3417 panic("Cannot register frame buffer\n");
3421 if (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);
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);
3451 /* Install new colormap */
3452 do_install_cmap(con
);
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
)
3471 * Blank the display.
3474 static void z3fb_blank(int blank
)
3484 static int z3fb_setcmap(struct fb_cmap
*cmap
, int con
)
3486 return(retz3_fb_set_cmap(cmap
, 1, con
));
3494 static int get_video_mode(const char *name
)
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
];