2 * linux/drivers/video/fm2fb.c -- BSC FrameMaster II/Rainbow II frame buffer
5 * Copyright (C) 1998 Steffen A. Mork (mork@ls7.cs.uni-dortmund.de)
6 * Copyright (C) 1999 Geert Uytterhoeven
8 * Written for 2.0.x by Steffen A. Mork
9 * Ported to 2.1.x by Geert Uytterhoeven
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive for
16 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/zorro.h>
24 #include <video/fbcon.h>
25 #include <video/fbcon-cfb32.h>
29 * Some technical notes:
31 * The BSC FrameMaster II (or Rainbow II) is a simple very dumb
32 * frame buffer which allows to display 24 bit true color images.
33 * Each pixel is 32 bit width so it's very easy to maintain the
34 * frame buffer. One long word has the following layout:
35 * AARRGGBB which means: AA the alpha channel byte, RR the red
36 * channel, GG the green channel and BB the blue channel.
38 * The FrameMaster II supports the following video modes.
40 * - interlaced/non interlaced
41 * - composite sync/sync/sync over green
43 * The resolution is to the following both ones:
47 * This means that pixel access per line is fixed due to the
48 * fixed line width. In case of maximal resolution the frame
49 * buffer needs an amount of memory of 1.769.472 bytes which
50 * is near to 2 MByte (the allocated address space of Zorro2).
51 * The memory is channel interleaved. That means every channel
52 * owns four VRAMs. Unfortunatly most FrameMasters II are
53 * not assembled with memory for the alpha channel. In this
54 * case it could be possible to add the frame buffer into the
57 * At relative address 0x1ffff8 of the frame buffers base address
58 * there exists a control register with the number of
59 * four control bits. They have the following meaning:
62 * 0 1 0=interlaced/1=non interlaced
63 * 1 2 0=video out disabled/1=video out enabled
64 * 2 4 0=normal mode as jumpered via JP8/1=complement mode
65 * 3 8 0=read onboard ROM/1 normal operation (required)
67 * As mentioned above there are several jumper. I think there
68 * is not very much information about the FrameMaster II in
69 * the world so I add these information for completeness.
71 * JP1 interlace selection (1-2 non interlaced/2-3 interlaced)
72 * JP2 wait state creation (leave as is!)
73 * JP3 wait state creation (leave as is!)
74 * JP4 modulate composite sync on green output (1-2 composite
75 * sync on green channel/2-3 normal composite sync)
76 * JP5 create test signal, shorting this jumper will create
78 * JP6 sync creation (1-2 composite sync/2-3 H-sync output)
79 * JP8 video mode (1-2 PAL/2-3 NTSC)
81 * With the following jumpering table you can connect the
82 * FrameMaster II to a normal TV via SCART connector:
86 * JP8: 1-2 (means PAL for Europe)
89 * There is no other possibility to change the video timings
90 * except the interlaced/non interlaced, sync control and the
91 * video mode PAL (50 Hz)/NTSC (60 Hz). Inside this
92 * FrameMaster II driver are assumed values to avoid anomalies
93 * to a future X server. Except the pixel clock is really
96 * 9 pin female video connector:
98 * 1 analog red 0.7 Vss
99 * 2 analog green 0.7 Vss
100 * 3 analog blue 0.7 Vss
108 * Some performance notes:
109 * The FrameMaster II was not designed to display a console
110 * this driver would do! It was designed to display still true
111 * color images. Imagine: When scroll up a text line there
112 * must copied ca. 1.7 MBytes to another place inside this
113 * frame buffer. This means 1.7 MByte read and 1.7 MByte write
114 * over the slow 16 bit wide Zorro2 bus! A scroll of one
115 * line needs 1 second so do not expect to much from this
116 * driver - he is at the limit!
125 #define FRAMEMASTER_SIZE 0x200000
126 #define FRAMEMASTER_REG 0x1ffff8
128 #define FRAMEMASTER_NOLACE 1
129 #define FRAMEMASTER_ENABLE 2
130 #define FRAMEMASTER_COMPL 4
131 #define FRAMEMASTER_ROM 8
134 struct FrameMaster_fb_par
142 static unsigned long fm2fb_mem_phys
;
143 static void *fm2fb_mem
;
144 static unsigned long fm2fb_reg_phys
;
145 static volatile unsigned char *fm2fb_reg
;
147 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
149 static int currcon
= 0;
150 static struct display disp
;
151 static struct fb_info fb_info
;
152 static struct { u_char red
, green
, blue
, pad
; } palette
[16];
153 #ifdef FBCON_HAS_CFB32
154 static u32 fbcon_cfb32_cmap
[16];
157 static struct fb_fix_screeninfo fb_fix
;
158 static struct fb_var_screeninfo fb_var
;
160 static int fm2fb_mode __initdata
= -1;
162 #define FM2FB_MODE_PAL 0
163 #define FM2FB_MODE_NTSC 1
165 static struct fb_var_screeninfo fb_var_modes
[] __initdata
= {
167 /* 768 x 576, 32 bpp (PAL) */
168 768, 576, 768, 576, 0, 0, 32, 0,
169 { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 },
170 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCEL_NONE
,
171 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT
, 0
173 /* 768 x 480, 32 bpp (NTSC - not supported yet */
174 768, 480, 768, 480, 0, 0, 32, 0,
175 { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 },
176 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCEL_NONE
,
177 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT
, 0
183 * Interface used by the world
186 static int fm2fb_open(struct fb_info
*info
, int user
);
187 static int fm2fb_release(struct fb_info
*info
, int user
);
188 static int fm2fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
189 struct fb_info
*info
);
190 static int fm2fb_get_var(struct fb_var_screeninfo
*var
, int con
,
191 struct fb_info
*info
);
192 static int fm2fb_set_var(struct fb_var_screeninfo
*var
, int con
,
193 struct fb_info
*info
);
194 static int fm2fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
195 struct fb_info
*info
);
196 static int fm2fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
197 struct fb_info
*info
);
198 static int fm2fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
199 struct fb_info
*info
);
200 static int fm2fb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
201 u_long arg
, int con
, struct fb_info
*info
);
205 * Interface to the low level console driver
208 int fm2fb_init(void);
209 static int fm2fbcon_switch(int con
, struct fb_info
*info
);
210 static int fm2fbcon_updatevar(int con
, struct fb_info
*info
);
211 static void fm2fbcon_blank(int blank
, struct fb_info
*info
);
218 static int fm2fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
219 u_int
*transp
, struct fb_info
*info
);
220 static int fm2fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
221 u_int transp
, struct fb_info
*info
);
222 static void do_install_cmap(int con
, struct fb_info
*info
);
225 static struct fb_ops fm2fb_ops
= {
226 fm2fb_open
, fm2fb_release
, fm2fb_get_fix
, fm2fb_get_var
, fm2fb_set_var
,
227 fm2fb_get_cmap
, fm2fb_set_cmap
, fm2fb_pan_display
, fm2fb_ioctl
232 * Open/Release the frame buffer device
235 static int fm2fb_open(struct fb_info
*info
, int user
)
238 * Nothing, only a usage count for the moment
245 static int fm2fb_release(struct fb_info
*info
, int user
)
253 * Get the Fixed Part of the Display
256 static int fm2fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
257 struct fb_info
*info
)
259 memcpy(fix
, &fb_fix
, sizeof(fb_fix
));
265 * Get the User Defined Part of the Display
268 static int fm2fb_get_var(struct fb_var_screeninfo
*var
, int con
,
269 struct fb_info
*info
)
271 memcpy(var
, &fb_var
, sizeof(fb_var
));
277 * Set the User Defined Part of the Display
280 static int fm2fb_set_var(struct fb_var_screeninfo
*var
, int con
,
281 struct fb_info
*info
)
283 struct display
*display
;
284 int oldbpp
= -1, err
;
287 display
= &fb_display
[con
];
289 display
= &disp
; /* used during initialization */
291 if (var
->xres
> fb_var
.xres
|| var
->yres
> fb_var
.yres
||
292 var
->xres_virtual
> fb_var
.xres_virtual
||
293 var
->yres_virtual
> fb_var
.yres_virtual
||
294 var
->bits_per_pixel
> fb_var
.bits_per_pixel
||
296 (var
->vmode
& FB_VMODE_MASK
) != FB_VMODE_NONINTERLACED
)
298 memcpy(var
, &fb_var
, sizeof(fb_var
));
300 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
301 oldbpp
= display
->var
.bits_per_pixel
;
304 if (oldbpp
!= var
->bits_per_pixel
) {
305 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
307 do_install_cmap(con
, info
);
314 * Pan or Wrap the Display
316 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
319 static int fm2fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
320 struct fb_info
*info
)
322 if (var
->xoffset
|| var
->yoffset
)
332 static int fm2fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
333 struct fb_info
*info
)
335 if (con
== currcon
) /* current console? */
336 return fb_get_cmap(cmap
, kspc
, fm2fb_getcolreg
, info
);
337 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
338 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
340 fb_copy_cmap(fb_default_cmap(256), cmap
, kspc
? 0 : 2);
348 static int fm2fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
349 struct fb_info
*info
)
353 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
354 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, 256, 0)))
357 if (con
== currcon
) { /* current console? */
358 err
= fb_set_cmap(cmap
, kspc
, fm2fb_setcolreg
, info
);
361 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
366 static int fm2fb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
367 u_long arg
, int con
, struct fb_info
*info
)
377 int __init
fm2fb_init(void)
380 const struct ConfigDev
*cd
= NULL
;
381 unsigned long board
, *ptr
;
384 if (!(key
= is_fm
= zorro_find(ZORRO_PROD_BSC_FRAMEMASTER_II
, 0, 0)) &&
385 !(key
= zorro_find(ZORRO_PROD_HELFRICH_RAINBOW_II
, 0, 0)))
387 cd
= zorro_get_board(key
);
388 if (!(board
= (u_long
)cd
->cd_BoardAddr
))
390 zorro_config_board(key
, 0);
392 /* assigning memory to kernel space */
393 fm2fb_mem_phys
= board
;
394 fm2fb_mem
= ioremap(board
, FRAMEMASTER_SIZE
);
395 fm2fb_reg_phys
= fm2fb_mem_phys
+FRAMEMASTER_REG
;
396 fm2fb_reg
= (unsigned char *)(fm2fb_mem
+FRAMEMASTER_REG
);
398 /* make EBU color bars on display */
399 ptr
= (unsigned long *)fm2fb_mem
;
400 for (y
= 0; y
< 576; y
++) {
401 for (x
= 0; x
< 96; x
++) *ptr
++ = 0xffffff; /* white */
402 for (x
= 0; x
< 96; x
++) *ptr
++ = 0xffff00; /* yellow */
403 for (x
= 0; x
< 96; x
++) *ptr
++ = 0x00ffff; /* cyan */
404 for (x
= 0; x
< 96; x
++) *ptr
++ = 0x00ff00; /* green */
405 for (x
= 0; x
< 96; x
++) *ptr
++ = 0xff00ff; /* magenta */
406 for (x
= 0; x
< 96; x
++) *ptr
++ = 0xff0000; /* red */
407 for (x
= 0; x
< 96; x
++) *ptr
++ = 0x0000ff; /* blue */
408 for (x
= 0; x
< 96; x
++) *ptr
++ = 0x000000; /* black */
410 fm2fbcon_blank(0, NULL
);
412 if (fm2fb_mode
== -1)
413 fm2fb_mode
= FM2FB_MODE_PAL
;
415 fb_var
= fb_var_modes
[fm2fb_mode
];
417 strcpy(fb_fix
.id
, is_fm
? "FrameMaster II" : "Rainbow II");
418 fb_fix
.smem_start
= fm2fb_mem_phys
;
419 fb_fix
.smem_len
= FRAMEMASTER_REG
;
420 fb_fix
.type
= FB_TYPE_PACKED_PIXELS
;
422 fb_fix
.visual
= FB_VISUAL_TRUECOLOR
;
423 fb_fix
.line_length
= 768<<2;
424 fb_fix
.mmio_start
= fm2fb_reg_phys
;
426 fb_fix
.accel
= FB_ACCEL_NONE
;
431 disp
.cmap
.red
= disp
.cmap
.green
= disp
.cmap
.blue
= disp
.cmap
.transp
= NULL
;
432 disp
.screen_base
= (char *)fm2fb_mem
;
433 disp
.visual
= fb_fix
.visual
;
434 disp
.type
= fb_fix
.type
;
435 disp
.type_aux
= fb_fix
.type_aux
;
438 disp
.line_length
= fb_fix
.line_length
;
439 disp
.can_soft_blank
= 1;
441 #ifdef FBCON_HAS_CFB32
442 disp
.dispsw
= &fbcon_cfb32
;
443 disp
.dispsw_data
= &fbcon_cfb32_cmap
;
445 disp
.dispsw
= &fbcon_dummy
;
447 disp
.scrollmode
= SCROLL_YREDRAW
;
449 strcpy(fb_info
.modename
, fb_fix
.id
);
451 fb_info
.fbops
= &fm2fb_ops
;
452 fb_info
.disp
= &disp
;
453 fb_info
.fontname
[0] = '\0';
454 fb_info
.changevar
= NULL
;
455 fb_info
.switch_con
= &fm2fbcon_switch
;
456 fb_info
.updatevar
= &fm2fbcon_updatevar
;
457 fb_info
.blank
= &fm2fbcon_blank
;
458 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
460 fm2fb_set_var(&fb_var
, -1, &fb_info
);
462 if (register_framebuffer(&fb_info
) < 0)
465 printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info
.node
),
470 int __init
fm2fb_setup(char *options
)
474 if (!options
|| !*options
)
477 for (this_opt
= strtok(options
, ","); this_opt
;
478 this_opt
= strtok(NULL
, ",")) {
479 if (!strncmp(this_opt
, "pal", 3))
480 fm2fb_mode
= FM2FB_MODE_PAL
;
481 else if (!strncmp(this_opt
, "ntsc", 4))
482 fm2fb_mode
= FM2FB_MODE_NTSC
;
488 static int fm2fbcon_switch(int con
, struct fb_info
*info
)
490 /* Do we have to save the colormap? */
491 if (fb_display
[currcon
].cmap
.len
)
492 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, fm2fb_getcolreg
, info
);
495 /* Install new colormap */
496 do_install_cmap(con
, info
);
501 * Update the `var' structure (called by fbcon.c)
504 static int fm2fbcon_updatevar(int con
, struct fb_info
*info
)
514 static void fm2fbcon_blank(int blank
, struct fb_info
*info
)
516 unsigned char t
= FRAMEMASTER_ROM
;
519 t
|= FRAMEMASTER_ENABLE
| FRAMEMASTER_NOLACE
;
524 * Read a single color register and split it into
525 * colors/transparent. Return != 0 for invalid regno.
528 static int fm2fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
529 u_int
*transp
, struct fb_info
*info
)
533 *red
= (palette
[regno
].red
<<8) | palette
[regno
].red
;
534 *green
= (palette
[regno
].green
<<8) | palette
[regno
].green
;
535 *blue
= (palette
[regno
].blue
<<8) | palette
[regno
].blue
;
542 * Set a single color register. The values supplied are already
543 * rounded down to the hardware's capabilities (according to the
544 * entries in the var structure). Return != 0 for invalid regno.
547 static int fm2fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
548 u_int transp
, struct fb_info
*info
)
555 palette
[regno
].red
= red
;
556 palette
[regno
].green
= green
;
557 palette
[regno
].blue
= blue
;
559 #ifdef FBCON_HAS_CFB32
560 fbcon_cfb32_cmap
[regno
] = (red
<< 16) | (green
<< 8) | blue
;
566 static void do_install_cmap(int con
, struct fb_info
*info
)
570 if (fb_display
[con
].cmap
.len
)
571 fb_set_cmap(&fb_display
[con
].cmap
, 1, fm2fb_setcolreg
, info
);
573 fb_set_cmap(fb_default_cmap(256), 1, fm2fb_setcolreg
, info
);