diff options
Diffstat (limited to 'drivers/video')
96 files changed, 19210 insertions, 6905 deletions
diff --git a/drivers/video/Config.in b/drivers/video/Config.in index f3cb63093..7c1887c1c 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -22,6 +22,7 @@ if [ "$CONFIG_FB" = "y" ]; then tristate 'Amiga CyberVision support' CONFIG_FB_CYBER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE + bool 'Amiga CyberVisionPPC support (experimental)' CONFIG_FB_CVPPC tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN fi @@ -35,9 +36,9 @@ if [ "$CONFIG_FB" = "y" ]; then if [ "$CONFIG_FB_OF" = "y" ]; then bool 'Apple "control" display support' CONFIG_FB_CONTROL bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM -# bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE + bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE bool 'ATI Mach64 display support' CONFIG_FB_ATY -# bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT + bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT bool 'Chips 65550 display support' CONFIG_FB_CT65550 bool 'S3 Trio display support' CONFIG_FB_S3TRIO fi @@ -48,21 +49,24 @@ if [ "$CONFIG_FB" = "y" ]; then if [ "$CONFIG_HP300" = "y" ]; then define_bool CONFIG_FB_HP300 y fi - # I used CONFIG_ARM here because the ARCH construct doesn't seem to work - # with xconfig. --pb - if [ "$ARCH" = "i386" -o "$ARCH" = "alpha" -o "$ARCH" = "ppc" -o \ - "$CONFIG_ARM" = "y" ]; then - if [ "$CONFIG_ARM" != "y" -o "$CONFIG_ARCH_ACORN" != "y" ] ; then - tristate 'Deprecated almost-VGA support (text only - use normal VGA console instead)' CONFIG_FB_VGA - fi - fi if [ "$ARCH" = "alpha" ]; then tristate 'TGA framebuffer support' CONFIG_FB_TGA fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA define_bool CONFIG_VIDEO_SELECT y - tristate 'MDA dual-headed support' CONFIG_FB_MDA + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + tristate 'Matrox acceleration' CONFIG_FB_MATROX + if [ "$CONFIG_FB_MATROX" != "n" ]; then + bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM + bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE + bool ' G100/G200 support' CONFIG_FB_MATROX_G100 + bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD + fi + bool 'ATI Mach64 display support' CONFIG_FB_ATY + fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS @@ -75,6 +79,16 @@ if [ "$CONFIG_FB" = "y" ]; then bool ' CGthree support' CONFIG_FB_CGTHREE if [ "$ARCH" = "sparc" ]; then bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX + bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN + fi + bool ' Leo (ZX) support' CONFIG_FB_LEO + fi + fi + if [ "$ARCH" = "sparc" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + bool 'PCI framebuffers' CONFIG_FB_PCI + if [ "$CONFIG_FB_PCI" != "n" ]; then + bool ' IGA 168x display support' CONFIG_FB_IGA fi fi fi @@ -139,48 +153,68 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_G364" = "y" ]; then + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ - "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ + "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" ]; then + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ - "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB16 m fi fi if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_CLGEN" = "y" ]; then + "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_CLGEN" = "m" ]; then + "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB24 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then + "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ + "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_MATROX" = "y" ]; then define_bool CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then + "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ + "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_MATROX" = "m" ]; then define_bool CONFIG_FBCON_CFB32 m fi fi diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 27365240a..8001bdf15 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -9,9 +9,6 @@ # parent makes.. # -GSPA = gspa -GSPH2C = gspahextoc - L_TARGET := video.a L_OBJS := M_OBJS := @@ -19,11 +16,16 @@ LX_OBJS := MX_OBJS := MOD_LIST_NAME := VIDEO_MODULES +CONFIG_FBGEN_BUILTIN := +CONFIG_FBGEN_MODULE := + # Frame Buffer Console -# Nasty trick to make sure all wanted stuff is linked in -O_TARGET = fbdev.o -L_OBJS += fbdev.o +ifeq ($(CONFIG_FB),y) + # Nasty trick to make sure all wanted stuff is linked in + O_TARGET = fbdev.o + L_OBJS += fbdev.o +endif ifeq ($(CONFIG_DUMMY_CONSOLE),y) L_OBJS += dummycon.o @@ -35,8 +37,7 @@ endif ifeq ($(CONFIG_FB),y) L_OBJS += fonts.o - OX_OBJS += fbcon.o fbcmap.o -# fbgen is not compiled by default since nobody uses it yet, except clgenfb + OX_OBJS += fbcon.o fbcmap.o fbmem.o ifeq ($(CONFIG_FONT_8x8),y) L_OBJS += font_8x8.o endif @@ -94,6 +95,10 @@ ifeq ($(CONFIG_FB_ATY),y) L_OBJS += atyfb.o endif +ifeq ($(CONFIG_FB_IGA),y) +L_OBJS += igafb.o +endif + ifeq ($(CONFIG_FB_CONTROL),y) L_OBJS += controlfb.o endif @@ -102,6 +107,10 @@ ifeq ($(CONFIG_FB_PLATINUM),y) L_OBJS += platinumfb.o endif +ifeq ($(CONFIG_FB_VALKYRIE),y) +L_OBJS += valkyriefb.o +endif + ifeq ($(CONFIG_FB_CT65550),y) L_OBJS += chipsfb.o endif @@ -114,6 +123,11 @@ else endif endif +ifeq ($(CONFIG_FB_CVPPC),y) +L_OBJS += cvppcfb.o +CONFIG_FBGEN_BUILTIN = y +endif + ifeq ($(CONFIG_FB_MAC),y) L_OBJS += macfb.o endif @@ -126,6 +140,10 @@ ifeq ($(CONFIG_FB_OF),y) L_OBJS += offb.o macmodes.o endif +ifeq ($(CONFIG_FB_IMSTT),y) +L_OBJS += imsttfb.o +endif + ifeq ($(CONFIG_FB_RETINAZ3),y) L_OBJS += retz3fb.o else @@ -136,11 +154,11 @@ endif ifeq ($(CONFIG_FB_CLGEN),y) L_OBJS += clgenfb.o -OX_OBJS += fbgen.o +CONFIG_FBGEN_BUILTIN = y else ifeq ($(CONFIG_FB_CLGEN),m) M_OBJS += clgenfb.o - OX_OBJS += fbgen.o + CONFIG_FBGEN_MODULE = y endif endif @@ -160,26 +178,10 @@ else endif endif -ifeq ($(CONFIG_FB_VGA),y) -L_OBJS += vgafb.o -else - ifeq ($(CONFIG_FB_VGA),m) - M_OBJS += vgafb.o - endif -endif - ifeq ($(CONFIG_FB_VESA),y) L_OBJS += vesafb.o endif -ifeq ($(CONFIG_FB_MDA),y) -L_OBJS += mdafb.o -else - ifeq ($(CONFIG_FB_MDA),m) - M_OBJS += mdafb.o - endif -endif - ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -192,6 +194,10 @@ ifdef CONFIG_FB_G364 L_OBJS := $(L_OBJS) g364fb.o endif +ifdef CONFIG_FB_G364 +L_OBJS := $(L_OBJS) g364fb.o +endif + ifeq ($(CONFIG_FB_SBUS),y) L_OBJS += sbusfb.o ifeq ($(CONFIG_FB_CREATOR),y) @@ -229,6 +235,20 @@ L_OBJS += sbusfb.o M_OBJS += tcxfb.o endif endif + ifeq ($(CONFIG_FB_CGFOURTEEN),y) + L_OBJS += cgfourteenfb.o + else + ifeq ($(CONFIG_FB_CGFOURTEEN),m) + M_OBJS += cgfourteenfb.o + endif + endif + ifeq ($(CONFIG_FB_LEO),y) + L_OBJS += leofb.o + else + ifeq ($(CONFIG_FB_LEO),m) + M_OBJS += leofb.o + endif + endif else ifeq ($(CONFIG_FB_SBUS),m) M_OBJS += sbusfb.o @@ -267,6 +287,20 @@ else M_OBJS += tcxfb.o endif endif + ifeq ($(CONFIG_FB_CGFOURTEEN),y) + M_OBJS += cgfourteenfb.o + else + ifeq ($(CONFIG_FB_CGFOURTEEN),m) + M_OBJS += cgfourteenfb.o + endif + endif + ifeq ($(CONFIG_FB_LEO),y) + M_OBJS += leofb.o + else + ifeq ($(CONFIG_FB_LEO),m) + M_OBJS += leofb.o + endif + endif endif endif @@ -278,6 +312,22 @@ else endif endif +ifdef CONFIG_FBGEN_BUILTIN +OX_OBJS += fbgen.o +else + ifdef CONFIG_FBGEN_MODULE + MX_OBJS += fbgen.o + endif +endif + +ifeq ($(CONFIG_FB_MATROX),y) +L_OBJS += matroxfb.o +else + ifeq ($(CONFIG_FB_MATROX),m) + M_OBJS += matroxfb.o + endif +endif + # Generic Low Level Drivers ifeq ($(CONFIG_FBCON_AFB),y) @@ -400,17 +450,22 @@ else endif endif - -ifdef CONFIG_AMIGA_GSP -L_OBJS += gspcon.o gspcore.o -endif - # VGA Text Console ifdef CONFIG_VGA_CONSOLE L_OBJS += vgacon.o endif +# MDA Text Console + +ifeq ($(CONFIG_MDA_CONSOLE),y) +L_OBJS += mdacon.o +else + ifeq ($(CONFIG_MDA_CONSOLE),m) + M_OBJS += mdacon.o + endif +endif + # Newport Text Console ifdef CONFIG_SGI @@ -419,11 +474,7 @@ endif include $(TOPDIR)/Rules.make -gspcore.c: gspcore.gsp - $(GSPA) $< > $*.hex - $(GSPH2C) $*.hex > gspcore.c - -promcon_tbl.c: prom.uni +promcon_tbl.c: prom.uni ../char/conmakehash ../char/conmakehash prom.uni | \ sed -e '/#include <[^>]*>/p' -e 's/types/init/' \ -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c index eb94dec73..c83c83c96 100644 --- a/drivers/video/S3triofb.c +++ b/drivers/video/S3triofb.c @@ -45,9 +45,9 @@ #include <asm/vc_ioctl.h> #endif -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "s3blit.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/s3blit.h> #define mem_in8(addr) in_8((void *)(addr)) @@ -250,8 +250,7 @@ static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, s3trio_getcolreg, - info); + return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -276,8 +275,7 @@ static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, s3trio_setcolreg, - info); + return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -574,7 +572,7 @@ __initfunc(void s3triofb_init_of(struct device_node *dp)) else disp.dispsw = &fbcon_cfb8; #else - disp.dispsw = NULL; + disp.dispsw = &fbcon_dummy; #endif disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW; @@ -612,6 +610,7 @@ __initfunc(void s3triofb_init_of(struct device_node *dp)) } #endif /* CONFIG_FB_COMPAT_XPMAC) */ + fb_info.flags = FBINFO_FLAG_DEFAULT; if (register_framebuffer(&fb_info) < 0) return; @@ -624,8 +623,7 @@ static int s3triofbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - s3trio_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info); currcon = con; /* Install new colormap */ @@ -678,17 +676,16 @@ static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, { if (regno > 255) return 1; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; + *red = (palette[regno].red << 8) | palette[regno].red; + *green = (palette[regno].green << 8) | palette[regno].green; + *blue = (palette[regno].blue << 8) | palette[regno].blue; + *transp = 0; return 0; } /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. + * Set a single color register. Return != 0 for invalid regno. */ static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -696,6 +693,10 @@ static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, { if (regno > 255) return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; @@ -714,11 +715,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - s3trio_setcolreg, &fb_info); + fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info); else - fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, s3trio_setcolreg, &fb_info); + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1, + s3trio_setcolreg, &fb_info); } void s3triofb_setup(char *options, int *ints) { @@ -837,9 +837,9 @@ static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { sx *= 8; dx *= 8; width *= 8; - Trio_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx, - (u_short)(dy*p->fontheight), (u_short)width, - (u_short)(height*p->fontheight), (u_short)S3_NEW); + Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)S3_NEW); } static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy, @@ -850,9 +850,9 @@ static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy, sx *= 8; width *= 8; bg = attr_bgcol_ec(p,conp); Trio_RectFill((u_short)sx, - (u_short)(sy*p->fontheight), + (u_short)(sy*fontheight(p)), (u_short)width, - (u_short)(height*p->fontheight), + (u_short)(height*fontheight(p)), (u_short)S3_NEW, (u_short)bg); } diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 52fb4487a..a20259904 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -21,10 +21,10 @@ #include <asm/irq.h> #include <asm/uaccess.h> -#include "fbcon-mfb.h" -#include "fbcon-cfb2.h" -#include "fbcon-cfb4.h" -#include "fbcon-cfb8.h" +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> #define MAX_VIDC20_PALETTE 256 #define MAX_VIDC_PALETTE 16 @@ -220,7 +220,7 @@ acornfb_set_disp(int con) break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } } @@ -228,12 +228,19 @@ acornfb_set_disp(int con) static int acornfb_vidc20_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info) { + int t; + if (regno >= current_par.palette_size) return 1; - *red = current_par.palette.vidc20[regno].d.red; - *green = current_par.palette.vidc20[regno].d.green; - *blue = current_par.palette.vidc20[regno].d.blue; - *trans = current_par.palette.vidc20[regno].d.ext; + t = current_par.palette.vidc20[regno].d.red; + *red = (t << 8) | t; + t = current_par.palette.vidc20[regno].d.green; + *green = (t << 8) | t; + t = current_par.palette.vidc20[regno].d.blue; + *blue = (t << 8) | t; + t = current_par.palette.vidc20[regno].d.ext; + t |= t << 4; + *transp = (t << 8) | t; return 0; } @@ -243,6 +250,9 @@ acornfb_vidc20_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int if (regno >= current_par.palette_size) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; current_par.palette.vidc20[regno].p = 0; current_par.palette.vidc20[regno].d.red = red; current_par.palette.vidc20[regno].d.green = green; @@ -261,8 +271,7 @@ acornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, int err = 0; if (con == currcon) - err = fb_get_cmap(cmap, &fb_display[con].var, - kspc, acornfb_vidc20_getcolreg, info); + err = fb_get_cmap(cmap, kspc, acornfb_vidc20_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -282,8 +291,8 @@ acornfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, current_par.palette_size, 0); if (!err) { if (con == currcon) - err = fb_set_cmap(cmap, &fb_display[con].var, - kspc, acornfb_vidc20_setcolreg, info); + err = fb_set_cmap(cmap, kspc, acornfb_vidc20_setcolreg, + info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -372,9 +381,10 @@ acornfb_init(unsigned long mem_start)) fb_info.switch_con = acornfb_switch; fb_info.updatevar = acornfb_update_var; fb_info.blank = acornfb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; acornfb_set_disp(-1); - fb_set_cmap(fb_default_cmap(current_par.palette_size), &fb_display[0].var, + fb_set_cmap(fb_default_cmap(current_par.palette_size), 1, acornfb_vidc20_setcolreg, &fb_info); register_framebuffer(&fb_info); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 840d23c03..ed588ab0d 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -60,10 +60,12 @@ #include <asm/amigahw.h> #include <asm/amigaints.h> #include <asm/setup.h> +#include <asm/io.h> -#include "fbcon-afb.h" -#include "fbcon-ilbm.h" -#include "fbcon-mfb.h" +#include <video/fbcon.h> +#include <video/fbcon-afb.h> +#include <video/fbcon-ilbm.h> +#include <video/fbcon-mfb.h> #define DEBUG @@ -756,8 +758,9 @@ extern volatile u_short amiga_audio_min_period; /* * Since we can't read the palette on OCS/ECS, and since reading one - * single color palette entry require 5 expensive custom chip bus accesses + * single color palette entry requires 5 expensive custom chip bus accesses * on AGA, we keep a copy of the current palette. + * Note that the entries are always 24 bit! */ #if defined(CONFIG_FB_AMIGA_AGA) @@ -1077,13 +1080,13 @@ static struct fb_var_screeninfo amifb_default; /* colour */ #define rgb2hw8_high(red, green, blue) \ - (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f)) + (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw8_low(red, green, blue) \ - (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f)) + (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f)) #define rgb2hw4(red, green, blue) \ - (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f)) + (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw2(red, green, blue) \ - (((red)<<10 & 0xc00) | ((green)<<6 & 0x0c0) | ((blue)<<2 & 0x00c)) + (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4)) /* sprpos/sprctl (sprite positioning) */ @@ -1476,7 +1479,8 @@ static int amifb_set_var(struct fb_var_screeninfo *var, int con, struct fb_fix_screeninfo fix; ami_encode_fix(&fix, &par); - display->screen_base = fix.smem_start; + display->screen_base = + phys_to_virt ((unsigned long) fix.smem_start); display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1502,7 +1506,7 @@ static int amifb_set_var(struct fb_var_screeninfo *var, int con, break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; } if (fb_info.changevar) (*fb_info.changevar)(con); @@ -1558,8 +1562,7 @@ static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, - ami_getcolreg, info); + return fb_get_cmap(cmap, kspc, ami_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -1584,8 +1587,7 @@ static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, - ami_setcolreg, info); + return fb_set_cmap(cmap, kspc, ami_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -1858,6 +1860,7 @@ default_chipset: fb_info.switch_con = &amifbcon_switch; fb_info.updatevar = &amifbcon_updatevar; fb_info.blank = &amifbcon_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; chipptr = chipalloc(videomemorysize+ SPRITEMEMSIZE+ @@ -1916,8 +1919,7 @@ static int amifbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, - &fb_display[currcon].var, 1, ami_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, ami_getcolreg, info); currcon = con; ami_set_var(&fb_display[con].var); @@ -1954,12 +1956,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - ami_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, ami_setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, - ami_setcolreg, info); + 1, ami_setcolreg, info); } static int flash_cursor(void) @@ -2126,7 +2126,7 @@ static int ami_encode_fix(struct fb_fix_screeninfo *fix, { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, amifb_name); - fix->smem_start = (char *)videomemory; + fix->smem_start = (char*) virt_to_phys((void *)videomemory); fix->smem_len = videomemorysize; #ifdef FBCON_HAS_MFB @@ -2767,17 +2767,34 @@ static int ami_update_par(void) static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) { + int len, tr, tg, tb; + if (IS_AGA) { if (regno > 255) return 1; + len = 8; + } else if (currentpar.bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + len = 2; } else { if (regno > 31) return 1; - } - - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; + len = 4; + } + tr = palette[regno].red>>(8-len); + tg = palette[regno].green>>(8-len); + tb = palette[regno].blue>>(8-len); + while (len < 16) { + tr |= tr<<len; + tg |= tg<<len; + tb |= tb<<len; + len <<= 1; + } + *red = tr; + *green = tg; + *blue = tb; + *transp = 0; return 0; } @@ -2791,16 +2808,22 @@ static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { -#if defined(CONFIG_FB_AMIGA_AGA) - u_short bplcon3 = currentpar.bplcon3; - if (IS_AGA) { if (regno > 255) return 1; - } else -#endif + } else if (currentpar.bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + } else { if (regno > 31) return 1; + } + red >>= 8; + green >>= 8; + blue >>= 8; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; /* * Update the corresponding Hardware Color Register, unless it's Color @@ -2810,13 +2833,10 @@ static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * being changed by ami_do_blank() during the VBlank. */ - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; - if (regno || !is_blanked) { #if defined(CONFIG_FB_AMIGA_AGA) if (IS_AGA) { + u_short bplcon3 = currentpar.bplcon3; VBlankOff(); custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); custom.color[regno&31] = rgb2hw8_high(red, green, blue); @@ -2826,26 +2846,24 @@ static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, VBlankOn(); } else #endif - { #if defined(CONFIG_FB_AMIGA_ECS) - if (currentpar.bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - VBlankOff(); - for (i = regno+12; i >= (int)regno; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - regno = down16(regno)+mul4(mod4(regno)); - for (i = regno+3; i >= (int)regno; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - VBlankOn(); - } else + if (currentpar.bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno+12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + regno = down16(regno)+mul4(mod4(regno)); + for (i = regno+3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else #endif - custom.color[regno] = rgb2hw4(red, green, blue); - } + custom.color[regno] = rgb2hw4(red, green, blue); } return 0; } @@ -2982,23 +3000,21 @@ static void ami_do_blank(void) custom.bplcon3 = bplcon3; } else #endif - { #if defined(CONFIG_FB_AMIGA_ECS) - if (par->bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - for (i = 12; i >= 0; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - for (i = 3; i >= 0; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - } else + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else #endif - custom.color[0] = rgb2hw4(red, green, blue); - } + custom.color[0] = rgb2hw4(red, green, blue); is_blanked = do_blank > 0 ? do_blank : 0; } diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index a64eaf1fa..68c2a6fb2 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -70,12 +70,12 @@ #include <linux/fb.h> #include <asm/atarikb.h> -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-iplan2p2.h" -#include "fbcon-iplan2p4.h" -#include "fbcon-iplan2p8.h" -#include "fbcon-mfb.h" +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-iplan2p2.h> +#include <video/fbcon-iplan2p4.h> +#include <video/fbcon-iplan2p8.h> +#include <video/fbcon-mfb.h> #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ @@ -682,32 +682,44 @@ static void tt_set_par( struct atafb_par *par ) } -static int tt_getcolreg( unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info ) +static int tt_getcolreg(unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info) { + int t, col; + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) regno += 254; if (regno > 255) return 1; - *blue = tt_palette[regno]; - *green = (*blue >> 4) & 0xf; - *red = (*blue >> 8) & 0xf; - *blue &= 0xf; + t = tt_palette[regno]; + col = t & 15; + col |= col << 4; + col |= col << 8; + *blue = col; + col = (t >> 4) & 15; + col |= col << 4; + col |= col << 8; + *green = col; + col = (t >> 8) & 15; + col |= col << 4; + col |= col << 8; + *red = col; *transp = 0; return 0; } -static int tt_setcolreg( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ) +static int tt_setcolreg(unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) { if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) regno += 254; if (regno > 255) return 1; - tt_palette[regno] = (red << 8) | (green << 4) | blue; + tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) | + (blue >> 12)); if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH && regno == 254) tt_palette[0] = 0; @@ -770,6 +782,9 @@ static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; /* Default hsync timing [mon_type] in picoseconds */ static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; +#ifdef FBCON_HAS_CFB16 +static u16 fbcon_cfb16_cmap[16]; +#endif static inline int hxx_prescale(struct falcon_hw *hw) { @@ -1621,9 +1636,9 @@ static int falcon_getcolreg( unsigned regno, unsigned *red, * Even with hicolor r/g/b=5/6/5 bit! */ col = f030_col[regno]; - *red = (col >> 26) & 0x3f; - *green = (col >> 18) & 0x3f; - *blue = (col >> 2) & 0x3f; + *red = (col >> 16) & 0xff00; + *green = (col >> 8) & 0xff00; + *blue = (col << 8) & 0xff00; *transp = 0; return 0; } @@ -1635,14 +1650,18 @@ static int falcon_setcolreg( unsigned regno, unsigned red, { if (regno > 255) return 1; - f030_col[regno] = (red << 26) | (green << 18) | (blue << 2); + f030_col[regno] = (((red & 0xfc00) << 16) | + ((green & 0xfc00) << 8) | + ((blue & 0xfc00) >> 8)); if (regno < 16) { shifter_tt.color_reg[regno] = - (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | - (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | - ((blue & 0xe) >> 1) | ((blue & 1) << 3); + (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | + (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | + ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); #ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (red << 11) | (green << 5) | blue; + fbcon_cfb16_cmap[regno] = ((red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11)); #endif } return 0; @@ -1923,35 +1942,51 @@ static void stste_set_par( struct atafb_par *par ) } -static int stste_getcolreg( unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info ) -{ unsigned col; +static int stste_getcolreg(unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *info) +{ + unsigned col, t; if (regno > 15) return 1; col = shifter_tt.color_reg[regno]; if (ATARIHW_PRESENT(EXTD_SHIFTER)) { - *red = ((col >> 7) & 0xe) | ((col >> 11) & 1); - *green = ((col >> 3) & 0xe) | ((col >> 7) & 1); - *blue = ((col << 1) & 0xe) | ((col >> 3) & 1); + t = ((col >> 7) & 0xe) | ((col >> 11) & 1); + t |= t << 4; + *red = t | (t << 8); + t = ((col >> 3) & 0xe) | ((col >> 7) & 1); + t |= t << 4; + *green = t | (t << 8); + t = ((col << 1) & 0xe) | ((col >> 3) & 1); + t |= t << 4; + *blue = t | (t << 8); } else { - *red = (col >> 8) & 0x7; - *green = (col >> 4) & 0x7; - *blue = col & 0x7; + t = (col >> 7) & 0xe; + t |= t << 4; + *red = t | (t << 8); + t = (col >> 3) & 0xe; + t |= t << 4; + *green = t | (t << 8); + t = (col << 1) & 0xe; + t |= t << 4; + *blue = t | (t << 8); } *transp = 0; return 0; } -static int stste_setcolreg( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ) +static int stste_setcolreg(unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) { if (regno > 15) return 1; + red >>= 12; + blue >>= 12; + green >>= 12; if (ATARIHW_PRESENT(EXTD_SHIFTER)) shifter_tt.color_reg[regno] = (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | @@ -1959,9 +1994,9 @@ static int stste_setcolreg( unsigned regno, unsigned red, ((blue & 0xe) >> 1) | ((blue & 1) << 3); else shifter_tt.color_reg[regno] = - ((red & 0x7) << 8) | - ((green & 0x7) << 4) | - (blue & 0x7); + ((red & 0xe) << 7) | + ((green & 0xe) << 3) | + ((blue & 0xe) >> 1); return 0; } @@ -2383,12 +2418,10 @@ do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &(fb_display[con].var), 1, - fbhw->setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &(fb_display[con].var), 1, - fbhw->setcolreg, info); + 1, fbhw->setcolreg, info); } @@ -2503,6 +2536,7 @@ atafb_set_disp(int con, struct fb_info *info) #ifdef FBCON_HAS_CFB16 case 16: display->dispsw = &fbcon_cfb16; + display->dispsw_data = fbcon_cfb16_cmap; break; #endif } @@ -2546,8 +2580,7 @@ static int atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console ? */ - return fb_get_cmap(cmap, &(fb_display[con].var), kspc, - fbhw->getcolreg, info); + return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap ? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); @@ -2568,8 +2601,7 @@ atafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) return err; } if (con == currcon) /* current console ? */ - return fb_set_cmap(cmap, &(fb_display[con].var), kspc, - fbhw->setcolreg, info); + return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -2675,8 +2707,7 @@ atafb_switch(int con, struct fb_info *info) { /* Do we have to save the colormap ? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, - &(fb_display[currcon].var), 1, fbhw->getcolreg, + fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg, info); do_fb_set_var(&fb_display[con].var,1); currcon=con; @@ -2707,8 +2738,7 @@ atafb_blank(int blank, struct fb_info *info) cmap.transp=NULL; cmap.start=0; cmap.len=16; - fb_set_cmap(&cmap, &(fb_display[currcon].var), 1, - fbhw->setcolreg, info); + fb_set_cmap(&cmap, 1, fbhw->setcolreg, info); } else do_install_cmap(currcon, info); @@ -2819,6 +2849,7 @@ __initfunc(void atafb_init(void)) fb_info.switch_con = &atafb_switch; fb_info.updatevar = &fb_update_var; fb_info.blank = &atafb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&atafb_predefined[default_par-1], 1); strcat(fb_info.modename, fb_var_names[default_par-1][0]); diff --git a/drivers/video/ati-gt.h b/drivers/video/ati-gt.h deleted file mode 100644 index 32dc792b5..000000000 --- a/drivers/video/ati-gt.h +++ /dev/null @@ -1,203 +0,0 @@ -/* the usage for the following structs vary from the gx and vt: -and sdram and sgram gt's - pll registers (sdram) 6,7,11; - crtc_h_sync_strt_wid[3]; - dsp1[3] (sdram,sgram,unused) - dsp2[3] (offset regbase+24, depends on colour mode); - crtc_h_tot_disp,crtc_v_tot_disp,crtc_v_sync_strt_wid,unused; - pll registers (sgram) 7,11; -*/ - -/* Register values for 1280x1024, 75Hz mode (20). no 16/32 */ -static struct aty_regvals aty_gt_reg_init_20 = { - { 0x41, 0xf9, 0x04 }, - { 0xe02a7, 0x1401a6, 0 }, - { 0x260957, 0x2806d6, 0 }, - { 0x10006b6, 0x20006b6, 0x30006b6 }, - - 0x9f00d2, 0x03ff0429, 0x30400, 0, - { 0xb5, 0x04 } -}; - -#if 0 -/* Register values for 1280x960, 75Hz mode (19) */ -static struct aty_regvals aty_gt_reg_init_19 = { -}; -#endif - -/* Register values for 1152x870, 75Hz mode (18) */ -static struct aty_regvals aty_gt_reg_init_18 = { - { 0x41, 0xe6, 0x04 }, - { 0x300295, 0x300194, 0x300593 }, - { 0x260a1c, 0x380561, 0}, - { 0x1000744, 0x2000744, 0x3000744 }, - - 0x8f00b5, 0x3650392, 0x230368, 0, - { 0xe6, 0x04 } -}; - -/* Register values for 1024x768, 75Hz mode (17), 32 bpp untested */ -static struct aty_regvals aty_gt_reg_init_17 = { - { 0x41, 0xb5, 0x04 }, - { 0xc0283, 0xc0182, 0xc0581 }, - { 0x36066d, 0x3806d6, 0}, - { 0xa0049e, 0x100049e, 0x200049e }, - - 0x7f00a3, 0x2ff031f, 0x30300, 0, - { 0xb8, 0x04 } -}; - -#if 0 -/* Register values for x, Hz mode (16) */ -static struct aty_regvals aty_gt_reg_init_16 = { -}; -#endif - -/* Register values for 1024x768, 70Hz mode (15) */ -static struct aty_regvals aty_gt_reg_init_15 = { - { 0x41, 0xad, 0x04 }, - { 0x310284, 0x310183, 0x310582 }, - { 0x0, 0x380727 }, - { 0x0 }, - 0x7f00a5, 0x2ff0325, 0x260302, -}; - -/* Register values for 1024x768, 60Hz mode (14) */ -static struct aty_regvals aty_gt_reg_init_14 = { - { 0x40, 0xe1, 0x14 }, - { 0x310284, 0x310183, 0x310582 }, - { 0x3607c0, 0x380840, 0x0 }, - { 0xa80592, 0x1000592, 0x0 }, - - 0x7f00a7, 0x2ff0325, 0x260302, 0, - { 0xe1, 0x14 } -}; - -/* Register values for 832x624, 75Hz mode (13) */ -static struct aty_regvals aty_gt_reg_init_13 = { - { 0x40, 0xc6, 0x14 }, - { 0x28026d, 0x28016c, 0x28056b }, - { 0x3608cf, 0x380960, 0 }, - { 0xb00655, 0x1000655, 0x2000655 }, - - 0x67008f, 0x26f029a, 0x230270, 0, - { 0xc6, 0x14 } -}; - -/* Register values for 800x600, 75Hz mode (12) */ -static struct aty_regvals aty_gt_reg_init_12 = { - { 0x42, 0xe4, 0x04 }, - { 0xa0267, 0xa0166, 0x0a0565}, - { 0x360a33, 0x48056d, 0}, - { 0xc00755, 0x1000755, 0x02000755}, - - 0x630083, 0x2570270, 0x30258, 0, - { 0xe4, 0x4 } -}; - -/* Register values for 800x600, 72Hz mode (11) */ -static struct aty_regvals aty_gt_reg_init_11 = { - { 0x42, 0xe6, 0x04 }, - { 0xf026c, 0xf016b, 0xf056a }, - { 0x360a1d, 0x480561, 0}, - { 0xc00745, 0x1000745, 0x2000745 }, - - 0x630081, 0x02570299, 0x6027c -}; - -/* Register values for 800x600, 60Hz mode (10) */ -static struct aty_regvals aty_gt_reg_init_10 = { - { 0x42, 0xb8, 0x04 }, - { 0x10026a, 0x100169, 0x100568 }, - { 0x460652, 0x4806ba, 0}, - { 0x68048b, 0xa0048b, 0x100048b }, - - 0x630083, 0x02570273, 0x40258, 0, - { 0xb8, 0x4 } -}; - -/* Register values for 800x600, 56Hz mode (9) */ -static struct aty_regvals aty_gt_reg_init_9 = { - { 0x42, 0xf9, 0x14 }, - { 0x90268, 0x90167, 0x090566 }, - { 0x460701, 0x480774, 0}, - { 0x700509, 0xa80509, 0x1000509 }, - - 0x63007f, 0x2570270, 0x20258 -}; - -#if 0 -/* Register values for 768x576, 50Hz mode (8) */ -static struct aty_regvals aty_gt_reg_init_8 = { -}; - -/* Register values for 640x870, 75Hz Full Page Display (7) */ -static struct aty_regvals aty_gt_reg_init_7 = { -}; -#endif - -/* Register values for 640x480, 67Hz mode (6) */ -static struct aty_regvals aty_gt_reg_init_6 = { - { 0x42, 0xd1, 0x14 }, - { 0x280259, 0x280158, 0x280557 }, - { 0x460858, 0x4808e2, 0}, - { 0x780600, 0xb00600, 0x1000600 }, - - 0x4f006b, 0x1df020c, 0x2301e2, 0, - { 0x8b, 0x4 } -}; - -/* Register values for 640x480, 60Hz mode (5) */ -static struct aty_regvals aty_gt_reg_init_5 = { - { 0x43, 0xe8, 0x04 }, - { 0x2c0253, 0x2c0152, 0x2c0551 }, - { 0x460a06, 0x580555, 0}, - { 0x880734, 0xc00734, 0x1000734 }, - - 0x4f0063, 0x1df020c, 0x2201e9, 0, - { 0xe8, 0x04 } -}; - -#if 0 -/* Register values for x, Hz mode (4) */ -static struct aty_regvals aty_gt_reg_init_4 = { -}; - -/* Register values for x, Hz mode (3) */ -static struct aty_regvals aty_gt_reg_init_3 = { -}; - -/* Register values for x, Hz mode (2) */ -static struct aty_regvals aty_gt_reg_init_2 = { -}; - -/* Register values for x, Hz mode (1) */ -static struct aty_regvals aty_gt_reg_init_1 = { -}; -#endif - -/* yikes, more data structures (dsp2) - * XXX kludge for sgram - */ -static int sgram_dsp[20][3] = { - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0,0,0}, - {0x5203d7,0x7803d9,0xb803dd}, //5 - {0x940666,0xe0066a,0x1700672}, //6 - {0,0,0}, - {0,0,0}, - {0x88055f,0xd80563,0x170056b}, //9 - {0x8404d9,0xb804dd,0x17004e5}, //10 - {0x7803e2,0xb803e6,0x17003ee}, //11 - {0x7803eb,0xb803ef,0x17003f7}, //12 - {0xe806c5,0x17006cd,0x2e006dd}, //13 - {0xe005f6,0x17005fe,0x2e0060e}, //14 - {0xd8052c,0x1700534,0x2e00544}, //15 - {0,0,0}, - {0xb804f2,0x17004e5,0x2e0050a}, //17 - {0xb803e6,0x17003ee,0x2e003fe}, //18 - {0,0,0}, - {0,0,0}, -}; diff --git a/drivers/video/ati-gx.h b/drivers/video/ati-gx.h deleted file mode 100644 index df48c1865..000000000 --- a/drivers/video/ati-gx.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Register values for 1280x1024, 75Hz (WAS 60) mode (20) */ -static struct aty_regvals aty_gx_reg_init_20 = { - { 0x200, 0x200, 0x200 }, - - { 0x1200a5, 0x1200a3, 0x1200a3 }, - { 0x30c0200, 0x30e0300, 0x30e0300 }, - { 0x2, 0x3, 0x3 }, - - 0x9f00d2, 0x3ff0429, 0x30400, 0x28100040, - { 0xd4, 0x9 } -}; - -/* Register values for 1152x870, 75Hz mode (18) */ -static struct aty_regvals aty_gx_reg_init_18 = { - { 0x200, 0x200, 0x200 }, - - { 0x300097, 0x300095, 0x300094 }, - { 0x3090200, 0x30e0300, 0x30e0600 }, - { 0x2, 0x3, 0x6 }, - - 0x8f00b5, 0x3650392, 0x230368, 0x24100040, - { 0x53, 0x3 } -}; - -/* Register values for 1024x768, 75Hz mode (17) */ -static struct aty_regvals aty_gx_reg_init_17 = { - { 0x200, 0x200, 0x200 }, - - { 0x2c0087, 0x2c0085, 0x2c0084 }, - { 0x3070200, 0x30e0300, 0x30e0600 }, - { 0x2, 0x3, 0x6 }, - - 0x7f00a5, 0x2ff0323, 0x230302, 0x20100000, - { 0x42, 0x3 } -}; - -/* Register values for 1024x768, 72Hz mode (15) */ -static struct aty_regvals aty_gx_reg_init_15 = { - { 0, 0, 0 }, - - { 0x310086, 0x310084, 0x310084 }, - { 0x3070200, 0x30e0300, 0x30e0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a5, 0x2ff0325, 0x260302, 0x20100000, - { 0x88, 0x7 } -}; - -/* Register values for 1024x768, 60Hz mode (14) */ -static struct aty_regvals aty_gx_reg_init_14 = { - { 0, 0, 0 }, - - { 0x310086, 0x310084, 0x310084 }, - { 0x3060200, 0x30d0300, 0x30d0300 }, - { 0x2002312, 0x3002312, 0x3002312 }, - - 0x7f00a7, 0x2ff0325, 0x260302, 0x20100000, - { 0x6c, 0x6 } -}; - -/* Register values for 832x624, 75Hz mode (13) */ -static struct aty_regvals aty_gx_reg_init_13 = { - { 0x200, 0x200, 0x200 }, - - { 0x28006f, 0x28006d, 0x28006c }, - { 0x3050200, 0x30b0300, 0x30e0600 }, - { 0x2, 0x3, 0x6 }, - - 0x67008f, 0x26f029a, 0x230270, 0x1a100040, - { 0x4f, 0x5 } -}; - -#if 0 /* not filled in yet */ -/* Register values for 800x600, 75Hz mode (12) */ -static struct aty_regvals aty_gx_reg_init_12 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 49.11MHz for V=74.40Hz */ -}; - -/* Register values for 800x600, 72Hz mode (11) */ -static struct aty_regvals aty_gx_reg_init_11 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 49.63MHz for V=71.66Hz */ -}; - -/* Register values for 800x600, 60Hz mode (10) */ -static struct aty_regvals aty_gx_reg_init_10 = { - { 0x10, 0x28, 0x50 }, - { }, - { } /* pixel clock = 41.41MHz for V=59.78Hz */ -}; - -/* Register values for 640x870, 75Hz Full Page Display (7) */ -static struct aty_regvals aty_gx_reg_init_7 = { - { 0x10, 0x30, 0x68 }, - { }, - { } /* pixel clock = 57.29MHz for V=75.01Hz */ -}; -#endif - -/* Register values for 640x480, 67Hz mode (6) */ -static struct aty_regvals aty_gx_reg_init_6 = { - { 0x200, 0x200, 0x200 }, - - { 0x28005b, 0x280059, 0x280058 }, - { 0x3040200, 0x3060300, 0x30c0600 }, - { 0x2002312, 0x3002312, 0x6002312 }, - - 0x4f006b, 0x1df020c, 0x2301e2, 0x14100040, - { 0x35, 0x07 } -}; - -#if 0 /* not filled in yet */ -/* Register values for 640x480, 60Hz mode (5) */ -static struct aty_regvals aty_gx_reg_init_5 = { - { 0x200, 0x200, 0x200 }, - { }, - { 0x35, 0x07 } -}; -#endif diff --git a/drivers/video/ati-vt.h b/drivers/video/ati-vt.h deleted file mode 100644 index 3b25d6d5d..000000000 --- a/drivers/video/ati-vt.h +++ /dev/null @@ -1,147 +0,0 @@ -/* Register values for 1280x1024, 60Hz mode (20) */ -static struct aty_regvals aty_vt_reg_init_20 = { - { 0, 0, 0 }, - - { 0x002e02a7, 0x002e02a7, 0 }, - { 0x03070200, 0x03070200, 0 }, - { 0x0a00cb22, 0x0b00cb23, 0 }, - - 0x009f00d2, 0x03ff0429, 0x00030400, 0x28000000, - { 0x00, 0xaa } -}; - -/* Register values for 1280x960, 75Hz mode (19) */ -static struct aty_regvals aty_vt_reg_init_19 = { - { 0, 0, 0 }, - { 0x003202a3, 0x003201a2, 0 }, - { 0x030b0200, 0x030b0300, 0 }, - { 0x0a00cb22, 0x0b00cb23, 0 }, - - 0x009f00d1, 0x03bf03e7, 0x000303c0, 0x28000000, - { 0x00, 0xc6 } -}; - -/* Register values for 1152x870, 75Hz mode (18) */ -static struct aty_regvals aty_vt_reg_init_18 = { - { 0, 0, 0 }, - - { 0x00300295, 0x00300194, 0 }, - { 0x03080200, 0x03080300, 0 }, - { 0x0a00cb21, 0x0b00cb22, 0 }, - - 0x008f00b5, 0x03650392, 0x00230368, 0x24000000, - { 0x00, 0x9d } -}; - -/* Register values for 1024x768, 75Hz mode (17) */ -static struct aty_regvals aty_vt_reg_init_17 = { - { 0, 0, 0 }, - - { 0x002c0283, 0x002c0182, 0 }, - { 0x03080200, 0x03080300, 0 }, - { 0x0a00cb21, 0x0b00cb22, 0 }, - - 0x007f00a3, 0x02ff031f, 0x00030300, 0x20000000, - { 0x01, 0xf7 } -}; - -/* Register values for 1024x768, 70Hz mode (15) */ -static struct aty_regvals aty_vt_reg_init_15 = { - { 0, 0, 0 }, - { 0x00310284, 0x00310183, 0 }, - { 0x03080200, 0x03080300, 0 }, - { 0x0a00cb21, 0x0b00cb22, 0 }, - - 0x007f00a5, 0x02ff0325, 0x00260302, 0x20000000, - { 0x01, 0xeb } -}; - -/* Register values for 1024x768, 60Hz mode (14) */ -static struct aty_regvals aty_vt_reg_init_14 = { - { 0, 0, 0 }, - - { 0x00310284, 0x00310183, 0x00310582 }, /* 32 bit 0x00310582 */ - { 0x03080200, 0x03080300, 0x03070600 }, /* 32 bit 0x03070600 */ - { 0x0a00cb21, 0x0b00cb22, 0x0e00cb23 }, - - 0x007f00a7, 0x02ff0325, 0x00260302, 0x20000000, - { 0x01, 0xcc } -}; - -/* Register values for 832x624, 75Hz mode (13) */ -static struct aty_regvals aty_vt_reg_init_13 = { - { 0, 0, 0 }, - - { 0x0028026d, 0x0028016c, 0x0028056b }, - { 0x03080200, 0x03070300, 0x03090600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x0067008f, 0x026f029a, 0x00230270, 0x1a000000, - { 0x01, 0xb4 } -}; - -/* Register values for 800x600, 75Hz mode (12) */ -static struct aty_regvals aty_vt_reg_init_12 = { - { 0, 0, 0 }, - - { 0x002a0267, 0x002a0166, 0x002a0565 }, - { 0x03040200, 0x03060300, 0x03070600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x00630083, 0x02570270, 0x00030258, 0x19000000, - { 0x01, 0x9c } -}; - -/* Register values for 800x600, 72Hz mode (11) */ -static struct aty_regvals aty_vt_reg_init_11 = { - { 0, 0, 0 }, - - { 0x002f026c, 0x002f016b, 0x002f056a }, - { 0x03050200, 0x03070300, 0x03090600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x00630081, 0x02570299, 0x0006027c, 0x19000000, - { 0x01, 0x9d } -}; - -/* Register values for 800x600, 60Hz mode (10) */ -static struct aty_regvals aty_vt_reg_init_10 = { - { 0, 0, 0 }, - - { 0x0030026a, 0x00300169, 0x00300568 }, - { 0x03050200, 0x03070300, 0x03090600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x00630083, 0x02570273, 0x00040258, 0x19000000, - { 0x02, 0xfb } -}; - -/* Register values for 640x480, 67Hz mode (6) */ -static struct aty_regvals aty_vt_reg_init_6 = { - { 0, 0, 0 }, - - { 0x00280259, 0x00280158, 0x00280557 }, - { 0x03050200, 0x03070300, 0x030a0600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x004f006b, 0x01df020c, 0x002301e2, 0x14000000, - { 0x02, 0xbe } -}; - -/* Register values for 640x480, 60Hz mode (5) */ -static struct aty_regvals aty_vt_reg_init_5 = { - { 0, 0, 0 }, - - { 0x002c0253, 0x002c0152, 0x002c0551 }, - { 0x03050200, 0x03070300, 0x03090600 }, - { 0x0a00cb21, 0x0b00cb21, 0x0e00cb22 }, - - 0x004f0063, 0x01df020c, 0x002201e9, 0x14000000, - { 0x02, 0x9e } -}; - /* 8 bit 15 bit 32 bit */ -static int vt_mem_cntl[3][3] = { { 0x0A00CB21, 0x0B00CB21, 0x0E00CB21 }, /* 1 MB VRAM */ - { 0x0A00CB22, 0x0B00CB22, 0x0E00CB22 }, /* 2 MB VRAM */ - { 0x0200053B, 0x0300053B, 0x0600053B } /* 4 M B VRAM */ - }; - diff --git a/drivers/video/aty.h b/drivers/video/aty.h index 517b500c5..667e7c3ec 100644 --- a/drivers/video/aty.h +++ b/drivers/video/aty.h @@ -718,12 +718,20 @@ /* mach64CT family / mach64VT class */ #define VT_CHIP_ID 0x5654 /* mach64VT (ATI264VT) */ #define VU_CHIP_ID 0x5655 /* mach64VTB (ATI264VTB) */ +#define VV_CHIP_ID 0x5656 /* mach64VT4 (ATI264VT4) */ /* mach64CT family / mach64GT (3D RAGE) class */ -#define LT_CHIP_ID 0x4c54 /* 3D RAGE LT */ -#define LG_CHIP_ID 0x4c47 /* 3D RAGE LG */ -#define GT_CHIP_ID 0x4754 /* 3D RAGE (GT) */ -#define GU_CHIP_ID 0x4755 /* 3D RAGE II/II+ (GTB) */ +#define LB_CHIP_ID 0x4c42 /* RAGE LT PRO, AGP */ +#define LD_CHIP_ID 0x4c44 /* RAGE LT PRO */ +#define LG_CHIP_ID 0x4c47 /* RAGE LT PRO */ +#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */ +#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */ +#define LT_CHIP_ID 0x4c54 /* RAGE LT */ +#define GT_CHIP_ID 0x4754 /* RAGE (GT) */ +#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */ +#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */ +#define GW_CHIP_ID 0x4757 /* RAGE IIC, AGP */ +#define GZ_CHIP_ID 0x475a /* RAGE IIC, AGP */ #define GB_CHIP_ID 0x4742 /* RAGE PRO, BGA, AGP 1x and 2x */ #define GD_CHIP_ID 0x4744 /* RAGE PRO, BGA, AGP 1x only */ #define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 7d271bc29..e3f1b1d8d 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -1,9 +1,9 @@ -/* +/* $Id: atyfb.c,v 1.90 1998/11/20 12:27:03 geert Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * - * Copyright (C) 1997-1998 Geert Uytterhoeven - * Copyright (C) 1998 Bernd Harries - * Copyright (C) 1998 Eddie C. Dost + * Copyright (C) 1997-1998 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * This driver is partly based on the PowerMac console driver: * @@ -26,15 +26,12 @@ TODO: - (ecd): - - - fix initialization of cursor timer. - - - add code to support cursor on all cards and all ramdacs. + - cursor support on all cards and all ramdacs. + - cursor parameters controlable via ioctl()s. + - guess PLL and MCLK based on the original PLL register values initialized + by the BIOS or Open Firmware (if they are initialized). - - make cursor parameters controllable via ioctl()s. - - (Anyone to help with all this?) + (Anyone to help with this?) ******************************************************************************/ @@ -65,29 +62,33 @@ #include <asm/io.h> -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +#if defined(CONFIG_PPC) #include <asm/prom.h> #include <asm/pci-bridge.h> -#include "macmodes.h" +#include <video/macmodes.h> #endif #ifdef __sparc__ #include <asm/pbm.h> +#include <asm/fbio.h> +#include <asm/uaccess.h> #endif +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + #include "aty.h" -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb24.h" -#include "fbcon-cfb32.h" -#define GUI_RESERVE 0x00001000 +/* + * Debug flags. + */ +#undef DEBUG -#define CLASS_GX 1 -#define CLASS_CT 2 -#define CLASS_VT 3 -#define CLASS_GT 4 + +#define GUI_RESERVE 0x00001000 #ifndef __powerpc__ @@ -166,6 +167,7 @@ struct pci_mmap_map { }; #define DEFAULT_CURSOR_BLINK_RATE (20) +#define CURSOR_DRAW_DELAY (2) struct aty_cursor { int enable; @@ -179,6 +181,7 @@ struct aty_cursor { u32 color[2]; u8 bits[8][64]; u8 mask[8][64]; + u8 *ram; struct timer_list *timer; }; @@ -188,8 +191,6 @@ struct fb_info_aty { unsigned long ati_regbase; unsigned long frame_buffer_phys; unsigned long frame_buffer; - struct display disp; - struct display_switch dispsw; struct pci_mmap_map *mmap_map; struct aty_cursor *cursor; struct aty_cmap_regs *aty_cmap_regs; @@ -208,6 +209,19 @@ struct fb_info_aty { u8 dac_type; u8 clk_type; u8 mem_refresh_rate; + struct display disp; + struct display_switch dispsw; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; #ifdef __sparc__ u8 open; u8 mmaped; @@ -299,6 +313,7 @@ static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p, */ static int aty_init(struct fb_info_aty *info, const char *name); +static struct aty_cursor *aty_init_cursor(struct fb_info_aty *fb); #ifdef CONFIG_ATARI static int store_video_par(char *videopar, unsigned char m64_num); static char *strtoke(char *s, const char *ct); @@ -309,6 +324,9 @@ static void init_engine(const struct atyfb_par *par, const struct fb_info_aty *info); static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info); static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); +#if defined(__sparc__) || defined(DEBUG) +static u8 aty_ld_pll(int offset, const struct fb_info_aty *info); +#endif static void aty_set_crtc(const struct fb_info_aty *info, const struct crtc *crtc); static int aty_var_to_crtc(const struct fb_info_aty *info, @@ -319,22 +337,17 @@ static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var); static void aty_set_pll_gx(const struct fb_info_aty *info, const struct pll_gx *pll); -static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, - struct pll_gx *pll); -static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, - struct pll_gx *pll); -static int aty_pll_gx_to_var(const struct pll_gx *pll, - struct fb_var_screeninfo *var); +static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll); +static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll); +static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per); static void aty_set_pll_ct(const struct fb_info_aty *info, const struct pll_ct *pll); static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div, u8 bpp, struct pll_ct *pll); -static int aty_var_to_pll_ct(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct pll_ct *pll); -static int aty_pll_ct_to_var(const struct pll_ct *pll, - struct fb_var_screeninfo *var); +static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, struct pll_ct *pll); +static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per); static void atyfb_set_par(const struct atyfb_par *par, struct fb_info_aty *info); static int atyfb_decode_var(const struct fb_var_screeninfo *var, @@ -348,12 +361,14 @@ static void set_off_pitch(struct atyfb_par *par, static int encode_fix(struct fb_fix_screeninfo *fix, const struct atyfb_par *par, const struct fb_info_aty *info); +static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, + int bpp, int accel); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb); static void do_install_cmap(int con, struct fb_info *info); -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +#if defined(CONFIG_PPC) static int read_aty_sense(const struct fb_info_aty *info); #endif @@ -383,12 +398,17 @@ static struct fb_ops atyfb_ops = { static char atyfb_name[16] = "ATY Mach64"; static char fontname[40] __initdata = { 0 }; +static char curblink __initdata = 1; +static char noaccel __initdata = 0; +static u32 default_vram __initdata = 0; +static int default_pll __initdata = 0; +static int default_mclk __initdata = 0; static const u32 ref_clk_per = 1000000000000ULL/14318180; -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) -static int default_vmode = VMODE_NVRAM; -static int default_cmode = CMODE_NVRAM; +#if defined(CONFIG_PPC) +static int default_vmode __initdata = VMODE_NVRAM; +static int default_cmode __initdata = CMODE_NVRAM; #endif #ifdef CONFIG_ATARI @@ -415,14 +435,20 @@ static struct aty_features { /* mach64CT family / mach64VT class */ { 0x5654, 0x5654, "mach64VT (ATI264VT)" }, { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" }, -/* { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */ + { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, /* mach64CT family / mach64GT (3D RAGE) class */ + { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" }, + { 0x4c42, 0x4c44, "3D RAGE LT PRO" }, + { 0x4c42, 0x4c47, "3D RAGE LT PRO" }, + { 0x4c42, 0x4c49, "3D RAGE LT PRO" }, + { 0x4c42, 0x4c50, "3D RAGE LT PRO" }, { 0x4c54, 0x4c54, "3D RAGE LT" }, - { 0x4c47, 0x4c47, "3D RAGE LG" }, { 0x4754, 0x4754, "3D RAGE (GT)" }, { 0x4755, 0x4755, "3D RAGE II+ (GTB)" }, -/* { 0x4756, 0x4756, "3D RAGE IIC" }, */ + { 0x4756, 0x4756, "3D RAGE IIC (PCI)" }, + { 0x4757, 0x4757, "3D RAGE IIC (AGP)" }, + { 0x475a, 0x475a, "3D RAGE IIC (AGP)" }, { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" }, { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" }, { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, @@ -430,6 +456,14 @@ static struct aty_features { { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, }; +static const char *aty_gx_ram[8] __initdata = { + "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV" +}; + +static const char *aty_ct_ram[8] __initdata = { + "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV" +}; + static inline u32 aty_ld_le32(volatile unsigned int regindex, const struct fb_info_aty *info) @@ -620,6 +654,12 @@ static void init_engine(const struct atyfb_par *par, aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info); aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info); + wait_for_fifo(5, info); + aty_st_le32(SCALE_3D_CNTL, 0, info); + aty_st_le32(Z_CNTL, 0, info); + aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info); + aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info); + /* insure engine is idle before leaving */ wait_for_idle(info); } @@ -648,22 +688,22 @@ static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); } -#if 0 /* ecd debug */ +#if defined(__sparc__) || defined(DEBUG) static u8 aty_ld_pll(int offset, const struct fb_info_aty *info) { - u8 val; + u8 res; /* write addr byte */ aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); eieio(); /* read the register value */ - val = aty_ld_8(CLOCK_CNTL + 2, info); + res = aty_ld_8(CLOCK_CNTL + 2, info); eieio(); - return val; + return res; } -#endif /* ecd debug */ +#endif -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +#if defined(CONFIG_PPC) /* * Apple monitor sense @@ -703,7 +743,7 @@ static int read_aty_sense(const struct fb_info_aty *info) return sense; } -#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */ +#endif /* defined(CONFIG_PPC) */ /* ------------------------------------------------------------------------- */ @@ -768,8 +808,7 @@ aty_set_cursor_shape(struct fb_info_aty *fb) return; #endif - ram = (u8 *)(fb->frame_buffer + c->offset); - + ram = c->ram; for (y = 0; y < c->size.y; y++) { for (x = 0; x < c->size.x >> 2; x++) { m = c->mask[x][y]; @@ -788,8 +827,9 @@ aty_set_cursor_shape(struct fb_info_aty *fb) } static void -aty_set_cursor(struct fb_info_aty *fb) +aty_set_cursor(struct fb_info_aty *fb, int on) { + struct atyfb_par *par = &fb->current_par; struct aty_cursor *c = fb->cursor; u16 xoff, yoff; int x, y; @@ -802,8 +842,8 @@ aty_set_cursor(struct fb_info_aty *fb) return; #endif - if (c->on) { - x = c->pos.x - c->hot.x; + if (on) { + x = c->pos.x - c->hot.x - par->crtc.xoffset; if (x < 0) { xoff = -x; x = 0; @@ -811,7 +851,7 @@ aty_set_cursor(struct fb_info_aty *fb) xoff = 0; } - y = c->pos.y - c->hot.y; + y = c->pos.y - c->hot.y - par->crtc.yoffset; if (y < 0) { yoff = -y; y = 0; @@ -827,11 +867,12 @@ aty_set_cursor(struct fb_info_aty *fb) aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb) | HWCURSOR_ENABLE, fb); } else { - wait_for_fifo(4, fb); + wait_for_fifo(1, fb); aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE, fb); } + wait_for_idle(fb); } static void @@ -847,7 +888,7 @@ aty_cursor_timer_handler(unsigned long dev_addr) if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) { fb->cursor->on ^= 1; - aty_set_cursor(fb); + aty_set_cursor(fb, fb->cursor->on); fb->cursor->vbl_cnt = fb->cursor->blink_rate; } @@ -857,9 +898,9 @@ out: } static void -atyfb_cursor(struct display *d, int mode, int x, int y) +atyfb_cursor(struct display *p, int mode, int x, int y) { - struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info; + struct fb_info_aty *fb = (struct fb_info_aty *)p->fb_info; struct aty_cursor *c = fb->cursor; if (!c) @@ -870,44 +911,82 @@ atyfb_cursor(struct display *d, int mode, int x, int y) return; #endif - x *= d->fontwidth; - y *= d->fontheight; - if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on) + x *= fontwidth(p); + y *= fontheight(p); + if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable) return; c->enable = 0; + if (c->on) + aty_set_cursor(fb, 0); c->pos.x = x; c->pos.y = y; switch (mode) { case CM_ERASE: c->on = 0; - aty_set_cursor(fb); break; case CM_DRAW: case CM_MOVE: - c->on = 1; - aty_set_cursor(fb); + if (c->on) + aty_set_cursor(fb, 1); + else + c->vbl_cnt = CURSOR_DRAW_DELAY; + c->enable = 1; + break; + } +} - if (!c->timer) { - c->timer = kmalloc(sizeof(*c->timer), GFP_KERNEL); - if (!c->timer) - return; +__initfunc(static struct aty_cursor * +aty_init_cursor(struct fb_info_aty *fb)) +{ + struct aty_cursor *cursor; + unsigned long addr; - c->blink_rate = DEFAULT_CURSOR_BLINK_RATE; + cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); + if (!cursor) + return 0; + memset(cursor, 0, sizeof(*cursor)); - init_timer(c->timer); - c->timer->expires = jiffies + (HZ / 50); - c->timer->data = (unsigned long)fb; - c->timer->function = aty_cursor_timer_handler; - add_timer(c->timer); - } + cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL); + if (!cursor->timer) { + kfree(cursor); + return 0; + } + memset(cursor->timer, 0, sizeof(*cursor->timer)); - c->vbl_cnt = c->blink_rate; - c->enable = 1; - break; + cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; + fb->total_vram -= PAGE_SIZE; + cursor->offset = fb->total_vram; + +#ifdef __sparc__ + addr = fb->frame_buffer - 0x800000 + cursor->offset; + cursor->ram = (u8 *)addr; +#else +#ifdef __BIG_ENDIAN + addr = fb->frame_buffer_phys - 0x800000 + cursor->offset; + cursor->ram = (u8 *)ioremap(addr, 1024); +#else + addr = fb->frame_buffer + cursor->offset; + cursor->ram = (u8 *)addr; +#endif +#endif + + if (! cursor->ram) { + kfree(cursor); + return NULL; + } + + if (curblink) { + init_timer(cursor->timer); + cursor->timer->expires = jiffies + (HZ / 50); + cursor->timer->data = (unsigned long)fb; + cursor->timer->function = aty_cursor_timer_handler; + add_timer(cursor->timer); } + + return cursor; } static int @@ -923,7 +1002,6 @@ atyfb_set_font(struct display *d, int width, int height) height = 16; } - c->offset = fb->total_vram - 0x1000; c->hot.x = 0; c->hot.y = 0; c->size.x = width; @@ -972,7 +1050,7 @@ static int aty_var_to_crtc(const struct fb_info_aty *info, u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; /* input */ @@ -1029,6 +1107,8 @@ static int aty_var_to_crtc(const struct fb_info_aty *info, FAIL("v_total too large"); v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; + if (bpp <= 8) { bpp = 8; pix_width = CRTC_PIX_WIDTH_8BPP; @@ -1073,10 +1153,9 @@ static int aty_var_to_crtc(const struct fb_info_aty *info, crtc->v_tot_disp = v_total | (v_disp<<16); crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); - crtc->gen_cntl = pix_width | CRTC_EXT_DISP_EN | CRTC_ENABLE; + crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) || - ((Gx == VT_CHIP_ID) && !(Rev & 0x03)) || - ((Gx == GT_CHIP_ID) && !(Rev & 0x03))) { + ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) { /* Not VTB/GTB */ /* FIXME: magic FIFO values */ crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; @@ -1129,7 +1208,7 @@ static int aty_crtc_to_var(const struct crtc *crtc, { u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; /* input */ @@ -1145,19 +1224,21 @@ static int aty_crtc_to_var(const struct crtc *crtc, v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; /* convert */ xres = (h_disp+1)*8; yres = v_disp+1; left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; - right = (h_sync_strt-h_disp)*8; + right = (h_sync_strt-h_disp)*8+h_sync_dly; hslen = h_sync_wid*8; upper = v_total-v_sync_strt-v_sync_wid; lower = v_sync_strt-v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT); + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); switch (pix_width) { #if 0 @@ -1277,13 +1358,12 @@ static void aty_set_pll_gx(const struct fb_info_aty *info, aty_st_514(0x03, 0x00, info); /* Sync Control */ aty_st_514(0x05, 0x00, info); /* Power Management */ aty_st_514(0x20, pll->m, info); /* F0 / M0 */ - aty_st_514(0x21, pll->m, info); /* F1 / N0 */ + aty_st_514(0x21, pll->n, info); /* F1 / N0 */ break; } } -static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, - struct pll_gx *pll) +static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll) { /* * FIXME: use real calculations instead of using fixed values from the old @@ -1329,7 +1409,7 @@ static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks); set++) - if (var->pixclock <= ATI18818_clocks[set].ps_lim) { + if (vclk_per <= ATI18818_clocks[set].ps_lim) { pll->m = ATI18818_clocks[set].mode; pll->n = ATI18818_clocks[set].prog; return 0; @@ -1337,8 +1417,7 @@ static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var, return -EINVAL; } -static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, - struct pll_gx *pll) +static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll) { /* * FIXME: use real calculations instead of using fixed values from the old @@ -1360,7 +1439,7 @@ static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, int i; for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++) - if (var->pixclock <= RGB514_clocks[i].limit) { + if (vclk_per <= RGB514_clocks[i].limit) { pll->m = RGB514_clocks[i].m; pll->n = RGB514_clocks[i].n; return 0; @@ -1370,8 +1449,7 @@ static int aty_var_to_pll_514(const struct fb_var_screeninfo *var, /* FIXME: ATI18818?? */ -static int aty_pll_gx_to_var(const struct pll_gx *pll, - struct fb_var_screeninfo *var) +static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per) { u8 df, vco_div_count, ref_div_count; @@ -1379,7 +1457,7 @@ static int aty_pll_gx_to_var(const struct pll_gx *pll, vco_div_count = pll->m & 0x3f; ref_div_count = pll->n; - var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df); + *vclk_per = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df); return 0; } @@ -1392,22 +1470,6 @@ static int aty_pll_gx_to_var(const struct pll_gx *pll, static void aty_set_pll_ct(const struct fb_info_aty *info, const struct pll_ct *pll) { -#if 0 /* ecd debug */ -printk("PLL_REF_DIV: %02x (%02x)\n", - pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info)); -printk("PLL_GEN_CNTL: %02x (%02x)\n", - pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info)); -printk("MCLK_FB_DIV: %02x (%02x)\n", - pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info)); -printk("PLL_VCLK_CNTL: %02x (%02x)\n", - pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info)); -printk("VCLK_POST_DIV: %02x (%02x)\n", - pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info)); -printk("VCLK0_FB_DIV: %02x (%02x)\n", - pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info)); -printk("PLL_EXT_CNTL: %02x (%02x)\n", - pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info)); -#endif /* ecd debug */ aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info); aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info); aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info); @@ -1416,10 +1478,9 @@ printk("PLL_EXT_CNTL: %02x (%02x)\n", aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info); aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info); - if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || - (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || - (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) || - (Gx == VU_CHIP_ID)) { + if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || + Gx == ET_CHIP_ID || + ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { if (info->ram_type >= SDRAM) aty_st_pll(DLL_CNTL, 0xa6, info); else @@ -1442,7 +1503,15 @@ static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, (vclk_fb_div*mclk_post_div*bpp); if (xclks_per_row < (1<<11)) FAIL("Dotclock to high"); - fifo_size = 24; + if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID || + Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || + Gx == GZ_CHIP_ID) { + fifo_size = 24; + dsp_loop_latency = 0; + } else { + fifo_size = 32; + dsp_loop_latency = 2; + } dsp_precision = 0; y = (xclks_per_row*fifo_size)>>11; while (y) { @@ -1456,21 +1525,21 @@ static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, if (info->total_vram > 1*1024*1024) { if (info->ram_type >= SDRAM) { /* >1 MB SDRAM */ - dsp_loop_latency = 8; + dsp_loop_latency += 8; page_size = 8; } else { /* >1 MB DRAM */ - dsp_loop_latency = 6; + dsp_loop_latency += 6; page_size = 9; } } else { if (info->ram_type >= SDRAM) { /* <2 MB SDRAM */ - dsp_loop_latency = 9; + dsp_loop_latency += 9; page_size = 10; } else { /* <2 MB DRAM */ - dsp_loop_latency = 8; + dsp_loop_latency += 8; page_size = 10; } } @@ -1491,11 +1560,10 @@ static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div, return 0; } -static int aty_var_to_pll_ct(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct pll_ct *pll) +static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, + u8 bpp, struct pll_ct *pll) { - u32 vclk_per, q, x; /* x is a workaround for sparc64-linux-gcc */ + u32 q, x; /* x is a workaround for sparc64-linux-gcc */ u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl; u8 mclk_fb_div, mclk_post_div, mpostdiv = 0; u8 vclk_fb_div, vclk_post_div, vpostdiv = 0; @@ -1505,7 +1573,6 @@ static int aty_var_to_pll_ct(const struct fb_info_aty *info, pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ - vclk_per = var->pixclock; pll_ref_div = info->pll_per*2*255/ref_clk_per; /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ @@ -1537,7 +1604,7 @@ static int aty_var_to_pll_ct(const struct fb_info_aty *info, vclk_fb_div = q*vclk_post_div/8; if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div, - vclk_post_div, var->bits_per_pixel, pll))) + vclk_post_div, bpp, pll))) return err; if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || @@ -1609,8 +1676,7 @@ static int aty_var_to_pll_ct(const struct fb_info_aty *info, return 0; } -static int aty_pll_ct_to_var(const struct pll_ct *pll, - struct fb_var_screeninfo *var) +static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per) { u8 pll_ref_div = pll->pll_ref_div; u8 vclk_fb_div = pll->vclk_fb_div; @@ -1624,7 +1690,7 @@ static int aty_pll_ct_to_var(const struct pll_ct *pll, (vclk_post_div & 3)]; if (vpostdiv == 0) return -EINVAL; - var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2; + *vclk_per = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2; return 0; } @@ -1657,7 +1723,7 @@ static void atyfb_set_par(const struct atyfb_par *par, aty_set_pll_ct(info, &par->pll.ct); i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff; if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))) - i |= info->mem_refresh_rate << 20; + i |= info->mem_refresh_rate << 20; switch (par->crtc.bpp) { case 8: case 24: @@ -1680,7 +1746,8 @@ static void atyfb_set_par(const struct atyfb_par *par, /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, info); aty_st_le32(BUS_CNTL, 0x7b23a040, info); - aty_st_le32(EXT_MEM_CNTL, 0x5000001, info); + aty_st_le32(EXT_MEM_CNTL, + aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); } aty_st_le32(MEM_CNTL, i, info); } @@ -1720,17 +1787,18 @@ static int atyfb_decode_var(const struct fb_var_screeninfo *var, if ((err = aty_var_to_crtc(info, var, &par->crtc))) return err; - if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID)) + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) switch (info->clk_type) { case CLK_ATI18818_1: - err = aty_var_to_pll_18818(var, &par->pll.gx); + err = aty_var_to_pll_18818(var->pixclock, &par->pll.gx); break; case CLK_IBMRGB514: - err = aty_var_to_pll_514(var, &par->pll.gx); + err = aty_var_to_pll_514(var->pixclock, &par->pll.gx); break; } else - err = aty_var_to_pll_ct(info, var, &par->pll.ct); + err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp, + &par->pll.ct); if (err) return err; @@ -1740,7 +1808,7 @@ static int atyfb_decode_var(const struct fb_var_screeninfo *var, par->accel_flags = 0; #if 0 - if (!fbmon_valid_timings(pixclock, htotal, vtotal, info)) + if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info)) return -EINVAL; #endif @@ -1757,10 +1825,10 @@ static int atyfb_encode_var(struct fb_var_screeninfo *var, if ((err = aty_crtc_to_var(&par->crtc, var))) return err; - if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID)) - err = aty_pll_gx_to_var(&par->pll.gx, var); + if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) + err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock); else - err = aty_pll_ct_to_var(&par->pll.ct, var); + err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock); if (err) return err; @@ -1853,15 +1921,15 @@ static int encode_fix(struct fb_fix_screeninfo *fix, * Reg Block 0 (CT-compatible block) is at ati_regbase_phys * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 */ - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { + if (Gx == GX_CHIP_ID || Gx == CX_CHIP_ID) { fix->mmio_start = (char *)info->ati_regbase_phys; fix->mmio_len = 0x400; fix->accel = FB_ACCEL_ATI_MACH64GX; - } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { + } else if (Gx == CT_CHIP_ID || Gx == ET_CHIP_ID) { fix->mmio_start = (char *)info->ati_regbase_phys; fix->mmio_len = 0x400; fix->accel = FB_ACCEL_ATI_MACH64CT; - } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { + } else if (Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == VV_CHIP_ID) { fix->mmio_start = (char *)(info->ati_regbase_phys-0x400); fix->mmio_len = 0x800; fix->accel = FB_ACCEL_ATI_MACH64VT; @@ -1891,32 +1959,6 @@ struct fb_var_screeninfo default_var = { 0, FB_VMODE_NONINTERLACED }; -#ifdef __sparc__ -struct fb_var_screeninfo default_var_1024x768 __initdata = { - /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ - 1024, 768, 1024, 768, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED -}; - -struct fb_var_screeninfo default_var_1152x900 __initdata = { - /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */ - 1152, 900, 1152, 900, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED -}; - -struct fb_var_screeninfo default_var_1280x1024 __initdata = { - /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ - 1280, 1024, 1280, 1024, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED -}; -#endif - /* * Get the Fixed Part of the Display @@ -1954,6 +1996,47 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con, } +static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, + int bpp, int accel) +{ + switch (bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; + disp->dispsw = &info->dispsw; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb32; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + } + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } +} + + /* * Set the User Defined Part of the Display */ @@ -2001,38 +2084,13 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, display->can_soft_blank = 1; display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; - switch (par.crtc.bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: - *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; - break; -#endif - default: - display->dispsw = NULL; - break; - } - display->scrollmode = accel ? 0 : SCROLL_YREDRAW; + atyfb_set_disp(display, info, par.crtc.bpp, accel); + if (accel) + display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; + else + display->scrollmode = SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); - if (info->cursor) { - display->dispsw->cursor = atyfb_cursor; - display->dispsw->set_font = atyfb_set_font; - } } if (con == currcon) atyfb_set_par(&par, info); @@ -2080,8 +2138,7 @@ static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, atyfb_getcolreg, - info); + return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else { @@ -2106,8 +2163,7 @@ static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, atyfb_setcolreg, - info); + return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -2117,7 +2173,27 @@ static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info) { +#ifdef __sparc__ + struct fb_info_aty *fb = (struct fb_info_aty *)info; + struct fbtype fbtyp; + + switch (cmd) { + case FBIOGTYPE: + fbtyp.fb_type = FBTYPE_PCI_GENERIC; + fbtyp.fb_width = fb->current_par.crtc.vxres; + fbtyp.fb_height = fb->current_par.crtc.vyres; + fbtyp.fb_depth = fb->current_par.crtc.bpp; + fbtyp.fb_cmsize = fb_display[con].cmap.len; + fbtyp.fb_size = fb->total_vram; + copy_to_user_ret((struct fbtype *)arg, &fbtyp, sizeof(fbtyp), -EFAULT); + break; + default: + return -EINVAL; + } + return 0; +#else return -EINVAL; +#endif } #ifdef __sparc__ @@ -2139,10 +2215,15 @@ static int atyfb_mmap(struct fb_info *info, struct file *file, /* To stop the swapper from even considering these pages. */ vma->vm_flags |= (VM_SHM | VM_LOCKED); + if (((vma->vm_offset == 0) && (size == fb->total_vram)) || + ((vma->vm_offset == fb->total_vram) && (size == PAGE_SIZE))) + vma->vm_offset += 0x8000000000000000UL; + #ifdef __sparc_v9__ /* Align it as much as desirable */ { - int j, max = -1, align; + unsigned long j, align; + int max = -1; map_offset = vma->vm_offset+size; for (i = 0; fb->mmap_map[i].size; i++) { @@ -2193,7 +2274,7 @@ static int atyfb_mmap(struct fb_info *info, struct file *file, if (start > offset) continue; - if (offset > end) + if (offset >= end) continue; map_size = fb->mmap_map[i].size - (offset - start); @@ -2237,6 +2318,78 @@ static int atyfb_mmap(struct fb_info *info, struct file *file, } return 0; } + +static struct { + u32 yoffset; + u8 r[2][256]; + u8 g[2][256]; + u8 b[2][256]; +} atyfb_save; + +static void atyfb_save_palette(struct fb_info *fb, int enter) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + int i, tmp, scale; + + for (i = 0; i < 256; i++) { + tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; + if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || + (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || + (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) || + (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID)) + tmp |= 0x2; + aty_st_8(DAC_CNTL, tmp, info); + aty_st_8(DAC_MASK, 0xff, info); + eieio(); + scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && + (info->current_par.crtc.bpp == 16)) ? 3 : 0; + info->aty_cmap_regs->rindex = i << scale; + eieio(); + atyfb_save.r[enter][i] = info->aty_cmap_regs->lut; + eieio(); + atyfb_save.g[enter][i] = info->aty_cmap_regs->lut; + eieio(); + atyfb_save.b[enter][i] = info->aty_cmap_regs->lut; + eieio(); + info->aty_cmap_regs->windex = i << scale; + eieio(); + info->aty_cmap_regs->lut = atyfb_save.r[1-enter][i]; + eieio(); + info->aty_cmap_regs->lut = atyfb_save.g[1-enter][i]; + eieio(); + info->aty_cmap_regs->lut = atyfb_save.b[1-enter][i]; + eieio(); + } +} + +static void atyfb_palette(int enter) +{ + struct fb_info_aty *info; + struct atyfb_par *par; + struct display *d; + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + d = &fb_display[i]; + if (d->fb_info && + d->fb_info->fbops == &atyfb_ops && + d->fb_info->display_fg && + d->fb_info->display_fg->vc_num == i) { + atyfb_save_palette(d->fb_info, enter); + info = (struct fb_info_aty *)d->fb_info; + par = &info->current_par; + if (enter) { + atyfb_save.yoffset = par->crtc.yoffset; + par->crtc.yoffset = 0; + set_off_pitch(par, info); + } else { + par->crtc.yoffset = atyfb_save.yoffset; + set_off_pitch(par, info); + } + break; + } + } +} #endif /* __sparc__ */ /* @@ -2250,9 +2403,9 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) int j, k; struct fb_var_screeninfo var; struct display *disp; - const char *chipname = NULL; - int pll, mclk; -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) + const char *chipname = NULL, *ramname = NULL; + int pll, mclk, gtb_memsize; +#if defined(CONFIG_PPC) int sense; #endif @@ -2269,10 +2422,11 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) printk("atyfb: Unknown mach64 0x%04x\n", Gx); return 0; } else - printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev); + printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, Gx, Rev); if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07; info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07; + ramname = aty_gx_ram[info->ram_type]; /* FIXME: clockchip/RAMDAC probing? */ #ifdef CONFIG_ATARI info->dac_type = DAC_ATI68860_B; @@ -2287,6 +2441,7 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) } else { info->bus_type = PCI; info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); + ramname = aty_ct_ram[info->ram_type]; info->dac_type = DAC_INTERNAL; info->clk_type = CLK_INTERNAL; if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { @@ -2315,10 +2470,14 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) (Gx == GU_CHIP_ID)) { /* RAGE II+ */ pll = 200; - } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || - (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || - (Gx == GQ_CHIP_ID)) { - /* RAGE PRO */ + } else if (Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || + Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || + Gx == GQ_CHIP_ID || Gx == VV_CHIP_ID || + Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || + Gx == GZ_CHIP_ID || Gx == LD_CHIP_ID || + Gx == LG_CHIP_ID || Gx == LB_CHIP_ID || + Gx == LI_CHIP_ID || Gx == LP_CHIP_ID) { + /* RAGE PRO or IIC */ pll = 230; } else { /* other RAGE */ @@ -2327,31 +2486,12 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) } } } - if (mclk < 44) - info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ - else if (mclk < 50) - info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ - else if (mclk < 55) - info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ - else if (mclk < 66) - info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ - else if (mclk < 75) - info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ - else if (mclk < 80) - info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ - else if (mclk < 100) - info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ - else - info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ - printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk); - info->pll_per = 1000000/pll; - info->mclk_per = 1000000/mclk; i = aty_ld_le32(MEM_CNTL, info); - if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || - ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID) || - (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || - (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID)) + gtb_memsize = !(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || + Gx == ET_CHIP_ID || + ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))); + if (gtb_memsize) switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ case MEM_SIZE_512K: info->total_vram = 0x80000; @@ -2398,21 +2538,93 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) info->total_vram = 0x80000; } + if (Gx == GI_CHIP_ID) { + if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000) + info->total_vram += 0x400000; + } + + if (default_vram) { + info->total_vram = default_vram*1024; + i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); + if (info->total_vram <= 0x80000) + i |= MEM_SIZE_512K; + else if (info->total_vram <= 0x100000) + i |= MEM_SIZE_1M; + else if (info->total_vram <= 0x200000) + i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; + else if (info->total_vram <= 0x400000) + i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; + else if (info->total_vram <= 0x600000) + i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; + else + i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; + aty_st_le32(MEM_CNTL, i, info); + } + if (default_pll) + pll = default_pll; + if (default_mclk) + mclk = default_mclk; + + printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n", + info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), + info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk); + + if (mclk < 44) + info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ + else if (mclk < 50) + info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ + else if (mclk < 55) + info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ + else if (mclk < 66) + info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ + else if (mclk < 75) + info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ + else if (mclk < 80) + info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ + else if (mclk < 100) + info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ + else + info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ + info->pll_per = 1000000/pll; + info->mclk_per = 1000000/mclk; + +#ifdef DEBUG + if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) { + int i; + printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " + "DSP_CONFIG DSP_ON_OFF\n" + "%08x %08x %08x %08x %08x %08x %08x\n" + "PLL", + aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), + aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), + aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), + aty_ld_le32(DSP_ON_OFF, info)); + for (i = 0; i < 16; i++) + printk(" %02x", aty_ld_pll(i, info)); + printk("\n"); + } +#endif + if (info->bus_type == ISA) if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) { /* protect GUI-regs if complete Aperture is VRAM */ info->total_vram -= GUI_RESERVE; } -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +#if defined(CONFIG_PPC) if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_CHOOSE; } if (default_vmode == VMODE_CHOOSE) { - sense = read_aty_sense(info); - default_vmode = mac_map_monitor_sense(sense); + if (Gx == LG_CHIP_ID) + /* G3 PowerBook with 1024x768 LCD */ + default_vmode = VMODE_1024_768_60; + else { + sense = read_aty_sense(info); + default_vmode = mac_map_monitor_sense(sense); + } } if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; @@ -2422,24 +2634,26 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) default_cmode = CMODE_8; if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; -#else /* !CONFIG_PMAC && !CONFIG_CHRP */ +#else /* !CONFIG_PPC */ var = default_var; -#endif /* !CONFIG_PMAC && !CONFIG_CHRP */ - var.accel_flags |= FB_ACCELF_TEXT; +#endif /* !CONFIG_PPC */ + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + + if (var.yres == var.yres_virtual) { + u32 vram = (info->total_vram - (PAGE_SIZE << 2)); + var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + if (atyfb_decode_var(&var, &info->default_par, info)) { printk("atyfb: can't set default video mode\n"); return 0; } - if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) - strcat(atyfb_name, "GX"); - else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) - strcat(atyfb_name, "CT"); - else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) - strcat(atyfb_name, "VT"); - else - strcat(atyfb_name, "GT"); - disp = &info->disp; strcpy(info->fb_info.modename, atyfb_name); @@ -2451,7 +2665,11 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) info->fb_info.switch_con = &atyfbcon_switch; info->fb_info.updatevar = &atyfbcon_updatevar; info->fb_info.blank = &atyfbcon_blank; + info->fb_info.flags = FBINFO_FLAG_DEFAULT; +#ifdef __sparc__ + atyfb_save_palette(&info->fb_info, 0); +#endif for (j = 0; j < 16; j++) { k = color_table[j]; info->palette[j].red = default_red[k]; @@ -2459,16 +2677,14 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name)) info->palette[j].blue = default_blu[k]; } - if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || - (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || - (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) || - (Gx == VU_CHIP_ID)) { - info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); - if (info->cursor) - memset(info->cursor, 0, sizeof(*info->cursor)); + if (Gx != GX_CHIP_ID && Gx != CX_CHIP_ID) { + info->cursor = aty_init_cursor(info); + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } } - - disp->dispsw = &info->dispsw; + atyfb_set_var(&var, -1, &info->fb_info); if (register_framebuffer(&info->fb_info) < 0) @@ -2489,8 +2705,12 @@ __initfunc(void atyfb_init(void)) struct fb_info_aty *info; unsigned long addr; #ifdef __sparc__ + extern void (*prom_palette) (int); extern int con_is_present(void); - u32 chip_id; + struct pcidev_cookie *pcp; + char prop[128]; + int node, len; + u32 mem, chip_id; int i, j; /* Do not attach when we have a serial console. */ @@ -2536,16 +2756,17 @@ __initfunc(void atyfb_init(void)) */ for (i = 0; i < 6 && pdev->base_address[i]; i++) /* nothing */; - j = i + 1; + j = i + 3; info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); if (!info->mmap_map) { printk("atyfb_init: can't alloc mmap_map\n"); kfree(info); + return; } - memset(info->mmap_map, 0, j * sizeof(*info->mmap_map)); - for (i = j = 0; i < 6 && pdev->base_address[i]; i++) { + + for (i = 0, j = 2; i < 6 && pdev->base_address[i]; i++) { int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); unsigned long base; u32 size, pbase; @@ -2564,8 +2785,7 @@ __initfunc(void atyfb_init(void)) size = ~(size) + 1; if (base == addr) { - info->mmap_map[j].voff = (pbase + 0x800000) - & PAGE_MASK; + info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; info->mmap_map[j].poff = __pa((base + 0x800000) & PAGE_MASK); info->mmap_map[j].size = 0x800000; @@ -2586,9 +2806,10 @@ __initfunc(void atyfb_init(void)) /* * Fix PROMs idea of MEM_CNTL settings... */ - chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE; - if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) { - u32 mem = aty_ld_le32(MEM_CNTL, info); + mem = aty_ld_le32(MEM_CNTL, info); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && + !((chip_id >> 24) & 1)) { switch (mem & 0x0f) { case 3: mem = (mem & ~(0x0f)) | 2; @@ -2606,53 +2827,93 @@ __initfunc(void atyfb_init(void)) break; } if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) - mem &= ~(0x00f00000); - aty_st_le32(MEM_CNTL, mem, info); + mem &= ~(0x00700000); } + mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ + aty_st_le32(MEM_CNTL, mem, info); /* - * Set default vmode and cmode from PROM properties. + * If this is the console device, we will set default video + * settings to what the PROM left us with. */ - { - struct pcidev_cookie *cookie = pdev->sysdata; - int node = cookie->prom_node; - int width = prom_getintdefault(node, "width", 1024); - int height = prom_getintdefault(node, "height", 768); - int depth = prom_getintdefault(node, "depth", 8); - - switch (width) { - case 1024: - if (height == 768) - default_var = default_var_1024x768; - break; - case 1152: - if (height == 900) - default_var = default_var_1152x900; - break; - case 1280: - if (height == 1024) - default_var = default_var_1280x1024; - break; - default: - break; + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "aliases"); + if (node) { + len = prom_getproperty(node, "screen", prop, sizeof(prop)); + if (len > 0) { + prop[len] = '\0'; + node = prom_finddevice(prop); + } else { + node = 0; } + } - switch (depth) { - case 8: - default_var.bits_per_pixel = 8; - break; - case 16: - default_var.bits_per_pixel = 16; - break; - case 24: - default_var.bits_per_pixel = 24; - break; - case 32: - default_var.bits_per_pixel = 32; - break; - default: - break; - } + pcp = pdev->sysdata; + if (node == pcp->prom_node) { + + struct fb_var_screeninfo *var = &default_var; + unsigned int N, P, Q, M, T; + u32 v_total, h_total; + struct crtc crtc; + u8 pll_regs[16]; + u8 clock_cntl; + + crtc.vxres = prom_getintdefault(node, "width", 1024); + crtc.vyres = prom_getintdefault(node, "height", 768); + crtc.bpp = prom_getintdefault(node, "depth", 8); + crtc.xoffset = crtc.yoffset = 0; + crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info); + crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info); + crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info); + crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info); + crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info); + aty_crtc_to_var(&crtc, var); + + h_total = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + v_total = var->yres + var->lower_margin + + var->vsync_len + var->upper_margin; + + /* + * Read the PLL to figure actual Refresh Rate. + */ + clock_cntl = aty_ld_8(CLOCK_CNTL, info); + /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */ + for (i = 0; i < 16; i++) + pll_regs[i] = aty_ld_pll(i, info); + + /* + * PLL Reference Devider M: + */ + M = pll_regs[2]; + + /* + * PLL Feedback Devider N (Dependant on CLOCK_CNTL): + */ + N = pll_regs[7 + (clock_cntl & 3)]; + + /* + * PLL Post Devider P (Dependant on CLOCK_CNTL): + */ + P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); + + /* + * PLL Devider Q: + */ + Q = N / P; + + /* + * Target Frequency: + * + * T * M + * Q = ------- + * 2 * R + * + * where R is XTALIN (= 14318 kHz). + */ + T = 2 * Q * 14318 / M; + + default_var.pixclock = 1000000000 / T; } #else /* __sparc__ */ @@ -2661,6 +2922,11 @@ __initfunc(void atyfb_init(void)) info->ati_regbase = (unsigned long) ioremap(info->ati_regbase_phys, 0x1000); + if(!info->ati_regbase) { + kfree(info); + return; + } + info->ati_regbase_phys += 0xc00; info->ati_regbase += 0xc00; @@ -2683,13 +2949,38 @@ __initfunc(void atyfb_init(void)) info->frame_buffer_phys = addr; info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + if(!info->frame_buffer) { + kfree(info); + return; + } + #endif /* __sparc__ */ if (!aty_init(info, "PCI")) { if (info->mmap_map) kfree(info->mmap_map); kfree(info); + return; } + +#ifdef __sparc__ + if (!prom_palette) + prom_palette = atyfb_palette; + + /* + * Add /dev/fb mmap values. + */ + info->mmap_map[0].voff = 0x8000000000000000UL; + info->mmap_map[0].poff = __pa(info->frame_buffer & PAGE_MASK); + info->mmap_map[0].size = info->total_vram; + info->mmap_map[0].prot_mask = _PAGE_CACHE; + info->mmap_map[0].prot_flag = _PAGE_E; + info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram; + info->mmap_map[1].poff = __pa(info->ati_regbase & PAGE_MASK); + info->mmap_map[1].size = PAGE_SIZE; + info->mmap_map[1].prot_mask = _PAGE_CACHE; + info->mmap_map[1].prot_flag = _PAGE_E; +#endif /* __sparc__ */ } } #elif defined(CONFIG_ATARI) @@ -2705,6 +2996,11 @@ __initfunc(void atyfb_init(void)) } info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_init: can't alloc fb_info_aty\n"); + return; + } + memset(info, 0, sizeof(struct fb_info_aty)); /* * Map the video memory (physical address given) to somewhere in the @@ -2736,63 +3032,78 @@ __initfunc(void atyfb_of_init(struct device_node *dp)) struct fb_info_aty *info; int i; - for (; dp; dp = dp->next) { - switch (dp->n_addrs) { - case 1: - case 3: - addr = dp->addrs[0].address; - break; - case 4: - addr = dp->addrs[1].address; - break; - default: - printk("Warning: got %d adresses for ATY:\n", dp->n_addrs); - for (i = 0; i < dp->n_addrs; i++) - printk(" %08x-%08x", dp->addrs[i].address, - dp->addrs[i].address+dp->addrs[i].size-1); - if (dp->n_addrs) - printk("\n"); - continue; - } + switch (dp->n_addrs) { + case 1: + case 2: + case 3: + addr = dp->addrs[0].address; + break; + case 4: + addr = dp->addrs[1].address; + break; + default: + printk("Warning: got %d adresses for ATY:\n", dp->n_addrs); + for (i = 0; i < dp->n_addrs; i++) + printk(" %08x-%08x", dp->addrs[i].address, + dp->addrs[i].address+dp->addrs[i].size-1); + if (dp->n_addrs) + printk("\n"); + return; + } - info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_of_init: can't alloc fb_info_aty\n"); + return; + } + memset(info, 0, sizeof(struct fb_info_aty)); - info->ati_regbase = (unsigned long)ioremap(0x7ff000+addr, - 0x1000)+0xc00; - info->ati_regbase_phys = 0x7ff000+addr; - info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys, + info->ati_regbase_phys = 0x7ff000+addr; + info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys, 0x1000); - info->ati_regbase_phys += 0xc00; - info->ati_regbase += 0xc00; - - /* enable memory-space accesses using config-space command register */ - if (pci_device_loc(dp, &bus, &devfn) == 0) { - pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); - if (cmd != 0xffff) { - cmd |= PCI_COMMAND_MEMORY; - pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); - } + + if(! info->ati_regbase) { + printk("atyfb_init: ioremap() returned NULL\n"); + kfree(info); + return; + } + + info->ati_regbase_phys += 0xc00; + info->ati_regbase += 0xc00; + + /* enable memory-space accesses using config-space command register */ + if (pci_device_loc(dp, &bus, &devfn) == 0) { + pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); + if (cmd != 0xffff) { + cmd |= PCI_COMMAND_MEMORY; + pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); } + } #ifdef __BIG_ENDIAN - /* Use the big-endian aperture */ - addr += 0x800000; + /* Use the big-endian aperture */ + addr += 0x800000; #endif - /* Map in frame buffer */ - info->frame_buffer_phys = addr; - info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + /* Map in frame buffer */ + info->frame_buffer_phys = addr; + info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); - if (!aty_init(info, dp->full_name)) { + if(! info->frame_buffer) { + printk("atyfb_init: ioremap() returned NULL\n"); kfree(info); return; - } + } + + if (!aty_init(info, dp->full_name)) { + kfree(info); + return; + } #ifdef CONFIG_FB_COMPAT_XPMAC - if (!console_fb_info) - console_fb_info = &info->fb_info; + if (!console_fb_info) + console_fb_info = &info->fb_info; #endif /* CONFIG_FB_COMPAT_XPMAC */ - } } #endif /* CONFIG_FB_OF */ @@ -2816,25 +3127,35 @@ __initfunc(void atyfb_setup(char *options, int *ints)) break; memcpy(fontname, this_opt + 5, i); fontname[i] = 0; - } -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) - if (!strncmp(this_opt, "vmode:", 6)) { - int vmode = simple_strtoul(this_opt+6, NULL, 0); + } else if (!strncmp(this_opt, "noblink", 7)) { + curblink = 0; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "vram:", 5)) + default_vram = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "pll:", 4)) + default_pll = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "mclk:", 5)) + default_mclk = simple_strtoul(this_opt+5, NULL, 0); +#if defined(CONFIG_PPC) + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) default_vmode = vmode; } else if (!strncmp(this_opt, "cmode:", 6)) { - int depth = simple_strtoul(this_opt+6, NULL, 0); - switch (depth) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: case 8: - default_cmode = 0; + default_cmode = CMODE_8; break; case 15: case 16: - default_cmode = 1; + default_cmode = CMODE_16; break; case 24: case 32: - default_cmode = 2; + default_cmode = CMODE_32; break; } } @@ -2844,7 +3165,7 @@ __initfunc(void atyfb_setup(char *options, int *ints)) * Why do we need this silly Mach64 argument? * We are already here because of mach64= so its redundant. */ - if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { + else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { static unsigned char m64_num; static char mach64_str[80]; strncpy(mach64_str, this_opt+7, 80); @@ -2914,8 +3235,7 @@ static int atyfbcon_switch(int con, struct fb_info *fb) /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - atyfb_getcolreg, fb); + fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); /* Erase HW Cursor */ if (info->cursor) @@ -2926,6 +3246,8 @@ static int atyfbcon_switch(int con, struct fb_info *fb) atyfb_decode_var(&fb_display[con].var, &par, info); atyfb_set_par(&par, info); + atyfb_set_disp(&fb_display[con], info, par.crtc.bpp, + par.accel_flags & FB_ACCELF_TEXT); /* Install new colormap */ do_install_cmap(con, fb); @@ -2940,19 +3262,6 @@ static int atyfbcon_switch(int con, struct fb_info *fb) } /* - * Update the `var' structure (called by fbcon.c) - */ - -static int atyfbcon_updatevar(int con, struct fb_info *fb) -{ - struct fb_info_aty *info = (struct fb_info_aty *)fb; - - info->current_par.crtc.yoffset = fb_display[con].var.yoffset; - set_off_pitch(&info->current_par, info); - return 0; -} - - /* * Blank the display. */ @@ -2995,9 +3304,10 @@ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, if (regno > 255) return 1; - *red = info->palette[regno].red; - *green = info->palette[regno].green; - *blue = info->palette[regno].blue; + *red = (info->palette[regno].red<<8) | info->palette[regno].red; + *green = (info->palette[regno].green<<8) | info->palette[regno].green; + *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; + *transp = 0; return 0; } @@ -3016,6 +3326,9 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, if (regno > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; info->palette[regno].red = red; info->palette[regno].green = green; info->palette[regno].blue = blue; @@ -3025,30 +3338,39 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID)) i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ aty_st_8(DAC_CNTL, i, info); - aty_st_8(DAC_REGS + DAC_MASK, 0xff, info); + aty_st_8(DAC_MASK, 0xff, info); eieio(); scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) && (info->current_par.crtc.bpp == 16)) ? 3 : 0; info->aty_cmap_regs->windex = regno << scale; eieio(); - info->aty_cmap_regs->lut = red << scale; + info->aty_cmap_regs->lut = red; eieio(); - info->aty_cmap_regs->lut = green << scale; + info->aty_cmap_regs->lut = green; eieio(); - info->aty_cmap_regs->lut = blue << scale; + info->aty_cmap_regs->lut = blue; eieio(); - if (regno < 16) { + if (regno < 16) + switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; + case 16: + info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; #endif #ifdef FBCON_HAS_CFB24 - fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno; + case 24: + info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | + regno; + break; #endif #ifdef FBCON_HAS_CFB32 - fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | - (regno << 8) | regno; + case 32: + i = (regno << 8) | regno; + info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; #endif - } + } return 0; } @@ -3058,12 +3380,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - atyfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, - atyfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); } } @@ -3113,14 +3433,8 @@ static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, } else direction |= DST_X_LEFT_TO_RIGHT; - wait_for_fifo(5, info); + wait_for_fifo(4, info); aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info); - /* - * ++Geert: - * Warning: SRC_OFF_PITCH may be thrashed by writing to other registers - * (e.g. CRTC_H_TOTAL_DISP, DP_SRC, DP_FRGD_CLR) - */ - aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info); aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info); aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info); aty_st_le32(DST_CNTL, direction, info); @@ -3149,6 +3463,50 @@ static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height, draw_rect(dstx, dsty, width, height, info); } + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int atyfbcon_updatevar(int con, struct fb_info *fb) +{ + struct fb_info_aty *info = (struct fb_info_aty *)fb; + struct atyfb_par *par = &info->current_par; + struct display *p = &fb_display[con]; + struct vc_data *conp = p->conp; + u32 yres, yoffset, sy, height; + + yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; + yoffset = fb_display[con].var.yoffset; + + sy = (conp->vc_rows + p->yscroll) * fontheight(p); + height = yres - conp->vc_rows * fontheight(p); + + if (height && (yoffset + yres > sy)) { + u32 xres, xoffset; + u32 bgx; + + xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; + xoffset = fb_display[con].var.xoffset; + + + bgx = attr_bgcol_ec(p, conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sy + height > par->crtc.vyres) { + wait_for_fifo(1, info); + aty_st_le32(SC_BOTTOM, sy + height - 1, info); + } + aty_rectfill(xoffset, sy, xres, height, bgx, info); + } + + if (info->cursor && (yoffset + yres <= sy)) + atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); + + info->current_par.crtc.yoffset = yoffset; + set_off_pitch(&info->current_par, info); + return 0; +} /* * Text console acceleration @@ -3164,12 +3522,12 @@ static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx, return; #endif - sx *= p->fontwidth; - sy *= p->fontheight; - dx *= p->fontwidth; - dy *= p->fontheight; - width *= p->fontwidth; - height *= p->fontheight; + sx *= fontwidth(p); + sy *= fontheight(p); + dx *= fontwidth(p); + dy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); aty_rectcopy(sx, sy, dx, dy, width, height, (struct fb_info_aty *)p->fb_info); @@ -3190,10 +3548,10 @@ static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy, bgx |= (bgx << 8); bgx |= (bgx << 16); - sx *= p->fontwidth; - sy *= p->fontheight; - width *= p->fontwidth; - height *= p->fontheight; + sx *= fontwidth(p); + sy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); aty_rectfill(sx, sy, width, height, bgx, (struct fb_info_aty *)p->fb_info); diff --git a/drivers/video/bwtwofb.c b/drivers/video/bwtwofb.c index a907fc2d1..00db47d10 100644 --- a/drivers/video/bwtwofb.c +++ b/drivers/video/bwtwofb.c @@ -1,4 +1,4 @@ -/* $Id: bwtwofb.c,v 1.1 1998/07/21 14:50:48 jj Exp $ +/* $Id: bwtwofb.c,v 1.6 1998/09/15 15:45:35 jj Exp $ * bwtwofb.c: BWtwo frame buffer driver * * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -23,13 +23,13 @@ #include <linux/init.h> #include <linux/selection.h> -#include "sbusfb.h" +#include <video/sbusfb.h> #include <asm/io.h> #ifndef __sparc_v9__ #include <asm/sun4paddr.h> #endif -#include "fbcon-mfb.h" +#include <video/fbcon-mfb.h> /* OBio addresses for the bwtwo registers */ #define BWTWO_REGISTER_OFFSET 0x400000 @@ -63,6 +63,7 @@ struct bw2_regs { #define BWTWO_SR_ID_MONO 0x02 #define BWTWO_SR_ID_MONO_ECL 0x03 #define BWTWO_SR_ID_MSYNC 0x04 +#define BWTWO_SR_ID_NOCONN 0x0a /* Control Register Constants */ #define BWTWO_CTL_ENABLE_INTS 0x80 @@ -94,7 +95,7 @@ static void bw2_unblank (struct fb_info_sbusfb *fb) static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) { - p->screen_base += ((y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin)) >> 3; + p->screen_base += (y_margin - fb->y_margin) * p->line_length + ((x_margin - fb->x_margin) >> 3); } static u8 bw2regs_1600[] __initdata = { @@ -134,13 +135,13 @@ static u8 bw2regs_66hz[] __initdata = { static char idstring[60] __initdata = { 0 }; -__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb)) +char __init *bwtwofb_init(struct fb_info_sbusfb *fb) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; #ifdef CONFIG_SUN4 - unsigned long phys = SUN4_300_BWTWO_PHYSADDR; + unsigned long phys = sun4_bwtwo_physaddr; #else unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; #endif @@ -152,7 +153,7 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb)) if (!fb->s.bw2.regs) { fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0, sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0); - if (!prom_getbool(fb->prom_node, "width")) { + if ((!ARCH_SUN4) && (!prom_getbool(fb->prom_node, "width"))) { /* Ugh, broken PROM didn't initialize us. * Let's deal with this ourselves. */ @@ -182,6 +183,8 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb)) else p = bw2regs_66hz; break; + case BWTWO_SR_ID_NOCONN: + return NULL; default: prom_printf("bw2: can't handle SR %02x\n", status); @@ -198,15 +201,18 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb)) fix->line_length = fb->var.xres_virtual>>3; disp->scrollmode = SCROLL_YREDRAW; + disp->inverse = 1; if (!disp->screen_base) disp->screen_base = (char *)sparc_alloc_io(phys, 0, type->fb_size, "bw2_ram", fb->iospace, 0); - disp->screen_base += (fix->line_length * fb->y_margin + fb->x_margin) >> 3; + disp->screen_base += fix->line_length * fb->y_margin + (fb->x_margin >> 3); fb->dispsw = fbcon_mfb; fix->visual = FB_VISUAL_MONO01; +#ifndef CONFIG_SUN4 fb->blank = bw2_blank; fb->unblank = bw2_unblank; +#endif fb->margins = bw2_margins; fb->physbase = phys; diff --git a/drivers/video/cgfourteenfb.c b/drivers/video/cgfourteenfb.c new file mode 100644 index 000000000..f22389921 --- /dev/null +++ b/drivers/video/cgfourteenfb.c @@ -0,0 +1,384 @@ +/* $Id: cgfourteenfb.c,v 1.3 1998/09/04 15:43:41 jj Exp $ + * cgfourteenfb.c: CGfourteen frame buffer driver + * + * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/selection.h> + +#include <video/sbusfb.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +#include <video/fbcon-cfb8.h> + +#define CG14_MCR_INTENABLE_SHIFT 7 +#define CG14_MCR_INTENABLE_MASK 0x80 +#define CG14_MCR_VIDENABLE_SHIFT 6 +#define CG14_MCR_VIDENABLE_MASK 0x40 +#define CG14_MCR_PIXMODE_SHIFT 4 +#define CG14_MCR_PIXMODE_MASK 0x30 +#define CG14_MCR_TMR_SHIFT 2 +#define CG14_MCR_TMR_MASK 0x0c +#define CG14_MCR_TMENABLE_SHIFT 1 +#define CG14_MCR_TMENABLE_MASK 0x02 +#define CG14_MCR_RESET_SHIFT 0 +#define CG14_MCR_RESET_MASK 0x01 +#define CG14_REV_REVISION_SHIFT 4 +#define CG14_REV_REVISION_MASK 0xf0 +#define CG14_REV_IMPL_SHIFT 0 +#define CG14_REV_IMPL_MASK 0x0f +#define CG14_VBR_FRAMEBASE_SHIFT 12 +#define CG14_VBR_FRAMEBASE_MASK 0x00fff000 +#define CG14_VMCR1_SETUP_SHIFT 0 +#define CG14_VMCR1_SETUP_MASK 0x000001ff +#define CG14_VMCR1_VCONFIG_SHIFT 9 +#define CG14_VMCR1_VCONFIG_MASK 0x00000e00 +#define CG14_VMCR2_REFRESH_SHIFT 0 +#define CG14_VMCR2_REFRESH_MASK 0x00000001 +#define CG14_VMCR2_TESTROWCNT_SHIFT 1 +#define CG14_VMCR2_TESTROWCNT_MASK 0x00000002 +#define CG14_VMCR2_FBCONFIG_SHIFT 2 +#define CG14_VMCR2_FBCONFIG_MASK 0x0000000c +#define CG14_VCR_REFRESHREQ_SHIFT 0 +#define CG14_VCR_REFRESHREQ_MASK 0x000003ff +#define CG14_VCR1_REFRESHENA_SHIFT 10 +#define CG14_VCR1_REFRESHENA_MASK 0x00000400 +#define CG14_VCA_CAD_SHIFT 0 +#define CG14_VCA_CAD_MASK 0x000003ff +#define CG14_VCA_VERS_SHIFT 10 +#define CG14_VCA_VERS_MASK 0x00000c00 +#define CG14_VCA_RAMSPEED_SHIFT 12 +#define CG14_VCA_RAMSPEED_MASK 0x00001000 +#define CG14_VCA_8MB_SHIFT 13 +#define CG14_VCA_8MB_MASK 0x00002000 + +#define CG14_MCR_PIXMODE_8 0 +#define CG14_MCR_PIXMODE_16 2 +#define CG14_MCR_PIXMODE_32 3 + +struct cg14_regs{ + volatile u8 mcr; /* Master Control Reg */ + volatile u8 ppr; /* Packed Pixel Reg */ + volatile u8 tms[2]; /* Test Mode Status Regs */ + volatile u8 msr; /* Master Status Reg */ + volatile u8 fsr; /* Fault Status Reg */ + volatile u8 rev; /* Revision & Impl */ + volatile u8 ccr; /* Clock Control Reg */ + volatile u32 tmr; /* Test Mode Read Back */ + volatile u8 mod; /* Monitor Operation Data Reg */ + volatile u8 acr; /* Aux Control */ + u8 xxx0[6]; + volatile u16 hct; /* Hor Counter */ + volatile u16 vct; /* Vert Counter */ + volatile u16 hbs; /* Hor Blank Start */ + volatile u16 hbc; /* Hor Blank Clear */ + volatile u16 hss; /* Hor Sync Start */ + volatile u16 hsc; /* Hor Sync Clear */ + volatile u16 csc; /* Composite Sync Clear */ + volatile u16 vbs; /* Vert Blank Start */ + volatile u16 vbc; /* Vert Blank Clear */ + volatile u16 vss; /* Vert Sync Start */ + volatile u16 vsc; /* Vert Sync Clear */ + volatile u16 xcs; + volatile u16 xcc; + volatile u16 fsa; /* Fault Status Address */ + volatile u16 adr; /* Address Registers */ + u8 xxx1[0xce]; + volatile u8 pcg[0x100]; /* Pixel Clock Generator */ + volatile u32 vbr; /* Frame Base Row */ + volatile u32 vmcr; /* VBC Master Control */ + volatile u32 vcr; /* VBC refresh */ + volatile u32 vca; /* VBC Config */ +}; + +#define CG14_CCR_ENABLE 0x04 +#define CG14_CCR_SELECT 0x02 /* HW/Full screen */ + +struct cg14_cursor { + volatile u32 cpl0[32]; /* Enable plane 0 */ + volatile u32 cpl1[32]; /* Color selection plane */ + volatile u8 ccr; /* Cursor Control Reg */ + u8 xxx0[3]; + volatile u16 cursx; /* Cursor x,y position */ + volatile u16 cursy; /* Cursor x,y position */ + volatile u32 color0; + volatile u32 color1; + u32 xxx1[0x1bc]; + volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */ + volatile u32 cpl1i[32]; /* Color selection autoinc */ +}; + +struct cg14_dac { + volatile u8 addr; /* Address Register */ + u8 xxx0[255]; + volatile u8 glut; /* Gamma table */ + u8 xxx1[255]; + volatile u8 select; /* Register Select */ + u8 xxx2[255]; + volatile u8 mode; /* Mode Register */ +}; + +struct cg14_xlut{ + volatile u8 x_xlut [256]; + volatile u8 x_xlutd [256]; + u8 xxx0[0x600]; + volatile u8 x_xlut_inc [256]; + volatile u8 x_xlutd_inc [256]; +}; + +/* Color look up table (clut) */ +/* Each one of these arrays hold the color lookup table (for 256 + * colors) for each MDI page (I assume then there should be 4 MDI + * pages, I still wonder what they are. I have seen NeXTStep split + * the screen in four parts, while operating in 24 bits mode. Each + * integer holds 4 values: alpha value (transparency channel, thanks + * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue + * + * I currently use the clut instead of the Xlut + */ +struct cg14_clut { + unsigned int c_clut [256]; + unsigned int c_clutd [256]; /* i wonder what the 'd' is for */ + unsigned int c_clut_inc [256]; + unsigned int c_clutd_inc [256]; +}; + +static struct sbus_mmap_map cg14_mmap_map[] __initdata = { + { CG14_REGS, 0x80000000, 0x1000 }, + { CG14_XLUT, 0x80003000, 0x1000 }, + { CG14_CLUT1, 0x80004000, 0x1000 }, + { CG14_CLUT2, 0x80005000, 0x1000 }, + { CG14_CLUT3, 0x80006000, 0x1000 }, + { CG3_MMAP_OFFSET - + 0x7000, 0x80000000, 0x7000 }, + { CG3_MMAP_OFFSET, 0x00000000, SBUS_MMAP_FBSIZE(1) }, + { MDI_CURSOR_MAP, 0x80001000, 0x1000 }, + { MDI_CHUNKY_BGR_MAP, 0x01000000, 0x400000 }, + { MDI_PLANAR_X16_MAP, 0x02000000, 0x200000 }, + { MDI_PLANAR_C16_MAP, 0x02800000, 0x200000 }, + { MDI_PLANAR_X32_MAP, 0x03000000, 0x100000 }, + { MDI_PLANAR_B32_MAP, 0x03400000, 0x100000 }, + { MDI_PLANAR_G32_MAP, 0x03800000, 0x100000 }, + { MDI_PLANAR_R32_MAP, 0x03c00000, 0x100000 }, + { 0, 0, 0 } +}; + +static void cg14_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) +{ + struct cg14_clut *clut = fb->s.cg14.clut; + + for (; count--; index++) + clut->c_clut[index] = + (fb->color_map CM(index,2) << 16) | + (fb->color_map CM(index,1) << 8) | + (fb->color_map CM(index,0)); +} + +static void cg14_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) +{ + p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin); +} + +static void cg14_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue) +{ + struct cg14_cursor *cur = fb->s.cg14.cursor; + + cur->color0 = ((red[0]) | (green[0] << 8) | (blue[0] << 16)); + cur->color1 = ((red[1]) | (green[1] << 8) | (blue[1] << 16)); +} + +/* Set cursor shape */ +static void cg14_setcurshape (struct fb_info_sbusfb *fb) +{ + struct cg14_cursor *cur = fb->s.cg14.cursor; + int i; + + for (i = 0; i < 32; i++){ + cur->cpl0 [i] = fb->cursor.bits[0][i]; + cur->cpl1 [i] = fb->cursor.bits[1][i]; + } +} + +/* Load cursor information */ +static void cg14_setcursor (struct fb_info_sbusfb *fb) +{ + struct cg_cursor *c = &fb->cursor; + struct cg14_cursor *cur = fb->s.cg14.cursor; + + if (c->enable) + cur->ccr |= CG14_CCR_ENABLE; + cur->cursx = ((c->cpos.fbx - c->chot.fbx) & 0xfff); + cur->cursy = ((c->cpos.fby - c->chot.fby) & 0xfff); +} + +static void cg14_switch_from_graph (struct fb_info_sbusfb *fb) +{ + /* Set the 8-bpp mode */ + if (fb->open && fb->mmaped){ + volatile char *mcr = &fb->s.cg14.regs->mcr; + + fb->s.cg14.mode = 8; + *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK)); + } +} + +static void cg14_reset (struct fb_info_sbusfb *fb) +{ + volatile char *mcr = &fb->s.cg14.regs->mcr; + + *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK)); +} + +static int cg14_ioctl (struct fb_info_sbusfb *fb, unsigned int cmd, unsigned long arg) +{ + volatile char *mcr = &fb->s.cg14.regs->mcr; + struct mdi_cfginfo *mdii; + int mode; + + switch (cmd) { + case MDI_RESET: + *mcr = (*mcr & ~CG14_MCR_PIXMODE_MASK); + break; + case MDI_GET_CFGINFO: + mdii = (struct mdi_cfginfo *)arg; + put_user_ret(FBTYPE_MDICOLOR, &mdii->mdi_type, -EFAULT); + __put_user_ret(fb->type.fb_height, &mdii->mdi_height, -EFAULT); + __put_user_ret(fb->type.fb_width, &mdii->mdi_width, -EFAULT); + __put_user_ret(fb->s.cg14.mode, &mdii->mdi_mode, -EFAULT); + __put_user_ret(72, &mdii->mdi_pixfreq, -EFAULT); /* FIXME */ + __put_user_ret(fb->s.cg14.ramsize, &mdii->mdi_size, -EFAULT); + break; + case MDI_SET_PIXELMODE: + get_user_ret(mode, (int *)arg, -EFAULT); + switch (mode){ + case MDI_32_PIX: + *mcr = (*mcr & ~CG14_MCR_PIXMODE_MASK) | + (CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT); + break; + case MDI_16_PIX: + *mcr = (*mcr & ~CG14_MCR_PIXMODE_MASK) | 0x20; + break; + case MDI_8_PIX: + *mcr = (*mcr & ~CG14_MCR_PIXMODE_MASK); + break; + default: + return -ENOSYS; + } + fb->s.cg14.mode = mode; + break; + default: + return -EINVAL; + } + return 0; +} + +__initfunc(static unsigned long get_phys(unsigned long addr)) +{ + return __get_phys(addr); +} + +__initfunc(static int get_iospace(unsigned long addr)) +{ + return __get_iospace(addr); +} + +static char idstring[60] __initdata = { 0 }; + +__initfunc(char *cgfourteenfb_init(struct fb_info_sbusfb *fb)) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct display *disp = &fb->disp; + struct fbtype *type = &fb->type; + unsigned long rphys, phys; + u32 bases[6]; + int is_8mb, i; + +#ifndef FBCON_HAS_CFB8 + return NULL; +#endif + prom_getproperty (fb->prom_node, "address", (char *) &bases[0], 8); + if (!bases[0]) { + printk("cg14 not mmaped\n"); + return NULL; + } + if (get_iospace(bases[0]) != get_iospace(bases[1])) { + printk("Ugh. cg14 iospaces don't match\n"); + return NULL; + } + fb->physbase = phys = get_phys(bases[1]); + rphys = get_phys(bases[0]); + fb->iospace = get_iospace(bases[0]); + fb->s.cg14.regs = (struct cg14_regs *)(unsigned long)bases[0]; + fb->s.cg14.clut = (void *)((unsigned long)bases[0]+CG14_CLUT1); + fb->s.cg14.cursor = (void *)((unsigned long)bases[0]+CG14_CURSORREGS); + disp->screen_base = (char *)bases[1]; + + /* CG14_VCA_8MB_MASK is not correctly set on the 501-2482 + * VSIMM, so we read the memory size from the PROM + */ + prom_getproperty(fb->prom_node, "reg", (char *) &bases[0], 24); + is_8mb = bases[5] == 0x800000; + + fb->mmap_map = kmalloc(sizeof(cg14_mmap_map), GFP_KERNEL); + if (!fb->mmap_map) + return NULL; + + for (i = 0; ; i++) { + fb->mmap_map[i].voff = cg14_mmap_map[i].voff; + fb->mmap_map[i].poff = (cg14_mmap_map[i].poff & 0x80000000) ? + (cg14_mmap_map[i].poff & 0x7fffffff) + rphys - phys : + cg14_mmap_map[i].poff; + fb->mmap_map[i].size = cg14_mmap_map[i].size; + if (is_8mb && fb->mmap_map[i].size >= 0x100000 && + fb->mmap_map[i].size <= 0x400000) + fb->mmap_map[i].size <<= 1; + if (!cg14_mmap_map[i].size) + break; + } + + strcpy(fb->info.modename, "CGfourteen"); + strcpy(fix->id, "CGfourteen"); + fix->line_length = fb->var.xres_virtual; + + disp->scrollmode = SCROLL_YREDRAW; + disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; + fb->dispsw = fbcon_cfb8; + + type->fb_depth = 24; + fb->emulations[1] = FBTYPE_SUN3COLOR; + + fb->margins = cg14_margins; + fb->loadcmap = cg14_loadcmap; + fb->setcursor = cg14_setcursor; + fb->setcursormap = cg14_setcursormap; + fb->setcurshape = cg14_setcurshape; + fb->reset = cg14_reset; + fb->switch_from_graph = cg14_switch_from_graph; + fb->ioctl = cg14_ioctl; + + fb->s.cg14.mode = 8; + fb->s.cg14.ramsize = (is_8mb) ? 0x800000 : 0x400000; + + cg14_reset(fb); + + sprintf(idstring, "cgfourteen at %x.%08lx, %dMB, rev=%d, impl=%d", fb->iospace, phys, + is_8mb ? 8 : 4, fb->s.cg14.regs->rev >> 4, fb->s.cg14.regs->rev & 0xf); + + return idstring; +} diff --git a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c index d5fc9f495..4e0bc74ed 100644 --- a/drivers/video/cgsixfb.c +++ b/drivers/video/cgsixfb.c @@ -1,4 +1,4 @@ -/* $Id: cgsixfb.c,v 1.7 1998/07/22 12:44:59 jj Exp $ +/* $Id: cgsixfb.c,v 1.11 1998/09/04 15:43:42 jj Exp $ * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -6,7 +6,6 @@ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -22,7 +21,7 @@ #include <linux/init.h> #include <linux/selection.h> -#include "sbusfb.h" +#include <video/sbusfb.h> #include <asm/io.h> /* Offset of interesting structures in the OBIO space */ @@ -246,15 +245,15 @@ static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx, fbc->clip = 0; fbc->pm = ~(0); - if (p->fontheightlog) { - y = sy << p->fontheightlog; h = height << p->fontheightlog; + if (fontheightlog(p)) { + y = sy << fontheightlog(p); h = height << fontheightlog(p); } else { - y = sy * p->fontheight; h = height * p->fontheight; + y = sy * fontheight(p); h = height * fontheight(p); } - if (p->fontwidthlog) { - x = sx << p->fontwidthlog; w = width << p->fontwidthlog; + if (fontwidthlog(p)) { + x = sx << fontwidthlog(p); w = width << fontwidthlog(p); } else { - x = sx * p->fontwidth; w = width * p->fontwidth; + x = sx * fontwidth(p); w = width * fontwidth(p); } fbc->arecty = y + fb->y_margin; fbc->arectx = x + fb->x_margin; @@ -300,26 +299,21 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int int i, x, y; u8 *fd; - if (p->fontheightlog) { - y = fb->y_margin + (yy << p->fontheightlog); - i = ((c & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) { + y = fb->y_margin + (yy << fontheightlog(p)); + i = ((c & p->charmask) << fontheightlog(p)); } else { - y = fb->y_margin + (yy * p->fontheight); - i = (c & p->charmask) * p->fontheight; + y = fb->y_margin + (yy * fontheight(p)); + i = (c & p->charmask) * fontheight(p); } -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - fd = p->fontdata + i; - x = fb->x_margin + xx * 8; -#else - if (p->fontwidth <= 8) + if (fontwidth(p) <= 8) fd = p->fontdata + i; else fd = p->fontdata + (i << 1); - if (p->fontwidthlog) - x = fb->x_margin + (xx << p->fontwidthlog); + if (fontwidthlog(p)) + x = fb->x_margin + (xx << fontwidthlog(p)); else - x = fb->x_margin + (xx * p->fontwidth); -#endif + x = fb->x_margin + (xx * fontwidth(p)); do { i = fbc->s; } while (i & 0x10000000); @@ -334,21 +328,17 @@ static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int fbc->incx = 0; fbc->incy = 1; fbc->x0 = x; - fbc->x1 = x + p->fontwidth - 1; + fbc->x1 = x + fontwidth(p) - 1; fbc->y0 = y; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif - for (i = 0; i < p->fontheight; i++) + if (fontwidth(p) <= 8) { + for (i = 0; i < fontheight(p); i++) fbc->font = *fd++ << 24; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { - for (i = 0; i < p->fontheight; i++) { + for (i = 0; i < fontheight(p); i++) { fbc->font = *(u16 *)fd << 16; fd += 2; } } -#endif } static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, @@ -372,50 +362,41 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh fbc->pm = 0xff; x = fb->x_margin; y = fb->y_margin; -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - x += xx * 8; -#else - if (p->fontwidthlog) - x += (xx << p->fontwidthlog); + if (fontwidthlog(p)) + x += (xx << fontwidthlog(p)); else - x += xx * p->fontwidth; -#endif - if (p->fontheightlog) - y += (yy << p->fontheightlog); + x += xx * fontwidth(p); + if (fontheightlog(p)) + y += (yy << fontheightlog(p)); else - y += (yy * p->fontheight); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif + y += (yy * fontheight(p)); + if (fontwidth(p) <= 8) { while (count >= 4) { count -= 4; fbc->incx = 0; fbc->incy = 1; fbc->x0 = x; - fbc->x1 = (x += 4 * p->fontwidth) - 1; + fbc->x1 = (x += 4 * fontwidth(p)) - 1; fbc->y0 = y; - if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); } else { - fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd1 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth == 8) { -#endif - for (i = 0; i < p->fontheight; i++) + if (fontwidth(p) == 8) { + for (i = 0; i < fontheight(p); i++) fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) << 8)) << 8)) << 8); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { - for (i = 0; i < p->fontheight; i++) + for (i = 0; i < fontheight(p); i++) fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) - << p->fontwidth)) << p->fontwidth)) << p->fontwidth)) << (24 - 3 * p->fontwidth); + << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p)); } } } else { @@ -424,48 +405,43 @@ static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned sh fbc->incx = 0; fbc->incy = 1; fbc->x0 = x; - fbc->x1 = (x += 2 * p->fontwidth) - 1; + fbc->x1 = (x += 2 * fontwidth(p)) - 1; fbc->y0 = y; - if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); - fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + fd2 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); } else { - fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); - fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); + fd1 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + fd2 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); } - for (i = 0; i < p->fontheight; i++) { - fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth); + for (i = 0; i < fontheight(p); i++) { + fbc->font = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p)); fd1 += 2; fd2 += 2; } } -#endif } while (count) { count--; fbc->incx = 0; fbc->incy = 1; fbc->x0 = x; - fbc->x1 = (x += p->fontwidth) - 1; + fbc->x1 = (x += fontwidth(p)) - 1; fbc->y0 = y; - if (p->fontheightlog) - i = ((*s++ & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) + i = ((*s++ & p->charmask) << fontheightlog(p)); else - i = ((*s++ & p->charmask) * p->fontheight); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif + i = ((*s++ & p->charmask) * fontheight(p)); + if (fontwidth(p) <= 8) { fd1 = p->fontdata + i; - for (i = 0; i < p->fontheight; i++) + for (i = 0; i < fontheight(p); i++) fbc->font = *fd1++ << 24; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { fd1 = p->fontdata + (i << 1); - for (i = 0; i < p->fontheight; i++) { + for (i = 0; i < fontheight(p); i++) { fbc->font = *(u16 *)fd1 << 16; fd1 += 2; } } -#endif } } @@ -474,7 +450,7 @@ static void cg6_revc(struct display *p, int xx, int yy) /* Not used if hw cursor */ } -static void cg6_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) { struct bt_regs *bt = fb->s.cg6.bt; int i; @@ -556,11 +532,13 @@ static void cg6_unblank (struct fb_info_sbusfb *fb) static void cg6_reset (struct fb_info_sbusfb *fb) { unsigned int rev, conf; + struct cg6_tec *tec = fb->s.cg6.tec; + struct cg6_fbc *fbc = fb->s.cg6.fbc; /* Turn off stuff in the Transform Engine. */ - fb->s.cg6.tec->tec_matrix = 0; - fb->s.cg6.tec->tec_clip = 0; - fb->s.cg6.tec->tec_vdc = 0; + tec->tec_matrix = 0; + tec->tec_clip = 0; + tec->tec_vdc = 0; /* Take care of bugs in old revisions. */ rev = (*(fb->s.cg6.fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK; @@ -575,21 +553,21 @@ static void cg6_reset (struct fb_info_sbusfb *fb) } /* Set things in the FBC. */ - fb->s.cg6.fbc->mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | - CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | - CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | - CG6_FBC_BDISP_MASK); - fb->s.cg6.fbc->mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | - CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | - CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | - CG6_FBC_BDISP_0); - fb->s.cg6.fbc->clip = 0; - fb->s.cg6.fbc->offx = 0; - fb->s.cg6.fbc->offy = 0; - fb->s.cg6.fbc->clipminx = 0; - fb->s.cg6.fbc->clipminy = 0; - fb->s.cg6.fbc->clipmaxx = fb->type.fb_width - 1; - fb->s.cg6.fbc->clipmaxy = fb->type.fb_height - 1; + fbc->mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | + CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | + CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | + CG6_FBC_BDISP_MASK); + fbc->mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | + CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | + CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | + CG6_FBC_BDISP_0); + fbc->clip = 0; + fbc->offx = 0; + fbc->offy = 0; + fbc->clipminx = 0; + fbc->clipminy = 0; + fbc->clipmaxx = fb->type.fb_width - 1; + fbc->clipmaxy = fb->type.fb_height - 1; /* Enable cursor in Brooktree DAC. */ fb->s.cg6.bt->addr = 0x06 << 24; fb->s.cg6.bt->control |= 0x03 << 24; @@ -611,6 +589,7 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; u32 conf; char *p; + struct bt_regs *bt; strcpy(fb->info.modename, "CGsix"); @@ -631,7 +610,7 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) sizeof(struct cg6_tec), "cgsix_tec", fb->iospace, 0); fb->s.cg6.thc = (struct cg6_thc *)sparc_alloc_io(phys + CG6_THC_OFFSET, 0, sizeof(struct cg6_thc), "cgsix_thc", fb->iospace, 0); - fb->s.cg6.bt = (struct bt_regs *)sparc_alloc_io(phys + CG6_BROOKTREE_OFFSET, 0, + fb->s.cg6.bt = bt = (struct bt_regs *)sparc_alloc_io(phys + CG6_BROOKTREE_OFFSET, 0, sizeof(struct bt_regs), "cgsix_dac", fb->iospace, 0); fb->s.cg6.fhc = (u32 *)sparc_alloc_io(phys + CG6_FHC_OFFSET, 0, sizeof(u32), "cgsix_fhc", fb->iospace, 0); @@ -652,14 +631,14 @@ __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) fb->mmap_map = cg6_mmap_map; /* Initialize Brooktree DAC */ - fb->s.cg6.bt->addr = 0x04 << 24; /* color planes */ - fb->s.cg6.bt->control = 0xff << 24; - fb->s.cg6.bt->addr = 0x05 << 24; - fb->s.cg6.bt->control = 0x00 << 24; - fb->s.cg6.bt->addr = 0x06 << 24; /* overlay plane */ - fb->s.cg6.bt->control = 0x73 << 24; - fb->s.cg6.bt->addr = 0x07 << 24; - fb->s.cg6.bt->control = 0x00 << 24; + bt->addr = 0x04 << 24; /* color planes */ + bt->control = 0xff << 24; + bt->addr = 0x05 << 24; + bt->control = 0x00 << 24; + bt->addr = 0x06 << 24; /* overlay plane */ + bt->control = 0x73 << 24; + bt->addr = 0x07 << 24; + bt->control = 0x00 << 24; conf = *fb->s.cg6.fhc; switch(conf & CG6_FHC_CPU_MASK) { diff --git a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c index 2cab0fc25..882669d8f 100644 --- a/drivers/video/cgthreefb.c +++ b/drivers/video/cgthreefb.c @@ -1,4 +1,4 @@ -/* $Id: cgthreefb.c,v 1.1 1998/07/21 14:50:47 jj Exp $ +/* $Id: cgthreefb.c,v 1.3 1998/09/04 15:43:43 jj Exp $ * cgthreefb.c: CGthree frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -21,10 +21,10 @@ #include <linux/init.h> #include <linux/selection.h> -#include "sbusfb.h" +#include <video/sbusfb.h> #include <asm/io.h> -#include "fbcon-cfb8.h" +#include <video/fbcon-cfb8.h> /* Control Register Constants */ #define CG3_CR_ENABLE_INTS 0x80 @@ -85,7 +85,7 @@ static struct sbus_mmap_map cg3_mmap_map[] = { #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */ #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */ -static void cg3_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +static void cg3_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) { struct bt_regs *bt = &fb->s.cg3.regs->cmap; u32 *i; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index c13954030..699ae96ff 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -38,10 +38,10 @@ #include <asm/adb.h> #include <asm/pmu.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "macmodes.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/macmodes.h> static int currcon = 0; @@ -62,15 +62,40 @@ struct fb_info_chips { #ifdef CONFIG_PMAC_PBOOK unsigned char *save_framebuffer; #endif +#ifdef FBCON_HAS_CFB16 + u16 fbcon_cfb16_cmap[16]; +#endif }; -#define write_xr(num,val) { out_8(p->io_base + 0x3D6, num); out_8(p->io_base + 0x3D7, val); } -#define read_xr(num,var) { out_8(p->io_base + 0x3D6, num); var = in_8(p->io_base + 0x3D7); } -#define write_fr(num,val) { out_8(p->io_base + 0x3D0, num); out_8(p->io_base + 0x3D1, val); } -#define read_fr(num,var) { out_8(p->io_base + 0x3D0, num); var = in_8(p->io_base + 0x3D1); } -#define write_cr(num,val) { out_8(p->io_base + 0x3D4, num); out_8(p->io_base + 0x3D5, val); } -#define read_cr(num,var) { out_8(p->io_base + 0x3D4, num); var = in_8(p->io_base + 0x3D5); } - +#define write_ind(num, val, ap, dp) do { \ + out_8(p->io_base + (ap), (num)); out_8(p->io_base + (dp), (val)); \ +} while (0) +#define read_ind(num, var, ap, dp) do { \ + out_8(p->io_base + (ap), (num)); var = in_8(p->io_base + (dp)); \ +} while (0); + +/* extension registers */ +#define write_xr(num, val) write_ind(num, val, 0x3d6, 0x3d7) +#define read_xr(num, var) read_ind(num, var, 0x3d6, 0x3d7) +/* flat panel registers */ +#define write_fr(num, val) write_ind(num, val, 0x3d0, 0x3d1) +#define read_fr(num, var) read_ind(num, var, 0x3d0, 0x3d1) +/* CRTC registers */ +#define write_cr(num, val) write_ind(num, val, 0x3d4, 0x3d5) +#define read_cr(num, var) read_ind(num, var, 0x3d4, 0x3d5) +/* graphics registers */ +#define write_gr(num, val) write_ind(num, val, 0x3ce, 0x3cf) +#define read_gr(num, var) read_ind(num, var, 0x3ce, 0x3cf) +/* sequencer registers */ +#define write_sr(num, val) write_ind(num, val, 0x3c4, 0x3c5) +#define read_sr(num, var) read_ind(num, var, 0x3c4, 0x3c5) +/* attribute registers - slightly strange */ +#define write_ar(num, val) do { \ + in_8(p->io_base + 0x3da); write_ind(num, val, 0x3c0, 0x3c0); \ +} while (0) +#define read_ar(num, var) do { \ + in_8(p->io_base + 0x3da); read_ind(num, var, 0x3c0, 0x3c1); \ +} while (0) static struct fb_info_chips *all_chips; @@ -187,8 +212,7 @@ static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, - chipsfb_getcolreg, info); + return fb_get_cmap(cmap, kspc, chipsfb_getcolreg, info); if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); else @@ -209,8 +233,7 @@ static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con, } if (con == currcon) - return fb_set_cmap(cmap, &disp->var, kspc, chipsfb_setcolreg, - info); + return fb_set_cmap(cmap, kspc, chipsfb_setcolreg, info); fb_copy_cmap(cmap, &disp->cmap, kspc==0); return 0; } @@ -229,9 +252,7 @@ static int chipsfb_switch(int con, struct fb_info *info) int bit_depth; if (fb_display[currcon].cmap.len) - fb_get_cmap(&old_disp->cmap, - &old_disp->var, 1, chipsfb_getcolreg, - info); + fb_get_cmap(&old_disp->cmap, 1, chipsfb_getcolreg, info); bit_depth = new_disp->var.bits_per_pixel; if (old_disp->var.bits_per_pixel != bit_depth) @@ -279,9 +300,10 @@ static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, if (regno > 255) return 1; - *red = p->palette[regno].red; - *green = p->palette[regno].green; - *blue = p->palette[regno].blue; + *red = (p->palette[regno].red<<8) | p->palette[regno].red; + *green = (p->palette[regno].green<<8) | p->palette[regno].green; + *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; + *transp = 0; return 0; } @@ -289,21 +311,26 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { struct fb_info_chips *p = (struct fb_info_chips *) info; + int hr; - if (regno > 255) + hr = (p->fix.visual != FB_VISUAL_PSEUDOCOLOR)? (regno << 3): regno; + if (hr > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; p->palette[regno].red = red; p->palette[regno].green = green; p->palette[regno].blue = blue; - out_8(p->io_base + 0x3c8, regno); + out_8(p->io_base + 0x3c8, hr); udelay(1); out_8(p->io_base + 0x3c9, red); out_8(p->io_base + 0x3c9, green); out_8(p->io_base + 0x3c9, blue); #ifdef FBCON_HAS_CFB16 - if (regno < 16) - fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; + if (regno < 16) + p->fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; #endif return 0; @@ -314,18 +341,13 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - chipsfb_setcolreg, info); - else - fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), &fb_display[con].var, 1, - chipsfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, chipsfb_setcolreg, info); + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), 1, chipsfb_setcolreg, info); + } } -#ifdef CONFIG_FB_COMPAT_XPMAC -/* from drivers/macintosh/pmac-cons.h */ -#define VMODE_800_600_60 10 /* 800x600, 60Hz */ -#endif /* CONFIG_FB_COMPAT_XPMAC */ - static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp) { int err; @@ -336,12 +358,11 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in if (con == currcon) { write_cr(0x13, 200); // 16 bit display width (decimal) write_xr(0x81, 0x14); // 15 bit (TrueColor) color mode - write_xr(0x82, 0x00); // disable palettes write_xr(0x20, 0x10); // 16 bit blitter mode } fix->line_length = 800*2; - fix->visual = FB_VISUAL_TRUECOLOR; + fix->visual = FB_VISUAL_DIRECTCOLOR; var->red.offset = 10; var->green.offset = 5; @@ -350,14 +371,14 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in #ifdef FBCON_HAS_CFB16 disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = p->fbcon_cfb16_cmap; #else - disp->dispsw = NULL; + disp->dispsw = &fbcon_dummy; #endif - } else if (bpp == 8) { + } else if (bpp == 8) { if (con == currcon) { write_cr(0x13, 100); // 8 bit display width (decimal) write_xr(0x81, 0x12); // 8 bit color mode - write_xr(0x82, 0x08); // Graphics gamma enable write_xr(0x20, 0x00); // 8 bit blitter mode } @@ -370,7 +391,7 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in #ifdef FBCON_HAS_CFB8 disp->dispsw = &fbcon_cfb8; #else - disp->dispsw = NULL; + disp->dispsw = &fbcon_dummy; #endif } @@ -392,11 +413,139 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in do_install_cmap(con, (struct fb_info *)p); } +struct chips_init_reg { + unsigned char addr; + unsigned char data; +}; + +#define N_ELTS(x) (sizeof(x) / sizeof(x[0])) + +static struct chips_init_reg chips_init_sr[] = { + { 0x00, 0x03 }, + { 0x01, 0x01 }, + { 0x02, 0x0f }, + { 0x04, 0x0e } +}; + +static struct chips_init_reg chips_init_gr[] = { + { 0x05, 0x00 }, + { 0x06, 0x0d }, + { 0x08, 0xff } +}; + +static struct chips_init_reg chips_init_ar[] = { + { 0x10, 0x01 }, + { 0x12, 0x0f }, + { 0x13, 0x00 } +}; + +static struct chips_init_reg chips_init_cr[] = { + { 0x00, 0x7f }, + { 0x01, 0x63 }, + { 0x02, 0x63 }, + { 0x03, 0x83 }, + { 0x04, 0x66 }, + { 0x05, 0x10 }, + { 0x06, 0x72 }, + { 0x07, 0x3e }, + { 0x08, 0x00 }, + { 0x09, 0x40 }, + { 0x0c, 0x00 }, + { 0x0d, 0x00 }, + { 0x10, 0x59 }, + { 0x11, 0x0d }, + { 0x12, 0x57 }, + { 0x13, 0x64 }, + { 0x14, 0x00 }, + { 0x15, 0x57 }, + { 0x16, 0x73 }, + { 0x17, 0xe3 }, + { 0x18, 0xff }, + { 0x30, 0x02 }, + { 0x31, 0x02 }, + { 0x32, 0x02 }, + { 0x33, 0x02 }, + { 0x40, 0x00 }, + { 0x41, 0x00 }, + { 0x40, 0x80 } +}; + +static struct chips_init_reg chips_init_fr[] = { + { 0x01, 0x02 }, + { 0x03, 0x08 }, + { 0x04, 0x81 }, + { 0x05, 0x21 }, + { 0x08, 0x0c }, + { 0x0a, 0x74 }, + { 0x0b, 0x11 }, + { 0x10, 0x0c }, + { 0x11, 0xe0 }, + /* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */ + { 0x20, 0x63 }, + { 0x21, 0x68 }, + { 0x22, 0x19 }, + { 0x23, 0x7f }, + { 0x24, 0x68 }, + { 0x26, 0x00 }, + { 0x27, 0x0f }, + { 0x30, 0x57 }, + { 0x31, 0x58 }, + { 0x32, 0x0d }, + { 0x33, 0x72 }, + { 0x34, 0x02 }, + { 0x35, 0x22 }, + { 0x36, 0x02 }, + { 0x37, 0x00 } +}; + +static struct chips_init_reg chips_init_xr[] = { + { 0xce, 0x00 }, /* set default memory clock */ + { 0xcc, 0x43 }, /* memory clock ratio */ + { 0xcd, 0x18 }, + { 0xce, 0xa1 }, + { 0xc8, 0x84 }, + { 0xc9, 0x0a }, + { 0xca, 0x00 }, + { 0xcb, 0x20 }, + { 0xcf, 0x06 }, + { 0xd0, 0x0e }, + { 0x09, 0x01 }, + { 0x0a, 0x02 }, + { 0x0b, 0x01 }, + { 0x20, 0x00 }, + { 0x40, 0x03 }, + { 0x41, 0x01 }, + { 0x42, 0x00 }, + { 0x80, 0x82 }, + { 0x81, 0x12 }, + { 0x82, 0x08 }, + { 0xa0, 0x00 }, + { 0xa8, 0x00 } +}; + +__initfunc(static void chips_hw_init(struct fb_info_chips *p)) +{ + int i; + + for (i = 0; i < N_ELTS(chips_init_xr); ++i) + write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); + out_8(p->io_base + 0x3c2, 0x29); /* set misc output reg */ + for (i = 0; i < N_ELTS(chips_init_sr); ++i) + write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); + for (i = 0; i < N_ELTS(chips_init_gr); ++i) + write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); + for (i = 0; i < N_ELTS(chips_init_ar); ++i) + write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); + for (i = 0; i < N_ELTS(chips_init_cr); ++i) + write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); + for (i = 0; i < N_ELTS(chips_init_fr); ++i) + write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); +} + __initfunc(static void init_chips(struct fb_info_chips *p)) { int i; - memset(&p->fix, 0, sizeof(p->fix)); strcpy(p->fix.id, "C&T 65550"); p->fix.smem_start = (char *) p->chips_base_phys; p->fix.smem_len = 800 * 600; @@ -405,7 +554,6 @@ __initfunc(static void init_chips(struct fb_info_chips *p)) p->fix.visual = FB_VISUAL_PSEUDOCOLOR; p->fix.line_length = 800; - memset(&p->var, 0, sizeof(p->var)); p->var.xres = 800; p->var.yres = 600; p->var.xres_virtual = 800; @@ -419,7 +567,6 @@ __initfunc(static void init_chips(struct fb_info_chips *p)) p->var.upper_margin = p->var.lower_margin = 16; p->var.hsync_len = p->var.vsync_len = 8; - memset(&p->disp, 0, sizeof(p->disp)); p->disp.var = p->var; p->disp.cmap.red = NULL; p->disp.cmap.green = NULL; @@ -443,6 +590,7 @@ __initfunc(static void init_chips(struct fb_info_chips *p)) p->info.switch_con = &chipsfb_switch; p->info.updatevar = &chipsfb_updatevar; p->info.blank = &chipsfb_blank; + p->info.flags = FBINFO_FLAG_DEFAULT; for (i = 0; i < 16; ++i) { int j = color_table[i]; @@ -458,6 +606,8 @@ __initfunc(static void init_chips(struct fb_info_chips *p)) printk("fb%d: Chips 65550 frame buffer\n", GET_FB_IDX(p->info.node)); + chips_hw_init(p); + #ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info) { display_info.height = p->var.yres; @@ -507,6 +657,7 @@ __initfunc(void chips_of_init(struct device_node *dp)) p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) return; + memset(p, 0, sizeof(*p)); addr = dp->addrs[0].address; p->chips_base_phys = addr; p->frame_buffer = __ioremap(addr+0x800000, 0x100000, _PAGE_NO_CACHE); diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c index fc3f15efe..68078c091 100644 --- a/drivers/video/clgenfb.c +++ b/drivers/video/clgenfb.c @@ -16,14 +16,13 @@ #include <asm/amigahw.h> #include <asm/pgtable.h> #include <asm/delay.h> -#include "fbcon.h" -#include "fbcon.h" -#include "fbcon-mfb.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb24.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> #include "clgenfb.h" @@ -33,17 +32,6 @@ #define arraysize(x) (sizeof(x)/sizeof(*(x))) -/* zorro IDs */ -#define ZORRO_PROD_HELFRICH_SD64_RAM 0x08930A00 -#define ZORRO_PROD_HELFRICH_SD64_REG 0x08930B00 -#define ZORRO_PROD_HELFRICH_PICCOLO_RAM 0x08930500 -#define ZORRO_PROD_HELFRICH_PICCOLO_REG 0x08930600 -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM 0x08770B00 -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG 0x08770C00 -#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM 0x08910200 -#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG 0x08910100 -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 0x08771800 - /* board types */ #define BT_NONE 0 #define BT_SD64 1 @@ -101,8 +89,22 @@ struct clgenfb_info int btype; int smallboard; unsigned char SFR; /* Shadow of special function register */ + + unsigned long fbmem_phys; + unsigned long fbregs_phys; struct clgenfb_par currentmode; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; }; static struct display disp; @@ -201,8 +203,8 @@ static int clgen_pan_display(const struct fb_var_screeninfo *var, struct fb_info_gen *info); static int clgen_blank(int blank_mode, struct fb_info_gen *info); -static struct display_switch *clgen_get_dispsw(const void *par, - struct fb_info_gen *info); +static void clgen_set_dispsw(const void *par, struct display *disp, + struct fb_info_gen *info); /* function table of the above functions */ static struct fbgen_hwswitch clgen_hwswitch = @@ -217,7 +219,7 @@ static struct fbgen_hwswitch clgen_hwswitch = clgen_setcolreg, clgen_pan_display, clgen_blank, - clgen_get_dispsw + clgen_set_dispsw }; /* Text console acceleration */ @@ -334,7 +336,7 @@ static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par, memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, clgenfb_name); - fix->smem_start = (char*)_info->fbmem; + fix->smem_start = (char*)_info->fbmem_phys; /* monochrome: only 1 memory plane */ /* 8 bit and above: Use whole memory area */ @@ -347,7 +349,7 @@ static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par, fix->ypanstep = 1; fix->ywrapstep = 0; fix->line_length = _par->line_length; - fix->mmio_start = (char *)_info->regs; + fix->mmio_start = (char *)_info->fbregs_phys; fix->mmio_len = 0x10000; fix->accel = FB_ACCEL_NONE; @@ -411,7 +413,7 @@ static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par, /* use highest possible virtual resolution */ if (_par->var.xres_virtual == -1 && - _par->var.xres_virtual == -1) + _par->var.yres_virtual == -1) { printk("clgen: using maximum available virtual resolution\n"); for (i=0; modes[i].xres != -1; i++) @@ -457,23 +459,54 @@ static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par, case 8: _par->line_length = _par->var.xres_virtual; _par->visual = FB_VISUAL_PSEUDOCOLOR; + _par->var.red.offset = 0; + _par->var.red.length = 6; + _par->var.green.offset = 0; + _par->var.green.length = 6; + _par->var.blue.offset = 0; + _par->var.blue.length = 6; break; case 16: _par->line_length = _par->var.xres_virtual * 2; _par->visual = FB_VISUAL_DIRECTCOLOR; + _par->var.red.offset = 10; + _par->var.red.length = 5; + _par->var.green.offset = 5; + _par->var.green.length = 5; + _par->var.blue.offset = 0; + _par->var.blue.length = 5; break; case 24: _par->line_length = _par->var.xres_virtual * 3; _par->visual = FB_VISUAL_DIRECTCOLOR; + _par->var.red.offset = 16; + _par->var.red.length = 8; + _par->var.green.offset = 8; + _par->var.green.length = 8; + _par->var.blue.offset = 0; + _par->var.blue.length = 8; break; case 32: _par->line_length = _par->var.xres_virtual * 4; _par->visual = FB_VISUAL_DIRECTCOLOR; + _par->var.red.offset = 16; + _par->var.red.length = 8; + _par->var.green.offset = 8; + _par->var.green.length = 8; + _par->var.blue.offset = 0; + _par->var.blue.length = 8; break; } + _par->var.red.msb_right = 0; + _par->var.green.msb_right = 0; + _par->var.blue.msb_right = 0; + _par->var.transp.offset = 0; + _par->var.transp.length = 0; + _par->var.transp.msb_right = 0; + _par->type = FB_TYPE_PACKED_PIXELS; /* convert from ps to kHz */ @@ -691,7 +724,7 @@ static void clgen_set_par(const void *par, struct fb_info_gen *info) #if 0 /* restore first 2 color registers for mono mode */ WClut( 0, 0x00, 0x00, 0x00); /* background: black */ - WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */ + WClut( 1, 0x3f, 0x3f, 0x3f); /* foreground: white */ #endif WGfx(GR5, 0); /* mode register */ @@ -955,16 +988,16 @@ static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green, { unsigned char bred, bgreen, bblue; - if (regno > 255 || regno < 0) + if (regno > 255) return (1); fb_info = (struct clgenfb_info *)info; RClut(regno, &bred, &bgreen, &bblue); - *red = (u_int)bred; - *green = (u_int)bgreen; - *blue = (u_int)bblue; + *red = (bred<<10) | (bred<<4) | (bred>>2); + *green = (bgreen<<10) | (bgreen<<4) | (bgreen>>2); + *blue = (bblue<<10) | (bblue<<4) | (bblue>>2); *transp = 0; return (0); } @@ -973,13 +1006,13 @@ static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - if (regno > 255 || regno < 0) + if (regno > 255) return (1); fb_info = (struct clgenfb_info *)info; /* "transparent" stuff is completely ignored. */ - WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff)); + WClut(regno, red>>10, green>>10, blue>>10); return (0); } @@ -1240,28 +1273,28 @@ static void init_vgachip(void) /* CLUT setup */ WClut( 0, 0x00, 0x00, 0x00); /* background: black */ - WClut( 1, 0xff, 0xff, 0xff); /* foreground: white */ - WClut( 2, 0x00, 0x80, 0x00); - WClut( 3, 0x00, 0x80, 0x80); - WClut( 4, 0x80, 0x00, 0x00); - WClut( 5, 0x80, 0x00, 0x80); - WClut( 6, 0x80, 0x40, 0x00); - WClut( 7, 0x80, 0x80, 0x80); - WClut( 8, 0x40, 0x40, 0x40); - WClut( 9, 0x40, 0x40, 0xc0); - WClut(10, 0x40, 0xc0, 0x40); - WClut(11, 0x40, 0xc0, 0xc0); - WClut(12, 0xc0, 0x40, 0x40); - WClut(13, 0xc0, 0x40, 0xc0); - WClut(14, 0xc0, 0xc0, 0x40); - WClut(15, 0xc0, 0xc0, 0xc0); + WClut( 1, 0x3f, 0x3f, 0x3f); /* foreground: white */ + WClut( 2, 0x00, 0x20, 0x00); + WClut( 3, 0x00, 0x20, 0x20); + WClut( 4, 0x20, 0x00, 0x00); + WClut( 5, 0x20, 0x00, 0x20); + WClut( 6, 0x20, 0x10, 0x00); + WClut( 7, 0x20, 0x20, 0x20); + WClut( 8, 0x10, 0x10, 0x10); + WClut( 9, 0x10, 0x10, 0x30); + WClut(10, 0x10, 0x30, 0x10); + WClut(11, 0x10, 0x30, 0x30); + WClut(12, 0x30, 0x10, 0x10); + WClut(13, 0x30, 0x10, 0x30); + WClut(14, 0x30, 0x30, 0x10); + WClut(15, 0x30, 0x30, 0x30); /* the rest a grey ramp */ { int i; for (i = 16; i < 256; i++) - WClut(i, i, i, i); + WClut(i, i>>2, i>>2, i>>2); } @@ -1338,10 +1371,11 @@ static void switch_monitor(int on) } } -static struct display_switch *clgen_get_dispsw(const void *par, - struct fb_info_gen *info) +static void clgen_set_dispsw(const void *par, struct display *disp, + struct fb_info_gen *info) { struct clgenfb_par *_par = (struct clgenfb_par*) par; + struct clgenfb_info *info2 = (struct clgenfb_info *)info; printk("clgen_get_dispsw(): "); switch (_par->var.bits_per_pixel) @@ -1349,44 +1383,53 @@ static struct display_switch *clgen_get_dispsw(const void *par, #ifdef FBCON_HAS_MFB case 1: printk("monochrome\n"); - return &fbcon_mfb; + disp->dispsw = &fbcon_mfb; + break; #endif #ifdef FBCON_HAS_CFB8 case 8: printk("8 bit color depth\n"); - return &fbcon_clgen_8; + disp->dispsw = &fbcon_clgen_8; + break; #endif #ifdef FBCON_HAS_CFB16 case 16: printk("16 bit color depth\n"); - return &fbcon_cfb16; + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = info2->fbcon_cmap.cfb16; + break; #endif #ifdef FBCON_HAS_CFB24 case 24: printk("24 bit color depth\n"); - return &fbcon_cfb24; + disp->dispsw = &fbcon_cfb24; + disp->dispsw_data = info2->fbcon_cmap.cfb24; + break; #endif #ifdef FBCON_HAS_CFB32 case 32: printk("32 bit color depth\n"); - return &fbcon_cfb32; + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = info2->fbcon_cmap.cfb32; + break; #endif default: printk("unsupported color depth\n"); - return NULL; + disp->dispsw = &fbcon_dummy; + break; } } static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - sx *= p->fontwidth; - sy *= p->fontheight; - dx *= p->fontwidth; - dy *= p->fontheight; - width *= p->fontwidth; - height *= p->fontheight; + sx *= fontwidth(p); + sy *= fontheight(p); + dx *= fontwidth(p); + dy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); fb_info = (struct clgenfb_info*)p->fb_info; @@ -1404,10 +1447,10 @@ static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, fb_info = (struct clgenfb_info*)p->fb_info; - sx *= p->fontwidth; - sy *= p->fontheight; - width *= p->fontwidth; - height *= p->fontheight; + sx *= fontwidth(p); + sy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); col = attr_bgcol_ec(p, conp); col &= 0xff; @@ -1494,8 +1537,10 @@ __initfunc(void clgenfb_init(void)) KERNELMAP_NOCACHE_SER, NULL); DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs); fb_info->regs += 0x600000; + fb_info->fbregs_phys = board_addr + 0x600000; - fb_info->fbmem = kernel_map(board_addr + 16777216, 16777216, + fb_info->fbmem_phys = board_addr + 16777216; + fb_info->fbmem = kernel_map(fb_info->fbmem_phys, 16777216, KERNELMAP_NOCACHE_SER, NULL); DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem); } @@ -1504,6 +1549,7 @@ __initfunc(void clgenfb_init(void)) cd2 = zorro_get_board(key2); printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr); + fb_info->fbmem_phys = board_addr; if (board_addr > 0x01000000) fb_info->fbmem = kernel_map(board_addr, board_size, KERNELMAP_NOCACHE_SER, NULL); @@ -1512,6 +1558,7 @@ __initfunc(void clgenfb_init(void)) /* set address for REG area of board */ fb_info->regs = (unsigned char *)ZTWO_VADDR(cd2->cd_BoardAddr); + fb_info->fbregs_phys = (unsigned long) cd2->cd_BoardAddr; DEBUG printk(KERN_INFO "clgen: Virtual address for board set to: $%p\n", fb_info->regs); DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem); @@ -1530,6 +1577,7 @@ __initfunc(void clgenfb_init(void)) fb_info->gen.info.switch_con = &fbgen_switch; fb_info->gen.info.updatevar = &fbgen_update_var; fb_info->gen.info.blank = &fbgen_blank; + fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; /* mark this board as "autoconfigured" */ zorro_config_board(key, 0); @@ -1835,7 +1883,7 @@ void WSFR2(unsigned char val) fb_info->regs[0x9000] = val; } -/*** WClut - set CLUT entry (range: 0..255 is automat. shifted to 0..63) ***/ +/*** WClut - set CLUT entry (range: 0..63) ***/ void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue) { unsigned int data = 0x3c9; @@ -1848,19 +1896,19 @@ void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigne /* but DAC data register IS, at least for Picasso II */ if(fb_info->btype == BT_PICASSO) data += 0xfff; - fb_info->regs[data] = (red >> 2); - fb_info->regs[data] = (green >> 2); - fb_info->regs[data] = (blue >> 2); + fb_info->regs[data] = red; + fb_info->regs[data] = green; + fb_info->regs[data] = blue; } else { - fb_info->regs[data] = (blue >> 2); - fb_info->regs[data] = (green >> 2); - fb_info->regs[data] = (red >> 2); + fb_info->regs[data] = blue; + fb_info->regs[data] = green; + fb_info->regs[data] = red; } } -/*** RClut - read CLUT entry and convert to 0..255 range ***/ +/*** RClut - read CLUT entry (range 0..63) ***/ void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue) { unsigned int data = 0x3c9; @@ -1871,15 +1919,15 @@ void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsig { if(fb_info->btype == BT_PICASSO) data += 0xfff; - *red = fb_info->regs[data] << 2; - *green = fb_info->regs[data] << 2; - *blue = fb_info->regs[data] << 2; + *red = fb_info->regs[data]; + *green = fb_info->regs[data]; + *blue = fb_info->regs[data]; } else { - *blue = fb_info->regs[data] << 2; - *green = fb_info->regs[data] << 2; - *red = fb_info->regs[data] << 2; + *blue = fb_info->regs[data]; + *green = fb_info->regs[data]; + *red = fb_info->regs[data]; } } diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 466bf52ee..d1a63b64f 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -49,16 +49,19 @@ #include <asm/adb.h> #include <asm/cuda.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> +#include <video/macmodes.h> -#include "macmodes.h" #include "controlfb.h" static int currcon = 0; static int switching = 0; +static char fontname[40] __initdata = { 0 }; +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; struct fb_par_control { int vmode, cmode; @@ -88,13 +91,24 @@ struct fb_info_control { int sense, control_use_bank2; unsigned long total_vram; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; }; /* * Exported functions */ void control_init(void); +#ifdef CONFIG_FB_OF void control_of_init(struct device_node *dp); +#endif +void controlfb_setup(char *options, int *ints); static int control_open(struct fb_info *info, int user); static int control_release(struct fb_info *info, int user); @@ -198,7 +212,7 @@ static int control_set_var(struct fb_var_screeninfo *var, int con, } if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { - printk("Not activating, in control_set_var.\n"); + /* printk("Not activating, in control_set_var.\n"); */ control_par_to_var(&par, var); return 0; } @@ -211,7 +225,7 @@ static int control_set_var(struct fb_var_screeninfo *var, int con, p->var = disp->var = *var; return 0; } -printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel); + /* printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel); */ /* OK, we're getting here at the right times... */ p->par = par; control_par_to_var(&par, var); @@ -244,8 +258,7 @@ static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, - controlfb_getcolreg, info); + return fb_get_cmap(cmap, kspc, controlfb_getcolreg, info); if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); else { @@ -269,8 +282,7 @@ static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, } if (con == currcon) - return fb_set_cmap(cmap, &disp->var, kspc, controlfb_setcolreg, - info); + return fb_set_cmap(cmap, kspc, controlfb_setcolreg, info); fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; } @@ -284,8 +296,7 @@ static int control_ioctl(struct inode *inode, struct file *file, u_int cmd, static int controlfb_switch(int con, struct fb_info *info) { if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, - &fb_display[currcon].var, 1, controlfb_getcolreg, + fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg, info); currcon = con; #if 0 @@ -346,9 +357,10 @@ static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, if (regno > 255) return 1; - *red = p->palette[regno].red; - *green = p->palette[regno].green; - *blue = p->palette[regno].blue; + *red = (p->palette[regno].red<<8) | p->palette[regno].red; + *green = (p->palette[regno].green<<8) | p->palette[regno].green; + *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; + *transp = 0; return 0; } @@ -356,9 +368,13 @@ static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { struct fb_info_control *p = (struct fb_info_control *) info; + int i; - if (regno > 255 || regno < 0) + if (regno > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; p->palette[regno].red = red; p->palette[regno].green = green; p->palette[regno].blue = blue; @@ -368,25 +384,29 @@ static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, out_8(&p->cmap_regs->lut, green); /* a time... */ out_8(&p->cmap_regs->lut, blue); - if(regno < 16) { -#if 0 + if (regno < 16) + switch (p->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; -#endif -#ifdef FBCON_HAS_CFB32 - fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; - /* I think. */ -#endif + case 16: +#if 0 + p->fbcon_cmap.cfb16[regno] = (red << 10) | (green << 5) | blue; #else -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; + p->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno; +#endif + break; #endif #ifdef FBCON_HAS_CFB32 - fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; - /* I think. */ + case 32: +#if 0 + p->fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | blue; +#else + i = (regno << 8) | regno; + p->fbcon_cmap.cfb32[regno] = (i << 16) | i; + /* I think */ #endif + break; #endif - } + } return 0; } @@ -395,12 +415,12 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - controlfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, controlfb_setcolreg, + info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, - controlfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg, + info); } } @@ -440,7 +460,7 @@ __initfunc(static void init_control(struct fb_info_control *p)) struct fb_par_control *par = &p->par; p->sense = read_control_sense(p); - printk("Monitor sense value = 0x%x, ", p->sense); + printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense); /* Try to pick a video mode out of NVRAM if we have one. */ par->vmode = nvram_read_byte(NV_VMODE); if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1]) @@ -467,13 +487,14 @@ __initfunc(static void init_control(struct fb_info_control *p)) control_par_to_all(p, 1); + p->info.flags = FBINFO_FLAG_DEFAULT; if (register_framebuffer(&p->info) < 0) { kfree(p); return; } control_set_hardware(p); - printk("fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); + printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); } /* Now how about actually saying, Make it so! */ @@ -523,8 +544,9 @@ static void control_set_hardware(struct fb_info_control *p) out_le32(&p->control_regs->reg19.r, 0); for (i = 0; i < 16; ++i) { - controlfb_setcolreg(color_table[i], default_red[i], default_grn[i], - default_blu[i], 0, (struct fb_info *)p); + controlfb_setcolreg(color_table[i], default_red[i]<<8, + default_grn[i]<<8, default_blu[i]<<8, + 0, (struct fb_info *)p); } /* Does the above need to be here each time? -- danj */ @@ -568,16 +590,24 @@ __initfunc(void control_of_init(struct device_node *dp)) struct fb_info_control *p; unsigned long addr, size; int i, bank1, bank2; - + +#if 0 if(dp->next != 0) printk("Warning: only using first control display device.\n"); /* danj: I have a feeling this no longer applies - if we somehow * - * had two of them, they'd be two framebuffers, right? */ - if(dp->n_addrs != 2) - panic("expecting 2 address for control (got %d)", dp->n_addrs); + * had two of them, they'd be two framebuffers, right? + * Yep. - paulus + */ +#endif + + if(dp->n_addrs != 2) { + printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); + return; + } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) return; + memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ for (i = 0; i < dp->n_addrs; ++i) { @@ -657,7 +687,7 @@ static int read_control_sense(struct fb_info_control *p) #if 1 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int control_var_to_par(struct fb_var_screeninfo *var, +static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info) { int xres = var->xres; @@ -758,7 +788,7 @@ static int control_var_to_par(struct fb_var_screeninfo *var, } #else /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int control_var_to_par(struct fb_var_screeninfo *var, +static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info) { struct fb_info_control *p = (struct fb_info_control *) fb_info; @@ -901,7 +931,7 @@ static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeni p->fix.smem_len = control_vram_reqd(par->vmode, par->cmode); /* Hmm, jonh used total_vram here. */ p->fix.visual = (par->cmode == CMODE_8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; p->fix.line_length = par->vxres << par->cmode; /* ywrapstep, xpanstep, ypanstep */ } @@ -935,8 +965,28 @@ if(disp->scrollmode != SCROLL_YREDRAW) { printk(KERN_ERR "Scroll mode not YREDRAW in control_par_to_display!!\n"); disp->scrollmode = SCROLL_YREDRAW; } - disp->dispsw = (par->cmode == CMODE_32) ? &fbcon_cfb32 : - ((par->cmode == CMODE_16) ? &fbcon_cfb16 : &fbcon_cfb8); + switch (par->cmode) { +#ifdef FBCON_HAS_CFB8 + case CMODE_8: + disp->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case CMODE_16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = p->fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case CMODE_32: + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = p->fbcon_cmap.cfb32; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + break; + } } static void control_init_info(struct fb_info *info, struct fb_info_control *p) @@ -945,7 +995,7 @@ static void control_init_info(struct fb_info *info, struct fb_info_control *p) info->node = -1; /* ??? danj */ info->fbops = &controlfb_ops; info->disp = &p->disp; - info->fontname[0] = 0; + strcpy(info->fontname, fontname); info->changevar = NULL; info->switch_con = &controlfb_switch; info->updatevar = &controlfb_updatevar; @@ -972,13 +1022,51 @@ static void control_par_to_all(struct fb_info_control *p, int init) } } -#if 0 +/* Parse user speficied options (`video=controlfb:') */ __initfunc(void controlfb_setup(char *options, int *ints)) { - /* Parse user speficied options (`video=controlfb:') */ - FUNCID; + char *this_opt; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt +5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } + } } +#if 0 static int controlfb_pan_display(struct fb_var_screeninfo *var, struct controlfb_par *par, const struct fb_info *fb_info) @@ -993,5 +1081,4 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var, return 0; } - #endif diff --git a/drivers/video/controlfb.h b/drivers/video/controlfb.h index 2e138b7c7..32943ed27 100644 --- a/drivers/video/controlfb.h +++ b/drivers/video/controlfb.h @@ -141,8 +141,8 @@ static struct control_regvals control_reg_init_17 = { 1024, 768 }; -/* Register values for 1024x768, 72Hz mode (15) */ -static struct control_regvals control_reg_init_15 = { +/* Register values for 1024x768, 72Hz mode (16 (15?)) */ +static struct control_regvals control_reg_init_16 = { { 1024, 2048, 4096 }, { 0x10, 0x28, 0x50 }, { 1607, 1604, 68, 39, 10, 1610, 1612, 132, @@ -253,8 +253,8 @@ static struct control_regvals *control_reg_init[VMODE_MAX] = { &control_reg_init_12, &control_reg_init_13, &control_reg_init_14, - &control_reg_init_15, - NULL, + &control_reg_init_16, + &control_reg_init_16, &control_reg_init_17, &control_reg_init_18, &control_reg_init_19, diff --git a/drivers/video/creatorfb.c b/drivers/video/creatorfb.c index 2175c9e5d..6c8f14b1d 100644 --- a/drivers/video/creatorfb.c +++ b/drivers/video/creatorfb.c @@ -1,10 +1,9 @@ -/* $Id: creatorfb.c,v 1.10 1998/07/25 22:54:37 davem Exp $ +/* $Id: creatorfb.c,v 1.15 1998/09/04 15:43:40 jj Exp $ * creatorfb.c: Creator/Creator3D frame buffer driver * * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -20,7 +19,7 @@ #include <linux/init.h> #include <linux/selection.h> -#include "sbusfb.h" +#include <video/sbusfb.h> #define FFB_SFB8R_VOFF 0x00000000 #define FFB_SFB8G_VOFF 0x00400000 @@ -69,56 +68,141 @@ #define FFB_PROM_POFF 0x00000000 #define FFB_EXP_POFF 0x00200000 -#define FFB_Y_BYTE_ADDR_SHIFT 11 -#define FFB_Y_ADDR_SHIFT 13 - -#define FFB_PPC_ACE_DISABLE 1 -#define FFB_PPC_ACE_AUX_ADD 3 -#define FFB_PPC_ACE_SHIFT 18 -#define FFB_PPC_DCE_DISABLE 2 -#define FFB_PPC_DCE_SHIFT 16 -#define FFB_PPC_ABE_DISABLE 2 -#define FFB_PPC_ABE_SHIFT 14 -#define FFB_PPC_VCE_DISABLE 1 -#define FFB_PPC_VCE_2D 2 -#define FFB_PPC_VCE_SHIFT 12 -#define FFB_PPC_APE_DISABLE 2 -#define FFB_PPC_APE_SHIFT 10 -#define FFB_PPC_CS_VARIABLE 2 -#define FFB_PPC_CS_SHIFT 0 - -#define FFB_FBC_WB_A 1 -#define FFB_FBC_WB_SHIFT 29 -#define FFB_FBC_PGE_MASK 3 -#define FFB_FBC_BE_SHIFT 4 -#define FFB_FBC_GE_SHIFT 2 -#define FFB_FBC_RE_SHIFT 0 +/* Draw operations */ +#define FFB_DRAWOP_DOT 0x00 +#define FFB_DRAWOP_AADOT 0x01 +#define FFB_DRAWOP_BRLINECAP 0x02 +#define FFB_DRAWOP_BRLINEOPEN 0x03 +#define FFB_DRAWOP_DDLINE 0x04 +#define FFB_DRAWOP_AALINE 0x05 +#define FFB_DRAWOP_TRIANGLE 0x06 +#define FFB_DRAWOP_POLYGON 0x07 +#define FFB_DRAWOP_RECTANGLE 0x08 +#define FFB_DRAWOP_FASTFILL 0x09 +#define FFB_DRAWOP_BCOPY 0x0a +#define FFB_DRAWOP_VSCROLL 0x0b + +/* Pixel processor control */ +/* Force WID */ +#define FFB_PPC_FW_DISABLE 0x800000 +#define FFB_PPC_FW_ENABLE 0xc00000 +/* Auxiliary clip */ +#define FFB_PPC_ACE_DISABLE 0x040000 +#define FFB_PPC_ACE_AUX_SUB 0x080000 +#define FFB_PPC_ACE_AUX_ADD 0x0c0000 +/* Depth cue */ +#define FFB_PPC_DCE_DISABLE 0x020000 +#define FFB_PPC_DCE_ENABLE 0x030000 +/* Alpha blend */ +#define FFB_PPC_ABE_DISABLE 0x008000 +#define FFB_PPC_ABE_ENABLE 0x00c000 +/* View clip */ +#define FFB_PPC_VCE_DISABLE 0x001000 +#define FFB_PPC_VCE_2D 0x002000 +#define FFB_PPC_VCE_3D 0x003000 +/* Area pattern */ +#define FFB_PPC_APE_DISABLE 0x000800 +#define FFB_PPC_APE_ENABLE 0x000c00 +/* Transparent background */ +#define FFB_PPC_TBE_OPAQUE 0x000200 +#define FFB_PPC_TBE_TRANSPARENT 0x000300 +/* Z source */ +#define FFB_PPC_ZS_VAR 0x000080 +#define FFB_PPC_ZS_CONST 0x0000c0 +/* Y source */ +#define FFB_PPC_YS_VAR 0x000020 +#define FFB_PPC_YS_CONST 0x000030 +/* X source */ +#define FFB_PPC_XS_WID 0x000004 +#define FFB_PPC_XS_VAR 0x000008 +#define FFB_PPC_XS_CONST 0x00000c +/* Color (BGR) source */ +#define FFB_PPC_CS_VAR 0x000002 +#define FFB_PPC_CS_CONST 0x000003 #define FFB_ROP_NEW 0x83 -#define FFB_ROP_RGB_SHIFT 0 #define FFB_UCSR_FIFO_MASK 0x00000fff #define FFB_UCSR_RP_BUSY 0x02000000 struct ffb_fbc { - u8 xxx1[0x60]; + /* Next vertex registers */ + u32 xxx1[3]; + volatile u32 alpha; + volatile u32 red; + volatile u32 green; + volatile u32 blue; + volatile u32 depth; + volatile u32 y; + volatile u32 x; + u32 xxx2[2]; + volatile u32 ryf; + volatile u32 rxf; + u32 xxx3[2]; + + volatile u32 dmyf; + volatile u32 dmxf; + u32 xxx4[2]; + volatile u32 ebyi; + volatile u32 ebxi; + u32 xxx5[2]; volatile u32 by; volatile u32 bx; - u32 xxx2; - u32 xxx3; + u32 dy; + u32 dx; volatile u32 bh; volatile u32 bw; - u8 xxx4[0x188]; + u32 xxx6[2]; + + u32 xxx7[32]; + + /* Setup unit vertex state register */ + volatile u32 suvtx; + u32 xxx8[63]; + + /* Control registers */ volatile u32 ppc; - u32 xxx5; + volatile u32 wid; volatile u32 fg; volatile u32 bg; - u8 xxx6[0x44]; + volatile u32 consty; + volatile u32 constz; + volatile u32 xclip; + volatile u32 dcss; + volatile u32 vclipmin; + volatile u32 vclipmax; + volatile u32 vclipzmin; + volatile u32 vclipzmax; + volatile u32 dcsf; + volatile u32 dcsb; + volatile u32 dczf; + volatile u32 dczb; + + u32 xxx9; + volatile u32 blendc; + volatile u32 blendc1; + volatile u32 blendc2; + volatile u32 fbramitc; volatile u32 fbc; volatile u32 rop; - u8 xxx7[0x34]; + volatile u32 cmp; + volatile u32 matchab; + volatile u32 matchc; + volatile u32 magnab; + volatile u32 magnc; + volatile u32 fbcfg0; + volatile u32 fbcfg1; + volatile u32 fbcfg2; + volatile u32 fbcfg3; + + u32 ppcfg; + volatile u32 pick; + volatile u32 fillmode; + volatile u32 fbramwac; volatile u32 pmask; - u8 xxx8[12]; + volatile u32 xpmask; + volatile u32 ypmask; + volatile u32 zpmask; volatile u32 clip0min; volatile u32 clip0max; volatile u32 clip1min; @@ -127,18 +211,64 @@ struct ffb_fbc { volatile u32 clip2max; volatile u32 clip3min; volatile u32 clip3max; - u8 xxx9[0x3c]; - volatile u32 unk1; - volatile u32 unk2; - u8 xxx10[0x10]; + + /* New 3dRAM III support regs */ + volatile u32 rawblend2; + volatile u32 rawpreblend; + volatile u32 rawstencil; + volatile u32 rawstencilctl; + volatile u32 threedram1; + volatile u32 threedram2; + volatile u32 passin; + volatile u32 rawclrdepth; + volatile u32 rawpmask; + volatile u32 rawcsrc; + volatile u32 rawmatch; + volatile u32 rawmagn; + volatile u32 rawropblend; + volatile u32 rawcmp; + volatile u32 rawwac; + volatile u32 fbramid; + + volatile u32 drawop; + u32 xxx10[2]; + volatile u32 fontlpat; + u32 xxx11; volatile u32 fontxy; volatile u32 fontw; volatile u32 fontinc; volatile u32 font; - u8 xxx11[0x4dc]; - volatile u32 unk3; - u8 xxx12[0xfc]; + u32 xxx12[3]; + volatile u32 blend2; + volatile u32 preblend; + volatile u32 stencil; + volatile u32 stencilctl; + + u32 xxx13[4]; + volatile u32 dcss1; + volatile u32 dcss2; + volatile u32 dcss3; + volatile u32 widpmask; + volatile u32 dcs2; + volatile u32 dcs3; + volatile u32 dcs4; + u32 xxx14; + volatile u32 dcd2; + volatile u32 dcd3; + volatile u32 dcd4; + u32 xxx15; + + volatile u32 pattern[32]; + + u32 xxx16[256]; + + volatile u32 devid; + u32 xxx17[63]; + volatile u32 ucsr; + u32 xxx18[31]; + + volatile u32 mer; }; struct ffb_dac { @@ -170,8 +300,6 @@ static struct sbus_mmap_map ffb_mmap_map[] = { { 0, 0, 0 } }; -static u32 ffb_cmap[16]; - static void ffb_setup(struct display *p) { p->next_line = 8192; @@ -185,22 +313,18 @@ static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx, register struct ffb_fbc *fbc = fb->s.ffb.fbc; int x, y, w, h; - fbc->ppc = 0x1803; - fbc->fg = ffb_cmap[attr_bgcol_ec(p,conp)]; - fbc->fbc = 0x2000707f; - fbc->rop = 0x83; - fbc->pmask = 0xffffffff; - fbc->unk2 = 8; + fbc->fg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p,conp)]; + fbc->drawop = FFB_DRAWOP_RECTANGLE; - if (p->fontheightlog) { - y = sy << p->fontheightlog; h = height << p->fontheightlog; + if (fontheightlog(p)) { + y = sy << fontheightlog(p); h = height << fontheightlog(p); } else { - y = sy * p->fontheight; h = height * p->fontheight; + y = sy * fontheight(p); h = height * fontheight(p); } - if (p->fontwidthlog) { - x = sx << p->fontwidthlog; w = width << p->fontwidthlog; + if (fontwidthlog(p)) { + x = sx << fontwidthlog(p); w = width << fontwidthlog(p); } else { - x = sx * p->fontwidth; w = width * p->fontwidth; + x = sx * fontwidth(p); w = width * fontwidth(p); } fbc->by = y + fb->y_margin; fbc->bx = x + fb->x_margin; @@ -213,12 +337,8 @@ static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s, { register struct ffb_fbc *fbc = fb->s.ffb.fbc; - fbc->ppc = 0x1803; - fbc->fg = ffb_cmap[attr_bgcol(p,s)]; - fbc->fbc = 0x2000707f; - fbc->rop = 0x83; - fbc->pmask = 0xffffffff; - fbc->unk2 = 8; + fbc->fg = ((u32 *)p->dispsw_data)[attr_bgcol(p,s)]; + fbc->drawop = FFB_DRAWOP_RECTANGLE; while (count-- > 0) { fbc->by = boxes[1]; fbc->bx = boxes[0]; @@ -235,48 +355,35 @@ static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int int i, xy; u8 *fd; - if (p->fontheightlog) { - xy = (yy << (16 + p->fontheightlog)); - i = ((c & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) { + xy = (yy << (16 + fontheightlog(p))); + i = ((c & p->charmask) << fontheightlog(p)); } else { - xy = ((yy * p->fontheight) << 16); - i = (c & p->charmask) * p->fontheight; + xy = ((yy * fontheight(p)) << 16); + i = (c & p->charmask) * fontheight(p); } -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - fd = p->fontdata + i; - xy += (xx * 8) + fb->s.ffb.xy_margin; -#else - if (p->fontwidth <= 8) + if (fontwidth(p) <= 8) fd = p->fontdata + i; else fd = p->fontdata + (i << 1); - if (p->fontwidthlog) - xy += (xx << p->fontwidthlog) + fb->s.ffb.xy_margin; + if (fontwidthlog(p)) + xy += (xx << fontwidthlog(p)) + fb->s.ffb.xy_margin; else - xy += (xx * p->fontwidth) + fb->s.ffb.xy_margin; -#endif - fbc->ppc = 0x203; - fbc->fg = ffb_cmap[attr_fgcol(p,c)]; - fbc->fbc = 0x2000707f; - fbc->rop = 0x83; - fbc->pmask = 0xffffffff; - fbc->bg = ffb_cmap[attr_bgcol(p,c)]; - fbc->fontw = p->fontwidth; + xy += (xx * fontwidth(p)) + fb->s.ffb.xy_margin; + fbc->fg = ((u32 *)p->dispsw_data)[attr_fgcol(p,c)]; + fbc->bg = ((u32 *)p->dispsw_data)[attr_bgcol(p,c)]; + fbc->fontw = fontwidth(p); fbc->fontinc = 0x10000; fbc->fontxy = xy; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif - for (i = 0; i < p->fontheight; i++) + if (fontwidth(p) <= 8) { + for (i = 0; i < fontheight(p); i++) fbc->font = *fd++ << 24; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { - for (i = 0; i < p->fontheight; i++) { + for (i = 0; i < fontheight(p); i++) { fbc->font = *(u16 *)fd << 16; fd += 2; } } -#endif } static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, @@ -287,105 +394,87 @@ static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned sh int i, xy; u8 *fd1, *fd2, *fd3, *fd4; - fbc->ppc = 0x203; - fbc->fg = ffb_cmap[attr_fgcol(p,*s)]; - fbc->fbc = 0x2000707f; - fbc->rop = 0x83; - fbc->pmask = 0xffffffff; - fbc->bg = ffb_cmap[attr_bgcol(p,*s)]; + fbc->fg = ((u32 *)p->dispsw_data)[attr_fgcol(p,*s)]; + fbc->bg = ((u32 *)p->dispsw_data)[attr_bgcol(p,*s)]; xy = fb->s.ffb.xy_margin; -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - xy += xx * 8; -#else - if (p->fontwidthlog) - xy += (xx << p->fontwidthlog); + if (fontwidthlog(p)) + xy += (xx << fontwidthlog(p)); else - xy += xx * p->fontwidth; -#endif - if (p->fontheightlog) - xy += (yy << (16 + p->fontheightlog)); + xy += xx * fontwidth(p); + if (fontheightlog(p)) + xy += (yy << (16 + fontheightlog(p))); else - xy += ((yy * p->fontheight) << 16); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif + xy += ((yy * fontheight(p)) << 16); + if (fontwidth(p) <= 8) { while (count >= 4) { count -= 4; - fbc->fontw = 4 * p->fontwidth; + fbc->fontw = 4 * fontwidth(p); fbc->fontinc = 0x10000; fbc->fontxy = xy; - if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); - fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); } else { - fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); - fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight); + fd1 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth == 8) { -#endif - for (i = 0; i < p->fontheight; i++) + if (fontwidth(p) == 8) { + for (i = 0; i < fontheight(p); i++) fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) << 8)) << 8)) << 8); xy += 32; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { - for (i = 0; i < p->fontheight; i++) + for (i = 0; i < fontheight(p); i++) fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) - << p->fontwidth)) << p->fontwidth)) << p->fontwidth)) << (24 - 3 * p->fontwidth); - xy += 4 * p->fontwidth; + << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p)); + xy += 4 * fontwidth(p); } } } else { while (count >= 2) { count -= 2; - fbc->fontw = 2 * p->fontwidth; + fbc->fontw = 2 * fontwidth(p); fbc->fontinc = 0x10000; fbc->fontxy = xy; - if (p->fontheightlog) { - fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); - fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1)); + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + fd2 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); } else { - fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); - fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1); + fd1 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + fd2 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); } - for (i = 0; i < p->fontheight; i++) { - fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth); + for (i = 0; i < fontheight(p); i++) { + fbc->font = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p)); fd1 += 2; fd2 += 2; } - xy += 2 * p->fontwidth; + xy += 2 * fontwidth(p); } -#endif } while (count) { count--; - fbc->fontw = p->fontwidth; + fbc->fontw = fontwidth(p); fbc->fontinc = 0x10000; fbc->fontxy = xy; - if (p->fontheightlog) - i = ((*s++ & p->charmask) << p->fontheightlog); + if (fontheightlog(p)) + i = ((*s++ & p->charmask) << fontheightlog(p)); else - i = ((*s++ & p->charmask) * p->fontheight); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth <= 8) { -#endif + i = ((*s++ & p->charmask) * fontheight(p)); + if (fontwidth(p) <= 8) { fd1 = p->fontdata + i; - for (i = 0; i < p->fontheight; i++) + for (i = 0; i < fontheight(p); i++) fbc->font = *fd1++ << 24; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY } else { fd1 = p->fontdata + (i << 1); - for (i = 0; i < p->fontheight; i++) { + for (i = 0; i < fontheight(p); i++) { fbc->font = *(u16 *)fd1 << 16; fd1 += 2; } } -#endif - xy += p->fontwidth; + xy += fontwidth(p); } } @@ -394,7 +483,7 @@ static void ffb_revc(struct display *p, int xx, int yy) /* Not used if hw cursor */ } -static void ffb_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) { struct ffb_dac *dac = fb->s.ffb.dac; int i, j = count; @@ -405,10 +494,12 @@ static void ffb_loadcmap (struct fb_info_sbusfb *fb, int index, int count) dac->value = ((fb->color_map CM(i,0))) | ((fb->color_map CM(i,1)) << 8) | ((fb->color_map CM(i,2)) << 16); + if (!p) + return; for (i = index, j = count; i < 16 && j--; i++) - ffb_cmap[i] = ((fb->color_map CM(i,0))) | - ((fb->color_map CM(i,1)) << 8) | - ((fb->color_map CM(i,2)) << 16); + ((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) | + ((fb->color_map CM(i,1)) << 8) | + ((fb->color_map CM(i,2)) << 16); } static struct display_switch ffb_dispsw __initdata = { @@ -478,6 +569,16 @@ static void ffb_setcursor (struct fb_info_sbusfb *fb) ffb_curs_enable (fb, fb->cursor.enable); } +static void ffb_switch_from_graph (struct fb_info_sbusfb *fb) +{ + register struct ffb_fbc *fbc = fb->s.ffb.fbc; + + fbc->ppc = FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST; + fbc->fbc = 0x2000707f; + fbc->rop = FFB_ROP_NEW; + fbc->pmask = 0xffffffff; +} + static char idstring[60] __initdata = { 0 }; __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb)) @@ -492,10 +593,15 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb)) if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0) return NULL; + disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL); + if (!disp->dispsw_data) + return NULL; + memset(disp->dispsw_data, 0, 16 * sizeof(u32)); + strcpy(fb->info.modename, "Creator"); strcpy(fix->id, "Creator"); - fix->visual = FB_VISUAL_DIRECTCOLOR; + fix->visual = FB_VISUAL_TRUECOLOR; fix->line_length = 8192; fix->accel = FB_ACCEL_SUN_CREATOR; @@ -516,8 +622,11 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb)) fb->setcursor = ffb_setcursor; fb->setcursormap = ffb_setcursormap; fb->setcurshape = ffb_setcurshape; + fb->switch_from_graph = ffb_switch_from_graph; fb->fill = ffb_fill; + ffb_switch_from_graph(fb); + fb->physbase = regs[0].phys_addr; fb->mmap_map = ffb_mmap_map; diff --git a/drivers/video/cvppcfb.c b/drivers/video/cvppcfb.c new file mode 100644 index 000000000..3e786ab61 --- /dev/null +++ b/drivers/video/cvppcfb.c @@ -0,0 +1,606 @@ +/* + * CybervisionPPC (TVP4020) low level driver for the frame buffer device + * ^^^^^^^^^ + * literally ;) + * + * Copyright (c) 1998 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) (v124) + * -------------------------------------------------------------------------- + * based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven + * -------------------------------------------------------------------------- + * TODO h/w parameters detect/modify, 8-bit CLUT, acceleration + * -------------------------------------------------------------------------- + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/amigahw.h> +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> +#include <asm/setup.h> +#include <asm/io.h> + +#define ISDIGIT(a) ((a)>='0' && (a)<='9') + +#undef CVPPCFB_MASTER_DEBUG +#ifdef CVPPCFB_MASTER_DEBUG +#define FBEGIN if (usr_startup.debug>1)\ + printk(__FUNCTION__ " {\n") +#define FEND if (usr_startup.debug>1)\ + printk("} /* " __FUNCTION__ " */\n") +#define DPRINTK(a,b...) if (usr_startup.debug)\ + printk("%s: " a, __FUNCTION__ , ## b) +#else +#define FBEGIN +#define FEND +#define DPRINTK(a,b...) +#endif + +static const char cvppcfb_name[16]="CybervisionPPC"; + +struct cvppcfb_startup { /* startup options */ + char font[40]; + u32 xres; + u32 yres; + u32 bpp; + unsigned long debug; + unsigned long YANW; /* You Are Not Welcome */ + struct fb_monspecs monitor; +}; +static struct cvppcfb_startup usr_startup = { + "\0", 640, 480, 16, 0, 1, { 31, 32, 58, 62, 0 } }; + +#define CVPPC_BASE 0xe0000000 +#define CVPPC_SIZE 0x00800000 +static char* video_base; /* virtual address of board video memory */ +static unsigned long video_phys;/* physical address of board video memory */ +static u32 video_size; /* size of board video memory */ + +struct cvppcfb_par { /* board parameters (sort of) */ + u32 xres; + u32 yres; + u32 vxres; + u32 vyres; + u32 vxoff; + u32 vyoff; + u32 bpp; + u32 clock; + u32 sflags; + u32 left; + u32 right; + u32 top; + u32 bottom; + u32 hsynclen; + u32 vsynclen; +}; + +struct cvppcfb_info { + struct fb_info_gen gen; + struct cvppcfb_par current_par; + int current_par_valid; + struct display disp; + struct { + u8 transp; + u8 red; + u8 green; + u8 blue; + } palette[256]; + union { +#ifdef FBCON_HAS_CFB16 + u16 cmap16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cmap32[16]; +#endif + } cmap; +}; +static struct cvppcfb_info fb_info; + +/* + * declaration of hw switch functions + */ +static void cvppcfb_detect(void); +static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix, + const void* par, struct fb_info_gen* info); +static int cvppcfb_decode_var(const struct fb_var_screeninfo* var, + void* par, struct fb_info_gen* info); +static int cvppcfb_encode_var(struct fb_var_screeninfo* var, + const void* par, struct fb_info_gen* info); +static void cvppcfb_get_par(void* par, struct fb_info_gen* info); +static void cvppcfb_set_par(const void* par, struct fb_info_gen* info); +static int cvppcfb_getcolreg(unsigned regno, + unsigned* red, unsigned* green, unsigned* blue, + unsigned* transp, struct fb_info* info); +static int cvppcfb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info* info); +static void cvppcfb_dispsw(const void* par, struct display* disp, + struct fb_info_gen* info); + +static struct fbgen_hwswitch cvppcfb_hwswitch={ + cvppcfb_detect, cvppcfb_encode_fix, cvppcfb_decode_var, + cvppcfb_encode_var, cvppcfb_get_par, cvppcfb_set_par, + cvppcfb_getcolreg, cvppcfb_setcolreg, NULL /* pan_display() */, + NULL /* blank() */, cvppcfb_dispsw +}; + +/* + * declaration of ops switch functions + */ +static int cvppcfb_open(struct fb_info* info, int user); +static int cvppcfb_release(struct fb_info* info, int user); + +static struct fb_ops cvppcfb_ops={ + cvppcfb_open, cvppcfb_release, fbgen_get_fix, fbgen_get_var, + fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, + fbgen_ioctl, NULL /* fb_mmap() */ +}; + +/* + * the actual definition of the above mentioned functions follows + */ + +/* + * private functions + */ + +static void cvppcfb_set_modename(struct cvppcfb_info* info, + struct cvppcfb_startup* s) { + + strcpy(info->gen.info.modename, cvppcfb_name); +} + +static void cvppcfb_decode_opt(struct cvppcfb_startup* s, void* par, + struct cvppcfb_info* info) { + struct cvppcfb_par* p=(struct cvppcfb_par* )par; + + memset(p, 0, sizeof(struct cvppcfb_par)); + p->xres=p->vxres=(s->xres+7)&~7; + p->yres=p->vyres=s->yres; + p->bpp=(s->bpp+7)&~7; + if (p->bpp==24) + p->bpp=32; + if (p->bpp<32) + p->clock=6666; + else + p->clock=10000; +} + +static void cvppcfb_encode_mcap(char* options, struct fb_monspecs* mcap) { + char* next; + int i=0; + + while (i<4 && options) { + if ((next=strchr(options, ';'))) + *(next++)='\0'; + switch (i++) { + case 0: /* vmin */ + mcap->vfmin=(__u16 ) + simple_strtoul(options, NULL, 0); + break; + case 1: /* vmax */ + mcap->vfmax=(__u16 ) + simple_strtoul(options, NULL, 0); + break; + case 2: /* hmin */ + mcap->hfmin=(__u32 ) + simple_strtoul(options, NULL, 0); + break; + case 3: /* hmax */ + mcap->hfmax=(__u32 ) + simple_strtoul(options, NULL, 0); + break; + } + options=next; + } +} + +static void cvppcfb_encode_mode(char* options, struct cvppcfb_startup* s) { + char* next; + int i=0; + + while (i<3 && options) { + if ((next=strchr(options, ';'))) + *(next++)='\0'; + switch (i++) { + case 0: + s->xres=(u32 ) + simple_strtoul(options, NULL, 0); + break; + case 1: + s->yres=(u32 ) + simple_strtoul(options, NULL, 0); + break; + case 2: + s->bpp=(u32 ) + simple_strtoul(options, NULL, 0); + break; + } + options=next; + } +} + +/* + * protected functions + */ + +static void cvppcfb_detect(void) { + + FBEGIN; + FEND; +} + +static int cvppcfb_encode_fix(struct fb_fix_screeninfo* fix, + const void* par, struct fb_info_gen* info) { + + FBEGIN; + strcpy(fix->id, cvppcfb_name); + fix->smem_start=(char* )video_phys; + fix->smem_len=(__u32 )video_size; + fix->type=FB_TYPE_PACKED_PIXELS; + if (((struct cvppcfb_par* )par)->bpp==8) + fix->visual=FB_VISUAL_PSEUDOCOLOR; + else + fix->visual=FB_VISUAL_TRUECOLOR; + fix->xpanstep=fix->ypanstep=fix->ywrapstep=0; + fix->line_length=0; /* computed by fbcon */ + fix->mmio_start=NULL; + fix->mmio_len=0; + fix->accel=FB_ACCEL_NONE; + FEND; + return 0; +} + +static int cvppcfb_decode_var(const struct fb_var_screeninfo* var, + void* par, struct fb_info_gen* info) { + struct cvppcfb_par p; + + FBEGIN; + memset(&p, 0, sizeof(struct cvppcfb_par)); + p.bpp=(var->bits_per_pixel+7)&~7; + if (p.bpp==24) + p.bpp=32; + if (p.bpp>32) { + DPRINTK("depth too big (%lu)\n", p.bpp); + return -EINVAL; + } + p.xres=(var->xres+7)&~7; + p.yres=var->yres; + if (p.xres<320 || p.yres<200 || p.xres>2048 || p.yres>2048) { + DPRINTK("bad resolution (%lux%lu)\n", p.xres, p.yres); + return -EINVAL; + } + p.vxres=(var->xres_virtual+7)&~7; + p.vxoff=(var->xoffset+7)&~7; + p.vyres=var->yres_virtual; + p.vyoff=var->yoffset; + if (p.vxres<p.xres+p.vxoff) + p.vxres=p.xres+p.vxoff; + if (p.vyres<p.yres+p.vyoff) + p.vyres=p.yres+p.vyoff; + if (p.vxres*p.vyres*p.bpp/8>video_size) { + DPRINTK("no memory for screen (%lux%lux%lu)\n", + p.vxres, p.vyres, p.bpp); + return -EINVAL; + } + p.sflags=var->sync&(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT); + p.clock=var->pixclock; + if (p.clock<6666) { + DPRINTK("pixclock too fast (%lu)\n", p.clock); + return -EINVAL; + } + p.left=var->left_margin; + p.top=var->upper_margin; + p.right=var->right_margin; + p.bottom=var->lower_margin; + p.hsynclen=var->hsync_len; + p.vsynclen=var->vsync_len; + *((struct cvppcfb_par* )par)=p; + FEND; + return 0; +} + +static int cvppcfb_encode_var(struct fb_var_screeninfo* var, + const void* par, struct fb_info_gen* info) { + struct cvppcfb_par* p=(struct cvppcfb_par* )par; + struct fb_var_screeninfo v; + + FBEGIN; + memset(&v, 0, sizeof(struct fb_var_screeninfo)); + v.xres=p->xres; + v.yres=p->yres; + v.xres_virtual=p->vxres; + v.yres_virtual=p->vyres; + v.xoffset=p->vxoff; + v.yoffset=p->vyoff; + v.bits_per_pixel=p->bpp; + switch (p->bpp) { + case 16: + v.red.offset=11; + v.red.length=5; + v.green.offset=5; + v.green.length=6; + v.blue.length=5; + break; + case 32: + v.transp.offset=24; + v.red.offset=16; + v.green.offset=8; + v.transp.length=8; + /* fallback */ + case 8: + v.red.length=v.green.length=v.blue.length=8; + break; + } + v.activate=FB_ACTIVATE_NOW; + v.height=v.width=-1; + v.pixclock=p->clock; + v.left_margin=p->left; + v.right_margin=p->right; + v.upper_margin=p->top; + v.lower_margin=p->bottom; + v.hsync_len=p->hsynclen; + v.vsync_len=p->vsynclen; + v.sync=p->sflags; + v.vmode=FB_VMODE_NONINTERLACED; + *var=v; + FEND; + return 0; +} + +static void cvppcfb_get_par(void* par, struct fb_info_gen* info) { + struct cvppcfb_info* i=(struct cvppcfb_info* )info; + + FBEGIN; + if (i->current_par_valid) + *((struct cvppcfb_par* )par)=i->current_par; + else + cvppcfb_decode_opt(&usr_startup, par, i); + FEND; +} + +static void cvppcfb_set_par(const void* par, struct fb_info_gen* info) { + struct cvppcfb_info* i=(struct cvppcfb_info* )info; + + FBEGIN; + i->current_par=*((struct cvppcfb_par* )par); + i->current_par_valid=1; + FEND; +} + +static int cvppcfb_getcolreg(unsigned regno, + unsigned* red, unsigned* green, unsigned* blue, + unsigned* transp, struct fb_info* info) { + struct cvppcfb_info* i=(struct cvppcfb_info* )info; + + if (regno<256) { + *red=i->palette[regno].red<<8|i->palette[regno].red; + *green=i->palette[regno].green<<8|i->palette[regno].green; + *blue=i->palette[regno].blue<<8|i->palette[regno].blue; + *transp=i->palette[regno].transp<<8|i->palette[regno].transp; + } + return regno>255; +} + +static int cvppcfb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info* info) { + struct cvppcfb_info* i=(struct cvppcfb_info* )info; + + if (regno<16) { + switch (i->current_par.bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + DPRINTK("8 bit depth not supported yet.\n"); + return 1; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + i->cmap.cmap16[regno]= + ((u32 )red & 0xf800) | + (((u32 )green & 0xfc00)>>5) | + (((u32 )blue & 0xf800)>>11); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + i->cmap.cmap32[regno]= + (((u32 )transp & 0xff00) << 16) | + (((u32 )red & 0xff00) << 8) | + (((u32 )green & 0xff00)) | + (((u32 )blue & 0xff00) >> 8); + break; +#endif + } + } + if (regno<256) { + i->palette[regno].red=red >> 8; + i->palette[regno].green=green >> 8; + i->palette[regno].blue=blue >> 8; + i->palette[regno].transp=transp >> 8; + } + return regno>255; +} + +static void cvppcfb_dispsw(const void* par, struct display* disp, + struct fb_info_gen* info) { + struct cvppcfb_info* i=(struct cvppcfb_info* )info; + unsigned long flags; + + FBEGIN; + save_flags(flags); + cli(); + switch (((struct cvppcfb_par* )par)->bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + disp->dispsw=&fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + disp->dispsw=&fbcon_cfb16; + disp->dispsw_data=i->cmap.cmap16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + disp->dispsw=&fbcon_cfb32; + disp->dispsw_data=i->cmap.cmap32; + break; +#endif + default: + disp->dispsw=&fbcon_dummy; + break; + } + restore_flags(flags); + FEND; +} + +static int cvppcfb_open(struct fb_info* info, int user) { + + MOD_INC_USE_COUNT; + return 0; +} + +static int cvppcfb_release(struct fb_info* info, int user) { + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * public functions + */ + +void cvppcfb_cleanup(struct fb_info* info) { + + unregister_framebuffer(info); +} + +__initfunc(void cvppcfb_init(void)) { + + FBEGIN; +#ifdef CVPPCFB_MASTER_DEBUG + printk("cvppcfb_init():\n"); + printk(" resolution %ldx%ldx%ld\n", usr_startup.xres, + usr_startup.yres, usr_startup.bpp); + printk(" debug: %ld, YANW: %ld\n", usr_startup.debug, + usr_startup.YANW); + printk(" monitorcap: %ld,%ld,%ld,%ld\n", + usr_startup.monitor.vfmin, usr_startup.monitor.vfmax, + usr_startup.monitor.hfmin, usr_startup.monitor.hfmax); +#endif + if (usr_startup.YANW) /* cannot probe yet */ + return; + memset(&fb_info, 0, sizeof(struct cvppcfb_info)); + video_size=CVPPC_SIZE; + video_phys=CVPPC_BASE; +#ifdef CONFIG_APUS + video_base=(char* ) + kernel_map(video_phys, video_size, KERNELMAP_NOCACHE_SER, NULL); +#else + video_base=ioremap(video_phys, video_size); +#endif + DPRINTK("video_phys=%08lx, video_base=%08lx\n", video_phys, video_base); + DPRINTK("phys_to_virt(video_phys)=%08lx\n", phys_to_virt(video_phys)); + DPRINTK("virt_to_phys(video_base)=%08lx\n", virt_to_phys(video_base)); + fb_info.disp.scrollmode=SCROLL_YREDRAW; + fb_info.gen.parsize=sizeof(struct cvppcfb_par); + fb_info.gen.fbhw=&cvppcfb_hwswitch; + cvppcfb_set_modename(&fb_info, &usr_startup); + fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT; + fb_info.gen.info.fbops=&cvppcfb_ops; + fb_info.gen.info.monspecs=usr_startup.monitor; + fb_info.gen.info.disp=&fb_info.disp; + strcpy(fb_info.gen.info.fontname, usr_startup.font); + fb_info.gen.info.switch_con=&fbgen_switch; + fb_info.gen.info.updatevar=&fbgen_update_var; + fb_info.gen.info.blank=&fbgen_blank; + fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info); + if (fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen)<0) { + printk( "cvppcfb: bad startup configuration: " + "unable to register.\n"); + return; + } + fbgen_set_disp(-1, &fb_info.gen); + fbgen_install_cmap(0, &fb_info.gen); + if (register_framebuffer(&fb_info.gen.info)<0) { + printk("cvppcfb: unable to register.\n"); + return; + } + printk("fb%d: %s frame buffer device, using %ldK of video memory\n", + GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename, + (unsigned long )(video_size>>10)); + MOD_INC_USE_COUNT; + FEND; +} + +__initfunc(void cvppcfb_setup(char* options, int* ints)) { + char* next; + + usr_startup.YANW=0; + DPRINTK("options: '%s'\n", options); + while (options) { + if ((next=strchr(options, ','))) + *(next++)='\0'; + if (!strncmp(options, "monitorcap:", 11)) + cvppcfb_encode_mcap(options+11, &usr_startup.monitor); + else if (!strncmp(options, "debug:", 6)) { + if (ISDIGIT(options[6])) + usr_startup.debug=options[6]-'0'; + else + usr_startup.debug=1; + } + else if (!strncmp(options, "mode:", 5)) + cvppcfb_encode_mode(options+5, &usr_startup); + else if (!strncmp(options, "font:", 5)) + strcpy(usr_startup.font, options+5); + else + DPRINTK("unrecognized option '%s'\n", options); + options=next; + } +#ifdef CVPPCFB_MASTER_DEBUG + printk("cvppcfb_setup():\n"); + printk(" resolution %ldx%ldx%ld\n", usr_startup.xres, + usr_startup.yres, usr_startup.bpp); + printk(" debug: %ld, YANW: %ld\n", usr_startup.debug, + usr_startup.YANW); + printk(" monitorcap: %ld,%ld,%ld,%ld\n", + usr_startup.monitor.vfmin, usr_startup.monitor.vfmax, + usr_startup.monitor.hfmin, usr_startup.monitor.hfmax); +#endif +} + +/* + * modularization + */ + +#ifdef MODULE +int init_module(void) { + + cvppcfb_init(); +} + +void cleanup_module(void) { + + cvppcfb_cleanup(); +} +#endif /* MODULE */ + diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c index ebf72f0bd..80ec1481b 100644 --- a/drivers/video/cyberfb.c +++ b/drivers/video/cyberfb.c @@ -1,24 +1,80 @@ /* - * linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device - * - * Copyright (C) 1996 Martin Apel - * Geert Uytterhoeven - * - * - * This file is based on the Amiga frame buffer device (amifb.c): - * - * Copyright (C) 1995 Geert Uytterhoeven - * - * - * History: - * - 22 Dec 95: Original version by Martin Apel - * - 05 Jan 96: Geert: integration into the current source tree - * - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ +* linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device +* $Id: cyberfb.c,v 1.6 1998/09/11 04:54:58 abair Exp $ +* +* Copyright (C) 1998 Alan Bair +* +* This file is based on two CyberVision64 frame buffer device drivers +* +* The second CyberVision64 frame buffer device (cvision.c cvision_core.c): +* +* Copyright (c) 1997 Antonio Santos +* +* Released as a patch to 2.1.35, but never included in the source tree. +* This is based on work from the NetBSD CyberVision64 frame buffer driver +* and support files (grf_cv.c, grf_cvreg.h, ite_cv.c): +* Permission to use the source of this driver was obtained from the +* author Michael Teske by Alan Bair. +* +* Copyright (c) 1995 Michael Teske +* +* The first CyberVision64 frame buffer device (cyberfb.c): +* +* Copyright (C) 1996 Martin Apel +* Geert Uytterhoeven +* +* Which is based on the Amiga frame buffer device (amifb.c): +* +* Copyright (C) 1995 Geert Uytterhoeven +* +* +* History: +* - 22 Dec 95: Original version by Martin Apel +* - 05 Jan 96: Geert: integration into the current source tree +* - 01 Aug 98: Alan: Merge in code from cvision.c and cvision_core.c +* $Log: cyberfb.c,v $ +* Revision 1.6 1998/09/11 04:54:58 abair +* Update for 2.1.120 change in include file location. +* Clean up for public release. +* +* Revision 1.5 1998/09/03 04:27:13 abair +* Move cv64_load_video_mode to cyber_set_video so a new video mode is install +* with each change of the 'var' data. +* +* Revision 1.4 1998/09/01 00:31:17 abair +* Put in a set of default 8,16,24 bpp modes and map cyber8,16 to them. +* Update operations with 'par' to handle a more complete set of parameter +* values for encode/decode process. +* +* Revision 1.3 1998/08/31 21:31:33 abair +* Swap 800x490 for 640x480 video mode and more cleanup. +* Abandon idea to resurrect "custom" mode setting via kernel opts, +* instead work on making use of fbset program to do this. +* +* Revision 1.2 1998/08/31 06:17:08 abair +* Make updates for changes in cyberfb.c released in 2.1.119 +* and do some cleanup of the code. +* +* Revision 1.1 1998/08/29 18:38:31 abair +* Initial revision +* +* Revision 1.3 1998/08/17 06:21:53 abair +* Remove more redundant code after merging in cvision_core.c +* Set blanking by colormap to pale red to detect this vs trying to +* use video blanking. More formating to Linux code style. +* +* Revision 1.2 1998/08/15 17:51:37 abair +* Added cvision_core.c code from 2.1.35 patches. +* Changed to compile correctly and switch to using initialization +* code. Added debugging and dropping of duplicate code. +* +* +* +* This file is subject to the terms and conditions of the GNU General Public +* License. See the file COPYING in the main directory of this archive +* for more details. +*/ + #include <linux/module.h> #include <linux/kernel.h> @@ -36,31 +92,31 @@ #include <asm/irq.h> #include <asm/pgtable.h> #include <asm/amigahw.h> +#include <asm/io.h> -#include "s3blit.h" -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" - +#include "cyberfb.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +/*#define CYBERFBDEBUG*/ #ifdef CYBERFBDEBUG #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +static void cv64_dump(void); #else #define DPRINTK(fmt, args...) #endif #define arraysize(x) (sizeof(x)/sizeof(*(x))) - #define wb_64(reg,dat) (*((unsigned char volatile *)CyberRegs + reg) = dat) - - struct cyberfb_par { - int xres; - int yres; - int bpp; - int accel; + struct fb_var_screeninfo var; + __u32 type; + __u32 type_aux; + __u32 visual; + __u32 line_length; }; static struct cyberfb_par current_par; @@ -73,148 +129,148 @@ static struct fb_info fb_info; /* - * Switch for Chipset Independency - */ +* Switch for Chipset Independency +*/ static struct fb_hwswitch { - /* Initialisation */ +/* Initialisation */ - int (*init)(void); +int (*init)(void); - /* Display Control */ +/* Display Control */ - int (*encode_fix)(struct fb_fix_screeninfo *fix, struct cyberfb_par *par); - int (*decode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par); - int (*encode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par); - int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); - int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); - void (*blank)(int blank); +int (*encode_fix)(struct fb_fix_screeninfo *fix, struct cyberfb_par *par); +int (*decode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par); +int (*encode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par); +int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); +int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +void (*blank)(int blank); } *fbhw; /* - * Frame Buffer Name - */ +* Frame Buffer Name +*/ static char cyberfb_name[16] = "Cybervision"; /* - * Cybervision Graphics Board - */ - -#define CYBER8_WIDTH 1152 -#define CYBER8_HEIGHT 886 -#define CYBER8_PIXCLOCK 12500 /* ++Geert: Just a guess */ +* Cybervision Graphics Board +*/ -#if 0 -#define CYBER16_WIDTH 800 -#define CYBER16_HEIGHT 600 -#endif -#define CYBER16_PIXCLOCK 25000 /* ++Geert: Just a guess */ - - -static unsigned int CyberKey = 0; -static unsigned char Cyber_colour_table [256][4]; +static unsigned char Cyber_colour_table [256][3]; static unsigned long CyberMem; static unsigned long CyberSize; static volatile char *CyberRegs; - +/* From cvision.c for cvision_core.c */ +static unsigned long cv64_mem; +static unsigned long cv64_fbmem; +static volatile char *cv64_regs; +static unsigned long cv64_size; +#if 0 +static int cvision_custom_mode = 0; +static int hbs, hbe, hss, hse, ht, vbs, vbe, vss, vse, vt; +#endif /* - * Predefined Video Modes - */ +* Predefined Video Modes +*/ static struct fb_videomode cyberfb_predefined[] __initdata = { - { - "640x480-8", { /* Cybervision 8 bpp */ - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "800x600-8", { /* Cybervision 8 bpp */ - 800, 600, 800, 600, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "1024x768-8", { /* Cybervision 8 bpp */ - 1024, 768, 1024, 768, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "1152x886-8", { /* Cybervision 8 bpp */ - 1152, 886, 1152, 886, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "1280x1024-8", { /* Cybervision 8 bpp */ - 1280, 1024, 1280, 1024, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "1600x1200-8", { /* Cybervision 8 bpp */ - 1600, 1200, 1600, 1200, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - }, { - "800x600-16", { /* Cybervision 16 bpp */ - 800, 600, 800, 600, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - } - } + { "640x480-8", { /* Default 8 BPP mode (cyber8) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "640x480-16", { /* Default 16 BPP mode (cyber16) */ + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "640x480-24", { /* Default 24 BPP mode */ + 640, 480, 640, 480, 0, 0, 24, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "800x490-8", { /* Cybervision 8 bpp */ + /* NO Acceleration */ + 800, 490, 800, 490, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, +/* I can't test these with my monitor, but I suspect they will + * be OK, since Antonio Santos indicated he had tested them in + * his system. + */ + { "800x600-8", { /* Cybervision 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 72, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1024x768-8", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 224, 72, 60, 12, 168, 4, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1152x886-8", { /* Cybervision 8 bpp */ + 1152, 886, 1152, 886, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 15873, 184, 40, 24, 1, 56, 16, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED + }}, + { "1280x1024-8", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 256, 48, 50, 12, 72, 4, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED + }} }; - #define NUM_TOTAL_MODES arraysize(cyberfb_predefined) - static int Cyberfb_inverse = 0; -#if 0 -static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */ -static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */ -#endif /* - * Some default modes - */ +* Some default modes +*/ #define CYBER8_DEFMODE (0) -#define CYBER16_DEFMODE (6) +#define CYBER16_DEFMODE (1) static struct fb_var_screeninfo cyberfb_default; - /* - * Interface used by the world - */ +* Interface used by the world +*/ void cyberfb_setup(char *options, int *ints); static int cyberfb_open(struct fb_info *info, int user); static int cyberfb_release(struct fb_info *info, int user); -static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct -fb_info *info); -static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, struct -fb_info *info); -static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, struct -fb_info *info); +static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -222,31 +278,28 @@ static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); static int cyberfb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); - + u_long arg, int con, struct fb_info *info); /* - * Interface to the low level console driver - */ +* Interface to the low level console driver +*/ void cyberfb_init(void); static int Cyberfb_switch(int con, struct fb_info *info); static int Cyberfb_updatevar(int con, struct fb_info *info); static void Cyberfb_blank(int blank, struct fb_info *info); - /* - * Text console acceleration - */ +* Text console acceleration +*/ #ifdef FBCON_HAS_CFB8 static struct display_switch fbcon_cyber8; #endif - /* - * Accelerated Functions used by the low level console driver - */ +* Accelerated Functions used by the low level console driver +*/ static void Cyber_WaitQueue(u_short fifo); static void Cyber_WaitBlit(void); @@ -257,28 +310,26 @@ static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height, u_short mode, u_short color); static void Cyber_MoveCursor(u_short x, u_short y); - /* - * Hardware Specific Routines - */ +* Hardware Specific Routines +*/ static int Cyber_init(void); static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, - struct cyberfb_par *par); + struct cyberfb_par *par); static int Cyber_decode_var(struct fb_var_screeninfo *var, - struct cyberfb_par *par); + struct cyberfb_par *par); static int Cyber_encode_var(struct fb_var_screeninfo *var, - struct cyberfb_par *par); + struct cyberfb_par *par); static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); + u_int *transp, struct fb_info *info); static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); + u_int transp, struct fb_info *info); static void Cyber_blank(int blank); - /* - * Internal routines - */ +* Internal routines +*/ static void cyberfb_get_par(struct cyberfb_par *par); static void cyberfb_set_par(struct cyberfb_par *par); @@ -287,41 +338,48 @@ static void do_install_cmap(int con, struct fb_info *info); static void cyberfb_set_disp(int con, struct fb_info *info); static int get_video_mode(const char *name); +/* For cvision_core.c */ +static unsigned short cv64_compute_clock(unsigned long); +static int cv_has_4mb (volatile caddr_t); +static void cv64_board_init (void); +static void cv64_load_video_mode (struct fb_var_screeninfo *); + /* -------------------- Hardware specific routines ------------------------- */ /* - * Initialization - * - * Set the default video mode for this chipset. If a video mode was - * specified on the command line, it will override the default mode. - */ +* Initialization +* +* Set the default video mode for this chipset. If a video mode was +* specified on the command line, it will override the default mode. +*/ static int Cyber_init(void) { int i; - char size; volatile u_long *CursorBase; + DPRINTK("ENTER\n"); - for (i = 0; i < 256; i++) - { +/* Init local cmap as greyscale levels */ + for (i = 0; i < 256; i++) { Cyber_colour_table [i][0] = i; Cyber_colour_table [i][1] = i; Cyber_colour_table [i][2] = i; - Cyber_colour_table [i][3] = 0; } - /* - * Just clear the thing for the biggest mode. - * - * ++Andre, TODO: determine size first, then clear all memory - * (the 3D penguin might need texture memory :-) ) - */ - - memset ((char*)CyberMem, 0, 1600 * 1200); +/* Initialize the board and determine fbmem size */ + cv64_board_init (); +#ifdef CYBERFBDEBUG + DPRINTK("Register state after initing board\n"); + cv64_dump(); +#endif +/* Clear framebuffer memory */ + DPRINTK("Clear framebuffer memory\n"); + memset ((char *) cv64_fbmem, 0, cv64_size); - /* Disable hardware cursor */ +/* Disable hardware cursor */ + DPRINTK("Disable HW cursor\n"); wb_64(S3_CRTC_ADR, S3_REG_LOCK2); wb_64(S3_CRTC_DATA, 0xa0); wb_64(S3_CRTC_ADR, S3_HGC_MODE); @@ -331,15 +389,10 @@ static int Cyber_init(void) wb_64(S3_CRTC_ADR, S3_HWGC_DY); wb_64(S3_CRTC_DATA, 0x00); - /* Get memory size (if not 2MB it is 4MB) */ - *(CyberRegs + S3_CRTC_ADR) = S3_LAW_CTL; - size = *(CyberRegs + S3_CRTC_DATA); - if ((size & 0x03) == 0x02) - CyberSize = 0x00200000; /* 2 MB */ - else - CyberSize = 0x00400000; /* 4 MB */ + CyberSize = cv64_size; - /* Initialize hardware cursor */ +/* Initialize hardware cursor */ + DPRINTK("Init HW cursor\n"); CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400); for (i=0; i < 8; i++) { @@ -356,34 +409,38 @@ static int Cyber_init(void) *(CursorBase+3+(i*4)) = 0xffff0000; } - Cyber_setcolreg (255, 56, 100, 160, 0, NULL /* unused */); + Cyber_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */); Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */); + DPRINTK("EXIT\n"); return 0; } /* - * This function should fill in the `fix' structure based on the - * values in the `par' structure. - */ +* This function should fill in the `fix' structure based on the +* values in the `par' structure. +*/ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, struct cyberfb_par *par) { + DPRINTK("ENTER\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, cyberfb_name); - fix->smem_start = (char *)CyberMem; + fix->smem_start = (char*) virt_to_phys ((void *)CyberMem); fix->smem_len = CyberSize; - fix->mmio_start = (char *)CyberRegs; + fix->mmio_start = (char*) virt_to_phys ((void *)CyberRegs); fix->mmio_len = 0x10000; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - if (par->bpp == 8) - fix->visual = FB_VISUAL_PSEUDOCOLOR; - else + if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 || + par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) { fix->visual = FB_VISUAL_DIRECTCOLOR; + } else { + fix->visual = FB_VISUAL_PSEUDOCOLOR; + } fix->xpanstep = 0; fix->ypanstep = 0; @@ -391,181 +448,194 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, fix->line_length = 0; fix->accel = FB_ACCEL_S3_TRIO64; + DPRINTK("EXIT\n"); return(0); } /* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ +* Fill the `par' structure based on the values in `var'. +* TODO: Verify and adjust values, return -EINVAL if bad. +*/ static int Cyber_decode_var(struct fb_var_screeninfo *var, struct cyberfb_par *par) { -#if 1 - par->xres = var->xres; - par->yres = var->yres; - par->bpp = var->bits_per_pixel; - if (var->accel_flags & FB_ACCELF_TEXT) - par->accel = FB_ACCELF_TEXT; - else - par->accel = 0; -#else - if (Cyberfb_Cyber8) { - par->xres = CYBER8_WIDTH; - par->yres = CYBER8_HEIGHT; - par->bpp = 8; + DPRINTK("ENTER\n"); + par->var.xres = var->xres; + par->var.yres = var->yres; + par->var.xres_virtual = var->xres_virtual; + par->var.yres_virtual = var->yres_virtual; + par->var.xoffset = var->xoffset; + par->var.yoffset = var->yoffset; + par->var.bits_per_pixel = var->bits_per_pixel; + par->var.grayscale = var->grayscale; + par->var.red = var->red; + par->var.green = var->green; + par->var.blue = var->blue; + par->var.transp = var->transp; + par->var.nonstd = var->nonstd; + par->var.activate = var->activate; + par->var.height = var->height; + par->var.width = var->width; + if (var->accel_flags & FB_ACCELF_TEXT) { + par->var.accel_flags = FB_ACCELF_TEXT; } else { - par->xres = CYBER16_WIDTH; - par->yres = CYBER16_HEIGHT; - par->bpp = 16; + par->var.accel_flags = 0; } -#endif + par->var.pixclock = var->pixclock; + par->var.left_margin = var->left_margin; + par->var.right_margin = var->right_margin; + par->var.upper_margin = var->upper_margin; + par->var.lower_margin = var->lower_margin; + par->var.hsync_len = var->hsync_len; + par->var.vsync_len = var->vsync_len; + par->var.sync = var->sync; + par->var.vmode = var->vmode; + DPRINTK("EXIT\n"); return(0); } - /* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ +* Fill the `var' structure based on the values in `par' and maybe +* other values read out of the hardware. +*/ static int Cyber_encode_var(struct fb_var_screeninfo *var, struct cyberfb_par *par) { - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->xres; - var->yres_virtual = par->yres; - var->xoffset = 0; - var->yoffset = 0; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - if (par->bpp == 8) { - var->red.offset = 0; - var->red.length = 8; - var->red.msb_right = 0; - var->blue = var->green = var->red; - } else { - var->red.offset = 11; - var->red.length = 5; - var->red.msb_right = 0; - var->green.offset = 5; - var->green.length = 6; - var->green.msb_right = 0; - var->blue.offset = 0; - var->blue.length = 5; - var->blue.msb_right = 0; - } - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0; - - var->vmode = FB_VMODE_NONINTERLACED; - - /* Dummy values */ - - if (par->bpp == 8) - var->pixclock = CYBER8_PIXCLOCK; - else - var->pixclock = CYBER16_PIXCLOCK; - var->sync = 0; - var->left_margin = 64; - var->right_margin = 96; - var->upper_margin = 35; - var->lower_margin = 12; - var->hsync_len = 112; - var->vsync_len = 2; - + DPRINTK("ENTER\n"); + var->xres = par->var.xres; + var->yres = par->var.yres; + var->xres_virtual = par->var.xres_virtual; + var->yres_virtual = par->var.yres_virtual; + var->xoffset = par->var.xoffset; + var->yoffset = par->var.yoffset; + + var->bits_per_pixel = par->var.bits_per_pixel; + var->grayscale = par->var.grayscale; + + var->red = par->var.red; + var->green = par->var.green; + var->blue = par->var.blue; + var->transp = par->var.transp; + + var->nonstd = par->var.nonstd; + var->activate = par->var.activate; + + var->height = par->var.height; + var->width = par->var.width; + + var->accel_flags = par->var.accel_flags; + + var->pixclock = par->var.pixclock; + var->left_margin = par->var.left_margin; + var->right_margin = par->var.right_margin; + var->upper_margin = par->var.upper_margin; + var->lower_margin = par->var.lower_margin; + var->hsync_len = par->var.hsync_len; + var->vsync_len = par->var.vsync_len; + var->sync = par->var.sync; + var->vmode = par->var.vmode; + + DPRINTK("EXIT\n"); return(0); } /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ +* Set a single color register. Return != 0 for invalid regno. +*/ static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { - if (regno > 255) - { + /*DPRINTK("ENTER\n");*/ + if (regno > 255) { + DPRINTK("EXIT - Register # > 255\n"); return (1); } wb_64(0x3c8, (unsigned char) regno); - Cyber_colour_table [regno][0] = red & 0xff; - Cyber_colour_table [regno][1] = green & 0xff; - Cyber_colour_table [regno][2] = blue & 0xff; - Cyber_colour_table [regno][3] = transp; - wb_64(0x3c9, (red & 0xff) >> 2); - wb_64(0x3c9, (green & 0xff) >> 2); - wb_64(0x3c9, (blue & 0xff) >> 2); + red >>= 10; + green >>= 10; + blue >>= 10; + Cyber_colour_table [regno][0] = red; + Cyber_colour_table [regno][1] = green; + Cyber_colour_table [regno][2] = blue; + + wb_64(0x3c9, red); + wb_64(0x3c9, green); + wb_64(0x3c9, blue); + + /*DPRINTK("EXIT\n");*/ return (0); } /* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ +* Read a single color register and split it into +* colors/transparent. Return != 0 for invalid regno. +*/ static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) { - if (regno >= 256) + int t; + + /*DPRINTK("ENTER\n");*/ + if (regno > 255) { + DPRINTK("EXIT - Register # > 255\n"); return (1); - *red = Cyber_colour_table [regno][0]; - *green = Cyber_colour_table [regno][1]; - *blue = Cyber_colour_table [regno][2]; - *transp = Cyber_colour_table [regno][3]; + } + /* ARB This shifting & oring seems VERY strange */ + t = Cyber_colour_table [regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + *transp = 0; + /*DPRINTK("EXIT\n");*/ return (0); } /* - * (Un)Blank the screen - */ +* (Un)Blank the screen +* blank: 1 = zero fb cmap +* 0 = restore fb cmap from local cmap +*/ void Cyber_blank(int blank) { int i; - if (blank) - { - for (i = 0; i < 256; i++) - { + DPRINTK("ENTER\n"); +#if 0 +/* Blank by turning gfx off */ + gfx_on_off (1, cv64_regs); +#else + if (blank) { + for (i = 0; i < 256; i++) { wb_64(0x3c8, (unsigned char) i); - wb_64(0x3c9, 0); + /* ARB Pale red to detect this blanking method */ + wb_64(0x3c9, 48); wb_64(0x3c9, 0); wb_64(0x3c9, 0); } - } - else - { - for (i = 0; i < 256; i++) - { + } else { + for (i = 0; i < 256; i++) { wb_64(0x3c8, (unsigned char) i); - wb_64(0x3c9, Cyber_colour_table[i][0] >> 2); - wb_64(0x3c9, Cyber_colour_table[i][1] >> 2); - wb_64(0x3c9, Cyber_colour_table[i][2] >> 2); + wb_64(0x3c9, Cyber_colour_table[i][0]); + wb_64(0x3c9, Cyber_colour_table[i][1]); + wb_64(0x3c9, Cyber_colour_table[i][2]); } } +#endif + DPRINTK("EXIT\n"); } @@ -576,11 +646,12 @@ static void Cyber_WaitQueue (u_short fifo) { u_short status; - do - { + DPRINTK("ENTER\n"); + do { status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); } while (status & fifo); + DPRINTK("EXIT\n"); } /************************************************************** @@ -590,11 +661,12 @@ static void Cyber_WaitBlit (void) { u_short status; - do - { + DPRINTK("ENTER\n"); + do { status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); } while (status & S3_HDW_BUSY); + DPRINTK("EXIT\n"); } /************************************************************** @@ -606,20 +678,19 @@ static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, { u_short blitcmd = S3_BITBLT; + DPRINTK("ENTER\n"); /* Set drawing direction */ /* -Y, X maj, -X (default) */ - if (curx > destx) + if (curx > destx) { blitcmd |= 0x0020; /* Drawing direction +X */ - else - { + } else { curx += (width - 1); destx += (width - 1); } - if (cury > desty) + if (cury > desty) { blitcmd |= 0x0080; /* Drawing direction +Y */ - else - { + } else { cury += (height - 1); desty += (height - 1); } @@ -639,6 +710,7 @@ static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1; *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd; + DPRINTK("EXIT\n"); } /************************************************************** @@ -649,6 +721,7 @@ static void Cyber_RectFill (u_short x, u_short y, u_short width, { u_short blitcmd = S3_FILLEDRECT; + DPRINTK("ENTER\n"); Cyber_WaitQueue (0x8000); *((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000; @@ -664,6 +737,7 @@ static void Cyber_RectFill (u_short x, u_short y, u_short width, *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1; *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd; + DPRINTK("EXIT\n"); } /************************************************************** @@ -671,6 +745,7 @@ static void Cyber_RectFill (u_short x, u_short y, u_short width, */ static void Cyber_MoveCursor (u_short x, u_short y) { + DPRINTK("ENTER\n"); *(CyberRegs + S3_CRTC_ADR) = 0x39; *(CyberRegs + S3_CRTC_DATA) = 0xa0; @@ -683,6 +758,7 @@ static void Cyber_MoveCursor (u_short x, u_short y) *(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8); *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_L; *(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff); + DPRINTK("EXIT\n"); } @@ -695,7 +771,7 @@ static struct fb_hwswitch Cyber_switch = { }; -/* -------------------- Generic routines ------------------------------------ */ +/* -------------------- Generic routines ---------------------------------- */ /* @@ -704,33 +780,34 @@ static struct fb_hwswitch Cyber_switch = { static void cyberfb_get_par(struct cyberfb_par *par) { - if (current_par_valid) - { + DPRINTK("ENTER\n"); + if (current_par_valid) { *par = current_par; - } - else - { + } else { fbhw->decode_var(&cyberfb_default, par); } + DPRINTK("EXIT\n"); } static void cyberfb_set_par(struct cyberfb_par *par) { + DPRINTK("ENTER\n"); current_par = *par; current_par_valid = 1; + DPRINTK("EXIT\n"); } static void cyber_set_video(struct fb_var_screeninfo *var) { - /* Set clipping rectangle to current screen size */ - - *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x1000; - *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x2000; - *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (var->yres - 1); - *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (var->xres - 1); + /* Load the video mode defined by the 'var' data */ + cv64_load_video_mode (var); +#ifdef CYBERFBDEBUG + DPRINTK("Register state after loading video mode\n"); + cv64_dump(); +#endif } @@ -739,8 +816,11 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) int err, activate; struct cyberfb_par par; - if ((err = fbhw->decode_var(var, &par))) + DPRINTK("ENTER\n"); + if ((err = fbhw->decode_var(var, &par))) { + DPRINTK("EXIT - decode_var failed\n"); return(err); + } activate = var->activate; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) cyberfb_set_par(&par); @@ -748,20 +828,27 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) var->activate = activate; cyber_set_video(var); + DPRINTK("EXIT\n"); return 0; } static void do_install_cmap(int con, struct fb_info *info) { - if (con != currcon) + DPRINTK("ENTER\n"); + if (con != currcon) { + DPRINTK("EXIT - Not current console\n"); return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - fbhw->setcolreg, info); - else + } + if (fb_display[con].cmap.len) { + DPRINTK("Use console cmap\n"); + fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); + } else { + DPRINTK("Use default cmap\n"); fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, fbhw->setcolreg, info); + 1, fbhw->setcolreg, info); + } + DPRINTK("EXIT\n"); } @@ -796,10 +883,13 @@ static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct cyberfb_par par; int error = 0; - if (con == -1) + DPRINTK("ENTER\n"); + if (con == -1) { cyberfb_get_par(&par); - else + } else { error = fbhw->decode_var(&fb_display[con].var, &par); + } + DPRINTK("EXIT\n"); return(error ? error : fbhw->encode_fix(fix, &par)); } @@ -814,17 +904,16 @@ static int cyberfb_get_var(struct fb_var_screeninfo *var, int con, struct cyberfb_par par; int error = 0; - if (con == -1) - { + DPRINTK("ENTER\n"); + if (con == -1) { cyberfb_get_par(&par); error = fbhw->encode_var(var, &par); disp.var = *var; /* ++Andre: don't know if this is the right place */ - } - else - { + } else { *var = fb_display[con].var; } + DPRINTK("EXIT\n"); return(error); } @@ -834,6 +923,7 @@ static void cyberfb_set_disp(int con, struct fb_info *info) struct fb_fix_screeninfo fix; struct display *display; + DPRINTK("ENTER\n"); if (con >= 0) display = &fb_display[con]; else @@ -842,7 +932,7 @@ static void cyberfb_set_disp(int con, struct fb_info *info) cyberfb_get_fix(&fix, con, info); if (con == -1) con = 0; - display->screen_base = fix.smem_start; + display->screen_base = phys_to_virt ((unsigned long) fix.smem_start); display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -869,6 +959,7 @@ static void cyberfb_set_disp(int con, struct fb_info *info) display->dispsw = NULL; break; } + DPRINTK("EXIT\n"); } @@ -881,8 +972,11 @@ static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, { int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; - if ((err = do_fb_set_var(var, con == currcon))) + DPRINTK("ENTER\n"); + if ((err = do_fb_set_var(var, con == currcon))) { + DPRINTK("EXIT - do_fb_set_var failed\n"); return(err); + } if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres = fb_display[con].var.xres; oldyres = fb_display[con].var.yres; @@ -903,6 +997,7 @@ static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, } } var->activate = 0; + DPRINTK("EXIT\n"); return(0); } @@ -914,14 +1009,19 @@ static int cyberfb_set_var(struct fb_var_screeninfo *var, int con, static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console? */ - return(fb_get_cmap(cmap, &fb_display[con].var, - kspc, fbhw->getcolreg, info)); - else if (fb_display[con].cmap.len) /* non default colormap? */ + DPRINTK("ENTER\n"); + if (con == currcon) { /* current console? */ + DPRINTK("EXIT - console is current console\n"); + return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info)); + } else if (fb_display[con].cmap.len) { /* non default colormap? */ + DPRINTK("Use console cmap\n"); fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else + } else { + DPRINTK("Use default cmap\n"); fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2); + } + DPRINTK("EXIT\n"); return(0); } @@ -935,16 +1035,22 @@ static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, { int err; + DPRINTK("ENTER\n"); if (!fb_display[con].cmap.len) { /* no colormap allocated? */ if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<<fb_display[con].var.bits_per_pixel, 0))) + 1<<fb_display[con].var.bits_per_pixel, + 0))) { + DPRINTK("EXIT - fb_alloc_cmap failed\n"); return(err); + } } - if (con == currcon) /* current console? */ - return(fb_set_cmap(cmap, &fb_display[con].var, - kspc, fbhw->setcolreg, info)); - else + if (con == currcon) { /* current console? */ + DPRINTK("EXIT - Current console\n"); + return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info)); + } else { fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + } + DPRINTK("EXIT\n"); return(0); } @@ -983,33 +1089,36 @@ static struct fb_ops cyberfb_ops = { __initfunc(void cyberfb_setup(char *options, int *ints)) { char *this_opt; + DPRINTK("ENTER\n"); fb_info.fontname[0] = '\0'; - if (!options || !*options) + if (!options || !*options) { + DPRINTK("EXIT - no options\n"); return; + } - for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { if (!strcmp(this_opt, "inverse")) { Cyberfb_inverse = 1; fb_invert_cmaps(); - } else if (!strncmp(this_opt, "font:", 5)) + } else if (!strncmp(this_opt, "font:", 5)) { strcpy(fb_info.fontname, this_opt+5); - else if (!strcmp (this_opt, "cyber8")){ + } else if (!strcmp (this_opt, "cyber8")) { cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var; - } - else if (!strcmp (this_opt, "cyber16")){ + } else if (!strcmp (this_opt, "cyber16")) { cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var; - } - else - get_video_mode(this_opt); + } else get_video_mode(this_opt); + } - DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",cyberfb_default.xres, - cyberfb_default.yres, - cyberfb_default.bits_per_pixel); + DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n", + cyberfb_default.xres, + cyberfb_default.yres, + cyberfb_default.bits_per_pixel); + DPRINTK("EXIT\n"); } - /* * Initialization */ @@ -1018,19 +1127,39 @@ __initfunc(void cyberfb_init(void)) { struct cyberfb_par par; unsigned long board_addr; + unsigned long board_size; const struct ConfigDev *cd; + unsigned int CyberKey = 0; + DPRINTK("ENTER\n"); - if (!(CyberKey = zorro_find(ZORRO_PROD_PHASE5_CYBERVISION64, 0, 0))) + if (!(CyberKey = zorro_find(ZORRO_PROD_PHASE5_CYBERVISION64, 0, 0))) { + DPRINTK("EXIT - zorro_find failed\n"); return; + } cd = zorro_get_board (CyberKey); zorro_config_board (CyberKey, 0); board_addr = (unsigned long)cd->cd_BoardAddr; + board_size = (unsigned long)cd->cd_BoardSize; + DPRINTK("board_addr=%08lx\n", board_addr); + DPRINTK("board_size=%08lx\n", board_size); + + cv64_mem = kernel_map (board_addr, board_size, KERNELMAP_NOCACHE_SER, + NULL); + cv64_regs = (volatile char *)(cv64_mem + 0x02000000); + cv64_fbmem = cv64_mem + 0x01400000; + DPRINTK("cv64_mem=%08lx cv64_regs=%08lx cv64_fbmem=%08lx\n", + cv64_mem, (long unsigned int)cv64_regs, cv64_fbmem); + + CyberMem = cv64_fbmem; + CyberRegs = cv64_regs; + DPRINTK("CyberMem=%08lx CyberRegs=%08lx\n", CyberMem, + (long unsigned int)CyberRegs); - /* This includes the video memory as well as the S3 register set */ - CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000, - KERNELMAP_NOCACHE_SER, NULL); - CyberRegs = (char*) (CyberMem + 0x00c00000); +#ifdef CYBERFBDEBUG + DPRINTK("Register state just after mapping memory\n"); + cv64_dump(); +#endif fbhw = &Cyber_switch; @@ -1052,28 +1181,34 @@ __initfunc(void cyberfb_init(void)) cyberfb_set_disp(-1, &fb_info); do_install_cmap(0, &fb_info); - if (register_framebuffer(&fb_info) < 0) + if (register_framebuffer(&fb_info) < 0) { + DPRINTK("EXIT - register_framebuffer failed\n"); return; + } printk("fb%d: %s frame buffer device, using %ldK of video memory\n", GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10); /* TODO: This driver cannot be unloaded yet */ MOD_INC_USE_COUNT; + DPRINTK("EXIT\n"); } static int Cyberfb_switch(int con, struct fb_info *info) { + DPRINTK("ENTER\n"); /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - fbhw->getcolreg, info); + if (fb_display[currcon].cmap.len) { + fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg, + info); + } do_fb_set_var(&fb_display[con].var, 1); currcon = con; /* Install new colormap */ do_install_cmap(con, info); + DPRINTK("EXIT\n"); return(0); } @@ -1087,17 +1222,20 @@ static int Cyberfb_switch(int con, struct fb_info *info) static int Cyberfb_updatevar(int con, struct fb_info *info) { + DPRINTK("Enter - Exit\n"); return(0); } /* - * Blank the display. - */ + * Blank the display. + */ static void Cyberfb_blank(int blank, struct fb_info *info) { + DPRINTK("Enter\n"); fbhw->blank(blank); + DPRINTK("Exit\n"); } @@ -1109,14 +1247,17 @@ __initfunc(static int get_video_mode(const char *name)) { int i; + DPRINTK("ENTER\n"); for (i = 0; i < NUM_TOTAL_MODES; i++) { if (!strcmp(name, cyberfb_predefined[i].name)) { cyberfb_default = cyberfb_predefined[i].var; + DPRINTK("EXIT - Matched predefined mode\n"); return(i); } } /* ++Andre: set cyberfb default mode */ cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var; + DPRINTK("EXIT - Use default cyber8 mode\n"); return(0); } @@ -1129,45 +1270,56 @@ __initfunc(static int get_video_mode(const char *name)) static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - sx *= 8; dx *= 8; width *= 8; - Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx, - (u_short)(dy*p->fontheight), (u_short)width, - (u_short)(height*p->fontheight), (u_short)S3_NEW); + DPRINTK("ENTER\n"); + sx *= 8; dx *= 8; width *= 8; + Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p)), (u_short)S3_NEW); + DPRINTK("EXIT\n"); } static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - unsigned char bg; - - sx *= 8; width *= 8; - bg = attr_bgcol_ec(p,conp); - Cyber_RectFill((u_short)sx, - (u_short)(sy*p->fontheight), - (u_short)width, - (u_short)(height*p->fontheight), - (u_short)S3_NEW, - (u_short)bg); + unsigned char bg; + + DPRINTK("ENTER\n"); + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + Cyber_RectFill((u_short)sx, + (u_short)(sy*fontheight(p)), + (u_short)width, + (u_short)(height*fontheight(p)), + (u_short)S3_NEW, + (u_short)bg); + DPRINTK("EXIT\n"); } static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) { - Cyber_WaitBlit(); - fbcon_cfb8_putc(conp, p, c, yy, xx); + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_putc(conp, p, c, yy, xx); + DPRINTK("EXIT\n"); } static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx) + const unsigned short *s, int count, + int yy, int xx) { - Cyber_WaitBlit(); - fbcon_cfb8_putcs(conp, p, s, count, yy, xx); + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_putcs(conp, p, s, count, yy, xx); + DPRINTK("EXIT\n"); } static void fbcon_cyber8_revc(struct display *p, int xx, int yy) { - Cyber_WaitBlit(); - fbcon_cfb8_revc(p, xx, yy); + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + fbcon_cfb8_revc(p, xx, yy); + DPRINTK("EXIT\n"); } static struct display_switch fbcon_cyber8 = { @@ -1193,3 +1345,1125 @@ void cleanup_module(void) /* TODO: clean up ... */ } #endif /* MODULE */ + +/* + * + * Low level initialization routines for the CyberVision64 graphics card + * + * Most of the following code is from cvision_core.c + * + */ + +#define MAXPIXELCLOCK 135000000 /* safety */ + +#ifdef CV_AGGRESSIVE_TIMING +long cv64_memclk = 55000000; +#else +long cv64_memclk = 50000000; +#endif + +/*********************/ + +static unsigned char clocks[]={ + 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69, + 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c, + 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a, + 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69, + 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65, + 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63, + 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d, + 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49, + 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42, + 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43, + 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49, + 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a, + 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49, + 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41, + 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43, + 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45, + 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45, + 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45, + 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44, + 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46, + 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f, + 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22, + 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46, + 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b, + 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44, + 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26, + 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b, + 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25, + 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25, + 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21, + 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29, + 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29, + 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29, + 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28, + 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26, + 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21, + 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28, + 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27, + 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22, + 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27, + 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27, + 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21, + 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26, + 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27, + 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9, + 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb, + 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9, + 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2, + 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25, + 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25, + 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25, + 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd, + 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3, + 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25, + 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2, + 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22, + 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb, + 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9, + 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc, + 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9, + 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1, + 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0, +}; + +/* Console colors */ +unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */ + /* R G B */ + {0x30, 0x30, 0x30}, + {0x00, 0x00, 0x00}, + {0x80, 0x00, 0x00}, + {0x00, 0x80, 0x00}, + {0x00, 0x00, 0x80}, + {0x80, 0x80, 0x00}, + {0x00, 0x80, 0x80}, + {0x80, 0x00, 0x80}, + {0xff, 0xff, 0xff}, + {0x40, 0x40, 0x40}, + {0xff, 0x00, 0x00}, + {0x00, 0xff, 0x00}, + {0x00, 0x00, 0xff}, + {0xff, 0xff, 0x00}, + {0x00, 0xff, 0xff}, + {0x00, 0x00, 0xff} +}; + +/* -------------------- Hardware specific routines ------------------------- */ +#if 0 +/* ARB Generates 100 usec delay */ +inline void __delay (unsigned long usecs) +{ + int k; + + for (k = 0; k < 1000; k++) { + asm volatile ("nop"); + } +} +#endif + +/* Wait while Graphics Engine is busy */ +inline void GfxBusyWait (volatile caddr_t board) +{ + int test; + DPRINTK("ENTER\n"); + + do { + test = vgar16 (board, ECR_GP_STAT); + asm volatile ("nop"); + } while (test & (1 << 9)); + DPRINTK("EXIT\n"); +} + +/* Wait for any of the 8 Trio32 FIFOs to be free */ +inline void GfxFifoWait (volatile caddr_t board) +{ + int test; + DPRINTK("ENTER\n"); + + do { + test = vgar16 (board, ECR_GP_STAT); + } while (test & 0x0f); + DPRINTK("EXIT\n"); +} + +/* Read Attribute Controller Register=idx */ +inline unsigned char RAttr (volatile caddr_t board, short idx) +{ + vgaw (board, ACT_ADDRESS_W, idx); + udelay(100); + /* __delay (0); */ + return (vgar (board, ACT_ADDRESS_R)); +} + +/* Read Sequencer Register=idx */ +inline unsigned char RSeq (volatile caddr_t board, short idx) +{ + vgaw (board, SEQ_ADDRESS, idx); + return (vgar (board, SEQ_ADDRESS_R)); +} + +/* Read CRT Controller Register=idx */ +inline unsigned char RCrt (volatile caddr_t board, short idx) +{ + vgaw (board, CRT_ADDRESS, idx); + return (vgar (board, CRT_ADDRESS_R)); +} + +/* Read Graphics Controller Register=idx */ +inline unsigned char RGfx (volatile caddr_t board, short idx) +{ + vgaw (board, GCT_ADDRESS, idx); + return (vgar (board, GCT_ADDRESS_R)); +} + +/* + * Special wakeup/passthrough registers on graphics boards + */ + +inline void cv64_write_port (unsigned short bits, + volatile unsigned char *board) +{ + volatile unsigned char *addr; + static unsigned char cvportbits = 0; /* Mirror port bits here */ + DPRINTK("ENTER\n"); + + addr = board + 0x40001; + if (bits & 0x8000) { + cvportbits |= bits & 0xff; /* Set bits */ + DPRINTK("Set bits: %04x\n", bits); + } else { + bits = bits & 0xff; + bits = (~bits) & 0xff; + cvportbits &= bits; /* Clear bits */ + DPRINTK("Clear bits: %04x\n", bits); + } + + *addr = cvportbits; + DPRINTK("EXIT\n"); +} + +/* + * Monitor switch on CyberVision board + * + * toggle: + * 0 = CyberVision Signal + * 1 = Amiga Signal + * board = board addr + * + */ +inline void cvscreen (int toggle, volatile unsigned char *board) +{ + DPRINTK("ENTER\n"); + if (toggle == 1) { + DPRINTK("Show Amiga video\n"); + cv64_write_port (0x10, board); + } else { + DPRINTK("Show CyberVision video\n"); + cv64_write_port (0x8010, board); + } + DPRINTK("EXIT\n"); +} + +/* Control screen display */ +/* toggle: 0 = on, 1 = off */ +/* board = registerbase */ +inline void gfx_on_off (int toggle, volatile unsigned char *board) +{ + int r; + DPRINTK("ENTER\n"); + + toggle &= 0x1; + toggle = toggle << 5; + DPRINTK("Turn display %s\n", (toggle ? "off" : "on")); + + r = (int) RSeq ((volatile caddr_t) board, SEQ_ID_CLOCKING_MODE); + r &= 0xdf; /* Set bit 5 to 0 */ + + WSeq (board, SEQ_ID_CLOCKING_MODE, r | toggle); + DPRINTK("EXIT\n"); +} + +/* + * Computes M, N, and R values from + * given input frequency. It uses a table of + * precomputed values, to keep CPU time low. + * + * The return value consist of: + * lower byte: Bits 4-0: N Divider Value + * Bits 5-6: R Value for e.g. SR10 or SR12 + * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13 + */ +static unsigned short cv64_compute_clock(unsigned long freq) +{ + static unsigned char *mnr, *save; /* M, N + R vals */ + unsigned long work_freq, r; + unsigned short erg; + long diff, d2; + + DPRINTK("ENTER\n"); + if (freq < 12500000 || freq > MAXPIXELCLOCK) { + printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n", + freq); + freq = 25000000; + } + DPRINTK("Freq = %ld\n", freq); + mnr = clocks; /* there the vals are stored */ + d2 = 0x7fffffff; + + while (*mnr) { /* mnr vals are 0-terminated */ + work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2); + + r = (mnr[1] >> 5) & 0x03; + if (r != 0) { + work_freq = work_freq >> r; /* r is the freq divider */ + } + + work_freq *= 0x3E8; /* 2nd part of OSC */ + + diff = abs(freq - work_freq); + + if (d2 >= diff) { + d2 = diff; + /* In save are the vals for minimal diff */ + save = mnr; + } + mnr += 2; + } + erg = *((unsigned short *)save); + + DPRINTK("EXIT\n"); + return (erg); +} + +static int cv_has_4mb (volatile caddr_t fb) +{ + volatile unsigned long *tr, *tw; + DPRINTK("ENTER\n"); + + /* write patterns in memory and test if they can be read */ + tw = (volatile unsigned long *) fb; + tr = (volatile unsigned long *) (fb + 0x02000000); + + *tw = 0x87654321; + + if (*tr != 0x87654321) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + /* upper memory region */ + tw = (volatile unsigned long *) (fb + 0x00200000); + tr = (volatile unsigned long *) (fb + 0x02200000); + + *tw = 0x87654321; + + if (*tr != 0x87654321) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + *tw = 0xAAAAAAAA; + + if (*tr != 0xAAAAAAAA) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + *tw = 0x55555555; + + if (*tr != 0x55555555) { + DPRINTK("EXIT - <4MB\n"); + return (0); + } + + DPRINTK("EXIT\n"); + return (1); +} + +static void cv64_board_init (void) +{ + int i; + unsigned char test; + unsigned int clockpar; + + DPRINTK("ENTER\n"); + + /* + * Special CyberVision 64 board operations + */ + /* Reset board */ + for (i = 0; i < 6; i++) { + cv64_write_port (0xff, (volatile unsigned char *) cv64_mem); + } + /* Return to operational mode */ + cv64_write_port (0x8004, (volatile unsigned char *) cv64_mem); + + /* + * Generic (?) S3 chip wakeup + */ + /* Disable I/O & memory decoders, video in setup mode */ + vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x10); + /* Video responds to cmds, addrs & data */ + vgaw (cv64_regs, SREG_OPTION_SELECT, 0x1); + /* Enable I/O & memory decoders, video in operational mode */ + vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x8); + /* VGA color emulation, enable cpu access to display mem */ + vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x03); + /* Unlock S3 VGA regs */ + WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_1, 0x48); + /* Unlock system control & extension registers */ + WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_2, 0xA5); +/* GRF - Enable interrupts */ + /* Enable enhanced regs access, Ready cntl 0 wait states */ + test = RCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG); + test = test | 0x01; /* enable enhaced register access */ + test = test & 0xEF; /* clear bit 4, 0 wait state */ + WCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG, test); + /* + * bit 0=1: Enable enhaced mode functions + * bit 2=0: Enhanced mode 8+ bits/pixel + * bit 4=1: Enable linear addressing + * bit 5=1: Enable MMIO + */ + vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, 0x31); + /* + * bit 0=1: Color emulation + * bit 1=1: Enable CPU access to display memory + * bit 5=1: Select high 64K memory page + */ +/* GRF - 0xE3 */ + vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x23); + + /* Cpu base addr */ + WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_4, 0x0); + + /* Reset. This does nothing on Trio, but standard VGA practice */ + /* WSeq (cv64_regs, SEQ_ID_RESET, 0x03); */ + /* Character clocks 8 dots wide */ + WSeq (cv64_regs, SEQ_ID_CLOCKING_MODE, 0x01); + /* Enable cpu write to all color planes */ + WSeq (cv64_regs, SEQ_ID_MAP_MASK, 0x0F); + /* Font table in 1st 8k of plane 2, font A=B disables swtich */ + WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x0); + /* Allow mem access to 256kb */ + WSeq (cv64_regs, SEQ_ID_MEMORY_MODE, 0x2); + /* Unlock S3 extensions to VGA Sequencer regs */ + WSeq (cv64_regs, SEQ_ID_UNLOCK_EXT, 0x6); + + /* Enable 4MB fast page mode */ + test = RSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL); + test = test | 1 << 6; + WSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL, test); + + /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */ + WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, 0xC0); + + /* Clear immediate clock load bit */ + test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2); + test = test & 0xDF; + /* If > 55MHz, enable 2 cycle memory write */ + if (cv64_memclk >= 55000000) { + test |= 0x80; + } + WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test); + + /* Set MCLK value */ + clockpar = cv64_compute_clock (cv64_memclk); + test = (clockpar & 0xFF00) >> 8; + WSeq (cv64_regs, SEQ_ID_MCLK_HI, test); + test = clockpar & 0xFF; + WSeq (cv64_regs, SEQ_ID_MCLK_LO, test); + + /* Chip rev specific: Not in my Trio manual!!! */ + if (RCrt (cv64_regs, CRT_ID_REVISION) == 0x10) + WSeq (cv64_regs, SEQ_ID_MORE_MAGIC, test); + + /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */ + + /* Set DCLK value */ + WSeq (cv64_regs, SEQ_ID_DCLK_HI, 0x13); + WSeq (cv64_regs, SEQ_ID_DCLK_LO, 0x41); + + /* Load DCLK (and MCLK?) immediately */ + test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2); + test = test | 0x22; + WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test); + + /* Enable loading of DCLK */ + test = vgar (cv64_regs, GREG_MISC_OUTPUT_R); + test = test | 0x0C; + vgaw (cv64_regs, GREG_MISC_OUTPUT_W, test); + + /* Turn off immediate xCLK load */ + WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, 0x2); + + /* Horizontal character clock counts */ + /* 8 LSB of 9 bits = total line - 5 */ + WCrt (cv64_regs, CRT_ID_HOR_TOTAL, 0x5F); + /* Active display line */ + WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, 0x4F); + /* Blank assertion start */ + WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, 0x50); + /* Blank assertion end */ + WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, 0x82); + /* HSYNC assertion start */ + WCrt (cv64_regs, CRT_ID_START_HOR_RETR, 0x54); + /* HSYNC assertion end */ + WCrt (cv64_regs, CRT_ID_END_HOR_RETR, 0x80); + WCrt (cv64_regs, CRT_ID_VER_TOTAL, 0xBF); + WCrt (cv64_regs, CRT_ID_OVERFLOW, 0x1F); + WCrt (cv64_regs, CRT_ID_PRESET_ROW_SCAN, 0x0); + WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE, 0x40); + WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00); + WCrt (cv64_regs, CRT_ID_CURSOR_END, 0x00); + WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00); + WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00); + WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00); + WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00); + WCrt (cv64_regs, CRT_ID_START_VER_RETR, 0x9C); + WCrt (cv64_regs, CRT_ID_END_VER_RETR, 0x0E); + WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, 0x8F); + WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, 0x50); + WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, 0x00); + WCrt (cv64_regs, CRT_ID_START_VER_BLANK, 0x96); + WCrt (cv64_regs, CRT_ID_END_VER_BLANK, 0xB9); + WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3); + WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF); + WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */ + WCrt (cv64_regs, CRT_ID_MISC_1, 0x35); + WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, 0x5A); + WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, 0x70); + WCrt (cv64_regs, CRT_ID_LAW_POS_LO, 0x40); + WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF); + + WGfx (cv64_regs, GCT_ID_SET_RESET, 0x0); + WGfx (cv64_regs, GCT_ID_ENABLE_SET_RESET, 0x0); + WGfx (cv64_regs, GCT_ID_COLOR_COMPARE, 0x0); + WGfx (cv64_regs, GCT_ID_DATA_ROTATE, 0x0); + WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x0); + WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE, 0x40); + WGfx (cv64_regs, GCT_ID_MISC, 0x01); + WGfx (cv64_regs, GCT_ID_COLOR_XCARE, 0x0F); + WGfx (cv64_regs, GCT_ID_BITMASK, 0xFF); + + /* Colors for text mode */ + for (i = 0; i < 0xf; i++) + WAttr (cv64_regs, i, i); + + WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, 0x41); + WAttr (cv64_regs, ACT_ID_OVERSCAN_COLOR, 0x01); + WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA, 0x0F); + WAttr (cv64_regs, ACT_ID_HOR_PEL_PANNING, 0x0); + WAttr (cv64_regs, ACT_ID_COLOR_SELECT, 0x0); + + vgaw (cv64_regs, VDAC_MASK, 0xFF); + + *((unsigned long *) (cv64_regs + ECR_FRGD_COLOR)) = 0xFF; + *((unsigned long *) (cv64_regs + ECR_BKGD_COLOR)) = 0; + + /* Colors initially set to grayscale */ + + vgaw (cv64_regs, VDAC_ADDRESS_W, 0); + for (i = 255; i >= 0; i--) { + vgaw (cv64_regs, VDAC_DATA, i); + vgaw (cv64_regs, VDAC_DATA, i); + vgaw (cv64_regs, VDAC_DATA, i); + } + + /* GFx hardware cursor off */ + WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00); + + /* Set first to 4MB, so test will work */ + WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13); + /* Find "correct" size of fbmem of Z3 board */ + if (cv_has_4mb ((volatile caddr_t) cv64_fbmem)) { + cv64_size = 1024 * 1024 * 4; + WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13); + DPRINTK("4MB board\n"); + } else { + cv64_size = 1024 * 1024 * 2; + WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x12); + DPRINTK("2MB board\n"); + } + + /* Initialize graphics engine */ + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x27); + vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x07); + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x1000); + udelay(200); + /* __delay (200000); */ + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x2000); + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x3FFF); + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + udelay(200); + /* __delay (200000); */ + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF); + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, ~0); + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xE000); + vgaw16 (cv64_regs, ECR_CURRENT_Y_POS2, 0x00); + vgaw16 (cv64_regs, ECR_CURRENT_X_POS2, 0x00); + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, 0x00); + vgaw16 (cv64_regs, ECR_DEST_Y2__AX_STEP2, 0x00); + vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, 0x00); + vgaw16 (cv64_regs, ECR_DEST_X2__DIA_STEP2, 0x00); + vgaw16 (cv64_regs, ECR_SHORT_STROKE, 0x00); + vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x01); + + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF); + vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x01); + vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x00); + + + /* Enable video display (set bit 5) */ +/* ARB - Would also seem to write to AR13. + * May want to use parts of WAttr to set JUST bit 5 + */ + WAttr (cv64_regs, 0x33, 0); + +/* GRF - function code ended here */ + + /* Turn gfx on again */ + gfx_on_off (0, cv64_regs); + + /* Pass-through */ + cvscreen (0, (volatile unsigned char *) cv64_mem); + + DPRINTK("EXIT\n"); +} + +static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode) +{ + int fx, fy; + unsigned short mnr; + unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT; + char LACE, DBLSCAN, TEXT, CONSOLE; + int cr50, sr15, sr18, clock_mode, test; + int m, n; + int tfillm, temptym; + int hmul; + + /* ---------------- */ + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + int bpp; + float freq_f; + long freq; + /* ---------------- */ + + DPRINTK("ENTER\n"); + TEXT = 0; /* if depth == 4 */ + CONSOLE = 0; /* mode num == 255 (console) */ + fx = fy = 8; /* force 8x8 font */ + +/* GRF - Disable interrupts */ + + gfx_on_off (1, cv64_regs); + + switch (video_mode->bits_per_pixel) { + case 15: + case 16: + hmul = 2; + break; + + default: + hmul = 1; + break; + } + + bpp = video_mode->bits_per_pixel; + xres = video_mode->xres; + hfront = video_mode->right_margin; + hsync = video_mode->hsync_len; + hback = video_mode->left_margin; + + LACE = 0; + DBLSCAN = 0; + + if (video_mode->vmode & FB_VMODE_DOUBLE) { + yres = video_mode->yres * 2; + vfront = video_mode->lower_margin * 2; + vsync = video_mode->vsync_len * 2; + vback = video_mode->upper_margin * 2; + DBLSCAN = 1; + } else if (video_mode->vmode & FB_VMODE_INTERLACED) { + yres = (video_mode->yres + 1) / 2; + vfront = (video_mode->lower_margin + 1) / 2; + vsync = (video_mode->vsync_len + 1) / 2; + vback = (video_mode->upper_margin + 1) / 2; + LACE = 1; + } else { + yres = video_mode->yres; + vfront = video_mode->lower_margin; + vsync = video_mode->vsync_len; + vback = video_mode->upper_margin; + } + + /* ARB Dropping custom setup method from cvision.c */ +#if 0 + if (cvision_custom_mode) { + HBS = hbs / 8 * hmul; + HBE = hbe / 8 * hmul; + HSS = hss / 8 * hmul; + HSE = hse / 8 * hmul; + HT = ht / 8 * hmul - 5; + + VBS = vbs - 1; + VSS = vss; + VSE = vse; + VBE = vbe; + VT = vt - 2; + } else { +#else + { +#endif + HBS = hmul * (xres / 8); + HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2); + HSS = hmul * ((xres/8) + (hfront/8) + 2); + HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1); + HT = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8)); + + VBS = yres; + VBE = yres + vfront + vsync + vback - 2; + VSS = yres + vfront - 1; + VSE = yres + vfront + vsync - 1; + VT = yres + vfront + vsync + vback - 2; + } + + vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31)); + + if (TEXT) + HDE = ((video_mode->xres + fx - 1) / fx) - 1; + else + HDE = (video_mode->xres + 3) * hmul / 8 - 1; + + VDE = video_mode->yres - 1; + + WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00); + WCrt (cv64_regs, CRT_ID_EXT_DAC_CNTL, 0x00); + + WSeq (cv64_regs, SEQ_ID_MEMORY_MODE, + (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e); + WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x00); + WSeq (cv64_regs, SEQ_ID_MAP_MASK, + (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF); + WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x00); + + /* cv64_compute_clock accepts arguments in Hz */ + /* pixclock is in ps ... convert to Hz */ + + freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000; + freq = ((long) freq_f) * 1000; + + mnr = cv64_compute_clock (freq); + WSeq (cv64_regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8)); + WSeq (cv64_regs, SEQ_ID_DCLK_LO, (mnr & 0xFF)); + + /* Load display parameters into board */ + WCrt (cv64_regs, CRT_ID_EXT_HOR_OVF, + ((HT & 0x100) ? 0x01 : 0x00) | + ((HDE & 0x100) ? 0x02 : 0x00) | + ((HBS & 0x100) ? 0x04 : 0x00) | + /* ((HBE & 0x40) ? 0x08 : 0x00) | */ + ((HSS & 0x100) ? 0x10 : 0x00) | + /* ((HSE & 0x20) ? 0x20 : 0x00) | */ + (((HT-5) & 0x100) ? 0x40 : 0x00) + ); + + WCrt (cv64_regs, CRT_ID_EXT_VER_OVF, + 0x40 | + ((VT & 0x400) ? 0x01 : 0x00) | + ((VDE & 0x400) ? 0x02 : 0x00) | + ((VBS & 0x400) ? 0x04 : 0x00) | + ((VSS & 0x400) ? 0x10 : 0x00) + ); + + WCrt (cv64_regs, CRT_ID_HOR_TOTAL, HT); + WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, HT - 5); + WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE)); + WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, HBS); + WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80)); + WCrt (cv64_regs, CRT_ID_START_HOR_RETR, HSS); + WCrt (cv64_regs, CRT_ID_END_HOR_RETR, + (HSE & 0x1F) | + ((HBE & 0x20) ? 0x80 : 0x00) + ); + WCrt (cv64_regs, CRT_ID_VER_TOTAL, VT); + WCrt (cv64_regs, CRT_ID_OVERFLOW, + 0x10 | + ((VT & 0x100) ? 0x01 : 0x00) | + ((VDE & 0x100) ? 0x02 : 0x00) | + ((VSS & 0x100) ? 0x04 : 0x00) | + ((VBS & 0x100) ? 0x08 : 0x00) | + ((VT & 0x200) ? 0x20 : 0x00) | + ((VDE & 0x200) ? 0x40 : 0x00) | + ((VSS & 0x200) ? 0x80 : 0x00) + ); + WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE, + 0x40 | + (DBLSCAN ? 0x80 : 0x00) | + ((VBS & 0x200) ? 0x20 : 0x00) | + (TEXT ? ((fy - 1) & 0x1F) : 0x00) + ); + + WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3); + + /* Text cursor */ + + if (TEXT) { +#if 1 + WCrt (cv64_regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2); + WCrt (cv64_regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1); +#else + WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00); + WCrt (cv64_regs, CRT_ID_CURSOR_END, fy & 0x1F); +#endif + WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F); + WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00); + WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00); + } + + WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00); + WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00); + WCrt (cv64_regs, CRT_ID_START_VER_RETR, VSS); + WCrt (cv64_regs, CRT_ID_END_VER_RETR, (VSE & 0x0F)); + WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, VDE); + WCrt (cv64_regs, CRT_ID_START_VER_BLANK, VBS); + WCrt (cv64_regs, CRT_ID_END_VER_BLANK, VBE); + WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF); + WCrt (cv64_regs, CRT_ID_LACE_RETR_START, HT / 2); + WCrt (cv64_regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00)); + WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE, + ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40)); + WGfx (cv64_regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01)); + WSeq (cv64_regs, SEQ_ID_MEMORY_MODE, + ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02)); + + vgaw (cv64_regs, VDAC_MASK, 0xFF); + + /* Blank border */ + test = RCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2); + WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20)); + + sr15 = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2); + sr15 &= 0xEF; + sr18 = RSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL); + sr18 &= 0x7F; + clock_mode = 0x00; + cr50 = 0x00; + + test = RCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2); + test &= 0xD; + + /* Clear roxxler byte-swapping... */ + cv64_write_port (0x0040, (volatile unsigned char *) cv64_mem); + cv64_write_port (0x0020, (volatile unsigned char *) cv64_mem); + + switch (video_mode->bits_per_pixel) { + case 1: + case 4: /* text */ + HDE = video_mode->xres / 16; + break; + + case 8: + if (freq > 80000000) { + clock_mode = 0x10 | 0x02; + sr15 |= 0x10; + sr18 |= 0x80; + } + HDE = video_mode->xres / 8; + cr50 |= 0x00; + break; + + case 15: + cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem); + clock_mode = 0x30; + HDE = video_mode->xres / 4; + cr50 |= 0x10; + break; + + case 16: + cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem); + clock_mode = 0x50; + HDE = video_mode->xres / 4; + cr50 |= 0x10; + break; + + case 24: + case 32: + cv64_write_port (0x8040, (volatile unsigned char *) cv64_mem); + clock_mode = 0xD0; + HDE = video_mode->xres / 2; + cr50 |= 0x30; + break; + } + + WCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test); + WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, sr15); + WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, sr18); + WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, HDE); + + WCrt (cv64_regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35)); + + test = RCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2); + test &= ~0x30; + test |= (HDE >> 4) & 0x30; + WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2, test); + + /* Set up graphics engine */ + switch (video_mode->xres) { + case 1024: + cr50 |= 0x00; + break; + + case 640: + cr50 |= 0x40; + break; + + case 800: + cr50 |= 0x80; + break; + + case 1280: + cr50 |= 0xC0; + break; + + case 1152: + cr50 |= 0x01; + break; + + case 1600: + cr50 |= 0x81; + break; + + default: /* XXX */ + break; + } + + WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_1, cr50); + + udelay(100); + /* __delay (100000); */ + WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41)); + udelay(100); + /* __delay (100000); */ + WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA, + (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F); + udelay(100); + /* __delay (100000); */ + + tfillm = (96 * (cv64_memclk / 1000)) / 240000; + + switch (video_mode->bits_per_pixel) { + case 32: + case 24: + temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000); + break; + case 15: + case 16: + temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000); + break; + case 4: + temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000); + break; + default: + temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000); + break; + } + + m = (temptym - tfillm - 9) / 2; + if (m < 0) + m = 0; + m = (m & 0x1F) << 3; + if (m < 0x18) + m = 0x18; + n = 0xFF; + + WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, m); + WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, n); + udelay(10); + /* __delay (10000); */ + + /* Text initialization */ + + if (TEXT) { + /* Do text initialization here ! */ + } + + if (CONSOLE) { + int i; + vgaw (cv64_regs, VDAC_ADDRESS_W, 0); + for (i = 0; i < 4; i++) { + vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][0]); + vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][1]); + vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][2]); + } + } + + WAttr (cv64_regs, 0x33, 0); + + /* Turn gfx on again */ + gfx_on_off (0, (volatile unsigned char *) cv64_regs); + + /* Pass-through */ + cvscreen (0, (volatile unsigned char *) cv64_mem); + +DPRINTK("EXIT\n"); +} + +void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy, + u_short w, u_short h) +{ + unsigned short drawdir = 0; + + DPRINTK("ENTER\n"); + if (sx > dx) { + drawdir |= 1 << 5; + } else { + sx += w - 1; + dx += w - 1; + } + + if (sy > dy) { + drawdir |= 1 << 7; + } else { + sy += h - 1; + dy += h - 1; + } + + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x7); + vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x67); + vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x0); + vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x1); + vgaw16 (cv64_regs, ECR_BITPLANE_READ_MASK, 0x1); + vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, 0xFFF); + vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, sy); + vgaw16 (cv64_regs, ECR_CURRENT_X_POS, sx); + vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, dy); + vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, dx); + vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1); + vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1); + vgaw16 (cv64_regs, ECR_DRAW_CMD, 0xC051 | drawdir); + DPRINTK("EXIT\n"); +} + +void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg) +{ + DPRINTK("ENTER\n"); + Cyber_WaitBlit(); + /* GfxBusyWait (cv64_regs); */ + vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x0027); + vgaw16 (cv64_regs, ECR_FRGD_COLOR, bg); + vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000); + vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, dy); + vgaw16 (cv64_regs, ECR_CURRENT_X_POS, dx); + vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1); + vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1); + vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x40B1); + DPRINTK("EXIT\n"); +} + +#ifdef CYBERFBDEBUG +/* + * Dump internal settings of CyberVision board + */ +static void cv64_dump (void) +{ + DPRINTK("ENTER\n"); + /* Dump the VGA setup values */ + *(CyberRegs + S3_CRTC_ADR) = 0x00; + DPRINTK("CR00 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x01; + DPRINTK("CR01 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x02; + DPRINTK("CR02 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x03; + DPRINTK("CR03 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x04; + DPRINTK("CR04 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x05; + DPRINTK("CR05 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x06; + DPRINTK("CR06 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x07; + DPRINTK("CR07 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x08; + DPRINTK("CR08 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x09; + DPRINTK("CR09 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x10; + DPRINTK("CR10 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x11; + DPRINTK("CR11 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x12; + DPRINTK("CR12 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x13; + DPRINTK("CR13 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x15; + DPRINTK("CR15 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x16; + DPRINTK("CR16 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x36; + DPRINTK("CR36 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x37; + DPRINTK("CR37 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x42; + DPRINTK("CR42 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x43; + DPRINTK("CR43 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x50; + DPRINTK("CR50 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x51; + DPRINTK("CR51 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x53; + DPRINTK("CR53 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x58; + DPRINTK("CR58 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x59; + DPRINTK("CR59 = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x5A; + DPRINTK("CR5A = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x5D; + DPRINTK("CR5D = %x\n", *(CyberRegs + S3_CRTC_DATA)); + *(CyberRegs + S3_CRTC_ADR) = 0x5E; + DPRINTK("CR5E = %x\n", *(CyberRegs + S3_CRTC_DATA)); + DPRINTK("MISC = %x\n", *(CyberRegs + GREG_MISC_OUTPUT_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x01; + DPRINTK("SR01 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x02; + DPRINTK("SR02 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x03; + DPRINTK("SR03 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x09; + DPRINTK("SR09 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x10; + DPRINTK("SR10 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x11; + DPRINTK("SR11 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x12; + DPRINTK("SR12 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x13; + DPRINTK("SR13 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + *(CyberRegs + SEQ_ADDRESS) = 0x15; + DPRINTK("SR15 = %x\n", *(CyberRegs + SEQ_ADDRESS_R)); + + return; +} +#endif diff --git a/drivers/video/cyberfb.h b/drivers/video/cyberfb.h new file mode 100644 index 000000000..232bc6857 --- /dev/null +++ b/drivers/video/cyberfb.h @@ -0,0 +1,444 @@ +/* + * linux/arch/m68k/console/cvision.h -- CyberVision64 definitions for the + * text console driver. + * + * Copyright (c) 1998 Alan Bair + * + * This file is based on the initial port to Linux of grf_cvreg.h: + * + * Copyright (c) 1997 Antonio Santos + * + * The original work is from the NetBSD CyberVision 64 framebuffer driver + * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c): + * Permission to use the source of this driver was obtained from the + * author Michael Teske by Alan Bair. + * + * Copyright (c) 1995 Michael Teske + * + * History: + * + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* s3 commands */ +#define S3_BITBLT 0xc011 +#define S3_TWOPOINTLINE 0x2811 +#define S3_FILLEDRECT 0x40b1 + +#define S3_FIFO_EMPTY 0x0400 +#define S3_HDW_BUSY 0x0200 + +/* Enhanced register mapping (MMIO mode) */ + +#define S3_READ_SEL 0xbee8 /* offset f */ +#define S3_MULT_MISC 0xbee8 /* offset e */ +#define S3_ERR_TERM 0x92e8 +#define S3_FRGD_COLOR 0xa6e8 +#define S3_BKGD_COLOR 0xa2e8 +#define S3_PIXEL_CNTL 0xbee8 /* offset a */ +#define S3_FRGD_MIX 0xbae8 +#define S3_BKGD_MIX 0xb6e8 +#define S3_CUR_Y 0x82e8 +#define S3_CUR_X 0x86e8 +#define S3_DESTY_AXSTP 0x8ae8 +#define S3_DESTX_DIASTP 0x8ee8 +#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ +#define S3_MAJ_AXIS_PCNT 0x96e8 +#define S3_CMD 0x9ae8 +#define S3_GP_STAT 0x9ae8 +#define S3_ADVFUNC_CNTL 0x4ae8 +#define S3_WRT_MASK 0xaae8 +#define S3_RD_MASK 0xaee8 + +/* Enhanced register mapping (Packed MMIO mode, write only) */ +#define S3_ALT_CURXY 0x8100 +#define S3_ALT_CURXY2 0x8104 +#define S3_ALT_STEP 0x8108 +#define S3_ALT_STEP2 0x810c +#define S3_ALT_ERR 0x8110 +#define S3_ALT_CMD 0x8118 +#define S3_ALT_MIX 0x8134 +#define S3_ALT_PCNT 0x8148 +#define S3_ALT_PAT 0x8168 + +/* Drawing modes */ +#define S3_NOTCUR 0x0000 +#define S3_LOGICALZERO 0x0001 +#define S3_LOGICALONE 0x0002 +#define S3_LEAVEASIS 0x0003 +#define S3_NOTNEW 0x0004 +#define S3_CURXORNEW 0x0005 +#define S3_NOT_CURXORNEW 0x0006 +#define S3_NEW 0x0007 +#define S3_NOTCURORNOTNEW 0x0008 +#define S3_CURORNOTNEW 0x0009 +#define S3_NOTCURORNEW 0x000a +#define S3_CURORNEW 0x000b +#define S3_CURANDNEW 0x000c +#define S3_NOTCURANDNEW 0x000d +#define S3_CURANDNOTNEW 0x000e +#define S3_NOTCURANDNOTNEW 0x000f + +#define S3_CRTC_ADR 0x03d4 +#define S3_CRTC_DATA 0x03d5 + +#define S3_REG_LOCK2 0x39 +#define S3_HGC_MODE 0x45 + +#define S3_HWGC_ORGX_H 0x46 +#define S3_HWGC_ORGX_L 0x47 +#define S3_HWGC_ORGY_H 0x48 +#define S3_HWGC_ORGY_L 0x49 +#define S3_HWGC_DX 0x4e +#define S3_HWGC_DY 0x4f + +#define S3_LAW_CTL 0x58 + +/**************************************************/ + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif /* !min */ + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif /* !max */ + +/* support for a BitBlt operation. The op-codes are identical + to X11 GCs */ +#define GRFBBOPclear 0x0 /* 0 */ +#define GRFBBOPand 0x1 /* src AND dst */ +#define GRFBBOPandReverse 0x2 /* src AND NOT dst */ +#define GRFBBOPcopy 0x3 /* src */ +#define GRFBBOPandInverted 0x4 /* NOT src AND dst */ +#define GRFBBOPnoop 0x5 /* dst */ +#define GRFBBOPxor 0x6 /* src XOR dst */ +#define GRFBBOPor 0x7 /* src OR dst */ +#define GRFBBOPnor 0x8 /* NOT src AND NOT dst */ +#define GRFBBOPequiv 0x9 /* NOT src XOR dst */ +#define GRFBBOPinvert 0xa /* NOT dst */ +#define GRFBBOPorReverse 0xb /* src OR NOT dst */ +#define GRFBBOPcopyInverted 0xc /* NOT src */ +#define GRFBBOPorInverted 0xd /* NOT src OR dst */ +#define GRFBBOPnand 0xe /* NOT src OR NOT dst */ +#define GRFBBOPset 0xf /* 1 */ + + +/* Read VGA register */ +#define vgar(ba, reg) (*(((volatile caddr_t)ba)+reg)) + +/* Write VGA register */ +#define vgaw(ba, reg, val) \ +*(((volatile caddr_t)ba)+reg) = ((val) & 0xff) + +/* Read 16 Bit VGA register */ +#define vgar16(ba, reg) ( *((unsigned short *) (((volatile caddr_t)ba)+reg)) ) + +/* Write 16 Bit VGA register */ +#define vgaw16(ba, reg, val) \ +*((unsigned short *) (((volatile caddr_t)ba)+reg)) = val + +/* Read 32 Bit VGA register */ +#define vgar32(ba, reg) ( *((unsigned long *) (((volatile caddr_t)ba)+reg)) ) + +/* Write 32 Bit VGA register */ +#define vgaw32(ba, reg, val) \ + *((unsigned long *) (((volatile caddr_t)ba)+reg)) = val + +/* + * Defines for the used register addresses (mw) + * + * NOTE: There are some registers that have different addresses when + * in mono or color mode. We only support color mode, and thus + * some addresses won't work in mono-mode! + * + * General and VGA-registers taken from retina driver. Fixed a few + * bugs in it. (SR and GR read address is Port + 1, NOT Port) + * + */ + +/* General Registers: */ +#define GREG_MISC_OUTPUT_R 0x03CC +#define GREG_MISC_OUTPUT_W 0x03C2 +#define GREG_FEATURE_CONTROL_R 0x03CA +#define GREG_FEATURE_CONTROL_W 0x03DA +#define GREG_INPUT_STATUS0_R 0x03C2 +#define GREG_INPUT_STATUS1_R 0x03DA + +/* Setup Registers: */ +#define SREG_OPTION_SELECT 0x0102 +#define SREG_VIDEO_SUBS_ENABLE 0x46E8 + +/* Attribute Controller: */ +#define ACT_ADDRESS 0x03C0 +#define ACT_ADDRESS_R 0x03C1 +#define ACT_ADDRESS_W 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_ID_PALETTE0 0x00 +#define ACT_ID_PALETTE1 0x01 +#define ACT_ID_PALETTE2 0x02 +#define ACT_ID_PALETTE3 0x03 +#define ACT_ID_PALETTE4 0x04 +#define ACT_ID_PALETTE5 0x05 +#define ACT_ID_PALETTE6 0x06 +#define ACT_ID_PALETTE7 0x07 +#define ACT_ID_PALETTE8 0x08 +#define ACT_ID_PALETTE9 0x09 +#define ACT_ID_PALETTE10 0x0A +#define ACT_ID_PALETTE11 0x0B +#define ACT_ID_PALETTE12 0x0C +#define ACT_ID_PALETTE13 0x0D +#define ACT_ID_PALETTE14 0x0E +#define ACT_ID_PALETTE15 0x0F +#define ACT_ID_ATTR_MODE_CNTL 0x10 +#define ACT_ID_OVERSCAN_COLOR 0x11 +#define ACT_ID_COLOR_PLANE_ENA 0x12 +#define ACT_ID_HOR_PEL_PANNING 0x13 +#define ACT_ID_COLOR_SELECT 0x14 + +/* Graphics Controller: */ +#define GCT_ADDRESS 0x03CE +#define GCT_ADDRESS_R 0x03CF +#define GCT_ADDRESS_W 0x03CF +#define GCT_ID_SET_RESET 0x00 +#define GCT_ID_ENABLE_SET_RESET 0x01 +#define GCT_ID_COLOR_COMPARE 0x02 +#define GCT_ID_DATA_ROTATE 0x03 +#define GCT_ID_READ_MAP_SELECT 0x04 +#define GCT_ID_GRAPHICS_MODE 0x05 +#define GCT_ID_MISC 0x06 +#define GCT_ID_COLOR_XCARE 0x07 +#define GCT_ID_BITMASK 0x08 + +/* Sequencer: */ +#define SEQ_ADDRESS 0x03C4 +#define SEQ_ADDRESS_R 0x03C5 +#define SEQ_ADDRESS_W 0x03C5 +#define SEQ_ID_RESET 0x00 +#define SEQ_ID_CLOCKING_MODE 0x01 +#define SEQ_ID_MAP_MASK 0x02 +#define SEQ_ID_CHAR_MAP_SELECT 0x03 +#define SEQ_ID_MEMORY_MODE 0x04 +#define SEQ_ID_UNKNOWN1 0x05 +#define SEQ_ID_UNKNOWN2 0x06 +#define SEQ_ID_UNKNOWN3 0x07 +/* S3 extensions */ +#define SEQ_ID_UNLOCK_EXT 0x08 +#define SEQ_ID_EXT_SEQ_REG9 0x09 +#define SEQ_ID_BUS_REQ_CNTL 0x0A +#define SEQ_ID_EXT_MISC_SEQ 0x0B +#define SEQ_ID_UNKNOWN4 0x0C +#define SEQ_ID_EXT_SEQ 0x0D +#define SEQ_ID_UNKNOWN5 0x0E +#define SEQ_ID_UNKNOWN6 0x0F +#define SEQ_ID_MCLK_LO 0x10 +#define SEQ_ID_MCLK_HI 0x11 +#define SEQ_ID_DCLK_LO 0x12 +#define SEQ_ID_DCLK_HI 0x13 +#define SEQ_ID_CLKSYN_CNTL_1 0x14 +#define SEQ_ID_CLKSYN_CNTL_2 0x15 +#define SEQ_ID_CLKSYN_TEST_HI 0x16 /* reserved for S3 testing of the */ +#define SEQ_ID_CLKSYN_TEST_LO 0x17 /* internal clock synthesizer */ +#define SEQ_ID_RAMDAC_CNTL 0x18 +#define SEQ_ID_MORE_MAGIC 0x1A + +/* CRT Controller: */ +#define CRT_ADDRESS 0x03D4 +#define CRT_ADDRESS_R 0x03D5 +#define CRT_ADDRESS_W 0x03D5 +#define CRT_ID_HOR_TOTAL 0x00 +#define CRT_ID_HOR_DISP_ENA_END 0x01 +#define CRT_ID_START_HOR_BLANK 0x02 +#define CRT_ID_END_HOR_BLANK 0x03 +#define CRT_ID_START_HOR_RETR 0x04 +#define CRT_ID_END_HOR_RETR 0x05 +#define CRT_ID_VER_TOTAL 0x06 +#define CRT_ID_OVERFLOW 0x07 +#define CRT_ID_PRESET_ROW_SCAN 0x08 +#define CRT_ID_MAX_SCAN_LINE 0x09 +#define CRT_ID_CURSOR_START 0x0A +#define CRT_ID_CURSOR_END 0x0B +#define CRT_ID_START_ADDR_HIGH 0x0C +#define CRT_ID_START_ADDR_LOW 0x0D +#define CRT_ID_CURSOR_LOC_HIGH 0x0E +#define CRT_ID_CURSOR_LOC_LOW 0x0F +#define CRT_ID_START_VER_RETR 0x10 +#define CRT_ID_END_VER_RETR 0x11 +#define CRT_ID_VER_DISP_ENA_END 0x12 +#define CRT_ID_SCREEN_OFFSET 0x13 +#define CRT_ID_UNDERLINE_LOC 0x14 +#define CRT_ID_START_VER_BLANK 0x15 +#define CRT_ID_END_VER_BLANK 0x16 +#define CRT_ID_MODE_CONTROL 0x17 +#define CRT_ID_LINE_COMPARE 0x18 +#define CRT_ID_GD_LATCH_RBACK 0x22 +#define CRT_ID_ACT_TOGGLE_RBACK 0x24 +#define CRT_ID_ACT_INDEX_RBACK 0x26 +/* S3 extensions: S3 VGA Registers */ +#define CRT_ID_DEVICE_HIGH 0x2D +#define CRT_ID_DEVICE_LOW 0x2E +#define CRT_ID_REVISION 0x2F +#define CRT_ID_CHIP_ID_REV 0x30 +#define CRT_ID_MEMORY_CONF 0x31 +#define CRT_ID_BACKWAD_COMP_1 0x32 +#define CRT_ID_BACKWAD_COMP_2 0x33 +#define CRT_ID_BACKWAD_COMP_3 0x34 +#define CRT_ID_REGISTER_LOCK 0x35 +#define CRT_ID_CONFIG_1 0x36 +#define CRT_ID_CONFIG_2 0x37 +#define CRT_ID_REGISTER_LOCK_1 0x38 +#define CRT_ID_REGISTER_LOCK_2 0x39 +#define CRT_ID_MISC_1 0x3A +#define CRT_ID_DISPLAY_FIFO 0x3B +#define CRT_ID_LACE_RETR_START 0x3C +/* S3 extensions: System Control Registers */ +#define CRT_ID_SYSTEM_CONFIG 0x40 +#define CRT_ID_BIOS_FLAG 0x41 +#define CRT_ID_LACE_CONTROL 0x42 +#define CRT_ID_EXT_MODE 0x43 +#define CRT_ID_HWGC_MODE 0x45 /* HWGC = Hardware Graphics Cursor */ +#define CRT_ID_HWGC_ORIGIN_X_HI 0x46 +#define CRT_ID_HWGC_ORIGIN_X_LO 0x47 +#define CRT_ID_HWGC_ORIGIN_Y_HI 0x48 +#define CRT_ID_HWGC_ORIGIN_Y_LO 0x49 +#define CRT_ID_HWGC_FG_STACK 0x4A +#define CRT_ID_HWGC_BG_STACK 0x4B +#define CRT_ID_HWGC_START_AD_HI 0x4C +#define CRT_ID_HWGC_START_AD_LO 0x4D +#define CRT_ID_HWGC_DSTART_X 0x4E +#define CRT_ID_HWGC_DSTART_Y 0x4F +/* S3 extensions: System Extension Registers */ +#define CRT_ID_EXT_SYS_CNTL_1 0x50 +#define CRT_ID_EXT_SYS_CNTL_2 0x51 +#define CRT_ID_EXT_BIOS_FLAG_1 0x52 +#define CRT_ID_EXT_MEM_CNTL_1 0x53 +#define CRT_ID_EXT_MEM_CNTL_2 0x54 +#define CRT_ID_EXT_DAC_CNTL 0x55 +#define CRT_ID_EX_SYNC_1 0x56 +#define CRT_ID_EX_SYNC_2 0x57 +#define CRT_ID_LAW_CNTL 0x58 /* LAW = Linear Address Window */ +#define CRT_ID_LAW_POS_HI 0x59 +#define CRT_ID_LAW_POS_LO 0x5A +#define CRT_ID_GOUT_PORT 0x5C +#define CRT_ID_EXT_HOR_OVF 0x5D +#define CRT_ID_EXT_VER_OVF 0x5E +#define CRT_ID_EXT_MEM_CNTL_3 0x60 +#define CRT_ID_EX_SYNC_3 0x63 +#define CRT_ID_EXT_MISC_CNTL 0x65 +#define CRT_ID_EXT_MISC_CNTL_1 0x66 +#define CRT_ID_EXT_MISC_CNTL_2 0x67 +#define CRT_ID_CONFIG_3 0x68 +#define CRT_ID_EXT_SYS_CNTL_3 0x69 +#define CRT_ID_EXT_SYS_CNTL_4 0x6A +#define CRT_ID_EXT_BIOS_FLAG_3 0x6B +#define CRT_ID_EXT_BIOS_FLAG_4 0x6C + +/* Enhanced Commands Registers: */ +#define ECR_SUBSYSTEM_STAT 0x42E8 +#define ECR_SUBSYSTEM_CNTL 0x42E8 +#define ECR_ADV_FUNC_CNTL 0x4AE8 +#define ECR_CURRENT_Y_POS 0x82E8 +#define ECR_CURRENT_Y_POS2 0x82EA /* Trio64 only */ +#define ECR_CURRENT_X_POS 0x86E8 +#define ECR_CURRENT_X_POS2 0x86EA /* Trio64 only */ +#define ECR_DEST_Y__AX_STEP 0x8AE8 +#define ECR_DEST_Y2__AX_STEP2 0x8AEA /* Trio64 only */ +#define ECR_DEST_X__DIA_STEP 0x8EE8 +#define ECR_DEST_X2__DIA_STEP2 0x8EEA /* Trio64 only */ +#define ECR_ERR_TERM 0x92E8 +#define ECR_ERR_TERM2 0x92EA /* Trio64 only */ +#define ECR_MAJ_AXIS_PIX_CNT 0x96E8 +#define ECR_MAJ_AXIS_PIX_CNT2 0x96EA /* Trio64 only */ +#define ECR_GP_STAT 0x9AE8 /* GP = Graphics Processor */ +#define ECR_DRAW_CMD 0x9AE8 +#define ECR_DRAW_CMD2 0x9AEA /* Trio64 only */ +#define ECR_SHORT_STROKE 0x9EE8 +#define ECR_BKGD_COLOR 0xA2E8 /* BKGD = Background */ +#define ECR_FRGD_COLOR 0xA6E8 /* FRGD = Foreground */ +#define ECR_BITPLANE_WRITE_MASK 0xAAE8 +#define ECR_BITPLANE_READ_MASK 0xAEE8 +#define ECR_COLOR_COMPARE 0xB2E8 +#define ECR_BKGD_MIX 0xB6E8 +#define ECR_FRGD_MIX 0xBAE8 +#define ECR_READ_REG_DATA 0xBEE8 +#define ECR_ID_MIN_AXIS_PIX_CNT 0x00 +#define ECR_ID_SCISSORS_TOP 0x01 +#define ECR_ID_SCISSORS_LEFT 0x02 +#define ECR_ID_SCISSORS_BUTTOM 0x03 +#define ECR_ID_SCISSORS_RIGHT 0x04 +#define ECR_ID_PIX_CNTL 0x0A +#define ECR_ID_MULT_CNTL_MISC_2 0x0D +#define ECR_ID_MULT_CNTL_MISC 0x0E +#define ECR_ID_READ_SEL 0x0F +#define ECR_PIX_TRANS 0xE2E8 +#define ECR_PIX_TRANS_EXT 0xE2EA +#define ECR_PATTERN_Y 0xEAE8 /* Trio64 only */ +#define ECR_PATTERN_X 0xEAEA /* Trio64 only */ + + +/* Pass-through */ +#define PASS_ADDRESS 0x40001 +#define PASS_ADDRESS_W 0x40001 + +/* Video DAC */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + + +#define WGfx(ba, idx, val) \ +do { vgaw(ba, GCT_ADDRESS, idx); vgaw(ba, GCT_ADDRESS_W , val); } while (0) + +#define WSeq(ba, idx, val) \ +do { vgaw(ba, SEQ_ADDRESS, idx); vgaw(ba, SEQ_ADDRESS_W , val); } while (0) + +#define WCrt(ba, idx, val) \ +do { vgaw(ba, CRT_ADDRESS, idx); vgaw(ba, CRT_ADDRESS_W , val); } while (0) + +#define WAttr(ba, idx, val) \ +do { \ + unsigned char tmp;\ + tmp = vgar(ba, ACT_ADDRESS_RESET);\ + vgaw(ba, ACT_ADDRESS_W, idx);\ + vgaw(ba, ACT_ADDRESS_W, val);\ +} while (0) + +#define SetTextPlane(ba, m) \ +do { \ + WGfx(ba, GCT_ID_READ_MAP_SELECT, m & 3 );\ + WSeq(ba, SEQ_ID_MAP_MASK, (1 << (m & 3)));\ +} while (0) + + /* --------------------------------- */ + /* prototypes */ + /* --------------------------------- */ + +/* in cvision_core.c */ +inline void __delay(unsigned long usecs); +inline void GfxBusyWait(volatile caddr_t board); +inline void GfxFifoWait(volatile caddr_t board); +inline unsigned char RAttr(volatile caddr_t board, short idx); +inline unsigned char RSeq(volatile caddr_t board, short idx); +inline unsigned char RCrt(volatile caddr_t board, short idx); +inline unsigned char RGfx(volatile caddr_t board, short idx); +inline void cv64_write_port(unsigned short bits, + volatile unsigned char *board); +inline void cvscreen(int toggle, volatile unsigned char *board); +inline void gfx_on_off(int toggle, volatile unsigned char *board); +#if 0 +unsigned short cv64_compute_clock(unsigned long freq); +int cv_has_4mb(volatile caddr_t fb); +void cv64_board_init(void); +void cv64_load_video_mode(struct fb_var_screeninfo *video_mode); +#endif + +void cvision_bitblt(u_short sx, u_short sy, u_short dx, u_short dy, u_short w, + u_short h); +void cvision_clear(u_short dx, u_short dy, u_short w, u_short h, u_short bg); diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 906554641..e0da396bf 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -14,7 +14,7 @@ #include <linux/fb.h> #include <linux/module.h> -#include "fbcon-mfb.h" +#include <video/fbcon-mfb.h> /* apollo video HW definitions */ @@ -306,7 +306,7 @@ static void dnfb_set_disp(int con, struct fb_info *info) #ifdef FBCON_HAS_MFB disp[con].dispsw = &fbcon_mfb; #else - disp[con].dispsw = NULL; + disp[con].dispsw = &fbcon_dummy; #endif } @@ -321,6 +321,7 @@ void dnfb_init(void) fb_info.blank=&dnfbcon_blank; fb_info.node = -1; fb_info.fbops = &dnfb_ops; + fb_info.flags = FBINFO_FLAG_DEFAULT; outb(RESET_CREG, AP_CONTROL_3A); outw(0x0, AP_WRITE_ENABLE); diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index d3e339e4f..5f1780bd8 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -31,10 +31,6 @@ static void memcpy_fs(int fsfromto, void *to, void *from, int len) } } -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) -#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ - ((1<<(width))-1)) : 0)) - static u16 red2[] = { 0x0000, 0xaaaa }; @@ -163,9 +159,10 @@ void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) * Get the colormap for a screen */ -int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, +int fb_get_cmap(struct fb_cmap *cmap, int kspc, int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *, - struct fb_info *), struct fb_info *info) + struct fb_info *), + struct fb_info *info) { int i, start; u16 *red, *green, *blue, *transp; @@ -181,10 +178,6 @@ int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, for (i = 0; i < cmap->len; i++) { if (getcolreg(start++, &hred, &hgreen, &hblue, &htransp, info)) return 0; - hred = CNVT_FROMHW(hred, var->red.length); - hgreen = CNVT_FROMHW(hgreen, var->green.length); - hblue = CNVT_FROMHW(hblue, var->blue.length); - htransp = CNVT_FROMHW(htransp, var->transp.length); if (kspc) { *red = hred; *green = hgreen; @@ -212,9 +205,10 @@ int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, * Set the colormap for a screen */ -int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, +int fb_set_cmap(struct fb_cmap *cmap, int kspc, int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, - struct fb_info *), struct fb_info *info) + struct fb_info *), + struct fb_info *info) { int i, start; u16 *red, *green, *blue, *transp; @@ -243,10 +237,6 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, else htransp = 0; } - hred = CNVT_TOHW(hred, var->red.length); - hgreen = CNVT_TOHW(hgreen, var->green.length); - hblue = CNVT_TOHW(hblue, var->blue.length); - htransp = CNVT_TOHW(htransp, var->transp.length); red++; green++; blue++; diff --git a/drivers/video/fbcon-afb.c b/drivers/video/fbcon-afb.c index a8c01d6a0..205c1347d 100644 --- a/drivers/video/fbcon-afb.c +++ b/drivers/video/fbcon-afb.c @@ -15,8 +15,8 @@ #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-afb.h" +#include <video/fbcon.h> +#include <video/fbcon-afb.h> /* @@ -174,22 +174,22 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx, u_short i, j; if (sx == 0 && dx == 0 && width == p->next_line) { - src = p->screen_base+sy*p->fontheight*width; - dest = p->screen_base+dy*p->fontheight*width; + src = p->screen_base+sy*fontheight(p)*width; + dest = p->screen_base+dy*fontheight(p)*width; i = p->var.bits_per_pixel; do { - mymemmove(dest, src, height*p->fontheight*width); + mymemmove(dest, src, height*fontheight(p)*width); src += p->next_plane; dest += p->next_plane; } while (--i); } else if (dy <= sy) { - src0 = p->screen_base+sy*p->fontheight*p->next_line+sx; - dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx; + src0 = p->screen_base+sy*fontheight(p)*p->next_line+sx; + dest0 = p->screen_base+dy*fontheight(p)*p->next_line+dx; i = p->var.bits_per_pixel; do { src = src0; dest = dest0; - j = height*p->fontheight; + j = height*fontheight(p); do { mymemmove(dest, src, width); src += p->next_line; @@ -199,13 +199,13 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx, dest0 += p->next_plane; } while (--i); } else { - src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; - dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; + src0 = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx; + dest0 = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx; i = p->var.bits_per_pixel; do { src = src0; dest = dest0; - j = height*p->fontheight; + j = height*fontheight(p); do { src -= p->next_line; dest -= p->next_line; @@ -224,13 +224,13 @@ void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx, u_short i, j; int bg; - dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest0 = p->screen_base+sy*fontheight(p)*p->next_line+sx; bg = attr_bgcol_ec(p,conp); i = p->var.bits_per_pixel; do { dest = dest0; - j = height*p->fontheight; + j = height*fontheight(p); do { if (bg & 1) mymemset(dest, width); @@ -250,8 +250,8 @@ void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy, u_short i, j; int fg, bg; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat0 = p->fontdata+(c&p->charmask)*p->fontheight; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; + cdat0 = p->fontdata+(c&p->charmask)*fontheight(p); fg = attr_fgcol(p,c); bg = attr_bgcol(p,c); @@ -264,7 +264,7 @@ void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy, expand += 512; if (fg & 1) expand += 256; - j = p->fontheight; + j = fontheight(p); do { *dest = expand[*cdat++]; dest += p->next_line; @@ -289,7 +289,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, u16 c1, c2, c3, c4; int fg0, bg0, fg, bg; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; fg0 = attr_fgcol(p,*s); bg0 = attr_bgcol(p,*s); @@ -299,7 +299,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, dest1 = dest0++; xx++; - cdat10 = p->fontdata+c1*p->fontheight; + cdat10 = p->fontdata+c1*fontheight(p); fg = fg0; bg = bg0; @@ -312,7 +312,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, expand += 512; if (fg & 1) expand += 256; - j = p->fontheight; + j = fontheight(p); do { *dest = expand[*cdat1++]; dest += p->next_line; @@ -328,10 +328,10 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, c4 = s[3] & p->charmask; dest1 = dest0; - cdat10 = p->fontdata+c1*p->fontheight; - cdat20 = p->fontdata+c2*p->fontheight; - cdat30 = p->fontdata+c3*p->fontheight; - cdat40 = p->fontdata+c4*p->fontheight; + cdat10 = p->fontdata+c1*fontheight(p); + cdat20 = p->fontdata+c2*fontheight(p); + cdat30 = p->fontdata+c3*fontheight(p); + cdat40 = p->fontdata+c4*fontheight(p); fg = fg0; bg = bg0; @@ -347,7 +347,7 @@ void fbcon_afb_putcs(struct vc_data *conp, struct display *p, expand += 512; if (fg & 1) expand += 256; - j = p->fontheight; + j = fontheight(p); do { #if defined(__BIG_ENDIAN) *(u32 *)dest = expand[*cdat1++]<<24 | @@ -381,7 +381,7 @@ void fbcon_afb_revc(struct display *p, int xx, int yy) u_short i, j; int mask; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; mask = p->fgcol ^ p->bgcol; /* @@ -394,7 +394,7 @@ void fbcon_afb_revc(struct display *p, int xx, int yy) do { if (mask & 1) { dest = dest0; - j = p->fontheight; + j = fontheight(p); do { *dest = ~*dest; dest += p->next_line; diff --git a/drivers/video/fbcon-afb.h b/drivers/video/fbcon-afb.h deleted file mode 100644 index c82d98c41..000000000 --- a/drivers/video/fbcon-afb.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Amiga bitplanes (afb) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE) -#define FBCON_HAS_AFB -#endif -#else -#if defined(CONFIG_FBCON_AFB) -#define FBCON_HAS_AFB -#endif -#endif - -extern struct display_switch fbcon_afb; -extern void fbcon_afb_setup(struct display *p); -extern void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_afb_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_afb_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c index 221fbc572..a05848f5b 100644 --- a/drivers/video/fbcon-cfb16.c +++ b/drivers/video/fbcon-cfb16.c @@ -9,23 +9,20 @@ * more details. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb16.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb16.h> /* * 16 bpp packed pixels */ -u16 fbcon_cfb16_cmap[16]; - static u32 tab_cfb16[] = { #if defined(__BIG_ENDIAN) 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff @@ -45,28 +42,28 @@ void fbcon_cfb16_setup(struct display *p) void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * p->fontwidth * 2 == bytes) { + if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); return; } - if (p->fontwidthlog) { - sx <<= p->fontwidthlog+1; - dx <<= p->fontwidthlog+1; - width <<= p->fontwidthlog+1; + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p)+1; + dx <<= fontwidthlog(p)+1; + width <<= fontwidthlog(p)+1; } else { - sx *= p->fontwidth*2; - dx *= p->fontwidth*2; - width *= p->fontwidth*2; + sx *= fontwidth(p)*2; + dx *= fontwidth(p)*2; + width *= fontwidth(p)*2; } if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx; dst = p->screen_base + dy * linesize + dx; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src += bytes; dst += bytes; @@ -74,7 +71,7 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx, } else { src = p->screen_base + (sy+height) * linesize + sx - bytes; dst = p->screen_base + (dy+height) * linesize + dx - bytes; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src -= bytes; dst -= bytes; @@ -82,36 +79,43 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx, } } +static inline void rectfill(u8 *dest, int width, int height, u32 data, + int linesize) +{ + int i; + + data |= data<<16; + + while (height-- > 0) { + u32 *p = (u32 *)dest; + for (i = 0; i < width/4; i++) { + *p++ = data; + *p++ = data; + } + if (width & 2) + *p++ = data; + if (width & 1) + *(u16 *)p = data; + dest += linesize; + } +} + void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - u8 *dest0, *dest; - int bytes = p->next_line, lines = height * p->fontheight, rows, i; + u8 *dest; + int bytes = p->next_line, lines = height * fontheight(p); u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 2; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2; - bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)]; - bgx |= (bgx << 16); + bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - width *= p->fontwidth/4; - if (sx == 0 && width * 8 == bytes) - for (i = 0; i < lines * width; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - dest += 8; - } - else { - dest0 = dest; - for (rows = lines; rows--; dest0 += bytes) { - dest = dest0; - for (i = 0; i < width; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - dest += 8; - } - } - } + width *= fontwidth(p)/4; + if (width * 8 == bytes) + rectfill(dest, lines * width * 4, 1, bgx, bytes); + else + rectfill(dest, width * 4, lines, bgx, bytes); } void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy, @@ -121,38 +125,32 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes = p->next_line, rows; u32 eorx, fgx, bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; - fgx = fbcon_cfb16_cmap[attr_fgcol(p, c)]; - bgx = fbcon_cfb16_cmap[attr_bgcol(p, c)]; + fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)]; fgx |= (fgx << 16); bgx |= (bgx << 16); eorx = fgx ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - switch (p->fontwidth) { + switch (fontwidth(p)) { case 4: case 8: -#endif - cdat = p->fontdata + (c & p->charmask) * p->fontheight; - for (rows = p->fontheight; rows--; dest += bytes) { + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + for (rows = fontheight(p); rows--; dest += bytes) { bits = *cdat++; ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth == 8) -#endif - { + if (fontwidth(p) == 8) { ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; } } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: - cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); - for (rows = p->fontheight; rows--; dest += bytes) { + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); + for (rows = fontheight(p); rows--; dest += bytes) { bits = *cdat++; ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; @@ -161,14 +159,13 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy, bits = *cdat++; ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; - if (p->fontwidth == 16) { + if (fontwidth(p) == 16) { ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx; } } break; } -#endif } void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, @@ -179,44 +176,37 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, int rows, bytes = p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2; - fgx = fbcon_cfb16_cmap[attr_fgcol(p, *s)]; - bgx = fbcon_cfb16_cmap[attr_bgcol(p, *s)]; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; + fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, *s)]; + bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, *s)]; fgx |= (fgx << 16); bgx |= (bgx << 16); eorx = fgx ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - switch (p->fontwidth) { + switch (fontwidth(p)) { case 4: case 8: -#endif while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + c * p->fontheight; - for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + cdat = p->fontdata + c * fontheight(p); + for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) { u8 bits = *cdat++; ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth == 8) -#endif - { - + if (fontwidth(p) == 8) { ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx; } } - dest0 += p->fontwidth*2;; + dest0 += fontwidth(p)*2;; } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + (c * p->fontheight << 1); - for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + cdat = p->fontdata + (c * fontheight(p) << 1); + for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) { u8 bits = *cdat++; ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; @@ -225,16 +215,15 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, bits = *cdat++; ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx; ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx; - if (p->fontwidth == 16) { + if (fontwidth(p) == 16) { ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx; ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx; } } - dest0 += p->fontwidth*2; + dest0 += fontwidth(p)*2; } break; } -#endif } void fbcon_cfb16_revc(struct display *p, int xx, int yy) @@ -242,13 +231,9 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy) u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth*2; - for (rows = p->fontheight; rows--; dest += bytes) { -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; - ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; -#else - switch (p->fontwidth) { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2; + for (rows = fontheight(p); rows--; dest += bytes) { + switch (fontwidth(p)) { case 16: ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; /* FALL THROUGH */ @@ -261,42 +246,27 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy) case 4: ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; } -#endif } } -void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p) +void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) { - u8 *dest0; - u32 *dest; int bytes = p->next_line; u32 bgx; - int i, j; - unsigned int right_start = conp->vc_cols*p->fontwidth; - unsigned int right_width = p->var.xres_virtual-right_start; - unsigned int bottom_start = conp->vc_rows*p->fontheight; - unsigned int bottom_width = p->var.yres_virtual-bottom_start; + unsigned int right_start = conp->vc_cols*fontwidth(p); + unsigned int bottom_start = conp->vc_rows*fontheight(p); + unsigned int right_width, bottom_width; - bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)]; - bgx |= (bgx << 16); + bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - if (right_width) { - dest0 = p->screen_base+right_start*2; - for (i = 0; i < bottom_start; i++, dest0 += bytes) { - for (j = 0, dest = (u32 *)dest0; j < right_width/2; j++) - *dest++ = bgx; - if (right_width & 1) - *(u16 *)dest = bgx; - } - } - if (bottom_width) { - dest = (u32 *)(p->screen_base+bottom_start*bytes); - for (i = 0; i < bytes*bottom_width/4; i++) - *dest++ = bgx; - if ((bytes*bottom_width) & 2) - *(u16 *)dest = bgx; - } + if (!bottom_only && (right_width = p->var.xres-right_start)) + rectfill(p->screen_base+right_start*2, right_width, + p->var.yres_virtual, bgx, bytes); + if ((bottom_width = p->var.yres-bottom_start)) + rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes, + right_start, bottom_width, bgx, bytes); } @@ -333,4 +303,4 @@ EXPORT_SYMBOL(fbcon_cfb16_clear); EXPORT_SYMBOL(fbcon_cfb16_putc); EXPORT_SYMBOL(fbcon_cfb16_putcs); EXPORT_SYMBOL(fbcon_cfb16_revc); -EXPORT_SYMBOL(fbcon_cfb16_cmap); +EXPORT_SYMBOL(fbcon_cfb16_clear_margins); diff --git a/drivers/video/fbcon-cfb16.h b/drivers/video/fbcon-cfb16.h deleted file mode 100644 index ebff9bcb9..000000000 --- a/drivers/video/fbcon-cfb16.h +++ /dev/null @@ -1,29 +0,0 @@ - /* - * 16 bpp packed pixel (cfb16) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE) -#define FBCON_HAS_CFB16 -#endif -#else -#if defined(CONFIG_FBCON_CFB16) -#define FBCON_HAS_CFB16 -#endif -#endif - -extern struct display_switch fbcon_cfb16; -extern u16 fbcon_cfb16_cmap[16]; -extern void fbcon_cfb16_setup(struct display *p); -extern void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_cfb16_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb16_revc(struct display *p, int xx, int yy); -extern void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p); diff --git a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c index 60bed6275..e25fadaae 100644 --- a/drivers/video/fbcon-cfb2.c +++ b/drivers/video/fbcon-cfb2.c @@ -16,8 +16,8 @@ #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb2.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb2.h> /* @@ -57,7 +57,7 @@ void fbcon_cfb2_setup(struct display *p) void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src,*dst; if (sx == 0 && dx == 0 && width * 2 == bytes) { @@ -69,7 +69,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx, if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx * 2; dst = p->screen_base + dy * linesize + dx * 2; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width * 2); src += bytes; dst += bytes; @@ -80,7 +80,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx, - bytes; dst = p->screen_base + (dy+height) * linesize + dx * 2 - bytes; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width * 2); src -= bytes; dst -= bytes; @@ -93,10 +93,10 @@ void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { u8 *dest0,*dest; - int bytes=p->next_line,lines=height * p->fontheight, rows, i; + int bytes=p->next_line,lines=height * fontheight(p), rows, i; u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * 2; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * 2; bgx=attr_bgcol_ec(p,conp); bgx |= (bgx << 2); /* expand the colour to 16 bits */ @@ -128,8 +128,8 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes=p->next_line,rows; u32 eorx,fgx,bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 2; - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2; + cdat = p->fontdata + (c & p->charmask) * fontheight(p); fgx=3;/*attr_fgcol(p,c);*/ bgx=attr_bgcol(p,c); @@ -139,7 +139,7 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy, bgx |= (bgx << 4); eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { + for (rows = fontheight(p) ; rows-- ; dest += bytes) { ((u8 *)dest)[0]= (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx; ((u8 *)dest)[1]= @@ -155,7 +155,7 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh int rows,bytes=p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 2; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 2; fgx=3/*attr_fgcol(p,*s)*/; bgx=attr_bgcol(p,*s); fgx |= (fgx << 2); @@ -165,9 +165,9 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh eorx = fgx ^ bgx; while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + c * p->fontheight; + cdat = p->fontdata + c * fontheight(p); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { ((u8 *)dest)[0]= (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx; ((u8 *)dest)[1]= @@ -182,8 +182,8 @@ void fbcon_cfb2_revc(struct display *p, int xx, int yy) u8 *dest; int bytes=p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 2; - for (rows = p->fontheight ; rows-- ; dest += bytes) { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2; + for (rows = fontheight(p) ; rows-- ; dest += bytes) { ((u16 *)dest)[0] ^= 0xffff; } } diff --git a/drivers/video/fbcon-cfb2.h b/drivers/video/fbcon-cfb2.h deleted file mode 100644 index 1cb29c5a9..000000000 --- a/drivers/video/fbcon-cfb2.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * 2 bpp packed pixel (cfb2) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE) -#define FBCON_HAS_CFB2 -#endif -#else -#if defined(CONFIG_FBCON_CFB2) -#define FBCON_HAS_CFB2 -#endif -#endif - -extern struct display_switch fbcon_cfb2; -extern void fbcon_cfb2_setup(struct display *p); -extern void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb2_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c index 49c023ef3..488aac290 100644 --- a/drivers/video/fbcon-cfb24.c +++ b/drivers/video/fbcon-cfb24.c @@ -9,23 +9,20 @@ * more details. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb24.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb24.h> /* * 24 bpp packed pixels */ -u32 fbcon_cfb24_cmap[16]; - void fbcon_cfb24_setup(struct display *p) { p->next_line = p->line_length ? p->line_length : p->var.xres_virtual*3; @@ -35,29 +32,29 @@ void fbcon_cfb24_setup(struct display *p) void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * p->fontwidth * 3 == bytes) { + if (sx == 0 && dx == 0 && width * fontwidth(p) * 3 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); return; } - if (p->fontwidthlog) { - sx <<= p->fontwidthlog; - dx <<= p->fontwidthlog; - width <<= p->fontwidthlog; + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p); + dx <<= fontwidthlog(p); + width <<= fontwidthlog(p); } else { - sx *= p->fontwidth; - dx *= p->fontwidth; - width *= p->fontwidth; + sx *= fontwidth(p); + dx *= fontwidth(p); + width *= fontwidth(p); } sx *= 3; dx *= 3; width *= 3; if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx; dst = p->screen_base + dy * linesize + dx; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src += bytes; dst += bytes; @@ -65,7 +62,7 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx, } else { src = p->screen_base + (sy+height) * linesize + sx - bytes; dst = p->screen_base + (dy+height) * linesize + dx - bytes; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src -= bytes; dst -= bytes; @@ -73,48 +70,63 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx, } } -static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest) -{ #if defined(__BIG_ENDIAN) - *dest++ = (d1<<8) | (d2>>16); - *dest++ = (d2<<16) | (d3>>8); - *dest++ = (d3<<24) | d4; +#define convert4to3(in1, in2, in3, in4, out1, out2, out3) \ + do { \ + out1 = (in1<<8) | (in2>>16); \ + out2 = (in2<<16) | (in3>>8); \ + out3 = (in3<<24) | in4; \ + } while (0); #elif defined(__LITTLE_ENDIAN) - *dest++ = (d1<<8) | (d2>>16); - *dest++ = (d2<<16) | (d3>>8); - *dest++ = (d3<<24) | d4; +#define convert4to3(in1, in2, in3, in4, out1, out2, out3) \ + do { \ + out1 = in1 | (in2<<24); \ + out2 = (in2>> 8) | (in3<<16); \ + out3 = (in3>>16) | (in4<< 8); \ + } while (0); #else #error FIXME: No endianness?? #endif + +static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest) +{ + convert4to3(d1, d2, d3, d4, *dest++, *dest++, *dest++); +} + +static inline void rectfill(u8 *dest, int width, int height, u32 data, + int linesize) +{ + u32 d1, d2, d3; + int i; + + convert4to3(data, data, data, data, d1, d2, d3); + while (height-- > 0) { + u32 *p = (u32 *)dest; + for (i = 0; i < width/4; i++) { + *p++ = d1; + *p++ = d2; + *p++ = d3; + } + dest += linesize; + } } void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - u8 *dest0, *dest; - int bytes = p->next_line, lines = height * p->fontheight, rows, i; + u8 *dest; + int bytes = p->next_line, lines = height * fontheight(p); u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 3; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 3; - bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - width *= p->fontwidth/4; - if (sx == 0 && width * 12 == bytes) - for (i = 0; i < lines * width; i++) { - store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); - dest += 12; - } - else { - dest0 = dest; - for (rows = lines; rows--; dest0 += bytes) { - dest = dest0; - for (i = 0; i < width; i++) { - store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); - dest += 12; - } - } - } + width *= fontwidth(p)/4; + if (width * 12 == bytes) + rectfill(dest, lines * width * 4, 1, bgx, bytes); + else + rectfill(dest, width * 4, lines, bgx, bytes); } void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy, @@ -124,34 +136,31 @@ void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes = p->next_line, rows; u32 eorx, fgx, bgx, d1, d2, d3, d4; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; - if (p->fontwidth <= 8) - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; + if (fontwidth(p) <= 8) + cdat = p->fontdata + (c & p->charmask) * fontheight(p); else - cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); - fgx = fbcon_cfb24_cmap[attr_fgcol(p, c)]; - bgx = fbcon_cfb24_cmap[attr_bgcol(p, c)]; + fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)]; eorx = fgx ^ bgx; - for (rows = p->fontheight; rows--; dest += bytes) { + for (rows = fontheight(p); rows--; dest += bytes) { bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)dest); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 8) + if (fontwidth(p) < 8) continue; -#endif d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 12) + if (fontwidth(p) < 12) continue; bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; @@ -159,14 +168,13 @@ void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy, d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); - if (p->fontwidth < 16) + if (fontwidth(p) < 16) continue; d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+32)); -#endif } } @@ -178,39 +186,32 @@ void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, int rows, bytes = p->next_line; u32 eorx, fgx, bgx, d1, d2, d3, d4; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; - fgx = fbcon_cfb24_cmap[attr_fgcol(p, *s)]; - bgx = fbcon_cfb24_cmap[attr_bgcol(p, *s)]; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; + fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, *s)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, *s)]; eorx = fgx ^ bgx; while (count--) { c = *s++ & p->charmask; -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - cdat = p->fontdata + c * p->fontheight; -#else - if (p->fontwidth <= 8) - cdat = p->fontdata + c * p->fontheight; + if (fontwidth(p) <= 8) + cdat = p->fontdata + c * fontheight(p); else - cdat = p->fontdata + (c * p->fontheight << 1); -#endif - for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + cdat = p->fontdata + (c * fontheight(p) << 1); + for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) { bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; d2 = (-(bits >> 6 & 1) & eorx) ^ bgx; d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)dest); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 8) + if (fontwidth(p) < 8) continue; -#endif d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+12)); -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 12) + if (fontwidth(p) < 12) continue; bits = *cdat++; d1 = (-(bits >> 7) & eorx) ^ bgx; @@ -218,16 +219,15 @@ void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, d3 = (-(bits >> 5 & 1) & eorx) ^ bgx; d4 = (-(bits >> 4 & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+24)); - if (p->fontwidth < 16) + if (fontwidth(p) < 16) continue; d1 = (-(bits >> 3 & 1) & eorx) ^ bgx; d2 = (-(bits >> 2 & 1) & eorx) ^ bgx; d3 = (-(bits >> 1 & 1) & eorx) ^ bgx; d4 = (-(bits & 1) & eorx) ^ bgx; store4pixels(d1, d2, d3, d4, (u32 *)(dest+32)); -#endif } - dest0 += p->fontwidth*3; + dest0 += fontwidth(p)*3; } } @@ -236,15 +236,9 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy) u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3; - for (rows = p->fontheight; rows--; dest += bytes) { -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff; - ((u32 *)dest)[5] ^= 0xffffffff; - ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; - ((u32 *)dest)[2] ^= 0xffffffff; -#else - switch (p->fontwidth) { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 3; + for (rows = fontheight(p); rows--; dest += bytes) { + switch (fontwidth(p)) { case 16: ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff; /* FALL THROUGH */ @@ -258,39 +252,27 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy) ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; ((u32 *)dest)[2] ^= 0xffffffff; } -#endif } } -void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p) +void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) { - u8 *dest0, *dest; int bytes = p->next_line; u32 bgx; - int i, j; - - unsigned int right_start = conp->vc_cols*p->fontwidth; - unsigned int right_width = p->var.xres_virtual-right_start; - unsigned int bottom_start = conp->vc_rows*p->fontheight; - unsigned int bottom_width = p->var.yres_virtual-bottom_start; - - bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)]; - - if (right_width) { - dest0 = p->screen_base+right_start*3; - for (i = 0; i < bottom_start; i++, dest0 += bytes) - for (j = 0, dest = dest0; j < right_width/4; j++) { - store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); - dest += 12; - } - } - if (bottom_width) { - dest = p->screen_base+bottom_start*bytes; - for (i = 0; i < bytes*bottom_width/12; i++) { - store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest); - dest += 12; - } - } + + unsigned int right_start = conp->vc_cols*fontwidth(p); + unsigned int bottom_start = conp->vc_rows*fontheight(p); + unsigned int right_width, bottom_width; + + bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + + if (!bottom_only && (right_width = p->var.xres-right_start)) + rectfill(p->screen_base+right_start*3, right_width, + p->var.yres_virtual, bgx, bytes); + if ((bottom_width = p->var.yres-bottom_start)) + rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes, + right_start, bottom_width, bgx, bytes); } @@ -327,4 +309,4 @@ EXPORT_SYMBOL(fbcon_cfb24_clear); EXPORT_SYMBOL(fbcon_cfb24_putc); EXPORT_SYMBOL(fbcon_cfb24_putcs); EXPORT_SYMBOL(fbcon_cfb24_revc); -EXPORT_SYMBOL(fbcon_cfb24_cmap); +EXPORT_SYMBOL(fbcon_cfb24_clear_margins); diff --git a/drivers/video/fbcon-cfb24.h b/drivers/video/fbcon-cfb24.h deleted file mode 100644 index 83cee1209..000000000 --- a/drivers/video/fbcon-cfb24.h +++ /dev/null @@ -1,29 +0,0 @@ - /* - * 24 bpp packed pixel (cfb24) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE) -#define FBCON_HAS_CFB24 -#endif -#else -#if defined(CONFIG_FBCON_CFB24) -#define FBCON_HAS_CFB24 -#endif -#endif - -extern struct display_switch fbcon_cfb24; -extern u32 fbcon_cfb24_cmap[16]; -extern void fbcon_cfb24_setup(struct display *p); -extern void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb24_revc(struct display *p, int xx, int yy); -extern void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p); diff --git a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c index 1a1c48bcf..cd1e80a7d 100644 --- a/drivers/video/fbcon-cfb32.c +++ b/drivers/video/fbcon-cfb32.c @@ -9,23 +9,20 @@ * more details. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb32.h> /* * 32 bpp packed pixels */ -u32 fbcon_cfb32_cmap[16]; - void fbcon_cfb32_setup(struct display *p) { p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2; @@ -35,28 +32,28 @@ void fbcon_cfb32_setup(struct display *p) void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src, *dst; - if (sx == 0 && dx == 0 && width * p->fontwidth * 4 == bytes) { + if (sx == 0 && dx == 0 && width * fontwidth(p) * 4 == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); return; } - if (p->fontwidthlog) { - sx <<= p->fontwidthlog+2; - dx <<= p->fontwidthlog+2; - width <<= p->fontwidthlog+2; + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p)+2; + dx <<= fontwidthlog(p)+2; + width <<= fontwidthlog(p)+2; } else { - sx *= p->fontwidth*4; - dx *= p->fontwidth*4; - width *= p->fontwidth*4; + sx *= fontwidth(p)*4; + dx *= fontwidth(p)*4; + width *= fontwidth(p)*4; } if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx; dst = p->screen_base + dy * linesize + dx; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src += bytes; dst += bytes; @@ -64,7 +61,7 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx, } else { src = p->screen_base + (sy+height) * linesize + sx - bytes; dst = p->screen_base + (dy+height) * linesize + dx - bytes; - for (rows = height * p->fontheight; rows--;) { + for (rows = height * fontheight(p); rows--;) { mymemmove(dst, src, width); src -= bytes; dst -= bytes; @@ -72,39 +69,45 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx, } } +static inline void rectfill(u8 *dest, int width, int height, u32 data, + int linesize) +{ + int i; + + while (height-- > 0) { + u32 *p = (u32 *)dest; + for (i = 0; i < width/4; i++) { + *p++ = data; + *p++ = data; + *p++ = data; + *p++ = data; + } + if (width & 2) { + *p++ = data; + *p++ = data; + } + if (width & 1) + *p++ = data; + dest += linesize; + } +} + void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { - u8 *dest0, *dest; - int bytes = p->next_line, lines = height * p->fontheight, rows, i; + u8 *dest; + int bytes = p->next_line, lines = height * fontheight(p); u32 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 4; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 4; - bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - width *= p->fontwidth/4; - if (sx == 0 && width * 16 == bytes) - for (i = 0; i < lines * width; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - dest += 16; - } - else { - dest0 = dest; - for (rows = lines; rows--; dest0 += bytes) { - dest = dest0; - for (i = 0; i < width; i++) { - ((u32 *)dest)[0] = bgx; - ((u32 *)dest)[1] = bgx; - ((u32 *)dest)[2] = bgx; - ((u32 *)dest)[3] = bgx; - dest += 16; - } - } - } + width *= fontwidth(p)/4; + if (width * 16 == bytes) + rectfill(dest, lines * width * 4, 1, bgx, bytes); + else + rectfill(dest, width * 4, lines, bgx, bytes); } void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy, @@ -114,48 +117,40 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes = p->next_line, rows; u32 eorx, fgx, bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - cdat = p->fontdata + (c & p->charmask) * p->fontheight; -#else - if (p->fontwidth <= 8) - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4; + if (fontwidth(p) <= 8) + cdat = p->fontdata + (c & p->charmask) * fontheight(p); else - cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); -#endif - fgx = fbcon_cfb32_cmap[attr_fgcol(p, c)]; - bgx = fbcon_cfb32_cmap[attr_bgcol(p, c)]; + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); + fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)]; eorx = fgx ^ bgx; - for (rows = p->fontheight; rows--; dest += bytes) { + for (rows = fontheight(p); rows--; dest += bytes) { bits = *cdat++; ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 8) + if (fontwidth(p) < 8) continue; -#endif ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 12) + if (fontwidth(p) < 12) continue; bits = *cdat++; ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx; - if (p->fontwidth < 16) + if (fontwidth(p) < 16) continue; ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx; -#endif } } @@ -167,51 +162,43 @@ void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, int rows, bytes = p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; - fgx = fbcon_cfb32_cmap[attr_fgcol(p, *s)]; - bgx = fbcon_cfb32_cmap[attr_bgcol(p, *s)]; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4; + fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, *s)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, *s)]; eorx = fgx ^ bgx; while (count--) { c = *s++ & p->charmask; -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - cdat = p->fontdata + c * p->fontheight; -#else - if (p->fontwidth <= 8) - cdat = p->fontdata + c * p->fontheight; + if (fontwidth(p) <= 8) + cdat = p->fontdata + c * fontheight(p); else - cdat = p->fontdata + (c * p->fontheight << 1); -#endif - for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) { + cdat = p->fontdata + (c * fontheight(p) << 1); + for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) { bits = *cdat++; ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 8) + if (fontwidth(p) < 8) continue; -#endif ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth < 12) + if (fontwidth(p) < 12) continue; bits = *cdat++; ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx; ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx; ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx; ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx; - if (p->fontwidth < 16) + if (fontwidth(p) < 16) continue; ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx; ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx; ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx; ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx; -#endif } - dest0 += p->fontwidth*4; + dest0 += fontwidth(p)*4; } } @@ -220,15 +207,9 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy) u8 *dest; int bytes = p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4; - for (rows = p->fontheight; rows--; dest += bytes) { -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff; - ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff; - ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff; - ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; -#else - switch (p->fontwidth) { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4; + for (rows = fontheight(p); rows--; dest += bytes) { + switch (fontwidth(p)) { case 16: ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff; ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff; @@ -246,36 +227,27 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy) ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff; /* FALL THROUGH */ } -#endif } } -void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p) +void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) { - u8 *dest0; - u32 *dest; int bytes = p->next_line; u32 bgx; - int i, j; - unsigned int right_start = conp->vc_cols*p->fontwidth; - unsigned int right_width = p->var.xres_virtual-right_start; - unsigned int bottom_start = conp->vc_rows*p->fontheight; - unsigned int bottom_width = p->var.yres_virtual-bottom_start; + unsigned int right_start = conp->vc_cols*fontwidth(p); + unsigned int bottom_start = conp->vc_rows*fontheight(p); + unsigned int right_width, bottom_width; - bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)]; + bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - if (right_width) { - dest0 = p->screen_base+right_start*4; - for (i = 0; i < bottom_start; i++, dest0 += bytes) - for (j = 0, dest = (u32 *)dest0; j < right_width; j++) - *dest++ = bgx; - } - if (bottom_width) { - dest = (u32 *)(p->screen_base+bottom_start*bytes); - for (i = 0; i < bytes*bottom_width/4; i++) - *dest++ = bgx; - } + if (!bottom_only && (right_width = p->var.xres-right_start)) + rectfill(p->screen_base+right_start*4, right_width, + p->var.yres_virtual, bgx, bytes); + if ((bottom_width = p->var.yres-bottom_start)) + rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes, + right_start, bottom_width, bgx, bytes); } @@ -312,4 +284,4 @@ EXPORT_SYMBOL(fbcon_cfb32_clear); EXPORT_SYMBOL(fbcon_cfb32_putc); EXPORT_SYMBOL(fbcon_cfb32_putcs); EXPORT_SYMBOL(fbcon_cfb32_revc); -EXPORT_SYMBOL(fbcon_cfb32_cmap); +EXPORT_SYMBOL(fbcon_cfb32_clear_margins); diff --git a/drivers/video/fbcon-cfb32.h b/drivers/video/fbcon-cfb32.h deleted file mode 100644 index 500528b04..000000000 --- a/drivers/video/fbcon-cfb32.h +++ /dev/null @@ -1,29 +0,0 @@ - /* - * 32 bpp packed pixel (cfb32) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE) -#define FBCON_HAS_CFB32 -#endif -#else -#if defined(CONFIG_FBCON_CFB32) -#define FBCON_HAS_CFB32 -#endif -#endif - -extern struct display_switch fbcon_cfb32; -extern u32 fbcon_cfb32_cmap[16]; -extern void fbcon_cfb32_setup(struct display *p); -extern void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb32_revc(struct display *p, int xx, int yy); -extern void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p); diff --git a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c index 4d3f196bf..78b87ffe7 100644 --- a/drivers/video/fbcon-cfb4.c +++ b/drivers/video/fbcon-cfb4.c @@ -16,8 +16,8 @@ #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb4.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb4.h> /* @@ -57,7 +57,7 @@ void fbcon_cfb4_setup(struct display *p) void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src,*dst; if (sx == 0 && dx == 0 && width * 4 == bytes) { @@ -69,7 +69,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx, if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx * 4; dst = p->screen_base + dy * linesize + dx * 4; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width * 4); src += bytes; dst += bytes; @@ -80,7 +80,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx, - bytes; dst = p->screen_base + (dy+height) * linesize + dx * 4 - bytes; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width * 4); src -= bytes; dst -= bytes; @@ -93,12 +93,12 @@ void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { u8 *dest0,*dest; - int bytes=p->next_line,lines=height * p->fontheight, rows, i; + int bytes=p->next_line,lines=height * fontheight(p), rows, i; u32 bgx; /* if(p->screen_base!=0xFDD00020) mac_boom(1);*/ - dest = p->screen_base + sy * p->fontheight * bytes + sx * 4; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * 4; bgx=attr_bgcol_ec(p,conp); bgx |= (bgx << 4); /* expand the colour to 32bits */ @@ -130,10 +130,10 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes=p->next_line,rows; u32 eorx,fgx,bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 4; - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4; + cdat = p->fontdata + (c & p->charmask) * fontheight(p); - fgx=15;/*attr_fgcol(p,c);*/ + fgx=attr_fgcol(p,c); bgx=attr_bgcol(p,c); fgx |= (fgx << 4); fgx |= (fgx << 8); @@ -141,7 +141,7 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy, bgx |= (bgx << 8); eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { + for (rows = fontheight(p) ; rows-- ; dest += bytes) { ((u16 *)dest)[0]= (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx; ((u16 *)dest)[1]= @@ -157,8 +157,8 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, int rows,bytes=p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 4; - fgx=15/*attr_fgcol(p,*s)*/; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 4; + fgx=attr_fgcol(p,*s); bgx=attr_bgcol(p,*s); fgx |= (fgx << 4); fgx |= (fgx << 8); @@ -169,9 +169,9 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, eorx = fgx ^ bgx; while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + c * p->fontheight; + cdat = p->fontdata + c * fontheight(p); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { ((u16 *)dest)[0]= (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx; ((u16 *)dest)[1]= @@ -186,9 +186,9 @@ void fbcon_cfb4_revc(struct display *p, int xx, int yy) u8 *dest; int bytes=p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * 4; - for (rows = p->fontheight ; rows-- ; dest += bytes) { - ((u32 *)dest)[0] ^= 0x0f0f0f0f; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4; + for (rows = fontheight(p) ; rows-- ; dest += bytes) { + ((u32 *)dest)[0] ^= 0xffffffff; } } diff --git a/drivers/video/fbcon-cfb4.h b/drivers/video/fbcon-cfb4.h deleted file mode 100644 index df08288cd..000000000 --- a/drivers/video/fbcon-cfb4.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * 4 bpp packed pixel (cfb4) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE) -#define FBCON_HAS_CFB4 -#endif -#else -#if defined(CONFIG_FBCON_CFB4) -#define FBCON_HAS_CFB4 -#endif -#endif - -extern struct display_switch fbcon_cfb4; -extern void fbcon_cfb4_setup(struct display *p); -extern void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb4_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c index b4de49b3b..5fe78bc30 100644 --- a/drivers/video/fbcon-cfb8.c +++ b/drivers/video/fbcon-cfb8.c @@ -9,15 +9,14 @@ * more details. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/tty.h> #include <linux/console.h> #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> /* @@ -49,24 +48,24 @@ void fbcon_cfb8_setup(struct display *p) void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src,*dst; - if (sx == 0 && dx == 0 && width * p->fontwidth == bytes) { + if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) { mymemmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, height * linesize); return; } - if (p->fontwidthlog) { - sx <<= p->fontwidthlog; dx <<= p->fontwidthlog; width <<= p->fontwidthlog; + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p); dx <<= fontwidthlog(p); width <<= fontwidthlog(p); } else { - sx *= p->fontwidth; dx *= p->fontwidth; width *= p->fontwidth; + sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p); } if (dy < sy || (dy == sy && dx < sx)) { src = p->screen_base + sy * linesize + sx; dst = p->screen_base + dy * linesize + dx; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width); src += bytes; dst += bytes; @@ -74,7 +73,7 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx, } else { src = p->screen_base + (sy+height) * linesize + sx - bytes; dst = p->screen_base + (dy+height) * linesize + dx - bytes; - for (rows = height * p->fontheight ; rows-- ;) { + for (rows = height * fontheight(p) ; rows-- ;) { mymemmove(dst, src, width); src -= bytes; dst -= bytes; @@ -82,24 +81,31 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx, } } +static inline void rectfill(u8 *dest, int width, int height, u8 data, + int linesize) +{ + while (height-- > 0) { + memset(dest, data, width); + dest += linesize; + } +} + void fbcon_cfb8_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { u8 *dest; - int bytes=p->next_line,lines=height * p->fontheight, rows; + int bytes=p->next_line,lines=height * fontheight(p); u8 bgx; - dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth; + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p); bgx=attr_bgcol_ec(p,conp); - if (sx == 0 && p->fontwidth == 8 && width * 8 == bytes) - memset(dest, bgx, lines * width * p->fontwidth); - else { - width *= p->fontwidth; - for (rows = lines; rows-- ; dest += bytes) - memset(dest, bgx, width); - } + width *= fontwidth(p); + if (width == bytes) + rectfill(dest, lines * width, 1, bgx, bytes); + else + rectfill(dest, width, lines, bgx, bytes); } void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, @@ -109,11 +115,11 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, int bytes=p->next_line,rows; u32 eorx,fgx,bgx; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth; - if (p->fontwidth <= 8) - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); + if (fontwidth(p) <= 8) + cdat = p->fontdata + (c & p->charmask) * fontheight(p); else - cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1); + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); fgx=attr_fgcol(p,c); bgx=attr_bgcol(p,c); @@ -123,33 +129,29 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, bgx |= (bgx << 16); eorx = fgx ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - switch (p->fontwidth) { + switch (fontwidth(p)) { case 4: - for (rows = p->fontheight ; rows-- ; dest += bytes) + for (rows = fontheight(p) ; rows-- ; dest += bytes) ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx; break; case 8: -#endif - for (rows = p->fontheight ; rows-- ; dest += bytes) { + for (rows = fontheight(p) ; rows-- ; dest += bytes) { ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx; ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx; } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: - for (rows = p->fontheight ; rows-- ; dest += bytes) { + for (rows = fontheight(p) ; rows-- ; dest += bytes) { ((u32 *)dest)[0]= (nibbletab_cfb8[*(u16 *)cdat >> 12] & eorx) ^ bgx; ((u32 *)dest)[1]= (nibbletab_cfb8[(*(u16 *)cdat >> 8) & 0xf] & eorx) ^ bgx; ((u32 *)dest)[2]= (nibbletab_cfb8[(*(u16 *)cdat >> 4) & 0xf] & eorx) ^ bgx; - if (p->fontwidth == 16) + if (fontwidth(p) == 16) ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx; cdat += 2; } break; } -#endif } void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, @@ -160,7 +162,7 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, int rows,bytes=p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth; + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); fgx=attr_fgcol(p,*s); bgx=attr_bgcol(p,*s); fgx |= (fgx << 8); @@ -168,51 +170,47 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, bgx |= (bgx << 8); bgx |= (bgx << 16); eorx = fgx ^ bgx; -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY - switch (p->fontwidth) { + switch (fontwidth(p)) { case 4: while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + c * p->fontheight; + cdat = p->fontdata + c * fontheight(p); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx; dest0+=4; } break; case 8: -#endif while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + c * p->fontheight; + cdat = p->fontdata + c * fontheight(p); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx; ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx; } dest0+=8; } -#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY break; case 12: case 16: while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + (c * p->fontheight << 1); + cdat = p->fontdata + (c * fontheight(p) << 1); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { ((u32 *)dest)[0]= (nibbletab_cfb8[*(u16 *)cdat >> 12] & eorx) ^ bgx; ((u32 *)dest)[1]= (nibbletab_cfb8[(*(u16 *)cdat >> 8) & 0xf] & eorx) ^ bgx; ((u32 *)dest)[2]= (nibbletab_cfb8[(*(u16 *)cdat >> 4) & 0xf] & eorx) ^ bgx; - if (p->fontwidth == 16) + if (fontwidth(p) == 16) ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx; cdat += 2; } - dest0+=p->fontwidth; + dest0+=fontwidth(p); } break; } -#endif } void fbcon_cfb8_revc(struct display *p, int xx, int yy) @@ -220,44 +218,36 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy) u8 *dest; int bytes=p->next_line, rows; - dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth; - for (rows = p->fontheight ; rows-- ; dest += bytes) { -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - ((u32 *)dest)[1] ^= 0x0f0f0f0f; - ((u32 *)dest)[0] ^= 0x0f0f0f0f; -#else - switch (p->fontwidth) { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); + for (rows = fontheight(p) ; rows-- ; dest += bytes) { + switch (fontwidth(p)) { case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */ case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */ case 8: ((u32 *)dest)[1] ^= 0x0f0f0f0f; /* FALL THROUGH */ case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f; /* FALL THROUGH */ default: break; } -#endif } } -void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p) +void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) { - u8 *dest; int bytes=p->next_line; u8 bgx; - int i; - unsigned int right_start = conp->vc_cols*p->fontwidth; - unsigned int right_width = p->var.xres_virtual-right_start; - unsigned int bottom_start = conp->vc_rows*p->fontheight; - unsigned int bottom_width = p->var.yres_virtual-bottom_start; + unsigned int right_start = conp->vc_cols*fontwidth(p); + unsigned int bottom_start = conp->vc_rows*fontheight(p); + unsigned int right_width, bottom_width; bgx=attr_bgcol_ec(p,conp); - if (right_width) { - dest = p->screen_base+right_start; - for (i = 0; i < bottom_start; i++, dest += bytes) - memset(dest, bgx, right_width); - } - if (bottom_width) - memset(p->screen_base+bottom_start*bytes, bgx, bytes*bottom_width); + if (!bottom_only && (right_width = p->var.xres-right_start)) + rectfill(p->screen_base+right_start, right_width, p->var.yres_virtual, + bgx, bytes); + if ((bottom_width = p->var.yres-bottom_start)) + rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes, + right_start, bottom_width, bgx, bytes); } @@ -294,3 +284,4 @@ EXPORT_SYMBOL(fbcon_cfb8_clear); EXPORT_SYMBOL(fbcon_cfb8_putc); EXPORT_SYMBOL(fbcon_cfb8_putcs); EXPORT_SYMBOL(fbcon_cfb8_revc); +EXPORT_SYMBOL(fbcon_cfb8_clear_margins); diff --git a/drivers/video/fbcon-cfb8.h b/drivers/video/fbcon-cfb8.h deleted file mode 100644 index e1d8170ed..000000000 --- a/drivers/video/fbcon-cfb8.h +++ /dev/null @@ -1,28 +0,0 @@ - /* - * 8 bpp packed pixel (cfb8) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE) -#define FBCON_HAS_CFB8 -#endif -#else -#if defined(CONFIG_FBCON_CFB8) -#define FBCON_HAS_CFB8 -#endif -#endif - -extern struct display_switch fbcon_cfb8; -extern void fbcon_cfb8_setup(struct display *p); -extern void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_cfb8_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_cfb8_revc(struct display *p, int xx, int yy); -extern void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p); diff --git a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c index b87a1d10c..183f05a46 100644 --- a/drivers/video/fbcon-ilbm.c +++ b/drivers/video/fbcon-ilbm.c @@ -15,8 +15,8 @@ #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-ilbm.h" +#include <video/fbcon.h> +#include <video/fbcon-ilbm.h> /* @@ -45,25 +45,25 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { if (sx == 0 && dx == 0 && width == p->next_plane) - mymemmove(p->screen_base+dy*p->fontheight*p->next_line, - p->screen_base+sy*p->fontheight*p->next_line, - height*p->fontheight*p->next_line); + mymemmove(p->screen_base+dy*fontheight(p)*p->next_line, + p->screen_base+sy*fontheight(p)*p->next_line, + height*fontheight(p)*p->next_line); else { u8 *src, *dest; u_int i; if (dy <= sy) { - src = p->screen_base+sy*p->fontheight*p->next_line+sx; - dest = p->screen_base+dy*p->fontheight*p->next_line+dx; - for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + src = p->screen_base+sy*fontheight(p)*p->next_line+sx; + dest = p->screen_base+dy*fontheight(p)*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) { mymemmove(dest, src, width); src += p->next_plane; dest += p->next_plane; } } else { - src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; - dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; - for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + src = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx; + dest = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) { src -= p->next_plane; dest -= p->next_plane; mymemmove(dest, src, width); @@ -79,10 +79,10 @@ void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx, u_int i, rows; int bg, bg0; - dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+sy*fontheight(p)*p->next_line+sx; bg0 = attr_bgcol_ec(p,conp); - for (rows = height*p->fontheight; rows--;) { + for (rows = height*fontheight(p); rows--;) { bg = bg0; for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { if (bg & 1) @@ -102,12 +102,12 @@ void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy, u8 d; int fg0, bg0, fg, bg; - dest = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat = p->fontdata+(c&p->charmask)*p->fontheight; + dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; + cdat = p->fontdata+(c&p->charmask)*fontheight(p); fg0 = attr_fgcol(p,c); bg0 = attr_bgcol(p,c); - for (rows = p->fontheight; rows--;) { + for (rows = fontheight(p); rows--;) { d = *cdat++; fg = fg0; bg = bg0; @@ -153,7 +153,7 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, u32 d; int fg0, bg0, fg, bg; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; fg0 = attr_fgcol(p,*s); bg0 = attr_bgcol(p,*s); @@ -163,8 +163,8 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, dest = dest0++; xx++; - cdat1 = p->fontdata+c1*p->fontheight; - for (rows = p->fontheight; rows--;) { + cdat1 = p->fontdata+c1*fontheight(p); + for (rows = fontheight(p); rows--;) { d = *cdat1++; fg = fg0; bg = bg0; @@ -191,11 +191,11 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, c4 = s[3] & p->charmask; dest = dest0; - cdat1 = p->fontdata+c1*p->fontheight; - cdat2 = p->fontdata+c2*p->fontheight; - cdat3 = p->fontdata+c3*p->fontheight; - cdat4 = p->fontdata+c4*p->fontheight; - for (rows = p->fontheight; rows--;) { + cdat1 = p->fontdata+c1*fontheight(p); + cdat2 = p->fontdata+c2*fontheight(p); + cdat3 = p->fontdata+c3*fontheight(p); + cdat4 = p->fontdata+c4*fontheight(p); + for (rows = fontheight(p); rows--;) { #if defined(__BIG_ENDIAN) d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; #elif defined(__LITTLE_ENDIAN) @@ -234,7 +234,7 @@ void fbcon_ilbm_revc(struct display *p, int xx, int yy) u_int rows, i; int mask; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; mask = p->fgcol ^ p->bgcol; /* @@ -246,7 +246,7 @@ void fbcon_ilbm_revc(struct display *p, int xx, int yy) for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { if (mask & 1) { dest = dest0; - for (rows = p->fontheight; rows--; dest += p->next_line) + for (rows = fontheight(p); rows--; dest += p->next_line) *dest = ~*dest; } mask >>= 1; diff --git a/drivers/video/fbcon-ilbm.h b/drivers/video/fbcon-ilbm.h deleted file mode 100644 index 13292f287..000000000 --- a/drivers/video/fbcon-ilbm.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Amiga interleaved bitplanes (ilbm) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE) -#define FBCON_HAS_ILBM -#endif -#else -#if defined(CONFIG_FBCON_ILBM) -#define FBCON_HAS_ILBM -#endif -#endif - -extern struct display_switch fbcon_ilbm; -extern void fbcon_ilbm_setup(struct display *p); -extern void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_ilbm_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-iplan2p2.c b/drivers/video/fbcon-iplan2p2.c index 3cd8ab81e..c8d6838be 100644 --- a/drivers/video/fbcon-iplan2p2.c +++ b/drivers/video/fbcon-iplan2p2.c @@ -19,8 +19,8 @@ #include <asm/byteorder.h> -#include "fbcon.h" -#include "fbcon-iplan2p2.h" +#include <video/fbcon.h> +#include <video/fbcon-iplan2p2.h> /* @@ -169,18 +169,25 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx, /* Special (but often used) case: Moving whole lines can be * done with memmove() */ - mymemmove(p->screen_base + dy * p->next_line * p->fontheight, - p->screen_base + sy * p->next_line * p->fontheight, - p->next_line * height * p->fontheight); + mymemmove(p->screen_base + dy * p->next_line * fontheight(p), + p->screen_base + sy * p->next_line * fontheight(p), + p->next_line * height * fontheight(p)); } else { int rows, cols; u8 *src; u8 *dst; int bytes = p->next_line; - int linesize = bytes * p->fontheight; - u_int colsize = height * p->fontheight; + int linesize; + u_int colsize; u_int upwards = (dy < sy) || (dy == sy && dx < sx); + if (fontheightlog(p)) { + linesize = bytes << fontheightlog(p); + colsize = height << fontheightlog(p); + } else { + linesize = bytes * fontheight(p); + colsize = height * fontheight(p); + } if ((sx & 1) == (dx & 1)) { /* odd->odd or even->even */ if (upwards) { @@ -258,19 +265,30 @@ void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy, u8 *start; int rows; int bytes = p->next_line; - int lines = height * p->fontheight; + int lines; u32 size; u32 cval; u16 pcval; cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp))); + if (fontheightlog(p)) + lines = height << fontheightlog(p); + else + lines = height * fontheight(p); + if (sx == 0 && width * 2 == bytes) { - offset = sy * bytes * p->fontheight; + if (fontheightlog(p)) + offset = (sy * bytes) << fontheightlog(p); + else + offset = sy * bytes * fontheight(p); size = lines * bytes; memset_even_2p(p->screen_base+offset, size, cval); } else { - offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1); + if (fontheightlog(p)) + offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*4 + (sx & 1); + else + offset = sy * bytes * fontheight(p) + (sx>>1)*4 + (sx & 1); start = p->screen_base + offset; pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp))); @@ -306,14 +324,21 @@ void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c, int bytes = p->next_line; u16 eorx, fgx, bgx, fdx; - dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1); - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + if (fontheightlog(p)) { + dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*4 + (xx & 1)); + cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p)); + } else { + dest = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*4 + (xx & 1)); + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + } fgx = expand2w(COLOR_2P(attr_fgcol(p,c))); bgx = expand2w(COLOR_2P(attr_bgcol(p,c))); eorx = fgx ^ bgx; - for (rows = p->fontheight ; rows-- ; dest += bytes) { + for (rows = fontheight(p) ; rows-- ; dest += bytes) { fdx = dup2w(*cdat++); movepw(dest, (fdx & eorx) ^ bgx); } @@ -330,16 +355,24 @@ void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p, u16 eorx, fgx, bgx, fdx; bytes = p->next_line; - dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1); + if (fontheightlog(p)) + dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*4 + (xx & 1)); + else + dest0 = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*4 + (xx & 1)); fgx = expand2w(COLOR_2P(attr_fgcol(p,*s))); bgx = expand2w(COLOR_2P(attr_bgcol(p,*s))); eorx = fgx ^ bgx; while (count--) { c = *s++ & p->charmask; - cdat = p->fontdata + (c * p->fontheight); + if (fontheightlog(p)) + cdat = p->fontdata + (c << fontheightlog(p)); + else + cdat = p->fontdata + c * fontheight(p); - for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { fdx = dup2w(*cdat++); movepw(dest, (fdx & eorx) ^ bgx); } @@ -353,9 +386,13 @@ void fbcon_iplan2p2_revc(struct display *p, int xx, int yy) int j; int bytes; - dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*4 + - (xx & 1); - j = p->fontheight; + if (fontheightlog(p)) + dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) + + (xx>>1)*4 + (xx & 1)); + else + dest = (p->screen_base + yy * p->next_line * fontheight(p) + + (xx>>1)*4 + (xx & 1)); + j = fontheight(p); bytes = p->next_line; while (j--) { /* This should really obey the individual character's @@ -368,6 +405,30 @@ void fbcon_iplan2p2_revc(struct display *p, int xx, int yy) } } +void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + u32 offset; + int bytes; + int lines; + u32 cval; + +/* No need to handle right margin, cannot occur with fontwidth == 8 */ + + bytes = p->next_line; + if (fontheightlog(p)) { + lines = p->var.yres - (conp->vc_rows << fontheightlog(p)); + offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p); + } else { + lines = p->var.yres - conp->vc_rows * fontheight(p); + offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p); + } + if (lines) { + cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp))); + memset_even_2p(p->screen_base+offset, lines * bytes, cval); + } +} + /* * `switch' for the low level operations @@ -376,7 +437,7 @@ void fbcon_iplan2p2_revc(struct display *p, int xx, int yy) struct display_switch fbcon_iplan2p2 = { fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear, fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc, NULL, - NULL, NULL, FONTWIDTH(8) + NULL, fbcon_iplan2p2_clear_margins, FONTWIDTH(8) }; @@ -402,3 +463,4 @@ EXPORT_SYMBOL(fbcon_iplan2p2_clear); EXPORT_SYMBOL(fbcon_iplan2p2_putc); EXPORT_SYMBOL(fbcon_iplan2p2_putcs); EXPORT_SYMBOL(fbcon_iplan2p2_revc); +EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins); diff --git a/drivers/video/fbcon-iplan2p2.h b/drivers/video/fbcon-iplan2p2.h deleted file mode 100644 index 07b5a0d31..000000000 --- a/drivers/video/fbcon-iplan2p2.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Atari interleaved bitplanes (2 planes) (iplan2p2) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE) -#define FBCON_HAS_IPLAN2P2 -#endif -#else -#if defined(CONFIG_FBCON_IPLAN2P2) -#define FBCON_HAS_IPLAN2P2 -#endif -#endif - -extern struct display_switch fbcon_iplan2p2; -extern void fbcon_iplan2p2_setup(struct display *p); -extern void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, - int sy, int sx, int height, int width); -extern void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_iplan2p2_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-iplan2p4.c b/drivers/video/fbcon-iplan2p4.c index 4bd21c366..04b4a8422 100644 --- a/drivers/video/fbcon-iplan2p4.c +++ b/drivers/video/fbcon-iplan2p4.c @@ -19,8 +19,8 @@ #include <asm/byteorder.h> -#include "fbcon.h" -#include "fbcon-iplan2p4.h" +#include <video/fbcon.h> +#include <video/fbcon-iplan2p4.h> /* @@ -177,18 +177,25 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx, /* Special (but often used) case: Moving whole lines can be *done with memmove() */ - mymemmove(p->screen_base + dy * p->next_line * p->fontheight, - p->screen_base + sy * p->next_line * p->fontheight, - p->next_line * height * p->fontheight); + mymemmove(p->screen_base + dy * p->next_line * fontheight(p), + p->screen_base + sy * p->next_line * fontheight(p), + p->next_line * height * fontheight(p)); } else { int rows, cols; u8 *src; u8 *dst; int bytes = p->next_line; - int linesize = bytes * p->fontheight; - u_int colsize = height * p->fontheight; + int linesize; + u_int colsize; u_int upwards = (dy < sy) || (dy == sy && dx < sx); + if (fontheightlog(p)) { + linesize = bytes << fontheightlog(p); + colsize = height << fontheightlog(p); + } else { + linesize = bytes * fontheight(p); + colsize = height * fontheight(p); + } if ((sx & 1) == (dx & 1)) { /* odd->odd or even->even */ @@ -269,18 +276,29 @@ void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p, int sy, u8 *start; int rows; int bytes = p->next_line; - int lines = height * p->fontheight; + int lines; u32 size; u32 cval1, cval2, pcval; expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); + if (fontheightlog(p)) + lines = height << fontheightlog(p); + else + lines = height * fontheight(p); + if (sx == 0 && width * 4 == bytes) { - offset = sy * bytes * p->fontheight; + if (fontheightlog(p)) + offset = (sy * bytes) << fontheightlog(p); + else + offset = sy * bytes * fontheight(p); size = lines * bytes; memset_even_4p(p->screen_base+offset, size, cval1, cval2); } else { - offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1); + if (fontheightlog(p)) + offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*8 + (sx & 1); + else + offset = sy * bytes * fontheight(p) + (sx>>1)*8 + (sx & 1); start = p->screen_base + offset; pcval = expand4l(attr_bgcol_ec(p,conp)); @@ -316,14 +334,21 @@ void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c, int bytes = p->next_line; u32 eorx, fgx, bgx, fdx; - dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1); - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + if (fontheightlog(p)) { + dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*8 + (xx & 1)); + cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p)); + } else { + dest = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*8 + (xx & 1)); + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + } fgx = expand4l(attr_fgcol(p,c)); bgx = expand4l(attr_bgcol(p,c)); eorx = fgx ^ bgx; - for(rows = p->fontheight ; rows-- ; dest += bytes) { + for(rows = fontheight(p) ; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); movepl(dest, (fdx & eorx) ^ bgx); } @@ -340,7 +365,12 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p, u32 eorx, fgx, bgx, fdx; bytes = p->next_line; - dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1); + if (fontheightlog(p)) + dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*8 + (xx & 1)); + else + dest0 = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*8 + (xx & 1)); fgx = expand4l(attr_fgcol(p,*s)); bgx = expand4l(attr_bgcol(p,*s)); eorx = fgx ^ bgx; @@ -354,9 +384,12 @@ void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p, */ c = *s++ & p->charmask; - cdat = p->fontdata + (c * p->fontheight); + if (fontheightlog(p)) + cdat = p->fontdata + (c << fontheightlog(p)); + else + cdat = p->fontdata + c * fontheight(p); - for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for(rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); movepl(dest, (fdx & eorx) ^ bgx); } @@ -370,9 +403,13 @@ void fbcon_iplan2p4_revc(struct display *p, int xx, int yy) int j; int bytes; - dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*8 + - (xx & 1); - j = p->fontheight; + if (fontheightlog(p)) + dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) + + (xx>>1)*8 + (xx & 1)); + else + dest = (p->screen_base + yy * p->next_line * fontheight(p) + + (xx>>1)*8 + (xx & 1)); + j = fontheight(p); bytes = p->next_line; while (j--) { @@ -388,6 +425,30 @@ void fbcon_iplan2p4_revc(struct display *p, int xx, int yy) } } +void fbcon_iplan2p4_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + u32 offset; + int bytes; + int lines; + u32 cval1, cval2; + +/* No need to handle right margin, cannot occur with fontwidth == 8 */ + + bytes = p->next_line; + if (fontheightlog(p)) { + lines = p->var.yres - (conp->vc_rows << fontheightlog(p)); + offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p); + } else { + lines = p->var.yres - conp->vc_rows * fontheight(p); + offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p); + } + if (lines) { + expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); + memset_even_4p(p->screen_base+offset, lines * bytes, cval1, cval2); + } +} + /* * `switch' for the low level operations @@ -396,7 +457,7 @@ void fbcon_iplan2p4_revc(struct display *p, int xx, int yy) struct display_switch fbcon_iplan2p4 = { fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear, fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc, NULL, - NULL, NULL, FONTWIDTH(8) + NULL, fbcon_iplan2p4_clear_margins, FONTWIDTH(8) }; @@ -422,3 +483,4 @@ EXPORT_SYMBOL(fbcon_iplan2p4_clear); EXPORT_SYMBOL(fbcon_iplan2p4_putc); EXPORT_SYMBOL(fbcon_iplan2p4_putcs); EXPORT_SYMBOL(fbcon_iplan2p4_revc); +EXPORT_SYMBOL(fbcon_iplan2p4_clear_margins); diff --git a/drivers/video/fbcon-iplan2p4.h b/drivers/video/fbcon-iplan2p4.h deleted file mode 100644 index 6d501a58e..000000000 --- a/drivers/video/fbcon-iplan2p4.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Atari interleaved bitplanes (4 planes) (iplan2p4) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE) -#define FBCON_HAS_IPLAN2P4 -#endif -#else -#if defined(CONFIG_FBCON_IPLAN2P4) -#define FBCON_HAS_IPLAN2P4 -#endif -#endif - -extern struct display_switch fbcon_iplan2p4; -extern void fbcon_iplan2p4_setup(struct display *p); -extern void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p, - int sy, int sx, int height, int width); -extern void fbcon_iplan2p4_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_iplan2p4_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_iplan2p4_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-iplan2p8.c b/drivers/video/fbcon-iplan2p8.c index aa2f4d2f1..dbdd56ac8 100644 --- a/drivers/video/fbcon-iplan2p8.c +++ b/drivers/video/fbcon-iplan2p8.c @@ -19,8 +19,8 @@ #include <asm/byteorder.h> -#include "fbcon.h" -#include "fbcon-iplan2p8.h" +#include <video/fbcon.h> +#include <video/fbcon-iplan2p8.h> /* @@ -209,18 +209,25 @@ void fbcon_iplan2p8_bmove(struct display *p, int sy, int sx, int dy, int dx, /* Special (but often used) case: Moving whole lines can be * done with memmove() */ - fast_memmove(p->screen_base + dy * p->next_line * p->fontheight, - p->screen_base + sy * p->next_line * p->fontheight, - p->next_line * height * p->fontheight); + fast_memmove(p->screen_base + dy * p->next_line * fontheight(p), + p->screen_base + sy * p->next_line * fontheight(p), + p->next_line * height * fontheight(p)); } else { int rows, cols; u8 *src; u8 *dst; int bytes = p->next_line; - int linesize = bytes * p->fontheight; - u_int colsize = height * p->fontheight; + int linesize; + u_int colsize; u_int upwards = (dy < sy) || (dy == sy && dx < sx); + if (fontheightlog(p)) { + linesize = bytes << fontheightlog(p); + colsize = height << fontheightlog(p); + } else { + linesize = bytes * fontheight(p); + colsize = height * fontheight(p); + } if ((sx & 1) == (dx & 1)) { /* odd->odd or even->even */ @@ -301,18 +308,29 @@ void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p, int sy, u8 *start; int rows; int bytes = p->next_line; - int lines = height * p->fontheight; + int lines; u32 size; u32 cval1, cval2, cval3, cval4, pcval1, pcval2; expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4); + if (fontheightlog(p)) + lines = height << fontheightlog(p); + else + lines = height * fontheight(p); + if (sx == 0 && width * 8 == bytes) { - offset = sy * bytes * p->fontheight; + if (fontheightlog(p)) + offset = (sy * bytes) << fontheightlog(p); + else + offset = sy * bytes * fontheight(p); size = lines * bytes; memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4); } else { - offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1); + if (fontheightlog(p)) + offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*16 + (sx & 1); + else + offset = sy * bytes * fontheight(p) + (sx>>1)*16 + (sx & 1); start = p->screen_base + offset; expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2); @@ -348,14 +366,21 @@ void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c, int bytes = p->next_line; u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; - dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1); - cdat = p->fontdata + (c & p->charmask) * p->fontheight; + if (fontheightlog(p)) { + dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*16 + (xx & 1)); + cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p)); + } else { + dest = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*16 + (xx & 1)); + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + } expand8dl(attr_fgcol(p,c), &fgx1, &fgx2); expand8dl(attr_bgcol(p,c), &bgx1, &bgx2); eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; - for(rows = p->fontheight ; rows-- ; dest += bytes) { + for(rows = fontheight(p) ; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); movepl2(dest, (fdx & eorx1) ^ bgx1, (fdx & eorx2) ^ bgx2); } @@ -372,8 +397,12 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p, u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; bytes = p->next_line; - dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + - (xx & 1); + if (fontheightlog(p)) + dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) + + (xx>>1)*16 + (xx & 1)); + else + dest0 = (p->screen_base + yy * bytes * fontheight(p) + + (xx>>1)*16 + (xx & 1)); expand8dl(attr_fgcol(p,*s), &fgx1, &fgx2); expand8dl(attr_bgcol(p,*s), &bgx1, &bgx2); @@ -389,9 +418,12 @@ void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p, */ c = *s++ & p->charmask; - cdat = p->fontdata + (c * p->fontheight); + if (fontheightlog(p)) + cdat = p->fontdata + (c << fontheightlog(p)); + else + cdat = p->fontdata + c * fontheight(p); - for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + for(rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); movepl2(dest, (fdx & eorx1) ^ bgx1, (fdx & eorx2) ^ bgx2); } @@ -405,9 +437,13 @@ void fbcon_iplan2p8_revc(struct display *p, int xx, int yy) int j; int bytes; - dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*16 + - (xx & 1); - j = p->fontheight; + if (fontheightlog(p)) + dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) + + (xx>>1)*16 + (xx & 1)); + else + dest = (p->screen_base + yy * p->next_line * fontheight(p) + + (xx>>1)*16 + (xx & 1)); + j = fontheight(p); bytes = p->next_line; while (j--) { @@ -425,6 +461,31 @@ void fbcon_iplan2p8_revc(struct display *p, int xx, int yy) } } +void fbcon_iplan2p8_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + u32 offset; + int bytes; + int lines; + u32 cval1, cval2, cval3, cval4; + +/* No need to handle right margin, cannot occur with fontwidth == 8 */ + + bytes = p->next_line; + if (fontheightlog(p)) { + lines = p->var.yres - (conp->vc_rows << fontheightlog(p)); + offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p); + } else { + lines = p->var.yres - conp->vc_rows * fontheight(p); + offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p); + } + if (lines) { + expand8ql(attr_bgcol_ec(p,conp), &cval1, &cval2, &cval3, &cval4); + memset_even_8p(p->screen_base+offset, lines * bytes, + cval1, cval2, cval3, cval4); + } +} + /* * `switch' for the low level operations @@ -433,7 +494,7 @@ void fbcon_iplan2p8_revc(struct display *p, int xx, int yy) struct display_switch fbcon_iplan2p8 = { fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear, fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc, NULL, - NULL, NULL, FONTWIDTH(8) + NULL, fbcon_iplan2p8_clear_margins, FONTWIDTH(8) }; @@ -459,3 +520,4 @@ EXPORT_SYMBOL(fbcon_iplan2p8_clear); EXPORT_SYMBOL(fbcon_iplan2p8_putc); EXPORT_SYMBOL(fbcon_iplan2p8_putcs); EXPORT_SYMBOL(fbcon_iplan2p8_revc); +EXPORT_SYMBOL(fbcon_iplan2p8_clear_margins); diff --git a/drivers/video/fbcon-iplan2p8.h b/drivers/video/fbcon-iplan2p8.h deleted file mode 100644 index ba298f84c..000000000 --- a/drivers/video/fbcon-iplan2p8.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Atari interleaved bitplanes (8 planes) (iplan2p8) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE) -#define FBCON_HAS_IPLAN2P8 -#endif -#else -#if defined(CONFIG_FBCON_IPLAN2P8) -#define FBCON_HAS_IPLAN2P8 -#endif -#endif - -extern struct display_switch fbcon_iplan2p8; -extern void fbcon_iplan2p8_setup(struct display *p); -extern void fbcon_iplan2p8_bmove(struct display *p, int sy, int sx, int dy, - int dx, int height, int width); -extern void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p, - int sy, int sx, int height, int width); -extern void fbcon_iplan2p8_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_iplan2p8_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_iplan2p8_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c index a4bac8fae..f2508e4cb 100644 --- a/drivers/video/fbcon-mac.c +++ b/drivers/video/fbcon-mac.c @@ -19,8 +19,8 @@ #include <linux/fb.h> #include <linux/delay.h> -#include "fbcon.h" -#include "fbcon-mac.h" +#include <video/fbcon.h> +#include <video/fbcon-mac.h> /* @@ -57,24 +57,24 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx, int dl,dr,dt,db,dw,dlo; int move_up; - src = (u8 *) (p->screen_base + sy * p->fontheight * p->next_line); - dest = (u8 *) (p->screen_base + dy * p->fontheight * p->next_line); + src = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line); + dest = (u8 *) (p->screen_base + dy * fontheight(p) * p->next_line); if( sx == 0 && width == p->conp->vc_cols) { - s = height * p->fontheight * p->next_line; + s = height * fontheight(p) * p->next_line; mymemmove(dest, src, s); return; } - l = sx * p->fontwidth; - r = l + width * p->fontwidth; - t = sy * p->fontheight; - b = t + height * p->fontheight; + l = sx * fontwidth(p); + r = l + width * fontwidth(p); + t = sy * fontheight(p); + b = t + height * fontheight(p); - dl = dx * p->fontwidth; - dr = dl + width * p->fontwidth; - dt = dy * p->fontheight; - db = dt + height * p->fontheight; + dl = dx * fontwidth(p); + dr = dl + width * fontwidth(p); + dt = dy * fontheight(p); + db = dt + height * fontheight(p); /* w is the # pixels between two long-aligned points, left and right */ w = (r&~31) - ((l+31)&~31); @@ -143,8 +143,8 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx, if (sy <= sx) { i = b; move_up = 0; - src += height * p->fontheight; - dest += height * p->fontheight; + src += height * fontheight(p); + dest += height * fontheight(p); } else { i = t; move_up = 1; @@ -195,22 +195,22 @@ void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx, u8 *dest; int l,r,t,b,w,lo,s; - inverse = attr_reverse(p,conp->vc_attr); + inverse = conp ? attr_reverse(p,conp->vc_attr) : 0; pixel = inverse ? PIXEL_WHITE_MAC : PIXEL_BLACK_MAC; - dest = (u8 *) (p->screen_base + sy * p->fontheight * p->next_line); + dest = (u8 *) (p->screen_base + sy * fontheight(p) * p->next_line); if( sx == 0 && width == p->conp->vc_cols) { - s = height * p->fontheight * p->next_line; + s = height * fontheight(p) * p->next_line; if (inverse) mymemclear(dest, s); else mymemset(dest, s); } - l = sx * p->fontwidth; - r = l + width * p->fontwidth; - t = sy * p->fontheight; - b = t + height * p->fontheight; + l = sx * fontwidth(p); + r = l + width * fontwidth(p); + t = sy * fontheight(p); + b = t + height * fontheight(p); /* w is the # pixels between two long-aligned points, left and right */ w = (r&~31) - ((l+31)&~31); /* lo is the # pixels between the left edge and a long-aligned left pixel */ @@ -272,23 +272,23 @@ void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, int yy, u8 d; int j; - cdat = p->fontdata+(c&p->charmask)*p->fontheight; + cdat = p->fontdata+(c&p->charmask)*fontheight(p); bold = attr_bold(p,c); ch_reverse = attr_reverse(p,c); ch_underline = attr_underline(p,c); - for (rows = 0; rows < p->fontheight; rows++) { + for (rows = 0; rows < fontheight(p); rows++) { d = *cdat++; if (!conp->vc_can_do_color) { - if (ch_underline && rows == (p->fontheight-2)) + if (ch_underline && rows == (fontheight(p)-2)) d = 0xff; else if (bold) d |= d>>1; if (ch_reverse) d = ~d; } - for (j = 0; j < p->fontwidth; j++) { - plot_pixel_mac(p, (d & 0x80) >> 7, (xx*p->fontwidth) + j, (yy*p->fontheight) + rows); + for (j = 0; j < fontwidth(p); j++) { + plot_pixel_mac(p, (d & 0x80) >> 7, (xx*fontwidth(p)) + j, (yy*fontheight(p)) + rows); d <<= 1; } } @@ -311,9 +311,9 @@ void fbcon_mac_revc(struct display *p, int xx, int yy) { u_int rows, j; - for (rows = 0; rows < p->fontheight; rows++) { - for (j = 0; j < p->fontwidth; j++) { - plot_pixel_mac (p, PIXEL_INVERT_MAC, (xx*p->fontwidth)+j, (yy*p->fontheight)+rows); + for (rows = 0; rows < fontheight(p); rows++) { + for (j = 0; j < fontwidth(p); j++) { + plot_pixel_mac (p, PIXEL_INVERT_MAC, (xx*fontwidth(p))+j, (yy*fontheight(p))+rows); } } } diff --git a/drivers/video/fbcon-mac.h b/drivers/video/fbcon-mac.h deleted file mode 100644 index 62d2ae6d3..000000000 --- a/drivers/video/fbcon-mac.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Mac variable bpp packed pixels (mac) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE) -#define FBCON_HAS_MAC -#endif -#else -#if defined(CONFIG_FBCON_MAC) -#define FBCON_HAS_MAC -#endif -#endif - -extern struct display_switch fbcon_mac; -extern void fbcon_mac_setup(struct display *p); -extern void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_mac_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_mac_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_mac_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c index b8f575859..32f1ea8d4 100644 --- a/drivers/video/fbcon-mfb.c +++ b/drivers/video/fbcon-mfb.c @@ -15,8 +15,8 @@ #include <linux/string.h> #include <linux/fb.h> -#include "fbcon.h" -#include "fbcon-mfb.h" +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> /* @@ -39,21 +39,21 @@ void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx, u_int rows; if (sx == 0 && dx == 0 && width == p->next_line) { - src = p->screen_base+sy*p->fontheight*width; - dest = p->screen_base+dy*p->fontheight*width; - mymemmove(dest, src, height*p->fontheight*width); + src = p->screen_base+sy*fontheight(p)*width; + dest = p->screen_base+dy*fontheight(p)*width; + mymemmove(dest, src, height*fontheight(p)*width); } else if (dy <= sy) { - src = p->screen_base+sy*p->fontheight*p->next_line+sx; - dest = p->screen_base+dy*p->fontheight*p->next_line+dx; - for (rows = height*p->fontheight; rows--;) { + src = p->screen_base+sy*fontheight(p)*p->next_line+sx; + dest = p->screen_base+dy*fontheight(p)*p->next_line+dx; + for (rows = height*fontheight(p); rows--;) { mymemmove(dest, src, width); src += p->next_line; dest += p->next_line; } } else { - src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx; - dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx; - for (rows = height*p->fontheight; rows--;) { + src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx; + dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx; + for (rows = height*fontheight(p); rows--;) { mymemmove(dest, src, width); src -= p->next_line; dest -= p->next_line; @@ -66,17 +66,18 @@ void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, int sx, { u8 *dest; u_int rows; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; - dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+sy*fontheight(p)*p->next_line+sx; if (sx == 0 && width == p->next_line) { - if (attr_reverse(p,conp->vc_attr)) - mymemset(dest, height*p->fontheight*width); + if (inverse) + mymemset(dest, height*fontheight(p)*width); else - mymemclear(dest, height*p->fontheight*width); + mymemclear(dest, height*fontheight(p)*width); } else - for (rows = height*p->fontheight; rows--; dest += p->next_line) - if (attr_reverse(p,conp->vc_attr)) + for (rows = height*fontheight(p); rows--; dest += p->next_line) + if (inverse) mymemset(dest, width); else mymemclear_small(dest, width); @@ -89,13 +90,13 @@ void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy, u_int rows, bold, revs, underl; u8 d; - dest = p->screen_base+yy*p->fontheight*p->next_line+xx; - cdat = p->fontdata+(c&p->charmask)*p->fontheight; + dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; + cdat = p->fontdata+(c&p->charmask)*fontheight(p); bold = attr_bold(p,c); revs = attr_reverse(p,c); underl = attr_underline(p,c); - for (rows = p->fontheight; rows--; dest += p->next_line) { + for (rows = fontheight(p); rows--; dest += p->next_line) { d = *cdat++; if (underl && !rows) d = 0xff; @@ -115,7 +116,7 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, u8 d; u16 c; - dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; bold = attr_bold(p,*s); revs = attr_reverse(p,*s); underl = attr_underline(p,*s); @@ -123,8 +124,8 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, while (count--) { c = *s++ & p->charmask; dest = dest0++; - cdat = p->fontdata+c*p->fontheight; - for (rows = p->fontheight; rows--; dest += p->next_line) { + cdat = p->fontdata+c*fontheight(p); + for (rows = fontheight(p); rows--; dest += p->next_line) { d = *cdat++; if (underl && !rows) d = 0xff; @@ -142,11 +143,33 @@ void fbcon_mfb_revc(struct display *p, int xx, int yy) u8 *dest; u_int rows; - dest = p->screen_base+yy*p->fontheight*p->next_line+xx; - for (rows = p->fontheight; rows--; dest += p->next_line) + dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; + for (rows = fontheight(p); rows--; dest += p->next_line) *dest = ~*dest; } +void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p, + int bottom_only) +{ + u8 *dest; + int height, bottom; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; + + /* XXX Need to handle right margin? */ + + height = p->var.yres - conp->vc_rows * fontheight(p); + if (!height) + return; + bottom = conp->vc_rows + p->yscroll; + if (bottom >= p->vrows) + bottom -= p->vrows; + dest = p->screen_base + bottom * fontheight(p) * p->next_line; + if (inverse) + mymemset(dest, height * p->next_line); + else + mymemclear(dest, height * p->next_line); +} + /* * `switch' for the low level operations @@ -154,7 +177,8 @@ void fbcon_mfb_revc(struct display *p, int xx, int yy) struct display_switch fbcon_mfb = { fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc, - fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, NULL, FONTWIDTH(8) + fbcon_mfb_putcs, fbcon_mfb_revc, NULL, NULL, fbcon_mfb_clear_margins, + FONTWIDTH(8) }; @@ -180,3 +204,4 @@ EXPORT_SYMBOL(fbcon_mfb_clear); EXPORT_SYMBOL(fbcon_mfb_putc); EXPORT_SYMBOL(fbcon_mfb_putcs); EXPORT_SYMBOL(fbcon_mfb_revc); +EXPORT_SYMBOL(fbcon_mfb_clear_margins); diff --git a/drivers/video/fbcon-mfb.h b/drivers/video/fbcon-mfb.h deleted file mode 100644 index 77f312e31..000000000 --- a/drivers/video/fbcon-mfb.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Monochrome (mfb) - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE) -#define FBCON_HAS_MFB -#endif -#else -#if defined(CONFIG_FBCON_MFB) -#define FBCON_HAS_MFB -#endif -#endif - -extern struct display_switch fbcon_mfb; -extern void fbcon_mfb_setup(struct display *p); -extern void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_mfb_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_mfb_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon-vga.c b/drivers/video/fbcon-vga.c index 3ea8a5234..fa4d387b8 100644 --- a/drivers/video/fbcon-vga.c +++ b/drivers/video/fbcon-vga.c @@ -18,8 +18,8 @@ #include <asm/io.h> -#include "fbcon.h" -#include "fbcon-vga.h" +#include <video/fbcon.h> +#include <video/fbcon-vga.h> /* diff --git a/drivers/video/fbcon-vga.h b/drivers/video/fbcon-vga.h deleted file mode 100644 index 7d62e213c..000000000 --- a/drivers/video/fbcon-vga.h +++ /dev/null @@ -1,27 +0,0 @@ - /* - * VGA characters/attributes - */ - -#include <linux/config.h> - -#ifdef MODULE -#if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE) -#define FBCON_HAS_VGA -#endif -#else -#if defined(CONFIG_FBCON_VGA) -#define FBCON_HAS_VGA -#endif -#endif - -extern struct display_switch fbcon_vga; -extern void fbcon_vga_setup(struct display *p); -extern void fbcon_vga_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); -extern void fbcon_vga_clear(struct vc_data *conp, struct display *p, int sy, - int sx, int height, int width); -extern void fbcon_vga_putc(struct vc_data *conp, struct display *p, int c, - int yy, int xx); -extern void fbcon_vga_putcs(struct vc_data *conp, struct display *p, - const unsigned short *s, int count, int yy, int xx); -extern void fbcon_vga_revc(struct display *p, int xx, int yy); diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c index c2b7abd51..9bdc9020b 100644 --- a/drivers/video/fbcon.c +++ b/drivers/video/fbcon.c @@ -29,6 +29,8 @@ * added by * Jakub Jelinek (jj@ultra.linux.cz) * + * Random hacking by Martin Mares <mj@ucw.cz> + * * * The low level operations for the various display memory organizations are * now in separate source files. @@ -54,8 +56,6 @@ #undef FBCONDEBUG -#define FLASHING_CURSOR 1 - #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -94,9 +94,9 @@ #define INCLUDE_LINUX_LOGO_DATA #include <asm/linux_logo.h> -#include "fbcon.h" -#include "fbcon-mac.h" /* for 6x11 font on mac */ -#include "font.h" +#include <video/fbcon.h> +#include <video/fbcon-mac.h> /* for 6x11 font on mac */ +#include <video/font.h> #ifdef FBCONDEBUG # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) @@ -112,6 +112,14 @@ struct display fb_display[MAX_NR_CONSOLES]; static int logo_lines; static int logo_shown = -1; +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FNTSUM(fd) (((int *)(fd))[-4]) +#define FONT_EXTRA_WORDS 4 + +static void fbcon_free_font(struct display *p); + /* * Emmanuel: fbcon will now use a hardware cursor if the * low-level driver provides a non-NULL dispsw->cursor pointer, @@ -120,12 +128,12 @@ static int logo_shown = -1; * if dispsw->cursor is NULL, use Atari alike software cursor */ -#if FLASHING_CURSOR static int cursor_drawn = 0; -#define CURSOR_DRAW_DELAY (2) +#define CURSOR_DRAW_DELAY (1) /* # VBL ints between cursor state changes */ +#define ARM_CURSOR_BLINK_RATE (10) #define AMIGA_CURSOR_BLINK_RATE (20) #define ATARI_CURSOR_BLINK_RATE (42) #define MAC_CURSOR_BLINK_RATE (32) @@ -135,16 +143,12 @@ static int vbl_cursor_cnt = 0; static int cursor_on = 0; static int cursor_blink_rate; -static __inline__ void CURSOR_UNDRAWN(void) +static inline void cursor_undrawn(void) { vbl_cursor_cnt = 0; cursor_drawn = 0; } -#endif -/* - * Scroll Method - */ #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) @@ -180,9 +184,7 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines); static void fbcon_setup(int con, int init, int logo); static __inline__ int real_y(struct display *p, int ypos); -#if FLASHING_CURSOR static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp); -#endif static __inline__ void updatescrollmode(struct display *p); static __inline__ void ywrap_up(int unit, struct vc_data *conp, struct display *p, int count); @@ -197,8 +199,6 @@ static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, static int fbcon_show_logo(void); -#if FLASHING_CURSOR - #ifdef CONFIG_MAC /* * On the Macintoy, there may or may not be a working VBL int. We need to prob @@ -225,13 +225,12 @@ static void cursor_timer_handler(unsigned long dev_addr) cursor_timer.next = cursor_timer.next = NULL; add_timer(&cursor_timer); } -#endif /* * Low Level Operations */ -static struct display_switch fbcon_dummy; +struct display_switch fbcon_dummy; /* NOTE: fbcon cannot be __initfunc: it may be called from take_over_console later */ @@ -271,39 +270,43 @@ static const char *fbcon_startup(void) * probe for VBL interrupts. */ if (MACH_IS_MAC) { - int ct = 0; - /* - * Probe for VBL: set temp. handler ... - */ - irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0, - "console/cursor", fbcon_vbl_detect); - /* - * ... and spin for 20 ms ... - */ - while (!vbl_detected && ++ct<1000) - udelay(20); + int ct = 0; + /* + * Probe for VBL: set temp. handler ... + */ + irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0, + "console/cursor", fbcon_vbl_detect); + vbl_detected = 0; + + /* + * ... and spin for 20 ms ... + */ + while (!vbl_detected && ++ct<1000) + udelay(20); - if(ct==1000) - printk("fbcon_startup: No VBL detected, using timer based cursor.\n"); + if(ct==1000) + printk("fbcon_startup: No VBL detected, using timer based cursor.\n"); - if (vbl_detected) { - /* - * interrupt based cursor ok - */ - cursor_blink_rate = MAC_CURSOR_BLINK_RATE; - irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0, - "console/cursor", fbcon_vbl_handler); - } else { - /* - * VBL not detected: fall through, use timer based cursor - */ - irqres = 1; - /* free interrupt here ?? */ - } + free_irq(IRQ_MAC_VBL, fbcon_vbl_detect); + + if (vbl_detected) { + /* + * interrupt based cursor ok + */ + cursor_blink_rate = MAC_CURSOR_BLINK_RATE; + irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0, + "console/cursor", fbcon_vbl_handler); + } else { + /* + * VBL not detected: fall through, use timer based cursor + */ + irqres = 1; + } } #endif /* CONFIG_MAC */ #if defined(__arm__) && defined(IRQ_VSYNCPULSE) + cursor_blink_rate = ARM_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, SA_SHIRQ, "console/cursor", fbcon_vbl_handler); #endif @@ -329,9 +332,6 @@ static void fbcon_init(struct vc_data *conp, int init) info = registered_fb[(int)con2fb_map[unit]]; info->changevar = &fbcon_changevar; - conp->vc_display_fg = &info->display_fg; - if (!info->display_fg) - info->display_fg = conp; fb_display[unit] = *(info->disp); /* copy from default */ DPRINTK("mode: %s\n",info->modename); DPRINTK("visual: %d\n",fb_display[unit].visual); @@ -340,7 +340,17 @@ static void fbcon_init(struct vc_data *conp, int init) fb_display[unit].var.bits_per_pixel); fb_display[unit].conp = conp; fb_display[unit].fb_info = info; + /* clear out the cmap so we don't have dangling pointers */ + fb_display[unit].cmap.len = 0; + fb_display[unit].cmap.red = 0; + fb_display[unit].cmap.green = 0; + fb_display[unit].cmap.blue = 0; + fb_display[unit].cmap.transp = 0; fbcon_setup(unit, init, !init); + /* Must be done after fbcon_setup to prevent excess updates */ + conp->vc_display_fg = &info->display_fg; + if (!info->display_fg) + info->display_fg = conp; } @@ -349,7 +359,8 @@ static void fbcon_deinit(struct vc_data *conp) int unit = conp->vc_num; struct display *p = &fb_display[unit]; - p->dispsw = NULL; + fbcon_free_font(p); + p->dispsw = &fbcon_dummy; p->conp = 0; } @@ -364,29 +375,34 @@ static int fbcon_changevar(int con) static __inline__ void updatescrollmode(struct display *p) { - if (p->scrollmode == SCROLL_YREDRAW) + int m; + if (p->scrollmode & __SCROLL_YFIXED) return; - if (divides(p->ywrapstep, p->fontheight) && - divides(p->fontheight, p->var.yres_virtual)) - p->scrollmode = SCROLL_YWRAP; - else if (divides(p->ypanstep, p->fontheight) && - p->var.yres_virtual >= p->var.yres+p->fontheight) - p->scrollmode = SCROLL_YPAN; + if (divides(p->ywrapstep, fontheight(p)) && + divides(fontheight(p), p->var.yres_virtual)) + m = __SCROLL_YWRAP; + else if (divides(p->ypanstep, fontheight(p)) && + p->var.yres_virtual >= p->var.yres+fontheight(p)) + m = __SCROLL_YPAN; + else if (p->scrollmode & __SCROLL_YNOMOVE) + m = __SCROLL_YREDRAW; else - p->scrollmode = SCROLL_YMOVE; + m = __SCROLL_YMOVE; + p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m; } static void fbcon_font_widths(struct display *p) { int i; - p->fontwidthlog = 0; + + p->_fontwidthlog = 0; for (i = 2; i <= 6; i++) - if (p->fontwidth == (1 << i)) - p->fontwidthlog = i; - p->fontheightlog = 0; + if (fontwidth(p) == (1 << i)) + p->_fontwidthlog = i; + p->_fontheightlog = 0; for (i = 2; i <= 6; i++) - if (p->fontheight == (1 << i)) - p->fontheightlog = i; + if (fontheight(p) == (1 << i)) + p->_fontheightlog = i; } #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w)) @@ -398,22 +414,52 @@ static void fbcon_setup(int con, int init, int logo) int nr_rows, nr_cols; int old_rows, old_cols; unsigned short *save = NULL, *r, *q; - /* Only if not module */ - int initmem_freed = 1; + int i, charcnt = 256; struct fbcon_font_desc *font; - if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT) + + if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) || + p->type == FB_TYPE_TEXT) logo = 0; p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + + for (i = 0; i < MAX_NR_CONSOLES; i++) + if (i != con && fb_display[i].fb_info == p->fb_info && + fb_display[i].conp && fb_display[i].fontdata) + break; + + fbcon_free_font(p); + if (i < MAX_NR_CONSOLES) { + struct display *q = &fb_display[i]; + + if (fontwidthvalid(p,fontwidth(q))) { + /* If we are not the first console on this + fb, copy the font from that console */ + p->_fontwidth = q->_fontwidth; + p->_fontheight = q->_fontheight; + p->_fontwidthlog = q->_fontwidthlog; + p->_fontheightlog = q->_fontheightlog; + p->fontdata = q->fontdata; + p->userfont = q->userfont; + if (p->userfont) { + REFCOUNT(p->fontdata)++; + charcnt = FNTCHARCNT(p->fontdata); + } + con_copy_unimap(con, i); + } + } - if (!p->fb_info->fontname[0] || - !(font = fbcon_find_font(p->fb_info->fontname))) - font = fbcon_get_default_font(p->var.xres, p->var.yres); - p->fontwidth = font->width; - p->fontheight = font->height; - p->fontdata = font->data; - fbcon_font_widths(p); - if (!fontwidthvalid(p,p->fontwidth)) { + if (!p->fontdata) { + if (!p->fb_info->fontname[0] || + !(font = fbcon_find_font(p->fb_info->fontname))) + font = fbcon_get_default_font(p->var.xres, p->var.yres); + p->_fontwidth = font->width; + p->_fontheight = font->height; + p->fontdata = font->data; + fbcon_font_widths(p); + } + + if (!fontwidthvalid(p,fontwidth(p))) { #ifdef CONFIG_MAC if (MACH_IS_MAC) /* ++Geert: hack to make 6x11 fonts work on mac */ @@ -422,26 +468,26 @@ static void fbcon_setup(int con, int init, int logo) #endif { /* ++Geert: changed from panic() to `correct and continue' */ - printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", p->fontwidth); + printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p)); p->dispsw = &fbcon_dummy; } } if (p->dispsw->set_font) - p->dispsw->set_font(p, p->fontwidth, p->fontheight); + p->dispsw->set_font(p, fontwidth(p), fontheight(p)); updatescrollmode(p); old_cols = conp->vc_cols; old_rows = conp->vc_rows; - nr_cols = p->var.xres/p->fontwidth; - nr_rows = p->var.yres/p->fontheight; + nr_cols = p->var.xres/fontwidth(p); + nr_rows = p->var.yres/fontheight(p); if (logo) { /* Need to make room for the logo */ int cnt; int step; - logo_lines = (LOGO_H + p->fontheight - 1) / p->fontheight; + logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p); q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); step = logo_lines * old_cols; for (r = q - logo_lines * old_cols; r < q; r++) @@ -454,7 +500,7 @@ static void fbcon_setup(int con, int init, int logo) scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2); r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i) - scr_memcpyw(save + cnt * nr_cols, r, 2 * i); + scr_memcpyw_to(save + cnt * nr_cols, r, 2 * i); r = q; } } @@ -483,42 +529,53 @@ static void fbcon_setup(int con, int init, int logo) conp->vc_cols = nr_cols; conp->vc_rows = nr_rows; } - p->vrows = p->var.yres_virtual/p->fontheight; + p->vrows = p->var.yres_virtual/fontheight(p); + if ((p->var.yres % fontheight(p)) && + (p->var.yres_virtual % fontheight(p) < p->var.yres % fontheight(p))) + p->vrows--; conp->vc_can_do_color = p->var.bits_per_pixel != 1; - p->fgshift = 8; - p->bgshift = 12; - p->charmask = 0xff; - conp->vc_hi_font_mask = 0; + conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800; + if (charcnt == 256) { + p->conp->vc_hi_font_mask = 0; + p->fgshift = 8; + p->bgshift = 12; + p->charmask = 0xff; + } else { + p->conp->vc_hi_font_mask = 0x100; + p->conp->vc_complement_mask <<= 1; + p->fgshift = 9; + p->bgshift = 13; + p->charmask = 0x1ff; + } - if (!p->dispsw) { + if (p->dispsw == &fbcon_dummy) printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not " "supported\n", p->type, p->type_aux, p->var.bits_per_pixel); - p->dispsw = &fbcon_dummy; - } p->dispsw->setup(p); p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1; p->bgcol = 0; if (!init) { - if (con == fg_console) - set_palette(); /* Unlike vgacon, we have to set palette before resize on directcolor, - so that it is drawn with correct colors */ - vc_resize_con(nr_rows, nr_cols, con); + if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows) + vc_resize_con(nr_rows, nr_cols, con); + else if (CON_IS_VISIBLE(conp) && + vt_cons[conp->vc_num]->vc_mode == KD_TEXT) { + if (p->dispsw->clear_margins) + p->dispsw->clear_margins(conp, p, 0); + update_screen(con); + } if (save) { q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows); - scr_memcpyw(q, save, logo_lines * nr_cols * 2); + scr_memcpyw_from(q, save, logo_lines * nr_cols * 2); conp->vc_y += logo_lines; conp->vc_pos += logo_lines * conp->vc_size_row; kfree(save); } - if (con == fg_console) - update_screen(con); /* So that we set origin correctly */ } if (logo) { - logo_shown = fg_console; - fbcon_show_logo(); /* This is protected above by initmem_freed */ + logo_shown = -2; conp->vc_top = logo_lines; } } @@ -574,7 +631,7 @@ static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height, if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) && (sx <= p->cursor_x) && (p->cursor_x < sx+width)) { - CURSOR_UNDRAWN(); + cursor_undrawn(); redraw_cursor = 1; } @@ -601,9 +658,12 @@ static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos) if (!p->can_soft_blank && console_blanked) return; + + if (vt_cons[unit]->vc_mode != KD_TEXT) + return; if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) { - CURSOR_UNDRAWN(); + cursor_undrawn(); redraw_cursor = 1; } @@ -624,9 +684,12 @@ static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count if (!p->can_soft_blank && console_blanked) return; + if (vt_cons[unit]->vc_mode != KD_TEXT) + return; + if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) && (p->cursor_x < (xpos + count))) { - CURSOR_UNDRAWN(); + cursor_undrawn(); redraw_cursor = 1; } p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos); @@ -653,29 +716,28 @@ static void fbcon_cursor(struct vc_data *conp, int mode) (mode == CM_ERASE) == !cursor_on) return; - cursor_on = 0; - if (cursor_drawn) - p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y)); - - p->cursor_x = conp->vc_x; - p->cursor_y = conp->vc_y; - - switch (mode) { - case CM_ERASE: - cursor_drawn = 0; - break; - case CM_MOVE: - case CM_DRAW: - if (cursor_drawn) - p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y)); - vbl_cursor_cnt = CURSOR_DRAW_DELAY; - cursor_on = 1; - break; - } + cursor_on = 0; + if (cursor_drawn) + p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y)); + + p->cursor_x = conp->vc_x; + p->cursor_y = conp->vc_y; + + switch (mode) { + case CM_ERASE: + cursor_drawn = 0; + break; + case CM_MOVE: + case CM_DRAW: + if (cursor_drawn) + p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y)); + vbl_cursor_cnt = CURSOR_DRAW_DELAY; + cursor_on = 1; + break; + } } -#if FLASHING_CURSOR static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp) { struct display *p; @@ -691,7 +753,6 @@ static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp) vbl_cursor_cnt = cursor_blink_rate; } } -#endif static int scrollback_phys_max = 0; static int scrollback_max = 0; @@ -704,7 +765,7 @@ static __inline__ void ywrap_up(int unit, struct vc_data *conp, if (p->yscroll >= p->vrows) /* Deal with wrap */ p->yscroll -= p->vrows; p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; + p->var.yoffset = p->yscroll*fontheight(p); p->var.vmode |= FB_VMODE_YWRAP; p->fb_info->updatevar(unit, p->fb_info); scrollback_max += count; @@ -721,7 +782,7 @@ static __inline__ void ywrap_down(int unit, struct vc_data *conp, if (p->yscroll < 0) /* Deal with wrap */ p->yscroll += p->vrows; p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; + p->var.yoffset = p->yscroll*fontheight(p); p->var.vmode |= FB_VMODE_YWRAP; p->fb_info->updatevar(unit, p->fb_info); scrollback_max -= count; @@ -741,9 +802,11 @@ static __inline__ void ypan_up(int unit, struct vc_data *conp, p->yscroll -= p->vrows-conp->vc_rows; } p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; + p->var.yoffset = p->yscroll*fontheight(p); p->var.vmode &= ~FB_VMODE_YWRAP; p->fb_info->updatevar(unit, p->fb_info); + if (p->dispsw->clear_margins) + p->dispsw->clear_margins(conp, p, 1); scrollback_max += count; if (scrollback_max > scrollback_phys_max) scrollback_max = scrollback_phys_max; @@ -761,9 +824,11 @@ static __inline__ void ypan_down(int unit, struct vc_data *conp, p->yscroll += p->vrows-conp->vc_rows; } p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; + p->var.yoffset = p->yscroll*fontheight(p); p->var.vmode &= ~FB_VMODE_YWRAP; p->fb_info->updatevar(unit, p->fb_info); + if (p->dispsw->clear_margins) + p->dispsw->clear_margins(conp, p, 1); scrollback_max -= count; if (scrollback_max < 0) scrollback_max = 0; @@ -777,6 +842,7 @@ static void fbcon_redraw(struct vc_data *conp, struct display *p, unsigned short *d = (unsigned short *) (conp->vc_origin + conp->vc_size_row * line); unsigned short *s = d + offset; + while (count--) { unsigned short *start = s; unsigned short *le = (unsigned short *) @@ -790,14 +856,16 @@ static void fbcon_redraw(struct vc_data *conp, struct display *p, if (attr != (c & 0xff00)) { attr = c & 0xff00; if (s > start) { - p->dispsw->putcs(conp, p, start, s - start, line, x); + p->dispsw->putcs(conp, p, start, s - start, + real_y(p, line), x); x += s - start; start = s; } } if (c == scr_readw(d)) { if (s > start) { - p->dispsw->putcs(conp, p, start, s - start, line, x); + p->dispsw->putcs(conp, p, start, s - start, + real_y(p, line), x); x += s - start + 1; start = s + 1; } else { @@ -810,7 +878,7 @@ static void fbcon_redraw(struct vc_data *conp, struct display *p, d++; } while (s < le); if (s > start) - p->dispsw->putcs(conp, p, start, s - start, line, x); + p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x); if (offset > 0) line++; else { @@ -828,6 +896,7 @@ void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h if (sy != dy) panic("fbcon_redraw_bmove width sy != dy"); /* h will be always 1, but it does not matter if we are more generic */ + while (h-- > 0) { struct vc_data *conp = p->conp; unsigned short *d = (unsigned short *) @@ -880,7 +949,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, if (!p->can_soft_blank && console_blanked) return 0; - if (!count) + if (!count || vt_cons[unit]->vc_mode != KD_TEXT) return 0; fbcon_cursor(conp, CM_ERASE); @@ -895,133 +964,119 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, case SM_UP: if (count > conp->vc_rows) /* Maximum realistic size */ count = conp->vc_rows; - if (vt_cons[unit]->vc_mode == KD_TEXT) - switch (p->scrollmode) { - case SCROLL_YWRAP: - if (b-t-count > 3*conp->vc_rows>>2) { - if (t > 0) - fbcon_bmove(conp, 0, 0, count, 0, t, - conp->vc_cols); - ywrap_up(unit, conp, p, count); - if (conp->vc_rows-b > 0) - fbcon_bmove(conp, b-count, 0, b, 0, - conp->vc_rows-b, conp->vc_cols); - } else - fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, - conp->vc_cols); - fbcon_clear(conp, b-count, 0, count, conp->vc_cols); - break; - - case SCROLL_YPAN: - if (( is_txt && (b-t == conp->vc_rows)) || - (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) { - if (t > 0) - fbcon_bmove(conp, 0, 0, count, 0, t, - conp->vc_cols); - ypan_up(unit, conp, p, count); - if (conp->vc_rows-b > 0) - fbcon_bmove(conp, b-count, 0, b, 0, - conp->vc_rows-b, conp->vc_cols); - } else - fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, - conp->vc_cols); - fbcon_clear(conp, b-count, 0, count, conp->vc_cols); - break; - - case SCROLL_YMOVE: - p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count, - conp->vc_cols); - p->dispsw->clear(conp, p, b-count, 0, count, - conp->vc_cols); - break; - case SCROLL_YREDRAW: - fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols); - p->dispsw->clear(conp, p, b-count, 0, count, - conp->vc_cols); - scr_memsetw((unsigned short *)(conp->vc_origin + - conp->vc_size_row * (b-count)), - conp->vc_video_erase_char, - conp->vc_size_row * count); - return 1; - } - else { - fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); + switch (p->scrollmode & __SCROLL_YMASK) { + case __SCROLL_YMOVE: + p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, b-count, 0, count, + conp->vc_cols); + break; + + case __SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, + conp->vc_cols); + ywrap_up(unit, conp, p, count); + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, + conp->vc_rows-b, conp->vc_cols); + } else if (p->scrollmode & __SCROLL_YPANREDRAW) + goto redraw_up; + else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case __SCROLL_YPAN: + if (( is_txt && (b-t == conp->vc_rows)) || + (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, + conp->vc_cols); + ypan_up(unit, conp, p, count); + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, + conp->vc_rows-b, conp->vc_cols); + } else if (p->scrollmode & __SCROLL_YPANREDRAW) + goto redraw_up; + else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case __SCROLL_YREDRAW: + redraw_up: + fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols); + p->dispsw->clear(conp, p, real_y(p, b-count), 0, + count, conp->vc_cols); + scr_memsetw((unsigned short *)(conp->vc_origin + + conp->vc_size_row * (b-count)), + conp->vc_video_erase_char, + conp->vc_size_row * count); + return 1; } break; case SM_DOWN: if (count > conp->vc_rows) /* Maximum realistic size */ count = conp->vc_rows; - if (vt_cons[unit]->vc_mode == KD_TEXT) - switch (p->scrollmode) { - case SCROLL_YWRAP: - if (b-t-count > 3*conp->vc_rows>>2) { - if (conp->vc_rows-b > 0) - fbcon_bmove(conp, b, 0, b-count, 0, - conp->vc_rows-b, conp->vc_cols); - ywrap_down(unit, conp, p, count); - if (t > 0) - fbcon_bmove(conp, count, 0, 0, 0, t, - conp->vc_cols); - } else - fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, - conp->vc_cols); - fbcon_clear(conp, t, 0, count, conp->vc_cols); - break; - - case SCROLL_YPAN: - if (( is_txt && (b-t == conp->vc_rows)) || - (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) { - if (conp->vc_rows-b > 0) - fbcon_bmove(conp, b, 0, b-count, 0, - conp->vc_rows-b, conp->vc_cols); - ypan_down(unit, conp, p, count); - if (t > 0) - fbcon_bmove(conp, count, 0, 0, 0, t, - conp->vc_cols); - } else - fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, - conp->vc_cols); - fbcon_clear(conp, t, 0, count, conp->vc_cols); - break; - - case SCROLL_YMOVE: - p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count, - conp->vc_cols); - p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols); - break; - - case SCROLL_YREDRAW: - fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols); - p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols); - scr_memsetw((unsigned short *)(conp->vc_origin + - conp->vc_size_row * t), - conp->vc_video_erase_char, - conp->vc_size_row * count); - return 1; - } - else { - /* - * Fixed bmove() should end Arno's frustration with copying? - * Confucius says: - * Man who copies in wrong direction, end up with trashed - * data - */ - fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); + switch (p->scrollmode & __SCROLL_YMASK) { + case __SCROLL_YMOVE: + p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, t, 0, + count, conp->vc_cols); + break; + + case __SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, + conp->vc_rows-b, conp->vc_cols); + ywrap_down(unit, conp, p, count); + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, + conp->vc_cols); + } else if (p->scrollmode & __SCROLL_YPANREDRAW) + goto redraw_down; + else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); fbcon_clear(conp, t, 0, count, conp->vc_cols); - } - break; + break; - case SM_LEFT: - fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count); - fbcon_clear(conp, 0, b-count, conp->vc_rows, count); - break; + case __SCROLL_YPAN: + if (( is_txt && (b-t == conp->vc_rows)) || + (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, + conp->vc_rows-b, conp->vc_cols); + ypan_down(unit, conp, p, count); + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, + conp->vc_cols); + } else if (p->scrollmode & __SCROLL_YPANREDRAW) + goto redraw_down; + else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; - case SM_RIGHT: - fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count); - fbcon_clear(conp, 0, t, conp->vc_rows, count); - break; + case __SCROLL_YREDRAW: + redraw_down: + fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols); + p->dispsw->clear(conp, p, real_y(p, t), 0, + count, conp->vc_cols); + scr_memsetw((unsigned short *)(conp->vc_origin + + conp->vc_size_row * t), + conp->vc_video_erase_char, + conp->vc_size_row * count); + return 1; + } } return 0; } @@ -1100,12 +1155,12 @@ static int fbcon_switch(struct vc_data *conp) conp2->vc_top = 0; logo_shown = -1; } - p->var.yoffset = p->yscroll*p->fontheight; - switch (p->scrollmode) { - case SCROLL_YWRAP: + p->var.yoffset = p->yscroll = 0; + switch (p->scrollmode & __SCROLL_YMASK) { + case __SCROLL_YWRAP: scrollback_phys_max = p->vrows-conp->vc_rows; break; - case SCROLL_YPAN: + case __SCROLL_YPAN: scrollback_phys_max = p->vrows-2*conp->vc_rows; if (scrollback_phys_max < 0) scrollback_phys_max = 0; @@ -1118,9 +1173,17 @@ static int fbcon_switch(struct vc_data *conp) scrollback_current = 0; if (info && info->switch_con) - (*info->switch_con)(conp->vc_num, info); - if (p->dispsw && p->dispsw->clear_margins) - p->dispsw->clear_margins(conp, p); + (*info->switch_con)(unit, info); + if (p->dispsw->clear_margins && vt_cons[unit]->vc_mode == KD_TEXT) + p->dispsw->clear_margins(conp, p, 0); + if (logo_shown == -2) { + logo_shown = fg_console; + fbcon_show_logo(); /* This is protected above by initmem_freed */ + update_region(fg_console, + conp->vc_origin + conp->vc_size_row * conp->vc_top, + conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2); + return 0; + } return 1; } @@ -1151,7 +1214,7 @@ static int fbcon_blank(struct vc_data *conp, int blank) p->var.xres_virtual*p->var.yres_virtual* p->var.bits_per_pixel>>3); } else - p->dispsw->clear(conp, p, 0, 0, p->conp->vc_rows, p->conp->vc_cols); + p->dispsw->clear(conp, p, 0, 0, conp->vc_rows, conp->vc_cols); return 0; } else { /* Tell console.c that it has to restore the screen itself */ @@ -1162,67 +1225,77 @@ static int fbcon_blank(struct vc_data *conp, int blank) return 0; } +static void fbcon_free_font(struct display *p) +{ + if (p->userfont && p->fontdata && + (--REFCOUNT(p->fontdata) == 0)) + kfree(p->fontdata - FONT_EXTRA_WORDS*sizeof(int)); + p->fontdata = NULL; + p->userfont = 0; +} static inline int fbcon_get_font(int unit, struct console_font_op *op) { struct display *p = &fb_display[unit]; u8 *data = op->data; + u8 *fontdata = p->fontdata; int i, j; #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - if (p->fontwidth != 8) return -EINVAL; + if (fontwidth(p) != 8) return -EINVAL; #endif - op->width = p->fontwidth; - op->height = p->fontheight; + op->width = fontwidth(p); + op->height = fontheight(p); op->charcount = (p->charmask == 0x1ff) ? 512 : 256; if (!op->data) return 0; if (op->width <= 8) { for (i = 0; i < op->charcount; i++) { - for (j = 0; j < p->fontheight; j++) - *data++ = p->fontdata[i*p->fontheight+j]; - data += 32 - p->fontheight; + for (j = 0; j < fontheight(p); j++) + *data++ = *fontdata++; + memset(data, 0, 32-j); + data += 32 - j; } } #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY else if (op->width <= 16) { for (i = 0; i < op->charcount; i++) { - for (j = 0; j < p->fontheight; j++) { - *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8; - *data++ = ((u16 *)p->fontdata)[i*p->fontheight+j]; + for (j = 0; j < fontheight(p); j++) { + *data++ = *(u16 *)fontdata >> 8; + *data++ = *(u16 *)fontdata; + fontdata += sizeof(u16); } - data += 2 * (32 - p->fontheight); + memset(data, 0, 2*(32-j)); + data += 2 * (32 - j); } } else if (op->width <= 24) { for (i = 0; i < op->charcount; i++) { - for (j = 0; j < p->fontheight; j++) { - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24; - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16; - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8; + for (j = 0; j < fontheight(p); j++) { + *data++ = *(u32 *)fontdata >> 24; + *data++ = *(u32 *)fontdata >> 16; + *data++ = *(u32 *)fontdata >> 8; + fontdata += sizeof(u32); } - data += 3 * (32 - p->fontheight); + memset(data, 0, 3*(32-j)); + data += 3 * (32 - j); } } else { for (i = 0; i < op->charcount; i++) { - for (j = 0; j < p->fontheight; j++) { - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24; - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16; - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8; - *data++ = ((u32 *)p->fontdata)[i*p->fontheight+j]; + for (j = 0; j < fontheight(p); j++) { + *data++ = *(u32 *)fontdata >> 24; + *data++ = *(u32 *)fontdata >> 16; + *data++ = *(u32 *)fontdata >> 8; + *data++ = *(u32 *)fontdata; + fontdata += sizeof(u32); } - data += 4 * (32 - p->fontheight); + memset(data, 0, 4*(32-j)); + data += 4 * (32 - j); } } #endif return 0; } - -#define REFCOUNT(fd) (((int *)(fd))[-1]) -#define FNTSIZE(fd) (((int *)(fd))[-2]) -#define FNTCHARCNT(fd) (((int *)(fd))[-3]) -#define FNTSUM(fd) (((int *)(fd))[-4]) - static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont) { struct display *p = &fb_display[unit]; @@ -1233,12 +1306,12 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int char *old_data = NULL; if (!fontwidthvalid(p,w)) { - if (userfont) - kfree(data); + if (userfont && op->op != KD_FONT_OP_COPY) + kfree(data - FONT_EXTRA_WORDS*sizeof(int)); return -ENXIO; } - resize = (w != p->fontwidth) || (h != p->fontheight); + resize = (w != fontwidth(p)) || (h != fontheight(p)); if (p->userfont) old_data = p->fontdata; if (userfont) @@ -1248,8 +1321,8 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int p->fontdata = data; if ((p->userfont = userfont)) REFCOUNT(data)++; - p->fontwidth = w; - p->fontheight = h; + p->_fontwidth = w; + p->_fontheight = h; if (p->conp->vc_hi_font_mask && cnt == 256) { p->conp->vc_hi_font_mask = 0; p->conp->vc_complement_mask >>= 1; @@ -1268,19 +1341,19 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int if (resize) { /* reset wrap/pan */ p->var.xoffset = p->var.yoffset = p->yscroll = 0; - if (!p->dispsw->set_font || - !p->dispsw->set_font(p, p->fontwidth, p->fontheight)) { - /* Adjust the virtual screen-size to fontheight*rows */ - p->var.yres_virtual = (p->var.yres/h)*h; - } p->vrows = p->var.yres_virtual/h; + if ((p->var.yres % h) && (p->var.yres_virtual % h < p->var.yres % h)) + p->vrows--; updatescrollmode(p); vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); - } else if (unit == fg_console) - update_screen( unit ); + } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) { + if (p->dispsw->clear_margins) + p->dispsw->clear_margins(p->conp, p, 0); + update_screen(unit); + } if (old_data && (--REFCOUNT(old_data) == 0)) - kfree( old_data - 4*sizeof(int) ); + kfree(old_data - FONT_EXTRA_WORDS*sizeof(int)); return 0; } @@ -1297,8 +1370,8 @@ static inline int fbcon_copy_font(int unit, struct console_font_op *op) od = &fb_display[h]; if (od->fontdata == p->fontdata) return 0; /* already the same font... */ - op->width = od->fontwidth; - op->height = od->fontheight; + op->width = fontwidth(od); + op->height = fontheight(od); return fbcon_do_set_font(unit, op, od->fontdata, od->userfont); } @@ -1309,9 +1382,10 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op) int size = h; int i, j, k; u8 *new_data, *data = op->data, c, *p; +#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY u32 d; +#else -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY if (w != 8) return -EINVAL; #endif @@ -1327,57 +1401,59 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op) } size *= op->charcount; - if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER ))) + if (!(new_data = kmalloc(FONT_EXTRA_WORDS*sizeof(int)+size, GFP_USER))) return -ENOMEM; - new_data += 4*sizeof(int); + new_data += FONT_EXTRA_WORDS*sizeof(int); FNTSIZE(new_data) = size; FNTCHARCNT(new_data) = op->charcount; REFCOUNT(new_data) = 0; /* usage counter */ k = 0; - p = data; + p = new_data; if (w <= 8) { for (i = 0; i < op->charcount; i++) { for (j = 0; j < h; j++) { - c = *p++; + c = *data++; k += c; - new_data[i*h+j] = c; + *p++ = c; } - p += 32 - h; + data += 32 - h; } } #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY else if (w <= 16) { for (i = 0; i < op->charcount; i++) { for (j = 0; j < h; j++) { - d = (p[0] << 8) | p[1]; - p += 2; + d = (data[0] << 8) | data[1]; + data += 2; k += d; - ((u16 *)new_data)[i*h+j] = d; + *(u16 *)p = d; + p += sizeof(u16); } - p += 2*(32 - h); + data += 2*(32 - h); } } else { for (i = 0; i < op->charcount; i++) { for (j = 0; j < h; j++) { if (w <= 24) { - d = (p[0] << 24) | - (p[1] << 16) | - (p[2] << 8); - p += 3; + d = (data[0] << 24) | + (data[1] << 16) | + (data[2] << 8); + data += 3; } else { - d = (p[0] << 24) | - (p[1] << 16) | - (p[2] << 8) | - p[3]; - p += 4; + d = (data[0] << 24) | + (data[1] << 16) | + (data[2] << 8) | + data[3]; + data += 4; } k += d; - ((u32 *)new_data)[i*h+j] = d; + *(u32 *)p = d; + p += sizeof(u32); } if (w <= 24) - p += 3*(32 - h); + data += 3*(32 - h); else - p += 4*(32 - h); + data += 4*(32 - h); } } #endif @@ -1389,7 +1465,7 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op) FNTSUM(fb_display[i].fontdata) == k && FNTSIZE(fb_display[i].fontdata) == size && !memcmp(fb_display[i].fontdata, new_data, size)) { - kfree(new_data - 4*sizeof(int)); + kfree(new_data - FONT_EXTRA_WORDS*sizeof(int)); new_data = fb_display[i].fontdata; break; } @@ -1495,11 +1571,11 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines) offset = p->yscroll-scrollback_current; limit = p->vrows; - switch (p->scrollmode) { - case SCROLL_YWRAP: + switch (p->scrollmode && __SCROLL_YMASK) { + case __SCROLL_YWRAP: p->var.vmode |= FB_VMODE_YWRAP; break; - case SCROLL_YPAN: + case __SCROLL_YPAN: limit -= conp->vc_rows; p->var.vmode &= ~FB_VMODE_YWRAP; break; @@ -1509,13 +1585,18 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines) else if (offset >= limit) offset -= limit; p->var.xoffset = 0; - p->var.yoffset = offset*p->fontheight; + p->var.yoffset = offset*fontheight(p); p->fb_info->updatevar(unit, p->fb_info); if (!offset) fbcon_cursor(conp, CM_DRAW); return 0; } +static inline unsigned safe_shift(unsigned d,int n) +{ + return n<0 ? d>>-n : d<<n; +} + __initfunc(static int fbcon_show_logo( void )) { struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ @@ -1532,10 +1613,10 @@ __initfunc(static int fbcon_show_logo( void )) return 0; /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for - * TRUECOLOR */ + * DIRECTCOLOR */ if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) || - p->visual == FB_VISUAL_TRUECOLOR) { - int is_truecolor = (p->visual == FB_VISUAL_TRUECOLOR); + p->visual == FB_VISUAL_DIRECTCOLOR) { + int is_truecolor = (p->visual == FB_VISUAL_DIRECTCOLOR); int use_256 = (!is_truecolor && depth >= 8) || (is_truecolor && depth >= 24); int first_col = use_256 ? 32 : depth > 4 ? 16 : 0; @@ -1588,7 +1669,7 @@ __initfunc(static int fbcon_show_logo( void )) #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS) - if (p->visual == FB_VISUAL_TRUECOLOR) { + if (p->visual == FB_VISUAL_DIRECTCOLOR) { unsigned int val; /* max. depth 32! */ int bdepth; int redshift, greenshift, blueshift; @@ -1629,13 +1710,21 @@ __initfunc(static int fbcon_show_logo( void )) val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); +#ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i ) +#else + for( i = bdepth-1; i >= 0; --i ) +#endif *dst++ = val >> (i*8); pix = (*src & 0x0f) | 0x10; /* lower nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); +#ifdef __LITTLE_ENDIAN + for( i = 0; i < bdepth; ++i ) +#else for( i = bdepth-1; i >= 0; --i ) +#endif *dst++ = val >> (i*8); } } @@ -1645,7 +1734,7 @@ __initfunc(static int fbcon_show_logo( void )) #endif #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS) - if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) { + if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR)) { /* Modes without color mapping, needs special data transformation... */ unsigned int val; /* max. depth 32! */ int bdepth = depth/8; @@ -1665,9 +1754,9 @@ __initfunc(static int fbcon_show_logo( void )) for( y1 = 0; y1 < LOGO_H; y1++ ) { dst = fb + y1*line + x*bdepth; for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { - val = ((linux_logo_red[*src-32] & redmask) << redshift) | - ((linux_logo_green[*src-32] & greenmask) << greenshift) | - ((linux_logo_blue[*src-32] & bluemask) << blueshift); + val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) | + safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) | + safe_shift((linux_logo_blue[*src-32] & bluemask), blueshift); #ifdef __LITTLE_ENDIAN for( i = 0; i < bdepth; ++i ) #else @@ -1702,8 +1791,15 @@ __initfunc(static int fbcon_show_logo( void )) unsigned char val, mask; int plane = p->next_plane; +#if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \ + defined(CONFIG_FBCON_IPLAN2P8) + int line_length = p->line_length; + /* for support of Atari interleaved planes */ -#define MAP_X(x) (plane > line ? x : (x & ~1)*depth + (x & 1)) +#define MAP_X(x) (line_length ? x : (x & ~1)*depth + (x & 1)) +#else +#define MAP_X(x) (x) +#endif /* extract a bit from the source image */ #define BIT(p,pix,bit) (p[pix*logo_depth/8] & \ (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit))) @@ -1766,7 +1862,7 @@ __initfunc(static int fbcon_show_logo( void )) /* Modes not yet supported: packed pixels with depth != 8 (does such a * thing exist in reality?) */ - return done ? (LOGO_H + p->fontheight - 1) / p->fontheight : 0 ; + return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ; } /* @@ -1801,7 +1897,7 @@ struct consw fb_con = { static void fbcon_dummy_op(void) {} -static struct display_switch fbcon_dummy = { +struct display_switch fbcon_dummy = { (void *)fbcon_dummy_op, /* fbcon_dummy_setup */ (void *)fbcon_dummy_op, /* fbcon_dummy_bmove */ (void *)fbcon_dummy_op, /* fbcon_dummy_clear */ @@ -1818,3 +1914,4 @@ static struct display_switch fbcon_dummy = { EXPORT_SYMBOL(fb_display); EXPORT_SYMBOL(fbcon_redraw_bmove); +EXPORT_SYMBOL(fbcon_dummy); diff --git a/drivers/video/fbcon.h b/drivers/video/fbcon.h deleted file mode 100644 index 98091ba0c..000000000 --- a/drivers/video/fbcon.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - * linux/drivers/video/fbcon.h -- Low level frame buffer based console driver - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#ifndef __VIDEO_FBCON_H -#define __VIDEO_FBCON_H - -#include <linux/config.h> -#include <linux/console_struct.h> - - - /* - * `switch' for the Low Level Operations - */ - -struct display_switch { - void (*setup)(struct display *p); - void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, - int height, int width); - void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx, - int height, int width); - void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, - int xx); - void (*putcs)(struct vc_data *conp, struct display *p, const unsigned short *s, - int count, int yy, int xx); - void (*revc)(struct display *p, int xx, int yy); - void (*cursor)(struct display *p, int mode, int xx, int yy); - int (*set_font)(struct display *p, int width, int height); - void (*clear_margins)(struct vc_data *conp, struct display *p); - unsigned int fontwidthmask; /* 1 at (1 << (width - 1)) if width is supported */ -}; - -#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY - -/* fontwidth w is supported by dispsw */ -#define FONTWIDTH(w) (1 << ((8) - 1)) -/* fontwidths w1-w2 inclusive are supported by dispsw */ -#define FONTWIDTHRANGE(w1,w2) FONTWIDTH(8) - -#else - -/* fontwidth w is supported by dispsw */ -#define FONTWIDTH(w) (1 << ((w) - 1)) -/* fontwidths w1-w2 inclusive are supported by dispsw */ -#define FONTWIDTHRANGE(w1,w2) (FONTWIDTH(w2+1) - FONTWIDTH(w1)) - -#endif - - /* - * Attribute Decoding - */ - -/* Color */ -#define attr_fgcol(p,s) \ - (((s) >> ((p)->fgshift)) & 0x0f) -#define attr_bgcol(p,s) \ - (((s) >> ((p)->bgshift)) & 0x0f) -#define attr_bgcol_ec(p,conp) \ - (((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f) - -/* Monochrome */ -#define attr_bold(p,s) \ - ((s) & 0x200) -#define attr_reverse(p,s) \ - (((s) & 0x800) ^ ((p)->inverse ? 0x800 : 0)) -#define attr_underline(p,s) \ - ((s) & 0x400) -#define attr_blink(p,s) \ - ((s) & 0x8000) - - /* - * Scroll Method - */ - -#define SCROLL_YWRAP (0) -#define SCROLL_YPAN (1) -#define SCROLL_YMOVE (2) -#define SCROLL_YREDRAW (3) - -extern void fbcon_redraw_bmove(struct display *, int, int, int, int, int, int); - - -/* ================================================================= */ -/* Utility Assembler Functions */ -/* ================================================================= */ - - -#ifdef __mc68000__ - -/* ====================================================================== */ - -/* Those of a delicate disposition might like to skip the next couple of - * pages. - * - * These functions are drop in replacements for memmove and - * memset(_, 0, _). However their five instances add at least a kilobyte - * to the object file. You have been warned. - * - * Not a great fan of assembler for the sake of it, but I think - * that these routines are at least 10 times faster than their C - * equivalents for large blits, and that's important to the lowest level of - * a graphics driver. Question is whether some scheme with the blitter - * would be faster. I suspect not for simple text system - not much - * asynchrony. - * - * Code is very simple, just gruesome expansion. Basic strategy is to - * increase data moved/cleared at each step to 16 bytes to reduce - * instruction per data move overhead. movem might be faster still - * For more than 15 bytes, we try to align the write direction on a - * longword boundary to get maximum speed. This is even more gruesome. - * Unaligned read/write used requires 68020+ - think this is a problem? - * - * Sorry! - */ - - -/* ++roman: I've optimized Robert's original versions in some minor - * aspects, e.g. moveq instead of movel, let gcc choose the registers, - * use movem in some places... - * For other modes than 1 plane, lots of more such assembler functions - * were needed (e.g. the ones using movep or expanding color values). - */ - -/* ++andreas: more optimizations: - subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc - addal is faster than addaw - movep is rather expensive compared to ordinary move's - some functions rewritten in C for clarity, no speed loss */ - -static __inline__ void *mymemclear_small(void *s, size_t count) -{ - if (!count) - return(0); - - __asm__ __volatile__( - "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" - "1: subql #1,%1 ; jcs 3f\n\t" - "2: moveml %2/%3/%4/%5,%0@-\n\t" - "dbra %1,2b\n\t" - "3:" - : "=a" (s), "=d" (count) - : "d" (0), "d" (0), "d" (0), "d" (0), - "0" ((char *)s+count), "1" (count) - ); - - return(0); -} - - -static __inline__ void *mymemclear(void *s, size_t count) -{ - if (!count) - return(0); - - if (count < 16) { - __asm__ __volatile__( - "lsrl #1,%1 ; jcc 1f ; clrb %0@+\n\t" - "1: lsrl #1,%1 ; jcc 1f ; clrw %0@+\n\t" - "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+\n\t" - "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t" - "1:" - : "=a" (s), "=d" (count) - : "0" (s), "1" (count) - ); - } else { - long tmp; - __asm__ __volatile__( - "movel %1,%2\n\t" - "lsrl #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t" - "lsrl #1,%2 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ - "clrw %0@+ ; subqw #2,%1 ; jra 2f\n\t" - "1: lsrl #1,%2 ; jcc 2f\n\t" - "clrw %0@+ ; subqw #2,%1\n\t" - "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t" - "lsrl #1,%1 ; jcc 3f ; clrl %0@+\n\t" - "3: lsrl #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t" - "4: subql #1,%1 ; jcs 6f\n\t" - "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t" - "dbra %1,5b ; clrw %1; subql #1,%1; jcc 5b\n\t" - "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t" - "7: ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t" - "8:" - : "=a" (s), "=d" (count), "=d" (tmp) - : "0" (s), "1" (count) - ); - } - - return(0); -} - - -static __inline__ void *mymemset(void *s, size_t count) -{ - if (!count) - return(0); - - __asm__ __volatile__( - "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" - "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" - "1: subql #1,%1 ; jcs 3f\n\t" - "2: moveml %2/%3/%4/%5,%0@-\n\t" - "dbra %1,2b\n\t" - "3:" - : "=a" (s), "=d" (count) - : "d" (-1), "d" (-1), "d" (-1), "d" (-1), - "0" ((char *) s + count), "1" (count) - ); - - return(0); -} - - -static __inline__ void *mymemmove(void *d, const void *s, size_t count) -{ - if (d < s) { - if (count < 16) { - __asm__ __volatile__( - "lsrl #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" - "1:" - : "=a" (d), "=a" (s), "=d" (count) - : "0" (d), "1" (s), "2" (count) - ); - } else { - long tmp; - __asm__ __volatile__( - "movel %0,%3\n\t" - "lsrl #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t" - "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ - "movew %1@+,%0@+ ; subqw #2,%2 ; jra 2f\n\t" - "1: lsrl #1,%3 ; jcc 2f\n\t" - "movew %1@+,%0@+ ; subqw #2,%2\n\t" - "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" - "lsrl #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t" - "3: lsrl #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" - "4: subql #1,%2 ; jcs 6f\n\t" - "5: movel %1@+,%0@+;movel %1@+,%0@+\n\t" - "movel %1@+,%0@+;movel %1@+,%0@+\n\t" - "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" - "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t" - "7: ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t" - "8:" - : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) - : "0" (d), "1" (s), "2" (count) - ); - } - } else { - if (count < 16) { - __asm__ __volatile__( - "lsrl #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t" - "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" - "1:" - : "=a" (d), "=a" (s), "=d" (count) - : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) - ); - } else { - long tmp; - __asm__ __volatile__( - "movel %0,%3\n\t" - "lsrl #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t" - "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ - "movew %1@-,%0@- ; subqw #2,%2 ; jra 2f\n\t" - "1: lsrl #1,%3 ; jcc 2f\n\t" - "movew %1@-,%0@- ; subqw #2,%2\n\t" - "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" - "lsrl #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t" - "3: lsrl #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" - "4: subql #1,%2 ; jcs 6f\n\t" - "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t" - "movel %1@-,%0@-;movel %1@-,%0@-\n\t" - "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" - "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t" - "7: ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t" - "8:" - : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) - : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) - ); - } - } - - return(0); -} - - -/* ++andreas: Simple and fast version of memmove, assumes size is - divisible by 16, suitable for moving the whole screen bitplane */ -static __inline__ void fast_memmove(char *dst, const char *src, size_t size) -{ - if (!size) - return; - if (dst < src) - __asm__ __volatile__ - ("1:" - " moveml %0@+,%/d0/%/d1/%/a0/%/a1\n" - " moveml %/d0/%/d1/%/a0/%/a1,%1@\n" - " addql #8,%1; addql #8,%1\n" - " dbra %2,1b\n" - " clrw %2; subql #1,%2\n" - " jcc 1b" - : "=a" (src), "=a" (dst), "=d" (size) - : "0" (src), "1" (dst), "2" (size / 16 - 1) - : "d0", "d1", "a0", "a1", "memory"); - else - __asm__ __volatile__ - ("1:" - " subql #8,%0; subql #8,%0\n" - " moveml %0@,%/d0/%/d1/%/a0/%/a1\n" - " moveml %/d0/%/d1/%/a0/%/a1,%1@-\n" - " dbra %2,1b\n" - " clrw %2; subql #1,%2\n" - " jcc 1b" - : "=a" (src), "=a" (dst), "=d" (size) - : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) - : "d0", "d1", "a0", "a1", "memory"); -} - -#else /* !m68k */ - - /* - * Anyone who'd like to write asm functions for other CPUs? - */ - -static __inline__ void *mymemclear_small(void *s, size_t count) -{ - return(memset(s, 0, count)); -} - -static __inline__ void *mymemclear(void *s, size_t count) -{ - return(memset(s, 0, count)); -} - -static __inline__ void *mymemset(void *s, size_t count) -{ - return(memset(s, 255, count)); -} - -#ifdef __i386__ -static __inline__ void fast_memmove(void *d, const void *s, size_t count) -{ - if (d < s) { -__asm__ __volatile__ ( - "cld\n\t" - "shrl $1,%%ecx\n\t" - "jnc 1f\n\t" - "movsb\n" - "1:\tshrl $1,%%ecx\n\t" - "jnc 2f\n\t" - "movsw\n" - "2:\trep\n\t" - "movsl" - : /* no output */ - :"c"(count),"D"((long)d),"S"((long)s) - :"cx","di","si","memory"); - } else { -__asm__ __volatile__ ( - "std\n\t" - "shrl $1,%%ecx\n\t" - "jnc 1f\n\t" - "movb 3(%%esi),%%al\n\t" - "movb %%al,3(%%edi)\n\t" - "decl %%esi\n\t" - "decl %%edi\n" - "1:\tshrl $1,%%ecx\n\t" - "jnc 2f\n\t" - "movw 2(%%esi),%%ax\n\t" - "movw %%ax,2(%%edi)\n\t" - "decl %%esi\n\t" - "decl %%edi\n\t" - "decl %%esi\n\t" - "decl %%edi\n" - "2:\trep\n\t" - "movsl" - : /* no output */ - :"c"(count),"D"(count-4+(long)d),"S"(count-4+(long)s) - :"ax","cx","di","si","memory"); - } -} - -static __inline__ void *mymemmove(char *dst, const char *src, size_t size) -{ - fast_memmove(dst, src, size); - return dst; -} -#else -static __inline__ void *mymemmove(void *d, const void *s, size_t count) -{ - return(memmove(d, s, count)); -} - -static __inline__ void fast_memmove(char *dst, const char *src, size_t size) -{ - memmove(dst, src, size); -} -#endif /* !i386 */ - -#endif /* !m68k */ - -#endif /* __VIDEO_FBCON_H */ diff --git a/drivers/video/fbgen.c b/drivers/video/fbgen.c index 3ff647980..c3c42ed5e 100644 --- a/drivers/video/fbgen.c +++ b/drivers/video/fbgen.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <asm/uaccess.h> +#include <asm/io.h> static int currcon = 0; @@ -114,8 +115,7 @@ int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fbgen_hwswitch *fbhw = info2->fbhw; if (con == currcon) /* current console ? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, fbhw->getcolreg, - info); + return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap ? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); @@ -144,8 +144,7 @@ int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console ? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, fbhw->setcolreg, - info); + return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -245,7 +244,7 @@ void fbgen_set_disp(int con, struct fb_info_gen *info) memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); fbhw->encode_fix(&fix, &par, info); - display->screen_base = fix.smem_start; + display->screen_base = phys_to_virt((unsigned long)fix.smem_start); display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -257,7 +256,7 @@ void fbgen_set_disp(int con, struct fb_info_gen *info) display->can_soft_blank = 1; else display->can_soft_blank = 0; - display->dispsw = fbhw->get_dispsw(&par, info); + fbhw->set_dispsw(&par, display, info); #if 0 /* FIXME: generic inverse is not supported yet */ display->inverse = (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); #else @@ -276,12 +275,10 @@ void fbgen_install_cmap(int con, struct fb_info_gen *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - fbhw->setcolreg, &info->info); + fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, &info->info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256; - fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, - fbhw->setcolreg, &info->info); + fb_set_cmap(fb_default_cmap(size), 1, fbhw->setcolreg, &info->info); } } @@ -315,8 +312,8 @@ int fbgen_switch(int con, struct fb_info *info) /* Do we have to save the colormap ? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - fbhw->getcolreg, &info2->info); + fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg, + &info2->info); fbgen_do_set_var(&fb_display[con].var, 1, info2); currcon = con; /* Install new colormap */ @@ -346,7 +343,7 @@ void fbgen_blank(int blank, struct fb_info *info) cmap.transp = NULL; cmap.start = 0; cmap.len = 16; - fb_set_cmap(&cmap, &fb_display[currcon].var, 1, fbhw->setcolreg, info); + fb_set_cmap(&cmap, 1, fbhw->setcolreg, info); } else fbgen_install_cmap(currcon, info2); } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c new file mode 100644 index 000000000..aab80ad6b --- /dev/null +++ b/drivers/video/fbmem.c @@ -0,0 +1,725 @@ +/* + * linux/drivers/video/fbmem.c + * + * Copyright (C) 1994 Martin Schaller + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/mman.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/console_struct.h> +#include <linux/init.h> +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif +#ifdef CONFIG_KMOD +#include <linux/kmod.h> +#endif + +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/setup.h> +#endif +#ifdef __powerpc__ +#include <asm/io.h> +#endif +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#include <linux/fb.h> + + + /* + * Frame buffer device initialization and setup routines + */ + +extern unsigned long acornfb_init(void); +extern void acornfb_setup(char *options, int *ints); +extern void amifb_init(void); +extern void amifb_setup(char *options, int *ints); +extern void atafb_init(void); +extern void atafb_setup(char *options, int *ints); +extern void macfb_init(void); +extern void macfb_setup(char *options, int *ints); +extern void cyberfb_init(void); +extern void cyberfb_setup(char *options, int *ints); +extern void cvppcfb_init(void); +extern void cvppcfb_setup(char *options, int *ints); +extern void retz3fb_init(void); +extern void retz3fb_setup(char *options, int *ints); +extern void clgenfb_init(void); +extern void clgenfb_setup(char *options, int *ints); +extern void vfb_init(void); +extern void vfb_setup(char *options, int *ints); +extern void offb_init(void); +extern void offb_setup(char *options, int *ints); +extern void atyfb_init(void); +extern void atyfb_setup(char *options, int *ints); +extern void igafb_init(void); +extern void igafb_setup(char *options, int *ints); +extern void imsttfb_init(void); +extern void imsttfb_setup(char *options, int *ints); +extern void dnfb_init(void); +extern void tgafb_init(void); +extern void virgefb_init(void); +extern void virgefb_setup(char *options, int *ints); +extern void resolver_video_setup(char *options, int *ints); +extern void s3triofb_init(void); +extern void s3triofb_setup(char *options, int *ints); +extern void vesafb_init(void); +extern void vesafb_setup(char *options, int *ints); +extern void matroxfb_init(void); +extern void matroxfb_setup(char* options, int *ints); +extern void hpfb_init(void); +extern void hpfb_setup(char *options, int *ints); +extern void sbusfb_init(void); +extern void sbusfb_setup(char *options, int *ints); +extern void valkyriefb_init(void); +extern void valkyriefb_setup(char *options, int *ints); +extern void g364fb_init(void); + +static struct { + const char *name; + void (*init)(void); + void (*setup)(char *options, int *ints); +} fb_drivers[] __initdata = { +#ifdef CONFIG_FB_RETINAZ3 + { "retz3", retz3fb_init, retz3fb_setup }, +#endif +#ifdef CONFIG_FB_ACORN + { "acorn", acornfb_init, acornfb_setup }, +#endif +#ifdef CONFIG_FB_AMIGA + { "amifb", amifb_init, amifb_setup }, +#endif +#ifdef CONFIG_FB_ATARI + { "atafb", atafb_init, atafb_setup }, +#endif +#ifdef CONFIG_FB_MAC + { "macfb", macfb_init, macfb_setup }, +#endif +#ifdef CONFIG_FB_CYBER + { "cyber", cyberfb_init, cyberfb_setup }, +#endif +#ifdef CONFIG_FB_CVPPC + { "cvppcfb", cvppcfb_init, cvppcfb_setup }, +#endif +#ifdef CONFIG_FB_CLGEN + { "clgen", clgenfb_init, clgenfb_setup }, +#endif +#ifdef CONFIG_FB_OF + { "offb", offb_init, offb_setup }, +#endif +#ifdef CONFIG_FB_SBUS + { "sbus", sbusfb_init, sbusfb_setup }, +#endif +#ifdef CONFIG_FB_ATY + { "atyfb", atyfb_init, atyfb_setup }, +#endif +#ifdef CONFIG_FB_IGA + { "igafb", igafb_init, igafb_setup }, +#endif +#ifdef CONFIG_FB_IMSTT + { "imsttfb", imsttfb_init, imsttfb_setup }, +#endif +#ifdef CONFIG_APOLLO + { "apollo", dnfb_init, NULL }, +#endif +#ifdef CONFIG_FB_S3TRIO + { "s3trio", s3triofb_init, s3triofb_setup }, +#endif +#ifdef CONFIG_FB_TGA + { "tga", tgafb_init, NULL }, +#endif +#ifdef CONFIG_FB_VIRGE + { "virge", virgefb_init, virgefb_setup }, +#endif +#ifdef CONFIG_FB_VESA + { "vesa", vesafb_init, vesafb_setup }, +#endif +#ifdef CONFIG_FB_MATROX + { "matrox", matroxfb_init, matroxfb_setup }, +#endif +#ifdef CONFIG_FB_HP300 + { "hpfb", hpfb_init, hpfb_setup }, +#endif +#ifdef CONFIG_FB_VALKYRIE + { "valkyriefb", valkyriefb_init, valkyriefb_setup }, +#endif +#ifdef CONFIG_FB_G364 + { "g364", g364fb_init, NULL }, +#endif +#ifdef CONFIG_GSP_RESOLVER + /* Not a real frame buffer device... */ + { "resolver", NULL, resolver_video_setup }, +#endif +#ifdef CONFIG_FB_VIRTUAL + /* Must be last to avoid that vfb becomes your primary display */ + { "vfb", vfb_init, vfb_setup }, +#endif +}; + +#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers)) + +static void (*pref_init_funcs[FB_MAX])(void); +static int num_pref_init_funcs __initdata = 0; + + +#define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT) +#define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1)) + +struct fb_info *registered_fb[FB_MAX]; +int num_registered_fb = 0; + +char con2fb_map[MAX_NR_CONSOLES]; + +static int first_fb_vc = 0; +static int last_fb_vc = MAX_NR_CONSOLES-1; +static int fbcon_is_default = 1; + +static inline int PROC_CONSOLE(void) +{ + if (!current->tty) + return fg_console; + + if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + /* XXX Should report error here? */ + return fg_console; + + if (MINOR(current->tty->device) < 1) + return fg_console; + + return MINOR(current->tty->device) - 1; +} + +#ifdef CONFIG_PROC_FS +static int fbmem_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) +{ + struct fb_info **fi; + + len = 0; + for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && len < 4000; fi++) + if (*fi) + len += sprintf(buf + len, "%d %s\n", + GET_FB_IDX((*fi)->node), + (*fi)->modename); + *start = buf + offset; + return len > offset ? len - offset : 0; +} +#endif + +static ssize_t +fb_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = GET_FB_IDX(inode->i_rdev); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + char *base_addr; + ssize_t copy_size; + + if (! fb || ! info->disp) + return -ENODEV; + + fb->fb_get_fix(&fix,PROC_CONSOLE(), info); + base_addr=info->disp->screen_base; + copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p); + if (copy_to_user(buf, base_addr+p, copy_size)) + return -EFAULT; + *ppos += copy_size; + return copy_size; +} + +static ssize_t +fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = GET_FB_IDX(inode->i_rdev); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + char *base_addr; + ssize_t copy_size; + + if (! fb || ! info->disp) + return -ENODEV; + + fb->fb_get_fix(&fix, PROC_CONSOLE(), info); + base_addr=info->disp->screen_base; + copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p); + if (copy_from_user(base_addr+p, buf, copy_size)) + return -EFAULT; + file->f_pos += copy_size; + return copy_size; +} + + +static int set_all_vcs(int fbidx, struct fb_ops *fb, + struct fb_var_screeninfo *var, struct fb_info *info) +{ + int unit, err; + + var->activate |= FB_ACTIVATE_TEST; + err = fb->fb_set_var(var, PROC_CONSOLE(), info); + var->activate &= ~FB_ACTIVATE_TEST; + if (err) + return err; + for (unit = 0; unit < MAX_NR_CONSOLES; unit++) + if (fb_display[unit].conp && con2fb_map[unit] == fbidx) + fb->fb_set_var(var, unit, info); + return 0; +} + +static void set_con2fb_map(int unit, int newidx) +{ + int oldidx = con2fb_map[unit]; + struct fb_info *oldfb, *newfb; + struct vc_data *conp; + char *fontdata; + unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog; + int userfont; + + if (newidx != con2fb_map[unit]) { + oldfb = registered_fb[oldidx]; + newfb = registered_fb[newidx]; + if (newfb->fbops->fb_open(newfb,0)) + return; + oldfb->fbops->fb_release(oldfb,0); + conp = fb_display[unit].conp; + fontdata = fb_display[unit].fontdata; + fontwidth = fb_display[unit]._fontwidth; + fontheight = fb_display[unit]._fontheight; + fontwidthlog = fb_display[unit]._fontwidthlog; + fontheightlog = fb_display[unit]._fontheightlog; + userfont = fb_display[unit].userfont; + con2fb_map[unit] = newidx; + fb_display[unit] = *(newfb->disp); + fb_display[unit].conp = conp; + fb_display[unit].fontdata = fontdata; + fb_display[unit]._fontwidth = fontwidth; + fb_display[unit]._fontheight = fontheight; + fb_display[unit]._fontwidthlog = fontwidthlog; + fb_display[unit]._fontheightlog = fontheightlog; + fb_display[unit].userfont = userfont; + fb_display[unit].fb_info = newfb; + if (!newfb->changevar) + newfb->changevar = oldfb->changevar; + /* tell console var has changed */ + if (newfb->changevar) + newfb->changevar(unit); + } +} + +#ifdef CONFIG_KMOD +static void try_to_load(int fb) +{ + char modname[16]; + + sprintf(modname, "fb%d", fb); + request_module(modname); +} +#endif /* CONFIG_KMOD */ + +static int +fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int fbidx = GET_FB_IDX(inode->i_rdev); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_cmap cmap; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct fb_con2fbmap con2fb; + int i; + + if (! fb) + return -ENODEV; + switch (cmd) { + case FBIOGET_VSCREENINFO: + if ((i = fb->fb_get_var(&var, PROC_CONSOLE(), info))) + return i; + return copy_to_user((void *) arg, &var, + sizeof(var)) ? -EFAULT : 0; + case FBIOPUT_VSCREENINFO: + if (copy_from_user(&var, (void *) arg, sizeof(var))) + return -EFAULT; + i = var.activate & FB_ACTIVATE_ALL + ? set_all_vcs(fbidx, fb, &var, info) + : fb->fb_set_var(&var, PROC_CONSOLE(), info); + if (i) + return i; + if (copy_to_user((void *) arg, &var, sizeof(var))) + return -EFAULT; + return 0; + case FBIOGET_FSCREENINFO: + if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(), info))) + return i; + return copy_to_user((void *) arg, &fix, sizeof(fix)) ? + -EFAULT : 0; + case FBIOPUTCMAP: + if (copy_from_user(&cmap, (void *) arg, sizeof(cmap))) + return -EFAULT; + return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(), info)); + case FBIOGETCMAP: + if (copy_from_user(&cmap, (void *) arg, sizeof(cmap))) + return -EFAULT; + return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE(), info)); + case FBIOPAN_DISPLAY: + if (copy_from_user(&var, (void *) arg, sizeof(var))) + return -EFAULT; + if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(), info))) + return i; + if (copy_to_user((void *) arg, &var, sizeof(var))) + return -EFAULT; + return i; + case FBIOGET_CON2FBMAP: + if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + con2fb.framebuffer = con2fb_map[con2fb.console-1]; + return copy_to_user((void *)arg, &con2fb, + sizeof(con2fb)) ? -EFAULT : 0; + case FBIOPUT_CON2FBMAP: + if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb))) + return - EFAULT; + if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) + return -EINVAL; +#ifdef CONFIG_KMOD + if (!registered_fb[con2fb.framebuffer]) + try_to_load(con2fb.framebuffer); +#endif /* CONFIG_KMOD */ + if (!registered_fb[con2fb.framebuffer]) + return -EINVAL; + if (con2fb.console != 0) + set_con2fb_map(con2fb.console-1, con2fb.framebuffer); + else + /* set them all */ + for (i = 0; i < MAX_NR_CONSOLES; i++) + set_con2fb_map(i, con2fb.framebuffer); + return 0; + default: + return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(), + info); + } +} + +static int +fb_mmap(struct file *file, struct vm_area_struct * vma) +{ + int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + unsigned long start; + u32 len; + + if (!fb) + return -ENODEV; + if (fb->fb_mmap) + return fb->fb_mmap(info, file, vma); + fb->fb_get_fix(&fix, PROC_CONSOLE(), info); + + /* frame buffer memory */ + start = (unsigned long)fix.smem_start; + len = (start & ~PAGE_MASK)+fix.smem_len; + start &= PAGE_MASK; + len = (len+~PAGE_MASK) & PAGE_MASK; + if (vma->vm_offset >= len) { + /* memory mapped io */ + vma->vm_offset -= len; + fb->fb_get_var(&var, PROC_CONSOLE(), info); + if (var.accel_flags) + return -EINVAL; + start = (unsigned long)fix.mmio_start; + len = (start & ~PAGE_MASK)+fix.mmio_len; + start &= PAGE_MASK; + len = (len+~PAGE_MASK) & PAGE_MASK; + } + if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len) + return -EINVAL; + vma->vm_offset += start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; +#if defined(__mc68000__) + if (CPU_IS_020_OR_030) + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; + if (CPU_IS_040_OR_060) { + pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + /* Use no-cache mode, serialized */ + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; + } +#elif defined(__powerpc__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; +#elif defined(__alpha__) + /* Caching is off in the I/O space quadrant by design. */ +#elif defined(__sparc__) + /* Should never get here, all fb drivers should have their own + mmap routines */ +#elif defined(__i386__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +#elif defined(__mips__) + pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; + pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; +#else +#warning What do we have to do here?? +#endif + if (remap_page_range(vma->vm_start, vma->vm_offset, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_file = file; + file->f_count++; + return 0; +} + +static int +fb_open(struct inode *inode, struct file *file) +{ + int fbidx = GET_FB_IDX(inode->i_rdev); + struct fb_info *info; + +#ifdef CONFIG_KMOD + if (!(info = registered_fb[fbidx])) + try_to_load(fbidx); +#endif /* CONFIG_KMOD */ + if (!(info = registered_fb[fbidx])) + return -ENODEV; + return info->fbops->fb_open(info,1); +} + +static int +fb_release(struct inode *inode, struct file *file) +{ + int fbidx = GET_FB_IDX(inode->i_rdev); + struct fb_info *info = registered_fb[fbidx]; + + info->fbops->fb_release(info,1); + return 0; +} + +static struct file_operations fb_fops = { + NULL, /* lseek */ + fb_read, /* read */ + fb_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + fb_ioctl, /* ioctl */ + fb_mmap, /* mmap */ + fb_open, /* open */ + NULL, /* flush */ + fb_release, /* release */ + NULL /* fsync */ +}; + +int +register_framebuffer(struct fb_info *fb_info) +{ + int i, j; + static int fb_ever_opened[FB_MAX]; + static int first = 1; + + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; + for (i = 0 ; i < FB_MAX; i++) + if (!registered_fb[i]) + break; + fb_info->node=GET_INODE(i); + registered_fb[i] = fb_info; + if (!fb_ever_opened[i]) { + /* + * We assume initial frame buffer devices can be opened this + * many times + */ + for (j = 0; j < MAX_NR_CONSOLES; j++) + if (con2fb_map[j] == i) + fb_info->fbops->fb_open(fb_info,0); + fb_ever_opened[i] = 1; + } + + if (first) { + first = 0; + take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); + } + + return 0; +} + +int +unregister_framebuffer(const struct fb_info *fb_info) +{ + int i, j; + + i = GET_FB_IDX(fb_info->node); + for (j = 0; j < MAX_NR_CONSOLES; j++) + if (con2fb_map[j] == i) + return -EBUSY; + if (!registered_fb[i]) + return -EINVAL; + registered_fb[i]=NULL; + num_registered_fb--; + return 0; +} + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_fbmem; +#endif + +__initfunc(void +fbmem_init(void)) +{ + int i; + +#ifdef CONFIG_PROC_FS + proc_fbmem = create_proc_entry("fb", 0, 0); + if (proc_fbmem) + proc_fbmem->read_proc = fbmem_read_proc; +#endif + + if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) + printk("unable to get major %d for fb devs\n", FB_MAJOR); + + /* + * Probe for all builtin frame buffer devices + */ + for (i = 0; i < num_pref_init_funcs; i++) + pref_init_funcs[i](); + + for (i = 0; i < NUM_FB_DRIVERS; i++) + if (fb_drivers[i].init) + fb_drivers[i].init(); +} + + +int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, + const struct fb_info *fb_info) +{ +#if 0 + /* + * long long divisions .... $#%%#$ + */ + unsigned long long hpicos, vpicos; + const unsigned long long _1e12 = 1000000000000ULL; + const struct fb_monspecs *monspecs = &fb_info->monspecs; + + hpicos = (unsigned long long)htotal*(unsigned long long)pixclock; + vpicos = (unsigned long long)vtotal*(unsigned long long)hpicos; + if (!vpicos) + return 0; + + if (monspecs->hfmin == 0) + return 1; + + if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 || + vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12) + return 0; +#endif + return 1; +} + +int fbmon_dpms(const struct fb_info *fb_info) +{ + return fb_info->monspecs.dpms; +} + + + /* + * Command line options + */ + +__initfunc(void video_setup(char *options, int *ints)) +{ + int i, j; + + if (!options || !*options) + return; + + if (!strncmp(options, "map:", 4)) { + options += 4; + if (*options) + for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { + if (!options[j]) + j = 0; + con2fb_map[i] = (options[j++]-'0') % FB_MAX; + } + return; + } + + if (!strncmp(options, "vc:", 3)) { + options += 3; + if (*options) + first_fb_vc = simple_strtoul(options, &options, 10) - 1; + if (first_fb_vc < 0) + first_fb_vc = 0; + if (*options++ == '-') + last_fb_vc = simple_strtoul(options, &options, 10) - 1; + fbcon_is_default = 0; + } + + if (num_pref_init_funcs == FB_MAX) + return; + + for (i = 0; i < NUM_FB_DRIVERS; i++) { + j = strlen(fb_drivers[i].name); + if (!strncmp(options, fb_drivers[i].name, j) && + options[j] == ':') { + if (!strcmp(options+j+1, "off")) + fb_drivers[i].init = NULL; + else { + if (fb_drivers[i].init) { + pref_init_funcs[num_pref_init_funcs++] = + fb_drivers[i].init; + fb_drivers[i].init = NULL; + } + if (fb_drivers[i].setup) + fb_drivers[i].setup(options+j+1, ints); + } + return; + } + } + /* + * If we get here no fb was specified and we default to pass the + * options to the first frame buffer that has an init and a setup + * function. + */ + for (i = 0; i < NUM_FB_DRIVERS; i++) { + if (fb_drivers[i].init && fb_drivers[i].setup) { + pref_init_funcs[num_pref_init_funcs++] = + fb_drivers[i].init; + fb_drivers[i].init = NULL; + + fb_drivers[i].setup(options, ints); + return; + } + } +} + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(register_framebuffer); +EXPORT_SYMBOL(unregister_framebuffer); diff --git a/drivers/video/font.h b/drivers/video/font.h deleted file mode 100644 index ab4385b17..000000000 --- a/drivers/video/font.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * font.h -- `Soft' font definitions - * - * Created 1995 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#ifndef _FONT_H_ -#define _FONT_H_ - -#include <linux/types.h> - -struct fbcon_font_desc { - int idx; - char *name; - int width, height; - void *data; - int pref; -}; - -#define VGA8x8_IDX 0 -#define VGA8x16_IDX 1 -#define PEARL8x8_IDX 2 -#define VGA6x11_IDX 3 -#define SUN8x16_IDX 4 -#define SUN12x22_IDX 5 -#define ACORN8x8_IDX 6 - -extern struct fbcon_font_desc font_vga_8x8, - font_vga_8x16, - font_pearl_8x8, - font_vga_6x11, - font_sun_8x16, - font_sun_12x22, - font_acorn_8x8; - -/* Find a font with a specific name */ - -extern struct fbcon_font_desc *fbcon_find_font(char *name); - -/* Get the default font for a specific screen size */ - -extern struct fbcon_font_desc *fbcon_get_default_font(int xres, int yres); - -/* Max. length for the name of a predefined font */ -#define MAX_FONT_NAME 32 - -#endif /* _FONT_H_ */ diff --git a/drivers/video/font_6x11.c b/drivers/video/font_6x11.c index 88a20e09e..362529c2b 100644 --- a/drivers/video/font_6x11.c +++ b/drivers/video/font_6x11.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX (11*256) diff --git a/drivers/video/font_8x16.c b/drivers/video/font_8x16.c index 26a34bce7..786619712 100644 --- a/drivers/video/font_8x16.c +++ b/drivers/video/font_8x16.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX 4096 diff --git a/drivers/video/font_8x8.c b/drivers/video/font_8x8.c index ff0701a68..6358e671f 100644 --- a/drivers/video/font_8x8.c +++ b/drivers/video/font_8x8.c @@ -4,7 +4,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX 2048 diff --git a/drivers/video/font_acorn_8x8.c b/drivers/video/font_acorn_8x8.c index 41acfd5f6..154d0fb39 100644 --- a/drivers/video/font_acorn_8x8.c +++ b/drivers/video/font_acorn_8x8.c @@ -2,7 +2,7 @@ #include <linux/config.h> -#include "font.h" +#include <video/font.h> static unsigned char acorndata_8x8[] = { /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ diff --git a/drivers/video/font_pearl_8x8.c b/drivers/video/font_pearl_8x8.c index 1f4e40fa6..c8d7da571 100644 --- a/drivers/video/font_pearl_8x8.c +++ b/drivers/video/font_pearl_8x8.c @@ -9,7 +9,7 @@ /* */ /**********************************************/ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX 2048 diff --git a/drivers/video/font_sun12x22.c b/drivers/video/font_sun12x22.c index 837e04203..c4cd54c7a 100644 --- a/drivers/video/font_sun12x22.c +++ b/drivers/video/font_sun12x22.c @@ -1,4 +1,4 @@ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX 5632 diff --git a/drivers/video/font_sun8x16.c b/drivers/video/font_sun8x16.c index 8bf027807..9f5bc40b4 100644 --- a/drivers/video/font_sun8x16.c +++ b/drivers/video/font_sun8x16.c @@ -1,4 +1,4 @@ -#include "font.h" +#include <video/font.h> #define FONTDATAMAX 4096 diff --git a/drivers/video/fonts.c b/drivers/video/fonts.c index 72f29410a..52ab1a697 100644 --- a/drivers/video/fonts.c +++ b/drivers/video/fonts.c @@ -16,7 +16,7 @@ #if defined(__mc68000__) || defined(CONFIG_APUS) #include <asm/setup.h> #endif -#include "font.h" +#include <video/font.h> #define NO_FONTS @@ -90,7 +90,7 @@ struct fbcon_font_desc *fbcon_get_default_font(int xres, int yres) for(i=0; i<num_fonts; i++) { f = fbcon_fonts[i]; c = f->pref; -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) #ifdef CONFIG_FONT_PEARL_8x8 if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX) c = 100; diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index 7a7bede02..11689b150 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -22,10 +22,10 @@ #include <asm/blinken.h> #include <asm/hwtest.h> -#include "fbcon-mfb.h" -#include "fbcon-cfb2.h" -#include "fbcon-cfb4.h" -#include "fbcon-cfb8.h" +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -360,6 +360,7 @@ __initfunc(int hpfb_init_one(unsigned long base)) fb_info.switch_con = &hpfb_switch; fb_info.updatevar = &fb_update_var; fb_info.blank = &hpfb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&hpfb_defined, 1); hpfb_get_var(&disp.var, -1, &fb_info); diff --git a/drivers/video/iga.h b/drivers/video/iga.h new file mode 100644 index 000000000..f68899314 --- /dev/null +++ b/drivers/video/iga.h @@ -0,0 +1,27 @@ +/* $Id: iga.h,v 1.1 1998/10/07 11:36:07 jj Exp $ + * iga1682.h: Sparc/PCI iga1682 driver constants etc. + * + * Copyleft 1998 V. Roganov and G. Raiko + */ + +#ifndef _IGA1682_H +#define _IGA1682_H 1 + +struct iga1682_info +{ + unsigned int total_vram; +}; + +#define DAC_W_INDEX 0x03C8 +#define DAC_DATA 0x03C9 +#define IGA_EXT_CNTRL 0x3CE +#define IGA_IDX_EXT_BUS_CNTL 0x30 +#define MEM_SIZE_ALIAS 0x3 +#define MEM_SIZE_1M 0x0 +#define MEM_SIZE_2M 0x1 +#define MEM_SIZE_4M 0x2 +#define MEM_SIZE_RESERVED 0x3 +#define IGA_IDX_OVERSCAN_COLOR 0x58 +#define IGA_IDX_EXT_MEM_2 0x72 + +#endif /* !(_IGA1682_H) */ diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c new file mode 100644 index 000000000..e3a86c868 --- /dev/null +++ b/drivers/video/igafb.c @@ -0,0 +1,783 @@ +/* + * linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682 + * + * Copyright (C) 1998 Vladimir Roganov and Gleb Raiko + * + * This driver is partly based on the Frame buffer device for ATI Mach64 + * and partially on VESA-related code. + * + * Copyright (C) 1997-1998 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/****************************************************************************** + + TODO: + Despite of IGA Card has advanced graphic acceleration, + initial version is almost dummy and does not support it. + Support for video modes and acceleration must be added + together with accelerated X-Windows driver implementation. + + (Anyone to help with this?) + + Most important thing at this moment is that we have working + JavaEngine1 console & X with new console interface. + +******************************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/selection.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> +#include <linux/kd.h> +#include <linux/vt_kern.h> + +#include <asm/io.h> + +#ifdef __sparc__ +#include <asm/pbm.h> +#include <asm/pcic.h> +#endif + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#include "iga.h" + +static char igafb_name[16] = "IGA 1682"; +static char fontname[40] __initdata = { 0 }; + +struct pci_mmap_map { + unsigned long voff; + unsigned long poff; + unsigned long size; + unsigned long prot_flag; + unsigned long prot_mask; +}; + +struct fb_info_iga { + struct fb_info fb_info; + unsigned long frame_buffer_phys; + unsigned long frame_buffer; + unsigned long io_base_phys; + unsigned long io_base; + u32 total_vram; + struct pci_mmap_map *mmap_map; + struct { u_short blue, green, red, pad; } palette[256]; + int video_cmap_len; + int currcon; + struct display disp; + struct display_switch dispsw; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; +#ifdef __sparc__ + u8 open; + u8 mmaped; + int vtconsole; + int consolecnt; +#endif +}; + +struct fb_var_screeninfo default_var = { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +#ifdef __sparc__ +struct fb_var_screeninfo default_var_1024x768 __initdata = { + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; + +struct fb_var_screeninfo default_var_1152x900 __initdata = { + /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */ + 1152, 900, 1152, 900, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; + +struct fb_var_screeninfo default_var_1280x1024 __initdata = { + /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED +}; + +/* + * Memory-mapped I/O functions for Sparc PCI + */ +static inline unsigned char pci_inb (struct fb_info_iga *info, + unsigned int reg) +{ + return *(volatile unsigned char*)(info->io_base + reg); +} +static inline void pci_outb (struct fb_info_iga *info, unsigned char c, + unsigned int reg) +{ + *(volatile unsigned char*)(info->io_base + reg) = c; +} +static inline unsigned int iga_inb(struct fb_info_iga *info, + unsigned int reg, unsigned int idx ) +{ + pci_outb(info, idx, reg); + return pci_inb(info, reg + 1); +} +static inline void iga_outb(struct fb_info_iga *info, unsigned char val, + unsigned int reg, unsigned int idx ) +{ + pci_outb(info, idx, reg); + pci_outb(info, val, reg+1); +} + +#endif /* __sparc__ */ + +/* + * Very important functionality for the JavaEngine1 computer: + * make screen border black (usign special IGA registers) + */ +static void iga_blank_border(struct fb_info_iga *info) +{ + int i; + + for (i=0; i < 3; i++) + iga_outb(info, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i); +} + + +/* + * Frame buffer device API + */ + +/* + * Open/Release the frame buffer device + */ + +static int igafb_open(struct fb_info *info, int user) +{ + /* + * Nothing, only a usage count for the moment + */ + MOD_INC_USE_COUNT; + return(0); +} + +static int igafb_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return(0); +} + +static int igafb_update_var(int con, struct fb_info *info) +{ + return 0; +} + +static int igafb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_info_iga *fb = (struct fb_info_iga*)info; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, igafb_name); + + fix->smem_start = (char *)fb->frame_buffer; + fix->smem_len = fb->total_vram; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->line_length = default_var.xres * (default_var.bits_per_pixel/8); + fix->visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + return 0; +} + +static int igafb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if(con == -1) + memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); + else + *var = fb_display[con].var; + return 0; +} + +static int igafb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); + return 0; +} + +#ifdef __sparc__ +static int igafb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct fb_info_iga *fb = (struct fb_info_iga *)info; + unsigned int size, page, map_size = 0; + unsigned long map_offset = 0; + int i; + + if (!fb->mmap_map) + return -ENXIO; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + /* To stop the swapper from even considering these pages. */ + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + /* Each page, see which map applies */ + for (page = 0; page < size; ) { + map_size = 0; + for (i = 0; fb->mmap_map[i].size; i++) { + unsigned long start = fb->mmap_map[i].voff; + unsigned long end = start + fb->mmap_map[i].size; + unsigned long offset = vma->vm_offset + page; + + if (start > offset) + continue; + if (offset >= end) + continue; + + map_size = fb->mmap_map[i].size - (offset - start); + map_offset = fb->mmap_map[i].poff + (offset - start); + break; + } + if (!map_size) { + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + + pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask); + pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; + + if (remap_page_range(vma->vm_start + page, map_offset, + map_size, vma->vm_page_prot)) + return -EAGAIN; + + page += map_size; + } + + if (!map_size) + return -EINVAL; + + vma->vm_file = file; + file->f_count++; + vma->vm_flags |= VM_IO; + + if (!fb->mmaped) { + int lastconsole = 0; + + if (info->display_fg) + lastconsole = info->display_fg->vc_num; + fb->mmaped = 1; + if (fb->consolecnt && fb_display[lastconsole].fb_info ==info) { + fb->vtconsole = lastconsole; + vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + } + } + return 0; +} +#endif /* __sparc__ */ + + +static int iga_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info) +{ + /* + * Read a single color register and split it into colors/transparent. + * Return != 0 for invalid regno. + */ + struct fb_info_iga *info = (struct fb_info_iga*) fb_info; + + if (regno >= info->video_cmap_len) + return 1; + + *red = info->palette[regno].red; + *green = info->palette[regno].green; + *blue = info->palette[regno].blue; + *transp = 0; + return 0; +} + +static int iga_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + struct fb_info_iga *info = (struct fb_info_iga*) fb_info; + + if (regno >= info->video_cmap_len) + return 1; + + info->palette[regno].red = red; + info->palette[regno].green = green; + info->palette[regno].blue = blue; + + pci_outb(info, regno, DAC_W_INDEX); + pci_outb(info, red, DAC_DATA); + pci_outb(info, green, DAC_DATA); + pci_outb(info, blue, DAC_DATA); + + if (regno << 16) + switch (default_var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: + info->fbcon_cmap.cfb16[regno] = + (regno << 10) | (regno << 5) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + info->fbcon_cmap.cfb24[regno] = + (regno << 16) | (regno << 8) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + i = (regno << 8) | regno; + info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; +#endif + } + return 0; +} + +static void do_install_cmap(int con, struct fb_info *fb_info) +{ + struct fb_info_iga *info = (struct fb_info_iga*) fb_info; + + if (con != info->currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, 1, + iga_setcolreg, &info->fb_info); + else + fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1, + iga_setcolreg, &info->fb_info); +} + +static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *fb_info) +{ + struct fb_info_iga *info = (struct fb_info_iga*) fb_info; + + if (con == info->currcon) /* current console? */ + return fb_get_cmap(cmap, kspc, iga_getcolreg, &info->fb_info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(info->video_cmap_len), + cmap, kspc ? 0 : 2); + return 0; +} + +static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + int err; + struct fb_info_iga *fb = (struct fb_info_iga*) info; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + err = fb_alloc_cmap(&fb_display[con].cmap, + fb->video_cmap_len,0); + if (err) + return err; + } + if (con == fb->currcon) /* current console? */ + return fb_set_cmap(cmap, kspc, iga_setcolreg, info); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return 0; +} + +static int igafb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + /* no panning */ + return -EINVAL; +} + +static int igafb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + return -EINVAL; +} + +/* + * Framebuffer option structure + */ +static struct fb_ops igafb_ops = { + igafb_open, + igafb_release, + igafb_get_fix, + igafb_get_var, + igafb_set_var, + igafb_get_cmap, + igafb_set_cmap, + igafb_pan_display, + igafb_ioctl, +#ifdef __sparc__ + igafb_mmap +#else + NULL +#endif +}; + +static void igafb_set_disp(int con, struct fb_info_iga *info) +{ + struct fb_fix_screeninfo fix; + struct display *display; + struct display_switch *sw; + + if (con >= 0) + display = &fb_display[con]; + else + display = &info->disp; /* used during initialization */ + + igafb_get_fix(&fix, con, &info->fb_info); + + memset(display, 0, sizeof(struct display)); + display->screen_base = (char*)info->frame_buffer; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->next_line = fix.line_length; + display->can_soft_blank = 0; + display->inverse = 0; + igafb_get_var(&display->var, -1, &info->fb_info); + + switch (default_var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + sw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 15: + case 16: + sw = &fbcon_cfb16; + display->dispsw_data = fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + sw = &fbcon_cfb24; + display->dispsw_data = fbcon_cmap.cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + sw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; + break; +#endif + default: + return; + } + memcpy(&info->dispsw, sw, sizeof(*sw)); + display->dispsw = &info->dispsw; + + display->scrollmode = SCROLL_YREDRAW; + info->dispsw.bmove = fbcon_redraw_bmove; +} + +static int igafb_switch(int con, struct fb_info *fb_info) +{ + struct fb_info_iga *info = (struct fb_info_iga*) fb_info; + + /* Do we have to save the colormap? */ + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, + iga_getcolreg, fb_info); + + info->currcon = con; + /* Install new colormap */ + do_install_cmap(con, fb_info); + igafb_update_var(con, fb_info); + return 1; +} + + + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void igafb_blank(int blank, struct fb_info *info) +{ + /* Not supported */ +} + + +__initfunc(static int iga_init(struct fb_info_iga *info)) +{ + char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) + & MEM_SIZE_ALIAS; + switch (vramsz) { + case MEM_SIZE_1M: + info->total_vram = 0x100000; + break; + case MEM_SIZE_2M: + info->total_vram = 0x200000; + break; + case MEM_SIZE_4M: + case MEM_SIZE_RESERVED: + info->total_vram = 0x400000; + break; + } + + if (default_var.bits_per_pixel > 8) { + info->video_cmap_len = 16; + } else { + int i, j; + for(i = 0; i < 16; i++) { + j = color_table[i]; + info->palette[i].red = default_red[j]; + info->palette[i].green = default_grn[j]; + info->palette[i].blue = default_blu[j]; + } + info->video_cmap_len = 256; + } + + strcpy(info->fb_info.modename, igafb_name); + info->fb_info.node = -1; + info->fb_info.fbops = &igafb_ops; + info->fb_info.disp = &info->disp; + strcpy(info->fb_info.fontname, fontname); + info->fb_info.changevar = NULL; + info->fb_info.switch_con = &igafb_switch; + info->fb_info.updatevar = &igafb_update_var; + info->fb_info.blank = &igafb_blank; + info->fb_info.flags=FBINFO_FLAG_DEFAULT; + + { + int j, k; + for (j = 0; j < 16; j++) { + k = color_table[j]; + info->palette[j].red = default_red[k]; + info->palette[j].green = default_grn[k]; + info->palette[j].blue = default_blu[k]; + } + } + + igafb_set_disp(-1, info); + + if (register_framebuffer(&info->fb_info) < 0) + return 0; + + printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n", + GET_FB_IDX(info->fb_info.node), igafb_name, + info->frame_buffer_phys, info->total_vram >> 20); + + iga_blank_border(info); + return 1; +} + + +__initfunc(void igafb_init(void)) +{ + struct pci_dev *pdev; + struct fb_info_iga *info; + unsigned long addr; + extern int con_is_present(void); + + /* Do not attach when we have a serial console. */ + if (!con_is_present()) + return; + + pdev = pci_find_device(PCI_VENDOR_ID_INTERG, + PCI_DEVICE_ID_INTERG_1682, 0); + if(pdev == NULL) + return; + + info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC); + if (!info) { + printk("igafb_init: can't alloc fb_info_iga\n"); + return; + } + memset(info, 0, sizeof(struct fb_info_iga)); + + info->frame_buffer = pdev->base_address[0]; + if (!info->frame_buffer) + return; + + pcibios_read_config_dword(0, pdev->devfn, + PCI_BASE_ADDRESS_0, + (unsigned int*)&addr); + if (!addr) + return; + info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK; + +#ifdef __sparc__ + + info->io_base_phys = info->frame_buffer_phys; + + /* Obtain virtual address and correct physical by PCIC shift */ + info->io_base = pcic_alloc_io(&info->io_base_phys); + if (!info->io_base) { + return; + } + + /* + * Figure mmap addresses from PCI config space. + * We need two regions: for video memory and for I/O ports. + * Later one can add region for video coprocessor registers. + * However, mmap routine loops until size != 0, so we put + * one additional region with size == 0. + */ + + info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC); + if (!info->mmap_map) { + printk("igafb_init: can't alloc mmap_map\n"); + kfree(info); + return; + } + + memset(info->mmap_map, 0, 4 * sizeof(*info->mmap_map)); + + /* + * Set default vmode and cmode from PROM properties. + */ + { + struct pcidev_cookie *cookie = pdev->sysdata; + int node = cookie->prom_node; + int width = prom_getintdefault(node, "width", 1024); + int height = prom_getintdefault(node, "height", 768); + int depth = prom_getintdefault(node, "depth", 8); + switch (width) { + case 1024: + if (height == 768) + default_var = default_var_1024x768; + break; + case 1152: + if (height == 900) + default_var = default_var_1152x900; + break; + case 1280: + if (height == 1024) + default_var = default_var_1280x1024; + break; + default: + break; + } + + switch (depth) { + case 8: + default_var.bits_per_pixel = 8; + break; + case 16: + default_var.bits_per_pixel = 16; + break; + case 24: + default_var.bits_per_pixel = 24; + break; + case 32: + default_var.bits_per_pixel = 32; + break; + default: + break; + } + } + +#endif + if (!iga_init(info)) { + if (info->mmap_map) + kfree(info->mmap_map); + kfree(info); + } + +#ifdef __sparc__ + /* + * Add /dev/fb mmap values. + */ + + /* First region is for video memory */ + info->mmap_map[0].voff = 0x0; + info->mmap_map[0].poff = info->frame_buffer_phys & PAGE_MASK; + info->mmap_map[0].size = info->total_vram & PAGE_MASK; + info->mmap_map[0].prot_mask = SRMMU_CACHE; + info->mmap_map[0].prot_flag = SRMMU_WRITE; + + /* Second region is for I/O ports */ + info->mmap_map[1].voff = info->frame_buffer_phys & PAGE_MASK; + info->mmap_map[1].poff = info->io_base_phys & PAGE_MASK; + info->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */ + info->mmap_map[1].prot_mask = SRMMU_CACHE; + info->mmap_map[1].prot_flag = SRMMU_WRITE; +#endif /* __sparc__ */ +} + +__initfunc(void igafb_setup(char *options, int *ints)) +{ + char *this_opt; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } + } +} diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c new file mode 100644 index 000000000..d50c403a6 --- /dev/null +++ b/drivers/video/imsttfb.c @@ -0,0 +1,1818 @@ +/* + * drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo + * + * This file is derived from the powermac console "imstt" driver: + * Copyright (C) 1997 Sigurdur Asgeirsson + * With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu) + * Modified by Danilo Beuche 1998 + * Some register values added by Damien Doligez, INRIA Rocquencourt + * + * This file was written by Ryan Nielsen (ran@krazynet.com) + * Most of the frame buffer device stuff was copied from atyfb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#if defined(CONFIG_PPC) +#include <linux/nvram.h> +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <video/macmodes.h> +#endif + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#ifndef __powerpc__ +#define eieio() /* Enforce In-order Execution of I/O */ +#endif + +enum { + IBM = 0x00, + TVP = 0x01 +}; + +/* TwinTurbo (Cosmo) registers */ +enum { + S1SA = 0, /* 0x00 */ + S2SA = 1, /* 0x04 */ + SP = 2, /* 0x08 */ + DSA = 3, /* 0x0C */ + CNT = 4, /* 0x10 */ + DP_OCTRL= 5, /* 0x14 */ + BI = 8, /* 0x20 */ + MBC = 9, /* 0x24 */ + BLTCTL = 10, /* 0x28 */ + + /* Scan Timing Generator Registers */ + HES = 12, /* 0x30 */ + HEB = 13, /* 0x34 */ + HSB = 14, /* 0x38 */ + HT = 15, /* 0x3C */ + VES = 16, /* 0x40 */ + VEB = 17, /* 0x44 */ + VSB = 18, /* 0x48 */ + VT = 19, /* 0x4C */ + HCIV = 20, /* 0x50 */ + VCIV = 21, /* 0x54 */ + TCDR = 22, /* 0x58 */ + VIL = 23, /* 0x5C */ + STGCTL = 24, /* 0x60 */ + + /* Screen Refresh Generator Registers */ + SSR = 25, /* 0x64 */ + HRIR = 26, /* 0x68 */ + SPR = 27, /* 0x6C */ + CMR = 28, /* 0x70 */ + SRGCTL = 29, /* 0x74 */ + + /* RAM Refresh Generator Registers */ + RRCIV = 30, /* 0x78 */ + RRSC = 31, /* 0x7C */ + RRCR = 34, /* 0x88 */ + + /* System Registers */ + GIOE = 32, /* 0x80 */ + GIO = 33, /* 0x84 */ + SCR = 35, /* 0x8C */ + SSTATUS = 36, /* 0x90 */ + PRC = 37, /* 0x94 */ + +#if 0 + /* PCI Registers */ + DVID = 0x00000000L, + SC = 0x00000004L, + CCR = 0x00000008L, + OG = 0x0000000CL, + BARM = 0x00000010L, + BARER = 0x00000030L, +#endif +}; + +/* IBM ramdac direct registers */ +enum { + PADDRW = 0x00, + PDATA = 0x04, + PPMASK = 0x08, + PADDRR = 0x0c, + PIDXLO = 0x10, + PIDXHI = 0x14, + PIDXDATA= 0x18, + PIDXCTL = 0x1c +}; + +/* IBM ramdac indirect registers */ +enum { + CLKCTL = 0x02, /* (0x01) Miscellaneous Clock Control */ + SYNCCTL = 0x03, /* (0x00) Sync Control */ + HSYNCPOS = 0x04, /* (0x00) Horizontal Sync Position */ + PWRMNGMT = 0x05, /* (0x00) Power Management */ + DACOP = 0x06, /* (0x02) DAC Operation */ + PALETCTL = 0x07, /* (0x00) Palette Control */ + SYSCLKCTL = 0x08, /* (0x01) System Clock Control */ + PIXFMT = 0x0a, /* () Pixel Format [bpp >> 3 + 2] */ + BPP8 = 0x0b, /* () 8 Bits/Pixel Control */ + BPP16 = 0x0c, /* () 16 Bits/Pixel Control [bit 1=1 for 565] */ + BPP24 = 0x0d, /* () 24 Bits/Pixel Control */ + BPP32 = 0x0e, /* () 32 Bits/Pixel Control */ + PIXCTL1 = 0x10, /* (0x05) Pixel PLL Control 1 */ + PIXCTL2 = 0x11, /* (0x00) Pixel PLL Control 2 */ + SYSCLKN = 0x15, /* () System Clock N (System PLL Reference Divider) */ + SYSCLKM = 0x16, /* () System Clock M (System PLL VCO Divider) */ + SYSCLKP = 0x17, /* () System Clock P */ + SYSCLKC = 0x18, /* () System Clock C */ + /* + * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1) + * c is charge pump bias which depends on the VCO frequency + */ + PIXM0 = 0x20, /* () Pixel M 0 */ + PIXN0 = 0x21, /* () Pixel N 0 */ + PIXP0 = 0x22, /* () Pixel P 0 */ + PIXC0 = 0x23, /* () Pixel C 0 */ + CURSCTL = 0x30, /* (0x00) Cursor Control */ + CURSXLO = 0x31, /* () Cursor X position, low 8 bits */ + CURSXHI = 0x32, /* () Cursor X position, high 8 bits */ + CURSYLO = 0x33, /* () Cursor Y position, low 8 bits */ + CURSYHI = 0x34, /* () Cursor Y position, high 8 bits */ + CURSHOTX = 0x35, /* () Cursor Hot Spot X */ + CURSHOTY = 0x36, /* () Cursor Hot Spot Y */ + CURSACCTL = 0x37, /* () Advanced Cursor Control Enable */ + CURSACATTR = 0x38, /* () Advanced Cursor Attribute */ + CURS1R = 0x40, /* () Cursor 1 Red */ + CURS1G = 0x41, /* () Cursor 1 Green */ + CURS1B = 0x42, /* () Cursor 1 Blue */ + CURS2R = 0x43, /* () Cursor 2 Red */ + CURS2G = 0x44, /* () Cursor 2 Green */ + CURS2B = 0x45, /* () Cursor 2 Blue */ + CURS3R = 0x46, /* () Cursor 3 Red */ + CURS3G = 0x47, /* () Cursor 3 Green */ + CURS3B = 0x48, /* () Cursor 3 Blue */ + BORDR = 0x60, /* () Border Color Red */ + BORDG = 0x61, /* () Border Color Green */ + BORDB = 0x62, /* () Border Color Blue */ + MISCTL1 = 0x70, /* (0x00) Miscellaneous Control 1 */ + MISCTL2 = 0x71, /* (0x00) Miscellaneous Control 2 */ + MISCTL3 = 0x72, /* (0x00) Miscellaneous Control 3 */ + KEYCTL = 0x78 /* (0x00) Key Control/DB Operation */ +}; + +/* TI TVP 3030 RAMDAC Direct Registers */ +enum { + TVPADDRW = 0x00, /* 0 Palette/Cursor RAM Write Adress/Index */ + TVPPDATA = 0x04, /* 1 Palette Data RAM Data */ + TVPPMASK = 0x08, /* 2 Pixel Read-Mask */ + TVPPADRR = 0x0c, /* 3 Palette/Cursor RAM Read Adress */ + TVPCADRW = 0x10, /* 4 Cursor/Overscan Color Write Address */ + TVPCDATA = 0x14, /* 5 Cursor/Overscan Color Data */ + /* 6 reserved */ + TVPCADRR = 0x1c, /* 7 Cursor/Overscan Color Read Address */ + /* 8 reserved */ + TVPDCCTL = 0x24, /* 9 Direct Cursor Control */ + TVPIDATA = 0x28, /* 10 Index Data */ + TVPCRDAT = 0x2c, /* 11 Cursor RAM Data */ + TVPCXPOL = 0x30, /* 12 Cursor-Position X LSB */ + TVPCXPOH = 0x34, /* 13 Cursor-Position X MSB */ + TVPCYPOL = 0x38, /* 14 Cursor-Position Y LSB */ + TVPCYPOH = 0x3c, /* 15 Cursor-Position Y MSB */ +}; + +/* TI TVP 3030 RAMDAC Indirect Registers */ +enum { + TVPIRREV = 0x01, /* Silicon Revision [RO] */ + TVPIRICC = 0x06, /* Indirect Cursor Control (0x00) */ + TVPIRBRC = 0x07, /* Byte Router Control (0xe4) */ + TVPIRLAC = 0x0f, /* Latch Control (0x06) */ + TVPIRTCC = 0x18, /* True Color Control (0x80) */ + TVPIRMXC = 0x19, /* Multiplex Control (0x98) */ + TVPIRCLS = 0x1a, /* Clock Selection (0x07) */ + TVPIRPPG = 0x1c, /* Palette Page (0x00) */ + TVPIRGEC = 0x1d, /* General Control (0x00) */ + TVPIRMIC = 0x1e, /* Miscellaneous Control (0x00) */ + TVPIRPLA = 0x2c, /* PLL Address */ + TVPIRPPD = 0x2d, /* Pixel Clock PLL Data */ + TVPIRMPD = 0x2e, /* Memory Clock PLL Data */ + TVPIRLPD = 0x2f, /* Loop Clock PLL Data */ + TVPIRCKL = 0x30, /* Color-Key Overlay Low */ + TVPIRCKH = 0x31, /* Color-Key Overlay High */ + TVPIRCRL = 0x32, /* Color-Key Red Low */ + TVPIRCRH = 0x33, /* Color-Key Red High */ + TVPIRCGL = 0x34, /* Color-Key Green Low */ + TVPIRCGH = 0x35, /* Color-Key Green High */ + TVPIRCBL = 0x36, /* Color-Key Blue Low */ + TVPIRCBH = 0x37, /* Color-Key Blue High */ + TVPIRCKC = 0x38, /* Color-Key Control (0x00) */ + TVPIRMLC = 0x39, /* MCLK/Loop Clock Control (0x18) */ + TVPIRSEN = 0x3a, /* Sense Test (0x00) */ + TVPIRTMD = 0x3b, /* Test Mode Data */ + TVPIRRML = 0x3c, /* CRC Remainder LSB [RO] */ + TVPIRRMM = 0x3d, /* CRC Remainder MSB [RO] */ + TVPIRRMS = 0x3e, /* CRC Bit Select [WO] */ + TVPIRDID = 0x3f, /* Device ID [RO] (0x30) */ + TVPIRRES = 0xff /* Software Reset [WO] */ +}; + +struct initvalues { + __u8 addr, value; +}; + +static struct initvalues ibm_initregs[] __initdata = { + { CLKCTL, 0x21 }, + { SYNCCTL, 0x00 }, + { HSYNCPOS, 0x00 }, + { PWRMNGMT, 0x00 }, + { DACOP, 0x02 }, + { PALETCTL, 0x00 }, + { SYSCLKCTL, 0x01 }, + + /* + * Note that colors in X are correct only if all video data is + * passed through the palette in the DAC. That is, "indirect + * color" must be configured. This is the case for the IBM DAC + * used in the 2MB and 4MB cards, at least. + */ + { BPP8, 0x00 }, + { BPP16, 0x00 }, + { BPP24, 0x00 }, + { BPP32, 0x00 }, + + { PIXCTL1, 0x05 }, + { PIXCTL2, 0x00 }, + { SYSCLKN, 0x08 }, + { SYSCLKM, 0x4f }, + { SYSCLKP, 0x00 }, + { SYSCLKC, 0x00 }, + { CURSCTL, 0x02 }, + { CURSACCTL, 0x01 }, + { CURSACATTR, 0xa8 }, + { CURS1R, 0xff }, + { CURS1G, 0xff }, + { CURS1B, 0xff }, + { CURS2R, 0xff }, + { CURS2G, 0xff }, + { CURS2B, 0xff }, + { CURS3R, 0xff }, + { CURS3G, 0xff }, + { CURS3B, 0xff }, + { BORDR, 0xff }, + { BORDG, 0xff }, + { BORDB, 0xff }, + { MISCTL1, 0x01 }, + { MISCTL2, 0x45 }, + { MISCTL3, 0x00 }, + { KEYCTL, 0x00 } +}; + +static struct initvalues tvp_initregs[] __initdata = { + { 0x6, 0x00 }, + { 0x7, 0xe4 }, + { 0xf, 0x06 }, + { 0x18, 0x80 }, + { 0x19, 0x4d }, + { 0x1a, 0x05 }, + { 0x1c, 0x00 }, + { 0x1d, 0x00 }, + { 0x1e, 0x08 }, + { 0x30, 0xff }, + { 0x31, 0xff }, + { 0x32, 0xff }, + { 0x33, 0xff }, + { 0x34, 0xff }, + { 0x35, 0xff }, + { 0x36, 0xff }, + { 0x37, 0xff }, + { 0x38, 0x00 }, + { TVPIRPLA, 0x00 }, + { TVPIRPPD, 0xc0 }, + { TVPIRPPD, 0xd5 }, + { TVPIRPPD, 0xea }, + { TVPIRPLA, 0x00 }, + { TVPIRMPD, 0xb9 }, + { TVPIRMPD, 0x3a }, + { TVPIRMPD, 0xb1 }, + { TVPIRPLA, 0x00 }, + { TVPIRLPD, 0xc1 }, + { TVPIRLPD, 0x3d }, + { TVPIRLPD, 0xf3 }, +}; + +struct imstt_regvals { + __u32 pitch; + __u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil; + __u8 pclk_m, pclk_n, pclk_p; + /* Values of the tvp which change depending on colormode x resolution */ + __u8 mlc[3]; /* Memory Loop Config 0x39 */ + __u8 lckl_p[3]; /* P value of LCKL PLL */ +}; + +struct imstt_cursor { + struct timer_list timer; + int enable; + int on; + int vbl_cnt; + int blink_rate; + __u16 x, y, width, height; +}; + +struct fb_info_imstt { + struct fb_info info; + struct fb_fix_screeninfo fix; + struct display disp; + struct display_switch dispsw; + union { +#ifdef FBCON_HAS_CFB16 + __u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + __u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + __u32 cfb32[16]; +#endif + } fbcon_cmap; + struct { + __u8 red, green, blue; + } palette[256]; + struct imstt_regvals init; + struct imstt_cursor cursor; + volatile __u8 *frame_buffer_phys, *frame_buffer; + volatile __u32 *dc_regs_phys, *dc_regs; + volatile __u8 *cmap_regs_phys, *cmap_regs; + __u32 total_vram; + __u32 ramdac; +}; + +#define USE_NV_MODES 1 +#define INIT_BPP 8 +#define INIT_XRES 640 +#define INIT_YRES 480 +#define CURSOR_BLINK_RATE 20 +#define CURSOR_DRAW_DELAY 2 + +static int currcon = 0; +static char fontname[40] __initdata = { 0 }; +static char curblink __initdata = 1; +static char noaccel __initdata = 0; +#if defined(CONFIG_PPC) +static signed char init_vmode __initdata = -1, init_cmode __initdata = -1; +#endif + +static struct imstt_regvals tvp_reg_init_2 = { + 512, + 0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196, + 0xec, 0x2a, 0xf3, + { 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_6 = { + 640, + 0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a, + 0xef, 0x2e, 0xb2, + { 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_12 = { + 800, + 0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270, + 0xf6, 0x2e, 0xf2, + { 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 } +}; + +static struct imstt_regvals tvp_reg_init_13 = { + 832, + 0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000, + 0xfe, 0x3e, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_17 = { + 1024, + 0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000, + 0xfc, 0x3a, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_18 = { + 1152, + 0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, + 0xfd, 0x3a, 0xf1, + { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } +}; + +static struct imstt_regvals tvp_reg_init_19 = { + 1280, + 0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7, + 0xf7, 0x36, 0xf0, + { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 } +}; + +static struct imstt_regvals tvp_reg_init_20 = { + 1280, + 0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000, + 0xf0, 0x2d, 0xf0, + { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 } +}; + +static __u32 +getclkMHz (struct fb_info_imstt *p) +{ + __u32 clk_m, clk_n, clk_p; + + clk_m = p->init.pclk_m; + clk_n = p->init.pclk_n; + clk_p = p->init.pclk_p; + + return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1)); +} + +static void +setclkMHz (struct fb_info_imstt *p, __u32 MHz) +{ + __u32 clk_m, clk_n, clk_p, x, stage, spilled; + + clk_m = clk_n = clk_p = 0; + stage = spilled = 0; + for (;;) { + switch (stage) { + case 0: + clk_m++; + break; + case 1: + clk_n++; + break; + } + x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1)); + if (x == MHz) + break; + if (x > MHz) { + spilled = 1; + stage = 1; + } else if (spilled && x < MHz) { + stage = 0; + } + } + + p->init.pclk_m = clk_m; + p->init.pclk_n = clk_n; + p->init.pclk_p = clk_p; +} + +static struct imstt_regvals * +compute_imstt_regvals_ibm (struct fb_info_imstt *p, int xres, int yres) +{ + struct imstt_regvals *init = &p->init; + __u32 MHz, hes, heb, veb, htp, vtp; + + switch (xres) { + case 640: + hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2; + MHz = 30 /* .25 */ ; + break; + case 832: + hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3; + MHz = 57 /* .27_ */ ; + break; + case 1024: + hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3; + MHz = 80; + break; + case 1152: + hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3; + MHz = 101 /* .6_ */ ; + break; + case 1280: + hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1; + MHz = yres == 960 ? 126 : 135; + break; + case 1600: + hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3; + MHz = 200; + break; + default: + return 0; + } + + setclkMHz(p, MHz); + + init->hes = hes; + init->heb = heb; + init->hsb = init->heb + (xres >> 3); + init->ht = init->hsb + htp; + init->ves = 0x0003; + init->veb = veb; + init->vsb = init->veb + yres; + init->vt = init->vsb + vtp; + init->vil = init->vsb; + + init->pitch = xres; + + return init; +} + +static struct imstt_regvals * +compute_imstt_regvals_tvp (struct fb_info_imstt *p, int xres, int yres) +{ + struct imstt_regvals *init; + + switch (xres) { + case 512: + init = &tvp_reg_init_2; + break; + case 640: + init = &tvp_reg_init_6; + break; + case 800: + init = &tvp_reg_init_12; + break; + case 832: + init = &tvp_reg_init_13; + break; + case 1024: + init = &tvp_reg_init_17; + break; + case 1152: + init = &tvp_reg_init_18; + break; + case 1280: + init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20; + break; + default: + return 0; + } + p->init = *init; + + return init; +} + +static struct imstt_regvals * +compute_imstt_regvals (struct fb_info_imstt *p, u_int xres, u_int yres) +{ + if (p->ramdac == IBM) + return compute_imstt_regvals_ibm(p, xres, yres); + else + return compute_imstt_regvals_tvp(p, xres, yres); +} + +static void +set_imstt_regvals_ibm (struct fb_info_imstt *p, u_int bpp) +{ + struct imstt_regvals *init = &p->init; + __u8 pformat = (bpp >> 3) + 2; + + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = PIXM0; eieio(); + p->cmap_regs[PIDXDATA] = init->pclk_m; eieio(); + p->cmap_regs[PIDXLO] = PIXN0; eieio(); + p->cmap_regs[PIDXDATA] = init->pclk_n; eieio(); + p->cmap_regs[PIDXLO] = PIXP0; eieio(); + p->cmap_regs[PIDXDATA] = init->pclk_p; eieio(); + p->cmap_regs[PIDXLO] = PIXC0; eieio(); + p->cmap_regs[PIDXDATA] = 0x02; eieio(); + + p->cmap_regs[PIDXLO] = PIXFMT; eieio(); + p->cmap_regs[PIDXDATA] = pformat; eieio(); +} + +static void +set_imstt_regvals_tvp (struct fb_info_imstt *p, u_int bpp) +{ + struct imstt_regvals *init = &p->init; + __u8 tcc, mxc, lckl_n, mic; + __u8 mlc, lckl_p; + + switch (bpp) { + case 8: + tcc = 0x80; + mxc = 0x4d; + lckl_n = 0xc1; + mlc = init->mlc[0]; + lckl_p = init->lckl_p[0]; + break; + case 16: + tcc = 0x44; + mxc = 0x55; + lckl_n = 0xe1; + mlc = init->mlc[1]; + lckl_p = init->lckl_p[1]; + break; + case 24: + /* ?!? */ + case 32: + tcc = 0x46; + mxc = 0x5d; + lckl_n = 0xf1; + mlc = init->mlc[2]; + lckl_p = init->lckl_p[2]; + break; + } + mic = 0x08; + + p->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + p->cmap_regs[TVPIDATA] = 0x00; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + p->cmap_regs[TVPIDATA] = init->pclk_m; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + p->cmap_regs[TVPIDATA] = init->pclk_n; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRPPD; eieio(); + p->cmap_regs[TVPIDATA] = init->pclk_p; eieio(); + + p->cmap_regs[TVPADDRW] = TVPIRTCC; eieio(); + p->cmap_regs[TVPIDATA] = tcc; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRMXC; eieio(); + p->cmap_regs[TVPIDATA] = mxc; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRMIC; eieio(); + p->cmap_regs[TVPIDATA] = mic; eieio(); + + p->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + p->cmap_regs[TVPIDATA] = 0x00; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRLPD; eieio(); + p->cmap_regs[TVPIDATA] = lckl_n; eieio(); + + p->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + p->cmap_regs[TVPIDATA] = 0x15; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRMLC; eieio(); + p->cmap_regs[TVPIDATA] = mlc; eieio(); + + p->cmap_regs[TVPADDRW] = TVPIRPLA; eieio(); + p->cmap_regs[TVPIDATA] = 0x2a; eieio(); + p->cmap_regs[TVPADDRW] = TVPIRLPD; eieio(); + p->cmap_regs[TVPIDATA] = lckl_p; eieio(); +} + +static void +set_imstt_regvals (struct fb_info_imstt *p, u_int bpp) +{ + struct imstt_regvals *init = &p->init; + __u32 ctl, pitch, byteswap, scr, line_pitch = init->pitch * (bpp >> 3); + + if (p->ramdac == IBM) + set_imstt_regvals_ibm(p, bpp); + else + set_imstt_regvals_tvp(p, bpp); + + /* + * From what I (jsk) can gather poking around with MacsBug, + * bits 8 and 9 in the SCR register control endianness + * correction (byte swapping). These bits must be set according + * to the color depth as follows: + * Color depth Bit 9 Bit 8 + * ========== ===== ===== + * 8bpp 0 0 + * 16bpp 0 1 + * 24bpp 1 0 + * 32bpp 1 1 + */ + switch (bpp) { + case 8: + ctl = 0x17b1; + pitch = init->pitch >> 2; + byteswap = 0x000; + break; + case 16: + ctl = 0x17b3; + pitch = init->pitch >> 1; + byteswap = 0x100; + break; + case 24: + ctl = 0x17b9; + pitch = init->pitch - (p->init.pitch >> 2); + byteswap = 0x200; + break; + case 32: + ctl = 0x17b5; + pitch = init->pitch; + byteswap = 0x300; + break; + } + if (p->ramdac == TVP) + ctl -= 0x30; + + out_le32(&p->dc_regs[HES], init->hes); + out_le32(&p->dc_regs[HEB], init->heb); + out_le32(&p->dc_regs[HSB], init->hsb); + out_le32(&p->dc_regs[HT], init->ht); + out_le32(&p->dc_regs[VES], init->ves); + out_le32(&p->dc_regs[VEB], init->veb); + out_le32(&p->dc_regs[VSB], init->vsb); + out_le32(&p->dc_regs[VT], init->vt); + out_le32(&p->dc_regs[VIL], init->vil); + out_le32(&p->dc_regs[HCIV], 1); + out_le32(&p->dc_regs[VCIV], 1); + out_le32(&p->dc_regs[TCDR], 4); + out_le32(&p->dc_regs[RRCIV], 1); + out_le32(&p->dc_regs[RRSC], 0x980); + out_le32(&p->dc_regs[RRCR], 0x11); + + if (p->ramdac == IBM) { + out_le32(&p->dc_regs[HRIR], 0x0100); + out_le32(&p->dc_regs[CMR], 0x00ff); + out_le32(&p->dc_regs[SRGCTL], 0x0073); + } else { + out_le32(&p->dc_regs[HRIR], 0x0200); + out_le32(&p->dc_regs[CMR], 0x01ff); + out_le32(&p->dc_regs[SRGCTL], 0x0003); + } + + switch (p->total_vram) { + case 0x00200000: + scr = 0x059d | byteswap; + break; + case 0x00400000: + case 0x00800000: + pitch /= 2; + scr = 0x150dd | byteswap; + break; + } + + out_le32(&p->dc_regs[SCR], scr); + out_le32(&p->dc_regs[SPR], pitch); + out_le32(&p->dc_regs[SP], (line_pitch << 16) | line_pitch); + out_le32(&p->dc_regs[DP_OCTRL], line_pitch); + + out_le32(&p->dc_regs[STGCTL], ctl); +} + +static void +set_16 (struct fb_info_imstt *p, __u8 x) +{ + if (p->ramdac == IBM) { + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = BPP16; eieio(); + p->cmap_regs[PIDXDATA] = x; eieio(); + } else { + /* ?!? */ + } +} + +#define set_555(_p) set_16(_p, 0x01) +#define set_565(_p) set_16(_p, 0x03) + +static void +imstt_set_cursor (struct fb_info_imstt *p, int on) +{ + struct imstt_cursor *c = &p->cursor; + + p->cmap_regs[PIDXHI] = 0; + if (!on) { + p->cmap_regs[PIDXLO] = CURSCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0x00; eieio(); + } else { + p->cmap_regs[PIDXLO] = CURSXHI; eieio(); + p->cmap_regs[PIDXDATA] = c->x >> 8; eieio(); + p->cmap_regs[PIDXLO] = CURSXLO; eieio(); + p->cmap_regs[PIDXDATA] = c->x & 0xff; eieio(); + p->cmap_regs[PIDXLO] = CURSYHI; eieio(); + p->cmap_regs[PIDXDATA] = c->y >> 8; eieio(); + p->cmap_regs[PIDXLO] = CURSYLO; eieio(); + p->cmap_regs[PIDXDATA] = c->y & 0xff; eieio(); + p->cmap_regs[PIDXLO] = CURSCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0x02; eieio(); + } +} + +static void +imsttfb_cursor (struct display *disp, int mode, int x, int y) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info; + struct imstt_cursor *c = &p->cursor; + + x *= fontwidth(disp); + y *= fontheight(disp); + + if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable) + return; + + c->enable = 0; + if (c->on) + imstt_set_cursor(p, 0); + c->x = x - disp->var.xoffset; + c->y = y - disp->var.yoffset; + + switch (mode) { + case CM_ERASE: + c->on = 0; + break; + case CM_DRAW: + case CM_MOVE: + if (c->on) + imstt_set_cursor(p, c->on); + else + c->vbl_cnt = CURSOR_DRAW_DELAY; + c->enable = 1; + break; + } +} + +static int +imsttfb_set_font (struct display *disp, int width, int height) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info; + struct imstt_cursor *c = &p->cursor; + u_int x, y; + + if (width > 32 || height > 32) + return -EINVAL; + + c->height = height; + c->width = width; + + p->cmap_regs[PIDXHI] = 1; eieio(); + for (x = 0; x < 0x100; x++) { + p->cmap_regs[PIDXLO] = x; eieio(); + p->cmap_regs[PIDXDATA] = 0x00; eieio(); + } + p->cmap_regs[PIDXHI] = 1; eieio(); + for (y = 0; y < height; y++) + for (x = 0; x < width >> 2; x++) { + p->cmap_regs[PIDXLO] = x + y * 8; eieio(); + p->cmap_regs[PIDXDATA] = 0xff; eieio(); + } + + return 1; +} + +static void +imstt_cursor_timer_handler (unsigned long dev_addr) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)dev_addr; + struct imstt_cursor *c = &p->cursor; + + if (!c->enable) + goto out; + + if (c->vbl_cnt && --c->vbl_cnt == 0) { + c->on ^= 1; + imstt_set_cursor(p, c->on); + c->vbl_cnt = c->blink_rate; + } + +out: + c->timer.expires = jiffies + (HZ / 50); + add_timer(&c->timer); +} + +__initfunc(static void +imstt_cursor_init (struct fb_info_imstt *p)) +{ + struct imstt_cursor *c = &p->cursor; + + imsttfb_set_font(&p->disp, fontwidth(&p->disp), fontheight(&p->disp)); + + c->enable = 1; + c->on = 1; + c->x = c->y = 0; + c->blink_rate = 0; + c->vbl_cnt = CURSOR_DRAW_DELAY; + + if (curblink) { + c->blink_rate = CURSOR_BLINK_RATE; + init_timer(&c->timer); + c->timer.expires = jiffies + (HZ / 50); + c->timer.data = (unsigned long)p; + c->timer.function = imstt_cursor_timer_handler; + add_timer(&c->timer); + } +} + +static void +imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info; + __u32 Bpp = disp->var.bits_per_pixel >> 3, + line_pitch = disp->line_length, + fb_offset_old, fb_offset_new; + + fb_offset_old = sy * line_pitch + sx * Bpp; + fb_offset_new = dy * line_pitch + dx * Bpp; + + while (in_le32(&p->dc_regs[SSTATUS]) & 0x80); + out_le32(&p->dc_regs[CNT], ((height - 1) << 16) | (width * Bpp - 1)); + out_le32(&p->dc_regs[S1SA], fb_offset_old); + /* out_le32(&p->dc_regs[S2SA], fb_offset_new); */ + out_le32(&p->dc_regs[DSA], fb_offset_new); + out_le32(&p->dc_regs[BLTCTL], 0xc0000005); + while (in_le32(&p->dc_regs[SSTATUS]) & 0x80); + while (in_le32(&p->dc_regs[SSTATUS]) & 0x40); +} + +static void +imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width) +{ + /* XXX .. */ + if (sy < dy || (sy == dy && sx < dx)) { + switch (disp->var.bits_per_pixel) { + case 8: fbcon_cfb8_bmove(disp, sy, sx, dy, dx, height, width); break; + case 16: fbcon_cfb16_bmove(disp, sy, sx, dy, dx, height, width); break; + case 24: fbcon_cfb24_bmove(disp, sy, sx, dy, dx, height, width); break; + case 32: fbcon_cfb32_bmove(disp, sy, sx, dy, dx, height, width); break; + } + return; + } + + sy *= fontheight(disp); + sx *= fontwidth(disp); + dy *= fontheight(disp); + dx *= fontwidth(disp); + height *= fontheight(disp); + width *= fontwidth(disp); + + imsttfb_rectcopy(disp, sy, sx, dy, dx, height, width); +} + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_imstt8 = { + fbcon_cfb8_setup, imsttfbcon_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc, + fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB16 +static struct display_switch fbcon_imstt16 = { + fbcon_cfb16_setup, imsttfbcon_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc, + fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB24 +static struct display_switch fbcon_imstt24 = { + fbcon_cfb24_setup, imsttfbcon_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc, + fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB32 +static struct display_switch fbcon_imstt32 = { + fbcon_cfb32_setup, imsttfbcon_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc, + fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins, + FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#ifdef CONFIG_FB_COMPAT_XPMAC +#include <asm/vc_ioctl.h> + +extern struct vc_mode display_info; +extern struct fb_info *console_fb_info; + +static void +set_display_info (struct display *disp) +{ + display_info.width = disp->var.xres; + display_info.height = disp->var.yres; + display_info.depth = disp->var.bits_per_pixel; + display_info.pitch = disp->line_length; + + switch (disp->var.xres) { + case 512: + display_info.mode = 2; + break; + case 640: + display_info.mode = 6; + break; + case 800: + display_info.mode = 12; + break; + case 832: + display_info.mode = 13; + break; + case 1024: + display_info.mode = 17; + break; + case 1152: + display_info.mode = 18; + break; + case 1280: + display_info.mode = disp->var.yres == 960 ? 19 : 20; + break; + default: + display_info.mode = 0; + } +} +#endif + +static int +imsttfb_getcolreg (u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + + if (regno > 255) + return 1; + *red = (p->palette[regno].red << 8) | p->palette[regno].red; + *green = (p->palette[regno].green << 8) | p->palette[regno].green; + *blue = (p->palette[regno].blue << 8) | p->palette[regno].blue; + *transp = 0; + + return 0; +} + +static int +imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + u_int bpp = fb_display[currcon].var.bits_per_pixel; + u_int i; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + p->palette[regno].red = red; + p->palette[regno].green = green; + p->palette[regno].blue = blue; + + /* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */ + if (bpp == 16 && p->ramdac == TVP && fb_display[currcon].var.green.length == 5) { + p->cmap_regs[PADDRW] = regno << 3; eieio(); + } else { + p->cmap_regs[PADDRW] = regno; eieio(); + } + p->cmap_regs[PDATA] = red; eieio(); + p->cmap_regs[PDATA] = green; eieio(); + p->cmap_regs[PDATA] = blue; eieio(); + + if (regno < 16) + switch (bpp) { +#ifdef FBCON_HAS_CFB16 + case 16: + p->fbcon_cmap.cfb16[regno] = (regno << (fb_display[currcon].var.green.length == 5 ? 10 : 11)) | (regno << 5) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + p->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + i = (regno << 8) | regno; + p->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; +#endif + } + + return 0; +} + +static void +do_install_cmap (int con, struct fb_info *info) +{ + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, 1, imsttfb_setcolreg, info); + else { + u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), 1, imsttfb_setcolreg, info); + } +} + +static int +imsttfb_open (struct fb_info *info, int user) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int +imsttfb_release (struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int +imsttfb_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + struct fb_var_screeninfo *var = &fb_display[con].var; + + *fix = p->fix; + fix->visual = var->bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + fix->line_length = var->xres * (var->bits_per_pixel >> 3); + + return 0; +} + +static int +imsttfb_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + *var = fb_display[con].var; + + return 0; +} + +static void +set_disp (struct display *disp, struct fb_info_imstt *p) +{ + u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT; + + p->dispsw = fbcon_dummy; + disp->dispsw = &p->dispsw; + disp->dispsw_data = 0; + switch (disp->var.bits_per_pixel) { + case 8: + disp->var.red.offset = 0; + disp->var.red.length = 8; + disp->var.green.offset = 0; + disp->var.green.length = 8; + disp->var.blue.offset = 0; + disp->var.blue.length = 8; + disp->var.transp.offset = 0; + disp->var.transp.length = 0; +#ifdef FBCON_HAS_CFB8 + p->dispsw = accel ? fbcon_imstt8 : fbcon_cfb8; +#endif + break; + case 16: /* RGB 555 */ + if (disp->var.green.length != 6) + disp->var.red.offset = 10; + disp->var.red.length = 5; + disp->var.green.offset = 5; + if (disp->var.green.length != 6) + disp->var.green.length = 5; + disp->var.blue.offset = 0; + disp->var.blue.length = 5; + disp->var.transp.offset = 0; + disp->var.transp.length = 0; +#ifdef FBCON_HAS_CFB16 + p->dispsw = accel ? fbcon_imstt16 : fbcon_cfb16; + disp->dispsw_data = p->fbcon_cmap.cfb16; +#endif + break; + case 24: /* RGB 888 */ + disp->var.red.offset = 16; + disp->var.red.length = 8; + disp->var.green.offset = 8; + disp->var.green.length = 8; + disp->var.blue.offset = 0; + disp->var.blue.length = 8; + disp->var.transp.offset = 0; + disp->var.transp.length = 0; +#ifdef FBCON_HAS_CFB24 + p->dispsw = accel ? fbcon_imstt24 : fbcon_cfb24; + disp->dispsw_data = p->fbcon_cmap.cfb24; +#endif + break; + case 32: /* RGBA 8888 */ + disp->var.red.offset = 16; + disp->var.red.length = 8; + disp->var.green.offset = 8; + disp->var.green.length = 8; + disp->var.blue.offset = 0; + disp->var.blue.length = 8; + disp->var.transp.offset = 24; + disp->var.transp.length = 8; +#ifdef FBCON_HAS_CFB32 + p->dispsw = accel ? fbcon_imstt32 : fbcon_cfb32; + disp->dispsw_data = p->fbcon_cmap.cfb32; +#endif + break; + } + + if (p->ramdac == IBM) { + p->dispsw.cursor = imsttfb_cursor; + p->dispsw.set_font = imsttfb_set_font; + } + + disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + disp->screen_base = (__u8 *)p->frame_buffer; + disp->visual = p->fix.visual; + disp->type = p->fix.type; + disp->type_aux = p->fix.type_aux; + disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3); + disp->can_soft_blank = 1; + disp->inverse = 0; + disp->ypanstep = 1; + disp->ywrapstep = 0; + if (accel) { + disp->scrollmode = SCROLL_YNOMOVE; + if (disp->var.yres == disp->var.yres_virtual) { + __u32 vram = (p->total_vram - (PAGE_SIZE << 2)); + disp->var.yres_virtual = ((vram << 3) / disp->var.bits_per_pixel) / disp->var.xres_virtual; + if (disp->var.yres_virtual < disp->var.yres) + disp->var.yres_virtual = disp->var.yres; + } + } else { + disp->scrollmode = SCROLL_YREDRAW; + disp->var.yoffset = disp->var.xoffset = 0; + out_le32(&p->dc_regs[SSR], 0); + } + + disp->var.activate = 0; + disp->var.red.msb_right = 0; + disp->var.green.msb_right = 0; + disp->var.blue.msb_right = 0; + disp->var.transp.msb_right = 0; + disp->var.height = -1; + disp->var.width = -1; + disp->var.vmode = FB_VMODE_NONINTERLACED; + disp->var.left_margin = disp->var.right_margin = 16; + disp->var.upper_margin = disp->var.lower_margin = 16; + disp->var.hsync_len = disp->var.vsync_len = 8; + +#ifdef CONFIG_FB_COMPAT_XPMAC + set_display_info(disp); +#endif +} + +static int +imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + struct display *disp; + u_int oldbpp, oldxres, oldyres, oldgreenlen; + + disp = &fb_display[con]; + + if ((var->bits_per_pixel != 8 && var->bits_per_pixel != 16 + && var->bits_per_pixel != 24 && var->bits_per_pixel != 32) + || var->xres_virtual < var->xres || var->yres_virtual < var->yres + || var->nonstd + || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + + if ((var->xres * var->yres) * (var->bits_per_pixel >> 3) > p->total_vram + || (var->xres_virtual * var->yres_virtual) * (var->bits_per_pixel >> 3) > p->total_vram) + return -EINVAL; + + if (!((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)) + return 0; + + if (!compute_imstt_regvals(p, var->xres, var->yres)) + return -EINVAL; + + oldbpp = disp->var.bits_per_pixel; + oldxres = disp->var.xres; + oldyres = disp->var.yres; + oldgreenlen = disp->var.green.length; + + disp->var.bits_per_pixel = var->bits_per_pixel; + disp->var.xres = var->xres; + disp->var.yres = var->yres; + disp->var.xres_virtual = var->xres_virtual; + disp->var.yres_virtual = var->yres_virtual; + disp->var.green.length = var->green.length; + disp->var.accel_flags = var->accel_flags; + + set_disp(disp, p); + + if (info->changevar) + (*info->changevar)(con); + + if (con == currcon) { + if (oldgreenlen != disp->var.green.length) { + if (disp->var.green.length == 6) + set_565(p); + else + set_555(p); + } + if (oldxres != disp->var.xres || oldyres != disp->var.yres || oldbpp != disp->var.bits_per_pixel) + set_imstt_regvals(p, disp->var.bits_per_pixel); + + } + disp->var.pixclock = 1000000 / getclkMHz(p); + + if (oldbpp != disp->var.bits_per_pixel) { + int err = fb_alloc_cmap(&disp->cmap, 0, 0); + if (err) + return err; + do_install_cmap(con, info); + } + + return 0; +} + +static int +imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + struct display *disp = &fb_display[con]; + __u32 off; + + if (var->xoffset + disp->var.xres > disp->var.xres_virtual + || var->yoffset + disp->var.yres > disp->var.yres_virtual) + return -EINVAL; + + disp->var.xoffset = var->xoffset; + disp->var.yoffset = var->yoffset; + if (con == currcon) { + off = var->yoffset * (disp->line_length >> 3) + + ((var->xoffset * (disp->var.bits_per_pixel >> 3)) >> 3); + out_le32(&p->dc_regs[SSR], off); + } + + return 0; +} + +static int +imsttfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, kspc, imsttfb_getcolreg, info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else { + u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + } + + return 0; +} + +static int +imsttfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0))) + return err; + } + if (con == currcon) /* current console? */ + return fb_set_cmap(cmap, kspc, imsttfb_setcolreg, info); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + + return 0; +} + +#define FBIMSTT_SETREG 0x545401 +#define FBIMSTT_GETREG 0x545402 +#define FBIMSTT_SETCMAPREG 0x545403 +#define FBIMSTT_GETCMAPREG 0x545404 +#define FBIMSTT_SETIDXREG 0x545405 +#define FBIMSTT_GETIDXREG 0x545406 + +static int +imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + __u8 init[2]; + __u32 reg[2]; + + switch (cmd) { + case FBIMSTT_SETREG: + if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + out_le32(&p->dc_regs[reg[0]], reg[1]); + return 0; + case FBIMSTT_GETREG: + if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x40000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + reg[1] = in_le32(&p->dc_regs[reg[0]]); + if (copy_to_user((void *)(arg + 4), ®[1], 4)) + return -EFAULT; + return 0; + case FBIMSTT_SETCMAPREG: + if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]); + return 0; + case FBIMSTT_GETCMAPREG: + if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0])) + return -EFAULT; + reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]); + if (copy_to_user((void *)(arg + 4), ®[1], 4)) + return -EFAULT; + return 0; + case FBIMSTT_SETIDXREG: + if (copy_from_user(init, (void *)arg, 2)) + return -EFAULT; + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = init[0]; eieio(); + p->cmap_regs[PIDXDATA] = init[1]; eieio(); + return 0; + case FBIMSTT_GETIDXREG: + if (copy_from_user(init, (void *)arg, 1)) + return -EFAULT; + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = init[0]; eieio(); + init[1] = p->cmap_regs[PIDXDATA]; + if (copy_to_user((void *)(arg + 1), &init[1], 1)) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } +} + +static struct fb_ops imsttfb_ops = { + imsttfb_open, + imsttfb_release, + imsttfb_get_fix, + imsttfb_get_var, + imsttfb_set_var, + imsttfb_get_cmap, + imsttfb_set_cmap, + imsttfb_pan_display, + imsttfb_ioctl +}; + +static int +imsttfbcon_switch (int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + struct display *old = &fb_display[currcon], *new = &fb_display[con]; + __u32 off; + + if (old->cmap.len) + fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info); + + if (p->ramdac == IBM) + imsttfb_cursor(old, CM_ERASE, p->cursor.x, p->cursor.y); + + currcon = con; + + if (old->var.xres != new->var.xres + || old->var.yres != new->var.yres + || old->var.bits_per_pixel != new->var.bits_per_pixel + || old->var.green.length != new->var.green.length) { + set_disp(new, p); + if (!compute_imstt_regvals(p, new->var.xres, new->var.yres)) + return -1; + if (new->var.bits_per_pixel == 16) { + if (new->var.green.length == 6) + set_565(p); + else + set_555(p); + } + set_imstt_regvals(p, new->var.bits_per_pixel); + } + if (old->var.yoffset != new->var.yoffset || old->var.xoffset != new->var.xoffset) { + off = new->var.yoffset * (new->line_length >> 3) + + ((new->var.xoffset * (new->var.bits_per_pixel >> 3)) >> 3); + out_le32(&p->dc_regs[SSR], off); + } + + do_install_cmap(con, info); + + return 0; +} + +static inline void +imsttfb_rectfill (struct display *disp, u_int sy, u_int sx, u_int height, u_int width, __u32 bgx) +{ + memset(disp->screen_base + sy + sx, bgx, height * width * (disp->var.bits_per_pixel >> 3)); +} + +static int +imsttfbcon_updatevar (int con, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + struct display *disp = &fb_display[con]; + struct vc_data *conp = disp->conp; + __u32 off, yres, yoffset, sy, height; + + if (con != currcon) + goto out; + + yres = disp->var.yres; + yoffset = disp->var.yoffset; + sy = (conp->vc_rows + disp->yscroll) * fontheight(disp); + height = yres - conp->vc_rows * fontheight(disp); + + if (height && (yoffset + yres > sy)) { + __u32 bgx = attr_bgcol_ec(disp, conp); + + if (sy + height > disp->var.yres_virtual) + printk("updatevar: %u + %u > %u\n", sy, height, disp->var.yres_virtual); + imsttfb_rectfill(disp, sy, disp->var.xoffset, height, disp->var.xres, bgx); + } + + if (p->ramdac == IBM && (yoffset + yres <= sy)) + imsttfb_cursor(disp, CM_ERASE, p->cursor.x, p->cursor.y); + + off = disp->var.yoffset * (disp->line_length >> 3) + + ((disp->var.xoffset * (disp->var.bits_per_pixel >> 3)) >> 3); + out_le32(&p->dc_regs[SSR], off); + +out: + return 0; +} + +static void +imsttfbcon_blank (int blank, struct fb_info *info) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)info; + __u32 ctrl; + + ctrl = in_le32(&p->dc_regs[STGCTL]); + if (blank > 0) { + switch (blank - 1) { + case VESA_NO_BLANKING: + case VESA_POWERDOWN: + ctrl &= ~0x00000380; + if (p->ramdac == IBM) { + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = MISCTL2; eieio(); + p->cmap_regs[PIDXDATA] = 0x55; eieio(); + p->cmap_regs[PIDXLO] = MISCTL1; eieio(); + p->cmap_regs[PIDXDATA] = 0x11; eieio(); + p->cmap_regs[PIDXLO] = SYNCCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0x0f; eieio(); + p->cmap_regs[PIDXLO] = PWRMNGMT;eieio(); + p->cmap_regs[PIDXDATA] = 0x1f; eieio(); + p->cmap_regs[PIDXLO] = CLKCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0xc0; + } + break; + case VESA_VSYNC_SUSPEND: + ctrl &= ~0x00000020; + break; + case VESA_HSYNC_SUSPEND: + ctrl &= ~0x00000010; + break; + } + } else { + if (p->ramdac == IBM) { + ctrl |= 0x000017b0; + p->cmap_regs[PIDXHI] = 0; eieio(); + p->cmap_regs[PIDXLO] = CLKCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0x01; eieio(); + p->cmap_regs[PIDXLO] = PWRMNGMT;eieio(); + p->cmap_regs[PIDXDATA] = 0x00; eieio(); + p->cmap_regs[PIDXLO] = SYNCCTL; eieio(); + p->cmap_regs[PIDXDATA] = 0x00; eieio(); + p->cmap_regs[PIDXLO] = MISCTL1; eieio(); + p->cmap_regs[PIDXDATA] = 0x01; eieio(); + p->cmap_regs[PIDXLO] = MISCTL2; eieio(); + p->cmap_regs[PIDXDATA] = 0x45; eieio(); + } else + ctrl |= 0x00001780; + } + out_le32(&p->dc_regs[STGCTL], ctrl); +} + +__initfunc(static void +init_imstt(struct fb_info_imstt *p)) +{ + __u32 i, tmp; + __u32 *ip, *end; + + tmp = in_le32(&p->dc_regs[PRC]); + if (p->ramdac == IBM) + p->total_vram = (tmp & 0x0004) ? 0x00400000 : 0x00200000; + else + p->total_vram = 0x00800000; + + ip = (__u32 *)p->frame_buffer; + end = (__u32 *)(p->frame_buffer + p->total_vram); + while (ip < end) + *ip++ = 0; + + /* initialize the card */ + tmp = in_le32(&p->dc_regs[STGCTL]); + out_le32(&p->dc_regs[STGCTL], tmp & ~0x1); + out_le32(&p->dc_regs[SSR], 0); + + /* set default values for DAC registers */ + if (p->ramdac == IBM) { + p->cmap_regs[PPMASK] = 0xff; eieio(); + p->cmap_regs[PIDXHI] = 0; eieio(); + for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) { + p->cmap_regs[PIDXLO] = ibm_initregs[i].addr; eieio(); + p->cmap_regs[PIDXDATA] = ibm_initregs[i].value; eieio(); + } + } else { + for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) { + p->cmap_regs[TVPADDRW] = tvp_initregs[i].addr; eieio(); + p->cmap_regs[TVPIDATA] = tvp_initregs[i].value; eieio(); + } + } + +#if USE_NV_MODES && defined(CONFIG_PPC) + { + int vmode = init_vmode, cmode = init_cmode; + + if (vmode == -1) { + vmode = nvram_read_byte(NV_VMODE); + if (vmode <= 0 || vmode > VMODE_MAX) + vmode = VMODE_640_480_67; + } + if (cmode == -1) { + cmode = nvram_read_byte(NV_CMODE); + if (cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; + } + if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) { + p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES; + p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES; + p->disp.var.bits_per_pixel = INIT_BPP; + } + } +#else + p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES; + p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES; + p->disp.var.bits_per_pixel = INIT_BPP; +#endif + + if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram + || !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) { + printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel); + kfree(p); + return; + } + + sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP"); + p->fix.smem_start = (__u8 *)p->frame_buffer_phys; + p->fix.smem_len = p->total_vram; + p->fix.mmio_start = (__u8 *)p->dc_regs_phys; + p->fix.mmio_len = 0x40000; + p->fix.accel = FB_ACCEL_IMS_TWINTURBO; + p->fix.type = FB_TYPE_PACKED_PIXELS; + p->fix.visual = p->disp.var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_DIRECTCOLOR; + p->fix.line_length = p->disp.var.xres * (p->disp.var.bits_per_pixel >> 3); + p->fix.xpanstep = 8; + p->fix.ypanstep = 1; + p->fix.ywrapstep = 0; + + p->disp.var.accel_flags = noaccel ? 0 : FB_ACCELF_TEXT; + set_disp(&p->disp, p); + + if (p->ramdac == IBM) + imstt_cursor_init(p); + if (p->disp.var.green.length == 6) + set_565(p); + else + set_555(p); + set_imstt_regvals(p, p->disp.var.bits_per_pixel); + + p->disp.var.pixclock = 1000000 / getclkMHz(p); + + strcpy(p->info.modename, p->fix.id); + strcpy(p->info.fontname, fontname); + p->info.node = -1; + p->info.fbops = &imsttfb_ops; + p->info.disp = &p->disp; + p->info.changevar = 0; + p->info.switch_con = &imsttfbcon_switch; + p->info.updatevar = &imsttfbcon_updatevar; + p->info.blank = &imsttfbcon_blank; + p->info.flags = FBINFO_FLAG_DEFAULT; + + for (i = 0; i < 16; i++) { + u_int j = color_table[i]; + p->palette[i].red = default_red[j]; + p->palette[i].green = default_grn[j]; + p->palette[i].blue = default_blu[j]; + } + + if (register_framebuffer(&p->info) < 0) { + kfree(p); + return; + } + + tmp = (in_le32(&p->dc_regs[SSTATUS]) & 0x0f00) >> 8; + printk("fb%d: %s frame buffer; %uMB vram; chip version %u\n", + GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20, tmp); + +#ifdef CONFIG_FB_COMPAT_XPMAC + strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name)); + display_info.fb_address = (__u32)p->frame_buffer_phys; + display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW]; + display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA]; + display_info.disp_reg_address = (__u32)p->dc_regs_phys; + set_display_info(&p->disp); + if (!console_fb_info) + console_fb_info = &p->info; +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +#if defined(CONFIG_FB_OF) +__initfunc(void +imsttfb_of_init(struct device_node *dp)) +{ + struct fb_info_imstt *p; + int i; + __u32 addr, size = 0; + __u8 bus, devfn; + __u16 cmd; + + for (i = 0; i < dp->n_addrs; i++) { + if (dp->addrs[i].size >= 0x02000000) { + addr = dp->addrs[i].address; + size = dp->addrs[i].size; + } + } + if (!size) + return; + + p = kmalloc(sizeof(struct fb_info_imstt), GFP_ATOMIC); + if (!p) + return; + + memset(p, 0, sizeof(struct fb_info_imstt)); + p->frame_buffer_phys = (__u8 *)addr; + p->frame_buffer = (__u8 *)ioremap(addr, size); + p->dc_regs_phys = (__u32 *)(p->frame_buffer_phys + 0x00800000); + p->dc_regs = (__u32 *)(p->frame_buffer + 0x00800000); + p->cmap_regs_phys = (__u8 *)(p->frame_buffer_phys + 0x00840000); + p->cmap_regs = (__u8 *)(p->frame_buffer + 0x00840000); + + if (dp->name[11] == '8') + p->ramdac = TVP; + else + p->ramdac = IBM; + + if (!pci_device_loc(dp, &bus, &devfn)) { + if (!pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd)) { + cmd |= PCI_COMMAND_MEMORY; + pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); + } + } + + init_imstt(p); +} +#endif + +__initfunc(void +imsttfb_init(void)) +{ +#if !defined(CONFIG_FB_OF) + /* ... */ +#endif +} + +__initfunc(void +imsttfb_setup(char *options, int *ints)) +{ + char *this_opt; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } else if (!strncmp(this_opt, "noblink", 7)) { + curblink = 0; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } +#if defined(CONFIG_PPC) + else if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + init_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case CMODE_8: + case 8: + init_cmode = CMODE_8; + break; + case CMODE_16: + case 15: + case 16: + init_cmode = CMODE_16; + break; + case CMODE_32: + case 24: + case 32: + init_cmode = CMODE_32; + break; + } + } +#endif + } +} diff --git a/drivers/video/leofb.c b/drivers/video/leofb.c new file mode 100644 index 000000000..6bfd09fd8 --- /dev/null +++ b/drivers/video/leofb.c @@ -0,0 +1,582 @@ +/* $Id: leofb.c,v 1.4 1998/09/04 15:43:45 jj Exp $ + * leofb.c: Leo (ZX) 24/8bit frame buffer driver + * + * Copyright (C) 1996,1997,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/selection.h> + +#include <video/sbusfb.h> +#include <asm/io.h> + +#define LEO_OFF_LC_SS0_KRN 0x00200000 +#define LEO_OFF_LC_SS0_USR 0x00201000 +#define LEO_OFF_LC_SS1_KRN 0x01200000 +#define LEO_OFF_LC_SS1_USR 0x01201000 +#define LEO_OFF_LD_SS0 0x00400000 +#define LEO_OFF_LD_SS1 0x01400000 +#define LEO_OFF_LD_GBL 0x00401000 +#define LEO_OFF_LX_KRN 0x00600000 +#define LEO_OFF_LX_CURSOR 0x00601000 +#define LEO_OFF_SS0 0x00800000 +#define LEO_OFF_SS1 0x01800000 +#define LEO_OFF_UNK 0x00602000 +#define LEO_OFF_UNK2 0x00000000 + +#define LEO_CUR_ENABLE 0x00000080 +#define LEO_CUR_UPDATE 0x00000030 +#define LEO_CUR_PROGRESS 0x00000006 +#define LEO_CUR_UPDATECMAP 0x00000003 + +#define LEO_CUR_TYPE_MASK 0x00000000 +#define LEO_CUR_TYPE_IMAGE 0x00000020 +#define LEO_CUR_TYPE_CMAP 0x00000050 + +struct leo_cursor { + u8 xxx0[16]; + volatile u32 cur_type; + volatile u32 cur_misc; + volatile u32 cur_cursxy; + volatile u32 cur_data; +}; + +#define LEO_KRN_TYPE_CLUT0 0x00001000 +#define LEO_KRN_TYPE_CLUT1 0x00001001 +#define LEO_KRN_TYPE_CLUT2 0x00001002 +#define LEO_KRN_TYPE_WID 0x00001003 +#define LEO_KRN_TYPE_UNK 0x00001006 +#define LEO_KRN_TYPE_VIDEO 0x00002003 +#define LEO_KRN_TYPE_CLUTDATA 0x00004000 +#define LEO_KRN_CSR_ENABLE 0x00000008 +#define LEO_KRN_CSR_PROGRESS 0x00000004 +#define LEO_KRN_CSR_UNK 0x00000002 +#define LEO_KRN_CSR_UNK2 0x00000001 + +struct leo_lx_krn { + volatile u32 krn_type; + volatile u32 krn_csr; + volatile u32 krn_value; +}; + +struct leo_lc_ss0_krn { + volatile u32 misc; + u8 xxx0[0x800-4]; + volatile u32 rev; +}; + +struct leo_lc_ss0_usr { + volatile u32 csr; + volatile u32 attrs; + volatile u32 fontc; + volatile u32 fontc2; + volatile u32 extent; + volatile u32 src; + u32 xxx1[1]; + volatile u32 copy; + volatile u32 fill; +}; + +struct leo_lc_ss1_krn { + u8 unknown; +}; + +struct leo_lc_ss1_usr { + u8 unknown; +}; + +struct leo_ld_ss0 { + u8 xxx0[0xe00]; + u32 xxx1[2]; + volatile u32 unk; + u32 xxx2[1]; + volatile u32 unk2; + volatile u32 unk3; + u32 xxx3[2]; + volatile u32 fg; + volatile u32 bg; + u8 xxx4[0x05c]; + volatile u32 planemask; + volatile u32 rop; +}; + +#define LEO_SS1_MISC_ENABLE 0x00000001 +#define LEO_SS1_MISC_STEREO 0x00000002 +struct leo_ld_ss1 { + u8 xxx0[0xef4]; + volatile u32 ss1_misc; +}; + +struct leo_ld_gbl { + u8 unknown; +}; + +static struct sbus_mmap_map leo_mmap_map[] = { + { LEO_SS0_MAP, LEO_OFF_SS0, 0x800000 }, + { LEO_LC_SS0_USR_MAP, LEO_OFF_LC_SS0_USR, PAGE_SIZE }, + { LEO_LD_SS0_MAP, LEO_OFF_LD_SS0, PAGE_SIZE }, + { LEO_LX_CURSOR_MAP, LEO_OFF_LX_CURSOR, PAGE_SIZE }, + { LEO_SS1_MAP, LEO_OFF_SS1, 0x800000 }, + { LEO_LC_SS1_USR_MAP, LEO_OFF_LC_SS1_USR, PAGE_SIZE }, + { LEO_LD_SS1_MAP, LEO_OFF_LD_SS1, PAGE_SIZE }, + { LEO_UNK_MAP, LEO_OFF_UNK, PAGE_SIZE }, + { LEO_LX_KRN_MAP, LEO_OFF_LX_KRN, PAGE_SIZE }, + { LEO_LC_SS0_KRN_MAP, LEO_OFF_LC_SS0_KRN, PAGE_SIZE }, + { LEO_LC_SS1_KRN_MAP, LEO_OFF_LC_SS1_KRN, PAGE_SIZE }, + { LEO_LD_GBL_MAP, LEO_OFF_LD_GBL, PAGE_SIZE }, + { LEO_UNK2_MAP, LEO_OFF_UNK2, 0x100000 }, + { 0, 0, 0 } +}; + +static void leo_setup(struct display *p) +{ + p->next_line = 8192; + p->next_plane = 0; +} + +static void leo_clear(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr; + register struct leo_ld_ss0 *ss = fb->s.leo.ld_ss0; + int x, y, w, h; + int i; + + do { + i = us->csr; + } while (i & 0x20000000); + ss->unk = 0xffff; + ss->unk2 = 0; + ss->unk3 = fb->s.leo.extent; + ss->fg = (attr_bgcol_ec(p,conp)<<24) | 0x030703; + ss->planemask = 0xff000000; + ss->rop = 0xd0840; + if (fontheightlog(p)) { + y = sy << fontheightlog(p); h = height << fontheightlog(p); + } else { + y = sy * fontheight(p); h = height * fontheight(p); + } + if (fontwidthlog(p)) { + x = sx << fontwidthlog(p); w = width << fontwidthlog(p); + } else { + x = sx * fontwidth(p); w = width * fontwidth(p); + } + us->extent = (w - 1) | ((h - 1) << 11); + i = us->attrs; + us->fill = (x + fb->x_margin) | ((y + fb->y_margin) << 11) | + ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); +} + +static void leo_fill(struct fb_info_sbusfb *fb, struct display *p, int s, + int count, unsigned short *boxes) +{ + int i; + register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr; + register struct leo_ld_ss0 *ss = fb->s.leo.ld_ss0; + + do { + i = us->csr; + } while (i & 0x20000000); + ss->unk = 0xffff; + ss->unk2 = 0; + ss->unk3 = fb->s.leo.extent; + ss->fg = (attr_bgcol(p,s)<<24) | 0x030703; + ss->planemask = 0xff000000; + ss->rop = 0xd0840; + while (count-- > 0) { + us->extent = (boxes[2] - boxes[0] - 1) | + ((boxes[3] - boxes[1] - 1) << 11); + i = us->attrs; + us->fill = boxes[0] | (boxes[1] << 11) | + ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); + } +} + +static void leo_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx) +{ + struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr; + register struct leo_ld_ss0 *ss = fb->s.leo.ld_ss0; + int i, x, y; + u8 *fd; + u32 *u; + + if (fontheightlog(p)) { + y = yy << (fontheightlog(p) + 11); + i = (c & p->charmask) << fontheightlog(p); + } else { + y = (yy * fontheight(p)) << 11; + i = (c & p->charmask) * fontheight(p); + } + if (fontwidth(p) <= 8) + fd = p->fontdata + i; + else + fd = p->fontdata + (i << 1); + if (fontwidthlog(p)) + x = xx << fontwidthlog(p); + else + x = xx * fontwidth(p); + do { + i = us->csr; + } while (i & 0x20000000); + ss->fg = attr_fgcol(p,c) << 24; + ss->bg = attr_bgcol(p,c) << 24; + ss->rop = 0x310040; + ss->planemask = 0xff000000; + us->fontc2 = 0xFFFFFFFE; + us->attrs = 4; + us->fontc = 0xFFFFFFFF<<(32-fontwidth(p)); + u = ((u32 *)p->screen_base) + y + x; + if (fontwidth(p) <= 8) { + for (i = 0; i < fontheight(p); i++, u += 2048) + *u = *fd++ << 24; + } else { + for (i = 0; i < fontheight(p); i++, u += 2048) { + *u = *(u16 *)fd << 16; + fd += 2; + } + } +} + +static void leo_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, + int count, int yy, int xx) +{ + struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info; + register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr; + register struct leo_ld_ss0 *ss = fb->s.leo.ld_ss0; + int i, x, y; + u8 *fd1, *fd2, *fd3, *fd4; + u32 *u; + + do { + i = us->csr; + } while (i & 0x20000000); + ss->fg = attr_fgcol(p,*s) << 24; + ss->bg = attr_bgcol(p,*s) << 24; + ss->rop = 0x310040; + ss->planemask = 0xff000000; + us->fontc2 = 0xFFFFFFFE; + us->attrs = 4; + us->fontc = 0xFFFFFFFF<<(32-fontwidth(p)); + if (fontwidthlog(p)) + x = (xx << fontwidthlog(p)); + else + x = xx * fontwidth(p); + if (fontheightlog(p)) + y = yy << (fontheightlog(p) + 11); + else + y = (yy * fontheight(p)) << 11; + u = ((u32 *)p->screen_base) + y + x; + if (fontwidth(p) <= 8) { + us->fontc = 0xFFFFFFFF<<(32-4*fontwidth(p)); + x = 4*fontwidth(p) - fontheight(p)*2048; + while (count >= 4) { + count -= 4; + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) << fontheightlog(p)); + } else { + fd1 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd2 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd3 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + fd4 = p->fontdata + ((*s++ & p->charmask) * fontheight(p)); + } + if (fontwidth(p) == 8) { + for (i = 0; i < fontheight(p); i++, u += 2048) + *u = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) + << 8)) << 8)) << 8); + u += x; + } else { + for (i = 0; i < fontheight(p); i++, u += 2048) + *u = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) + << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p)); + u += x; + } + } + } else { + us->fontc = 0xFFFFFFFF<<(32-2*fontwidth(p)); + x = 2*fontwidth(p) - fontheight(p)*2048; + while (count >= 2) { + count -= 2; + if (fontheightlog(p)) { + fd1 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + fd2 = p->fontdata + ((*s++ & p->charmask) << (fontheightlog(p) + 1)); + } else { + fd1 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + fd2 = p->fontdata + (((*s++ & p->charmask) * fontheight(p)) << 1); + } + for (i = 0; i < fontheight(p); i++, u += 2048) { + *u = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p)); + fd1 += 2; fd2 += 2; + } + u += x; + } + } + us->fontc = 0xFFFFFFFF<<(32-fontwidth(p)); + x = fontwidth(p) - fontheight(p)*2048; + while (count) { + count--; + if (fontheightlog(p)) + i = ((*s++ & p->charmask) << fontheightlog(p)); + else + i = ((*s++ & p->charmask) * fontheight(p)); + if (fontwidth(p) <= 8) { + fd1 = p->fontdata + i; + for (i = 0; i < fontheight(p); i++, u += 2048) + *u = *fd1++ << 24; + } else { + fd1 = p->fontdata + (i << 1); + for (i = 0; i < fontheight(p); i++, u += 2048) { + *u = *(u16 *)fd1 << 16; + fd1 += 2; + } + } + u += x; + } +} + +static void leo_revc(struct display *p, int xx, int yy) +{ + /* Not used if hw cursor */ +} + +static int leo_wait (struct leo_lx_krn *lx_krn) +{ + int i; + + for (i = 0; (lx_krn->krn_csr & LEO_KRN_CSR_PROGRESS) && i < 300000; i++) + udelay (1); /* Busy wait at most 0.3 sec */ + if (i == 300000) return -EFAULT; /* Timed out - should we print some message? */ + return 0; +} + +static void leo_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) +{ + struct leo_lx_krn *lx_krn = fb->s.leo.lx_krn; + int i; + + lx_krn->krn_type = LEO_KRN_TYPE_CLUT0; + i = leo_wait (lx_krn); + if (i) return; + lx_krn->krn_type = LEO_KRN_TYPE_CLUTDATA; + for (i = 0; i < 256; i++) + lx_krn->krn_value = fb->color_map CM(i,0) | + (fb->color_map CM(i,1) << 8) | + (fb->color_map CM(i,2) << 16); /* Throw colors there :)) */ + lx_krn->krn_type = LEO_KRN_TYPE_CLUT0; + lx_krn->krn_csr |= (LEO_KRN_CSR_UNK|LEO_KRN_CSR_UNK2); +} + +static void leo_restore_palette (struct fb_info_sbusfb *fb) +{ + fb->s.leo.ld_ss1->ss1_misc &= ~(LEO_SS1_MISC_ENABLE); +} + +static struct display_switch leo_dispsw __initdata = { + leo_setup, fbcon_redraw_bmove, leo_clear, leo_putc, leo_putcs, leo_revc, + NULL, NULL, NULL, FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */ +}; + +static void leo_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue) +{ + struct leo_cursor *l = fb->s.leo.cursor; + int i; + + for (i = 0; (l->cur_misc & LEO_CUR_PROGRESS) && i < 300000; i++) + udelay (1); /* Busy wait at most 0.3 sec */ + if (i == 300000) return; /* Timed out - should we print some message? */ + l->cur_type = LEO_CUR_TYPE_CMAP; + l->cur_data = (red[0] | (green[0]<<8) | (blue[0]<<16)); + l->cur_data = (red[1] | (green[1]<<8) | (blue[1]<<16)); + l->cur_misc = LEO_CUR_UPDATECMAP; +} + +/* Set cursor shape */ +static void leo_setcurshape (struct fb_info_sbusfb *fb) +{ + int i, j, k; + u32 m, n, mask; + struct leo_cursor *l = fb->s.leo.cursor; + + l->cur_misc &= ~LEO_CUR_ENABLE; + for (k = 0; k < 2; k ++) { + l->cur_type = (k * LEO_CUR_TYPE_IMAGE); /* LEO_CUR_TYPE_MASK is 0 */ + for (i = 0; i < 32; i++) { + mask = 0; + m = fb->cursor.bits[k][i]; + /* mask = m with reversed bit order */ + for (j = 0, n = 1; j < 32; j++, n <<= 1) + if (m & n) + mask |= (0x80000000 >> j); + l->cur_data = mask; + } + } + l->cur_misc |= LEO_CUR_ENABLE; +} + +/* Load cursor information */ +static void leo_setcursor (struct fb_info_sbusfb *fb) +{ + struct cg_cursor *c = &fb->cursor; + struct leo_cursor *l = fb->s.leo.cursor; + + l->cur_misc &= ~LEO_CUR_ENABLE; + l->cur_cursxy = ((c->cpos.fbx - c->chot.fbx) & 0x7ff) + |(((c->cpos.fby - c->chot.fby) & 0x7ff) << 11); + l->cur_misc |= LEO_CUR_UPDATE; + if (c->enable) + l->cur_misc |= LEO_CUR_ENABLE; +} + +static void leo_blank (struct fb_info_sbusfb *fb) +{ + fb->s.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO; + fb->s.leo.lx_krn->krn_csr &= ~LEO_KRN_CSR_ENABLE; +} + +static void leo_unblank (struct fb_info_sbusfb *fb) +{ + fb->s.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO; + if (!(fb->s.leo.lx_krn->krn_csr & LEO_KRN_CSR_ENABLE)) + fb->s.leo.lx_krn->krn_csr |= LEO_KRN_CSR_ENABLE; +} + +__initfunc(static int +leo_wid_put (struct fb_info_sbusfb *fb, struct fb_wid_list *wl)) +{ + struct leo_lx_krn *lx_krn = fb->s.leo.lx_krn; + struct fb_wid_item *wi; + int i, j; + + lx_krn->krn_type = LEO_KRN_TYPE_WID; + i = leo_wait (lx_krn); + if (i) return i; + for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { + switch (wi->wi_type) { + case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break; + case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break; + default: return -EINVAL; + } + lx_krn->krn_type = 0x5800 + j; + lx_krn->krn_value = wi->wi_values[0]; + } + return 0; +} + +static void leo_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) +{ + p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin); +} + +static char idstring[40] __initdata = { 0 }; + +__initfunc(char *leofb_init(struct fb_info_sbusfb *fb)) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct fb_var_screeninfo *var = &fb->var; + struct display *disp = &fb->disp; + struct fbtype *type = &fb->type; + unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; + struct fb_wid_item wi; + struct fb_wid_list wl; + int i; + + strcpy(fb->info.modename, "Leo"); + + strcpy(fix->id, "Leo"); + fix->visual = 0xff; /* We only know how to do acceleration and know nothing + about the actual memory layout */ + fix->line_length = 8192; + fix->accel = FB_ACCEL_SUN_LEO; + + var->accel_flags = FB_ACCELF_TEXT; + + disp->scrollmode = SCROLL_YREDRAW; + if (!disp->screen_base) + disp->screen_base = (char *)sparc_alloc_io(phys + LEO_OFF_SS0, 0, + 0x800000, "leo_ram", fb->iospace, 0); + disp->screen_base += 8192 * fb->y_margin + 4 * fb->x_margin; + fb->s.leo.lc_ss0_usr = (struct leo_lc_ss0_usr *) + sparc_alloc_io(phys + LEO_OFF_LC_SS0_USR, 0, + PAGE_SIZE, "leo_lc_ss0_usr", fb->iospace, 0); + fb->s.leo.ld_ss0 = (struct leo_ld_ss0 *) + sparc_alloc_io(phys + LEO_OFF_LD_SS0, 0, + PAGE_SIZE, "leo_ld_ss0", fb->iospace, 0); + fb->s.leo.ld_ss1 = (struct leo_ld_ss1 *) + sparc_alloc_io(phys + LEO_OFF_LD_SS1, 0, + PAGE_SIZE, "leo_ld_ss1", fb->iospace, 0); + fb->s.leo.lx_krn = (struct leo_lx_krn *) + sparc_alloc_io(phys + LEO_OFF_LX_KRN, 0, + PAGE_SIZE, "leo_lx_krn", fb->iospace, 0); + fb->s.leo.cursor = (struct leo_cursor *) + sparc_alloc_io(phys + LEO_OFF_LX_CURSOR, 0, + sizeof(struct leo_cursor), "leo_lx_cursor", fb->iospace, 0); + fb->dispsw = leo_dispsw; + + fb->s.leo.extent = (type->fb_width-1) | ((type->fb_height-1) << 16); + + fb->s.leo.ld_ss0->unk = 0xffff; + fb->s.leo.ld_ss0->unk2 = 0; + fb->s.leo.ld_ss0->unk3 = fb->s.leo.extent; + wl.wl_count = 1; + wl.wl_list = &wi; + wi.wi_type = FB_WID_DBL_8; + wi.wi_index = 0; + wi.wi_values [0] = 0x2c0; + leo_wid_put (fb, &wl); + wi.wi_index = 1; + wi.wi_values [0] = 0x30; + leo_wid_put (fb, &wl); + wi.wi_index = 2; + wi.wi_values [0] = 0x20; + leo_wid_put (fb, &wl); + + fb->s.leo.ld_ss1->ss1_misc |= LEO_SS1_MISC_ENABLE; + + fb->s.leo.ld_ss0->fg = 0x30703; + fb->s.leo.ld_ss0->planemask = 0xff000000; + fb->s.leo.ld_ss0->rop = 0xd0840; + fb->s.leo.lc_ss0_usr->extent = (type->fb_width-1) | ((type->fb_height-1) << 11); + i = fb->s.leo.lc_ss0_usr->attrs; + fb->s.leo.lc_ss0_usr->fill = (0) | ((0) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); + do { + i = fb->s.leo.lc_ss0_usr->csr; + } while (i & 0x20000000); + + fb->margins = leo_margins; + fb->loadcmap = leo_loadcmap; + fb->setcursor = leo_setcursor; + fb->setcursormap = leo_setcursormap; + fb->setcurshape = leo_setcurshape; + fb->restore_palette = leo_restore_palette; + fb->fill = leo_fill; + fb->blank = leo_blank; + fb->unblank = leo_unblank; + + fb->physbase = phys; + fb->mmap_map = leo_mmap_map; + +#ifdef __sparc_v9__ + sprintf(idstring, "leo at %016lx", phys); +#else + sprintf(idstring, "leo at %x.%08lx", fb->iospace, phys); +#endif + + return idstring; +} diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index 67d6e87b1..2d0ad2924 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -22,12 +22,11 @@ #include <asm/macintosh.h> #include <linux/fb.h> - /* conditionalize these ?? */ -#include "fbcon-mfb.h" -#include "fbcon-cfb2.h" -#include "fbcon-cfb4.h" -#include "fbcon-cfb8.h" +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -237,7 +236,7 @@ static void macfb_set_disp(int con) break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } } @@ -261,7 +260,7 @@ static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, if (console_loglevel < 7) return -EINVAL; if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, 0 /*offb_getcolreg*/, info); + return fb_get_cmap(cmap, kspc, 0 /*offb_getcolreg*/, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -285,7 +284,7 @@ static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, 1 /*offb_setcolreg*/, info); + return fb_set_cmap(cmap, kspc, 1 /*offb_setcolreg*/, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); #endif @@ -415,6 +414,7 @@ __initfunc(void macfb_init(void)) fb_info.switch_con=&macfb_switch; fb_info.updatevar=&fb_update_var; fb_info.blank=&macfb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&macfb_defined,1); macfb_get_var(&disp.var, -1, &fb_info); diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index 57cf4877a..0fbe917d3 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c @@ -12,7 +12,7 @@ #include <linux/fb.h> #include <linux/string.h> -#include "macmodes.h" +#include <video/macmodes.h> struct mac_mode { int number; @@ -348,7 +348,7 @@ int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var) int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, int *cmode) { - int i = 0; + unsigned int i; if (var->bits_per_pixel <= 8) *cmode = CMODE_8; @@ -367,7 +367,7 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, continue; if (var->pixclock > mode->pixclock) continue; - if (var->vmode != mode->vmode) + if ((var->vmode & FB_VMODE_MASK) != mode->vmode) continue; *vmode = mode->number; return 0; diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h deleted file mode 100644 index e0e90c738..000000000 --- a/drivers/video/macmodes.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * linux/drivers/video/macmodes.h -- Standard MacOS video modes - * - * Copyright (C) 1998 Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - - - /* - * Video mode values. - * These are supposed to be the same as the values that Apple uses in - * MacOS. - */ - -#define VMODE_NVRAM 0 -#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */ -#define VMODE_512_384_60 2 /* 512x384, 60Hz */ -#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */ -#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */ -#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */ -#define VMODE_640_480_67 6 /* 640x480, 67Hz */ -#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */ -#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */ -#define VMODE_800_600_56 9 /* 800x600, 56Hz */ -#define VMODE_800_600_60 10 /* 800x600, 60Hz */ -#define VMODE_800_600_72 11 /* 800x600, 72Hz */ -#define VMODE_800_600_75 12 /* 800x600, 75Hz */ -#define VMODE_832_624_75 13 /* 832x624, 75Hz */ -#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */ -#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */ -#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */ -#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */ -#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ -#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ -#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ -#define VMODE_MAX 20 -#define VMODE_CHOOSE 99 - -#define CMODE_NVRAM -1 -#define CMODE_8 0 /* 8 bits/pixel */ -#define CMODE_16 1 /* 16 (actually 15) bits/pixel */ -#define CMODE_32 2 /* 32 (actually 24) bits/pixel */ - - -extern int mac_vmode_to_var(int vmode, int cmode, - struct fb_var_screeninfo *var); -extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, - int *cmode); -extern int mac_map_monitor_sense(int sense); - - - /* - * Addresses in NVRAM where video mode and pixel size are stored. - */ - -#define NV_VMODE 0x140f -#define NV_CMODE 0x1410 diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c new file mode 100644 index 000000000..e9f3f44a3 --- /dev/null +++ b/drivers/video/matroxfb.c @@ -0,0 +1,5381 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique and G200 + * + * (c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.5 1998/11/19 + * + * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net> + * + * Contributors: "menion?" <menion@mindless.com> + * Betatesting, fixes, ideas + * + * "Kurt Garloff" <garloff@kg1.ping.de> + * Betatesting, fixes, ideas, videomodes, videomodes timmings + * + * "Tom Rini" <tmrini@ntplx.net> + * MTRR stuff, betatesting, fixes, ideas + * + * "Bibek Sahu" <scorpio@dodds.net> + * Access device through readb|w|l and write b|w|l + * Extensive debugging stuff + * + * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> + * Betatesting + * + * "Kelly French" <targon@hazmat.com> + * Betatesting, bug reporting + * + * "Pablo Bianucci" <pbian@pccp.com.ar> + * Fixes, ideas, betatesting + * + * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> + * Fixes, enhandcements, ideas, betatesting + * + * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> + * PPC betatesting, PPC support, backward compatibility + * + * "Paul Womar" <Paul@pwomar.demon.co.uk> + * "Owen Waller" <O.Waller@ee.qub.ac.uk> + * PPC betatesting + * + * "H. Peter Arvin" <hpa@transmeta.com> + * Ideas + * + * (following author is not in any relation with this code, but his code + * is included in this driver) + * + * Based on framebuffer driver for VBE 2.0 compliant graphic boards + * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * + * (following author is not in any relation with this code, but his ideas + * were used when writting this driver) + * + * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> + * + */ + +/* general, but fairly heavy, debugging */ +#undef MATROXFB_DEBUG + +/* heavy debugging: */ +/* -- logs putc[s], so everytime a char is displayed, it's logged */ +#undef MATROXFB_DEBUG_HEAVY + +/* This one _could_ cause infinite loops */ +/* It _does_ cause lots and lots of messages during idle loops */ +#undef MATROXFB_DEBUG_LOOP + +/* Debug register calls, too? */ +#undef MATROXFB_DEBUG_REG + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/pci.h> + +#include <asm/io.h> +#include <asm/spinlock.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include <video/fbcon.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#if defined(CONFIG_FB_COMPAT_XPMAC) +#include <asm/vc_ioctl.h> +#endif +#if defined(CONFIG_PPC) +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <video/macmodes.h> +#endif + +#ifdef MATROXFB_DEBUG + +#define DEBUG +#define DBG(x) printk("matroxfb: %s\n", (x)); + +#ifdef MATROXFB_DEBUG_HEAVY +#define DBG_HEAVY(x) DBG(x) +#else /* MATROXFB_DEBUG_HEAVY */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#endif /* MATROXFB_DEBUG_HEAVY */ + +#ifdef MATROXFB_DEBUG_LOOP +#define DBG_LOOP(x) DBG(x) +#else /* MATROXFB_DEBUG_LOOP */ +#define DBG_LOOP(x) /* DBG_LOOP */ +#endif /* MATROXFB_DEBUG_LOOP */ + +#ifdef MATROXFB_DEBUG_REG +#define DBG_REG(x) DBG(x) +#else /* MATROXFB_DEBUG_REG */ +#define DBG_REG(x) /* DBG_REG */ +#endif /* MATROXFB_DEBUG_REG */ + +#else /* MATROXFB_DEBUG */ + +#define DBG(x) /* DBG */ +#define DBG_HEAVY(x) /* DBG_HEAVY */ +#define DBG_REG(x) /* DBG_REG */ +#define DBG_LOOP(x) /* DBG_LOOP */ + +#endif /* MATROXFB_DEBUG */ + +#ifndef __i386__ +#ifndef ioremap_nocache +#define ioremap_nocache(X,Y) ioremap(X,Y) +#endif +#endif + +#if defined(__alpha__) || defined(__m68k__) +#define READx_WORKS +#define MEMCPYTOIO_WORKS +#else +#define READx_FAILS +/* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */ +/* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */ +/* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */ +/* much of PCI bandwidth is used during transfers... */ +#if defined(__i386__) || defined(__ppc__) +#define MEMCPYTOIO_MEMCPY +#else +#define MEMCPYTOIO_WRITEL +#endif +#endif + +#ifdef __sparc__ +#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..." +#endif + +#ifdef __m68k__ +#define MAP_BUSTOVIRT +#else +#define MAP_IOREMAP +#endif + +#ifdef DEBUG +#define dprintk(X...) printk(X) +#else +#define dprintk(X...) +#endif + +#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF +#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A +#endif +#ifndef PCI_SS_VENDOR_ID_MATROX +#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX +#endif +#ifndef PCI_DEVICE_ID_MATROX_G200_AGP +#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G100 +#define PCI_DEVICE_ID_MATROX_G100 0x1000 +#endif +#ifndef PCI_DEVICE_ID_MATROX_G100_AGP +#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 +#endif + +#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP +#define PCI_SS_ID_MATROX_GENERIC 0xFF00 +#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01 +#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02 +#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03 +#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04 +#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05 +#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001 +#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */ +#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */ +#endif + +#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR +#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR +#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) + +/* G100, G200 and Mystique have (almost) same DAC */ +#undef NEED_DAC1064 +#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100) +#define NEED_DAC1064 1 +#endif + +typedef struct { + u_int8_t* vaddr; +} vaddr_t; + +#ifdef READx_WORKS +static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { + return readb(va.vaddr + offs); +} + +static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { + return readl(va.vaddr + offs); +} + +static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { + writeb(value, va.vaddr + offs); +} + +static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { + writew(value, va.vaddr + offs); +} + +static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { + writel(value, va.vaddr + offs); +} +#else +static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) { + return *(volatile u_int8_t*)(va.vaddr + offs); +} + +static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) { + return *(volatile u_int32_t*)(va.vaddr + offs); +} + +static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) { + *(volatile u_int8_t*)(va.vaddr + offs) = value; +} + +static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) { + *(volatile u_int16_t*)(va.vaddr + offs) = value; +} + +static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { + *(volatile u_int32_t*)(va.vaddr + offs) = value; +} +#endif + +static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) { +#ifdef MEMCPYTOIO_WORKS + memcpy_toio(va.vaddr + offs, src, len); +#elif defined(MEMCPYTOIO_WRITEL) +#define srcd ((const u_int32_t*)src) + if (offs & 3) { + while (len >= 4) { + mga_writel(va, offs, get_unaligned(srcd++)); + offs += 4; + len -= 4; + } + } else { + while (len >= 4) { + mga_writel(va, offs, *srcd++); + offs += 4; + len -= 4; + } + } +#undef srcd + if (len) { + u_int32_t tmp; + + memcpy(&tmp, src, len); + mga_writel(va, offs, tmp); + } +#elif defined(MEMCPYTOIO_MEMCPY) + memcpy(va.vaddr + offs, src, len); +#else +#error "Sorry, do not know how to write block of data to device" +#endif +} + +static inline void vaddr_add(vaddr_t* va, unsigned long offs) { + va->vaddr += offs; +} + +static inline void* vaddr_va(vaddr_t va) { + return va.vaddr; +} + +#define MGA_IOREMAP_NORMAL 0 +#define MGA_IOREMAP_NOCACHE 1 + +#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE +#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE +static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) { +#ifdef MAP_IOREMAP + if (flags & MGA_IOREMAP_NOCACHE) + virt->vaddr = ioremap_nocache(phys, size); + else + virt->vaddr = ioremap(phys, size); +#else +#ifdef MAP_BUSTOVIRT + virt->vaddr = bus_to_virt(phys); +#else +#error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up" +#endif +#endif + return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */ +} + +static inline void mga_iounmap(vaddr_t va) { +#ifdef MAP_IOREMAP + iounmap(va.vaddr); +#endif +} + +struct matroxfb_par +{ + struct fb_var_screeninfo var; + + unsigned int final_bppShift; + int visual; /* unfortunately, fix */ + int video_type; + unsigned int cmap_len; + void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int); + void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int); +}; + +struct my_timming { + unsigned int pixclock; + unsigned int HDisplay; + unsigned int HSyncStart; + unsigned int HSyncEnd; + unsigned int HTotal; + unsigned int VDisplay; + unsigned int VSyncStart; + unsigned int VSyncEnd; + unsigned int VTotal; + unsigned int sync; + int dblscan; + int interlaced; +}; + +struct matrox_fb_info; + +#define MATROX_2MB_WITH_4MB_ADDON + +struct matrox_pll_features { + unsigned int vco_freq_min; + unsigned int ref_freq; + unsigned int feed_div_min; + unsigned int feed_div_max; + unsigned int in_div_min; + unsigned int in_div_max; + unsigned int post_shift_max; +}; + +struct matrox_DAC1064_features { + u_int8_t xvrefctrl; + unsigned int cursorimage; +}; + +struct matrox_accel_features { + int has_cacheflush; +}; + +/* current hardware status */ +struct matrox_hw_state { + u_int32_t MXoptionReg; + unsigned char DACclk[6]; + unsigned char DACreg[64]; + unsigned char MiscOutReg; + unsigned char DACpal[768]; + unsigned char CRTC[25]; + unsigned char CRTCEXT[6]; + unsigned char SEQ[5]; + /* unused for MGA mode, but who knows... */ + unsigned char GCTL[9]; + /* unused for MGA mode, but who knows... */ + unsigned char ATTR[21]; +}; + +struct matrox_accel_data { +#ifdef CONFIG_FB_MATROX_MILLENIUM + unsigned char ramdac_rev; +#endif + u_int32_t m_dwg_rect; + u_int32_t m_opmode; +}; + +#ifdef CONFIG_FB_MATROX_MULTIHEAD +#define ACCESS_FBINFO(x) (minfo->x) +#define ACCESS_FBINFO2(info, x) (((struct matrox_fb_info*)info)->x) + +#define MINFO minfo + +#define WPMINFO struct matrox_fb_info* minfo, +#define CPMINFO const struct matrox_fb_info* minfo, +#define PMINFO minfo, + +static inline struct matrox_fb_info* mxinfo(struct display* p) { + return (struct matrox_fb_info*)p->fb_info; +} + +#define PMXINFO(p) mxinfo(p), +#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x) + +#else + +struct matrox_fb_info global_mxinfo; +struct display global_disp; + +#define ACCESS_FBINFO(x) (global_mxinfo.x) +#define ACCESS_FBINFO2(info, x) (global_mxinfo.x) + +#define MINFO (&global_mxinfo) + +#define WPMINFO +#define CPMINFO +#define PMINFO + +#if 0 +static inline struct matrox_fb_info* mxinfo(struct display* p) { + return &global_mxinfo; +} +#endif + +#define PMXINFO(p) +#define MINFO_FROM_DISP(x) + +#endif + +struct matrox_switch { + int (*preinit)(WPMINFO struct matrox_hw_state*); + void (*reset)(WPMINFO struct matrox_hw_state*); + int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*); + void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*); +}; + +struct matrox_fb_info { + /* fb_info must be first */ + struct fb_info fbcon; + + struct matrox_fb_info* next_fb; + + struct matroxfb_par curr; + struct matrox_hw_state hw1; + struct matrox_hw_state hw2; + struct matrox_hw_state* newhw; + struct matrox_hw_state* currenthw; + + struct matrox_accel_data accel; + +#ifdef MATROX_2MB_WITH_4MB_ADDON + unsigned int _mga_ydstorg; + unsigned int _curr_ydstorg; +#endif + + struct pci_dev* pcidev; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + unsigned int len_usable; + } video; + + struct { + unsigned long base; /* physical */ + vaddr_t vbase; /* CPU view */ + unsigned int len; + } mmio; + + unsigned int max_pixel_clock; + + struct matrox_switch* hw_switch; + int currcon; + struct display* currcon_display; + + struct { + struct matrox_pll_features pll; + struct matrox_DAC1064_features DAC1064; + struct matrox_accel_features accel; + } features; + struct { + spinlock_t DAC; + } lock; + + int interleave; + int millenium; + int milleniumII; + struct { + int cfb4; + const int* vxres; + int cross4MB; + } capable; + struct { + unsigned int size; + unsigned int mgabase; + vaddr_t vbase; + } fastfont; +#ifdef CONFIG_MTRR + struct { + int vram; + int vram_valid; + } mtrr; +#endif + struct { + int precise_width; + int mga_24bpp_fix; + int novga; + int nobios; + int nopciretry; + int inverse; + int hwcursor; + int blink; + + int accelerator; + int video64bits; + } devflags; + struct display_switch dispsw; + struct { + int x; + int y; + unsigned int w; + unsigned int u; + unsigned int d; + unsigned int type; + int state; + struct timer_list timer; + } cursor; +#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) + union { +#ifdef FBCON_HAS_CFB16 + u_int16_t cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u_int32_t cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u_int32_t cfb32[16]; +#endif + } cmap; +#endif + struct { unsigned red, green, blue, transp; } palette[256]; +#if defined(CONFIG_FB_COMPAT_XPMAC) + char matrox_name[32]; +#endif +}; + +#if defined(CONFIG_PPC) +unsigned char nvram_read_byte(int); +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +#endif +#if defined(CONFIG_FB_OF) +void matrox_of_init(struct device_node *dp); +#endif + +#ifdef MATROX_2MB_WITH_4MB_ADDON +#define mga_ydstorg(x) ACCESS_FBINFO2(x, _mga_ydstorg) +#define curr_ydstorg(x) ACCESS_FBINFO2(x, _curr_ydstorg) +#else +#define mga_ydstorg(x) (0) +#define curr_ydstorg(x) (0) +#endif + +#define PCI_OPTION_REG 0x40 +#define PCI_MGA_INDEX 0x44 +#define PCI_MGA_DATA 0x48 + +#define M_DWGCTL 0x1C00 +#define M_MACCESS 0x1C04 +#define M_CTLWTST 0x1C08 + +#define M_PLNWT 0x1C1C + +#define M_BCOL 0x1C20 +#define M_FCOL 0x1C24 + +#define M_SGN 0x1C58 +#define M_LEN 0x1C5C +#define M_AR0 0x1C60 +#define M_AR1 0x1C64 +#define M_AR2 0x1C68 +#define M_AR3 0x1C6C +#define M_AR4 0x1C70 +#define M_AR5 0x1C74 +#define M_AR6 0x1C78 + +#define M_CXBNDRY 0x1C80 +#define M_FXBNDRY 0x1C84 +#define M_YDSTLEN 0x1C88 +#define M_PITCH 0x1C8C +#define M_YDST 0x1C90 +#define M_YDSTORG 0x1C94 +#define M_YTOP 0x1C98 +#define M_YBOT 0x1C9C + +/* mystique only */ +#define M_CACHEFLUSH 0x1FFF + +#define M_EXEC 0x0100 + +#define M_DWG_TRAP 0x04 +#define M_DWG_BITBLT 0x08 +#define M_DWG_ILOAD 0x09 + +#define M_DWG_LINEAR 0x0080 +#define M_DWG_SOLID 0x0800 +#define M_DWG_ARZERO 0x1000 +#define M_DWG_SGNZERO 0x2000 +#define M_DWG_SHIFTZERO 0x4000 + +#define M_DWG_REPLACE 0x000C0000 +#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40) +#define M_DWG_XOR 0x00060010 + +#define M_DWG_BFCOL 0x04000000 +#define M_DWG_BMONOWF 0x08000000 + +#define M_DWG_TRANSC 0x40000000 + +#define M_FIFOSTATUS 0x1E10 +#define M_STATUS 0x1E14 + +#define M_IEN 0x1E1C + +#define M_VCOUNT 0x1E20 + +#define M_RESET 0x1E40 + +#define M_OPMODE 0x1E54 +#define M_OPMODE_DMA_GEN_WRITE 0x00 +#define M_OPMODE_DMA_BLIT 0x04 +#define M_OPMODE_DMA_VECTOR_WRITE 0x08 +#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */ +#define M_OPMODE_DMA_BE_8BPP 0x0000 +#define M_OPMODE_DMA_BE_16BPP 0x0100 +#define M_OPMODE_DMA_BE_32BPP 0x0200 +#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */ +#define M_OPMODE_DIR_BE_8BPP 0x000000 +#define M_OPMODE_DIR_BE_16BPP 0x010000 +#define M_OPMODE_DIR_BE_32BPP 0x020000 + +#define M_ATTR_INDEX 0x1FC0 +#define M_ATTR_DATA 0x1FC1 + +#define M_MISC_REG 0x1FC2 +#define M_3C2_RD 0x1FC2 + +#define M_SEQ_INDEX 0x1FC4 +#define M_SEQ_DATA 0x1FC5 + +#define M_MISC_REG_READ 0x1FCC + +#define M_GRAPHICS_INDEX 0x1FCE +#define M_GRAPHICS_DATA 0x1FCF + +#define M_CRTC_INDEX 0x1FD4 + +#define M_ATTR_RESET 0x1FDA +#define M_3DA_WR 0x1FDA + +#define M_EXTVGA_INDEX 0x1FDE +#define M_EXTVGA_DATA 0x1FDF + +#define M_RAMDAC_BASE 0x3C00 + +/* fortunately, same on TVP3026 and MGA1064 */ +#define M_DAC_REG (M_RAMDAC_BASE+0) +#define M_DAC_VAL (M_RAMDAC_BASE+1) +#define M_PALETTE_MASK (M_RAMDAC_BASE+2) + +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define TVP3026_INDEX 0x00 +#define TVP3026_PALWRADD 0x00 +#define TVP3026_PALDATA 0x01 +#define TVP3026_PIXRDMSK 0x02 +#define TVP3026_PALRDADD 0x03 +#define TVP3026_CURCOLWRADD 0x04 +#define TVP3026_CLOVERSCAN 0x00 +#define TVP3026_CLCOLOR0 0x01 +#define TVP3026_CLCOLOR1 0x02 +#define TVP3026_CLCOLOR2 0x03 +#define TVP3026_CURCOLDATA 0x05 +#define TVP3026_CURCOLRDADD 0x07 +#define TVP3026_CURCTRL 0x09 +#define TVP3026_X_DATAREG 0x0A +#define TVP3026_CURRAMDATA 0x0B +#define TVP3026_CURPOSXL 0x0C +#define TVP3026_CURPOSXH 0x0D +#define TVP3026_CURPOSYL 0x0E +#define TVP3026_CURPOSYH 0x0F + +#define TVP3026_XSILICONREV 0x01 +#define TVP3026_XCURCTRL 0x06 +#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define TVP3026_XCURCTRL_BLANK2048 0x00 +#define TVP3026_XCURCTRL_BLANK4096 0x10 +#define TVP3026_XCURCTRL_INTERLACED 0x20 +#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */ +#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */ +#define TVP3026_XCURCTRL_INDIRECT 0x00 +#define TVP3026_XCURCTRL_DIRECT 0x80 +#define TVP3026_XLATCHCTRL 0x0F +#define TVP3026_XLATCHCTRL_1_1 0x06 +#define TVP3026_XLATCHCTRL_2_1 0x07 +#define TVP3026_XLATCHCTRL_4_1 0x06 +#define TVP3026_XLATCHCTRL_8_1 0x06 +#define TVP3026_XLATCHCTRL_16_1 0x06 +#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026A_XLATCHCTRL_8_3 0x07 +#define TVP3026B_XLATCHCTRL_4_3 0x08 +#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */ +#define TVP3026_XTRUECOLORCTRL 0x18 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00 +#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20 +#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80 +#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */ +#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00 +#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */ +#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */ +#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17 +#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06 +#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07 +#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05 +#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04 +#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03 +#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01 +#define TVP3026_XMUXCTRL 0x19 +#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */ +#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */ +#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */ +#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */ +#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48 +#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50 +#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58 +#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */ +#define TVP3026_XCLKCTRL 0x1A +#define TVP3026_XCLKCTRL_DIV1 0x00 +#define TVP3026_XCLKCTRL_DIV2 0x10 +#define TVP3026_XCLKCTRL_DIV4 0x20 +#define TVP3026_XCLKCTRL_DIV8 0x30 +#define TVP3026_XCLKCTRL_DIV16 0x40 +#define TVP3026_XCLKCTRL_DIV32 0x50 +#define TVP3026_XCLKCTRL_DIV64 0x60 +#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70 +#define TVP3026_XCLKCTRL_SRC_CLK0 0x00 +#define TVP3026_XCLKCTRL_SRC_CLK1 0x01 +#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/ +#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */ +#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */ +#define TVP3026_XCLKCTRL_SRC_PLL 0x05 +#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */ +#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07 +#define TVP3026_XPALETTEPAGE 0x1C +#define TVP3026_XGENCTRL 0x1D +#define TVP3026_XGENCTRL_HSYNC_POS 0x00 +#define TVP3026_XGENCTRL_HSYNC_NEG 0x01 +#define TVP3026_XGENCTRL_VSYNC_POS 0x00 +#define TVP3026_XGENCTRL_VSYNC_NEG 0x02 +#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00 +#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08 +#define TVP3026_XGENCTRL_BLACK_0IRE 0x00 +#define TVP3026_XGENCTRL_BLACK_75IRE 0x10 +#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00 +#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20 +#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00 +#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40 +#define TVP3026_XMISCCTRL 0x1E +#define TVP3026_XMISCCTRL_DAC_PUP 0x00 +#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01 +#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */ +#define TVP3026_XMISCCTRL_DAC_6BIT 0x04 +#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C +#define TVP3026_XMISCCTRL_PSEL_DIS 0x00 +#define TVP3026_XMISCCTRL_PSEL_EN 0x10 +#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */ +#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */ +#define TVP3026_XGENIOCTRL 0x2A +#define TVP3026_XGENIODATA 0x2B +#define TVP3026_XPLLADDR 0x2C +#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX)) +#define TVP3026_XPLLDATA_N 0x00 +#define TVP3026_XPLLDATA_M 0x01 +#define TVP3026_XPLLDATA_P 0x02 +#define TVP3026_XPLLDATA_STAT 0x03 +#define TVP3026_XPIXPLLDATA 0x2D +#define TVP3026_XMEMPLLDATA 0x2E +#define TVP3026_XLOOPPLLDATA 0x2F +#define TVP3026_XCOLKEYOVRMIN 0x30 +#define TVP3026_XCOLKEYOVRMAX 0x31 +#define TVP3026_XCOLKEYREDMIN 0x32 +#define TVP3026_XCOLKEYREDMAX 0x33 +#define TVP3026_XCOLKEYGREENMIN 0x34 +#define TVP3026_XCOLKEYGREENMAX 0x35 +#define TVP3026_XCOLKEYBLUEMIN 0x36 +#define TVP3026_XCOLKEYBLUEMAX 0x37 +#define TVP3026_XCOLKEYCTRL 0x38 +#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01 +#define TVP3026_XCOLKEYCTRL_RED_EN 0x02 +#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04 +#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08 +#define TVP3026_XCOLKEYCTRL_NEGATE 0x10 +#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00 +#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20 +#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40 +#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60 +#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80 +#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0 +#define TVP3026_XMEMPLLCTRL 0x39 +#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */ +#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08 +#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */ +#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00 +#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20 +#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */ +#define TVP3026_XSENSETEST 0x3A +#define TVP3026_XTESTMODEDATA 0x3B +#define TVP3026_XCRCREML 0x3C +#define TVP3026_XCRCREMH 0x3D +#define TVP3026_XCRCBITSEL 0x3E +#define TVP3026_XID 0x3F + +#endif + +#ifdef NEED_DAC1064 + +#define DAC1064_OPT_SCLK_PCI 0x00 +#define DAC1064_OPT_SCLK_PLL 0x01 +#define DAC1064_OPT_SCLK_EXT 0x02 +#define DAC1064_OPT_SCLK_MASK 0x03 +#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */ +#define DAC1064_OPT_GDIV3 0x00 +#define DAC1064_OPT_MDIV1 0x08 +#define DAC1064_OPT_MDIV2 0x00 +#define DAC1064_OPT_RESERVED 0x10 + +#define M1064_INDEX 0x00 +#define M1064_PALWRADD 0x00 +#define M1064_PALDATA 0x01 +#define M1064_PIXRDMSK 0x02 +#define M1064_PALRDADD 0x03 +#define M1064_X_DATAREG 0x0A +#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */ +#define M1064_CURPOSXH 0x0D +#define M1064_CURPOSYL 0x0E +#define M1064_CURPOSYH 0x0F + +#define M1064_XCURADDL 0x04 +#define M1064_XCURADDH 0x05 +#define M1064_XCURCTRL 0x06 +#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */ +#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */ +#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */ +#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */ +#define M1064_XCURCOL0RED 0x08 +#define M1064_XCURCOL0GREEN 0x09 +#define M1064_XCURCOL0BLUE 0x0A +#define M1064_XCURCOL1RED 0x0C +#define M1064_XCURCOL1GREEN 0x0D +#define M1064_XCURCOL1BLUE 0x0E +#define M1064_XCURCOL2RED 0x10 +#define M1064_XCURCOL2GREEN 0x11 +#define M1064_XCURCOL2BLUE 0x12 +#define DAC1064_XVREFCTRL 0x18 +#define DAC1064_XVREFCTRL_INTERNAL 0x3F +#define DAC1064_XVREFCTRL_EXTERNAL 0x00 +#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03 +#define M1064_XMULCTRL 0x19 +#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */ +#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */ +#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */ +#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */ +#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */ +#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */ +#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00 +#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08 +#define M1064_XPIXCLKCTRL 0x1A +#define M1064_XPIXCLKCTRL_SRC_PCI 0x00 +#define M1064_XPIXCLKCTRL_SRC_PLL 0x01 +#define M1064_XPIXCLKCTRL_SRC_EXT 0x02 +#define M1064_XPIXCLKCTRL_SRC_MASK 0x03 +#define M1064_XPIXCLKCTRL_EN 0x00 +#define M1064_XPIXCLKCTRL_DIS 0x04 +#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00 +#define M1064_XPIXCLKCTRL_PLL_UP 0x08 +#define M1064_XGENCTRL 0x1D +#define M1064_XGENCTRL_VS_0 0x00 +#define M1064_XGENCTRL_VS_1 0x01 +#define M1064_XGENCTRL_ALPHA_DIS 0x00 +#define M1064_XGENCTRL_ALPHA_EN 0x02 +#define M1064_XGENCTRL_BLACK_0IRE 0x00 +#define M1064_XGENCTRL_BLACK_75IRE 0x10 +#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00 +#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20 +#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20 +#define M1064_XMISCCTRL 0x1E +#define M1064_XMISCCTRL_DAC_DIS 0x00 +#define M1064_XMISCCTRL_DAC_EN 0x01 +#define M1064_XMISCCTRL_MFC_VGA 0x00 +#define M1064_XMISCCTRL_MFC_MAFC 0x02 +#define M1064_XMISCCTRL_MFC_DIS 0x06 +#define M1064_XMISCCTRL_DAC_6BIT 0x00 +#define M1064_XMISCCTRL_DAC_8BIT 0x08 +#define M1064_XMISCCTRL_LUT_DIS 0x00 +#define M1064_XMISCCTRL_LUT_EN 0x10 +#define M1064_XGENIOCTRL 0x2A +#define M1064_XGENIODATA 0x2B +#define DAC1064_XSYSPLLM 0x2C +#define DAC1064_XSYSPLLN 0x2D +#define DAC1064_XSYSPLLP 0x2E +#define DAC1064_XSYSPLLSTAT 0x2F +#define M1064_XZOOMCTRL 0x38 +#define M1064_XZOOMCTRL_1 0x00 +#define M1064_XZOOMCTRL_2 0x01 +#define M1064_XZOOMCTRL_4 0x03 +#define M1064_XSENSETEST 0x3A +#define M1064_XSENSETEST_BCOMP 0x01 +#define M1064_XSENSETEST_GCOMP 0x02 +#define M1064_XSENSETEST_RCOMP 0x04 +#define M1064_XSENSETEST_PDOWN 0x00 +#define M1064_XSENSETEST_PUP 0x80 +#define M1064_XCRCREML 0x3C +#define M1064_XCRCREMH 0x3D +#define M1064_XCRCBITSEL 0x3E +#define M1064_XCOLKEYMASKL 0x40 +#define M1064_XCOLKEYMASKH 0x41 +#define M1064_XCOLKEYL 0x42 +#define M1064_XCOLKEYH 0x43 +#define M1064_XPIXPLLAM 0x44 +#define M1064_XPIXPLLAN 0x45 +#define M1064_XPIXPLLAP 0x46 +#define M1064_XPIXPLLBM 0x48 +#define M1064_XPIXPLLBN 0x49 +#define M1064_XPIXPLLBP 0x4A +#define M1064_XPIXPLLCM 0x4C +#define M1064_XPIXPLLCN 0x4D +#define M1064_XPIXPLLCP 0x4E +#define M1064_XPIXPLLSTAT 0x4F + +#endif + +#ifdef __LITTLE_ENDIAN +#define MX_OPTION_BSWAP 0x00000000 + +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) +#else +#ifdef __BIG_ENDIAN +#define MX_OPTION_BSWAP 0x80000000 + +#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */ +#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT) +#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */ +#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT) +#else +#error "Byte ordering have to be defined. Cannot continue." +#endif +#endif + +#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr)) +#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val)) +#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1)) +#ifdef __LITTLE_ENDIAN +#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port)) +#else +#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0) +#endif + +#ifdef __LITTLE_ENDIAN +#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n)) +#else +#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n)) +#endif + +#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000) + +/* code speedup */ +#ifdef CONFIG_FB_MATROX_MILLENIUM +#define isInterleave(x) (x->interleave) +#define isMillenium(x) (x->millenium) +#define isMilleniumII(x) (x->milleniumII) +#else +#define isInterleave(x) (0) +#define isMillenium(x) (0) +#define isMilleniumII(x) (0) +#endif + +static void matrox_cfbX_init(struct matrox_fb_info* minfo) { + u_int32_t maccess; + u_int32_t mpitch; + u_int32_t mopmode; + + DBG("matrox_cfbX_init") + +#ifdef MATROX_2MB_WITH_4MB_ADDON + curr_ydstorg(MINFO) = mga_ydstorg(MINFO); +#endif + mpitch = ACCESS_FBINFO(curr.var.xres_virtual); + + switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) { + case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ + mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ + mopmode = M_OPMODE_4BPP; + break; + case 8: maccess = 0x00000000; + mopmode = M_OPMODE_8BPP; + break; + case 16: if (ACCESS_FBINFO(curr.var.green.length) == 5) + maccess = 0xC0000001; + else + maccess = 0x40000001; +#ifdef MATROX_2MB_WITH_4MB_ADDON + curr_ydstorg(MINFO) >>= 1; +#endif + mopmode = M_OPMODE_16BPP; + break; + case 24: maccess = 0x00000003; +#ifdef MATROX_2MB_WITH_4MB_ADDON + curr_ydstorg(MINFO) /= 3; +#endif + mopmode = M_OPMODE_24BPP; + break; + case 32: maccess = 0x00000002; +#ifdef MATROX_2MB_WITH_4MB_ADDON + curr_ydstorg(MINFO) >>= 2; +#endif + mopmode = M_OPMODE_32BPP; + break; + default: maccess = 0x00000000; + mopmode = 0x00000000; + break; /* turn off acceleration!!! */ + } + mga_fifo(8); + mga_outl(M_PITCH, mpitch); + mga_outl(M_YDSTORG, curr_ydstorg(MINFO)); + mga_outl(M_PLNWT, -1); + mga_outl(M_OPMODE, mopmode); + mga_outl(M_CXBNDRY, 0xFFFF0000); + mga_outl(M_YTOP, 0); + mga_outl(M_YBOT, 0x007FFFFF); + mga_outl(M_MACCESS, maccess); + ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; + if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC; + ACCESS_FBINFO(accel.m_opmode) = mopmode; +} + +static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { + int pixx = p->var.xres_virtual, start, end; + MINFO_FROM_DISP(p); + + DBG("matrox_cfbX_bmove") + + sx *= fontwidth(p); + dx *= fontwidth(p); + width *= fontwidth(p); + height *= fontheight(p); + sy *= fontheight(p); + dy *= fontheight(p); + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_AR5, pixx); + width--; + start = sy*pixx+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -pixx); + width--; + end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(4); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height); + WaitTillIdle(); +} + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { + int pixx, start, end; + MINFO_FROM_DISP(p); + /* both (sx or dx or width) and fontwidth() are odd, so their multiply is + also odd, that means that we cannot use acceleration */ + + DBG("matrox_cfb4_bmove") + + if ((sx | dx | width) & fontwidth(p) & 1) { + fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width); + return; + } + sx *= fontwidth(p); + dx *= fontwidth(p); + width *= fontwidth(p); + height *= fontheight(p); + sy *= fontheight(p); + dy *= fontheight(p); + pixx = p->var.xres_virtual >> 1; + sx >>= 1; + dx >>= 1; + width >>= 1; + if ((dy < sy) || ((dy == sy) && (dx <= sx))) { + mga_fifo(2); + mga_outl(M_AR5, pixx); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | + M_DWG_BFCOL | M_DWG_REPLACE); + width--; + start = sy*pixx+sx+curr_ydstorg(MINFO); + end = start+width; + } else { + mga_fifo(3); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -pixx); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + width--; + end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + start = end+width; + dy += height-1; + } + mga_fifo(5); + mga_outl(M_AR0, end); + mga_outl(M_AR3, start); + mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); + mga_outl(M_YDST, dy*pixx >> 5); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); +} +#endif + +static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height, + int width) { + + DBG("matroxfb_accel_clear") + + mga_fifo(4); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE); + mga_outl(M_FCOL, color); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height); + WaitTillIdle(); +} + +static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) { + + DBG("matrox_cfbX_clear") + + matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p), + height * fontheight(p), width * fontwidth(p)); +} + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + int whattodo; + MINFO_FROM_DISP(p); + + DBG("matrox_cfb4_clear") + + whattodo = 0; + bgx = attr_bgcol_ec(p, conp); + bgx |= bgx << 4; + bgx |= bgx << 8; + bgx |= bgx << 16; + sy *= fontheight(p); + sx *= fontwidth(p); + height *= fontheight(p); + width *= fontwidth(p); + if (sx & 1) { + sx ++; + if (!width) return; + width --; + whattodo = 1; + } + if (width & 1) { + whattodo |= 2; + } + width >>= 1; + sx >>= 1; + if (width) { + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2); + mga_outl(M_FCOL, bgx); + mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); + mga_outl(M_YDST, sy * p->var.xres_virtual >> 6); + mga_outl(M_LEN | M_EXEC, height); + WaitTillIdle(); + } + if (whattodo) { + u_int32_t step = p->var.xres_virtual >> 1; + vaddr_t vbase = ACCESS_FBINFO(video.vbase); + if (whattodo & 1) { + unsigned int uaddr = sy * step + sx - 1; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0xF0; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2); + uaddr += step; + } + } + if (whattodo & 2) { + unsigned int uaddr = sy * step + sx + width; + u_int32_t loop; + u_int8_t bgx2 = bgx & 0x0F; + for (loop = height; loop > 0; loop --) { + mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2); + uaddr += step; + } + } + } +} +#endif + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb8_clear") + + bgx = attr_bgcol_ec(p, conp); + bgx |= bgx << 8; + bgx |= bgx << 16; + matrox_cfbX_clear(bgx, p, sy, sx, height, width); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb16_clear") + + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { + u_int32_t bgx; + + DBG("matrox_cfb32_clear") + + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + matrox_cfbX_clear(bgx, p, sy, sx, height, width); +} +#endif + +static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { + unsigned int charcell; + unsigned int ar3; + MINFO_FROM_DISP(p); + + charcell = fontwidth(p) * fontheight(p); + yy *= fontheight(p); + xx *= fontwidth(p); + mga_fifo(7); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); + ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell; + mga_outl(M_AR3, ar3); + mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); + mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p)); + WaitTillIdle(); +} + +static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { + u_int32_t ar0; + u_int32_t step; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matrox_cfbX_putc"); + + yy *= fontheight(p); + xx *= fontwidth(p); +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_8BPP); +#else + mga_fifo(7); +#endif + ar0 = fontwidth(p) - 1; + mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx); + if (fontwidth(p) <= 8) + step = 1; + else if (fontwidth(p) <= 16) + step = 2; + else + step = 4; + if (fontwidth(p) == step << 3) { + size_t charcell = fontheight(p)*step; + /* TODO: Align charcell to 4B for BE */ + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_AR3, 0); + mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1); + mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p)); + mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell); + } else { + u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step; + int i; + + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + mga_outl(M_AR5, 0); + mga_outl(M_AR3, 0); + mga_outl(M_AR0, ar0); + mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p)); + + switch (step) { + case 1: + for (i = fontheight(p); i > 0; i--) { +#ifdef __LITTLE_ENDIAN + mga_outl(0, *chardata++); +#else + mga_outl(0, (*chardata++) << 24); +#endif + } + break; + case 2: + for (i = fontheight(p); i > 0; i--) { +#ifdef __LITTLE_ENDIAN + mga_outl(0, *(u_int16_t*)chardata); +#else + mga_outl(0, (*(u_int16_t*)chardata) << 16); +#endif + chardata += 2; + } + break; + case 4: + mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4); + break; + } + } + WaitTillIdle(); +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif +} + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb8_putc"); + + fgx = attr_fgcol(p, c); + bgx = attr_bgcol(p, c); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb16_putc"); + + fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb32_putc"); + + fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)]; + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)]; + ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); +} +#endif + +static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { + unsigned int charcell; + MINFO_FROM_DISP(p); + + yy *= fontheight(p); + xx *= fontwidth(p); + charcell = fontwidth(p) * fontheight(p); + mga_fifo(3); + mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + while (count--) { + u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (*s++ & p->charmask)*charcell; + + mga_fifo(4); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); + mga_outl(M_AR3, ar3); + mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); + mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p)); + xx += fontwidth(p); + } + WaitTillIdle(); +} + +static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t step; + u_int32_t ydstlen; + u_int32_t xlen; + u_int32_t ar0; + u_int32_t charcell; + u_int32_t fxbndry; + vaddr_t mmio; + int easy; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfbX_putcs"); + + yy *= fontheight(p); + xx *= fontwidth(p); + if (fontwidth(p) <= 8) + step = 1; + else if (fontwidth(p) <= 16) + step = 2; + else + step = 4; + charcell = fontheight(p)*step; + xlen = (charcell + 3) & ~3; + ydstlen = (yy<<16) | fontheight(p); + if (fontwidth(p) == step << 3) { + ar0 = fontheight(p)*fontwidth(p) - 1; + easy = 1; + } else { + ar0 = fontwidth(p) - 1; + easy = 0; + } +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_8BPP); +#else + mga_fifo(3); +#endif + if (easy) + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); + else + mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); + mga_outl(M_FCOL, fgx); + mga_outl(M_BCOL, bgx); + fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx; + mmio = ACCESS_FBINFO(mmio.vbase); + while (count--) { + u_int8_t* chardata = p->fontdata + (*s++ & p->charmask)*charcell; + + mga_fifo(5); + mga_writel(mmio, M_FXBNDRY, fxbndry); + mga_writel(mmio, M_AR0, ar0); + mga_writel(mmio, M_AR3, 0); + if (easy) { + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + mga_memcpy_toio(mmio, 0, chardata, xlen); + } else { + mga_writel(mmio, M_AR5, 0); + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + switch (step) { + case 1: { + u_int8_t* charend = chardata + charcell; + for (; chardata != charend; chardata++) { +#ifdef __LITTLE_ENDIAN + mga_writel(mmio, 0, *chardata); +#else + mga_writel(mmio, 0, (*chardata) << 24); +#endif + } + } + break; + case 2: { + u_int8_t* charend = chardata + charcell; + for (; chardata != charend; chardata += 2) { +#ifdef __LITTLE_ENDIAN + mga_writel(mmio, 0, *(u_int16_t*)chardata); +#else + mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16); +#endif + } + } + break; + default: + mga_memcpy_toio(mmio, 0, chardata, charcell); + break; + } + } + fxbndry += fontwidth(p) + (fontwidth(p) << 16); + } + WaitTillIdle(); +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif +} + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb8_putcs"); + + fgx = attr_fgcol(p, *s); + bgx = attr_bgcol(p, *s); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB16 +static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb16_putcs"); + + fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, *s)]; + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, *s)]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) +static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { + u_int32_t fgx, bgx; + MINFO_FROM_DISP(p); + + DBG_HEAVY("matroxfb_cfb32_putcs"); + + fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, *s)]; + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, *s)]; + ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); +} +#endif + +#ifdef FBCON_HAS_CFB4 +static void matrox_cfb4_revc(struct display* p, int xx, int yy) { + MINFO_FROM_DISP(p); + + DBG_LOOP("matroxfb_cfb4_revc"); + + if (fontwidth(p) & 1) { + fbcon_cfb4_revc(p, xx, yy); + return; + } + yy *= fontheight(p); + xx *= fontwidth(p); + xx |= (xx + fontwidth(p)) << 16; + xx >>= 1; + + mga_fifo(5); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0xFFFFFFFF); + mga_outl(M_FXBNDRY, xx); + mga_outl(M_YDST, yy * p->var.xres_virtual >> 6); + mga_outl(M_LEN | M_EXEC, fontheight(p)); + WaitTillIdle(); +} +#endif + +#ifdef FBCON_HAS_CFB8 +static void matrox_cfb8_revc(struct display* p, int xx, int yy) { + MINFO_FROM_DISP(p); + + DBG_LOOP("matrox_cfb8_revc") + + yy *= fontheight(p); + xx *= fontwidth(p); + + mga_fifo(4); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0x0F0F0F0F); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); + mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p)); + WaitTillIdle(); +} +#endif + +static void matrox_cfbX_revc(struct display* p, int xx, int yy) { + MINFO_FROM_DISP(p); + + DBG_LOOP("matrox_cfbX_revc") + + yy *= fontheight(p); + xx *= fontwidth(p); + + mga_fifo(4); + mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); + mga_outl(M_FCOL, 0xFFFFFFFF); + mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); + mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p)); + WaitTillIdle(); +} + +static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) { + unsigned int bottom_height, right_width; + unsigned int bottom_start, right_start; + unsigned int cell_h, cell_w; + + DBG("matrox_cfbX_clear_margins") + + cell_w = fontwidth(p); + if (!cell_w) return; /* PARANOID */ + right_width = p->var.xres % cell_w; + right_start = p->var.xres - right_width; + if (!bottom_only && right_width) { + /* clear whole right margin, not only visible portion */ + matroxfb_accel_clear( PMXINFO(p) + /* color */ 0x00000000, + /* y */ 0, + /* x */ p->var.xoffset + right_start, + /* height */ p->var.yres_virtual, + /* width */ right_width); + } + cell_h = fontheight(p); + if (!cell_h) return; /* PARANOID */ + bottom_height = p->var.yres % cell_h; + if (bottom_height) { + bottom_start = p->var.yres - bottom_height; + matroxfb_accel_clear( PMXINFO(p) + /* color */ 0x00000000, + /* y */ p->var.yoffset + bottom_start, + /* x */ p->var.xoffset, + /* height */ bottom_height, + /* width */ right_start); + } +} + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static void outTi3026(CPMINFO int reg, int val) { + + DBG_REG("outTi3026") + + mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg); + mga_outb(M_RAMDAC_BASE+TVP3026_X_DATAREG, val); +} + +static int inTi3026(CPMINFO int reg) { + + DBG_REG("inTi3026") + + mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, reg); + return mga_inb(M_RAMDAC_BASE+TVP3026_X_DATAREG); +} + +#define POS3026_XCURCTRL 20 + +static void matroxfb_ti3026_flashcursor(unsigned long ptr) { +#define minfo ((struct matrox_fb_info*)ptr) + spin_lock(&ACCESS_FBINFO(lock.DAC)); + outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA); + ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; + add_timer(&ACCESS_FBINFO(cursor.timer)); + spin_unlock(&ACCESS_FBINFO(lock.DAC)); +#undef minfo +} + +static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) { + unsigned long flags; + u_int32_t xline; + unsigned int i; + unsigned int w, h; + unsigned int cd, cu; + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + DBG("matroxfb_ti3026_createcursor"); + + w = fontwidth(p); + h = fontheight(p); + + if (ACCESS_FBINFO(curr.var.vmode) & FB_VMODE_DOUBLE) + h *= 2; + cd = h; + if (cd >= 10) + cd -= 1; + switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) { + case CUR_NONE: + cu = cd; + break; + case CUR_UNDERLINE: + cu = cd - 2; + break; + case CUR_LOWER_THIRD: + cu = (h * 2) / 3; + break; + case CUR_LOWER_HALF: + cu = h / 2; + break; + case CUR_TWO_THIRDS: + cu = h / 3; + break; + case CUR_BLOCK: + default: + cu = 0; + cd = h; + break; + } + ACCESS_FBINFO(cursor.w) = w; + ACCESS_FBINFO(cursor.u) = cu; + ACCESS_FBINFO(cursor.d) = cd; + xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); + spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); + mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0); + for (i = 0; i < cu; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + for (; i < cd; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + for (; i < 64; i++) { + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); + } + for (i = 0; i < 512; i++) + mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF); + spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); +} + +static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) { + unsigned long flags; + MINFO_FROM_DISP(p); + + DBG("matroxfb_ti3026_cursor") + + if (mode == CM_ERASE) { + if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { + spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + del_timer(&ACCESS_FBINFO(cursor.timer)); + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); + spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); + } + return; + } + if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) + matroxfb_ti3026_createcursor(PMINFO p); + x *= fontwidth(p); + y *= fontheight(p); + y -= p->var.yoffset; + if (ACCESS_FBINFO(curr.var.vmode) & FB_VMODE_DOUBLE) + y *= 2; + spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); + if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y))) { + ACCESS_FBINFO(cursor.x) = x; + ACCESS_FBINFO(cursor.y) = y; + x += 64; + y += 64; + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL])); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y); + mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8); + } + ACCESS_FBINFO(cursor.state) = CM_DRAW; + if (ACCESS_FBINFO(devflags.blink)) + mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); + outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA); + spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); +} +#undef POS3026_XCURCTRL + +static int matroxfb_ti3026_setfont(struct display* p, int width, int height) { + + DBG("matrox_ti3026_setfont"); + + if (p && p->conp) + matroxfb_ti3026_createcursor(PMXINFO(p) p); + return 0; +} +#endif + +#ifdef NEED_DAC1064 +static void outDAC1064(CPMINFO int reg, int val) { + + DBG_REG("outDAC1064"); + + mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg); + mga_outb(M_RAMDAC_BASE+M1064_X_DATAREG, val); +} + +static int inDAC1064(CPMINFO int reg) { + + DBG_REG("inDAC1064"); + + mga_outb(M_RAMDAC_BASE+M1064_INDEX, reg); + return mga_inb(M_RAMDAC_BASE+M1064_X_DATAREG); +} + +static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { +#define minfo ((struct matrox_fb_info*)ptr) + spin_lock(&ACCESS_FBINFO(lock.DAC)); + outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); + ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; + add_timer(&ACCESS_FBINFO(cursor.timer)); + spin_unlock(&ACCESS_FBINFO(lock.DAC)); +#undef minfo +} + +static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { + vaddr_t cursorbase; + u_int32_t xline; + unsigned int i; + unsigned int w, h; + unsigned int cu, cd; + + if (ACCESS_FBINFO(currcon_display) != p) + return; + + w = fontwidth(p); + h = fontheight(p); + + if (ACCESS_FBINFO(curr.var.vmode) & FB_VMODE_DOUBLE) + h *= 2; + cd = h; + if (cd >= 10) + cd -= 1; + switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) { + case CUR_NONE: + cu = cd; + break; + case CUR_UNDERLINE: + cu = cd - 2; + break; + case CUR_LOWER_THIRD: + cu = (h * 2) / 3; + break; + case CUR_LOWER_HALF: + cu = h / 2; + break; + case CUR_TWO_THIRDS: + cu = h / 3; + break; + case CUR_BLOCK: + default: + cu = 0; + cd = h; + break; + } + ACCESS_FBINFO(cursor.w) = w; + ACCESS_FBINFO(cursor.u) = cu; + ACCESS_FBINFO(cursor.d) = cd; + xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); + cursorbase = ACCESS_FBINFO(video.vbase); + h = ACCESS_FBINFO(features.DAC1064.cursorimage); +#ifdef __BIG_ENDIAN + WaitTillIdle(); + mga_outl(M_OPMODE, M_OPMODE_32BPP); +#endif + for (i = 0; i < cu; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, 0); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } + for (; i < cd; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, xline); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } + for (; i < 64; i++) { + mga_writel(cursorbase, h, 0); + mga_writel(cursorbase, h+4, 0); + mga_writel(cursorbase, h+8, ~0); + mga_writel(cursorbase, h+12, ~0); + h += 16; + } +#ifdef __BIG_ENDIAN + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); +#endif +} + +static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { + unsigned long flags; + MINFO_FROM_DISP(p); + + if (mode == CM_ERASE) { + if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { + spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + del_timer(&ACCESS_FBINFO(cursor.timer)); + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); + spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); + } + return; + } + if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) + matroxfb_DAC1064_createcursor(PMINFO p); + x *= fontwidth(p); + y *= fontheight(p); + y -= p->var.yoffset; + if (ACCESS_FBINFO(curr.var.vmode) & FB_VMODE_DOUBLE) + y *= 2; + spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags); + if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y))) { + ACCESS_FBINFO(cursor.x) = x; + ACCESS_FBINFO(cursor.y) = y; + x += 64; + y += 64; + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y); + mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8); + } + ACCESS_FBINFO(cursor.state) = CM_DRAW; + if (ACCESS_FBINFO(devflags.blink)) + mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); + outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA); + spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags); +} + +static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { + if (p && p->conp) + matroxfb_DAC1064_createcursor(PMXINFO(p) p); + return 0; +} +#endif + +#ifndef FNTCHARCNT +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#endif + +static int matroxfb_fastfont_tryset(WPMINFO struct display* p) { + unsigned int fsize; + unsigned int width; + + if (!p || !p->fontdata) + return 0; + width = fontwidth(p); + if (width > 32) + return 0; + fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p); + if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size)) + return 0; + mga_outl(M_OPMODE, M_OPMODE_8BPP); + if (width <= 8) { + if (width == 8) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize); + else { + vaddr_t dst; + unsigned int i; + u_int8_t* font; + u_int32_t mask, valid, reg; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int8_t*)p->fontdata; + mask = ~0 << (8 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (*font++ & mask) << (8 - valid); + valid += width; + if (valid >= 8) { + mga_writeb(dst, i++, reg >> 8); + reg = reg << 8; + valid -= 8; + } + } + if (valid) + mga_writeb(dst, i, reg >> 8); + } + } else if (width <= 16) { + if (width == 16) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2); + else { + vaddr_t dst; + u_int16_t* font; + u_int32_t mask, valid, reg; + unsigned int i; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int16_t*)p->fontdata; + mask = ~0 << (16 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (ntohs(*font++) & mask) << (16 - valid); + valid += width; + if (valid >= 16) { + mga_writew(dst, i, htons(reg >> 16)); + i += 2; + reg = reg << 16; + valid -= 16; + } + } + if (valid) + mga_writew(dst, i, htons(reg >> 16)); + } + } else { + if (width == 32) + mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4); + else { + vaddr_t dst; + u_int32_t* font; + u_int32_t mask, valid, reg; + unsigned int i; + + dst = ACCESS_FBINFO(fastfont.vbase); + font = (u_int32_t*)p->fontdata; + mask = ~0 << (32 - width); + valid = 0; + reg = 0; + i = 0; + while (fsize--) { + reg |= (ntohl(*font) & mask) >> valid; + valid += width; + if (valid >= 32) { + mga_writel(dst, i, htonl(reg)); + i += 4; + valid -= 32; + if (valid) + reg = (ntohl(*font) & mask) << (width - valid); + else + reg = 0; + } + font++; + } + if (valid) + mga_writel(dst, i, htonl(reg)); + } + } + mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); + return 1; +} + +#define matrox_cfb16_revc matrox_cfbX_revc +#define matrox_cfb24_revc matrox_cfbX_revc +#define matrox_cfb32_revc matrox_cfbX_revc + +#define matrox_cfb24_clear matrox_cfb32_clear +#define matrox_cfb24_putc matrox_cfb32_putc +#define matrox_cfb24_putcs matrox_cfb32_putcs + +#ifdef FBCON_HAS_CFB4 +static struct display_switch matroxfb_cfb4 = { + fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear, + fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc, + NULL, NULL, NULL, + /* cursor... */ /* set_font... */ + FONTWIDTH(8) /* fix, fix, fix it */ +}; +#endif + +#ifdef FBCON_HAS_CFB8 +static struct display_switch matroxfb_cfb8 = { + fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear, + matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +#ifdef FBCON_HAS_CFB16 +static struct display_switch matroxfb_cfb16 = { + fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear, + matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +#ifdef FBCON_HAS_CFB24 +static struct display_switch matroxfb_cfb24 = { + fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear, + matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */ +}; +#endif + +#ifdef FBCON_HAS_CFB32 +static struct display_switch matroxfb_cfb32 = { + fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear, + matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc, + NULL, NULL, matrox_cfbX_clear_margins, + ~1 /* FONTWIDTHS */ +}; +#endif + +static struct pci_dev* pci_find(struct pci_dev* p) { + + DBG("pci_find") + + if (p) return p->next; + return pci_devices; +} + +static void initMatrox(WPMINFO struct display* p) { + struct display_switch *swtmp; + + DBG("initMatrox") + + p->dispsw_data = NULL; + if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) { + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: + swtmp = &fbcon_cfb4; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + swtmp = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); + swtmp = &fbcon_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); + swtmp = &fbcon_cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); + swtmp = &fbcon_cfb32; + break; +#endif + default: + p->dispsw = &fbcon_dummy; + return; + } + dprintk(KERN_INFO "matroxfb: acceleration disabled\n"); + p->dispsw = swtmp; + return; + } + switch (p->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: + swtmp = &matroxfb_cfb4; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + swtmp = &matroxfb_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); + swtmp = &matroxfb_cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); + swtmp = &matroxfb_cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); + swtmp = &matroxfb_cfb32; + break; +#endif + default: + p->dispsw = &fbcon_dummy; + return; + } + dprintk(KERN_INFO "matroxfb: now accelerated\n"); + memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw))); + p->dispsw = &ACCESS_FBINFO(dispsw); + if (ACCESS_FBINFO(devflags.hwcursor)) { + if (isMillenium(MINFO)) { +#ifdef CONFIG_FB_MATROX_MILLENIUM + ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor; + ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont; +#endif + } else { +#ifdef NEED_DAC1064 + ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; + ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; +#endif + } + } +} + +/* --------------------------------------------------------------------- */ + +/* + * card parameters + */ + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vesafb_defined __initdata = { + 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ + 0,0, /* virtual -> visible no offset */ + 8, /* depth -> load bits_per_pixel */ + 0, /* greyscale ? */ + {0,0,0}, /* R */ + {0,0,0}, /* G */ + {0,0,0}, /* B */ + {0,0,0}, /* transparency */ + 0, /* standard pixel format */ + FB_ACTIVATE_NOW, + -1,-1, + FB_ACCELF_TEXT, /* accel flags */ + 0L,0L,0L,0L,0L, + 0L,0L,0, /* No sync info */ + FB_VMODE_NONINTERLACED, + {0,0,0,0,0,0} +}; + + + +/* --------------------------------------------------------------------- */ + +static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { + struct matroxfb_par* p = &ACCESS_FBINFO(curr); + unsigned int pos; + unsigned short p0, p1, p2; + + DBG("matrox_pan_var") + + p->var.xoffset = var->xoffset; + p->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + p->var.vmode |= FB_VMODE_YWRAP; + else + p->var.vmode &= ~FB_VMODE_YWRAP; + + pos = (p->var.yoffset * p->var.xres_virtual + p->var.xoffset) * p->final_bppShift / 32; + if (mga_ydstorg(MINFO)) { + if (isInterleave(MINFO)) + pos += mga_ydstorg(MINFO) >> 3; + else + pos += mga_ydstorg(MINFO) >> 2; + } + + p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF; + p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8; + p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F); + mga_setr(M_CRTC_INDEX, 0x0D, p0); + mga_setr(M_CRTC_INDEX, 0x0C, p1); + mga_setr(M_EXTVGA_INDEX, 0x00, p2); +} + + /* + * Open/Release the frame buffer device + */ + +static int matroxfb_open(struct fb_info *info, int user) +{ + DBG_LOOP("matroxfb_open") + + /* + * Nothing, only a usage count for the moment + */ + MOD_INC_USE_COUNT; + return(0); +} + +static int matroxfb_release(struct fb_info *info, int user) +{ + DBG_LOOP("matroxfb_release") + + MOD_DEC_USE_COUNT; + return(0); +} + +static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info* info) { +#define minfo ((struct matrox_fb_info*)info) + + DBG("matroxfb_pan_display") + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || + var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + } + if (con == ACCESS_FBINFO(currcon)) + matrox_pan_var(PMINFO var); + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + fb_display[con].var.vmode |= FB_VMODE_YWRAP; + else + fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + return 0; +#undef minfo +} + +static int matroxfb_updatevar(int con, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + DBG("matroxfb_updatevar"); + + matrox_pan_var(PMINFO &fb_display[con].var); + return 0; +#undef minfo +} + +static int matroxfb_get_final_bppShift(CPMINFO int bpp) { + int bppshft2; + + DBG("matroxfb_get_final_bppShift") + + bppshft2 = bpp; + if (isInterleave(MINFO)) + bppshft2 >>= 1; + if (ACCESS_FBINFO(devflags.video64bits)) + bppshft2 >>= 1; + return bppshft2; +} + +static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { + int over; + int rounding; + + DBG("matroxfb_test_and_set_rounding") + + switch (bpp) { + case 4: rounding = 128; + break; + case 8: rounding = 64; + break; + case 16: rounding = 32; + break; + case 24: rounding = 64; + break; + default: rounding = 16; + break; + } + if (isInterleave(MINFO)) { + rounding *= 2; + } + over = xres % rounding; + if (over) + xres += rounding-over; + return xres; +} + +static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { + const int* width; + int xres_new; + + DBG("matroxfb_pitch_adjust") + + width = ACCESS_FBINFO(capable.vxres); + + if (ACCESS_FBINFO(devflags.precise_width)) { + while (*width) { + if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) { + break; + } + width++; + } + xres_new = *width; + } else { + xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); + } + if (!xres_new) return 0; + if (xres != xres_new) { + printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new); + } + return xres_new; +} + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static const unsigned char DACseq[] = +{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL, + TVP3026_XMUXCTRL, TVP3026_XCLKCTRL, + TVP3026_XPALETTEPAGE, + TVP3026_XGENCTRL, + TVP3026_XMISCCTRL, + TVP3026_XGENIOCTRL, + TVP3026_XGENIODATA, + TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX, + TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX, + TVP3026_XCOLKEYCTRL, + TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL }; + +#define POS3026_XLATCHCTRL 0 +#define POS3026_XTRUECOLORCTRL 1 +#define POS3026_XMUXCTRL 2 +#define POS3026_XCLKCTRL 3 +#define POS3026_XGENCTRL 5 +#define POS3026_XMISCCTRL 6 +#define POS3026_XMEMPLLCTRL 18 +#define POS3026_XCURCTRL 20 + +static const unsigned char MGADACbpp32[] = +{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888, + 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL, + 0x00, + TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS, + TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH, + 0x00, + 0x1E, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + TVP3026_XCOLKEYCTRL_ZOOM1, + 0x00, 0x00, TVP3026_XCURCTRL_DIS }; +#endif /* CONFIG_FB_MATROX_MILLENIUM */ + +static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int bestdiff = ~0; + unsigned int bestvco = 0; + unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq); + unsigned int fwant; + unsigned int p; + + DBG("PLL_calcclock") + + fwant = freq; + +#ifdef DEBUG + printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max)); + printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq)); + printk(KERN_ERR "freq: %d\n", freq); + printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min)); + printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min)); + printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max)); + printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min)); + printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max)); + printk(KERN_ERR "fmax: %d\n", fmax); +#endif + for (p = 1; p <= ACCESS_FBINFO(features.pll.post_shift_max); p++) { + if (fwant * 2 > fmax) + break; + fwant *= 2; + } + if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min); + if (fwant > fmax) fwant = fmax; + for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) { + unsigned int m; + + if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break; + for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) { + unsigned int diff, fvco; + unsigned int n; + + n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1; + if (n > ACCESS_FBINFO(features.pll.feed_div_max)) + break; + if (n < ACCESS_FBINFO(features.pll.feed_div_min)) + n = ACCESS_FBINFO(features.pll.feed_div_min); + fvco = (fxtal * (n + 1)) / (m + 1); + if (fvco < fwant) + diff = fwant - fvco; + else + diff = fvco - fwant; + if (diff < bestdiff) { + bestdiff = diff; + *post = p; + *in = m; + *feed = n; + bestvco = fvco; + } + } + } + dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant); + return bestvco; +} + +#ifdef NEED_DAC1064 +static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int fvco; + unsigned int p; + + DBG("DAC1064_calcclock") + + fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); + p = (1 << p) - 1; + if (fvco <= 100000) + ; + else if (fvco <= 140000) + p |= 0x08; + else if (fvco <= 180000) + p |= 0x10; + else + p |= 0x18; + *post = p; +} +#endif + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) { + unsigned int fvco; + unsigned int lin, lfeed, lpost; + + DBG("Ti3026_calcclock") + + fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); + fvco >>= (*post = lpost); + *in = 64 - lin; + *feed = 64 - lfeed; + return fvco; +} + +static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, int Bpp) { + unsigned int f_pll; + unsigned int pixfeed, pixin, pixpost; + unsigned int loopfeed, loopin, looppost, loopdiv, z; + + DBG("Ti3026_setpclk") + + f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); + + hw->DACclk[0] = pixin | 0xC0; + hw->DACclk[1] = pixfeed; + hw->DACclk[2] = pixpost | 0xB0; + if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) { + loopfeed = 3; /* set lm to any possible value */ + loopin = 3 * 32 / Bpp; + } else { + loopfeed = 4; + loopin = 4 * 32 / Bpp; + } + z = (110000 * loopin) / (f_pll * loopfeed); + loopdiv = 0; /* div 2 */ + if (z < 2) + looppost = 0; + else if (z < 4) + looppost = 1; + else if (z < 8) + looppost = 2; + else { + looppost = 3; + loopdiv = z/16; + } + if (ACCESS_FBINFO(curr.var.bits_per_pixel) == 24) { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = (65 - loopfeed) | 0x80; + if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) { + if (isInterleave(MINFO)) + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3; + else { + hw->DACclk[4] &= ~0xC0; + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3; + } + } else { + if (isInterleave(MINFO)) + ; /* default... */ + else { + hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */ + hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3; + } + } + hw->DACclk[5] = looppost | 0xF8; + if (ACCESS_FBINFO(devflags.mga_24bpp_fix)) + hw->DACclk[5] ^= 0x40; + } else { + hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; + hw->DACclk[4] = 65 - loopfeed; + hw->DACclk[5] = looppost | 0xF0; + } + hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL; + return 0; +} +#endif + +static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { + unsigned int pixclock = var->pixclock; + + DBG("var2my") + + if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ + mt->pixclock = 1000000000 / pixclock; + if (mt->pixclock < 1) mt->pixclock = 1; + mt->dblscan = var->vmode & FB_VMODE_DOUBLE; + mt->interlaced = var->vmode & FB_VMODE_INTERLACED; + mt->HDisplay = var->xres; + mt->HSyncStart = mt->HDisplay + var->right_margin; + mt->HSyncEnd = mt->HSyncStart + var->hsync_len; + mt->HTotal = mt->HSyncEnd + var->left_margin; + mt->VDisplay = var->yres; + mt->VSyncStart = mt->VDisplay + var->lower_margin; + mt->VSyncEnd = mt->VSyncStart + var->vsync_len; + mt->VTotal = mt->VSyncEnd + var->upper_margin; + mt->sync = var->sync; +} + +static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + unsigned int hd, hs, he, hbe, ht; + unsigned int vd, vs, ve, vt; + unsigned int wd; + unsigned int divider; + int i; + + DBG("vgaHWinit") + + hw->SEQ[0] = 0x00; + hw->SEQ[1] = 0x01; /* or 0x09 */ + hw->SEQ[2] = 0x0F; /* bitplanes */ + hw->SEQ[3] = 0x00; + hw->SEQ[4] = 0x0E; + /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */ + if (m->dblscan) { + m->VTotal <<= 1; + m->VDisplay <<= 1; + m->VSyncStart <<= 1; + m->VSyncEnd <<= 1; + } + if (m->interlaced) { + m->VTotal >>= 1; + m->VDisplay >>= 1; + m->VSyncStart >>= 1; + m->VSyncEnd >>= 1; + } + + /* GCTL is ignored when not using 0xA0000 aperture */ + hw->GCTL[0] = 0x00; + hw->GCTL[1] = 0x00; + hw->GCTL[2] = 0x00; + hw->GCTL[3] = 0x00; + hw->GCTL[4] = 0x00; + hw->GCTL[5] = 0x40; + hw->GCTL[6] = 0x05; + hw->GCTL[7] = 0x0F; + hw->GCTL[8] = 0xFF; + + /* Whole ATTR is ignored in PowerGraphics mode */ + for (i = 0; i < 16; i++) + hw->ATTR[i] = i; + hw->ATTR[16] = 0x41; + hw->ATTR[17] = 0xFF; + hw->ATTR[18] = 0x0F; + hw->ATTR[19] = 0x00; + hw->ATTR[20] = 0x00; + + hd = m->HDisplay >> 3; + hs = m->HSyncStart >> 3; + he = m->HSyncEnd >> 3; + ht = m->HTotal >> 3; + /* standard timmings are in 8pixels, but for interleaved we cannot */ + /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ + /* using 16 or more pixels per unit can save us */ + divider = ACCESS_FBINFO(curr.final_bppShift); + while (divider & 3) { + hd >>= 1; + hs >>= 1; + he >>= 1; + ht >>= 1; + divider <<= 1; + } + divider = divider / 4; + /* divider can be from 1 to 8 */ + while (divider > 8) { + hd <<= 1; + hs <<= 1; + he <<= 1; + ht <<= 1; + divider >>= 1; + } + hd = hd - 1; + hs = hs - 1; + he = he - 1; + ht = ht - 1; + vd = m->VDisplay - 1; + vs = m->VSyncStart - 1; + ve = m->VSyncEnd - 1; + vt = m->VTotal - 2; + if (((ht & 0x0F) == 0x0E) || ((ht & 0x0F) == 0x04)) + ht++; + hbe = ht; + wd = ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.final_bppShift) / 64; + + hw->CRTCEXT[0] = 0; + hw->CRTCEXT[5] = 0; + if (m->interlaced) { + hw->CRTCEXT[0] = 0x80; + hw->CRTCEXT[5] = (hs + he - ht) >> 1; + if (!m->dblscan) + wd <<= 1; + vt &= ~1; + } + hw->CRTCEXT[0] |= (wd & 0x300) >> 4; + hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) | + ((hd & 0x100) >> 7) | /* blanking */ + ((hs & 0x100) >> 6) | /* sync start */ + (hbe & 0x040); /* end hor. blanking */ + hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | + ((vd & 0x400) >> 8) | /* disp end */ + ((vd & 0xC00) >> 7) | /* vblanking start */ + ((vs & 0xC00) >> 5); + hw->CRTCEXT[3] = (divider - 1) | 0x80; + hw->CRTCEXT[4] = 0; + + hw->CRTC[0] = ht-4; + hw->CRTC[1] = hd; + hw->CRTC[2] = hd; + hw->CRTC[3] = (hbe & 0x1F) | 0x80; + hw->CRTC[4] = hs; + hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); + hw->CRTC[6] = vt & 0xFF; + hw->CRTC[7] = ((vt & 0x100) >> 8) | + ((vd & 0x100) >> 7) | + ((vs & 0x100) >> 6) | + ((vd & 0x100) >> 5) | + 0x10 | + ((vt & 0x200) >> 4) | + ((vd & 0x200) >> 3) | + ((vs & 0x200) >> 2); + hw->CRTC[8] = 0x00; + hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40; + if (m->dblscan && !m->interlaced) + hw->CRTC[9] |= 0x80; + for (i = 10; i < 16; i++) + hw->CRTC[i] = 0x00; + hw->CRTC[16] = vs /* & 0xFF */; + hw->CRTC[17] = (ve & 0x0F) | 0x20; + hw->CRTC[18] = vd /* & 0xFF */; + hw->CRTC[19] = wd /* & 0xFF */; + hw->CRTC[20] = 0x00; + hw->CRTC[21] = vd /* & 0xFF */; + hw->CRTC[22] = (vt + 1) /* & 0xFF */; + hw->CRTC[23] = 0xC3; + hw->CRTC[24] = 0xFF; + return 0; +}; + +#ifdef NEED_DAC1064 + +static const unsigned char MGA1064_DAC_regs[] = { + M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, + M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, + M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, + M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, + DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, + M1064_XMISCCTRL, + M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, + M1064_XCRCBITSEL, + M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH }; + +#define POS1064_XCURADDL 0 +#define POS1064_XCURADDH 1 +#define POS1064_XVREFCTRL 12 +#define POS1064_XMULCTRL 13 +#define POS1064_XGENCTRL 15 + +static const unsigned char MGA1064_DAC[] = { + 0x00, 0x00, M1064_XCURCTRL_DIS, + 0x00, 0x00, 0x00, /* black */ + 0xFF, 0xFF, 0xFF, /* white */ + 0xFF, 0x00, 0x00, /* red */ + 0x00, 0, + M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, + M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, + M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_VGA | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN, + 0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, + 0x00, + 0x00, 0x00, 0xFF, 0xFF}; + +static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) { + unsigned int m, n, p; + + DBG("DAC1064_setpclk") + + DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + hw->DACclk[0] = m; + hw->DACclk[1] = n; + hw->DACclk[2] = p; +} + +__initfunc(static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem)) { + u_int32_t mx; + + DBG("DAC1064_setmclk") + + mx = hw->MXoptionReg | 0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x000000BB; + if (oscinfo & DAC1064_OPT_GDIV1) + mx |= 0x00000008; + if (oscinfo & DAC1064_OPT_MDIV1) + mx |= 0x00000010; + if (oscinfo & DAC1064_OPT_RESERVED) + mx |= 0x00000080; + if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { + /* select PCI clock until we have setup oscilator... */ + int clk; + unsigned int m, n, p; + + /* powerup system PLL, select PCI clock */ + mx |= 0x00000020; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + + /* !!! you must not access device if MCLK is not running !!! + Doing so cause immediate PCI lockup :-( Maybe they should + generate ABORT or I/O (parity...) error and Linux should + recover from this... (kill driver/process). But world is not + perfect... */ + /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not + select PLL... because of PLL can be stopped at this time) */ + DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p); + for (clk = 65536; clk; --clk) { + if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40) + break; + } + if (!clk) + printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); + /* select PLL */ + mx |= 0x00000005; + } else { + /* select specified system clock source */ + mx |= oscinfo & DAC1064_OPT_SCLK_MASK; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + mx &= ~0x00000004; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); + hw->MXoptionReg = mx; +} + +static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + + DBG("DAC1064_init_1") + + memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); + switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) { + /* case 4: not supported by MGA1064 DAC */ + case 8: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 16: + if (ACCESS_FBINFO(curr.var.green.length) == 5) + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + else + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 24: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + case 32: + hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; + break; + default: + return 1; /* unsupported depth */ + } + hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); + hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; + hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; + hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; + hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; + return 0; +} + +static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + + DBG("DAC1064_init_2") + + DAC1064_setpclk(PMINFO hw, m->pixclock); + if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 16) { /* 256 entries */ + int i; + + for (i = 0; i < 256; i++) { + hw->DACpal[i * 3 + 0] = i; + hw->DACpal[i * 3 + 1] = i; + hw->DACpal[i * 3 + 2] = i; + } + } else if (ACCESS_FBINFO(curr.var.bits_per_pixel) > 8) { + if (ACCESS_FBINFO(curr.var.green.length) == 5) { /* 0..31, 128..159 */ + int i; + + for (i = 0; i < 32; i++) { + /* with p15 == 0 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 3; + hw->DACpal[i * 3 + 2] = i << 3; + /* with p15 == 1 */ + hw->DACpal[(i + 128) * 3 + 0] = i << 3; + hw->DACpal[(i + 128) * 3 + 1] = i << 3; + hw->DACpal[(i + 128) * 3 + 2] = i << 3; + } + } else { + int i; + + for (i = 0; i < 64; i++) { /* 0..63 */ + hw->DACpal[i * 3 + 0] = i << 3; + hw->DACpal[i * 3 + 1] = i << 2; + hw->DACpal[i * 3 + 2] = i << 3; + } + } + } else { + memset(hw->DACpal, 0, 768); + } + return 0; +} + +static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) { + + DBG("DAC1064_restore_1") + + outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); + outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); + outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); + if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) { + unsigned int i; + + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) + outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); + } +} + +static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) { + unsigned int i; + + DBG("DAC1064_restore_2") + + for (i = 0; i < 3; i++) + outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]); + while (!(inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)); + if (p && p->conp) { + matroxfb_DAC1064_createcursor(PMINFO p); + i = matroxfb_fastfont_tryset(PMINFO p); + } else + i = 0; + if (i) { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; + } else { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; + } +#ifdef DEBUG + dprintk(KERN_DEBUG "DAC1064regs "); + for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { + dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DAC1064clk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, hw->DACclk[i]); + dprintk("\n"); +#endif +} +#endif /* NEED_DAC1064 */ + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + + DBG("MGA1064_init") + + if (DAC1064_init_1(PMINFO hw, m)) return 1; + if (vgaHWinit(PMINFO hw, m)) return 1; + + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO hw, m)) return 1; + return 0; +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + + DBG("MGAG100_init") + + if (DAC1064_init_1(PMINFO hw, m)) return 1; + hw->MXoptionReg &= ~0x2000; + if (vgaHWinit(PMINFO hw, m)) return 1; + + hw->MiscOutReg = 0xEF; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->MiscOutReg &= ~0x40; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->MiscOutReg &= ~0x80; + if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */ + hw->CRTCEXT[3] |= 0x40; + + if (DAC1064_init_2(PMINFO hw, m)) return 1; + return 0; +} +#endif /* G100 */ + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m) { + u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; + + DBG("Ti3026_init") + + memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); + switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) { + case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; + break; + case 16: + /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(curr.var.green.length) == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; + break; + case 24: + /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */ + hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888; + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; + break; + case 32: + /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */ + hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; + break; + default: + return 1; /* TODO: failed */ + } + if (vgaHWinit(PMINFO hw, m)) return 1; + + /* set SYNC */ + hw->MiscOutReg = 0xCB; + if (m->sync & FB_SYNC_HOR_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG; + if (m->sync & FB_SYNC_VERT_HIGH_ACT) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG; + if (m->sync & FB_SYNC_ON_GREEN) + hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN; + + /* set DELAY */ + if (ACCESS_FBINFO(video.len) < 0x400000) + hw->CRTCEXT[3] |= 0x08; + else if (ACCESS_FBINFO(video.len) > 0x400000) + hw->CRTCEXT[3] |= 0x10; + + /* set HWCURSOR */ + if (m->interlaced) { + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED; + } + if (m->HTotal >= 1536) + hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096; + + /* set interleaving */ + hw->MXoptionReg &= ~0x00001000; + if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; + + /* set DAC */ + Ti3026_setpclk(PMINFO hw, m->pixclock, ACCESS_FBINFO(curr.final_bppShift)); + return 0; +} +#endif /* CONFIG_FB_MATROX_MILLENIUM */ + +static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { + + DBG("matroxfb_get_cmap_len") + + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: + return 16; /* pseudocolor... 16 entries HW palette */ +#endif +#ifdef FBCON_HAS_CFB8 + case 8: + return 256; /* pseudocolor... 256 entries HW palette */ +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + return 16; /* directcolor... 16 entries SW palette */ + /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif + } + return 16; /* return something reasonable... or panic()? */ +} + +static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len) { + unsigned int vramlen; + unsigned int memlen; + + DBG("matroxfb_decode_var") + + if ((var->xres > var->xres_virtual) || (var->yres > var->yres_virtual) || + (var->xoffset > var->xres_virtual) || (var->yoffset > var->yres_virtual)) + return -EINVAL; + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 + case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; + break; +#endif +#ifdef FBCON_HAS_CFB8 + case 8: break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: break; +#endif + default: return -EINVAL; + } + vramlen = ACCESS_FBINFO(video.len_usable); + var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel); + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; + if (memlen > vramlen) + return -EINVAL; /* out of memory */ + /* There is hardware bug that no line can cross 4MB boundary */ + /* give up for CFB24, it is impossible to easy workaround it */ + /* for other try to do something */ + if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000) && (var->bits_per_pixel != 24)) { + int new_xres = var->xres_virtual; + + if (new_xres <= 512) + new_xres = 512; + else if (new_xres <= 1024) + new_xres = 1024; + else if (new_xres <= 2048) + new_xres = 2048; + else + new_xres = var->xres_virtual; + memlen = new_xres * var->bits_per_pixel / 8; + /* if now out of memory, try shrink virtual height */ + /* but if new virtual height is smaller than visible height, return -EINVAL */ + if (var->yres_virtual * memlen > vramlen) { + unsigned int new_yres; + + new_yres = vramlen / memlen; + if (new_yres < var->yres) + return -EINVAL; + var->yres_virtual = new_yres; + } + var->xres_virtual = new_xres; + } + + if (var->bits_per_pixel == 4) { + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + *visual = MX_VISUAL_PSEUDOCOLOR; + } else if (var->bits_per_pixel <= 8) { + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + *visual = MX_VISUAL_PSEUDOCOLOR; + } else { + if (var->bits_per_pixel <= 16) { + if (var->green.length == 5) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + } else if (var->bits_per_pixel <= 24) { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + } else { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } + dprintk("matroxfb: truecolor: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + var->transp.length, + var->red.length, + var->green.length, + var->blue.length, + var->transp.offset, + var->red.offset, + var->green.offset, + var->blue.offset); + *visual = MX_VISUAL_DIRECTCOLOR; + } + *video_cmap_len = matroxfb_get_cmap_len(var); + dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, + var->xres_virtual, var->yres_virtual); + return 0; +} + +#ifdef CONFIG_FB_MATROX_MILLENIUM +__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) { + unsigned int f_pll; + unsigned int pclk_m, pclk_n, pclk_p; + unsigned int mclk_m, mclk_n, mclk_p; + unsigned int rfhcnt, mclk_ctl; + int tmout; + + DBG("ti3026_setMCLK") + + f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); + + /* save pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD); + pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA); + + /* stop pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* set pclk to new mclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + }; + if (!tmout) + printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n"); + + /* output pclk on mclk pin */ + mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop MCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00); + + /* set mclk to new freq */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m); + outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n"); + + f_pll = f_pll * 333 / (10000 << mclk_p); + if (isMilleniumII(MINFO)) { + rfhcnt = (f_pll - 128) / 256; + if (rfhcnt > 15) + rfhcnt = 15; + } else { + rfhcnt = (f_pll - 64) / 128; + if (rfhcnt > 15) + rfhcnt = 0; + } + hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + /* output MCLK to MCLK pin */ + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4); + + /* stop PCLK */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + /* restore pclk */ + outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p); + + /* wait for PLL to lock */ + for (tmout = 500000; tmout; tmout--) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); +} + +__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) { + + DBG("ti3026_ramdac_init") + + ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; + ACCESS_FBINFO(features.pll.ref_freq) = 114545; + ACCESS_FBINFO(features.pll.feed_div_min) = 2; + ACCESS_FBINFO(features.pll.feed_div_max) = 24; + ACCESS_FBINFO(features.pll.in_div_min) = 2; + ACCESS_FBINFO(features.pll.in_div_max) = 63; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ti3026_setMCLK(PMINFO hw, 60000); +} +#endif + +__initfunc(static void matroxfb_fastfont_init(struct matrox_fb_info* minfo)) { + unsigned int size; + + size = ACCESS_FBINFO(fastfont.size); + ACCESS_FBINFO(fastfont.size) = 0; + if (size) { + unsigned int end = ACCESS_FBINFO(video.len_usable); + + if (size < end) { + unsigned int start; + + start = (end - size) & PAGE_MASK; + if (start >= 0x00100000) { + ACCESS_FBINFO(video.len_usable) = start; + ACCESS_FBINFO(fastfont.mgabase) = start * 8; + ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase); + vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start); + ACCESS_FBINFO(fastfont.size) = end - start; + } + } + } +} + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) { + + DBG("MGA1064_ramdac_init"); + + /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ + ACCESS_FBINFO(features.pll.vco_freq_min) = 50000; + ACCESS_FBINFO(features.pll.ref_freq) = 14318; + ACCESS_FBINFO(features.pll.feed_div_min) = 100; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL; + /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ + DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); +} + +__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) { + static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + DBG("MGA1064_preinit") + + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.vxres) = vxres_mystique; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; + + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00094E20; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_setr(M_SEQ_INDEX, 0x01, 0x20); + mga_outl(M_CTLWTST, 0x00000000); + udelay(200); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outl(M_MACCESS, 0x0000C000); + return 0; +} + +__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) { + + DBG("MGA1064_reset"); + + ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; + if (ACCESS_FBINFO(devflags.hwcursor)) + ACCESS_FBINFO(video.len_usable) -= 1024; + matroxfb_fastfont_init(MINFO); + MGA1064_ramdac_init(PMINFO hw); +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +/* BIOS environ */ +static int x7AF4 = 0; /* flags */ +#if 0 +static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */ +#endif + +__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) { + int reg; + int selClk; + int clk; + + DBG("MGAG100_progPixClock") + + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS); + switch (flags & 3) { + case 0: reg = M1064_XPIXPLLAM; break; + case 1: reg = M1064_XPIXPLLBM; break; + default: reg = M1064_XPIXPLLCM; break; + } + outDAC1064(PMINFO reg++, m); + outDAC1064(PMINFO reg++, n); + outDAC1064(PMINFO reg, p); + selClk = mga_inb(M_MISC_REG_READ) & ~0xC; + /* there should be flags & 0x03 & case 0/1/else */ + /* and we should first select source and after that we should wait for PLL */ + /* and we are waiting for PLL with oscilator disabled... Is it right? */ + switch (flags & 0x03) { + case 0x00: break; + case 0x01: selClk |= 4; break; + default: selClk |= 0x0C; break; + } + mga_outb(M_MISC_REG, selClk); + for (clk = 65536; clk; clk--) + if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) + break; + if (!clk) + printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A'); + selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK; + switch (flags & 0x0C) { + case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break; + case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break; + default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break; + } + outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk); + outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS); +} + +__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) { + unsigned int m, n, p; + + DBG("MGAG100_setPixClock") + + DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); + MGAG100_progPixClock(PMINFO flags, m, n, p); +} + +__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) { + static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; +#if 0 + u_int32_t reg50; + u_int32_t q; +#endif + + DBG("MGAG100_preinit") + + /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ + ACCESS_FBINFO(capable.vxres) = vxres_g100; + ACCESS_FBINFO(features.accel.has_cacheflush) = 1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; + + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x00078C20; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + mga_outl(M_CTLWTST, 0x03258A31); /* 03258A31 is x7AF0, default is 0x02032521 */ +#if 0 + hw->MXoptionReg |= 0x1000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + q = def50 & 0x3000; + reg50 = (reg50 & ~0x3000) | q; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + mga_outb(0x1C05, 0x00); + mga_outb(0x1C05, 0x80); + udelay(100); + mga_outb(0x1C05, 0x40); + mga_outb(0x1C05, 0xC0); + pci_write_config_byte(ACCESS_FBINFO(pcidev), 0x50, def50 & 0x0F); + { + mga_outb(M_GRAPHICS_INDEX, 6); + mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4); + mga_setr(M_EXTVGA_INDEX, 0x03, 0x81); + mga_setr(M_EXTVGA_INDEX, 0x04, 0x00); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x000, 0xAA); + mga_writeb(ACCESS_FBINFO(video.vbase), 0x800, 0x55); + if (mga_readb(ACCESS_FBINFO(video.vbase), 0x000) != 0xAA) { + hw->MXoptionReg &= ~0x1000; + } + } +#endif + hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000; + if (!(x7AF4 & 0x10)) + hw->MXoptionReg |= 0x4000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + return 0; +} + +__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) { + u_int8_t b; + + DBG("MGAG100_reset") + + ACCESS_FBINFO(features.pll.vco_freq_min) = 50000; + ACCESS_FBINFO(features.pll.ref_freq) = 27000; + ACCESS_FBINFO(features.pll.feed_div_min) = 7; + ACCESS_FBINFO(features.pll.feed_div_max) = 127; + ACCESS_FBINFO(features.pll.in_div_min) = 1; + ACCESS_FBINFO(features.pll.in_div_max) = 31; + ACCESS_FBINFO(features.pll.post_shift_max) = 3; + ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT; + ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; + if (ACCESS_FBINFO(devflags.hwcursor)) + ACCESS_FBINFO(video.len_usable) -= 1024; + matroxfb_fastfont_init(MINFO); + + { +#ifdef G100_BROKEN_IBM_82351 + u_int32_t d; + + find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */ + pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b); + if (b == ACCESS_FBINFO(pcidev)->bus->number) { + pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */ + pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */ + pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */ + } +#endif + if (x7AF4 & 8) { + hw->MXoptionReg |= 0x40; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + } + mga_setr(M_EXTVGA_INDEX, 0x06, 0x50); + } + DAC1064_setmclk(PMINFO hw, DAC1064_OPT_SCLK_PLL, 120000); + MGAG100_setPixClock(PMINFO 4, 25175); + MGAG100_setPixClock(PMINFO 5, 28322); + if (x7AF4 & 0x10) { + b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1; + outDAC1064(PMINFO M1064_XGENIODATA, b); + b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1; + outDAC1064(PMINFO M1064_XGENIOCTRL, b); + } +} +#endif + +static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) { + int i; + + DBG("vgaHWrestore") + + dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); + dprintk(KERN_INFO "SEQ regs: "); + for (i = 0; i < 5; i++) + dprintk("%02X:", hw->SEQ[i]); + dprintk("\n"); + dprintk(KERN_INFO "GDC regs: "); + for (i = 0; i < 9; i++) + dprintk("%02X:", hw->GCTL[i]); + dprintk("\n"); + dprintk(KERN_INFO "CRTC regs: "); + for (i = 0; i < 25; i++) + dprintk("%02X:", hw->CRTC[i]); + dprintk("\n"); + dprintk(KERN_INFO "ATTR regs: "); + for (i = 0; i < 21; i++) + dprintk("%02X:", hw->ATTR[i]); + dprintk("\n"); + + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0); + mga_outb(M_MISC_REG, hw->MiscOutReg); + for (i = 1; i < 5; i++) + mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]); + mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F); + for (i = 0; i < 25; i++) + mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]); + for (i = 0; i < 9; i++) + mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]); + for (i = 0; i < 21; i++) { + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, i); + mga_outb(M_ATTR_INDEX, hw->ATTR[i]); + } + mga_outb(M_PALETTE_MASK, 0xFF); + mga_outb(M_DAC_REG, 0x00); + for (i = 0; i < 768; i++) + mga_outb(M_DAC_VAL, hw->DACpal[i]); + mga_inb(M_ATTR_RESET); + mga_outb(M_ATTR_INDEX, 0x20); +} + +static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) +{ +#ifdef CONFIG_FB_MATROX_MULTIHEAD + struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info; +#endif + + DBG("matrox_setcolreg") + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= ACCESS_FBINFO(curr.cmap_len)) + return 1; + + ACCESS_FBINFO(palette[regno].red) = red; + ACCESS_FBINFO(palette[regno].green) = green; + ACCESS_FBINFO(palette[regno].blue) = blue; + ACCESS_FBINFO(palette[regno].transp) = transp; + + if (ACCESS_FBINFO(curr.var.grayscale)) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + red = CNVT_TOHW(red, ACCESS_FBINFO(curr.var.red.length)); + green = CNVT_TOHW(green, ACCESS_FBINFO(curr.var.green.length)); + blue = CNVT_TOHW(blue, ACCESS_FBINFO(curr.var.blue.length)); + transp = CNVT_TOHW(transp, ACCESS_FBINFO(curr.var.transp.length)); + + switch (ACCESS_FBINFO(curr.var.bits_per_pixel)) { +#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) +#ifdef FBCON_HAS_CFB4 + case 4: +#endif +#ifdef FBCON_HAS_CFB8 + case 8: +#endif + mga_outb(M_DAC_REG, regno); + mga_outb(M_DAC_VAL, red); + mga_outb(M_DAC_VAL, green); + mga_outb(M_DAC_VAL, blue); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + ACCESS_FBINFO(cmap.cfb16[regno]) = + (red << ACCESS_FBINFO(curr.var.red.offset)) | + (green << ACCESS_FBINFO(curr.var.green.offset)) | + (blue << ACCESS_FBINFO(curr.var.blue.offset)) | + (transp << ACCESS_FBINFO(curr.var.transp.offset)); /* for 1:5:5:5 */ + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + ACCESS_FBINFO(cmap.cfb24[regno]) = + (red << ACCESS_FBINFO(curr.var.red.offset)) | + (green << ACCESS_FBINFO(curr.var.green.offset)) | + (blue << ACCESS_FBINFO(curr.var.blue.offset)); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + ACCESS_FBINFO(cmap.cfb32[regno]) = + (red << ACCESS_FBINFO(curr.var.red.offset)) | + (green << ACCESS_FBINFO(curr.var.green.offset)) | + (blue << ACCESS_FBINFO(curr.var.blue.offset)) | + (transp << ACCESS_FBINFO(curr.var.transp.offset)); /* 8:8:8:8 */ + break; +#endif + } + return 0; +} + +static void do_install_cmap(WPMINFO int con) +{ + struct display* dsp; + + DBG("do_install_cmap") + + if (con != ACCESS_FBINFO(currcon)) + return; + if (con >= 0) + dsp = fb_display+con; + else + dsp = ACCESS_FBINFO(fbcon.disp); + if (dsp->cmap.len) + fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); + else + fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)), + 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); +} + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + + DBG("MGA1064_restore") + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + mga_outb(M_IEN, 0x00); + mga_outb(M_CACHEFLUSH, 0x00); + DAC1064_restore_1(PMINFO hw, oldhw); + vgaHWrestore(PMINFO hw, oldhw); + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO hw, oldhw, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + + DBG("MGAG100_restore") + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + DAC1064_restore_1(PMINFO hw, oldhw); + vgaHWrestore(PMINFO hw, oldhw); + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + DAC1064_restore_2(PMINFO hw, oldhw, p); +} +#endif + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) { + int i; + + DBG("Ti3026_restore") + + dprintk(KERN_INFO "EXTVGA regs: "); + for (i = 0; i < 6; i++) + dprintk("%02X:", hw->CRTCEXT[i]); + dprintk("\n"); + + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + vgaHWrestore(PMINFO hw, oldhw); + for (i = 0; i < 6; i++) + mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); + + for (i = 0; i < 21; i++) { + outTi3026(PMINFO DACseq[i], hw->DACreg[i]); + } + if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) { + /* agrhh... setting up PLL is very slow on Millenium... */ + /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */ + /* Maybe even we should call schedule() ? */ + + outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 0; i < 3; i++) + outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]); + /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */ + if (hw->MiscOutReg & 0x08) { + int tmout; + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout); + } + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]); + outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); + for (i = 3; i < 6; i++) + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]); + if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[3] & 0xC0) == 0xC0)) { + int tmout; + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); + for (tmout = 500000; tmout; --tmout) { + if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) + break; + udelay(10); + } + if (!tmout) + printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n"); + else + dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout); + } + } + if (p && p->conp) { + matroxfb_ti3026_createcursor(PMINFO p); + i = matroxfb_fastfont_tryset(PMINFO p); + } else + i = 0; + if (i) { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; + } else { + ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; + ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; + } + + dprintk(KERN_DEBUG "3026DACregs "); + for (i = 0; i < 21; i++) { + dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]); + if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); + } + dprintk("\n" KERN_DEBUG "DACclk "); + for (i = 0; i < 6; i++) + dprintk("C%02X=%02X ", i, hw->DACclk[i]); + dprintk("\n"); +} +#endif + +static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + + DBG("matroxfb_get_fix") + +#define minfo ((struct matrox_fb_info*)info) + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id,"MATROX"); + + fix->smem_start = (void*)ACCESS_FBINFO(video.base); + fix->smem_len = ACCESS_FBINFO(video.len); + fix->type = ACCESS_FBINFO(curr.video_type); + fix->visual = ACCESS_FBINFO(curr.visual); + fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = (ACCESS_FBINFO(curr.var.xres_virtual) * ACCESS_FBINFO(curr.var.bits_per_pixel)) >> 3; + fix->mmio_start = (void*)ACCESS_FBINFO(mmio.base); + fix->mmio_len = ACCESS_FBINFO(mmio.len); + fix->accel = ACCESS_FBINFO(devflags.accelerator); + return 0; +#undef minfo +} + +static int matroxfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + + DBG("matroxfb_get_var") + + if(con < 0) + *var=ACCESS_FBINFO2(info, curr.var); + else + *var=fb_display[con].var; + return 0; +} + +static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + int err; + int visual; + int cmap_len; + struct display* display; + int chgvar; + + DBG("matroxfb_set_var") + + if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len)) != 0) + return err; + switch (var->activate & FB_ACTIVATE_MASK) { + case FB_ACTIVATE_TEST: return 0; + case FB_ACTIVATE_NXTOPEN: /* ?? */ + case FB_ACTIVATE_NOW: break; /* continue */ + default: return -EINVAL; /* unknown */ + } + if (con >= 0) { + display = fb_display+con; + chgvar = ((display->var.xres != var->xres) || + (display->var.yres != var->yres) || + (display->var.xres_virtual != var->xres_virtual) || + (display->var.yres_virtual != var->yres_virtual) || + (display->var.bits_per_pixel != var->bits_per_pixel) || + memcmp(&display->var.red, &var->red, sizeof(var->red)) || + memcmp(&display->var.green, &var->green, sizeof(var->green)) || + memcmp(&display->var.blue, &var->blue, sizeof(var->blue))); + } else { + display = ACCESS_FBINFO(fbcon.disp); + chgvar = 0; + } + display->var = *var; + /* cmap */ + display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)); + display->visual = visual; + display->type = FB_TYPE_PACKED_PIXELS; + display->type_aux = 0; + display->ypanstep = 1; + display->ywrapstep = 0; + display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + display->can_soft_blank = 1; + display->inverse = ACCESS_FBINFO(devflags.inverse); + /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */ + /* next_plane, fontdata, _font*, userfont */ + initMatrox(PMINFO display); /* dispsw */ + /* dispsw, scrollmode, yscroll */ + /* fgshift, bgshift, charmask */ + if (chgvar && info && info->changevar) + info->changevar(con); + if (con == ACCESS_FBINFO(currcon)) { + unsigned int pos; + + ACCESS_FBINFO(curr.var) = *var; + ACCESS_FBINFO(curr.visual) = visual; + ACCESS_FBINFO(curr.cmap_len) = cmap_len; + ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); + if (visual == MX_VISUAL_PSEUDOCOLOR) { + int i; + + for (i = 0; i < 16; i++) { + int j; + + j = color_table[i]; + ACCESS_FBINFO(palette[i].red) = default_red[j]; + ACCESS_FBINFO(palette[i].green) = default_grn[j]; + ACCESS_FBINFO(palette[i].blue) = default_blu[j]; + } + } + + { struct my_timming mt; + struct matrox_hw_state* hw; + struct matrox_hw_state* ohw; + + var2my(var, &mt); + hw = ACCESS_FBINFO(newhw); + ohw = ACCESS_FBINFO(currenthw); + + /* MXoptionReg is not set from scratch */ + hw->MXoptionReg = ohw->MXoptionReg; + /* DACclk[3]..[5] are not initialized with DAC1064 */ + memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk)); + /* others are initialized by init() */ + + del_timer(&ACCESS_FBINFO(cursor.timer)); + ACCESS_FBINFO(cursor.state) = CM_ERASE; + + ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt)); + pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + if (mga_ydstorg(MINFO)) { + if (isInterleave(MINFO)) + pos += mga_ydstorg(MINFO) >> 3; + else + pos += mga_ydstorg(MINFO) >> 2; + } + + hw->CRTC[0x0D] = pos & 0xFF; + hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; + hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F); + ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display)); + ACCESS_FBINFO(currenthw) = hw; + ACCESS_FBINFO(newhw) = ohw; + matrox_cfbX_init(MINFO); + do_install_cmap(PMINFO con); +#if defined(CONFIG_FB_COMPAT_XPMAC) + if (console_fb_info == &ACCESS_FBINFO(fbcon)) { + int vmode, cmode; + + display_info.width = var->xres; + display_info.height = var->yres; + display_info.depth = var->bits_per_pixel; + display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8; + if (mac_var_to_vmode(var, &vmode, &cmode) + display_info.mode = 0; + else + display_info.mode = vmode; + strcpy(display_info.name, ACCESS_FBINFO(matrox_name)); + display_info.fb_address = ACCESS_FBINFO(video.base); + /* we should not expose this addresses outside of driver. Every access to DAC must be + exclusive locked by spinlock_irq(ACCESS_FBINFO(lock.DAC)) or by turning hardware cursor (flashing) OFF */ + display_info.cmap_adr_address = ACCESS_FBINFO(mmio.base) + M_DAC_REG; + display_info.cmap_data_address = ACCESS_FBINFO(mmio.base) + M_DAC_VAL; + display_info.disp_reg_address = ACCESS_FBINFO(mmio.base); + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ + } + } + return 0; +#undef minfo +} + +static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info) +{ + + DBG("matrox_getcolreg") + +#define minfo ((struct matrox_fb_info*)info) + /* + * Read a single color register and split it into colors/transparent. + * Return != 0 for invalid regno. + */ + + if (regno >= ACCESS_FBINFO(curr.cmap_len)) + return 1; + + *red = ACCESS_FBINFO(palette[regno].red); + *green = ACCESS_FBINFO(palette[regno].green); + *blue = ACCESS_FBINFO(palette[regno].blue); + *transp = ACCESS_FBINFO(palette[regno].transp); + return 0; +#undef minfo +} + +static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct display* dsp = (con < 0) ? info->disp : fb_display+con; + + DBG("matroxfb_get_cmap") + + if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */ + return fb_get_cmap(cmap, kspc, matrox_getcolreg, info); + else if (dsp->cmap.len) /* non default colormap? */ + fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)), + cmap, kspc ? 0 : 2); + return 0; +} + +static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + unsigned int cmap_len; + struct display* dsp = (con < 0) ? info->disp : (fb_display + con); + + DBG("matroxfb_set_cmap") + + cmap_len = matroxfb_get_cmap_len(&dsp->var); + if (dsp->cmap.len != cmap_len) { + int err; + + err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0); + if (err) + return err; + } + if (con == ACCESS_FBINFO2(info, currcon)) /* current console? */ + return fb_set_cmap(cmap, kspc, matrox_setcolreg, info); + else + fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); + return 0; +} + +static int matroxfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + + DBG("matroxfb_ioctl") + + return -EINVAL; +} + +static struct fb_ops matroxfb_ops = { + matroxfb_open, + matroxfb_release, + matroxfb_get_fix, + matroxfb_get_var, + matroxfb_set_var, + matroxfb_get_cmap, + matroxfb_set_cmap, + matroxfb_pan_display, + matroxfb_ioctl, + NULL /* mmap */ +}; + +static int matroxfb_switch(int con, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + struct fb_cmap* cmap; + + DBG("matroxfb_switch"); + + if (ACCESS_FBINFO(currcon) >= 0) { + /* Do we have to save the colormap? */ + cmap = &fb_display[ACCESS_FBINFO2(info, currcon)].cmap; + dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO2(info, currcon), cmap->len); + + if (cmap->len) { + dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + fb_get_cmap(cmap, 1, matrox_getcolreg, info); +#ifdef DEBUG + if (cmap->red) { + dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]); + } +#endif + } + } + ACCESS_FBINFO(currcon) = con; + ACCESS_FBINFO(currcon_display) = fb_display+con; + fb_display[con].var.activate = FB_ACTIVATE_NOW; +#ifdef DEBUG + cmap = &fb_display[con].cmap; + dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len); + dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + if (fb_display[con].cmap.red) { + dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]); + } +#endif + matroxfb_set_var(&fb_display[con].var, con, info); +#ifdef DEBUG + dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len); + dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); + if (fb_display[con].cmap.red) { + dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]); + } +#endif + return 0; +#undef minfo +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static void matroxfb_blank(int blank, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + int seq; + int crtc; + + DBG("matroxfb_blank") + + switch (blank) { + case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */ + case 2: seq = 0x20; crtc = 0x10; break; + case 3: seq = 0x20; crtc = 0x20; break; + case 4: seq = 0x20; crtc = 0x30; break; + default: seq = 0x00; crtc = 0x00; break; + } + mga_outb(M_SEQ_INDEX, 1); + mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); + mga_outb(M_EXTVGA_INDEX, 1); + mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); +#undef minfo +} + +#define RSResolution(X) ((X) & 0x0F) +#define RS640x400 1 +#define RS640x480 2 +#define RS800x600 3 +#define RS1024x768 4 +#define RS1280x1024 5 +#define RS1600x1200 6 +#define RS768x576 7 +#define RS960x720 8 +#define RS1152x864 9 +#define RS1408x1056 10 +/* B-F */ +static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { + { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, + { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, + { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, + { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, + { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, + { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, + { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, + { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, + { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, + { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 } +}; + +#define RSDepth(X) (((X) >> 4) & 0x0F) +#define RS8bpp 0x1 +#define RS15bpp 0x2 +#define RS16bpp 0x3 +#define RS32bpp 0x4 +#define RS4bpp 0x5 +#define RS24bpp 0x6 +/* 7-F */ +static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = { + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, + { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, + { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, + { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, + { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 } +}; + +#define RSCreate(X,Y) ((X) | ((Y) << 4)) +static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { +/* default must be first */ +#ifdef FBCON_HAS_CFB8 + { 0x101, RSCreate(RS640x480, RS8bpp ) }, + { 0x100, RSCreate(RS640x400, RS8bpp ) }, + { 0x180, RSCreate(RS768x576, RS8bpp ) }, + { 0x103, RSCreate(RS800x600, RS8bpp ) }, + { 0x188, RSCreate(RS960x720, RS8bpp ) }, + { 0x105, RSCreate(RS1024x768, RS8bpp ) }, + { 0x190, RSCreate(RS1152x864, RS8bpp ) }, + { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, + { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, + { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, +#endif +#ifdef FBCON_HAS_CFB4 + { 0x102, RSCreate(RS800x600, RS4bpp ) }, + { 0x104, RSCreate(RS1024x768, RS4bpp ) }, +#endif +#ifdef FBCON_HAS_CFB16 + { 0x110, RSCreate(RS640x480, RS15bpp) }, + { 0x181, RSCreate(RS768x576, RS15bpp) }, + { 0x113, RSCreate(RS800x600, RS15bpp) }, + { 0x189, RSCreate(RS960x720, RS15bpp) }, + { 0x116, RSCreate(RS1024x768, RS15bpp) }, + { 0x191, RSCreate(RS1152x864, RS15bpp) }, + { 0x119, RSCreate(RS1280x1024, RS15bpp) }, + { 0x199, RSCreate(RS1408x1056, RS15bpp) }, + { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, + { 0x111, RSCreate(RS640x480, RS16bpp) }, + { 0x182, RSCreate(RS768x576, RS16bpp) }, + { 0x114, RSCreate(RS800x600, RS16bpp) }, + { 0x18A, RSCreate(RS960x720, RS16bpp) }, + { 0x117, RSCreate(RS1024x768, RS16bpp) }, + { 0x192, RSCreate(RS1152x864, RS16bpp) }, + { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, + { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, + { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, +#endif +#ifdef FBCON_HAS_CFB24 + { 0x1B2, RSCreate(RS640x480, RS24bpp) }, + { 0x184, RSCreate(RS768x576, RS24bpp) }, + { 0x1B5, RSCreate(RS800x600, RS24bpp) }, + { 0x18C, RSCreate(RS960x720, RS24bpp) }, + { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, + { 0x194, RSCreate(RS1152x864, RS24bpp) }, + { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, + { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, + { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, +#endif +#ifdef FBCON_HAS_CFB32 + { 0x112, RSCreate(RS640x480, RS32bpp) }, + { 0x183, RSCreate(RS768x576, RS32bpp) }, + { 0x115, RSCreate(RS800x600, RS32bpp) }, + { 0x18B, RSCreate(RS960x720, RS32bpp) }, + { 0x118, RSCreate(RS1024x768, RS32bpp) }, + { 0x193, RSCreate(RS1152x864, RS32bpp) }, + { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, + { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, +#endif + { 0, 0 }}; + +/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ +static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */ +static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ +static int inv24 = 0; /* "matrox:inv24" */ +static int cross4MB = -1; /* "matrox:cross4MB" */ +static int disabled = 0; /* "matrox:disabled" */ +static int noaccel = 0; /* "matrox:noaccel" */ +static int nopan = 0; /* "matrox:nopan" */ +static int no_pci_retry = 0; /* "matrox:nopciretry" */ +static int novga = 0; /* "matrox:novga" */ +static int nobios = 0; /* "matrox:nobios" */ +static int inverse = 0; /* "matrox:inverse" */ +static int hwcursor = 1; /* "matrox:nohwcursor" */ +static int blink = 1; /* "matrox:noblink" */ +static int grayscale = 0; /* "matrox:grayscale" */ +static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */ +static int dev = -1; /* "matrox:dev:xxxxx" */ +static unsigned int vesa = 0x101; /* "matrox:vesa:xxxxx" */ +static unsigned int depth = 0; /* "matrox:depth:xxxxx" */ +static unsigned int xres = 0; /* "matrox:xres:xxxxx" */ +static unsigned int yres = 0; /* "matrox:yres:xxxxx" */ +static unsigned int upper = 0; /* "matrox:upper:xxxxx" */ +static unsigned int lower = 0; /* "matrox:lower:xxxxx" */ +static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */ +static unsigned int left = 0; /* "matrox:left:xxxxx" */ +static unsigned int right = 0; /* "matrox:right:xxxxx" */ +static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */ +static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */ +static int sync = -1; /* "matrox:sync:xxxxx" */ +static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ +static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ +static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ +static char fontname[64]; /* "matrox:font:xxxxx" */ + +#ifndef MODULE +__initfunc(void matroxfb_setup(char *options, int *ints)) { + char *this_opt; + + DBG("matroxfb_setup") + + fontname[0] = '\0'; + + if (!options || !*options) + return; + + for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + if (!*this_opt) continue; + + dprintk("matroxfb_setup: option %s\n", this_opt); + + if (!strncmp(this_opt, "dev:", 4)) + dev = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "depth:", 6)) { + switch (simple_strtoul(this_opt+6, NULL, 0)) { + case 4: depth = RS4bpp; break; + case 8: depth = RS8bpp; break; + case 15:depth = RS15bpp; break; + case 16:depth = RS16bpp; break; + case 24:depth = RS24bpp; break; + case 32:depth = RS32bpp; break; + default: + printk(KERN_ERR "matroxfb: unsupported color depth\n"); + } + } else if (!strncmp(this_opt, "xres:", 5)) + xres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "yres:", 5)) + yres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vslen:", 6)) + vslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "hslen:", 6)) + hslen = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "left:", 5)) + left = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "right:", 6)) + right = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "upper:", 6)) + upper = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "lower:", 6)) + lower = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "pixclock:", 9)) + pixclock = simple_strtoul(this_opt+9, NULL, 0); + else if (!strncmp(this_opt, "sync:", 5)) + sync = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vesa:", 5)) + vesa = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fontname, this_opt+5); + else if (!strncmp(this_opt, "maxclk:", 7)) + maxclk = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "fh:", 3)) + fh = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "fv:", 3)) + fv = simple_strtoul(this_opt+3, NULL, 0); + else if (!strncmp(this_opt, "mem:", 4)) + mem = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "fastfont:", 9)) + fastfont = simple_strtoul(this_opt+9, NULL, 0); + else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */ + fastfont = 0; + else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ + disabled = 1; + else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ + disabled = 0; + else { + int value = 1; + + if (!strncmp(this_opt, "no", 2)) { + value = 0; + this_opt += 2; + } + if (! strcmp(this_opt, "inverse")) + inverse = value; + else if (!strcmp(this_opt, "accel")) + noaccel = !value; + else if (!strcmp(this_opt, "pan")) + nopan = !value; + else if (!strcmp(this_opt, "pciretry")) + no_pci_retry = !value; + else if (!strcmp(this_opt, "vga")) + novga = !value; + else if (!strcmp(this_opt, "bios")) + nobios = !value; + else if (!strcmp(this_opt, "inv24")) + inv24 = value; + else if (!strcmp(this_opt, "cross4MB")) + cross4MB = value; + else if (!strcmp(this_opt, "hwcursor")) + hwcursor = value; + else if (!strcmp(this_opt, "blink")) + blink = value; + else if (!strcmp(this_opt, "grayscale")) + grayscale = value; + else { + printk(KERN_ERR "matroxfb: unknown parameter %s%s\n", value?"":"no", this_opt); + } + } + } +} +#endif + +__initfunc(static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize)) { + vaddr_t vm; + unsigned int offs; + unsigned int offs2; + unsigned char store; + unsigned char bytes[16]; + unsigned char* tmp; + unsigned long cbase; + unsigned long mbase; + unsigned int clen; + unsigned int mlen; + + DBG("matroxfb_getmemory") + + vm = ACCESS_FBINFO(video.vbase); + maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ + /* at least 2MB */ + if (maxSize < 0x0200000) return 0; + if (maxSize > 0x1000000) maxSize = 0x1000000; + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80); + + store = mga_readb(vm, 0x1234); + tmp = bytes; + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + *tmp++ = mga_readb(vm, offs); + for (offs = 0x100000; offs < maxSize; offs += 0x200000) + mga_writeb(vm, offs, 0x02); + if (ACCESS_FBINFO(features.accel.has_cacheflush)) + mga_outb(M_CACHEFLUSH, 0x00); + else + mga_writeb(vm, 0x1234, 0x99); + cbase = mbase = 0; + clen = mlen = 0; + for (offs = 0x100000; offs < maxSize; offs += 0x200000) { + if (mga_readb(vm, offs) != 0x02) + continue; + mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); + if (mga_readb(vm, offs)) + continue; + if (offs - 0x100000 == cbase + clen) { + clen += 0x200000; + } else { + cbase = offs - 0x100000; + clen = 0x200000; + } + if ((clen > mlen) +#ifndef MATROX_2MB_WITH_4MB_ADDON + && (cbase == 0) +#endif + ) { + mbase = cbase; + mlen = clen; + } + } + tmp = bytes; + for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) + mga_writeb(vm, offs2, *tmp++); + mga_writeb(vm, 0x1234, store); + + mga_outb(M_EXTVGA_INDEX, 0x03); + mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80); + + *realOffset = mbase; + *realSize = mlen; +#ifdef CONFIG_FB_MATROX_MILLENIUM + ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF)); +#endif + return 1; +} + +#ifdef CONFIG_FB_MATROX_MILLENIUM +__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) { + static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960, + 1024, 1152, 1280, 1600, 1664, 1920, + 2048, 0}; + static const int vxres_mill1[] = { 640, 768, 800, 960, + 1024, 1152, 1280, 1600, 1920, + 2048, 0}; + + DBG("Ti3026_preinit") + + ACCESS_FBINFO(millenium) = 1; + ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); + ACCESS_FBINFO(capable.cfb4) = 1; + ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; + ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; + + /* preserve VGA I/O, BIOS and PPC */ + hw->MXoptionReg &= 0xC0000100; + hw->MXoptionReg |= 0x002C0000; + if (ACCESS_FBINFO(devflags.novga)) + hw->MXoptionReg &= ~0x00000100; + if (ACCESS_FBINFO(devflags.nobios)) + hw->MXoptionReg &= ~0x40000000; + if (ACCESS_FBINFO(devflags.nopciretry)) + hw->MXoptionReg |= 0x20000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); + + ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV); + + outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED); + outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR); + outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA); + + outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); + outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00); + outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00); + + mga_outb(M_MISC_REG, 0x67); + + outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL); + + mga_outl(M_RESET, 1); + udelay(250); + mga_outl(M_RESET, 0); + udelay(250); + mga_outl(M_MACCESS, 0x00008000); + udelay(10); + return 0; +} + +__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) { + + DBG("Ti3026_reset") + + matroxfb_fastfont_init(MINFO); + + ti3026_ramdac_init(PMINFO hw); +} +#endif + +#ifdef CONFIG_FB_MATROX_MILLENIUM +static struct matrox_switch matrox_millenium = { + Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore +}; +#endif + +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static struct matrox_switch matrox_mystique = { + MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore +}; +#endif + +#ifdef CONFIG_FB_MATROX_G100 +static struct matrox_switch matrox_G100 = { + MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore +}; +#endif + +struct video_board { + int maxvram; + int accelID; + struct matrox_switch* lowlevel; + }; +#ifdef CONFIG_FB_MATROX_MILLENIUM +static struct video_board vbMillenium __initdata = {0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium}; +static struct video_board vbMillenium2 __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium}; +static struct video_board vbMillenium2A __initdata = {0x1000000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium}; +#endif /* CONFIG_FB_MATROX_MILLENIUM */ +#ifdef CONFIG_FB_MATROX_MYSTIQUE +static struct video_board vbMystique __initdata = {0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique}; +#endif /* CONFIG_FB_MATROX_MYSTIQUE */ +#ifdef CONFIG_FB_MATROX_G100 +static struct video_board vbG100 __initdata = {0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100}; +static struct video_board vbG200 __initdata = {0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100}; +#endif + +#define DEVF_VIDEO64BIT 0x01 +#define DEVF_SWAPS 0x02 +#define DEVF_MILLENIUM 0x04 +#define DEVF_MILLENIUM2 0x08 +#define DEVF_CROSS4MB 0x10 +static struct board { + unsigned short vendor, device, rev, svid, sid; + unsigned int flags; + unsigned int maxclk; + struct video_board* base; + const char* name; + } dev_list[] __initdata = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, + 0, 0, + DEVF_MILLENIUM, + 220000, + &vbMillenium, + "Millennium (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, + 0, 0, + DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS, + 220000, + &vbMillenium2, + "Millennium II (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, + 0, 0, + DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS, + 250000, + &vbMillenium2A, + "Millennium II (AGP)"}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, + 0, 0, + DEVF_VIDEO64BIT, + 180000, + &vbMystique, + "Mystique (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS, + 220000, + &vbMystique, + "Mystique 220 (PCI)"}, +#endif +#ifdef CONFIG_FB_MATROX_G100 + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "MGA-G100 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "unknown G100 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "Productiva G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG100, + "unknown G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG200, + "Mystique G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 250000, + &vbG200, + "Millennium G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG200, + "Marvel G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + &vbG200, + "MGA-G200 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS, + 220000, + &vbG200, + "unknown G200 (AGP)"}, +#endif + {0, 0, 0xFF, + 0, 0, + 0, + 0, + NULL, + NULL}}; + +__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) { + unsigned long ctrlptr_phys = 0; + unsigned long video_base_phys = 0; + unsigned int memsize; + struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw); + + DBG("initMatrox2") + + /* set default values... */ + vesafb_defined.accel_flags = FB_ACCELF_TEXT; + + ACCESS_FBINFO(hw_switch) = b->base->lowlevel; + ACCESS_FBINFO(devflags.accelerator) = b->base->accelID; + ACCESS_FBINFO(max_pixel_clock) = b->maxclk; + + printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); + ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT; + if (ACCESS_FBINFO(capable.cross4MB) < 0) + ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB; + if (b->flags & DEVF_SWAPS) { + ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF; + video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF; /* aligned at 8MB (or 16 for Mill 2) */ + } else { + ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF; + video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF; /* aligned at 8MB */ + } + if (!ctrlptr_phys) { + printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); + return -EINVAL; + } + if (!video_base_phys) { + printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); + return -EINVAL; + } + if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); + return -ENOMEM; + } + ACCESS_FBINFO(mmio.base) = ctrlptr_phys; + ACCESS_FBINFO(mmio.len) = 16384; + memsize = b->base->maxvram; +/* convert mem (autodetect k, M) */ + if (mem < 1024) mem *= 1024; + if (mem < 0x00100000) mem *= 1024; + + if (mem && (mem < memsize)) + memsize = mem; + ACCESS_FBINFO(video.base) = video_base_phys; + if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", + video_base_phys, memsize); + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + return -ENOMEM; + } + { + u_int32_t cmd; + u_int32_t mga_option; + + /* Matrox MilleniumII is deactivated on bootup, but address + regions are assigned to board. So we have to enable it */ + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option); + pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd); + mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ + if ((cmd & PCI_COMMAND_MEMORY) != + PCI_COMMAND_MEMORY) { + /* But if we have to enable it, we have probably to + disable VGA I/O and BIOS... Sure? */ + dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n"); + cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE; + mga_option &= 0xBFFFFEFF; + ACCESS_FBINFO(devflags.novga) = 1; + ACCESS_FBINFO(devflags.nobios) = 1; + } + mga_option |= MX_OPTION_BSWAP; + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) { + if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) { + printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); + } + mga_option |= 0x20000000; + ACCESS_FBINFO(devflags.nopciretry) = 1; + } + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd); + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option); + hw->MXoptionReg = mga_option; + + /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ + /* maybe preinit() candidate, but it is same... for all devices... at this time... */ + pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00); + } + + if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) { + mga_iounmap(ACCESS_FBINFO(video.vbase)); + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + return -ENXIO; + } + + { + unsigned int offs; + + if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) { + printk(KERN_ERR "matroxfb: cannot determine memory size\n"); + mga_iounmap(ACCESS_FBINFO(video.vbase)); + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + return -ENOMEM; + } +#ifdef MATROX_2MB_WITH_4MB_ADDON +#ifdef FBCON_HAS_CFB24 + { + unsigned int end = offs + ACCESS_FBINFO(video.len); + + if (offs) + offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3; + ACCESS_FBINFO(video.len) = end - offs; + } +#endif + mga_ydstorg(MINFO) = offs; + video_base_phys += offs; +#endif + } + ACCESS_FBINFO(curr.video_type) = FB_TYPE_PACKED_PIXELS; + ACCESS_FBINFO(currcon) = -1; + ACCESS_FBINFO(currcon_display) = NULL; + mga_iounmap(ACCESS_FBINFO(video.vbase)); + ACCESS_FBINFO(video.base) = video_base_phys; + if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) { + printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", + video_base_phys, ACCESS_FBINFO(video.len)); + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + return -ENOMEM; + } + ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len); + if (ACCESS_FBINFO(video.len_usable) > 0x08000000) + ACCESS_FBINFO(video.len_usable) = 0x08000000; +#ifdef CONFIG_MTRR + ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1); + ACCESS_FBINFO(mtrr.vram_valid) = 1; + printk(KERN_INFO "matroxfb: MTRR's turned on\n"); +#endif /* CONFIG_MTRR */ + +/* validate params, autodetect k, M */ + if (fh < 1000) fh *= 1000; /* 1kHz minimum */ + if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ + if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ + vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ + + ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh; + ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0; + ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv; + ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */ + +/* static settings */ + for (RSptr = vesamap; RSptr->vesa; RSptr++) { + if (RSptr->vesa == vesa) break; + } + if (!RSptr->vesa) { + printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); + RSptr = vesamap; + } + { + int res = RSResolution(RSptr->info)-1; + if (!left) + left = timmings[res].left; + if (!xres) + xres = timmings[res].xres; + if (!right) + right = timmings[res].right; + if (!hslen) + hslen = timmings[res].hslen; + if (!upper) + upper = timmings[res].upper; + if (!yres) + yres = timmings[res].yres; + if (!lower) + lower = timmings[res].lower; + if (!vslen) + vslen = timmings[res].vslen; + if (!(fv||fh||maxclk||pixclock)) + fv = timmings[res].vfreq; + if (!depth) + depth = RSDepth(RSptr->info); + } + if (sync == -1) { + sync = 0; + if (yres < 480) + sync |= FB_SYNC_VERT_HIGH_ACT; + } + if (xres < 320) + xres = 320; + if (xres > 2048) + xres = 2048; + if (yres < 200) + yres = 200; + if (yres > 2048) + yres = 2048; + { + unsigned int tmp; + + if (fv) { + tmp = fv * (upper + yres + lower + vslen); + if ((tmp < fh) || (fh == 0)) fh = tmp; + } + if (fh) { + tmp = fh * (left + xres + right + hslen); + if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; + } + maxclk = (maxclk + 499) / 500; + if (maxclk) { + tmp = (2000000000 + maxclk) / maxclk; + if (tmp > pixclock) pixclock = tmp; + } + } + vesafb_defined.red = colors[depth-1].red; + vesafb_defined.green = colors[depth-1].green; + vesafb_defined.blue = colors[depth-1].blue; + vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; + if (pixclock < 2000) /* > 500MHz */ + pixclock = 4000; /* 250MHz */ + if (pixclock > 1000000) + pixclock = 1000000; /* 1MHz */ + vesafb_defined.xres = xres; + vesafb_defined.yres = yres; + vesafb_defined.xoffset = 0; + vesafb_defined.yoffset = 0; + vesafb_defined.grayscale = grayscale; + vesafb_defined.pixclock = pixclock; + vesafb_defined.left_margin = left; + vesafb_defined.right_margin = right; + vesafb_defined.hsync_len = hslen; + vesafb_defined.upper_margin = upper; + vesafb_defined.lower_margin = lower; + vesafb_defined.vsync_len = vslen; + vesafb_defined.sync = sync; + vesafb_defined.vmode = 0; + + if (!ACCESS_FBINFO(devflags.novga)) + request_region(0x3C0, 32, "matrox"); + if (noaccel) + vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; + + strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA"); + ACCESS_FBINFO(fbcon.changevar) = NULL; + ACCESS_FBINFO(fbcon.node) = -1; + ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops; + ACCESS_FBINFO(fbcon.disp) = d; + ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch; + ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar; + ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank; + ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT; + ACCESS_FBINFO(hw_switch->reset(PMINFO hw)); + ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; +#if defined(CONFIG_FB_COMPAT_XPMAC) + strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */ + strcat(ACCESS_FBINFO(matrox_name), b->name); + if (!console_fb_info) + console_fb_info = &ACCESS_FBINFO(fbcon); +#endif +#if defined(CONFIG_PPC) + if ((xres <= 640) && (yres <= 480)) { + struct fb_var_screeninfo var; + + if (default_vmode == VMODE_NVRAM) + default_vmode = nvram_read_byte(NV_VMODE); + if ((default_vmode <= 0) || (default_vmode > VMODE_MAX)) + default_vmode = VMODE_640_480_60; + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); + if ((default_cmode < CMODE_8) || (default_cmode > CMODE_32)) + default_cmode = CMODE_8; + if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { + var.accel_flags = vesafb_defined.accel_flags; + vesafb_defined = var; + } + } +#endif + { + int pixel_size = vesafb_defined.bits_per_pixel; + int avamem = ACCESS_FBINFO(video.len_usable); + + vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO xres, pixel_size); + if (nopan) { + vesafb_defined.yres_virtual = vesafb_defined.yres; + } else { + vesafb_defined.yres_virtual = (avamem * 8 / (pixel_size * vesafb_defined.xres_virtual)) & ~0x1F; + if (vesafb_defined.yres_virtual < vesafb_defined.yres) + vesafb_defined.yres_virtual = vesafb_defined.yres; + } + } + if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) { + printk(KERN_ERR "matroxfb: cannot set required parameters\n"); + return -EINVAL; + } + + printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, + vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); + printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", + ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len)); + +/* We do not have to set currcon to 0... register_framebuffer do it for us on first console + * and we do not want currcon == 0 for subsequent framebuffers */ + + if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) + return -EINVAL; + printk("fb%d: %s frame buffer device\n", + GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename)); + if (ACCESS_FBINFO(currcon) < 0) { + /* there is no console on this fb... but we have to initialize hardware + * until someone tells me what is proper thing to do */ + printk(KERN_INFO "fb%d: initializing hardware\n", + GET_FB_IDX(ACCESS_FBINFO(fbcon.node))); + matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon)); + } + return 0; +} + +static struct matrox_fb_info* fb_list = NULL; + +__initfunc(static int matrox_init(void)) { + struct pci_dev* pdev = NULL; + + DBG("matrox_init") + + if (disabled) + return -ENXIO; + while ((pdev = pci_find(pdev)) != NULL) { + struct board* b; + u_int8_t rev; + u_int16_t svid; + u_int16_t sid; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid); + for (b = dev_list; b->vendor; b++) { + if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue; + if (b->svid) + if ((b->svid != svid) || (b->sid != sid)) continue; + if (dev <= 0) { + struct matrox_fb_info* minfo; + struct display* d; + int err; + +#ifdef CONFIG_FB_MATROX_MULTIHEAD + minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL); + if (minfo) { + d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL); + if (d) { +#else + minfo = &global_mxinfo; + d = &global_disp; +#endif + memset(MINFO, 0, sizeof(*MINFO)); + memset(d, 0, sizeof(*d)); + + ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1); + ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2); + ACCESS_FBINFO(pcidev) = pdev; + /* CMDLINE */ + memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); + /* DEVFLAGS */ + ACCESS_FBINFO(devflags.inverse) = inverse; + ACCESS_FBINFO(devflags.novga) = novga; + ACCESS_FBINFO(devflags.nobios) = nobios; + ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; + ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; + ACCESS_FBINFO(devflags.precise_width) = option_precise_width; + ACCESS_FBINFO(devflags.hwcursor) = hwcursor; + ACCESS_FBINFO(devflags.blink) = blink; + ACCESS_FBINFO(capable.cross4MB) = cross4MB; + + ACCESS_FBINFO(fastfont.size) = fastfont; + + ACCESS_FBINFO(cursor.state) = CM_ERASE; + ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL; + ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO; + spin_lock_init(&ACCESS_FBINFO(lock.DAC)); + + err = initMatrox2(PMINFO d, b); + if (!err) { + ACCESS_FBINFO(next_fb) = fb_list; + fb_list = MINFO; +#ifdef CONFIG_FB_MATROX_MULTIHEAD + goto leave; +#else + return 0; +#endif + } +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree(d); + } + kfree(minfo); + } +#endif + } +#ifdef CONFIG_FB_MATROX_MULTIHEAD +leave:; +#endif + if (dev == 0) return 0; + if (dev > 0) dev--; + break; + } + } + return 0; +} + +#ifndef MODULE +__initfunc(void matroxfb_init(void)) +{ + DBG("matroxfb_init") +#if defined(CONFIG_FB_OF) +/* Nothing to do, must be called from offb */ +#else + matrox_init(); +#endif +} + +#if defined(CONFIG_FB_OF) +__initfunc(void matrox_of_init(struct device_node *dp)) { + DBG("matrox_of_init"); + matrox_init(); +} +#endif /* CONFIG_FB_OF */ + +#else + +MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200"); +MODULE_PARM(mem, "i"); +MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); +MODULE_PARM(disabled, "i"); +MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)"); +MODULE_PARM(noaccel, "i"); +MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); +MODULE_PARM(nopan, "i"); +MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); +MODULE_PARM(no_pci_retry, "i"); +MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); +MODULE_PARM(novga, "i"); +MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); +MODULE_PARM(nobios, "i"); +MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); +MODULE_PARM(inv24, "i"); +MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); +MODULE_PARM(inverse, "i"); +MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); +#ifdef CONFIG_FB_MATROX_MULTIHEAD +MODULE_PARM(dev, "i"); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); +#else +MODULE_PARM(dev, "i"); +MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)"); +#endif +MODULE_PARM(vesa, "i"); +MODULE_PARM_DESC(vesa, "Startup videomode (0x100-0x1FF) (default=0x101)"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); +MODULE_PARM(upper, "i"); +MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); +MODULE_PARM(lower, "i"); +MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); +MODULE_PARM(vslen, "i"); +MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); +MODULE_PARM(left, "i"); +MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); +MODULE_PARM(right, "i"); +MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); +MODULE_PARM(hslen, "i"); +MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); +MODULE_PARM(pixclock, "i"); +MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); +MODULE_PARM(sync, "i"); +MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); +MODULE_PARM(depth, "i"); +MODULE_PARM_DESC(depth, "Color depth (8,15,16,24,32) (default=vesa)"); +MODULE_PARM(maxclk, "i"); +MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); +MODULE_PARM(fh, "i"); +MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); +MODULE_PARM(fv, "i"); +MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" +"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); +MODULE_PARM(hwcursor, "i"); +MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)"); +MODULE_PARM(blink, "i"); +MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)"); +MODULE_PARM(fastfont, "i"); +MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)"); +MODULE_PARM(grayscale, "i"); +MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); +MODULE_PARM(cross4MB, "i"); +MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. It cannot at least on Millennium (I/II)."); + +__initfunc(int init_module(void)) { + + DBG("init_module") + +#ifdef DEBUG + if( disabled ) + return 0; +#endif /* DEBUG */ + + if (depth == 0) + depth = 0; /* default */ + else if (depth == 4) + depth = RS4bpp; + else if (depth == 8) + depth = RS8bpp; + else if (depth == 15) + depth = RS15bpp; + else if (depth == 16) + depth = RS16bpp; + else if (depth == 24) + depth = RS24bpp; + else if (depth == 32) + depth = RS32bpp; + else { + printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); + depth = 0; + } + matrox_init(); + if (!fb_list) return -ENXIO; + return 0; +} + +void cleanup_module(void) { + + DBG("cleanup_module") + +#ifdef DEBUG + if( disabled ) + return; +#endif /* DEBUG */ + + while (fb_list) { + struct matrox_fb_info* minfo; + + minfo = fb_list; + fb_list = fb_list->next_fb; + unregister_framebuffer(&ACCESS_FBINFO(fbcon)); + del_timer(&ACCESS_FBINFO(cursor.timer)); +#ifdef CONFIG_MTRR + if (ACCESS_FBINFO(mtrr.vram_valid)) + mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len)); +#endif + mga_iounmap(ACCESS_FBINFO(mmio.vbase)); + mga_iounmap(ACCESS_FBINFO(video.vbase)); +#ifdef CONFIG_FB_MATROX_MULTIHEAD + kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display)); + kfree_s(minfo, sizeof(struct matrox_fb_info)); +#endif + } +} +#endif /* MODULE */ +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/video/mdacon.c b/drivers/video/mdacon.c new file mode 100644 index 000000000..ea5afadd8 --- /dev/null +++ b/drivers/video/mdacon.c @@ -0,0 +1,617 @@ +/* + * linux/drivers/video/mdacon.c -- Low level MDA based console driver + * + * (c) 1998 Andrew Apted <ajapted@netspace.net.au> + * + * including portions (c) 1995-1998 Patrick Caulfield. + * + * This file is based on the VGA console driver (vgacon.c): + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * + * and on the old console.c, vga.c and vesa_blank.c drivers: + * + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/console_struct.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/malloc.h> +#include <linux/vt_kern.h> +#include <linux/vt_buffer.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/vga.h> + + +/* description of the hardware layout */ + +static unsigned long mda_vram_base; /* Base of video memory */ +static unsigned long mda_vram_len; /* Size of video memory */ +static unsigned int mda_num_columns; /* Number of text columns */ +static unsigned int mda_num_lines; /* Number of text lines */ + +static unsigned int mda_index_port; /* Register select port */ +static unsigned int mda_value_port; /* Register value port */ +static unsigned int mda_mode_port; /* Mode control port */ +static unsigned int mda_status_port; /* Status and Config port */ +static unsigned int mda_gfx_port; /* Graphics control port */ + +/* current hardware state */ + +static int mda_origin_loc=-1; +static int mda_cursor_loc=-1; +static int mda_cursor_size_from=-1; +static int mda_cursor_size_to=-1; + +static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type; +static char *mda_type_name; + +/* console information */ + +static int mda_first_vc = 13; +static int mda_last_vc = 16; + +static struct vc_data *mda_display_fg = NULL; + +#ifdef MODULE_PARM +MODULE_PARM(mda_first_vc, "1-255i"); +MODULE_PARM(mda_last_vc, "1-255i"); +#endif + + +/* MDA register values + */ + +#define MDA_CURSOR_BLINKING 0x00 +#define MDA_CURSOR_OFF 0x20 +#define MDA_CURSOR_SLOWBLINK 0x60 + +#define MDA_MODE_GRAPHICS 0x02 +#define MDA_MODE_VIDEO_EN 0x08 +#define MDA_MODE_BLINK_EN 0x20 +#define MDA_MODE_GFX_PAGE1 0x80 + +#define MDA_STATUS_HSYNC 0x01 +#define MDA_STATUS_VSYNC 0x80 +#define MDA_STATUS_VIDEO 0x08 + +#define MDA_CONFIG_COL132 0x08 +#define MDA_GFX_MODE_EN 0x01 +#define MDA_GFX_PAGE_EN 0x02 + + +/* + * MDA could easily be classified as "pre-dinosaur hardware". + */ + +static void write_mda_b(unsigned int val, unsigned char reg) +{ + unsigned long flags; + + save_flags(flags); cli(); + + outb_p(reg, mda_index_port); + outb_p(val, mda_value_port); + + restore_flags(flags); +} + +static void write_mda_w(unsigned int val, unsigned char reg) +{ + unsigned long flags; + + save_flags(flags); cli(); + + outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port); + outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port); + + restore_flags(flags); +} + +static int test_mda_b(unsigned char val, unsigned char reg) +{ + unsigned long flags; + + save_flags(flags); cli(); + + outb_p(reg, mda_index_port); + outb (val, mda_value_port); + + udelay(20); val = (inb_p(mda_value_port) == val); + + restore_flags(flags); + + return val; +} + +static inline void mda_set_origin(unsigned int location) +{ + if (mda_origin_loc == location) + return; + + write_mda_w(location >> 1, 0x0c); + + mda_origin_loc = location; +} + +static inline void mda_set_cursor(unsigned int location) +{ + if (mda_cursor_loc == location) + return; + + write_mda_w(location >> 1, 0x0e); + + mda_cursor_loc = location; +} + +static inline void mda_set_cursor_size(int from, int to) +{ + if (mda_cursor_size_from==from && mda_cursor_size_to==to) + return; + + if (from > to) { + write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */ + } else { + write_mda_b(from, 0x0a); /* cursor start */ + write_mda_b(to, 0x0b); /* cursor end */ + } + + mda_cursor_size_from = from; + mda_cursor_size_to = to; +} + + +#ifndef MODULE +__initfunc(void mdacon_setup(char *str, int *ints)) +{ + /* command line format: mdacon=<first>,<last> */ + + if (ints[0] < 2) + return; + + if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || + ints[2] < 1 || ints[2] > MAX_NR_CONSOLES) + return; + + mda_first_vc = ints[1]-1; + mda_last_vc = ints[2]-1; +} +#endif + +#ifdef MODULE +static int mda_detect(void) +#else +__initfunc(static int mda_detect(void)) +#endif +{ + int count=0; + u16 *p, p_save; + u16 *q, q_save; + + /* do a memory check */ + + p = (u16 *) mda_vram_base; + q = (u16 *) (mda_vram_base + 0x01000); + + p_save = scr_readw(p); q_save = scr_readw(q); + + scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++; + scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++; + scr_writew(p_save, p); + + if (count != 2) { + return 0; + } + + /* check if we have 4K or 8K */ + + scr_writew(0xA55A, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0xA55A) count++; + + scr_writew(0x5AA5, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0x5AA5) count++; + + scr_writew(p_save, p); scr_writew(q_save, q); + + if (count == 4) { + mda_vram_len = 0x02000; + } + + /* Ok, there is definitely a card registering at the correct + * memory location, so now we do an I/O port test. + */ + + if (! test_mda_b(0x66, 0x0f)) { /* cursor low register */ + return 0; + } + if (! test_mda_b(0x99, 0x0f)) { /* cursor low register */ + return 0; + } + + /* See if the card is a Hercules, by checking whether the vsync + * bit of the status register is changing. This test lasts for + * approximately 1/10th of a second. + */ + + p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC; + + for (count=0; count < 50000 && p_save == q_save; count++) { + q_save = inb(mda_status_port) & MDA_STATUS_VSYNC; + udelay(2); + } + + if (p_save != q_save) { + switch (inb_p(mda_status_port) & 0x70) { + case 0x10: + mda_type = TYPE_HERCPLUS; + mda_type_name = "HerculesPlus"; + break; + case 0x50: + mda_type = TYPE_HERCCOLOR; + mda_type_name = "HerculesColor"; + break; + default: + mda_type = TYPE_HERC; + mda_type_name = "Hercules"; + break; + } + } + + return 1; +} + +#ifdef MODULE +static void mda_initialize(void) +#else +__initfunc(static void mda_initialize(void)) +#endif +{ + write_mda_b(97, 0x00); /* horizontal total */ + write_mda_b(80, 0x01); /* horizontal displayed */ + write_mda_b(82, 0x02); /* horizontal sync pos */ + write_mda_b(15, 0x03); /* horizontal sync width */ + + write_mda_b(25, 0x04); /* vertical total */ + write_mda_b(6, 0x05); /* vertical total adjust */ + write_mda_b(25, 0x06); /* vertical displayed */ + write_mda_b(25, 0x07); /* vertical sync pos */ + + write_mda_b(2, 0x08); /* interlace mode */ + write_mda_b(13, 0x09); /* maximum scanline */ + write_mda_b(12, 0x0a); /* cursor start */ + write_mda_b(13, 0x0b); /* cursor end */ + + write_mda_w(0x0000, 0x0c); /* start address */ + write_mda_w(0x0000, 0x0e); /* cursor location */ + + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); + outb_p(0x00, mda_status_port); + outb_p(0x00, mda_gfx_port); +} + +#ifdef MODULE +static const char *mdacon_startup(void) +#else +__initfunc(static const char *mdacon_startup(void)) +#endif +{ + mda_num_columns = 80; + mda_num_lines = 25; + + mda_vram_base = VGA_MAP_MEM(0xb0000); + mda_vram_len = 0x01000; + + mda_index_port = 0x3b4; + mda_value_port = 0x3b5; + mda_mode_port = 0x3b8; + mda_status_port = 0x3ba; + mda_gfx_port = 0x3bf; + + mda_type = TYPE_MDA; + mda_type_name = "MDA"; + + if (! mda_detect()) { + printk("mdacon: MDA card not detected."); + return NULL; + } + + if (mda_type != TYPE_MDA) { + mda_initialize(); + } + + printk("mdacon: %s with %ldK of memory detected.\n", + mda_type_name, mda_vram_len/1024); + + return "MDA-2"; +} + +static void mdacon_init(struct vc_data *c, int init) +{ + c->vc_complement_mask = 0x0800; /* reverse video */ + c->vc_display_fg = &mda_display_fg; + + if (init) { + c->vc_cols = mda_num_columns; + c->vc_rows = mda_num_lines; + } else { + vc_resize_con(mda_num_lines, mda_num_columns, c->vc_num); + } + + /* make the first MDA console visible */ + + if (mda_display_fg == NULL) + mda_display_fg = c; + + MOD_INC_USE_COUNT; +} + +static void mdacon_deinit(struct vc_data *c) +{ + /* con_set_default_unimap(c->vc_num); */ + + if (mda_display_fg == c) + mda_display_fg = NULL; + + MOD_DEC_USE_COUNT; +} + +static inline u16 mda_convert_attr(u16 ch) +{ + u16 attr = 0x0700; + + /* Underline and reverse-video are mutually exclusive on MDA. + * Since reverse-video is used for cursors and selected areas, + * it takes precedence. + */ + + if (ch & 0x0800) attr = 0x7000; /* reverse */ + else if (ch & 0x0400) attr = 0x0100; /* underline */ + + return ((ch & 0x0200) << 2) | /* intensity */ + (ch & 0x8000) | /* blink */ + (ch & 0x00ff) | attr; +} + +static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, + u8 blink, u8 underline, u8 reverse) +{ + /* The attribute is just a bit vector: + * + * Bit 0..1 : intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink + */ + + return (intensity & 3) | + ((underline & 1) << 2) | + ((reverse & 1) << 3) | + ((blink & 1) << 7); +} + +static void mdacon_invert_region(struct vc_data *c, u16 *p, int count) +{ + for (; count > 0; count--) { + scr_writew(scr_readw(p) ^ 0x0800, p++); + } +} + +#define MDA_ADDR(x,y) ((u16 *) mda_vram_base + (y)*mda_num_columns + (x)) + +static void mdacon_putc(struct vc_data *c, int ch, int y, int x) +{ + scr_writew(mda_convert_attr(ch), MDA_ADDR(x, y)); +} + +static void mdacon_putcs(struct vc_data *c, const unsigned short *s, + int count, int y, int x) +{ + u16 *dest = MDA_ADDR(x, y); + + for (; count > 0; count--) { + scr_writew(mda_convert_attr(*s++), dest++); + } +} + +static void mdacon_clear(struct vc_data *c, int y, int x, + int height, int width) +{ + u16 *dest = MDA_ADDR(x, y); + u16 eattr = mda_convert_attr(c->vc_video_erase_char); + + if (width <= 0 || height <= 0) + return; + + if (x==0 && width==mda_num_columns) { + scr_memsetw(dest, eattr, height*width*2); + } else { + for (; height > 0; height--, dest+=mda_num_columns) + scr_memsetw(dest, eattr, width*2); + } +} + +static void mdacon_bmove(struct vc_data *c, int sy, int sx, + int dy, int dx, int height, int width) +{ + u16 *src, *dest; + + if (width <= 0 || height <= 0) + return; + + if (sx==0 && dx==0 && width==mda_num_columns) { + scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2); + + } else if (dy < sy || (dy == sy && dx < sx)) { + src = MDA_ADDR(sx, sy); + dest = MDA_ADDR(dx, dy); + + for (; height > 0; height--) { + scr_memmovew(dest, src, width*2); + src += mda_num_columns; + dest += mda_num_columns; + } + } else { + src = MDA_ADDR(sx, sy+height-1); + dest = MDA_ADDR(dx, dy+height-1); + + for (; height > 0; height--) { + scr_memmovew(dest, src, width*2); + src -= mda_num_columns; + dest -= mda_num_columns; + } + } +} + +static int mdacon_switch(struct vc_data *c) +{ + return 1; /* redrawing needed */ +} + +static int mdacon_set_palette(struct vc_data *c, unsigned char *table) +{ + return -EINVAL; +} + +static int mdacon_blank(struct vc_data *c, int blank) +{ + if (blank) { + outb_p(0x00, mda_mode_port); /* disable video */ + } else { + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); + } + + return 0; +} + +static int mdacon_font_op(struct vc_data *c, struct console_font_op *op) +{ + return -ENOSYS; +} + +static int mdacon_scrolldelta(struct vc_data *c, int lines) +{ + return 0; +} + +static void mdacon_cursor(struct vc_data *c, int mode) +{ + if (mode == CM_ERASE) { + mda_set_cursor(mda_vram_len - 1); + return; + } + + mda_set_cursor(c->vc_y*mda_num_columns*2 + c->vc_x*2); + + switch (c->vc_cursor_type & 0x0f) { + + case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break; + case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break; + case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break; + case CUR_BLOCK: mda_set_cursor_size(1, 13); break; + case CUR_NONE: mda_set_cursor_size(14, 13); break; + default: mda_set_cursor_size(12, 13); break; + } +} + +static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) +{ + u16 eattr = mda_convert_attr(c->vc_video_erase_char); + + if (!lines) + return 0; + + if (lines > c->vc_rows) /* maximum realistic size */ + lines = c->vc_rows; + + switch (dir) { + + case SM_UP: + scr_memmovew(MDA_ADDR(0,t), MDA_ADDR(0,t+lines), + (b-t-lines)*mda_num_columns*2); + scr_memsetw(MDA_ADDR(0,b-lines), eattr, + lines*mda_num_columns*2); + break; + + case SM_DOWN: + scr_memmovew(MDA_ADDR(0,t+lines), MDA_ADDR(0,t), + (b-t-lines)*mda_num_columns*2); + scr_memsetw(MDA_ADDR(0,t), eattr, lines*mda_num_columns*2); + break; + } + + return 0; +} + + +/* + * The console `switch' structure for the MDA based console + */ + +struct consw mda_con = { + mdacon_startup, /* con_startup */ + mdacon_init, /* con_init */ + mdacon_deinit, /* con_deinit */ + mdacon_clear, /* con_clear */ + mdacon_putc, /* con_putc */ + mdacon_putcs, /* con_putcs */ + mdacon_cursor, /* con_cursor */ + mdacon_scroll, /* con_scroll */ + mdacon_bmove, /* con_bmove */ + mdacon_switch, /* con_switch */ + mdacon_blank, /* con_blank */ + mdacon_font_op, /* con_font_op */ + mdacon_set_palette, /* con_set_palette */ + mdacon_scrolldelta, /* con_scrolldelta */ + NULL, /* con_set_origin */ + NULL, /* con_save_screen */ + mdacon_build_attr, /* con_build_attr */ + mdacon_invert_region, /* con_invert_region */ +}; + +#ifdef MODULE +void mda_console_init(void) +#else +__initfunc(void mda_console_init(void)) +#endif +{ + if (mda_first_vc > mda_last_vc) + return; + + take_over_console(&mda_con, mda_first_vc, mda_last_vc, 0); +} + +#ifdef MODULE + +int init_module(void) +{ + mda_console_init(); + + return 0; +} + +void cleanup_module(void) +{ + give_up_console(&mda_con); +} + +#endif diff --git a/drivers/video/mdafb.c b/drivers/video/mdafb.c deleted file mode 100644 index 35190d580..000000000 --- a/drivers/video/mdafb.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * linux/drivers/video/mdafb.c -- MDA frame buffer device - * - * Adapted from vgafb, May 1998 by Andrew Apted - * - * This file is based on vgacon.c and vgafb.c. Read about their - * contributors there. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - - -/* KNOWN PROBLEMS/TO DO ==================================================== * - * - * - detecting amount of memory is not yet implemented - * - * ========================================================================= */ - - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/malloc.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/selection.h> - -#include <asm/io.h> -#include <asm/uaccess.h> - -#include "fbcon.h" -#include "fbcon-vga.h" - - -#ifdef __powerpc__ -#define VGA_OFFSET _ISA_MEM_BASE; -#else -#define VGA_OFFSET 0x0 -#endif - - -static int mda_font_height = 16; /* !!! */ - - -static int currcon = 0; -static struct display disp; -static struct fb_info fb_info; - -static struct fb_fix_screeninfo fb_fix = { { 0, } }; -static struct fb_var_screeninfo fb_var = { 0, }; - - -/* Description of the hardware situation */ -static unsigned char mda_video_type; -static unsigned long mda_video_mem_base; /* Base of video memory */ -static unsigned long mda_video_mem_len; /* End of video memory */ -static u16 mda_video_port_reg; /* Video register select port */ -static u16 mda_video_port_val; /* Video register value port */ -static unsigned long mda_video_num_columns; /* Number of text columns */ -static unsigned long mda_video_num_lines; /* Number of text lines */ - - - /* - * MDA screen access - */ - -static inline void mda_writew(u16 val, u16 *addr) -{ -#ifdef __powerpc__ - st_le16(addr, val); -#else - writew(val, (unsigned long)addr); -#endif /* !__powerpc__ */ -} - -static inline u16 mda_readw(u16 *addr) -{ -#ifdef __powerpc__ - return ld_le16(addr); -#else - return readw((unsigned long)addr); -#endif /* !__powerpc__ */ -} - - -static inline void write_mda(unsigned char reg, unsigned int val) -{ - unsigned long flags; - - save_flags(flags); cli(); - - outb(reg, mda_video_port_reg); - outb(val >> 8, mda_video_port_val); - outb(reg+1, mda_video_port_reg); - outb(val & 0xff, mda_video_port_val); - - restore_flags(flags); -} - -static inline void mda_set_origin(unsigned short location) -{ - write_mda(12, location >> 1); -} - -static inline void mda_set_cursor(int location) -{ - write_mda(14, location >> 1); -} - - - /* - * Move hardware mda cursor - */ - -void fbcon_mdafb_cursor(struct display *p, int mode, int x, int y) -{ - switch (mode) { - case CM_ERASE: - mda_set_cursor(mda_video_mem_len - 1); - break; - - case CM_MOVE: - case CM_DRAW: - mda_set_cursor(y*p->next_line + (x << 1)); - break; - } -} - - - /* - * Interface to the low level console driver - */ - -void mdafb_setup(char *options, int *ints); -static int mdafbcon_switch(int con, struct fb_info *info); -static int mdafbcon_updatevar(int con, struct fb_info *info); -static void mdafbcon_blank(int blank, struct fb_info *info); - - - /* - * Open/Release the frame buffer device - */ - -static int mdafb_open(struct fb_info *info, int user) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int mdafb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return 0; -} - - - /* - * Get the Fixed Part of the Display - */ - -static int mdafb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) -{ - memcpy(fix, &fb_fix, sizeof(fb_fix)); - return 0; -} - - - /* - * Get the User Defined Part of the Display - */ - -static int mdafb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - memcpy(var, &fb_var, sizeof(fb_var)); - return 0; -} - - - /* - * Set the User Defined Part of the Display - */ - -static int mdafb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - struct display *display; - - if (con >= 0) - display = &fb_display[con]; - else - display = &disp; /* used during initialization */ - - if (var->xres > fb_var.xres || var->yres > fb_var.yres || - var->xres_virtual > fb_var.xres_virtual || - var->yres_virtual > fb_var.yres_virtual || - var->bits_per_pixel > fb_var.bits_per_pixel || - var->nonstd || !(var->accel_flags & FB_ACCELF_TEXT) || - (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - return -EINVAL; - - memcpy(var, &fb_var, sizeof(fb_var)); - - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - display->var = *var; - mda_set_origin(var->yoffset/mda_font_height*fb_fix.line_length); - } - - return 0; -} - - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int mdafb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - if (var->xoffset || var->yoffset+var->yres > var->yres_virtual) - return -EINVAL; - - mda_set_origin(var->yoffset/mda_font_height*fb_fix.line_length); - return 0; -} - - - /* - * Get the Colormap - */ - -static int mdafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - /* MDA is simply black and white */ - - return 0; -} - - - /* - * Set the Colormap - */ - -static int mdafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - /* MDA is simply black and white */ - - return 0; -} - - -static int mdafb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info) -{ - return -EINVAL; -} - - /* - * Interface used by the world - */ - -static struct fb_ops mdafb_ops = { - mdafb_open, mdafb_release, mdafb_get_fix, mdafb_get_var, - mdafb_set_var, mdafb_get_cmap, mdafb_set_cmap, mdafb_pan_display, - mdafb_ioctl -}; - - /* - * MDA text console with hardware cursor - */ - -static struct display_switch fbcon_mdafb = { - fbcon_vga_setup, fbcon_vga_bmove, fbcon_vga_clear, fbcon_vga_putc, - fbcon_vga_putcs, fbcon_vga_revc, fbcon_mdafb_cursor, NULL, NULL, - FONTWIDTH(8) -}; - - - /* - * Initialisation - */ - -__initfunc(void mdafb_init(void)) -{ - u16 saved; - u16 *p; - - mda_video_num_lines = 25; - mda_video_num_columns = 80; - mda_video_type = VIDEO_TYPE_MDA; - mda_video_mem_base = 0xb0000 + VGA_OFFSET; - mda_video_mem_len = 0x01000; - mda_video_port_reg = 0x3b4; - mda_video_port_val = 0x3b5; - - strcpy(fb_fix.id, "MDA-Dual-Head"); - request_region(0x3b0, 12, "mda-2"); - request_region(0x3bf, 1, "mda-2"); - - /* - * Find out if there is a graphics card present. - * Are there smarter methods around? - */ - p = (u16 *)mda_video_mem_base; - saved = mda_readw(p); - mda_writew(0xAA55, p); - if (mda_readw(p) != 0xAA55) { - mda_writew(saved, p); - return; - } - mda_writew(0x55AA, p); - if (mda_readw(p) != 0x55AA) { - mda_writew(saved, p); - return; - } - mda_writew(saved, p); - - fb_fix.smem_start = (char *) mda_video_mem_base; - fb_fix.smem_len = mda_video_mem_len; - fb_fix.type = FB_TYPE_TEXT; - fb_fix.type_aux = FB_AUX_TEXT_MDA; - fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; - fb_fix.ypanstep = mda_font_height; - fb_fix.xpanstep = 0; - fb_fix.ywrapstep = 0; - fb_fix.line_length = 2 * mda_video_num_columns; - fb_fix.mmio_start = NULL; - fb_fix.mmio_len = 0; - fb_fix.accel = FB_ACCEL_NONE; - - fb_var.xres = mda_video_num_columns*8; - fb_var.yres = mda_video_num_lines * mda_font_height; - fb_var.xres_virtual = fb_var.xres; - /* the cursor is put at the end of the video memory, hence the -2 */ - fb_var.yres_virtual = ((fb_fix.smem_len-2)/fb_fix.line_length)* - mda_font_height; - - fb_var.xoffset = fb_var.yoffset = 0; - fb_var.bits_per_pixel = 1; - fb_var.grayscale = 1; - fb_var.red.offset = 0; - fb_var.red.length = 0; - fb_var.red.msb_right = 0; - fb_var.green.offset = 0; - fb_var.green.length = 0; - fb_var.green.msb_right = 0; - fb_var.blue.offset = 0; - fb_var.blue.length = 0; - fb_var.blue.msb_right = 0; - fb_var.transp.offset = 0; - fb_var.transp.length = 0; - fb_var.transp.msb_right = 0; - fb_var.nonstd = 0; - fb_var.activate = 0; - fb_var.height = fb_var.width = -1; - fb_var.accel_flags = FB_ACCELF_TEXT; - fb_var.pixclock = 39722; /* 25.175 MHz */ - fb_var.left_margin = 40; - fb_var.right_margin = 24; - fb_var.upper_margin = 39; - fb_var.lower_margin = 9; - fb_var.hsync_len = 96; - fb_var.vsync_len = 2; - fb_var.sync = 0; - fb_var.vmode = FB_VMODE_NONINTERLACED; - - disp.var = fb_var; - disp.cmap.start = 0; - disp.cmap.len = 0; - disp.cmap.red = NULL; - disp.cmap.green = NULL; - disp.cmap.blue = NULL; - disp.cmap.transp = NULL; - -#ifdef __i386__ - disp.screen_base = ioremap((unsigned long) fb_fix.smem_start, - fb_fix.smem_len); -#else - disp.screen_base = bus_to_virt((unsigned long) fb_fix.smem_start); -#endif - disp.visual = fb_fix.visual; - disp.type = fb_fix.type; - disp.type_aux = fb_fix.type_aux; - disp.ypanstep = fb_fix.ypanstep; - disp.ywrapstep = fb_fix.ywrapstep; - disp.line_length = fb_fix.line_length; - disp.can_soft_blank = 1; - disp.inverse = 0; - disp.dispsw = &fbcon_mdafb; - - strcpy(fb_info.modename, fb_fix.id); - fb_info.node = -1; - fb_info.fbops = &mdafb_ops; - fb_info.disp = &disp; - fb_info.fontname[0] = '\0'; - fb_info.changevar = NULL; - fb_info.switch_con = &mdafbcon_switch; - fb_info.updatevar = &mdafbcon_updatevar; - fb_info.blank = &mdafbcon_blank; - - mdafb_set_var(&fb_var, -1, &fb_info); - - if (register_framebuffer(&fb_info) < 0) - return; - - printk("fb%d: MDA frame buffer device, using %dK of video memory\n", - GET_FB_IDX(fb_info.node), fb_fix.smem_len>>10); -} - -__initfunc(void mdafb_setup(char *options, int *ints)) -{ - /* nothing yet */ -} - - /* - * Update the `var' structure (called by fbcon.c) - */ - -static int mdafbcon_updatevar(int con, struct fb_info *info) -{ - if (con == currcon) { - struct fb_var_screeninfo *var = &fb_display[currcon].var; - - /* hardware scrolling */ - - mda_set_origin(var->yoffset / mda_font_height * - fb_fix.line_length); - } - - return 0; -} - -static int mdafbcon_switch(int con, struct fb_info *info) -{ - currcon = con; - mdafbcon_updatevar(con, info); - return 0; -} - - /* - * Blank the display. - */ - -static void mdafbcon_blank(int blank, struct fb_info *info) -{ - if (blank) { - outb_p(0x00, 0x3b8); /* disable video */ - } else { - outb_p(0x08, 0x3b8); /* enable video */ - } -} - - -#ifdef MODULE -int init_module(void) -{ - mdafb_init(); - return 0; -} - -void cleanup_module(void) -{ - unregister_framebuffer(&fb_info); -} -#endif /* MODULE */ diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 0e6e57f56..d66176242 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -31,10 +31,13 @@ #endif #include <asm/io.h> #include <asm/prom.h> +#include <asm/bootx.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "macmodes.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> +#include <video/macmodes.h> static int currcon = 0; @@ -47,6 +50,14 @@ struct fb_info_offb { struct { u_char red, green, blue, pad; } palette[256]; volatile unsigned char *cmap_adr; volatile unsigned char *cmap_data; + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; }; #ifdef __powerpc__ @@ -91,6 +102,12 @@ struct fb_info *console_fb_info = NULL; struct vc_mode display_info; #endif /* CONFIG_FB_COMPAT_XPMAC */ +extern boot_infos_t *boot_infos; + +static int offb_init_driver(struct device_node *); +static void offb_init_nodriver(struct device_node *); +static void offb_init_fb(const char *name, const char *full_name, int width, + int height, int depth, int pitch, unsigned long address); /* * Interface to the low level console driver @@ -175,7 +192,8 @@ static int offb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { struct display *display; - int oldbpp = -1, err; + unsigned int oldbpp = 0; + int err; int activate = var->activate; struct fb_info_offb *info2 = (struct fb_info_offb *)info; @@ -197,7 +215,7 @@ static int offb_set_var(struct fb_var_screeninfo *var, int con, oldbpp = display->var.bits_per_pixel; display->var = *var; } - if (oldbpp != var->bits_per_pixel) { + if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con, info); @@ -229,8 +247,7 @@ static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, offb_getcolreg, - info); + return fb_get_cmap(cmap, kspc, offb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -258,8 +275,7 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, offb_setcolreg, - info); + return fb_set_cmap(cmap, kspc, offb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -279,12 +295,21 @@ extern void atyfb_of_init(struct device_node *dp); #ifdef CONFIG_FB_S3TRIO extern void s3triofb_init_of(struct device_node *dp); #endif /* CONFIG_FB_S3TRIO */ +#ifdef CONFIG_FB_IMSTT +extern void imsttfb_of_init(struct device_node *dp); +#endif #ifdef CONFIG_FB_CT65550 extern void chips_of_init(struct device_node *dp); #endif /* CONFIG_FB_CT65550 */ +#ifdef CONFIG_FB_MATROX +extern void matrox_of_init(struct device_node *dp); +#endif /* CONFIG_FB_MATROX */ #ifdef CONFIG_FB_CONTROL extern void control_of_init(struct device_node *dp); #endif /* CONFIG_FB_CONTROL */ +#ifdef CONFIG_FB_VALKYRIE +extern void valkyrie_of_init(struct device_node *dp); +#endif /* CONFIG_FB_VALKYRIE */ #ifdef CONFIG_FB_PLATINUM extern void platinum_of_init(struct device_node *dp); #endif /* CONFIG_FB_PLATINUM */ @@ -297,193 +322,365 @@ extern void platinum_of_init(struct device_node *dp); __initfunc(void offb_init(void)) { struct device_node *dp; - int dpy, i, *pp, len; - unsigned *up, address; - struct fb_fix_screeninfo *fix; - struct fb_var_screeninfo *var; - struct display *disp; - struct fb_info_offb *info; + unsigned int dpy; + struct device_node *displays = find_type_devices("display"); + struct device_node *macos_display = NULL; + + /* If we're booted from BootX... */ + if (prom_num_displays == 0 && boot_infos != 0) { + unsigned long addr = (unsigned long) boot_infos->dispDeviceBase; + if (!ofonly) { + /* find the device node corresponding to the macos display */ + for (dp = displays; dp != NULL; dp = dp->next) { + int i; + /* + * Grrr... It looks like the MacOS ATI driver + * munges the assigned-addresses property (but + * the AAPL,address value is OK). + */ + if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) { + unsigned int *ap = (unsigned int *) + get_property(dp, "AAPL,address", NULL); + if (ap != NULL) { + dp->addrs[0].address = *ap; + dp->addrs[0].size = 0x01000000; + } + } + /* + * See if the display address is in one of the address + * ranges for this display. + */ + for (i = 0; i < dp->n_addrs; ++i) { + if (dp->addrs[i].address <= addr + && addr < dp->addrs[i].address + dp->addrs[i].size) + break; + } + if (i < dp->n_addrs) { + printk(KERN_INFO "MacOS display is %s\n", dp->full_name); + macos_display = dp; + break; + } + } + } + + /* initialize it */ + if (macos_display == NULL || !offb_init_driver(macos_display)) { + offb_init_fb("MacOS display", "MacOS display", + boot_infos->dispDeviceRect[2], + boot_infos->dispDeviceRect[3], + boot_infos->dispDeviceDepth, + boot_infos->dispDeviceRowBytes, addr); + } + } for (dpy = 0; dpy < prom_num_displays; dpy++) { - if (!(dp = find_path_device(prom_display_paths[dpy]))) - continue; + if ((dp = find_path_device(prom_display_paths[dpy]))) + if (ofonly || !offb_init_driver(dp)) + offb_init_nodriver(dp); + } - if (!ofonly) { + if (!ofonly) { + for (dp = find_type_devices("display"); dp != NULL; dp = dp->next) { + for (dpy = 0; dpy < prom_num_displays; dpy++) + if (strcmp(dp->full_name, prom_display_paths[dpy]) == 0) + break; + if (dpy >= prom_num_displays && dp != macos_display) + offb_init_driver(dp); + } + } +} + +__initfunc(static int offb_init_driver(struct device_node *dp)) +{ #ifdef CONFIG_FB_ATY - if (!strncmp(dp->name, "ATY", 3)) { - atyfb_of_init(dp); - continue; - } + if (!strncmp(dp->name, "ATY", 3)) { + atyfb_of_init(dp); + return 1; + } #endif /* CONFIG_FB_ATY */ #ifdef CONFIG_FB_S3TRIO - if (s3triofb_init_of(dp)) - continue; + if (s3triofb_init_of(dp)) + return 1; #endif /* CONFIG_FB_S3TRIO */ +#ifdef CONFIG_FB_IMSTT + if (!strncmp(dp->name, "IMS,tt128mb", 11)) { + imsttfb_of_init(dp); + return 1; + } +#endif #ifdef CONFIG_FB_CT65550 - if (!strcmp(dp->name, "chips65550")) { - chips_of_init(dp); - continue; - } + if (!strcmp(dp->name, "chips65550")) { + chips_of_init(dp); + return 1; + } #endif /* CONFIG_FB_CT65550 */ +#ifdef CONFIG_FB_MATROX + if (!strncmp(dp->name, "MTRX", 4)) { + matrox_of_init(dp); + return 1; + } +#endif /* CONFIG_FB_MATROX */ #ifdef CONFIG_FB_CONTROL - if(!strcmp(dp->name, "control")) { - control_of_init(dp); - continue; - } + if(!strcmp(dp->name, "control")) { + control_of_init(dp); + return 1; + } #endif /* CONFIG_FB_CONTROL */ +#ifdef CONFIG_FB_VALKYRIE + if(!strcmp(dp->name, "valkyrie")) { + valkyrie_of_init(dp); + return 1; + } +#endif /* CONFIG_FB_VALKYRIE */ #ifdef CONFIG_FB_PLATINUM - if (!strncmp(dp->name, "platinum",8)) { - printk("jonh: offb_init sees device node %s\n", dp->name); - platinum_of_init(dp); - continue; - } + if (!strncmp(dp->name, "platinum",8)) { + platinum_of_init(dp); + return 1; + } #endif /* CONFIG_FB_PLATINUM */ + return 0; +} + +__initfunc(static void offb_init_nodriver(struct device_node *dp)) +{ + int *pp, i; + unsigned int len; + int width = 640, height = 480, depth = 8, pitch; + unsigned *up, address; + + if ((pp = (int *)get_property(dp, "depth", &len)) != NULL + && len == sizeof(int)) + depth = *pp; + if ((pp = (int *)get_property(dp, "width", &len)) != NULL + && len == sizeof(int)) + width = *pp; + if ((pp = (int *)get_property(dp, "height", &len)) != NULL + && len == sizeof(int)) + height = *pp; + if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL + && len == sizeof(int)) + pitch = *pp; + else + pitch = width; + if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL + && len == sizeof(unsigned)) + address = (u_long)*up; + else { + for (i = 0; i < dp->n_addrs; ++i) + if (dp->addrs[i].size >= len) + break; + if (i >= dp->n_addrs) { + printk("no framebuffer address found for %s\n", dp->full_name); + return; } + address = (u_long)dp->addrs[i].address; - info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC); - fix = &info->fix; - var = &info->var; - disp = &info->disp; + /* kludge for valkyrie */ + if (strcmp(dp->name, "valkyrie") == 0) + address += 0x1000; + } + offb_init_fb(dp->name, dp->full_name, width, height, depth, + pitch, address); +} - strcpy(fix->id, "OFfb "); - strncat(fix->id, dp->name, sizeof(fix->id)); - fix->id[sizeof(fix->id)-1] = '\0'; +__initfunc(static void offb_init_fb(const char *name, const char *full_name, + int width, int height, int depth, + int pitch, unsigned long address)) +{ + int i; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + struct display *disp; + struct fb_info_offb *info; - if ((pp = (int *)get_property(dp, "depth", &len)) != NULL - && len == sizeof(int) && *pp != 8) { - printk("%s: can't use depth = %d\n", dp->full_name, *pp); - kfree(info); - continue; - } - if ((pp = (int *)get_property(dp, "width", &len)) != NULL - && len == sizeof(int)) - var->xres = var->xres_virtual = *pp; - if ((pp = (int *)get_property(dp, "height", &len)) != NULL - && len == sizeof(int)) - var->yres = var->yres_virtual = *pp; - if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL - && len == sizeof(int)) - fix->line_length = *pp; - else - fix->line_length = var->xres_virtual; - fix->smem_len = fix->line_length*var->yres; - if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL - && len == sizeof(unsigned)) - address = (u_long)*up; - else { - for (i = 0; i < dp->n_addrs; ++i) - if (dp->addrs[i].size >= len) - break; - if (i >= dp->n_addrs) { - printk("no framebuffer address found for %s\n", dp->full_name); - kfree(info); - continue; - } - address = (u_long)dp->addrs[i].address; - } - fix->smem_start = (char *)address; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; + printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", + width, height, name, address, depth, pitch); + if (depth != 8 && depth != 16 && depth != 32) { + printk("%s: can't use depth = %d\n", full_name, depth); + return; + } + + info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC); + if (info == 0) + return; + memset(info, 0, sizeof(*info)); + + fix = &info->fix; + var = &info->var; + disp = &info->disp; + + strcpy(fix->id, "OFfb "); + strncat(fix->id, name, sizeof(fix->id)); + fix->id[sizeof(fix->id)-1] = '\0'; + + var->xres = var->xres_virtual = width; + var->yres = var->yres_virtual = height; + fix->line_length = pitch; + + fix->smem_start = (char *)address; + fix->smem_len = pitch * height; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; /* XXX kludge for ati */ - if (strncmp(dp->name, "ATY,", 4) == 0) { - info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0; - info->cmap_data = info->cmap_adr + 1; - } + if (strncmp(name, "ATY,", 4) == 0) { + info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0; + info->cmap_data = info->cmap_adr + 1; + } + + if (depth == 8) + fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_STATIC_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; - fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_STATIC_PSEUDOCOLOR; - - var->xoffset = var->yoffset = 0; - var->bits_per_pixel = 8; - var->grayscale = 0; - var->red.offset = var->green.offset = var->blue.offset = 0; - var->red.length = var->green.length = var->blue.length = 8; - var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; - var->transp.offset = var->transp.length = var->transp.msb_right = 0; - var->nonstd = 0; - var->activate = 0; - var->height = var->width = -1; - var->pixclock = 10000; - var->left_margin = var->right_margin = 16; - var->upper_margin = var->lower_margin = 16; - var->hsync_len = var->vsync_len = 8; - var->sync = 0; - var->vmode = FB_VMODE_NONINTERLACED; - - disp->var = *var; - disp->cmap.start = 0; - disp->cmap.len = 0; - disp->cmap.red = NULL; - disp->cmap.green = NULL; - disp->cmap.blue = NULL; - disp->cmap.transp = NULL; - disp->screen_base = ioremap(address, fix->smem_len); - disp->visual = fix->visual; - disp->type = fix->type; - disp->type_aux = fix->type_aux; - disp->ypanstep = 0; - disp->ywrapstep = 0; - disp->line_length = fix->line_length; - disp->can_soft_blank = info->cmap_adr ? 1 : 0; - disp->inverse = 0; + var->xoffset = var->yoffset = 0; + var->bits_per_pixel = depth; + switch (depth) { + case 8: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 555 */ + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGB 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.msb_right = 0; + var->grayscale = 0; + var->nonstd = 0; + var->activate = 0; + var->height = var->width = -1; + var->pixclock = 10000; + var->left_margin = var->right_margin = 16; + var->upper_margin = var->lower_margin = 16; + var->hsync_len = var->vsync_len = 8; + var->sync = 0; + var->vmode = FB_VMODE_NONINTERLACED; + + disp->var = *var; + disp->cmap.start = 0; + disp->cmap.len = 0; + disp->cmap.red = NULL; + disp->cmap.green = NULL; + disp->cmap.blue = NULL; + disp->cmap.transp = NULL; + disp->screen_base = ioremap(address, fix->smem_len); + disp->visual = fix->visual; + disp->type = fix->type; + disp->type_aux = fix->type_aux; + disp->ypanstep = 0; + disp->ywrapstep = 0; + disp->line_length = fix->line_length; + disp->can_soft_blank = info->cmap_adr ? 1 : 0; + disp->inverse = 0; + switch (depth) { #ifdef FBCON_HAS_CFB8 - disp->dispsw = &fbcon_cfb8; -#else - disp->dispsw = NULL; + case 8: + disp->dispsw = &fbcon_cfb8; + break; #endif - disp->scrollmode = SCROLL_YREDRAW; - - strcpy(info->info.modename, "OFfb "); - strncat(info->info.modename, dp->full_name, - sizeof(info->info.modename)); - info->info.node = -1; - info->info.fbops = &offb_ops; - info->info.disp = disp; - info->info.fontname[0] = '\0'; - info->info.changevar = NULL; - info->info.switch_con = &offbcon_switch; - info->info.updatevar = &offbcon_updatevar; - info->info.blank = &offbcon_blank; - - for (i = 0; i < 16; i++) { - int j = color_table[i]; - info->palette[i].red = default_red[j]; - info->palette[i].green = default_grn[j]; - info->palette[i].blue = default_blu[j]; - } - offb_set_var(var, -1, &info->info); +#ifdef FBCON_HAS_CFB16 + case 16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = info->fbcon_cmap.cfb16; + for (i = 0; i < 16; i++) + info->fbcon_cmap.cfb16[i] = + (((default_blu[i] >> 3) & 0x1f) << 10) | + (((default_grn[i] >> 3) & 0x1f) << 5) | + ((default_red[i] >> 3) & 0x1f); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + disp->dispsw = &fbcon_cfb32; + disp->dispsw_data = info->fbcon_cmap.cfb32; + for (i = 0; i < 16; i++) + info->fbcon_cmap.cfb32[i] = (default_blu[i] << 16) | + (default_grn[i] << 8) | + default_red[i]; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + } - if (register_framebuffer(&info->info) < 0) { - kfree(info); - return; - } + disp->scrollmode = SCROLL_YREDRAW; + + strcpy(info->info.modename, "OFfb "); + strncat(info->info.modename, full_name, sizeof(info->info.modename)); + info->info.node = -1; + info->info.fbops = &offb_ops; + info->info.disp = disp; + info->info.fontname[0] = '\0'; + info->info.changevar = NULL; + info->info.switch_con = &offbcon_switch; + info->info.updatevar = &offbcon_updatevar; + info->info.blank = &offbcon_blank; + info->info.flags = FBINFO_FLAG_DEFAULT; + + for (i = 0; i < 16; i++) { + int j = color_table[i]; + info->palette[i].red = default_red[j]; + info->palette[i].green = default_grn[j]; + info->palette[i].blue = default_blu[j]; + } + offb_set_var(var, -1, &info->info); - printk("fb%d: Open Firmware frame buffer device on %s\n", - GET_FB_IDX(info->info.node), dp->full_name); + if (register_framebuffer(&info->info) < 0) { + kfree(info); + return; + } + + printk("fb%d: Open Firmware frame buffer device on %s\n", + GET_FB_IDX(info->info.node), full_name); #ifdef CONFIG_FB_COMPAT_XPMAC - if (!console_fb_info) { - display_info.height = var->yres; - display_info.width = var->xres; - display_info.depth = 8; - display_info.pitch = fix->line_length; - display_info.mode = 0; - strncpy(display_info.name, dp->name, sizeof(display_info.name)); - display_info.fb_address = address; - display_info.cmap_adr_address = 0; - display_info.cmap_data_address = 0; - display_info.disp_reg_address = 0; - /* XXX kludge for ati */ - if (strncmp(dp->name, "ATY,", 4) == 0) { - display_info.disp_reg_address = address + 0x7ffc00; - display_info.cmap_adr_address = address + 0x7ffcc0; - display_info.cmap_data_address = address + 0x7ffcc1; - } - console_fb_info = &info->info; + if (!console_fb_info) { + display_info.height = var->yres; + display_info.width = var->xres; + display_info.depth = depth; + display_info.pitch = fix->line_length; + display_info.mode = 0; + strncpy(display_info.name, name, sizeof(display_info.name)); + display_info.fb_address = address; + display_info.cmap_adr_address = 0; + display_info.cmap_data_address = 0; + display_info.disp_reg_address = 0; + /* XXX kludge for ati */ + if (strncmp(name, "ATY,", 4) == 0) { + display_info.disp_reg_address = address + 0x7ffc00; + display_info.cmap_adr_address = address + 0x7ffcc0; + display_info.cmap_data_address = address + 0x7ffcc1; } -#endif /* CONFIG_FB_COMPAT_XPMAC) */ + console_fb_info = &info->info; } +#endif /* CONFIG_FB_COMPAT_XPMAC) */ } @@ -505,8 +702,7 @@ static int offbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - offb_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info); currcon = con; /* Install new colormap */ @@ -561,9 +757,11 @@ static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, if (!info2->cmap_adr || regno > 255) return 1; - *red = info2->palette[regno].red; - *green = info2->palette[regno].green; - *blue = info2->palette[regno].blue; + + *red = (info2->palette[regno].red<<8) | info2->palette[regno].red; + *green = (info2->palette[regno].green<<8) | info2->palette[regno].green; + *blue = (info2->palette[regno].blue<<8) | info2->palette[regno].blue; + *transp = 0; return 0; } @@ -578,12 +776,19 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { struct fb_info_offb *info2 = (struct fb_info_offb *)info; - + int i; + if (!info2->cmap_adr || regno > 255) return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + info2->palette[regno].red = red; info2->palette[regno].green = green; info2->palette[regno].blue = blue; + *info2->cmap_adr = regno; mach_eieio(); *info2->cmap_data = red; @@ -592,6 +797,23 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, mach_eieio(); *info2->cmap_data = blue; mach_eieio(); + + if (regno < 16) + switch (info2->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: + info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + i = (regno << 8) | regno; + info2->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; +#endif + } + return 0; } @@ -601,12 +823,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - offb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, offb_setcolreg, - info); + 1, offb_setcolreg, info); } @@ -632,24 +852,35 @@ int console_setmode(struct vc_mode *mode, int doit) switch (mode->depth) { case 8: case 0: /* default */ - cmode = 0; /* CMODE_8 */ + cmode = CMODE_8; break; case 16: - cmode = 1; /* CMODE_16 */ + cmode = CMODE_16; break; case 24: case 32: - cmode = 2; /* CMODE_32 */ + cmode = CMODE_32; break; default: return -EINVAL; } if ((err = mac_vmode_to_var(mode->mode, cmode, &var))) return err; - var.activate = doit ? FB_ACTIVATE_NOW : FB_ACTIVATE_TEST; + var.activate = FB_ACTIVATE_TEST; err = console_fb_info->fbops->fb_set_var(&var, fg_console, console_fb_info); - return err; + if (err || !doit) + return err; + else { + int unit; + var.activate = FB_ACTIVATE_NOW; + for (unit = 0; unit < MAX_NR_CONSOLES; unit++) + if (fb_display[unit].conp && + (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit])) + console_fb_info->fbops->fb_set_var(&var, unit, + console_fb_info); + } + return 0; } static u16 palette_red[16]; diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index f2a3e9410..89f6860f2 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -1,19 +1,12 @@ /* * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display * - * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org> - * Copyright (C) 1998 Dan Jacobowitz + * Copyright (C) 1998 Franz Sirl * * Frame buffer structure from: - * drivers/video/chipsfb.c -- frame buffer device for - * Chips & Technologies 65550 chip. - * - * Copyright (C) 1998 Paul Mackerras - * - * This file is derived from the Powermac "chips" driver: - * Copyright (C) 1997 Fabio Riccardi. - * And from the frame buffer device for Open Firmware-initialized devices: - * Copyright (C) 1997 Geert Uytterhoeven. + * drivers/video/controlfb.c -- frame buffer device for + * Apple 'control' display chip. + * Copyright (C) 1998 Dan Jacobowitz * * Hardware information from: * platinum.c: Console support for PowerMac "platinum" display adaptor. @@ -47,18 +40,21 @@ #include <asm/prom.h> #include <asm/pgtable.h> #include <asm/adb.h> -#include <asm/cuda.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> +#include <video/macmodes.h> -#include "macmodes.h" #include "platinumfb.h" +static char fontname[40] __initdata = { 0 }; + static int currcon = 0; -static int switching = 0; + +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; struct fb_par_platinum { int vmode, cmode; @@ -68,68 +64,104 @@ struct fb_par_platinum { }; struct fb_info_platinum { - struct fb_info info; - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; + struct fb_info fb_info; struct display disp; - struct fb_par_platinum par; + struct fb_par_platinum default_par; + struct fb_par_platinum current_par; + struct { __u8 red, green, blue; - } palette[256]; + } palette[256]; volatile struct cmap_regs *cmap_regs; - unsigned long cmap_regs_phys; + unsigned long cmap_regs_phys; volatile struct platinum_regs *platinum_regs; - unsigned long platinum_regs_phys; + unsigned long platinum_regs_phys; - __u8 *frame_buffer; - __u8 *base_frame_buffer; - unsigned long frame_buffer_phys; + __u8 *frame_buffer; + volatile __u8 *base_frame_buffer; + unsigned long frame_buffer_phys; - int sense; - unsigned long total_vram; + unsigned long total_vram; + int clktype; + int dactype; + + union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif + } fbcon_cmap; }; /* - * Exported functions + * Frame buffer device API */ -void platinum_init(void); -void platinum_of_init(struct device_node *dp); static int platinum_open(struct fb_info *info, int user); static int platinum_release(struct fb_info *info, int user); static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); + struct fb_info *fb); static int platinum_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int platinum_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int platinum_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + struct fb_info *fb); static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); + u_long arg, int con, struct fb_info *info); + + +/* + * Interface to the low level console driver + */ + +static int platinum_switch(int con, struct fb_info *fb); +static int platinum_updatevar(int con, struct fb_info *fb); +static void platinum_blank(int blank, struct fb_info *fb); + + +/* + * internal functions + */ -static int read_platinum_sense(struct fb_info_platinum *p); static inline int platinum_vram_reqd(int video_mode, int color_mode); -static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *params); -static void platinum_set_hardware(struct fb_info_platinum *p); -static void platinum_par_to_all(struct fb_info_platinum *p, int init); -static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var); -static int platinum_var_to_par(struct fb_var_screeninfo *var, - struct fb_par_platinum *par, const struct fb_info *fb_info); - -static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p); -static void platinum_par_to_display(struct fb_par_platinum *par, - struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p); -static void platinum_init_display(struct display *disp); -static void platinum_par_to_fix(struct fb_par_platinum *par, struct fb_fix_screeninfo *fix, - struct fb_info_platinum *p); -static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p); +static int read_platinum_sense(struct fb_info_platinum *info); +static void set_platinum_clock(struct fb_info_platinum *info); +static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_platinum *info); +static int platinum_par_to_var(struct fb_var_screeninfo *var, + const struct fb_par_platinum *par, + const struct fb_info_platinum *info); +static int platinum_var_to_par(const struct fb_var_screeninfo *var, + struct fb_par_platinum *par, + const struct fb_info_platinum *info); +static int platinum_encode_fix(struct fb_fix_screeninfo *fix, + const struct fb_par_platinum *par, + const struct fb_info_platinum *info); +static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *fb); +static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb); +static void do_install_cmap(int con, struct fb_info *info); + + +/* + * Interface used by the world + */ + +void platinum_init(void); +#ifdef CONFIG_FB_OF +void platinum_of_init(struct device_node *dp); +#endif +void platinum_setup(char *options, int *ints); + static struct fb_ops platinumfb_ops = { platinum_open, @@ -143,13 +175,6 @@ static struct fb_ops platinumfb_ops = { platinum_ioctl }; -static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, - u_int *blue, u_int *transp, struct fb_info *info); -static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static void do_install_cmap(int con, struct fb_info *info); - -#define FUNCID { printk(KERN_INFO "entering %s\n", __FUNCTION__); } __openfirmware @@ -167,76 +192,121 @@ static int platinum_release(struct fb_info *info, int user) } static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_platinum *cp = (struct fb_info_platinum *) info; + const struct fb_info_platinum *info = (struct fb_info_platinum *)fb; + struct fb_par_platinum par; - *fix = cp->fix; + if (con == -1) + par = info->default_par; + else + platinum_var_to_par(&fb_display[con].var, &par, info); + + platinum_encode_fix(fix, &par, info); return 0; } static int platinum_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_platinum *cp = (struct fb_info_platinum *) info; + const struct fb_info_platinum *info = (struct fb_info_platinum *)fb; + + if (con == -1) + platinum_par_to_var(var, &info->default_par, info); + else + *var = fb_display[con].var; - *var = cp->var; return 0; } -/* Sets everything according to var */ static int platinum_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *fb) { - struct fb_info_platinum *p = (struct fb_info_platinum *) info; - struct display *disp; + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; struct fb_par_platinum par; - int depthchange, err; + struct display *display; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp, err; + int activate = var->activate; + + display = (con >= 0) ? &fb_display[con] : fb->disp; -// FUNCID; - disp = (con >= 0) ? &fb_display[con] : &p->disp; if((err = platinum_var_to_par(var, &par, info))) { - printk (KERN_ERR "Error in platinum_set_var, calling platinum_var_to_par: %d.\n", err); + printk(KERN_ERR "platinum_set_var: error calling platinum_var_to_par: %d.\n", err); return err; } - if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { - printk("Not activating, in platinum_set_var.\n"); - platinum_par_to_var(&par, var); + platinum_par_to_var(var, &par, info); + + if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { + printk(KERN_INFO "platinum_set_var: Not activating.\n"); return 0; } -/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */ -#define DIRTY(x) (p->var.x != var->x) - depthchange = DIRTY(bits_per_pixel); - if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) && - !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) { - platinum_par_to_var(&par, var); - p->var = disp->var = *var; - return 0; + + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + display->var = *var; + + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + struct fb_fix_screeninfo fix; + + platinum_encode_fix(&fix, &par, info); + display->screen_base = (char *) info->frame_buffer + 0x1000; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = 0; + + switch(par.cmode) { +#ifdef FBCON_HAS_CFB8 + case CMODE_8: + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case CMODE_16: + display->dispsw = &fbcon_cfb16; + display->dispsw_data = info->fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case CMODE_32: + display->dispsw = &fbcon_cfb32; + display->dispsw_data = info->fbcon_cmap.cfb32; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } + + display->scrollmode = SCROLL_YREDRAW; + if (info->fb_info.changevar) + (*info->fb_info.changevar)(con); } - printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel); - /* OK, we're getting here at the right times... */ - p->par = par; - platinum_par_to_var(&par, var); - p->var = *var; - platinum_par_to_fix(&par, &p->fix, p); - platinum_par_to_display(&par, disp, &p->fix, p); - p->disp = *disp; - - if(info->changevar && !switching) /* Don't want to do this if just switching consoles. */ - (*info->changevar)(con); - if(con == currcon) - platinum_set_hardware(p); - if(depthchange) - if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) - return err; - if(depthchange || switching) - do_install_cmap(con, info); + + if (con == currcon) + platinum_set_par(&par, info); + + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, &info->fb_info); + } + return 0; } static int platinum_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *info) { /* * Pan (or wrap, depending on the `vmode' field) the display using the @@ -244,21 +314,18 @@ static int platinum_pan_display(struct fb_var_screeninfo *var, int con, * If the values don't fit, return -EINVAL. */ -// FUNCID; if (var->xoffset != 0 || var->yoffset != 0) return -EINVAL; return 0; } static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) + struct fb_info *info) { -// FUNCID; if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, - platinum_getcolreg, info); + return fb_get_cmap(cmap, kspc, platinum_getcolreg, info); if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); @@ -267,63 +334,54 @@ static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con, } static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) + struct fb_info *info) { - struct display *disp = &fb_display[con]; int err; -// FUNCID; - if (disp->cmap.len == 0) { + if (!fb_display[con].cmap.len) { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - err = fb_alloc_cmap(&disp->cmap, size, 0); + err = fb_alloc_cmap(&fb_display[con].cmap, size, 0); if (err) return err; } if (con == currcon) - return fb_set_cmap(cmap, &disp->var, kspc, platinum_setcolreg, - info); - fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + return fb_set_cmap(cmap, kspc, platinum_setcolreg, info); + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; } static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info) + u_long arg, int con, struct fb_info *info) { -// FUNCID; + printk(KERN_ERR "platinum_ioctl not yet implemented\n"); return -EINVAL; } -static int platinum_switch(int con, struct fb_info *info) +static int platinum_switch(int con, struct fb_info *fb) { -// FUNCID; + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; + struct fb_par_platinum par; + if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, - &fb_display[currcon].var, 1, platinum_getcolreg, - info); + fb_get_cmap(&fb_display[currcon].cmap, 1, platinum_getcolreg, + fb); currcon = con; -#if 0 + platinum_var_to_par(&fb_display[currcon].var, &par, info); - platinum_set_par(&par, info); /*STOPPEDHERE - did i define that? */ - do_install_cmap(con, info); -#else - /* I see no reason not to do this. Minus info->changevar(). */ - /* DOH. This makes platinum_set_var compare, you guessed it, */ - /* fb_display[con].var (first param), and fb_display[con].var! */ - /* Perhaps I just fixed that... */ - switching = 1; - platinum_set_var(&fb_display[con].var, con, info); - switching = 0; -#endif - return 0; + platinum_set_par(&par, info); + do_install_cmap(con, fb); + + return 1; } -static int platinum_updatevar(int con, struct fb_info *info) +static int platinum_updatevar(int con, struct fb_info *fb) { + printk(KERN_ERR "platinum_updatevar is doing nothing yet.\n"); return 0; } -static void platinum_blank(int blank_mode, struct fb_info *info) +static void platinum_blank(int blank, struct fb_info *fb) { /* * Blank the screen if blank_mode != 0, else unblank. If blank == NULL @@ -337,71 +395,68 @@ static void platinum_blank(int blank_mode, struct fb_info *info) */ /* [danj] I think there's something fishy about those constants... */ /* - struct fb_info_platinum *p = (struct fb_info_platinum *) info; + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; int ctrl; - ctrl = ld_le32(&p->platinum_regs->ctrl.r) | 0x33; - if (blank_mode) + ctrl = ld_le32(&info->platinum_regs->ctrl.r) | 0x33; + if (blank) --blank_mode; - if (blank_mode & VESA_VSYNC_SUSPEND) + if (blank & VESA_VSYNC_SUSPEND) ctrl &= ~3; - if (blank_mode & VESA_HSYNC_SUSPEND) + if (blank & VESA_HSYNC_SUSPEND) ctrl &= ~0x30; - out_le32(&p->platinum_regs->ctrl.r, ctrl); + out_le32(&info->platinum_regs->ctrl.r, ctrl); */ /* TODO: Figure out how the heck to powerdown this thing! */ -//FUNCID; return; } static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, - u_int *blue, u_int *transp, struct fb_info *info) + u_int *blue, u_int *transp, struct fb_info *fb) { - struct fb_info_platinum *p = (struct fb_info_platinum *) info; + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; -// FUNCID; - if (regno > 255 || regno < 0) + if (regno > 255) return 1; - *red = p->palette[regno].red; - *green = p->palette[regno].green; - *blue = p->palette[regno].blue; + + *red = (info->palette[regno].red<<8) | info->palette[regno].red; + *green = (info->palette[regno].green<<8) | info->palette[regno].green; + *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; + *transp = 0; return 0; } static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) + u_int transp, struct fb_info *fb) { - struct fb_info_platinum *p = (struct fb_info_platinum *) info; + struct fb_info_platinum *info = (struct fb_info_platinum *) fb; + volatile struct cmap_regs *cmap_regs = info->cmap_regs; + int scale; -// FUNCID; - if (regno > 255 || regno < 0) + if (regno > 255) return 1; - p->palette[regno].red = red; - p->palette[regno].green = green; - p->palette[regno].blue = blue; - out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */ - out_8(&p->cmap_regs->lut, red); /* send one color channel at */ - out_8(&p->cmap_regs->lut, green); /* a time... */ - out_8(&p->cmap_regs->lut, blue); + red >>= 8; + green >>= 8; + blue >>= 8; + + info->palette[regno].red = red; + info->palette[regno].green = green; + info->palette[regno].blue = blue; + + scale = (info->current_par.cmode == CMODE_16) ? 3 : 0; + + out_8(&cmap_regs->addr, regno); /* tell clut what addr to fill */ + out_8(&cmap_regs->lut, red<<scale); /* send one color channel at */ + out_8(&cmap_regs->lut, green<<scale); /* a time... */ + out_8(&cmap_regs->lut, blue<<scale); if(regno < 16) { -#if 0 -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue; -#endif -#ifdef FBCON_HAS_CFB32 - fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; - /* I think. */ -#endif -#else #ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; + info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | (regno << 0); #endif #ifdef FBCON_HAS_CFB32 - fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; - /* I think. */ -#endif + info->fbcon_cmap.cfb32[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno; #endif } return 0; @@ -409,53 +464,46 @@ static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static void do_install_cmap(int con, struct fb_info *info) { -// FUNCID; if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - platinum_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, platinum_setcolreg, + info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1, - platinum_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, platinum_setcolreg, + info); } } -#ifdef CONFIG_FB_COMPAT_XPMAC -extern struct vc_mode display_info; -extern struct fb_info *console_fb_info; -#if 0 -extern int (*console_setmode_ptr)(struct vc_mode *, int); -extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int, - struct fb_info *); -int console_setmode(struct vc_mode *, int); -#endif -#endif /* CONFIG_FB_COMPAT_XPMAC */ - static inline int platinum_vram_reqd(int video_mode, int color_mode) { - return vmode_attrs[video_mode - 1].vres - * platinum_reg_init[video_mode-1]->pitch[color_mode]; + return vmode_attrs[video_mode-1].vres * + (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000; } #define STORE_D2(a, d) { \ - out_8(&p->cmap_regs->addr, (a+32)); \ - out_8(&p->cmap_regs->d2, (d)); \ + out_8(&cmap_regs->addr, (a+32)); \ + out_8(&cmap_regs->d2, (d)); \ } -static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_params) +static void set_platinum_clock(struct fb_info_platinum *info) { -// FUNCID; + volatile struct cmap_regs *cmap_regs = info->cmap_regs; + struct platinum_regvals *init; + + init = platinum_reg_init[info->current_par.vmode-1]; + STORE_D2(6, 0xc6); - out_8(&p->cmap_regs->addr,3+32); - if (in_8(&p->cmap_regs->d2) == 2) { - STORE_D2(7, clock_params[0]); - STORE_D2(8, clock_params[1]); + out_8(&cmap_regs->addr,3+32); + + if (in_8(&cmap_regs->d2) == 2) { + STORE_D2(7, init->clock_params[info->clktype][0]); + STORE_D2(8, init->clock_params[info->clktype][1]); STORE_D2(3, 3); } else { - STORE_D2(4, clock_params[0]); - STORE_D2(5, clock_params[1]); + STORE_D2(4, init->clock_params[info->clktype][0]); + STORE_D2(5, init->clock_params[info->clktype][1]); STORE_D2(3, 2); } @@ -464,131 +512,145 @@ static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_ } -__initfunc(static void init_platinum(struct fb_info_platinum *p)) -{ - struct fb_par_platinum *par = &p->par; - -// FUNCID; - p->sense = read_platinum_sense(p); - printk("Monitor sense value = 0x%x, ", p->sense); - /* Try to pick a video mode out of NVRAM if we have one. */ - par->vmode = nvram_read_byte(NV_VMODE); - if(par->vmode <= 0 || par->vmode > VMODE_MAX || !platinum_reg_init[par->vmode - 1]) - par->vmode = VMODE_CHOOSE; - if(par->vmode == VMODE_CHOOSE) - par->vmode = mac_map_monitor_sense(p->sense); - if(!platinum_reg_init[par->vmode - 1]) - par->vmode = VMODE_640_480_67; - - par->cmode = nvram_read_byte(NV_CMODE); - if(par->cmode < CMODE_8 || par->cmode > CMODE_32) - par->cmode = CMODE_8; - /* - * Reduce the pixel size if we don't have enough VRAM. - */ - while(par->cmode > CMODE_8 && platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) - par->cmode--; - - printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode); - - par->vxres = par->xres = vmode_attrs[par->vmode - 1].hres; - par->vyres = par->yres = vmode_attrs[par->vmode - 1].vres; - par->xoffset = par->yoffset = 0; - - platinum_par_to_all(p, 1); - - if (register_framebuffer(&p->info) < 0) { - kfree(p); - return; - } - platinum_set_hardware(p); - - printk("fb%d: platinum display adapter\n", GET_FB_IDX(p->info.node)); -} - /* Now how about actually saying, Make it so! */ /* Some things in here probably don't need to be done each time. */ -static void platinum_set_hardware(struct fb_info_platinum *p) +static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_platinum *info) { - struct platinum_regvals *init; - int i, dtype, clkmode; - int vmode, cmode; + volatile struct platinum_regs *platinum_regs = info->platinum_regs; + volatile struct cmap_regs *cmap_regs = info->cmap_regs; + struct platinum_regvals *init; + int i; + int vmode, cmode; -// FUNCID; - vmode = p->par.vmode; - cmode = p->par.cmode; + info->current_par = *par; + + vmode = par->vmode; + cmode = par->cmode; init = platinum_reg_init[vmode - 1]; /* Initialize display timing registers */ - out_be32(&p->platinum_regs->reg[24].r, 7); /* turn display off */ + out_be32(&platinum_regs->reg[24].r, 7); /* turn display off */ for (i = 0; i < 26; ++i) - out_be32(&p->platinum_regs->reg[i+32].r, init->regs[i]); - out_be32(&p->platinum_regs->reg[26+32].r, (p->total_vram == 0x100000 ? - init->offset[cmode] + 4 - cmode : - init->offset[cmode])); - out_be32(&p->platinum_regs->reg[16].r, (unsigned) p->frame_buffer_phys + init->fb_offset); - out_be32(&p->platinum_regs->reg[18].r, init->pitch[cmode]); - out_be32(&p->platinum_regs->reg[19].r, (p->total_vram == 0x100000 ? - init->mode[cmode+1] : - init->mode[cmode])); - out_be32(&p->platinum_regs->reg[20].r, (p->total_vram == 0x100000 ? 0x11 : 0x1011)); - out_be32(&p->platinum_regs->reg[21].r, 0x100); - out_be32(&p->platinum_regs->reg[22].r, 1); - out_be32(&p->platinum_regs->reg[23].r, 1); - out_be32(&p->platinum_regs->reg[26].r, 0xc00); - out_be32(&p->platinum_regs->reg[27].r, 0x235); - /* out_be32(&p->platinum_regs->reg[27].r, 0x2aa); */ - - STORE_D2(0, (p->total_vram == 0x100000 ? + out_be32(&platinum_regs->reg[i+32].r, init->regs[i]); + + out_be32(&platinum_regs->reg[26+32].r, (info->total_vram == 0x100000 ? + init->offset[cmode] + 4 - cmode : + init->offset[cmode])); + out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys + 0x1000 - 0x10); + out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]); + out_be32(&platinum_regs->reg[19].r, (info->total_vram == 0x100000 ? + init->mode[cmode+1] : + init->mode[cmode])); + out_be32(&platinum_regs->reg[20].r, (info->total_vram == 0x100000 ? 0x11 : 0x1011)); + out_be32(&platinum_regs->reg[21].r, 0x100); + out_be32(&platinum_regs->reg[22].r, 1); + out_be32(&platinum_regs->reg[23].r, 1); + out_be32(&platinum_regs->reg[26].r, 0xc00); + out_be32(&platinum_regs->reg[27].r, 0x235); + /* out_be32(&platinum_regs->reg[27].r, 0x2aa); */ + + STORE_D2(0, (info->total_vram == 0x100000 ? init->dacula_ctrl[cmode] & 0xf : init->dacula_ctrl[cmode])); STORE_D2(1, 4); STORE_D2(2, 0); - /* - * Try to determine whether we have an old or a new DACula. - */ - out_8(&p->cmap_regs->addr, 0x40); - dtype = in_8(&p->cmap_regs->d2); - switch (dtype) { - case 0x3c: - clkmode = 1; - break; - case 0x84: - clkmode = 0; - break; - default: - clkmode = 0; - printk("Unknown DACula type: %x\n", dtype); - } - set_platinum_clock(p, init->clock_params[clkmode]); + set_platinum_clock(info); - out_be32(&p->platinum_regs->reg[24].r, 0); /* turn display on */ + out_be32(&platinum_regs->reg[24].r, 0); /* turn display on */ #ifdef CONFIG_FB_COMPAT_XPMAC - /* And let the world know the truth. */ - if (!console_fb_info || console_fb_info == &p->info) { - display_info.height = p->var.yres; - display_info.width = p->var.xres; + if (console_fb_info == &info->fb_info) { + display_info.height = par->yres; + display_info.width = par->xres; display_info.depth = ( (cmode == CMODE_32) ? 32 : ((cmode == CMODE_16) ? 16 : 8)); - display_info.pitch = p->fix.line_length; + display_info.pitch = vmode_attrs[vmode-1].hres * (1<<cmode) + 0x20; display_info.mode = vmode; strncpy(display_info.name, "platinum", sizeof(display_info.name)); - display_info.fb_address = p->frame_buffer_phys - + init->fb_offset - + 0x10; - display_info.cmap_adr_address = p->cmap_regs_phys; - display_info.cmap_data_address = p->cmap_regs_phys + 0x30; - display_info.disp_reg_address = p->platinum_regs_phys; - console_fb_info = &p->info; + display_info.fb_address = info->frame_buffer_phys + 0x1000; + display_info.cmap_adr_address = info->cmap_regs_phys; + display_info.cmap_data_address = info->cmap_regs_phys + 0x30; + display_info.disp_reg_address = info->platinum_regs_phys; + } #endif /* CONFIG_FB_COMPAT_XPMAC */ } + +__initfunc(static int init_platinum(struct fb_info_platinum *info)) +{ + struct fb_var_screeninfo var; + struct display *disp; + int sense; + int j,k; + + sense = read_platinum_sense(info); + printk(KERN_INFO "Monitor sense value = 0x%x, ", sense); + + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 || default_vmode > VMODE_MAX || + !platinum_reg_init[default_vmode-1]) + default_vmode = VMODE_CHOOSE; + } + if (default_vmode == VMODE_CHOOSE) { + default_vmode = mac_map_monitor_sense(sense); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + /* + * Reduce the pixel size if we don't have enough VRAM. + */ + while(default_cmode > CMODE_8 && platinum_vram_reqd(default_vmode, default_cmode) > info->total_vram) + default_cmode--; + + printk("using video mode %d and color mode %d.\n", default_vmode, default_cmode); + + mac_vmode_to_var(default_vmode, default_cmode, &var); + + if (platinum_var_to_par(&var, &info->default_par, info)) { + printk(KERN_ERR "platinumfb: can't set default video mode\n"); + return 0; + } + + disp = &info->disp; + + strcpy(info->fb_info.modename, "platinum"); + info->fb_info.node = -1; + info->fb_info.fbops = &platinumfb_ops; + info->fb_info.disp = disp; + strcpy(info->fb_info.fontname, fontname); + info->fb_info.changevar = NULL; + info->fb_info.switch_con = &platinum_switch; + info->fb_info.updatevar = &platinum_updatevar; + info->fb_info.blank = &platinum_blank; + info->fb_info.flags = FBINFO_FLAG_DEFAULT; + + for (j = 0; j < 16; j++) { + k = color_table[j]; + info->palette[j].red = default_red[k]; + info->palette[j].green = default_grn[k]; + info->palette[j].blue = default_blu[k]; + } + platinum_set_var(&var, -1, &info->fb_info); + + if (register_framebuffer(&info->fb_info) < 0) + return 0; + + printk(KERN_INFO "fb%d: platinum frame buffer device\n", + GET_FB_IDX(info->fb_info.node)); + + return 1; +} + __initfunc(void platinum_init(void)) { #ifndef CONFIG_FB_OF @@ -600,17 +662,27 @@ __initfunc(void platinum_init(void)) #endif /* CONFIG_FB_OF */ } +#ifdef __powerpc__ +#define invalidate_cache(addr) \ + asm volatile("eieio; dcbi 0,%1" \ + : "=m" (*(addr)) : "r" (addr) : "memory"); +#else +#define invalidate_cache(addr) +#endif + __initfunc(void platinum_of_init(struct device_node *dp)) { - struct fb_info_platinum *p; + struct fb_info_platinum *info; unsigned long addr, size; int i, bank0, bank1, bank2, bank3; -//FUNCID; + if(dp->n_addrs != 2) panic("expecting 2 address for platinum (got %d)", dp->n_addrs); - p = kmalloc(sizeof(*p), GFP_ATOMIC); - if (p == 0) + + info = kmalloc(sizeof(*info), GFP_ATOMIC); + if (info == 0) return; + memset(info, 0, sizeof(*info)); /* Map in frame buffer and registers */ for (i = 0; i < dp->n_addrs; ++i) { @@ -618,47 +690,67 @@ __initfunc(void platinum_of_init(struct device_node *dp)) size = dp->addrs[i].size; if (size >= 0x400000) { /* frame buffer - map only 4MB */ - p->frame_buffer_phys = addr; - p->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); - p->base_frame_buffer = p->frame_buffer; + info->frame_buffer_phys = addr; + info->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); + info->base_frame_buffer = info->frame_buffer; } else { /* registers */ - p->platinum_regs_phys = addr; - p->platinum_regs = ioremap(addr, size); + info->platinum_regs_phys = addr; + info->platinum_regs = ioremap(addr, size); } } - p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ - p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + + info->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ + info->cmap_regs = ioremap(info->cmap_regs_phys, 0x1000); /* Grok total video ram */ - out_be32(&p->platinum_regs->reg[16].r, (unsigned)p->frame_buffer_phys); - out_be32(&p->platinum_regs->reg[20].r, 0x1011); /* select max vram */ - out_be32(&p->platinum_regs->reg[24].r, 0); /* switch in vram */ - eieio(); - p->frame_buffer[0x100000] = 0x34; - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x100000]) : "memory"); - p->frame_buffer[0x200000] = 0x56; - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory"); - p->frame_buffer[0x300000] = 0x78; - asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x300000]) : "memory"); + out_be32(&info->platinum_regs->reg[16].r, (unsigned)info->frame_buffer_phys); + out_be32(&info->platinum_regs->reg[20].r, 0x1011); /* select max vram */ + out_be32(&info->platinum_regs->reg[24].r, 0); /* switch in vram */ + + info->base_frame_buffer[0x100000] = 0x34; + info->base_frame_buffer[0x100008] = 0x0; + invalidate_cache(&info->base_frame_buffer[0x100000]); + info->base_frame_buffer[0x200000] = 0x56; + info->base_frame_buffer[0x200008] = 0x0; + invalidate_cache(&info->base_frame_buffer[0x200000]); + info->base_frame_buffer[0x300000] = 0x78; + info->base_frame_buffer[0x300008] = 0x0; + invalidate_cache(&info->base_frame_buffer[0x300000]); bank0 = 1; /* builtin 1MB vram, always there */ - bank1 = p->frame_buffer[0x100000] == 0x34; - bank2 = p->frame_buffer[0x200000] == 0x56; - bank3 = p->frame_buffer[0x300000] == 0x78; - p->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; - printk("Total VRAM = %dMB\n", p->total_vram / 1024 / 1024); + bank1 = info->base_frame_buffer[0x100000] == 0x34; + bank2 = info->base_frame_buffer[0x200000] == 0x56; + bank3 = info->base_frame_buffer[0x300000] == 0x78; + info->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; + printk(KERN_INFO "Total VRAM = %dMB %d%d%d%d\n", (int) (info->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0); -// p->frame_buffer = p->base_frame_buffer -// + platinum_reg_init[p->par.vmode-1]->fb_offset; + /* + * Try to determine whether we have an old or a new DACula. + */ + out_8(&info->cmap_regs->addr, 0x40); + info->dactype = in_8(&info->cmap_regs->d2); + switch (info->dactype) { + case 0x3c: + info->clktype = 1; + break; + case 0x84: + info->clktype = 0; + break; + default: + info->clktype = 0; + printk(KERN_INFO "Unknown DACula type: %x\n", info->dactype); + break; + } + + if (!init_platinum(info)) { + kfree(info); + return; + } #ifdef CONFIG_FB_COMPAT_XPMAC -#if 0 - console_set_cmap_ptr = platinum_set_cmap; - console_setmode_ptr = platinum_console_setmode; + if (!console_fb_info) + console_fb_info = &info->fb_info; #endif -#endif /* CONFIG_FB_COMPAT_XPMAC */ - - init_platinum(p); } /* @@ -666,387 +758,141 @@ __initfunc(void platinum_of_init(struct device_node *dp)) * Note that this can be called before calibrate_delay, * so we can't use udelay. */ -static int read_platinum_sense(struct fb_info_platinum *p) +static int read_platinum_sense(struct fb_info_platinum *info) { + volatile struct platinum_regs *platinum_regs = info->platinum_regs; int sense; - out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */ + out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ __delay(2000); - sense = (~in_be32(&p->platinum_regs->reg[23].r) & 7) << 8; + sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8; /* drive each sense line low in turn and collect the other 2 */ - out_be32(&p->platinum_regs->reg[23].r, 3); /* drive A low */ + out_be32(&platinum_regs->reg[23].r, 3); /* drive A low */ __delay(2000); - sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 3) << 4; - out_be32(&p->platinum_regs->reg[23].r, 5); /* drive B low */ + sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4; + out_be32(&platinum_regs->reg[23].r, 5); /* drive B low */ __delay(2000); - sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 4) << 1; - sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 1) << 2; - out_be32(&p->platinum_regs->reg[23].r, 6); /* drive C low */ + sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1; + sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2; + out_be32(&platinum_regs->reg[23].r, 6); /* drive C low */ __delay(2000); - sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 6) >> 1; + sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1; - out_be32(&p->platinum_regs->reg[23].r, 7); /* turn off drivers */ + out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ return sense; } -#if 0 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int platinum_var_to_par(struct fb_var_screeninfo *var, - struct fb_par_platinum *par, const struct fb_info *fb_info) -{ - int xres = var->xres; - int yres = var->yres; - int bpp = var->bits_per_pixel; - - struct platinum_regvals *init; - struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info; - -// FUNCID; - /* - * Get the video params out of 'var'. If a value doesn't fit, round it up, - * if it's too big, return -EINVAL. - * - * Suggestion: Round up in the following order: bits_per_pixel, xres, - * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, - * bitfields, horizontal timing, vertical timing. - */ - /* swiped by jonh from atyfb.c */ - if (xres <= 512 && yres <= 384) - par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */ - else if (xres <= 640 && yres <= 480) - par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ - else if (xres <= 640 && yres <= 870) - par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ - else if (xres <= 768 && yres <= 576) - par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */ - else if (xres <= 800 && yres <= 600) - par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ - else if (xres <= 832 && yres <= 624) - par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */ - else if (xres <= 1024 && yres <= 768) - par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ - else if (xres <= 1152 && yres <= 870) - par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ - else if (xres <= 1280 && yres <= 960) - par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ - else if (xres <= 1280 && yres <= 1024) - par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ - else { - printk(KERN_ERR "Bad resolution in platinum_var_to_par()!\n"); +static int platinum_var_to_par(const struct fb_var_screeninfo *var, + struct fb_par_platinum *par, + const struct fb_info_platinum *info) +{ + if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) { + printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n"); + printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres); + printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres); + printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual); + printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual); + printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel); + printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock); + printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode); return -EINVAL; } - xres = vmode_attrs[par->vmode - 1].hres; - yres = vmode_attrs[par->vmode - 1].vres; -/* - if (var->xres_virtual <= xres) - par->vxres = xres; - else - par->vxres = (var->xres_virtual+7) & ~7; - if (var->yres_virtual <= yres) - par->vyres = yres; - else - par->vyres = var->yres_virtual; - - par->xoffset = (var->xoffset+7) & ~7; - par->yoffset = var->yoffset; - if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres) + if(!platinum_reg_init[par->vmode-1]) { + printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", par->vmode); return -EINVAL; -*/ + } - /* I'm too chicken to think about virtual */ - /* resolutions just yet. Bok bok. */ - - /* And I'm too chicken to even figure out what they are. Awk awk. [danj] */ - if (var->xres_virtual > xres || var->yres_virtual > yres - || var->xoffset != 0 || var->yoffset != 0) { - printk(KERN_ERR "Bad virtual resolution in platinum_var_to_par()!\n"); + if (platinum_vram_reqd(par->vmode, par->cmode) > info->total_vram) { + printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", par->vmode, par->cmode); return -EINVAL; } - par->xres = xres; - par->yres = yres; - par->vxres = xres; - par->vyres = yres; + par->xres = vmode_attrs[par->vmode-1].hres; + par->yres = vmode_attrs[par->vmode-1].vres; par->xoffset = 0; par->yoffset = 0; - - if (bpp <= 8) - par->cmode = CMODE_8; - else if (bpp <= 16) - par->cmode = CMODE_16; - else if (bpp <= 32) - par->cmode = CMODE_32; - else { - printk(KERN_ERR "Bad color mode in platinum_var_to_par()!\n"); - return -EINVAL; - } - - if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) { - printk(KERN_ERR "Bad vram size requested in platinum_var_to_par()!\n"); - return -EINVAL; - } - /* Check if we know about the wanted video mode */ - init = platinum_reg_init[par->vmode-1]; - if (init == NULL) { - /* I'm not sure if platinum has any specific requirements -- */ - /* if we have a regvals struct, we're good to go? */ - printk(KERN_ERR "platinum_reg_init failed platinum_var_to_par()!\n"); - return -EINVAL; - } - - return 0; -} -#else -/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */ -static int platinum_var_to_par(struct fb_var_screeninfo *var, - struct fb_par_platinum *par, const struct fb_info *fb_info) -{ - struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info; - -// FUNCID; - if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) - return -EINVAL; - par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres; - par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres; - par->xoffset = par->yoffset = 0; + par->vxres = par->xres; + par->vyres = par->yres; - if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) - return -EINVAL; - - /* Check if we know about the wanted video mode */ - if(!platinum_reg_init[par->vmode-1]) { - /* I'm not sure if platinum has any specific requirements -- */ - /* if we have a regvals struct, we're good to go? */ - return -EINVAL; - } return 0; } -#endif -#if 0 -static void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var) -{ - memset(var, 0, sizeof(*var)); - var->xres = vmode_attrs[par->vmode - 1].hres; - var->yres = vmode_attrs[par->vmode - 1].vres; - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; /* For now. */ - var->xoffset = par->xoffset; - var->yoffset = par->yoffset; - var->grayscale = 0; - - if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) { - printk(KERN_ERR "Bad color mode in platinum_par_to_var()!\n"); - par->cmode = CMODE_8; - } - switch(par->cmode) { - case CMODE_8: - var->bits_per_pixel = 8; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CMODE_16: /* RGB 555 */ - var->bits_per_pixel = 16; - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CMODE_32: /* RGB 888 */ - var->bits_per_pixel = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - var->nonstd = 0; - var->activate = 0; - var->height = -1; - var->width = -1; - var->vmode = FB_VMODE_NONINTERLACED; - - /* these are total guesses, copied right out of atyfb.c */ - var->left_margin = var->right_margin = 64; - var->upper_margin = var->lower_margin = 32; - var->hsync_len = 8; - var->vsync_len = 8; - var->sync = 0; - -#if 1 -/* jonh's pixclocks...*/ - /* no long long support in the kernel :-( */ - /* this splittig trick will work if xres > 232 */ - var->pixclock = 1000000000/ - (var->left_margin+var->xres+var->right_margin+var->hsync_len); - var->pixclock *= 1000; - var->pixclock /= vmode_attrs[par->vmode-1].vfreq* - (var->upper_margin+var->yres+var->lower_margin+var->vsync_len); -#else -/* danj's */ - /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */ - /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */ - /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */ - var->pixclock = 255990 * platinum_reg_init[par->vmode-1]->clock_params[0]; - var->pixclock /= platinum_reg_init[par->vmode-1]->clock_params[1]; - var->pixclock >>= platinum_reg_init[par->vmode-1]->clock_params[2]; -#endif -} -#else -static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var) +static int platinum_par_to_var(struct fb_var_screeninfo *var, + const struct fb_par_platinum *par, + const struct fb_info_platinum *info) { -// FUNCID; - mac_vmode_to_var(par->vmode, par->cmode, var); + return mac_vmode_to_var(par->vmode, par->cmode, var); } -#endif -static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p) +static int platinum_encode_fix(struct fb_fix_screeninfo *fix, + const struct fb_par_platinum *par, + const struct fb_info_platinum *info) { -// FUNCID; memset(fix, 0, sizeof(*fix)); strcpy(fix->id, "platinum"); - fix->mmio_start = (char *)p->platinum_regs_phys; + fix->smem_start = (void *) (info->frame_buffer_phys + 0x1000); + fix->smem_len = (u32) info->total_vram - 0x1000; + fix->mmio_start = (char *) (info->platinum_regs_phys); fix->mmio_len = 0x1000; fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; fix->ywrapstep = 0; fix->xpanstep = 0; fix->ypanstep = 0; -} - -/* Fix must already be inited ^^^^^^^ */ -static void platinum_par_to_fix(struct fb_par_platinum *par, - struct fb_fix_screeninfo *fix, - struct fb_info_platinum *p) -{ -// FUNCID; - fix->smem_start = (void *)(p->frame_buffer_phys); - fix->smem_len = platinum_vram_reqd(par->vmode, par->cmode); - /* Hmm, jonh used total_vram here. */ fix->visual = (par->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; -// fix->line_length = par->vxres << par->cmode; - fix->line_length = platinum_reg_init[par->vmode-1]->pitch[par->cmode]; - -} + fix->line_length = vmode_attrs[par->vmode-1].hres * (1<<par->cmode) + 0x20; -static void platinum_init_display(struct display *disp) -{ - memset(disp, 0, sizeof(*disp)); - disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS; - disp->can_soft_blank = 1; - disp->scrollmode = SCROLL_YREDRAW; -#if 0 - disp->type_aux = fix->type_aux; - disp->cmap.red = NULL; /* ??? danj */ - disp->cmap.green = NULL; - disp->cmap.blue = NULL; - disp->cmap.transp = NULL; - /* Yeah, I realize I just set 0 = 0. */ -#endif -} - -static void platinum_par_to_display(struct fb_par_platinum *par, - struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p) -{ -// FUNCID; - disp->var = p->var; - disp->screen_base = (char *) p->frame_buffer - + platinum_reg_init[par->vmode-1]->fb_offset - + ((par->yres % 16) / 2) * fix->line_length + 0x10; - disp->visual = fix->visual; - disp->line_length = fix->line_length; - - if(disp->scrollmode != SCROLL_YREDRAW) { - printk(KERN_ERR "Scroll mode not YREDRAW in platinum_par_to_display!!\n"); - disp->scrollmode = SCROLL_YREDRAW; - } - - switch(par->cmode) { -#ifdef FBCON_HAS_CFB8 - case CMODE_8: - disp->dispsw = &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case CMODE_16: - disp->dispsw = &fbcon_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case CMODE_32: - disp->dispsw = &fbcon_cfb32; - break; -#endif - default: - disp->dispsw = NULL; - break; - } + return 0; } -static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p) -{ -// FUNCID; - strcpy(info->modename, p->fix.id); - info->node = -1; /* ??? danj */ - info->fbops = &platinumfb_ops; - info->disp = &p->disp; - info->fontname[0] = 0; - info->changevar = NULL; - info->switch_con = &platinum_switch; - info->updatevar = &platinum_updatevar; - info->blank = &platinum_blank; -} -/* danj: Oh, I HOPE I didn't miss anything major in here... */ -static void platinum_par_to_all(struct fb_info_platinum *p, int init) +/* + * Parse user speficied options (`video=platinumfb:') + */ +__initfunc(void platinum_setup(char *options, int *ints)) { -// FUNCID; - if(init) { - platinum_init_fix(&p->fix, p); - } - platinum_par_to_fix(&p->par, &p->fix, p); + char *this_opt; - platinum_par_to_var(&p->par, &p->var); + if (!options || !*options) + return; - if(init) { - platinum_init_display(&p->disp); - } - platinum_par_to_display(&p->par, &p->disp, &p->fix, p); - - if(init) { - platinum_init_info(&p->info, p); + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } } } - -#if 0 -__initfunc(void platinum_setup(char *options, int *ints)) -{ - /* Parse user speficied options (`video=platinumfb:') */ - FUNCID; -} - -#endif - diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h index a9b4b1c8f..d3aa5c3ef 100644 --- a/drivers/video/platinumfb.h +++ b/drivers/video/platinumfb.h @@ -311,8 +311,6 @@ static struct platinum_regvals platinum_reg_init_1 = { {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} }; -#define VMODE_MAX 20 - static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = { &platinum_reg_init_1, &platinum_reg_init_2, @@ -366,34 +364,3 @@ struct vmode_attr vmode_attrs[VMODE_MAX] = { {1280, 1024, 75} }; -/* this stuff should probably be shared by the various vmode-based */ -/* drivers in a vmode.h header. */ - -#define VMODE_NVRAM 0 /* use value stored in nvram */ -#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */ -#define VMODE_512_384_60 2 /* 512x384, 60Hz */ -#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */ -#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */ -#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */ -#define VMODE_640_480_67 6 /* 640x480, 67Hz */ -#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */ -#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */ -#define VMODE_800_600_56 9 /* 800x600, 56Hz */ -#define VMODE_800_600_60 10 /* 800x600, 60Hz */ -#define VMODE_800_600_72 11 /* 800x600, 72Hz */ -#define VMODE_800_600_75 12 /* 800x600, 75Hz */ -#define VMODE_832_624_75 13 /* 832x624, 75Hz */ -#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */ -#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */ -#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */ -#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */ -#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */ -#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */ -#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */ -#define VMODE_MAX 20 -#define VMODE_CHOOSE 99 /* choose based on monitor sense */ - -#define CMODE_NVRAM -1 /* use value stored in nvram */ -#define CMODE_8 0 /* 8 bits/pixel */ -#define CMODE_16 1 /* 16 (actually 15) bits/pixel */ -#define CMODE_32 2 /* 32 (actually 24) bits/pixel */ diff --git a/drivers/video/promcon.c b/drivers/video/promcon.c index 76f945b45..9148f609e 100644 --- a/drivers/video/promcon.c +++ b/drivers/video/promcon.c @@ -1,4 +1,4 @@ -/* $Id: promcon.c,v 1.10 1998/07/24 15:31:53 jj Exp $ +/* $Id: promcon.c,v 1.12 1998/08/23 20:19:01 mj Exp $ * Console driver utilizing PROM sun terminal emulation * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -178,8 +178,6 @@ promcon_init(struct vc_data *conp, int init) if (!init) { if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) vc_resize_con(ph + 1, pw + 1, conp->vc_num); - else if (conp->vc_num == fg_console) - update_screen(fg_console); } } diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c index 548f88602..8bfffe147 100644 --- a/drivers/video/retz3fb.c +++ b/drivers/video/retz3fb.c @@ -36,12 +36,13 @@ #include <asm/system.h> #include <asm/irq.h> #include <asm/pgtable.h> +#include <asm/io.h> -#include "retz3fb.h" -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include "retz3fb.h" /* #define DEBUG if(1) */ #define DEBUG if(0) @@ -98,38 +99,26 @@ struct display_data { long v_dispend; /* Horizontal Display End */ }; -static struct retz3fb_par current_par; - -static int current_par_valid = 0; -static int currcon = 0; - -static struct display disp; -static struct fb_info fb_info; - - -/* - * Switch for Chipset Independency - */ - -static struct fb_hwswitch { - - /* Initialisation */ +struct retz3_fb_info { + struct fb_info info; + unsigned long base; + unsigned long fbmem; + unsigned long fbsize; + volatile unsigned char *regs; + unsigned long physfbmem; + unsigned long physregs; + int currcon; + int current_par_valid; /* set to 0 by memset */ + struct display disp; + struct retz3fb_par current_par; + unsigned char color_table [256][3]; +}; - int (*init)(void); - /* Display Control */ +static char fontname[40] __initdata = { 0 }; - int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3fb_par *par); - int (*decode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par); - int (*encode_var)(struct fb_var_screeninfo *var, struct retz3fb_par *par); - int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned - int *green, unsigned int *blue, unsigned int *transp, - struct fb_info *info); - int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int - green, unsigned int blue, unsigned int transp, - struct fb_info *info); - void (*blank)(int blank); -} *fbhw; +#define retz3info(info) ((struct retz3_fb_info *)(info)) +#define fbinfo(info) ((struct fb_info *)(info)) /* @@ -139,13 +128,6 @@ static struct fb_hwswitch { static char retz3fb_name[16] = "RetinaZ3"; -static unsigned char retz3_color_table [256][4]; -static unsigned long z3_mem; -static unsigned long z3_fbmem; -static unsigned long z3_size; -static volatile unsigned char *z3_regs; - - /* * A small info on how to convert XFree86 timing values into fb * timings - by Frank Neumann: @@ -197,7 +179,7 @@ static struct fb_videomode retz3fb_predefined[] __initdata = { 640, 480, 640, 480, 0, 0, 8, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } }, /* @@ -228,14 +210,14 @@ static struct fb_videomode retz3fb_predefined[] __initdata = { 640, 480, 640, 480, 0, 0, 16, 0, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } }, { "640x480-24", { /* 640x480, 24 bpp */ 640, 480, 640, 480, 0, 0, 24, 0, {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } }, }; @@ -297,7 +279,7 @@ static struct display_switch fbcon_retz3_8; * Accelerated Functions used by the low level console driver */ -static void retz3_bitblt(struct fb_var_screeninfo *scr, +static void retz3_bitblt(struct display *p, unsigned short curx, unsigned short cury, unsigned short destx, unsigned short desty, unsigned short width, unsigned short height, unsigned short cmd, @@ -307,29 +289,28 @@ static void retz3_bitblt(struct fb_var_screeninfo *scr, * Hardware Specific Routines */ -static int retz3_init(void); -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, - struct retz3fb_par *par); +static int retz3_encode_fix(struct fb_info *info, + struct fb_fix_screeninfo *fix, + struct retz3fb_par *par); static int retz3_decode_var(struct fb_var_screeninfo *var, - struct retz3fb_par *par); + struct retz3fb_par *par); static int retz3_encode_var(struct fb_var_screeninfo *var, - struct retz3fb_par *par); + struct retz3fb_par *par); static int retz3_getcolreg(unsigned int regno, unsigned int *red, unsigned int *green, unsigned int *blue, unsigned int *transp, struct fb_info *info); static int retz3_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info); -static void retz3_blank(int blank); - /* * Internal routines */ -static void retz3fb_get_par(struct retz3fb_par *par); -static void retz3fb_set_par(struct retz3fb_par *par); -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par); +static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par); +static int do_fb_set_var(struct fb_info *info, + struct fb_var_screeninfo *var, int isactive); static void do_install_cmap(int con, struct fb_info *info); static void retz3fb_set_disp(int con, struct fb_info *info); static int get_video_mode(const char *name); @@ -381,12 +362,11 @@ static unsigned short find_fq(unsigned int freq) } -static int retz3_set_video(struct fb_var_screeninfo *var, +static int retz3_set_video(struct fb_info *info, + struct fb_var_screeninfo *var, struct retz3fb_par *par) { -#if 0 - float freq_f; -#endif + volatile unsigned char *regs = retz3info(info)->regs; unsigned int freq; int xres, hfront, hsync, hback; @@ -482,11 +462,11 @@ static int retz3_set_video(struct fb_var_screeninfo *var, if (data.v_total >= 1024) printk("MAYDAY: v_total >= 1024; bailing out!\n"); - reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); - reg_w(GREG_FEATURE_CONTROL_W, 0x00); + reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); + reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00); - seq_w(SEQ_RESET, 0x00); - seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ + seq_w(regs, SEQ_RESET, 0x00); + seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */ /* * CLOCKING_MODE bits: @@ -495,32 +475,32 @@ static int retz3_set_video(struct fb_var_screeninfo *var, * (The CL drivers sets it to 0x21 with the comment: * FullBandwidth (video off) and 8/9 dot clock) */ - seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); + seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); - seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ - seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ - seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ - seq_w(SEQ_RESET, 0x01); - seq_w(SEQ_RESET, 0x03); + seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ + seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ + seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ + seq_w(regs, SEQ_RESET, 0x01); + seq_w(regs, SEQ_RESET, 0x03); - seq_w(SEQ_EXTENDED_ENABLE, 0x05); + seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05); - seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_LINEAR_0, 0x4a); - seq_w(SEQ_LINEAR_1, 0x00); + seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ + seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_LINEAR_0, 0x4a); + seq_w(regs, SEQ_LINEAR_1, 0x00); - seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); - seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); - seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); + seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00); + seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00); + seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); /* * The lower 4 bits (0-3) are used to set the font-width for * text-mode - DON'T try to set this for gfx-mode. */ - seq_w(SEQ_EXT_CLOCK_MODE, 0x10); - seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); + seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10); + seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03); /* * Extended Pixel Control: @@ -528,52 +508,52 @@ static int retz3_set_video(struct fb_var_screeninfo *var, * bit 1: (Packed/Nibble Pixel Format ?) * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp */ - seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); - - seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); - seq_w(SEQ_COLOR_EXP_WFG, 0x01); - seq_w(SEQ_COLOR_EXP_WBG, 0x00); - seq_w(SEQ_EXT_RW_CONTROL, 0x00); - seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); - seq_w(SEQ_COLOR_KEY_CNTL, 0x40); - seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); - seq_w(SEQ_CRC_CONTROL, 0x00); - seq_w(SEQ_PERF_SELECT, 0x10); - seq_w(SEQ_ACM_APERTURE_1, 0x00); - seq_w(SEQ_ACM_APERTURE_2, 0x30); - seq_w(SEQ_ACM_APERTURE_3, 0x00); - seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); + seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); + + seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04); + seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01); + seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00); + seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00); + seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); + seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40); + seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00); + seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00); + seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00); + seq_w(regs, SEQ_CRC_CONTROL, 0x00); + seq_w(regs, SEQ_PERF_SELECT, 0x10); + seq_w(regs, SEQ_ACM_APERTURE_1, 0x00); + seq_w(regs, SEQ_ACM_APERTURE_2, 0x30); + seq_w(regs, SEQ_ACM_APERTURE_3, 0x00); + seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03); /* unlock register CRT0..CRT7 */ - crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); + crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); /* Zuerst zu schreibende Werte nur per printk ausgeben */ DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); - crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); + crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff); DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); - crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); + crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); - crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); + crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff); DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); - crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); + crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); - crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); + crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff); tmp = (data.h_sstop & 0x1f); if (data.h_bstop & 0x20) tmp |= 0x80; DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); - crt_w(CRT_END_HOR_RETR, tmp); + crt_w(regs, CRT_END_HOR_RETR, tmp); DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); - crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); + crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff)); tmp = 0x10; /* LineCompare bit #9 */ if (data.v_total & 256) @@ -591,9 +571,9 @@ static int retz3_set_video(struct fb_var_screeninfo *var, if (data.v_sstart & 512) tmp |= 0x80; DEBUG printk("CRT_OVERFLOW: %d\n", tmp); - crt_w(CRT_OVERFLOW, tmp); + crt_w(regs, CRT_OVERFLOW, tmp); - crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ + crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ tmp = 0x40; /* LineCompare bit #8 */ if (data.v_bstart & 512) @@ -601,47 +581,47 @@ static int retz3_set_video(struct fb_var_screeninfo *var, if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); - crt_w(CRT_MAX_SCAN_LINE, tmp); + crt_w(regs, CRT_MAX_SCAN_LINE, tmp); - crt_w(CRT_CURSOR_START, 0x00); - crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ + crt_w(regs, CRT_CURSOR_START, 0x00); + crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */ - crt_w(CRT_START_ADDR_HIGH, 0x00); - crt_w(CRT_START_ADDR_LOW, 0x00); + crt_w(regs, CRT_START_ADDR_HIGH, 0x00); + crt_w(regs, CRT_START_ADDR_LOW, 0x00); - crt_w(CRT_CURSOR_LOC_HIGH, 0x00); - crt_w(CRT_CURSOR_LOC_LOW, 0x00); + crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00); + crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00); DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); - crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); + crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff)); #if 1 /* 5 refresh cycles per scanline */ DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); + crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); #else DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); + crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); #endif DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); - crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); + crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); - crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); + crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff)); DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); - crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); + crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff)); DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); - crt_w(CRT_MODE_CONTROL, 0xe3); + crt_w(regs, CRT_MODE_CONTROL, 0xe3); DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); - crt_w(CRT_LINE_COMPARE, 0xff); + crt_w(regs, CRT_LINE_COMPARE, 0xff); tmp = (var->xres_virtual / 8) * (bpp / 8); - crt_w(CRT_OFFSET, tmp); + crt_w(regs, CRT_OFFSET, tmp); - crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ + crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ tmp = 0x20; /* Enable extended end bits */ if (data.h_total & 0x100) @@ -655,12 +635,12 @@ static int retz3_set_video(struct fb_var_screeninfo *var, if (var->vmode & FB_VMODE_INTERLACED) tmp |= 0x10; DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); - crt_w(CRT_EXT_HOR_TIMING1, tmp); + crt_w(regs, CRT_EXT_HOR_TIMING1, tmp); tmp = 0x00; if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) tmp |= 0x10; - crt_w(CRT_EXT_START_ADDR, tmp); + crt_w(regs, CRT_EXT_START_ADDR, tmp); tmp = 0x00; if (data.h_total & 0x200) @@ -673,7 +653,7 @@ static int retz3_set_video(struct fb_var_screeninfo *var, tmp |= 0x08; tmp |= ((data.h_bstop & 0xc0) >> 2); tmp |= ((data.h_sstop & 0x60) << 1); - crt_w(CRT_EXT_HOR_TIMING2, tmp); + crt_w(regs, CRT_EXT_HOR_TIMING2, tmp); DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); tmp = 0x10; /* Line compare bit 10 */ @@ -688,139 +668,84 @@ static int retz3_set_video(struct fb_var_screeninfo *var, tmp |= ((data.v_bstop & 0x300) >> 3); if (data.v_sstop & 0x10) tmp |= 0x80; - crt_w(CRT_EXT_VER_TIMING, tmp); + crt_w(regs, CRT_EXT_VER_TIMING, tmp); DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); - crt_w(CRT_MONITOR_POWER, 0x00); + crt_w(regs, CRT_MONITOR_POWER, 0x00); /* * Convert from ps to Hz. */ -#if 0 - freq_f = (1.0/(float)var->pixclock) * 1000000000; - freq = ((unsigned int)freq_f) * 1000; -#else freq = 2000000000 / var->pixclock; freq = freq * 500; -#endif best_freq = find_fq(freq); - pll_w(0x02, best_freq); + pll_w(regs, 0x02, best_freq); best_freq = find_fq(61000000); - pll_w(0x0a, best_freq); - pll_w(0x0e, 0x22); - - gfx_w(GFX_SET_RESET, 0x00); - gfx_w(GFX_ENABLE_SET_RESET, 0x00); - gfx_w(GFX_COLOR_COMPARE, 0x00); - gfx_w(GFX_DATA_ROTATE, 0x00); - gfx_w(GFX_READ_MAP_SELECT, 0x00); - gfx_w(GFX_GRAPHICS_MODE, 0x00); - gfx_w(GFX_MISC, 0x05); - gfx_w(GFX_COLOR_XCARE, 0x0f); - gfx_w(GFX_BITMASK, 0xff); - - reg_r(ACT_ADDRESS_RESET); - attr_w(ACT_PALETTE0 , 0x00); - attr_w(ACT_PALETTE1 , 0x01); - attr_w(ACT_PALETTE2 , 0x02); - attr_w(ACT_PALETTE3 , 0x03); - attr_w(ACT_PALETTE4 , 0x04); - attr_w(ACT_PALETTE5 , 0x05); - attr_w(ACT_PALETTE6 , 0x06); - attr_w(ACT_PALETTE7 , 0x07); - attr_w(ACT_PALETTE8 , 0x08); - attr_w(ACT_PALETTE9 , 0x09); - attr_w(ACT_PALETTE10, 0x0a); - attr_w(ACT_PALETTE11, 0x0b); - attr_w(ACT_PALETTE12, 0x0c); - attr_w(ACT_PALETTE13, 0x0d); - attr_w(ACT_PALETTE14, 0x0e); - attr_w(ACT_PALETTE15, 0x0f); - reg_r(ACT_ADDRESS_RESET); - - attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ - - attr_w(ACT_OVERSCAN_COLOR, 0x00); - attr_w(ACT_COLOR_PLANE_ENA, 0x0f); - attr_w(ACT_HOR_PEL_PANNING, 0x00); - attr_w(ACT_COLOR_SELECT, 0x00); - - reg_r(ACT_ADDRESS_RESET); - reg_w(ACT_DATA, 0x20); - - reg_w(VDAC_MASK, 0xff); + pll_w(regs, 0x0a, best_freq); + pll_w(regs, 0x0e, 0x22); + + gfx_w(regs, GFX_SET_RESET, 0x00); + gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00); + gfx_w(regs, GFX_COLOR_COMPARE, 0x00); + gfx_w(regs, GFX_DATA_ROTATE, 0x00); + gfx_w(regs, GFX_READ_MAP_SELECT, 0x00); + gfx_w(regs, GFX_GRAPHICS_MODE, 0x00); + gfx_w(regs, GFX_MISC, 0x05); + gfx_w(regs, GFX_COLOR_XCARE, 0x0f); + gfx_w(regs, GFX_BITMASK, 0xff); + + reg_r(regs, ACT_ADDRESS_RESET); + attr_w(regs, ACT_PALETTE0 , 0x00); + attr_w(regs, ACT_PALETTE1 , 0x01); + attr_w(regs, ACT_PALETTE2 , 0x02); + attr_w(regs, ACT_PALETTE3 , 0x03); + attr_w(regs, ACT_PALETTE4 , 0x04); + attr_w(regs, ACT_PALETTE5 , 0x05); + attr_w(regs, ACT_PALETTE6 , 0x06); + attr_w(regs, ACT_PALETTE7 , 0x07); + attr_w(regs, ACT_PALETTE8 , 0x08); + attr_w(regs, ACT_PALETTE9 , 0x09); + attr_w(regs, ACT_PALETTE10, 0x0a); + attr_w(regs, ACT_PALETTE11, 0x0b); + attr_w(regs, ACT_PALETTE12, 0x0c); + attr_w(regs, ACT_PALETTE13, 0x0d); + attr_w(regs, ACT_PALETTE14, 0x0e); + attr_w(regs, ACT_PALETTE15, 0x0f); + reg_r(regs, ACT_ADDRESS_RESET); + + attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ + + attr_w(regs, ACT_OVERSCAN_COLOR, 0x00); + attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f); + attr_w(regs, ACT_HOR_PEL_PANNING, 0x00); + attr_w(regs, ACT_COLOR_SELECT, 0x00); + + reg_r(regs, ACT_ADDRESS_RESET); + reg_w(regs, ACT_DATA, 0x20); + + reg_w(regs, VDAC_MASK, 0xff); /* * Extended palette adressing ??? */ switch (bpp){ case 8: - reg_w(0x83c6, 0x00); + reg_w(regs, 0x83c6, 0x00); break; case 16: - reg_w(0x83c6, 0x60); + reg_w(regs, 0x83c6, 0x60); break; case 24: - reg_w(0x83c6, 0xe0); + reg_w(regs, 0x83c6, 0xe0); break; default: printk("Illegal color-depth: %i\n", bpp); } - reg_w(VDAC_ADDRESS, 0x00); - - seq_w(SEQ_MAP_MASK, 0x0f ); - - return 0; -} - -/* - * Initialization - * - * Set the default video mode for this chipset. If a video mode was - * specified on the command line, it will override the default mode. - */ - -static int retz3_init(void) -{ - short i; -#if 0 - volatile unsigned long *CursorBase; -#endif - - for (i = 0; i < 256; i++){ - for (i = 0; i < 256; i++){ - retz3_color_table [i][0] = i; - retz3_color_table [i][1] = i; - retz3_color_table [i][2] = i; - retz3_color_table [i][3] = 0; - } - } - - /* Disable hardware cursor */ + reg_w(regs, VDAC_ADDRESS, 0x00); - seq_w(SEQ_CURSOR_Y_INDEX, 0x00); - -#if 0 - /* Initialize hardware cursor */ - CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); - for (i=0; i < 8; i++){ - *(CursorBase +(i*4)) = 0xffffff00; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } - for (i=8; i < 64; i++){ - *(CursorBase +(i*4)) = 0xffff0000; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } -#endif - - retz3_setcolreg (255, 56, 100, 160, 0, NULL /* unused */); - retz3_setcolreg (254, 0, 0, 0, 0, NULL /* unused */); + seq_w(regs, SEQ_MAP_MASK, 0x0f ); return 0; } @@ -831,14 +756,17 @@ static int retz3_init(void) * values in the `par' structure. */ -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, +static int retz3_encode_fix(struct fb_info *info, + struct fb_fix_screeninfo *fix, struct retz3fb_par *par) { + struct retz3_fb_info *zinfo = retz3info(info); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, retz3fb_name); - fix->smem_start = (char *)z3_fbmem; - fix->smem_len = z3_size; - fix->mmio_start = (char *)z3_regs; + fix->smem_start = (char *)(zinfo->physfbmem); + fix->smem_len = zinfo->fbsize; + fix->mmio_start = (char *)(zinfo->physregs); fix->mmio_len = 0x00c00000; fix->type = FB_TYPE_PACKED_PIXELS; @@ -846,7 +774,7 @@ static int retz3_encode_fix(struct fb_fix_screeninfo *fix, if (par->bpp == 8) fix->visual = FB_VISUAL_PSEUDOCOLOR; else - fix->visual = FB_VISUAL_DIRECTCOLOR; + fix->visual = FB_VISUAL_TRUECOLOR; fix->xpanstep = 0; fix->ypanstep = 0; @@ -944,29 +872,33 @@ static int retz3_encode_var(struct fb_var_screeninfo *var, /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. + * Set a single color register. Return != 0 for invalid regno. */ static int retz3_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info) { + struct retz3_fb_info *zinfo = retz3info(info); + volatile unsigned char *regs = zinfo->regs; + /* We'll get to this */ if (regno > 255) return 1; - retz3_color_table [regno][0] = red & 0xff; - retz3_color_table [regno][1] = green & 0xff; - retz3_color_table [regno][2] = blue & 0xff; - retz3_color_table [regno][3] = transp; + red >>= 10; + green >>= 10; + blue >>= 10; - reg_w(VDAC_ADDRESS_W, regno); - reg_w(VDAC_DATA, (red & 0xff) >> 2); - reg_w(VDAC_DATA, (green & 0xff) >> 2); - reg_w(VDAC_DATA, (blue & 0xff) >> 2); + zinfo->color_table[regno][0] = red; + zinfo->color_table[regno][1] = green; + zinfo->color_table[regno][2] = blue; + + reg_w(regs, VDAC_ADDRESS_W, regno); + reg_w(regs, VDAC_DATA, red); + reg_w(regs, VDAC_DATA, green); + reg_w(regs, VDAC_DATA, blue); return 0; } @@ -981,50 +913,32 @@ static int retz3_getcolreg(unsigned int regno, unsigned int *red, unsigned int *green, unsigned int *blue, unsigned int *transp, struct fb_info *info) { + struct retz3_fb_info *zinfo = retz3info(info); + int t; + if (regno > 255) return 1; - *red = retz3_color_table [regno][0]; - *green = retz3_color_table [regno][1]; - *blue = retz3_color_table [regno][2]; - *transp = retz3_color_table [regno][3]; + t = zinfo->color_table[regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = zinfo->color_table[regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = zinfo->color_table[regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + *transp = 0; return 0; } -/* - * (Un)Blank the screen - */ - -void retz3_blank(int blank) -{ - short i; - - if (blank) - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - } - else - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); - } -} - - -static void retz3_bitblt (struct fb_var_screeninfo *var, +static void retz3_bitblt (struct display *p, unsigned short srcx, unsigned short srcy, unsigned short destx, unsigned short desty, unsigned short width, unsigned short height, unsigned short cmd, unsigned short mask) { - - volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); - unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); + struct fb_var_screeninfo *var = &p->var; + struct retz3_fb_info *zinfo = retz3info(p->fb_info); + volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET); + unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF); unsigned short mod; unsigned long tmp; @@ -1127,55 +1041,50 @@ static void retz3_MoveCursor (unsigned short x, unsigned short y) } #endif -/* -------------------- Interfaces to hardware functions -------------------- */ - - -static struct fb_hwswitch retz3_switch = { - retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, - retz3_getcolreg, retz3_setcolreg, retz3_blank -}; - - -/* -------------------- Generic routines ------------------------------------ */ - /* * Fill the hardware's `par' structure. */ -static void retz3fb_get_par(struct retz3fb_par *par) +static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par) { - if (current_par_valid) - *par = current_par; + struct retz3_fb_info *zinfo = retz3info(info); + + if (zinfo->current_par_valid) + *par = zinfo->current_par; else - fbhw->decode_var(&retz3fb_default, par); + retz3_decode_var(&retz3fb_default, par); } -static void retz3fb_set_par(struct retz3fb_par *par) +static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par) { - current_par = *par; - current_par_valid = 1; + struct retz3_fb_info *zinfo = retz3info(info); + + zinfo->current_par = *par; + zinfo->current_par_valid = 1; } -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +static int do_fb_set_var(struct fb_info *info, + struct fb_var_screeninfo *var, int isactive) { int err, activate; struct retz3fb_par par; + struct retz3_fb_info *zinfo = retz3info(info); - if ((err = fbhw->decode_var(var, &par))) + if ((err = retz3_decode_var(var, &par))) return err; activate = var->activate; /* XXX ... what to do about isactive ? */ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) - retz3fb_set_par(&par); - fbhw->encode_var(var, &par); + retz3fb_set_par(info, &par); + retz3_encode_var(var, &par); var->activate = activate; - retz3_set_video(var, ¤t_par); + retz3_set_video(info, var, &zinfo->current_par); return 0; } @@ -1183,15 +1092,15 @@ static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) static void do_install_cmap(int con, struct fb_info *info) { - if (con != currcon) + struct retz3_fb_info *zinfo = retz3info(info); + + if (con != zinfo->currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - fbhw->setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, - fbhw->setcolreg, info); + 1, retz3_setcolreg, info); } @@ -1227,10 +1136,10 @@ static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, int error = 0; if (con == -1) - retz3fb_get_par(&par); + retz3fb_get_par(info, &par); else - error = fbhw->decode_var(&fb_display[con].var, &par); - return(error ? error : fbhw->encode_fix(fix, &par)); + error = retz3_decode_var(&fb_display[con].var, &par); + return(error ? error : retz3_encode_fix(info, fix, &par)); } @@ -1245,8 +1154,8 @@ static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, int error = 0; if (con == -1) { - retz3fb_get_par(&par); - error = fbhw->encode_var(var, &par); + retz3fb_get_par(info, &par); + error = retz3_encode_var(var, &par); } else *var = fb_display[con].var; return error; @@ -1258,18 +1167,19 @@ static void retz3fb_set_disp(int con, struct fb_info *info) { struct fb_fix_screeninfo fix; struct display *display; + struct retz3_fb_info *zinfo = retz3info(info); if (con >= 0) display = &fb_display[con]; else - display = &disp; /* used during initialization */ + display = &zinfo->disp; /* used during initialization */ retz3fb_get_fix(&fix, con, info); if (con == -1) con = 0; - display->screen_base = fix.smem_start; + display->screen_base = (char *)zinfo->fbmem; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1277,6 +1187,12 @@ static void retz3fb_set_disp(int con, struct fb_info *info) display->ywrapstep = fix.ywrapstep; display->can_soft_blank = 1; display->inverse = z3fb_inverse; + + /* + * This seems to be about 20% faster. + */ + display->scrollmode = SCROLL_YREDRAW; + switch (display->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB8 case 8: @@ -1293,12 +1209,13 @@ static void retz3fb_set_disp(int con, struct fb_info *info) break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } } #endif + /* * Set the User Defined Part of the Display */ @@ -1308,18 +1225,14 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, { int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; struct display *display; + struct retz3_fb_info *zinfo = retz3info(info); if (con >= 0) display = &fb_display[con]; else - display = &disp; /* used during initialization */ - -#if 0 - if (con == -1) - con = 0; -#endif + display = &zinfo->disp; /* used during initialization */ - if ((err = do_fb_set_var(var, con == currcon))) + if ((err = do_fb_set_var(info, var, con == zinfo->currcon))) return err; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres = display->var.xres; @@ -1339,7 +1252,7 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_fix_screeninfo fix; retz3fb_get_fix(&fix, con, info); - display->screen_base = fix.smem_start; + display->screen_base = (char *)zinfo->fbmem; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1364,14 +1277,14 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } /* retz3fb_set_disp(con, info); */ - if (fb_info.changevar) - (*fb_info.changevar)(con); + if (info->changevar) + (*info->changevar)(con); } if (oldbpp != var->bits_per_pixel) { @@ -1391,9 +1304,10 @@ static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console? */ - return(fb_get_cmap(cmap, &fb_display[con].var, kspc, - fbhw->getcolreg, info)); + struct retz3_fb_info *zinfo = retz3info(info); + + if (con == zinfo->currcon) /* current console? */ + return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info)); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -1411,6 +1325,7 @@ static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { int err; + struct retz3_fb_info *zinfo = retz3info(info); if (!fb_display[con].cmap.len) { /* no colormap allocated? */ if ((err = fb_alloc_cmap(&fb_display[con].cmap, @@ -1418,9 +1333,8 @@ static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 0))) return err; } - if (con == currcon) /* current console? */ - return(fb_set_cmap(cmap, &fb_display[con].var, kspc, - fbhw->setcolreg, info)); + if (con == zinfo->currcon) /* current console? */ + return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info)); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -1463,8 +1377,6 @@ __initfunc(void retz3fb_setup(char *options, int *ints)) { char *this_opt; - fb_info.fontname[0] = '\0'; - if (!options || !*options) return; @@ -1473,9 +1385,10 @@ __initfunc(void retz3fb_setup(char *options, int *ints)) if (!strcmp(this_opt, "inverse")) { z3fb_inverse = 1; fb_invert_cmaps(); - } else if (!strncmp(this_opt, "font:", 5)) - strcpy(fb_info.fontname, this_opt+5); - else + } else if (!strncmp(this_opt, "font:", 5)) { + strncpy(fontname, this_opt+5, 39); + fontname[39] = '\0'; + }else z3fb_mode = get_video_mode(this_opt); } } @@ -1490,58 +1403,79 @@ __initfunc(void retz3fb_init(void)) unsigned long board_addr, board_size; unsigned int key; const struct ConfigDev *cd; - + volatile unsigned char *regs; struct retz3fb_par par; + struct retz3_fb_info *zinfo; + struct fb_info *fb_info; + short i; if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0))) return; + if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), GFP_KERNEL))) + return; + memset(zinfo, 0, sizeof(struct retz3_fb_info)); + cd = zorro_get_board (key); zorro_config_board (key, 0); board_addr = (unsigned long)cd->cd_BoardAddr; board_size = (unsigned long)cd->cd_BoardSize; - z3_mem = kernel_map (board_addr, board_size, - KERNELMAP_NOCACHE_SER, NULL); - - z3_regs = (char*) z3_mem; - z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; - + zinfo->base = kernel_map (board_addr, board_size, + KERNELMAP_NOCACHE_SER, NULL); + zinfo->regs = (unsigned char *)(zinfo->base); + zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET; /* Get memory size - for now we asume its a 4MB board */ + zinfo->fbsize = 0x00400000; /* 4 MB */ + zinfo->physregs = board_addr; + zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET; - z3_size = 0x00400000; /* 4 MB */ - - fbhw = &retz3_switch; + fb_info = fbinfo(zinfo); - fbhw->init(); + for (i = 0; i < 256; i++){ + for (i = 0; i < 256; i++){ + zinfo->color_table[i][0] = i; + zinfo->color_table[i][1] = i; + zinfo->color_table[i][2] = i; + } + } - strcpy(fb_info.modename, retz3fb_name); - fb_info.changevar = NULL; - fb_info.node = -1; - fb_info.fbops = &retz3fb_ops; - fb_info.disp = &disp; - fb_info.switch_con = &z3fb_switch; - fb_info.updatevar = &z3fb_updatevar; - fb_info.blank = &z3fb_blank; + regs = zinfo->regs; + /* Disable hardware cursor */ + seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00); + + retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info); + retz3_setcolreg (254, 0, 0, 0, 0, fb_info); + + strcpy(fb_info->modename, retz3fb_name); + fb_info->changevar = NULL; + fb_info->node = -1; + fb_info->fbops = &retz3fb_ops; + fb_info->disp = &zinfo->disp; + fb_info->switch_con = &z3fb_switch; + fb_info->updatevar = &z3fb_updatevar; + fb_info->blank = &z3fb_blank; + fb_info->flags = FBINFO_FLAG_DEFAULT; + strncpy(fb_info->fontname, fontname, 40); if (z3fb_mode == -1) retz3fb_default = retz3fb_predefined[0].var; - fbhw->decode_var(&retz3fb_default, &par); - fbhw->encode_var(&retz3fb_default, &par); + retz3_decode_var(&retz3fb_default, &par); + retz3_encode_var(&retz3fb_default, &par); - do_fb_set_var(&retz3fb_default, 0); - retz3fb_get_var(&disp.var, -1, &fb_info); + do_fb_set_var(fb_info, &retz3fb_default, 0); + retz3fb_get_var(&zinfo->disp.var, -1, fb_info); - retz3fb_set_disp(-1, &fb_info); + retz3fb_set_disp(-1, fb_info); - do_install_cmap(0, &fb_info); + do_install_cmap(0, fb_info); - if (register_framebuffer(&fb_info) < 0) + if (register_framebuffer(fb_info) < 0) return; printk("fb%d: %s frame buffer device, using %ldK of video memory\n", - GET_FB_IDX(fb_info.node), fb_info.modename, z3_size>>10); + GET_FB_IDX(fb_info->node), fb_info->modename,zinfo->fbsize>>10); /* TODO: This driver cannot be unloaded yet */ MOD_INC_USE_COUNT; @@ -1550,14 +1484,15 @@ __initfunc(void retz3fb_init(void)) static int z3fb_switch(int con, struct fb_info *info) { + struct retz3_fb_info *zinfo = retz3info(info); + /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, - &fb_display[currcon].var, 1, fbhw->getcolreg, - info); + if (fb_display[zinfo->currcon].cmap.len) + fb_get_cmap(&fb_display[zinfo->currcon].cmap, 1, + retz3_getcolreg, info); - do_fb_set_var(&fb_display[con].var, 1); - currcon = con; + do_fb_set_var(info, &fb_display[con].var, 1); + zinfo->currcon = con; /* Install new colormap */ do_install_cmap(con, info); return 0; @@ -1583,7 +1518,24 @@ static int z3fb_updatevar(int con, struct fb_info *info) static void z3fb_blank(int blank, struct fb_info *info) { - fbhw->blank(blank); + struct retz3_fb_info *zinfo = retz3info(info); + volatile unsigned char *regs = retz3info(info)->regs; + short i; + + if (blank) + for (i = 0; i < 256; i++){ + reg_w(regs, VDAC_ADDRESS_W, i); + reg_w(regs, VDAC_DATA, 0); + reg_w(regs, VDAC_DATA, 0); + reg_w(regs, VDAC_DATA, 0); + } + else + for (i = 0; i < 256; i++){ + reg_w(regs, VDAC_ADDRESS_W, i); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]); + reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]); + } } @@ -1628,31 +1580,31 @@ void cleanup_module(void) */ #ifdef FBCON_HAS_CFB8 -static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, int dy, int dx, - int height, int width) +static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx, + int dy, int dx, int height, int width) { - int fontwidth = p->fontwidth; + int fontwidth = fontwidth(p); sx *= fontwidth; dx *= fontwidth; width *= fontwidth; - retz3_bitblt(&p->var, + retz3_bitblt(p, (unsigned short)sx, - (unsigned short)(sy*p->fontheight), + (unsigned short)(sy*fontheight(p)), (unsigned short)dx, - (unsigned short)(dy*p->fontheight), + (unsigned short)(dy*fontheight(p)), (unsigned short)width, - (unsigned short)(height*p->fontheight), + (unsigned short)(height*fontheight(p)), Z3BLTcopy, 0xffff); } -static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int - sy, int sx, int height, int width) +static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, + int sy, int sx, int height, int width) { unsigned short col; - int fontwidth = p->fontwidth; + int fontwidth = fontwidth(p); sx *= fontwidth; width *= fontwidth; @@ -1661,13 +1613,13 @@ static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p, int col &= 0xff; col |= (col << 8); - retz3_bitblt(&p->var, + retz3_bitblt(p, (unsigned short)sx, - (unsigned short)(sy*p->fontheight), + (unsigned short)(sy*fontheight(p)), (unsigned short)sx, - (unsigned short)(sy*p->fontheight), + (unsigned short)(sy*fontheight(p)), (unsigned short)width, - (unsigned short)(height*p->fontheight), + (unsigned short)(height*fontheight(p)), Z3BLTset, col); } diff --git a/drivers/video/retz3fb.h b/drivers/video/retz3fb.h index 149842860..5cc751067 100644 --- a/drivers/video/retz3fb.h +++ b/drivers/video/retz3fb.h @@ -16,40 +16,40 @@ /* * Macros to read and write to registers. */ -#define reg_w(reg,dat) (*(z3_regs + reg) = dat) -#define reg_r(reg) (*(z3_regs + reg)) +#define reg_w(regs, reg,dat) (*(regs + reg) = dat) +#define reg_r(regs, reg) (*(regs + reg)) /* * Macro to access the sequencer. */ -#define seq_w(sreg,sdat) \ - do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) +#define seq_w(regs, sreg, sdat) \ + do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0) /* * Macro to access the CRT controller. */ -#define crt_w(creg,cdat) \ - do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) +#define crt_w(regs, creg, cdat) \ + do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0) /* * Macro to access the graphics controller. */ -#define gfx_w(greg,gdat) \ - do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) +#define gfx_w(regs, greg, gdat) \ + do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0) /* * Macro to access the attribute controller. */ -#define attr_w(areg,adat) \ - do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) +#define attr_w(regs, areg, adat) \ + do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0) /* * Macro to access the pll. */ -#define pll_w(preg,pdat) \ - do{ reg_w(PLL_IDX, preg); \ - reg_w(PLL_DATA, (pdat & 0xff)); \ - reg_w(PLL_DATA, (pdat >> 8));\ +#define pll_w(regs, preg, pdat) \ + do{ reg_w(regs, PLL_IDX, preg); \ + reg_w(regs, PLL_DATA, (pdat & 0xff)); \ + reg_w(regs, PLL_DATA, (pdat >> 8));\ } while(0) /* diff --git a/drivers/video/s3blit.h b/drivers/video/s3blit.h deleted file mode 100644 index ef9340770..000000000 --- a/drivers/video/s3blit.h +++ /dev/null @@ -1,74 +0,0 @@ -/* s3 commands */ -#define S3_BITBLT 0xc011 -#define S3_TWOPOINTLINE 0x2811 -#define S3_FILLEDRECT 0x40b1 - -#define S3_FIFO_EMPTY 0x0400 -#define S3_HDW_BUSY 0x0200 - -/* Enhanced register mapping (MMIO mode) */ - -#define S3_READ_SEL 0xbee8 /* offset f */ -#define S3_MULT_MISC 0xbee8 /* offset e */ -#define S3_ERR_TERM 0x92e8 -#define S3_FRGD_COLOR 0xa6e8 -#define S3_BKGD_COLOR 0xa2e8 -#define S3_PIXEL_CNTL 0xbee8 /* offset a */ -#define S3_FRGD_MIX 0xbae8 -#define S3_BKGD_MIX 0xb6e8 -#define S3_CUR_Y 0x82e8 -#define S3_CUR_X 0x86e8 -#define S3_DESTY_AXSTP 0x8ae8 -#define S3_DESTX_DIASTP 0x8ee8 -#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ -#define S3_MAJ_AXIS_PCNT 0x96e8 -#define S3_CMD 0x9ae8 -#define S3_GP_STAT 0x9ae8 -#define S3_ADVFUNC_CNTL 0x4ae8 -#define S3_WRT_MASK 0xaae8 -#define S3_RD_MASK 0xaee8 - -/* Enhanced register mapping (Packed MMIO mode, write only) */ -#define S3_ALT_CURXY 0x8100 -#define S3_ALT_CURXY2 0x8104 -#define S3_ALT_STEP 0x8108 -#define S3_ALT_STEP2 0x810c -#define S3_ALT_ERR 0x8110 -#define S3_ALT_CMD 0x8118 -#define S3_ALT_MIX 0x8134 -#define S3_ALT_PCNT 0x8148 -#define S3_ALT_PAT 0x8168 - -/* Drawing modes */ -#define S3_NOTCUR 0x0000 -#define S3_LOGICALZERO 0x0001 -#define S3_LOGICALONE 0x0002 -#define S3_LEAVEASIS 0x0003 -#define S3_NOTNEW 0x0004 -#define S3_CURXORNEW 0x0005 -#define S3_NOT_CURXORNEW 0x0006 -#define S3_NEW 0x0007 -#define S3_NOTCURORNOTNEW 0x0008 -#define S3_CURORNOTNEW 0x0009 -#define S3_NOTCURORNEW 0x000a -#define S3_CURORNEW 0x000b -#define S3_CURANDNEW 0x000c -#define S3_NOTCURANDNEW 0x000d -#define S3_CURANDNOTNEW 0x000e -#define S3_NOTCURANDNOTNEW 0x000f - -#define S3_CRTC_ADR 0x03d4 -#define S3_CRTC_DATA 0x03d5 - -#define S3_REG_LOCK2 0x39 -#define S3_HGC_MODE 0x45 - -#define S3_HWGC_ORGX_H 0x46 -#define S3_HWGC_ORGX_L 0x47 -#define S3_HWGC_ORGY_H 0x48 -#define S3_HWGC_ORGY_L 0x49 -#define S3_HWGC_DX 0x4e -#define S3_HWGC_DY 0x4f - - -#define S3_LAW_CTL 0x58 diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c index a771c37bd..f4fbe2ec5 100644 --- a/drivers/video/sbusfb.c +++ b/drivers/video/sbusfb.c @@ -40,8 +40,11 @@ #include <linux/vt_kern.h> #include <asm/uaccess.h> +#include <asm/pgtable.h> /* io_remap_page_range() */ -#include "sbusfb.h" +#include <video/sbusfb.h> + +#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5) /* * Interface used by the world @@ -53,6 +56,7 @@ void sbusfb_setup(char *options, int *ints); static int currcon; static int defx_margin = -1, defy_margin = -1; static char fontname[40] __initdata = { 0 }; +static int curblink __initdata = 1; static struct { int depth; int xres, yres; @@ -88,8 +92,6 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); static void sbusfb_cursor(struct display *p, int mode, int x, int y); static void sbusfb_clear_margin(struct display *p, int s); -extern int io_remap_page_range(unsigned long from, unsigned long offset, - unsigned long size, pgprot_t prot, int space); /* @@ -143,8 +145,10 @@ static int sbusfb_release(struct fb_info *info, int user) if (user) { if (fb->vtconsole != -1) { vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; - if (fb->mmaped) + if (fb->mmaped) { + fb->graphmode--; sbusfb_clear_margin(&fb_display[fb->vtconsole], 0); + } } if (fb->reset) fb->reset(fb); @@ -180,7 +184,8 @@ static int sbusfb_mmap(struct fb_info *info, struct file *file, #ifdef __sparc_v9__ /* Align it as much as desirable */ { - int j, max = -1, alignment, s = 0; + unsigned long j, alignment, s = 0; + int max = -1; map_offset = vma->vm_offset+size; for (i = 0; fb->mmap_map[i].size; i++) { @@ -247,7 +252,9 @@ static int sbusfb_mmap(struct fb_info *info, struct file *file, fb->mmaped = 1; if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { fb->vtconsole = lastconsole; + fb->graphmode++; vt_cons [lastconsole]->vc_mode = KD_GRAPHICS; + vc_cons[lastconsole].d->vc_sw->con_cursor(vc_cons[lastconsole].d,CM_ERASE); } else if (fb->unblank && !fb->blanked) (*fb->unblank)(fb); } @@ -258,6 +265,8 @@ static void sbusfb_clear_margin(struct display *p, int s) { struct fb_info_sbusfb *fb = sbusfbinfod(p); + if (fb->switch_from_graph) + (*fb->switch_from_graph)(fb); if (fb->fill) { unsigned short rects [16]; @@ -289,13 +298,13 @@ static void sbusfb_clear_margin(struct display *p, int s) fb_base -= (skip_bytes + fb->x_margin) / 8; skip_bytes /= 8; scr_size /= 8; - memset (fb_base, ~0, skip_bytes - fb->x_margin / 8); - memset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, ~0, skip_bytes - fb->x_margin / 8); + mymemset (fb_base, skip_bytes - fb->x_margin / 8); + mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8); incr = fb->var.xres_virtual / 8; size = fb->x_margin / 8 * 2; for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0; h <= he; q += incr, h++) - memset (q, ~0, size); + mymemset (q, size); } else { fb_base -= (skip_bytes + fb->x_margin); memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); @@ -307,8 +316,6 @@ static void sbusfb_clear_margin(struct display *p, int s) memset (q, attr_bgcol(p,s), size); } } - if (fb->switch_from_graph) - (*fb->switch_from_graph)(fb); } static void sbusfb_disp_setup(struct display *p) @@ -414,13 +421,13 @@ static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb) copy_from_user (fb->cursor.bits [1], f.image, bytes)) return -EFAULT; if (f.size.fbx <= 32) { - u = ~(0xffffffff >> f.size.fbx); + u = 0xffffffff << (32 - f.size.fbx); for (i = fb->cursor.size.fby - 1; i >= 0; i--) { fb->cursor.bits [0][i] &= u; fb->cursor.bits [1][i] &= fb->cursor.bits [0][i]; } } else { - u = ~(0xffffffff >> (f.size.fbx - 32)); + u = 0xffffffff << (64 - f.size.fbx); for (i = fb->cursor.size.fby - 1; i >= 0; i--) { fb->cursor.bits [0][2*i+1] &= u; fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i]; @@ -443,42 +450,58 @@ static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb) static unsigned char hw_cursor_cmap[2] = { 0, 0xff }; +static void +sbusfb_cursor_timer_handler(unsigned long dev_addr) +{ + struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr; + + if (!fb->setcursor) return; + + if (fb->cursor.mode != 2) { + fb->cursor.enable ^= 1; + fb->setcursor(fb); + } + + fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate; + add_timer(&fb->cursor.timer); +} + static void sbusfb_cursor(struct display *p, int mode, int x, int y) { struct fb_info_sbusfb *fb = sbusfbinfod(p); switch (mode) { case CM_ERASE: + fb->cursor.mode = 2; fb->cursor.enable = 0; (*fb->setcursor)(fb); - fb->hw_cursor_shown = 0; break; case CM_MOVE: case CM_DRAW: - if (!fb->hw_cursor_shown) { - fb->cursor.size.fbx = p->fontwidth; - fb->cursor.size.fby = p->fontheight; + if (fb->cursor.mode) { + fb->cursor.size.fbx = fontwidth(p); + fb->cursor.size.fby = fontheight(p); fb->cursor.chot.fbx = 0; fb->cursor.chot.fby = 0; fb->cursor.enable = 1; memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits)); - fb->cursor.bits[0][p->fontheight - 2] = (0xffffffff << (32 - p->fontwidth)); - fb->cursor.bits[1][p->fontheight - 2] = (0xffffffff << (32 - p->fontwidth)); - fb->cursor.bits[0][p->fontheight - 1] = (0xffffffff << (32 - p->fontwidth)); - fb->cursor.bits[1][p->fontheight - 1] = (0xffffffff << (32 - p->fontwidth)); + fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p))); + fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p))); (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap); (*fb->setcurshape) (fb); - fb->hw_cursor_shown = 1; + fb->cursor.mode = 0; } - if (p->fontwidthlog) - fb->cursor.cpos.fbx = (x << p->fontwidthlog) + fb->x_margin; + if (fontwidthlog(p)) + fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin; else - fb->cursor.cpos.fbx = (x * p->fontwidth) + fb->x_margin; - if (p->fontheightlog) - fb->cursor.cpos.fby = (y << p->fontheightlog) + fb->y_margin; + fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin; + if (fontheightlog(p)) + fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin; else - fb->cursor.cpos.fby = (y * p->fontheight) + fb->y_margin; + fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin; (*fb->setcursor)(fb); break; } @@ -492,7 +515,7 @@ static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, sbusfb_getcolreg, info); + return fb_get_cmap(cmap, kspc, sbusfb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -514,12 +537,12 @@ static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, &fb_display[con].var, kspc, sbusfb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, sbusfb_setcolreg, info); if (!err) { struct fb_info_sbusfb *fb = sbusfbinfo(info); if (fb->loadcmap) - (*fb->loadcmap)(fb, cmap->start, cmap->len); + (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len); } return err; } else @@ -610,7 +633,7 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, __put_user_ret(fb->color_map CM(i,2), bp, -EFAULT); rp++; gp++; bp++; } - (*fb->loadcmap)(fb, index, count); + (*fb->loadcmap)(fb, NULL, index, count); break; } case FBIOPUTCMAP_SPARC: { /* load color map entries */ @@ -643,7 +666,7 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, __get_user_ret(fb->color_map CM(i,2), bp, -EFAULT); rp++; gp++; bp++; } - (*fb->loadcmap)(fb, index, count); + (*fb->loadcmap)(fb, NULL, index, count); break; } case FBIOGCURMAX: { @@ -661,7 +684,7 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, lastconsole = info->display_fg->vc_num; if (vt_cons[lastconsole]->vc_mode == KD_TEXT) return -EINVAL; /* Don't let graphics programs hide our nice text cursor */ - fb->hw_cursor_shown = 0; /* Forget state of our text cursor */ + fb->cursor.mode = 2; /* Forget state of our text cursor */ } return sbus_hw_scursor ((struct fbcursor *) arg, fb); @@ -678,7 +701,8 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, (*fb->setcursor) (fb); break; default: - /* FIXME: Call here possible fb specific ioctl */ + if (fb->ioctl) + return fb->ioctl(fb, cmd, arg); return -EINVAL; } return 0; @@ -714,7 +738,8 @@ __initfunc(void sbusfb_setup(char *options, int *ints)) break; memcpy(fontname, p+5, i); fontname[i] = 0; - } + } else if (!strncmp(p, "noblink", 7)) + curblink = 0; while (*p && *p != ' ' && *p != ',') p++; if (*p != ',') break; p++; @@ -729,18 +754,20 @@ static int sbusfbcon_switch(int con, struct fb_info *info) /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, sbusfb_getcolreg, info); - - lastconsole = info->display_fg->vc_num; - if (lastconsole != con && - (fb_display[lastconsole].fontwidth != fb_display[con].fontwidth || - fb_display[lastconsole].fontheight != fb_display[con].fontheight)) - fb->hw_cursor_shown = 0; + fb_get_cmap(&fb_display[currcon].cmap, 1, sbusfb_getcolreg, info); + + if (info->display_fg) { + lastconsole = info->display_fg->vc_num; + if (lastconsole != con && + (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) || + fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con]))) + fb->cursor.mode = 1; + } x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2; y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2; if (fb->margins) fb->margins(fb, &fb_display[con], x_margin, y_margin); - if (fb->x_margin != x_margin || fb->y_margin != y_margin) { + if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) { fb->x_margin = x_margin; fb->y_margin = y_margin; sbusfb_clear_margin(&fb_display[con], 0); } @@ -786,9 +813,10 @@ static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, if (!fb->color_map || regno > 255) return 1; - *red = fb->color_map CM(regno, 0); - *green = fb->color_map CM(regno, 1); - *blue = fb->color_map CM(regno, 2); + *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0); + *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1); + *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2); + *transp = 0; return 0; } @@ -806,6 +834,9 @@ static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, if (!fb->color_map || regno > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; fb->color_map CM(regno, 0) = red; fb->color_map CM(regno, 1) = green; fb->color_map CM(regno, 2) = blue; @@ -820,13 +851,12 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - sbusfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, sbusfb_setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, sbusfb_setcolreg, info); + 1, sbusfb_setcolreg, info); if (fb->loadcmap) - (*fb->loadcmap)(fb, 0, 256); + (*fb->loadcmap)(fb, &fb_display[con], 0, 256); } static int sbusfb_set_font(struct display *p, int width, int height) @@ -859,7 +889,7 @@ static int sbusfb_set_font(struct display *p, int width, int height) p->var.xres = w - 2*x_margin; p->var.yres = h - 2*y_margin; - fb->hw_cursor_shown = 0; + fb->cursor.mode = 1; if (fb->margins) fb->margins(fb, p, x_margin, y_margin); @@ -987,6 +1017,7 @@ sizechange: fb->info.switch_con = &sbusfbcon_switch; fb->info.updatevar = &sbusfbcon_updatevar; fb->info.blank = &sbusfbcon_blank; + fb->info.flags = FBINFO_FLAG_DEFAULT; fb->cursor.hwsize.fbx = 32; fb->cursor.hwsize.fby = 32; @@ -1034,8 +1065,17 @@ sizechange: goto sizechange; disp->dispsw = &fb->dispsw; - if (fb->setcursor) + if (fb->setcursor) { fb->dispsw.cursor = sbusfb_cursor; + if (curblink) { + fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE; + init_timer(&fb->cursor.timer); + fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate; + fb->cursor.timer.data = (unsigned long)fb; + fb->cursor.timer.function = sbusfb_cursor_timer_handler; + add_timer(&fb->cursor.timer); + } + } fb->dispsw.set_font = sbusfb_set_font; fb->setup = fb->dispsw.setup; fb->dispsw.setup = sbusfb_disp_setup; diff --git a/drivers/video/sbusfb.h b/drivers/video/sbusfb.h deleted file mode 100644 index f65ca1d71..000000000 --- a/drivers/video/sbusfb.h +++ /dev/null @@ -1,116 +0,0 @@ -#include <asm/sbus.h> -#include <asm/oplib.h> -#include <asm/fbio.h> - -#include "fbcon.h" - -struct bt_regs { - volatile unsigned int addr; /* address register */ - volatile unsigned int color_map; /* color map */ - volatile unsigned int control; /* control register */ - volatile unsigned int cursor; /* cursor map register */ -}; - -struct fb_info_creator { - struct ffb_fbc *fbc; - struct ffb_dac *dac; - int dac_rev; - int xy_margin; -}; -struct fb_info_cgsix { - struct bt_regs *bt; - struct cg6_fbc *fbc; - struct cg6_thc *thc; - struct cg6_tec *tec; - volatile u32 *fhc; -}; -struct fb_info_bwtwo { - struct bw2_regs *regs; -}; -struct fb_info_cgthree { - struct cg3_regs *regs; -}; -struct fb_info_tcx { - struct bt_regs *bt; - struct tcx_thc *thc; - struct tcx_tec *tec; - u32 *cplane; -}; - -struct cg_cursor { - short enable; /* cursor is enabled */ - struct fbcurpos cpos; /* position */ - struct fbcurpos chot; /* hot-spot */ - struct fbcurpos size; /* size of mask & image fields */ - struct fbcurpos hwsize; /* hw max size */ - int bits[2][128]; /* space for mask & image bits */ - char color [6]; /* cursor colors */ -}; - -struct sbus_mmap_map { - unsigned long voff; - unsigned long poff; - unsigned long size; -}; - -#define SBUS_MMAP_FBSIZE(n) (-n) -#define SBUS_MMAP_EMPTY 0x80000000 - -struct fb_info_sbusfb { - struct fb_info info; - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; - struct display disp; - struct display_switch dispsw; - struct fbtype type; - struct linux_sbus_device *sbdp; - int prom_node, prom_parent; - union { - struct fb_info_creator ffb; - struct fb_info_cgsix cg6; - struct fb_info_bwtwo bw2; - struct fb_info_cgthree cg3; - struct fb_info_tcx tcx; - } s; - unsigned char *color_map; - struct cg_cursor cursor; - unsigned char hw_cursor_shown; - unsigned char open; - unsigned char mmaped; - unsigned char blanked; - int x_margin; - int y_margin; - int vtconsole; - int consolecnt; - int emulations[4]; - struct sbus_mmap_map *mmap_map; - unsigned long physbase; - int iospace; - /* Methods */ - void (*setup)(struct display *); - void (*setcursor)(struct fb_info_sbusfb *); - void (*setcurshape)(struct fb_info_sbusfb *); - void (*setcursormap)(struct fb_info_sbusfb *, unsigned char *, unsigned char *, unsigned char *); - void (*loadcmap)(struct fb_info_sbusfb *, int, int); - void (*blank)(struct fb_info_sbusfb *); - void (*unblank)(struct fb_info_sbusfb *); - void (*margins)(struct fb_info_sbusfb *, struct display *, int, int); - void (*reset)(struct fb_info_sbusfb *); - void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *); - void (*switch_from_graph)(struct fb_info_sbusfb *); - void (*restore_palette)(struct fb_info_sbusfb *); -}; - -extern char *creatorfb_init(struct fb_info_sbusfb *); -extern char *cgsixfb_init(struct fb_info_sbusfb *); -extern char *cgthreefb_init(struct fb_info_sbusfb *); -extern char *tcxfb_init(struct fb_info_sbusfb *); -extern char *leofb_init(struct fb_info_sbusfb *); -extern char *bwtwofb_init(struct fb_info_sbusfb *); -extern char *cgfourteenfb_init(struct fb_info_sbusfb *); - -#define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info)) -#define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info)) -#define CM(i, j) [3*(i)+(j)] - -#define SBUSFBINIT_SIZECHANGE ((char *)-1) diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 1831e6b33..a99a3a0cd 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -17,8 +17,9 @@ #include <linux/malloc.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/init.h> -#include "fbcon.h" +#include <video/fbcon.h> /* @@ -83,13 +84,15 @@ static void xxx_detect(void) * it as the default video mode */ + struct xxxfb_par par; + /* ... */ xxx_get_par(&par); xxx_encode_var(&default_var, &par); } static int xxx_encode_fix(struct fb_fix_screeninfo *fix, struct xxxfb_par *par, - const struct fb_info *fb_info) + const struct fb_info *info) { /* * This function should fill in the 'fix' structure based on the values @@ -101,7 +104,7 @@ static int xxx_encode_fix(struct fb_fix_screeninfo *fix, struct xxxfb_par *par, } static int xxx_decode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par, - const struct fb_info *fb_info) + const struct fb_info *info) { /* * Get the video params out of 'var'. If a value doesn't fit, round it up, @@ -122,7 +125,7 @@ static int xxx_decode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par, } static int xxx_encode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par, - const struct fb_info *fb_info) + const struct fb_info *info) { /* * Fill the 'var' structure based on the values in 'par' and maybe other @@ -133,7 +136,7 @@ static int xxx_encode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par, return 0; } -static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *fb_info) +static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *info) { /* * Fill the hardware's 'par' structure. @@ -146,7 +149,7 @@ static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *fb_info) } } -static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *fb_info) +static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *info) { /* * Set the hardware according to 'par'. @@ -159,10 +162,11 @@ static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *fb_info) static int xxx_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, - const struct fb_info *fb_info) + const struct fb_info *info) { /* * Read a single color register and split it into colors/transparent. + * The return values must have a 16 bit magnitude. * Return != 0 for invalid regno. */ @@ -172,12 +176,12 @@ static int xxx_getcolreg(unsigned regno, unsigned *red, unsigned *green, static int xxx_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, - const struct fb_info *fb_info) + const struct fb_info *info) { /* - * Set a single color register. The values supplied are already rounded - * down to the hardware's capabilities (according to the entries in the - * `var' structure). Return != 0 for invalid regno. + * Set a single color register. The values supplied have a 16 bit + * magnitude. + * Return != 0 for invalid regno. */ if (regno < 16) { @@ -185,25 +189,29 @@ static int xxx_setcolreg(unsigned regno, unsigned red, unsigned green, * Make the first 16 colors of the palette available to fbcon */ if (is_cfb15) /* RGB 555 */ - fbcon_cfb15_cmap[regno] = be16_to_cpu((red << 10) | (green << 5) | - blue); + ...fbcon_cmap.cfb16[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); if (is_cfb16) /* RGB 565 */ - fbcon_cfb16_cmap[regno] = be16_to_cpu((red << 11) | (green << 5) | - blue); + ...fbcon_cmap.cfb16[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); if (is_cfb24) /* RGB 888 */ - fbcon_cfb24_cmap[regno] = be32_to_cpu((red << 16) | (green << 8) | - blue); + ...fbcon_cmap.cfb24[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); if (is_cfb32) /* RGBA 8888 */ - fbcon_cfb32_cmap[regno] = be32_to_cpu((red << 24) | (green << 16) | - (blue << 8) | transp); + ...fbcon_cmap.cfb32[regno] = ((red & 0xff00) << 16) | + ((green & 0xff00) << 8) | + (blue & 0xff00) | + ((transp & 0xff00) >> 8); } /* ... */ return 0; } static int xxx_pan_display(struct fb_var_screeninfo *var, - struct xxxfb_par *par, - const struct fb_info *fb_info) + struct xxxfb_par *par, const struct fb_info *info) { /* * Pan (or wrap, depending on the `vmode' field) the display using the @@ -215,7 +223,7 @@ static int xxx_pan_display(struct fb_var_screeninfo *var, return 0; } -static int xxx_blank(int blank_mode, const struct fb_info *fb_info) +static int xxx_blank(int blank_mode, const struct fb_info *info) { /* * Blank the screen if blank_mode != 0, else unblank. If blank == NULL @@ -232,30 +240,45 @@ static int xxx_blank(int blank_mode, const struct fb_info *fb_info) return 0; } -static struct display_switch *xxx_get_dispsw(const void *par, - struct fb_info_gen *info) +static void xxx_set_dispsw(const void *par, struct display *disp, + struct fb_info_gen *info) { + unsigned long flags; + /* - * Return a pointer to appropriate low level text console operations for - * the video mode `par' of your video hardware. These can be generic - * software routines, or hardware accelerated routines specifically - * tailored for your hardware. - * If you don't have any appropriate operations, simple fill in the NULL - * pointer, and there will be no text output. + * Fill in a pointer to appropriate low level text console operations (and + * optionally a pointer to help data) for the video mode `par' of your + * video hardware. These can be generic software routines, or hardware + * accelerated routines specifically tailored for your hardware. + * If you don't have any appropriate operations, you must fill in a + * pointer to dummy operations, and there will be no text output. */ + save_flags(flags); cli(); #ifdef FBCON_HAS_CFB8 - if (is_cfb8) - return &fbcon_cfb8; + if (is_cfb8) { + disp->dispsw = fbcon_cfb8; + } else #endif #ifdef FBCON_HAS_CFB16 - if (is_cfb16) - return &fbcon_cfb16; + if (is_cfb16) { + disp->dispsw = fbcon_cfb16; + disp->dispsw_data = ...fbcon_cmap.cfb16; /* console palette */ + } else +#endif +#ifdef FBCON_HAS_CFB24 + if (is_cfb24) { + disp->dispsw = fbcon_cfb24; + disp->dispsw_data = ...fbcon_cmap.cfb24; /* console palette */ + } else #endif #ifdef FBCON_HAS_CFB32 - if (is_cfb32) - return &fbcon_cfb32; + if (is_cfb32) { + disp->dispsw = fbcon_cfb32; + disp->dispsw_data = ...fbcon_cmap.cfb32; /* console palette */ + } else #endif - return NULL; + disp->dispsw = &fbcon_dummy; + restore_flags(flags); } @@ -278,27 +301,26 @@ struct fbgen_hwswitch xxx_switch = { __initfunc(void xxxfb_init(void)) { - struct fb_var_screeninfo var; - - fb_info.fbhw = &xxx_switch; - fbhw->detect(); - strcpy(fb_info.modename, "XXX"); - fb_info.changevar = NULL; - fb_info.node = -1; - fb_info.fbops = &xxxfb_ops; - fb_info.disp = disp; - fb_info.switch_con = &xxxfb_switch; - fb_info.updatevar = &xxxfb_update_var; - fb_info.blank = &xxxfb_blank; + fb_info.gen.fbhw = &xxx_switch; + fb_info.gen.fbhw->detect(); + strcpy(fb_info.gen.info.modename, "XXX"); + fb_info.gen.info.changevar = NULL; + fb_info.gen.info.node = -1; + fb_info.gen.info.fbops = &xxxfb_ops; + fb_info.gen.info.disp = &disp; + fb_info.gen.info.switch_con = &xxxfb_switch; + fb_info.gen.info.updatevar = &xxxfb_update_var; + fb_info.gen.info.blank = &xxxfb_blank; + fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; /* This should give a reasonable default video mode */ - fbgen_get_var(&disp.var, -1, &fb_info.gen); - fbgen_do_set_var(var, 1, &fbinfo.gen); - fbgen_set_disp(-1, &fb_info.gen.info); + fbgen_get_var(&disp.var, -1, &fb_info.gen.info); + fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_set_disp(-1, &fb_info.gen); fbgen_install_cmap(0, &fb_info.gen); if (register_framebuffer(&fb_info.gen.info) < 0) return; - printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node), - fb_info.modename); + printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node), + fb_info.gen.info.modename); /* uncomment this if your driver cannot be unloaded */ /* MOD_INC_USE_COUNT; */ @@ -316,7 +338,7 @@ void xxxfb_cleanup(struct fb_info *info) * clean up all instances. */ - unregister_framebuffer(&fb_info); + unregister_framebuffer(info); /* ... */ } diff --git a/drivers/video/tcxfb.c b/drivers/video/tcxfb.c index 181b6c53e..90d6152fa 100644 --- a/drivers/video/tcxfb.c +++ b/drivers/video/tcxfb.c @@ -1,4 +1,4 @@ -/* $Id: tcxfb.c,v 1.1 1998/07/21 14:50:44 jj Exp $ +/* $Id: tcxfb.c,v 1.6 1998/09/04 15:43:46 jj Exp $ * tcxfb.c: TCX 24/8bit frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -21,10 +21,10 @@ #include <linux/init.h> #include <linux/selection.h> -#include "sbusfb.h" +#include <video/sbusfb.h> #include <asm/io.h> -#include "fbcon-cfb8.h" +#include <video/fbcon-cfb8.h> /* THC definitions */ #define TCX_THC_MISC_REV_SHIFT 16 @@ -102,7 +102,7 @@ static void tcx_switch_from_graph (struct fb_info_sbusfb *fb) tcx_set_control_plane (fb); } -static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count) +static void tcx_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) { struct bt_regs *bt = fb->s.tcx.bt; int i; @@ -113,6 +113,7 @@ static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count) bt->color_map = fb->color_map CM(i,1) << 24; bt->color_map = fb->color_map CM(i,2) << 24; } + bt->addr = 0; } static void tcx_restore_palette (struct fb_info_sbusfb *fb) @@ -211,7 +212,7 @@ __initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) struct display *disp = &fb->disp; struct fbtype *type = &fb->type; unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; - int lowdepth; + int lowdepth, i, j; #ifndef FBCON_HAS_CFB8 return NULL; @@ -265,10 +266,22 @@ __initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) fb->blank = tcx_blank; fb->unblank = tcx_unblank; fb->reset = tcx_reset; - + fb->physbase = 0; + for (i = 0; i < 13; i++) { + /* tcx_mmap_map has to be sorted by voff, while + order of phys registers from PROM differs a little + bit. Here is the correction */ + switch (i) { + case 10: j = 12; break; + case 11: + case 12: j = i - 1; break; + default: j = i; break; + } + tcx_mmap_map[i].poff = fb->sbdp->reg_addrs[j].phys_addr; + } fb->mmap_map = tcx_mmap_map; - + /* Initialize Brooktree DAC */ fb->s.tcx.bt->addr = 0x04 << 24; /* color planes */ fb->s.tcx.bt->control = 0xff << 24; @@ -278,13 +291,13 @@ __initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) fb->s.tcx.bt->control = 0x73 << 24; fb->s.tcx.bt->addr = 0x07 << 24; fb->s.tcx.bt->control = 0x00 << 24; - + sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK, lowdepth ? "8-bit only" : "24-bit depth"); tcx_reset(fb); - + return idstring; } diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index d15d87a6b..201984959 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -15,7 +15,7 @@ /* KNOWN PROBLEMS/TO DO ===================================================== * * - * - How to set a single color register? + * - How to set a single color register on 24-plane cards? * * - Hardware cursor (useful for other graphics boards too) * @@ -38,9 +38,9 @@ #include <linux/selection.h> #include <asm/io.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb32.h> /* TGA hardware description (minimal) */ @@ -242,6 +242,9 @@ static int currcon = 0; static struct display disp; static struct fb_info fb_info; static struct { u_char red, green, blue, pad; } palette[256]; +#ifdef FBCON_HAS_CFB32 +static u32 fbcon_cfb32_cmap[16]; +#endif static struct fb_fix_screeninfo fb_fix = { { "DEC TGA ", } }; static struct fb_var_screeninfo fb_var = { 0, }; @@ -404,13 +407,11 @@ static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, tgafb_getcolreg, - info); + return fb_get_cmap(cmap, kspc, tgafb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else - fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); + fb_copy_cmap(fb_default_cmap(256), cmap, kspc ? 0 : 2); return 0; } @@ -424,15 +425,14 @@ static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, int err; if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<<fb_display[con].var.bits_per_pixel, 0))) + if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0))) return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, &fb_display[con].var, kspc, tgafb_setcolreg, - info); + err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info); #if 1 - tga_update_palette(); + if (tga_type != 0) + tga_update_palette(); #endif return err; } else @@ -681,9 +681,9 @@ __initfunc(void tgafb_init(void)) TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG); } - /* finally, enable video scan & cursor + /* finally, enable video scan (and pray for the monitor... :-) */ - TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */ + TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */ fb_var.xres = fb_var.xres_virtual = 640; fb_var.yres = fb_var.yres_virtual = 480; @@ -748,10 +748,11 @@ __initfunc(void tgafb_init(void)) case 1: /* 24-plane */ case 3: /* 24plusZ */ disp.dispsw = &fbcon_cfb32; + disp.dispsw_data = &fbcon_cfb32_cmap; break; #endif default: - disp.dispsw = NULL; + disp.dispsw = &fbcon_dummy; } disp.scrollmode = SCROLL_YREDRAW; @@ -764,6 +765,7 @@ __initfunc(void tgafb_init(void)) fb_info.switch_con = &tgafbcon_switch; fb_info.updatevar = &tgafbcon_updatevar; fb_info.blank = &tgafbcon_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; tgafb_set_var(&fb_var, -1, &fb_info); @@ -779,8 +781,7 @@ static int tgafbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - tgafb_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, tgafb_getcolreg, info); currcon = con; /* Install new colormap */ @@ -804,7 +805,13 @@ static int tgafbcon_updatevar(int con, struct fb_info *info) static void tgafbcon_blank(int blank, struct fb_info *info) { - /* Nothing */ + /* Should also do stuff here for vesa blanking -tor */ + + if (blank > 0) { + TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */ + } else { + TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */ + } } /* @@ -817,9 +824,10 @@ static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, { if (regno > 255) return 1; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; + *red = (palette[regno].red<<8) | palette[regno].red; + *green = (palette[regno].green<<8) | palette[regno].green; + *blue = (palette[regno].blue<<8) | palette[regno].blue; + *transp = 0; return 0; } @@ -835,6 +843,9 @@ static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, { if (regno > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; @@ -844,7 +855,14 @@ static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; #endif - /* How to set a single color register?? */ + if (tga_type == 0) { /* 8-plane */ + BT485_WRITE(regno, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + } + /* How to set a single color register on 24-plane cards?? */ return 0; } @@ -852,31 +870,21 @@ static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, #if 1 /* - * FIXME: since I don't know how to set a single arbitrary color register, - * all color palette registers have to be updated + * FIXME: since I don't know how to set a single arbitrary color register + * on 24-plane cards, all color palette registers have to be updated */ static void tga_update_palette(void) { int i; - if (tga_type == 0) { /* 8-plane */ - BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); - TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); - for (i = 0; i < 256; i++) { - TGA_WRITE_REG(palette[i].red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - } - } else { - BT463_LOAD_ADDR(0x0000); - TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); + BT463_LOAD_ADDR(0x0000); + TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); - for (i = 0; i < 256; i++) { - TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - } + for (i = 0; i < 256; i++) { + TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG); } } #endif @@ -886,14 +894,12 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - tgafb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, tgafb_setcolreg, info); else - fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, tgafb_setcolreg, - info); + fb_set_cmap(fb_default_cmap(256), 1, tgafb_setcolreg, info); #if 1 - tga_update_palette(); + if (tga_type != 0) + tga_update_palette(); #endif } diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c new file mode 100644 index 000000000..d7f2131de --- /dev/null +++ b/drivers/video/valkyriefb.c @@ -0,0 +1,896 @@ +/* + * valkyriefb.c -- frame buffer device for the PowerMac 'valkyrie' display + * + * Created 8 August 1998 by Martin Costabel and Kevin Schoedel + * + * Vmode-switching changes and vmode 15/17 modifications created 29 August + * 1998 by Barry Nathan <barryn@pobox.com>. + * + * Derived directly from: + * + * controlfb.c -- frame buffer device for the PowerMac 'control' display + * Copyright (C) 1998 Dan Jacobowitz <dan@debian.org> + * + * pmc-valkyrie.c -- Console support for PowerMac "valkyrie" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * and indirectly: + * + * Frame buffer structure from: + * drivers/video/chipsfb.c -- frame buffer device for + * Chips & Technologies 65550 chip. + * + * Copyright (C) 1998 Paul Mackerras + * + * This file is derived from the Powermac "chips" driver: + * Copyright (C) 1997 Fabio Riccardi. + * And from the frame buffer device for Open Firmware-initialized devices: + * Copyright (C) 1997 Geert Uytterhoeven. + * + * Hardware information from: + * control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/selection.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/nvram.h> +#ifdef CONFIG_FB_COMPAT_XPMAC +#include <asm/vc_ioctl.h> +#endif +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pgtable.h> +#include <asm/adb.h> +#include <asm/cuda.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/macmodes.h> + +#include "valkyriefb.h" + +static int can_soft_blank = 1; + +static int default_vmode = VMODE_NVRAM; +static int default_cmode = CMODE_NVRAM; +static char fontname[40] __initdata = { 0 }; + +static int currcon = 0; +static int switching = 0; + +struct fb_par_valkyrie { + int vmode, cmode; + int xres, yres; + int vxres, vyres; + int xoffset, yoffset; +}; + +struct fb_info_valkyrie { + struct fb_info info; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + struct display disp; + struct fb_par_valkyrie par; + struct { + __u8 red, green, blue; + } palette[256]; + + struct cmap_regs *cmap_regs; + unsigned long cmap_regs_phys; + + struct valkyrie_regs *valkyrie_regs; + unsigned long valkyrie_regs_phys; + + __u8 *frame_buffer; + unsigned long frame_buffer_phys; + + int sense; + unsigned long total_vram; +#ifdef FBCON_HAS_CFB16 + u16 fbcon_cfb16_cmap[16]; +#endif +}; + +/* + * Exported functions + */ +void valkyriefb_init(void); +void valkyrie_of_init(struct device_node *dp); +void valkyriefb_setup(char *options, int *ints); + +static int valkyrie_open(struct fb_info *info, int user); +static int valkyrie_release(struct fb_info *info, int user); +static int valkyrie_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int valkyrie_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int valkyrie_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int valkyrie_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int valkyrie_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int valkyrie_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int valkyrie_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); + +static int read_valkyrie_sense(struct fb_info_valkyrie *p); +static inline int valkyrie_vram_reqd(int video_mode, int color_mode); +static void set_valkyrie_clock(unsigned char *params); +static void valkyrie_set_par(const struct fb_par_valkyrie *p, struct fb_info_valkyrie *info); +static inline int valkyrie_par_to_var(struct fb_par_valkyrie *par, struct fb_var_screeninfo *var); +static int valkyrie_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_valkyrie *par, const struct fb_info *fb_info); + +static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p); +static void valkyrie_par_to_display(struct fb_par_valkyrie *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p); +static void valkyrie_init_display(struct display *disp); +static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix, + struct fb_info_valkyrie *p); +static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p); + +static struct fb_ops valkyriefb_ops = { + valkyrie_open, + valkyrie_release, + valkyrie_get_fix, + valkyrie_get_var, + valkyrie_set_var, + valkyrie_get_cmap, + valkyrie_set_cmap, + valkyrie_pan_display, + valkyrie_ioctl +}; + +static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info); +static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static void do_install_cmap(int con, struct fb_info *info); + + +__openfirmware + + +static int valkyrie_open(struct fb_info *info, int user) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int valkyrie_release(struct fb_info *info, int user) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int valkyrie_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_info_valkyrie *cp = (struct fb_info_valkyrie *) info; + + *fix = cp->fix; + return 0; +} + +static int valkyrie_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_valkyrie *cp = (struct fb_info_valkyrie *) info; + + *var = cp->var; + return 0; +} + +/* Sets everything according to var */ +static int valkyrie_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + struct display *disp; + struct fb_par_valkyrie par; + int depthchange, err; + + disp = (con >= 0) ? &fb_display[con] : &p->disp; + if ((err = valkyrie_var_to_par(var, &par, info))) { + /* printk (KERN_ERR "Error in valkyrie_set_var, calling valkyrie_var_to_par: %d.\n", err); */ + return err; + } + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) { + /* printk("Not activating, in valkyrie_set_var.\n"); */ + valkyrie_par_to_var(&par, var); + return 0; + } + + /* + * I know, we want to use fb_display[con], but grab certain info + * from p->var instead. + */ +#define DIRTY(x) (p->var.x != var->x) + depthchange = DIRTY(bits_per_pixel); + /* adding "&& !DIRTY(pixclock)" corrects vmode-switching problems */ + if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) && + !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel) && !DIRTY(pixclock)) { + valkyrie_par_to_var(&par, var); + p->var = disp->var = *var; + return 0; + } + + p->par = par; + valkyrie_par_to_var(&par, var); + p->var = *var; + valkyrie_par_to_fix(&par, &p->fix, p); + valkyrie_par_to_display(&par, disp, &p->fix, p); + p->disp = *disp; + + if (info->changevar && !switching) { + /* Don't want to do this if just switching consoles. */ + (*info->changevar)(con); + } + if (con == currcon) + valkyrie_set_par(&par, p); + if (depthchange) + if ((err = fb_alloc_cmap(&disp->cmap, 0, 0))) + return err; + if (depthchange || switching) + do_install_cmap(con, info); + return 0; +} + +static int valkyrie_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (var->xoffset != 0 || var->yoffset != 0) + return -EINVAL; + return 0; +} + +static int valkyrie_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == currcon) { + /* current console? */ + return fb_get_cmap(cmap, kspc, valkyriefb_getcolreg, info); + } + if (fb_display[con].cmap.len) { /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2); + } + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + } + return 0; +} + +static int valkyrie_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + struct display *disp = &fb_display[con]; + int err; + + if (disp->cmap.len == 0) { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + err = fb_alloc_cmap(&disp->cmap, size, 0); + if (err) { + return err; + } + } + + if (con == currcon) { + return fb_set_cmap(cmap, kspc, valkyriefb_setcolreg, info); + } + fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + return 0; +} + +static int valkyrie_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + return -EINVAL; +} + +static int valkyriefb_switch(int con, struct fb_info *fb) +{ + struct fb_info_valkyrie *info = (struct fb_info_valkyrie *) fb; + struct fb_par_valkyrie par; + + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, 1, valkyriefb_getcolreg, + fb); + currcon = con; +#if 1 + valkyrie_var_to_par(&fb_display[currcon].var, &par, fb); + valkyrie_set_par(&par, info); + do_install_cmap(con, fb); +#else + /* I see no reason not to do this. Minus info->changevar(). */ + /* DOH. This makes valkyrie_set_var compare, you guessed it, */ + /* fb_display[con].var (first param), and fb_display[con].var! */ + /* Perhaps I just fixed that... */ + switching = 1; + valkyrie_set_var(&fb_display[con].var, con, info); + switching = 0; +#endif + return 0; +} + +static int valkyriefb_updatevar(int con, struct fb_info *info) +{ + return 0; +} + +static void valkyriefb_blank(int blank_mode, struct fb_info *info) +{ +/* + * Blank the screen if blank_mode != 0, else unblank. If blank_mode == NULL + * then the caller blanks by setting the CLUT (Color Look Up Table) to all + * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due + * to e.g. a video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + struct valkyrie_regvals *init; + unsigned char vmode; + + if (p->disp.can_soft_blank + && ((vmode = p->par.vmode) > 0) + && (vmode <= VMODE_MAX) + && ((init = valkyrie_reg_init[vmode - 1]) != NULL)) { + if (blank_mode) + --blank_mode; + switch (blank_mode) { + default: /* unblank */ + out_8(&p->valkyrie_regs->mode.r, init->mode); + break; + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + /* + * [kps] Value extracted from MacOS. I don't know + * whether this bit disables hsync or vsync, or + * whether the hardware can do the other as well. + */ + out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40); + break; + case VESA_POWERDOWN: + out_8(&p->valkyrie_regs->mode.r, 0x66); + break; + } + } +} + +static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green, + u_int *blue, u_int *transp, struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + + if (regno > 255) + return 1; + *red = (p->palette[regno].red<<8) | p->palette[regno].red; + *green = (p->palette[regno].green<<8) | p->palette[regno].green; + *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; + + return 0; +} + +static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info; + volatile struct cmap_regs *cmap_regs = p->cmap_regs; + + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + p->palette[regno].red = red; + p->palette[regno].green = green; + p->palette[regno].blue = blue; + + /* tell clut which address to fill */ + out_8(&p->cmap_regs->addr, regno); + udelay(1); + /* send one color channel at a time */ + out_8(&cmap_regs->lut, red); + out_8(&cmap_regs->lut, green); + out_8(&cmap_regs->lut, blue); + + if (regno < 16) { +#ifdef FBCON_HAS_CFB16 + p->fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno; +#endif + } + + return 0; +} + +static void do_install_cmap(int con, struct fb_info *info) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) { + fb_set_cmap(&fb_display[con].cmap, 1, valkyriefb_setcolreg, + info); + } + else { + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), 1, valkyriefb_setcolreg, + info); + } +} + +#ifdef CONFIG_FB_COMPAT_XPMAC +extern struct vc_mode display_info; +extern struct fb_info *console_fb_info; +#endif /* CONFIG_FB_COMPAT_XPMAC */ + +static int valkyrie_vram_reqd(int video_mode, int color_mode) +{ + int pitch; + + if ((pitch = valkyrie_reg_init[video_mode-1]->pitch[color_mode]) == 0) + pitch = 2 * valkyrie_reg_init[video_mode-1]->pitch[0]; + return valkyrie_reg_init[video_mode-1]->vres * pitch; +} + +static void set_valkyrie_clock(unsigned char *params) +{ + struct adb_request req; + int i; + + for (i = 0; i < 3; ++i) { + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x50, i + 1, params[i]); + while (!req.complete) + cuda_poll(); + } +} + +__initfunc(static void init_valkyrie(struct fb_info_valkyrie *p)) +{ + struct fb_par_valkyrie *par = &p->par; + struct fb_var_screeninfo var; + int j, k; + + p->sense = read_valkyrie_sense(p); + printk("Monitor sense value = 0x%x, ", p->sense); + + /* Try to pick a video mode out of NVRAM if we have one. */ + if (default_vmode == VMODE_NVRAM) { + default_vmode = nvram_read_byte(NV_VMODE); + if (default_vmode <= 0 + || default_vmode > VMODE_MAX + || !valkyrie_reg_init[default_vmode - 1]) + default_vmode = VMODE_CHOOSE; + } + if (default_vmode == VMODE_CHOOSE) + default_vmode = mac_map_monitor_sense(p->sense); + if (!valkyrie_reg_init[default_vmode - 1]) + default_vmode = VMODE_640_480_67; + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); + + /* + * Reduce the pixel size if we don't have enough VRAM or bandwitdh. + */ + if (default_cmode < CMODE_8 + || default_cmode > CMODE_16 + || valkyrie_reg_init[default_vmode-1]->pitch[default_cmode] == 0 + || valkyrie_vram_reqd(default_vmode, default_cmode) > p->total_vram) + default_cmode = CMODE_8; + + printk("using video mode %d and color mode %d.\n", default_vmode, default_cmode); + + mac_vmode_to_var(default_vmode, default_cmode, &var); + if (valkyrie_var_to_par(&var, par, &p->info)) { + printk(KERN_ERR "valkyriefb: can't set default video mode\n"); + return ; + } + + valkyrie_init_fix(&p->fix, p); + valkyrie_par_to_fix(&p->par, &p->fix, p); + valkyrie_par_to_var(&p->par, &p->var); + valkyrie_init_display(&p->disp); + valkyrie_par_to_display(&p->par, &p->disp, &p->fix, p); + valkyrie_init_info(&p->info, p); + + /* Initialize colormap */ + for (j = 0; j < 16; j++) { + k = color_table[j]; + p->palette[j].red = default_red[k]; + p->palette[j].green = default_grn[k]; + p->palette[j].blue = default_blu[k]; + } + + valkyrie_set_var (&var, -1, &p->info); + + if (register_framebuffer(&p->info) < 0) { + kfree(p); + return; + } + + printk("fb%d: valkyrie frame buffer device\n", GET_FB_IDX(p->info.node)); +} + +static void valkyrie_set_par(const struct fb_par_valkyrie *par, + struct fb_info_valkyrie *p) +{ + struct valkyrie_regvals *init; + volatile struct valkyrie_regs *valkyrie_regs = p->valkyrie_regs; + int vmode, cmode; + + vmode = par->vmode; + cmode = par->cmode; + + if (vmode <= 0 + || vmode > VMODE_MAX + || (init = valkyrie_reg_init[vmode - 1]) == NULL) + panic("valkyrie: display mode %d not supported", vmode); + + /* Reset the valkyrie */ + out_8(&valkyrie_regs->status.r, 0); + udelay(100); + + /* Initialize display timing registers */ + out_8(&valkyrie_regs->mode.r, init->mode | 0x80); + out_8(&valkyrie_regs->depth.r, cmode + 3); + set_valkyrie_clock(init->clock_params); + udelay(100); + + /* Turn on display */ + out_8(&valkyrie_regs->mode.r, init->mode); + +#ifdef CONFIG_FB_COMPAT_XPMAC + /* And let the world know the truth. */ + if (!console_fb_info || console_fb_info == &p->info) { + display_info.height = p->var.yres; + display_info.width = p->var.xres; + display_info.depth = (cmode == CMODE_16) ? 16 : 8; + display_info.pitch = p->fix.line_length; + display_info.mode = vmode; + strncpy(display_info.name, "valkyrie", + sizeof(display_info.name)); + display_info.fb_address = p->frame_buffer_phys + 0x1000; + display_info.cmap_adr_address = p->cmap_regs_phys; + display_info.cmap_data_address = p->cmap_regs_phys + 8; + display_info.disp_reg_address = p->valkyrie_regs_phys; + console_fb_info = &p->info; + } +#endif /* CONFIG_FB_COMPAT_XPMAC */ +} + +__initfunc(void valkyriefb_init(void)) +{ +#ifndef CONFIG_FB_OF + struct device_node *dp; + + dp = find_devices("valkyrie"); + if (dp != 0) + valkyrie_of_init(dp); +#endif /* CONFIG_FB_OF */ +} + +__initfunc(void valkyrie_of_init(struct device_node *dp)) +{ + struct fb_info_valkyrie *p; + unsigned long addr, size; + + if(dp->n_addrs != 1) + panic("expecting 1 address for valkyrie (got %d)", dp->n_addrs); + + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (p == 0) + return; + memset(p, 0, sizeof(*p)); + + /* Map in frame buffer and registers */ + addr = dp->addrs[0].address; + size = 4096; + p->frame_buffer_phys = addr; + p->frame_buffer = __ioremap(addr, 0x100000, _PAGE_WRITETHRU); + p->cmap_regs_phys = addr + 0x304000; + p->cmap_regs = ioremap(p->cmap_regs_phys, size); + p->valkyrie_regs_phys = addr + 0x30a000; + p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, size); + + /* + * kps: As far as I know, all Valkyries have fixed usable VRAM. + */ + p->total_vram = 0x100000; + + init_valkyrie(p); +} + +/* + * Get the monitor sense value. + */ +static int read_valkyrie_sense(struct fb_info_valkyrie *p) +{ + int sense, in; + + out_8(&p->valkyrie_regs->msense.r, 0); /* release all lines */ + __delay(20000); + sense = ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x70) << 4; + /* drive each sense line low in turn and collect the other 2 */ + out_8(&p->valkyrie_regs->msense.r, 4); /* drive A low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x30); + out_8(&p->valkyrie_regs->msense.r, 2); /* drive B low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x40) >> 3; + sense |= (in & 0x10) >> 2; + out_8(&p->valkyrie_regs->msense.r, 1); /* drive C low */ + __delay(20000); + sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x60) >> 5; + + out_8(&p->valkyrie_regs->msense.r, 7); + + return sense; +} + +/* + * This routine takes a user-supplied var, + * and picks the best vmode/cmode from it. + */ +static int valkyrie_var_to_par(struct fb_var_screeninfo *var, + struct fb_par_valkyrie *par, const struct fb_info *fb_info) + +/* [bkn] I did a major overhaul of this function. + * + * Much of the old code was "swiped by jonh from atyfb.c". Because + * macmodes has mac_var_to_vmode, I felt that it would be better to + * rework this function to use that, instead of reinventing the wheel to + * add support for vmode 17. This was reinforced by the fact that + * the previously swiped atyfb.c code is no longer there. + * + * So, I swiped and adapted platinum_var_to_par (from platinumfb.c), replacing + * most, but not all, of the old code in the process. One side benefit of + * swiping the platinumfb code is that we now have more comprehensible error + * messages when a vmode/cmode switch fails. (Most of the error messages are + * platinumfb.c, but I added two of my own, and I also changed some commas + * into colons to make the messages more consistent with other Linux error + * messages.) In addition, I think the new code *might* fix some vmode- + * switching oddities, but I'm not sure. + * + * There may be some more opportunities for cleanup in here, but this is a + * good start... + */ + +{ + int bpp = var->bits_per_pixel; + struct valkyrie_regvals *init; + struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) fb_info; + + /* these are old variables that are no longer needed with my new code + [bkn] + + int xres = var->xres; + int yres = var->yres; + */ + + /* + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + * Suggestion: Round up in the following order: bits_per_pixel, xres, + * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, + * bitfields, horizontal timing, vertical timing. + */ + + if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) { + printk(KERN_ERR "valkyrie_var_to_par: mac_var_to_vmode unsuccessful.\n"); + printk(KERN_ERR "valkyrie_var_to_par: var->xres = %d\n", var->xres); + printk(KERN_ERR "valkyrie_var_to_par: var->yres = %d\n", var->yres); + printk(KERN_ERR "valkyrie_var_to_par: var->xres_virtual = %d\n", var->xres_virtual); + printk(KERN_ERR "valkyrie_var_to_par: var->yres_virtual = %d\n", var->yres_virtual); + printk(KERN_ERR "valkyrie_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel); + printk(KERN_ERR "valkyrie_var_to_par: var->pixclock = %d\n", var->pixclock); + printk(KERN_ERR "valkyrie_var_to_par: var->vmode = %d\n", var->vmode); + return -EINVAL; + } + + /* Check if we know about the wanted video mode */ + if(!valkyrie_reg_init[par->vmode-1]) { + printk(KERN_ERR "valkyrie_var_to_par: vmode %d not valid.\n", par->vmode); + return -EINVAL; + } + + par->xres = var->xres; + par->yres = var->yres; + par->xoffset = 0; + par->yoffset = 0; + par->vxres = par->xres; + par->vyres = par->yres; + + if (var->xres_virtual > var->xres || var->yres_virtual > var->yres + || var->xoffset != 0 || var->yoffset != 0) { + return -EINVAL; + } + + if (bpp <= 8) + par->cmode = CMODE_8; + else if (bpp <= 16) + par->cmode = CMODE_16; + else { + printk(KERN_ERR "valkyrie_var_to_par: cmode %d not supported.\n", par->cmode); + return -EINVAL; + } + + init = valkyrie_reg_init[par->vmode-1]; + if (init->pitch[par->cmode] == 0) { + printk(KERN_ERR "valkyrie_var_to_par: vmode %d does not support cmode %d.\n", par->vmode, par->cmode); + return -EINVAL; + } + + if (valkyrie_vram_reqd(par->vmode, par->cmode) > p->total_vram) { + printk(KERN_ERR "valkyrie_var_to_par: not enough ram for vmode %d, cmode %d.\n", par->vmode, par->cmode); + return -EINVAL; + } + + return 0; +} + +static int valkyrie_par_to_var(struct fb_par_valkyrie *par, struct fb_var_screeninfo *var) +{ + return mac_vmode_to_var(par->vmode, par->cmode, var); +} + +static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p) +{ + memset(fix, 0, sizeof(*fix)); + strcpy(fix->id, "valkyrie"); + fix->mmio_start = (char *)p->valkyrie_regs_phys; + fix->mmio_len = sizeof(struct valkyrie_regs); + fix->type = FB_TYPE_PACKED_PIXELS; + + fix->type_aux = 0; + fix->ywrapstep = 0; + fix->ypanstep = 0; + fix->xpanstep = 0; + +} + +/* Fix must already be inited above */ +static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, + struct fb_fix_screeninfo *fix, + struct fb_info_valkyrie *p) +{ + fix->smem_start = (void *)(p->frame_buffer_phys + 0x1000); +#if 1 + fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode); +#else + fix->smem_len = p->total_vram; +#endif + fix->visual = (par->cmode == CMODE_8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + fix->line_length = par->vxres << par->cmode; + /* ywrapstep, xpanstep, ypanstep */ +} + +static void valkyrie_init_display(struct display *disp) +{ + memset(disp, 0, sizeof(*disp)); + disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS; + disp->can_soft_blank = can_soft_blank; + disp->scrollmode = SCROLL_YREDRAW; +} + +static void valkyrie_par_to_display(struct fb_par_valkyrie *par, + struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p) +{ + disp->var = p->var; + disp->screen_base = (char *) p->frame_buffer + 0x1000; + disp->visual = fix->visual; + disp->line_length = fix->line_length; + + if(disp->scrollmode != SCROLL_YREDRAW) { + printk(KERN_ERR "Scroll mode not YREDRAW in valkyrie_par_to_display\n"); + disp->scrollmode = SCROLL_YREDRAW; + } + switch (par->cmode) { +#ifdef FBCON_HAS_CFB8 + case CMODE_8: + disp->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case CMODE_16: + disp->dispsw = &fbcon_cfb16; + disp->dispsw_data = p->fbcon_cfb16_cmap; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + break; + } +} + +static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p) +{ + strcpy(info->modename, p->fix.id); + info->node = -1; /* ??? danj */ + info->fbops = &valkyriefb_ops; + info->disp = &p->disp; + strcpy(info->fontname, fontname); + info->changevar = NULL; + info->switch_con = &valkyriefb_switch; + info->updatevar = &valkyriefb_updatevar; + info->blank = &valkyriefb_blank; + info->flags = FBINFO_FLAG_DEFAULT; +} + + +/* + * Parse user speficied options (`video=valkyriefb:') + */ +__initfunc(void valkyriefb_setup(char *options, int *ints)) +{ + char *this_opt; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } + else if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } + else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + } + } + /* XXX - remove these options once blanking has been tested */ + else if (!strncmp(this_opt, "noblank", 7)) { + can_soft_blank = 0; + } + else if (!strncmp(this_opt, "blank", 5)) { + can_soft_blank = 1; + } + } +} diff --git a/drivers/video/valkyriefb.h b/drivers/video/valkyriefb.h new file mode 100644 index 000000000..ee246a4fc --- /dev/null +++ b/drivers/video/valkyriefb.h @@ -0,0 +1,186 @@ +/* + * valkyriefb.h: Constants of all sorts for valkyriefb + * + * Created 8 August 1998 by Martin Costabel and Kevin Schoedel + * + * Vmode-switching changes and vmode 15/17 modifications created 29 August + * 1998 by Barry Nathan <barryn@pobox.com>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based directly on: + * + * controlfb.h: Constants of all sorts for controlfb + * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org> + * + * pmc-valkyrie.h: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * pmc-valkyrie.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * and indirectly from: + * + * pmc-control.h: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1997 Paul Mackerras. + * + * pmc-control.c: Console support for PowerMac "control" display adaptor. + * Copyright (C) 1996 Paul Mackerras. + * + * platinumfb.c: Console support for PowerMac "platinum" display adaptor. + * Copyright (C) 1998 Jon Howell + */ + +/* + * Structure of the registers for the Valkyrie colormap registers. + */ +struct cmap_regs { + unsigned char addr; + char pad1[7]; + unsigned char lut; +}; + +/* + * Structure of the registers for the "valkyrie" display adaptor. + */ + +struct vpreg { /* padded register */ + unsigned char r; + char pad[7]; +}; + + +struct valkyrie_regs { + struct vpreg mode; + struct vpreg depth; + struct vpreg status; + struct vpreg reg3; + struct vpreg intr; + struct vpreg reg5; + struct vpreg intr_enb; + struct vpreg msense; +}; + +/* + * Register initialization tables for the valkyrie display. + * + * Dot clock rate is + * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0]. + */ +struct valkyrie_regvals { + unsigned char mode; + unsigned char clock_params[3]; + int pitch[2]; /* bytes/line, indexed by color_mode */ + int hres; + int vres; +}; + +/* Register values for 1024x768, 75Hz mode (17) */ +/* I'm not sure which mode this is (16 or 17), so I'm defining it as 17, + * since the equivalent mode in controlfb (which I adapted this from) is + * also 17. Just because MacOS can't do this on Valkyrie doesn't mean we + * can't! :) + * + * I was going to use 12, 31, 3, which I found by myself, but instead I'm + * using 11, 28, 3 like controlfb, for consistency's sake. + */ + +static struct valkyrie_regvals valkyrie_reg_init_17 = { + 15, + { 11, 28, 3 }, /* pixel clock = 79.55MHz for V=74.50Hz */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 1024x768, 72Hz mode (15) */ +/* This used to be 12, 30, 3 for pixel clock = 78.12MHz for V=72.12Hz, but + * that didn't match MacOS in the same video mode on this chip, and it also + * caused the 15" Apple Studio Display to not work in this mode. While this + * mode still doesn't match MacOS exactly (as far as I can tell), it's a lot + * closer now, and it works with the Apple Studio Display. + * + * Yes, even though MacOS calls it "72Hz", in reality it's about 70Hz. + */ +static struct valkyrie_regvals valkyrie_reg_init_15 = { + 15, + { 12, 29, 3 }, /* pixel clock = 75.52MHz for V=69.71Hz? */ + /* I interpolated the V=69.71 from the vmode 14 and old 15 + * numbers. Is this result correct? + */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 1024x768, 60Hz mode (14) */ +static struct valkyrie_regvals valkyrie_reg_init_14 = { + 14, + { 15, 31, 3 }, /* pixel clock = 64.58MHz for V=59.62Hz */ + { 1024, 0 }, + 1024, 768 +}; + +/* Register values for 832x624, 75Hz mode (13) */ +static struct valkyrie_regvals valkyrie_reg_init_13 = { + 9, + { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ + { 832, 0 }, + 832, 624 +}; + +/* Register values for 800x600, 72Hz mode (11) */ +static struct valkyrie_regvals valkyrie_reg_init_11 = { + 13, + { 17, 27, 3 }, /* pixel clock = 49.63MHz for V=71.66Hz */ + { 800, 0 }, + 800, 600 +}; + +/* Register values for 800x600, 60Hz mode (10) */ +static struct valkyrie_regvals valkyrie_reg_init_10 = { + 12, + { 20, 53, 2 }, /* pixel clock = 41.41MHz for V=59.78Hz */ + { 800, 1600 }, + 800, 600 +}; + +/* Register values for 640x480, 67Hz mode (6) */ +static struct valkyrie_regvals valkyrie_reg_init_6 = { + 6, + { 14, 27, 2 }, /* pixel clock = 30.13MHz for V=66.43Hz */ + { 640, 1280 }, + 640, 480 +}; + +/* Register values for 640x480, 60Hz mode (5) */ +static struct valkyrie_regvals valkyrie_reg_init_5 = { + 11, + { 23, 37, 2 }, /* pixel clock = 25.14MHz for V=59.85Hz */ + { 640, 1280 }, + 640, 480 +}; + +static struct valkyrie_regvals *valkyrie_reg_init[VMODE_MAX] = { + NULL, + NULL, + NULL, + NULL, + &valkyrie_reg_init_5, + &valkyrie_reg_init_6, + NULL, + NULL, + NULL, + &valkyrie_reg_init_10, + &valkyrie_reg_init_11, + NULL, + &valkyrie_reg_init_13, + &valkyrie_reg_init_14, + &valkyrie_reg_init_15, + NULL, + &valkyrie_reg_init_17, + NULL, + NULL, + NULL +}; diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index cf1534a9a..cbad38a82 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -4,9 +4,9 @@ * switching to graphics mode happens at boot time (while * running in real mode, see arch/i386/video.S). * - * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> + * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * - */ + */ #include <linux/module.h> #include <linux/kernel.h> @@ -21,13 +21,16 @@ #include <linux/selection.h> #include <linux/ioport.h> #include <linux/init.h> +#include <linux/config.h> #include <asm/io.h> +#include <asm/mtrr.h> -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> #define dac_reg (0x3c8) #define dac_val (0x3c9) @@ -47,6 +50,7 @@ char *video_vbase; /* mapped */ int video_bpp; int video_width; int video_height; +int video_height_virtual; int video_type = FB_TYPE_PACKED_PIXELS; int video_visual; int video_linelength; @@ -75,19 +79,29 @@ static struct fb_var_screeninfo vesafb_defined = { static struct display disp; static struct fb_info fb_info; -static struct { u_char red, green, blue, pad; } palette[256]; +static struct { u_short blue, green, red, pad; } palette[256]; +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; -static int inverse = 0; +static int inverse = 0; +static int currcon = 0; -static int currcon = 0; +static int pmi_setpal = 0; /* pmi for palette changes ??? */ +static int ypan = 0; +static int ywrap = 0; +static unsigned short *pmi_base = 0; +static void (*pmi_start)(void); +static void (*pmi_pal)(void); -/* --------------------------------------------------------------------- */ -/* speed up scrolling */ - -#define USE_REDRAW 1 -#define USE_MEMMOVE 2 - -static int vesafb_scroll = USE_REDRAW; static struct display_switch vesafb_sw; /* --------------------------------------------------------------------- */ @@ -111,8 +125,39 @@ static int vesafb_release(struct fb_info *info, int user) return(0); } -static int fb_update_var(int con, struct fb_info *info) +static int vesafb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) { + int offset; + + if (!ypan && !ywrap) + return -EINVAL; + if (var->xoffset) + return -EINVAL; + if (ypan && var->yoffset+var->yres > var->yres_virtual) + return -EINVAL; + if (ywrap && var->yoffset > var->yres_virtual) + return -EINVAL; + + offset = (var->yoffset * video_linelength + var->xoffset) / 4; + + __asm__ __volatile__( + "call *(%%edi)" + : /* no return value */ + : "a" (0x4f07), /* EAX */ + "b" (0), /* EBX */ + "c" (offset), /* ECX */ + "d" (offset >> 16), /* EDX */ + "D" (&pmi_start)); /* EDI */ + return 0; +} + +static int vesafb_update_var(int con, struct fb_info *info) +{ + if (con == currcon && (ywrap || ypan)) { + struct fb_var_screeninfo *var = &fb_display[currcon].var; + return vesafb_pan_display(var,con,info); + } return 0; } @@ -126,9 +171,9 @@ static int vesafb_get_fix(struct fb_fix_screeninfo *fix, int con, fix->smem_len=video_size; fix->type = video_type; fix->visual = video_visual; - fix->xpanstep=0; - fix->ypanstep=0; - fix->ywrapstep=0; + fix->xpanstep = 0; + fix->ypanstep = (ywrap || ypan) ? 1 : 0; + fix->ywrapstep = ywrap ? 1 : 0; fix->line_length=video_linelength; return 0; } @@ -179,28 +224,66 @@ static void vesafb_set_disp(int con) case 15: case 16: sw = &fbcon_cfb16; + display->dispsw_data = fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + sw = &fbcon_cfb24; + display->dispsw_data = fbcon_cmap.cfb24; break; #endif #ifdef FBCON_HAS_CFB32 case 32: sw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; break; #endif default: + sw = &fbcon_dummy; return; } memcpy(&vesafb_sw, sw, sizeof(*sw)); display->dispsw = &vesafb_sw; - if (vesafb_scroll == USE_REDRAW) { + if (!ypan && !ywrap) { display->scrollmode = SCROLL_YREDRAW; vesafb_sw.bmove = fbcon_redraw_bmove; } } static int vesafb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) + struct fb_info *info) { - memcpy(var, &vesafb_defined, sizeof(struct fb_var_screeninfo)); + + if (var->xres != vesafb_defined.xres || + var->yres != vesafb_defined.yres || + var->xres_virtual != vesafb_defined.xres_virtual || + var->yres_virtual > video_height_virtual || + var->yres_virtual < video_height || + var->xoffset || + var->bits_per_pixel != vesafb_defined.bits_per_pixel || + var->nonstd) + return -EINVAL; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) + return 0; + + if (ypan || ywrap) { + if (vesafb_defined.yres_virtual != var->yres_virtual) { + vesafb_defined.yres_virtual = var->yres_virtual; + if (con != -1) { + fb_display[con].var = vesafb_defined; + info->changevar(con); + } + } + + if (var->yoffset != vesafb_defined.yoffset) + return vesafb_pan_display(var,con,info); + return 0; + } + + if (var->yoffset) + return -EINVAL; return 0; } @@ -219,9 +302,41 @@ static int vesa_getcolreg(unsigned regno, unsigned *red, unsigned *green, *red = palette[regno].red; *green = palette[regno].green; *blue = palette[regno].blue; + *transp = 0; return 0; } +#ifdef FBCON_HAS_CFB8 + +static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue) +{ + struct { u_char blue, green, red, pad; } entry; + + if (pmi_setpal) { + entry.red = red >> 10; + entry.green = green >> 10; + entry.blue = blue >> 10; + entry.pad = 0; + __asm__ __volatile__( + "call *(%%esi)" + : /* no return value */ + : "a" (0x4f09), /* EAX */ + "b" (0), /* EBX */ + "c" (1), /* ECX */ + "d" (regno), /* EDX */ + "D" (&entry), /* EDI */ + "S" (&pmi_pal)); /* ESI */ + } else { + /* without protected mode interface, try VGA registers... */ + outb_p(regno, dac_reg); + outb_p(red >> 10, dac_val); + outb_p(green >> 10, dac_val); + outb_p(blue >> 10, dac_val); + } +} + +#endif + static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fb_info) @@ -235,7 +350,7 @@ static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= video_cmap_len) return 1; - + palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; @@ -243,28 +358,44 @@ static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green, switch (video_bpp) { #ifdef FBCON_HAS_CFB8 case 8: - /* Hmm, can we do it _always_ this way ??? */ - outb_p(regno, dac_reg); - outb_p(red, dac_val); - outb_p(green, dac_val); - outb_p(blue, dac_val); + vesa_setpalette(regno,red,green,blue); break; #endif #ifdef FBCON_HAS_CFB16 case 15: case 16: - fbcon_cfb16_cmap[regno] = - (red << vesafb_defined.red.offset) | (green << 5) | blue; + if (vesafb_defined.red.offset == 10) { + /* 1:5:5:5 */ + fbcon_cmap.cfb16[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + fbcon_cmap.cfb16[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } break; #endif #ifdef FBCON_HAS_CFB24 case 24: - /* FIXME: todo */ + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb24[regno] = + (red << vesafb_defined.red.offset) | + (green << vesafb_defined.green.offset) | + (blue << vesafb_defined.blue.offset); break; #endif #ifdef FBCON_HAS_CFB32 case 32: - fbcon_cfb32_cmap[regno] = + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb32[regno] = (red << vesafb_defined.red.offset) | (green << vesafb_defined.green.offset) | (blue << vesafb_defined.blue.offset); @@ -279,11 +410,9 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - vesa_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, vesa_setcolreg, info); else - fb_set_cmap(fb_default_cmap(video_cmap_len), - &fb_display[con].var, 1, vesa_setcolreg, + fb_set_cmap(fb_default_cmap(video_cmap_len), 1, vesa_setcolreg, info); } @@ -291,7 +420,7 @@ static int vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, vesa_getcolreg, info); + return fb_get_cmap(cmap, kspc, vesa_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -311,20 +440,13 @@ static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, vesa_setcolreg, info); + return fb_set_cmap(cmap, kspc, vesa_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; } -static int vesafb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - /* no panning */ - return -EINVAL; -} - -static int vesafb_ioctl(struct inode *inode, struct file *file, +static int vesafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info) { @@ -355,14 +477,18 @@ void vesafb_setup(char *options, int *ints) for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { if (!*this_opt) continue; - printk("vesafb_setup: option %s\n", this_opt); - if (! strcmp(this_opt, "inverse")) inverse=1; else if (! strcmp(this_opt, "redraw")) - vesafb_scroll = USE_REDRAW; - else if (! strcmp(this_opt, "memmove")) - vesafb_scroll = USE_MEMMOVE; + ywrap=0,ypan=0; + else if (! strcmp(this_opt, "ypan")) + ywrap=0,ypan=1; + else if (! strcmp(this_opt, "ywrap")) + ywrap=1,ypan=0; + else if (! strcmp(this_opt, "vgapal")) + pmi_setpal=0; + else if (! strcmp(this_opt, "pmipal")) + pmi_setpal=1; else if (!strncmp(this_opt, "font:", 5)) strcpy(fb_info.fontname, this_opt+5); } @@ -372,13 +498,14 @@ static int vesafb_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - vesa_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, vesa_getcolreg, + info); currcon = con; /* Install new colormap */ do_install_cmap(con, info); - return 0; + vesafb_update_var(con,info); + return 1; } /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ @@ -400,24 +527,72 @@ __initfunc(void vesafb_init(void)) video_width = screen_info.lfb_width; video_height = screen_info.lfb_height; video_linelength = screen_info.lfb_linelength; - video_size = video_linelength * video_height /* screen_info.lfb_size */; + video_size = screen_info.lfb_size * 65536; video_visual = (video_bpp == 8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; video_vbase = ioremap((unsigned long)video_base, video_size); - printk("vesafb: %dx%dx%d, linelength=%d\n", - video_width, video_height, video_bpp, video_linelength); - printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %d\n", - video_base, video_vbase, video_size); - if (vesafb_scroll == USE_REDRAW) printk("vesafb: scrolling=redraw\n"); - if (vesafb_scroll == USE_MEMMOVE) printk("vesafb: scrolling=memmove\n"); - + printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n", + video_base, video_vbase, video_size/1024); + printk("vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", + video_width, video_height, video_bpp, video_linelength, screen_info.pages); + + if (screen_info.vesapm_seg) { + printk("vesafb: protected mode interface info at %04x:%04x\n", + screen_info.vesapm_seg,screen_info.vesapm_off); + } + + if (screen_info.vesapm_seg < 0xc000) + ywrap = ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ + + if (ypan || ywrap || pmi_setpal) { + pmi_base = (unsigned short*)(__PAGE_OFFSET+((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_start = (void*)((char*)pmi_base + pmi_base[1]); + pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); + printk("vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); + if (pmi_base[3]) { + printk("vesafb: pmi: ports = "); + for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++) + printk("%x ",pmi_base[i]); + printk("\n"); + if (pmi_base[i] != 0xffff) { + /* + * memory areas not supported (yet?) + * + * Rules are: we have to set up a descriptor for the requested + * memory area and pass it in the ES register to the BIOS function. + */ + printk("vesafb: can't handle memory requests, pmi disabled\n"); + ywrap = ypan = pmi_setpal = 0; + } + } + } + vesafb_defined.xres=video_width; vesafb_defined.yres=video_height; vesafb_defined.xres_virtual=video_width; - vesafb_defined.yres_virtual=video_height; + vesafb_defined.yres_virtual=video_size / video_linelength; vesafb_defined.bits_per_pixel=video_bpp; + if ((ypan || ywrap) && vesafb_defined.yres_virtual > video_height) { + printk("vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", + ywrap ? "ywrap" : "ypan",vesafb_defined.yres_virtual); + } else { + printk("vesafb: scrolling: redraw\n"); + vesafb_defined.yres_virtual = video_height; + ypan = ywrap = 0; + } + video_height_virtual = vesafb_defined.yres_virtual; + + /* some dummy values for timing to make fbset happy */ + vesafb_defined.pixclock = 10000000 / video_width * 1000 / video_height; + vesafb_defined.left_margin = (video_width / 8) & 0xf8; + vesafb_defined.right_margin = 32; + vesafb_defined.upper_margin = 16; + vesafb_defined.lower_margin = 4; + vesafb_defined.hsync_len = (video_width / 8) & 0xf8; + vesafb_defined.vsync_len = 4; + if (video_bpp > 8) { vesafb_defined.red.offset = screen_info.red_pos; vesafb_defined.red.length = screen_info.red_size; @@ -451,6 +626,9 @@ __initfunc(void vesafb_init(void)) video_cmap_len = 256; } request_region(0x3c0, 32, "vga+"); +#ifdef CONFIG_MTRR + mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1); +#endif strcpy(fb_info.modename, "VESA VGA"); fb_info.changevar = NULL; @@ -458,8 +636,9 @@ __initfunc(void vesafb_init(void)) fb_info.fbops = &vesafb_ops; fb_info.disp=&disp; fb_info.switch_con=&vesafb_switch; - fb_info.updatevar=&fb_update_var; + fb_info.updatevar=&vesafb_update_var; fb_info.blank=&vesafb_blank; + fb_info.flags=FBINFO_FLAG_DEFAULT; vesafb_set_disp(-1); if (register_framebuffer(&fb_info)<0) diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index f2bc39cd0..ccc5e2a27 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -22,13 +22,14 @@ #include <linux/fb.h> #include <linux/init.h> -#include "fbcon-mfb.h" -#include "fbcon-cfb2.h" -#include "fbcon-cfb4.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" -#include "fbcon-cfb24.h" -#include "fbcon-cfb32.h" +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -49,6 +50,17 @@ static int currcon = 0; static struct display disp; static struct fb_info fb_info; static struct { u_char red, green, blue, pad; } palette[256]; +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; static char vfb_name[16] = "Virtual FB"; static struct fb_var_screeninfo vfb_default = { @@ -282,20 +294,23 @@ static int vfb_set_var(struct fb_var_screeninfo *var, int con, #ifdef FBCON_HAS_CFB16 case 16: display->dispsw = &fbcon_cfb16; + display->dispsw_data = fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB24 case 24: display->dispsw = &fbcon_cfb24; + display->dispsw_data = fbcon_cmap.cfb24; break; #endif #ifdef FBCON_HAS_CFB32 case 32: display->dispsw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } if (fb_info.changevar) @@ -349,8 +364,7 @@ static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, vfb_getcolreg, - info); + return fb_get_cmap(cmap, kspc, vfb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -374,8 +388,7 @@ static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, &fb_display[con].var, kspc, vfb_setcolreg, - info); + return fb_set_cmap(cmap, kspc, vfb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -432,6 +445,7 @@ __initfunc(void vfb_init(void)) fb_info.switch_con = &vfbcon_switch; fb_info.updatevar = &vfbcon_updatevar; fb_info.blank = &vfbcon_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; vfb_set_var(&vfb_default, -1, &fb_info); @@ -449,8 +463,7 @@ static int vfbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - vfb_getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, vfb_getcolreg, info); currcon = con; /* Install new colormap */ @@ -579,9 +592,10 @@ static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, { if (regno > 255) return 1; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; + *red = (palette[regno].red<<8) | palette[regno].red; + *green = (palette[regno].green<<8) | palette[regno].green; + *blue = (palette[regno].blue<<8) | palette[regno].blue; + *transp = 0; return 0; } @@ -597,6 +611,9 @@ static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, { if (regno > 255) return 1; + red >>= 8; + green >>= 8; + blue >>= 8; palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; @@ -609,11 +626,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - vfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, vfb_setcolreg, info); else - fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, vfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, + vfb_setcolreg, info); } diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c index a464d389a..3f76e591a 100644 --- a/drivers/video/vgacon.c +++ b/drivers/video/vgacon.c @@ -64,8 +64,6 @@ */ #undef TRIDENT_GLITCH -#undef VGA_CAN_DO_64KB - #define dac_reg 0x3c8 #define dac_val 0x3c9 #define attrib_port 0x3c0 @@ -115,6 +113,7 @@ static int vga_palette_blanked; static int vga_is_gfx; static int vga_512_chars; static int vga_video_font_height; +static unsigned int vga_rolled_over = 0; void no_scroll(char *str, int *ints) @@ -190,7 +189,7 @@ __initfunc(static const char *vgacon_startup(void)) display_desc = "*MDA"; request_region(0x3b0,12,"mda"); request_region(0x3bf, 1,"mda"); - vga_video_font_height = 16; + vga_video_font_height = 14; } } else /* If not, it is color. */ @@ -453,9 +452,8 @@ static int vgacon_switch(struct vc_data *c) */ vga_video_num_columns = c->vc_cols; vga_video_num_lines = c->vc_rows; - if (vga_is_gfx) - return 1; - scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size); + if (!vga_is_gfx) + scr_memcpyw_to((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size); return 0; /* Redrawing not needed */ } @@ -474,8 +472,7 @@ static void vga_set_palette(struct vc_data *c, unsigned char *table) static int vgacon_set_palette(struct vc_data *c, unsigned char *table) { #ifdef CAN_LOAD_PALETTE - - if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked) + if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(c)) return -EINVAL; vga_set_palette(c, table); return 0; @@ -637,10 +634,11 @@ static int vgacon_blank(struct vc_data *c, int blank) vga_palette_blanked = 1; return 0; } - scr_memsetw((void *)vga_vram_base, BLANK, vc_cons[0].d->vc_screenbuf_size); + vgacon_set_origin(c); + scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size); return 1; case -1: /* Entering graphic mode */ - scr_memsetw((void *)vga_vram_base, BLANK, vc_cons[0].d->vc_screenbuf_size); + scr_memsetw((void *)vga_vram_base, BLANK, c->vc_screenbuf_size); vga_is_gfx = 1; return 1; default: /* VESA blanking */ @@ -899,14 +897,24 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; else { - int p = c->vc_visible_origin - vga_vram_base; - int margin = c->vc_rows/4 * c->vc_size_row; - p += lines * c->vc_size_row; - if (lines < 0 && p < margin) + int vram_size = vga_vram_end - vga_vram_base; + int margin = c->vc_size_row * 4; + int ul, we, p, st; + + if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) { + ul = c->vc_scr_end - vga_vram_base; + we = vga_rolled_over + c->vc_size_row; + } else { + ul = 0; + we = vram_size; + } + p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row; + st = (c->vc_origin - vga_vram_base - ul + we) % we; + if (p < margin) p = 0; - c->vc_visible_origin = p + vga_vram_base; - if (lines > 0 && c->vc_visible_origin > c->vc_origin - margin) - c->vc_visible_origin = c->vc_origin; + if (p > st - margin) + p = st; + c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); return 1; @@ -919,6 +927,7 @@ static int vgacon_set_origin(struct vc_data *c) return 0; c->vc_origin = c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); + vga_rolled_over = 0; return 1; } @@ -935,9 +944,8 @@ static void vgacon_save_screen(struct vc_data *c) c->vc_x = ORIG_X; c->vc_y = ORIG_Y; } - if (vga_is_gfx) - return; - scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size); + if (!vga_is_gfx) + scr_memcpyw_from((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size); } static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) @@ -962,6 +970,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) (u16 *)(oldo + delta), c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_base; + vga_rolled_over = oldo - vga_vram_base; } else c->vc_origin += delta; scr_memsetw((u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta); @@ -971,6 +980,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) (u16 *)oldo, c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_end - c->vc_screenbuf_size; + vga_rolled_over = 0; } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff --git a/drivers/video/vgafb.c b/drivers/video/vgafb.c deleted file mode 100644 index c8fc4c9a0..000000000 --- a/drivers/video/vgafb.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * linux/drivers/video/vgafb.c -- VGA frame buffer device - * - * Created 28 Mar 1998 by Geert Uytterhoeven - * Hardware cursor support added on 14 Apr 1998 by Emmanuel Marty - * - * This file is heavily based on vgacon.c. Read about its contributors there. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - - - - -/* KNOWN PROBLEMS/TO DO ===================================================== * - * - * - add support for loadable fonts and VESA blanking - * - * - for now only VGA _text_ mode is supported - * - * KNOWN PROBLEMS/TO DO ==================================================== */ - - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/malloc.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/selection.h> -#include <linux/console.h> -#include <linux/vt_kern.h> - -#include <asm/io.h> -#include <asm/uaccess.h> - -#include "fbcon.h" -#include "fbcon-vga.h" - - -#define BLANK 0x0020 - -#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ -#define CAN_LOAD_PALETTE /* undefine if the user must not do this */ - -#define dac_reg (0x3c8) -#define dac_val (0x3c9) - -#ifdef __powerpc__ -#define VGA_OFFSET _ISA_MEM_BASE; -#else -#define VGA_OFFSET 0x0 -#endif - - -static int currcon = 0; -static struct display disp; -static struct fb_info fb_info; -static struct { u_char red, green, blue, pad; } palette[16]; - -static struct fb_fix_screeninfo fb_fix = { { 0, } }; -static struct fb_var_screeninfo fb_var = { 0, }; - - -/* Description of the hardware situation */ -static unsigned char vga_video_type; -static unsigned long vga_video_mem_base; /* Base of video memory */ -static unsigned long vga_video_mem_term; /* End of video memory */ -static u16 vga_video_port_reg; /* Video register select port */ -static u16 vga_video_port_val; /* Video register value port */ -static unsigned long vga_video_num_columns; /* Number of text columns */ -static unsigned long vga_video_num_lines; /* Number of text lines */ -static int vga_can_do_color = 0; - - - /* - * VGA screen access - */ - -static inline void vga_writew(u16 val, u16 *addr) -{ -#ifdef __powerpc__ - st_le16(addr, val); -#else - writew(val, (unsigned long)addr); -#endif /* !__powerpc__ */ -} - -static inline u16 vga_readw(u16 *addr) -{ -#ifdef __powerpc__ - return ld_le16(addr); -#else - return readw((unsigned long)addr); -#endif /* !__powerpc__ */ -} - -/* - * By replacing the four outb_p with two back to back outw, we can reduce - * the window of opportunity to see text mislocated to the RHS of the - * console during heavy scrolling activity. However there is the remote - * possibility that some pre-dinosaur hardware won't like the back to back - * I/O. Since the Xservers get away with it, we should be able to as well. - */ -static inline void write_vga(unsigned char reg, unsigned int val) -{ -#ifndef SLOW_VGA - unsigned int v1, v2; - - v1 = reg + (val & 0xff00); - v2 = reg + 1 + ((val << 8) & 0xff00); - outw(v1, vga_video_port_reg); - outw(v2, vga_video_port_reg); -#else - outb_p(reg, vga_video_port_reg); - outb_p(val >> 8, vga_video_port_val); - outb_p(reg+1, vga_video_port_reg); - outb_p(val & 0xff, vga_video_port_val); -#endif -} - -static inline void vga_set_origin(unsigned short location) -{ - write_vga(12, location >> 1); -} - -static inline void vga_set_cursor(int location) -{ - write_vga(14, location >> 1); -} - -static void vga_set_split(unsigned short linenum) -{ - unsigned long flags; - unsigned char overflow, fontsize; - - if (vga_video_type != VIDEO_TYPE_VGAC) { - return; - } - - save_flags(flags); cli(); - - outb_p(0x07, vga_video_port_reg); - overflow = inb_p(vga_video_port_val); - - outb_p(0x09, vga_video_port_reg); - fontsize = inb_p(vga_video_port_val); - - overflow &= ~0x10; overflow |= (linenum & 0x100) ? 0x10 : 0; - fontsize &= ~0x40; fontsize |= (linenum & 0x200) ? 0x40 : 0; - linenum &= 0xff; - - outb_p(0x18, vga_video_port_reg); - outb_p(linenum, vga_video_port_val); - - outb_p(0x07, vga_video_port_reg); - outb_p(overflow, vga_video_port_val); - - outb_p(0x09, vga_video_port_reg); - outb_p(fontsize, vga_video_port_val); - - restore_flags(flags); -} - -static inline void vga_set_palreg(u_int regno, u_int red, - u_int green, u_int blue) -{ - unsigned long flags; - - save_flags(flags); cli(); - - outb_p(regno, dac_reg); - outb_p(red, dac_val); - outb_p(green, dac_val); - outb_p(blue, dac_val); - - restore_flags(flags); -} - - - /* - * Interface used by the world - */ - -static int vgafb_open(struct fb_info *info, int user); -static int vgafb_release(struct fb_info *info, int user); -static int vgafb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -static int vgafb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int vgafb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int vgafb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int vgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int vgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int vgafb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); - - - /* - * Interface to the low level console driver - */ - -void vgafb_init(void); -void vgafb_setup(char *options, int *ints); -static int vgafbcon_switch(int con, struct fb_info *info); -static int vgafbcon_updatevar(int con, struct fb_info *info); -static void vgafbcon_blank(int blank, struct fb_info *info); - - - /* - * VGA text console with hardware cursor - */ - -static struct display_switch fbcon_vgafb; - - - /* - * Internal routines - */ - -static int vgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); -static int vgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static void do_install_cmap(int con, struct fb_info *info); - - -static struct fb_ops vgafb_ops = { - vgafb_open, vgafb_release, vgafb_get_fix, vgafb_get_var, vgafb_set_var, - vgafb_get_cmap, vgafb_set_cmap, vgafb_pan_display, vgafb_ioctl -}; - - - /* - * Open/Release the frame buffer device - */ - -static int vgafb_open(struct fb_info *info, int user) - -{ - /* - * Nothing, only a usage count for the moment - */ - - MOD_INC_USE_COUNT; - return(0); -} - -static int vgafb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return(0); -} - - - /* - * Get the Fixed Part of the Display - */ - -static int vgafb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) -{ - memcpy(fix, &fb_fix, sizeof(fb_fix)); - return 0; -} - - - /* - * Get the User Defined Part of the Display - */ - -static int vgafb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - memcpy(var, &fb_var, sizeof(fb_var)); - return 0; -} - - - /* - * Set the User Defined Part of the Display - */ - -static int vgafb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - struct display *display; - int oldbpp = -1, err; - - if (con >= 0) - display = &fb_display[con]; - else - display = &disp; /* used during initialization */ - - if (var->xres > fb_var.xres || var->yres > fb_var.yres || - var->xres_virtual > fb_var.xres_virtual || - var->yres_virtual > fb_var.yres_virtual || - var->bits_per_pixel > fb_var.bits_per_pixel || - var->nonstd || !(var->accel_flags & FB_ACCELF_TEXT) || - (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - return -EINVAL; - memcpy(var, &fb_var, sizeof(fb_var)); - - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldbpp = display->var.bits_per_pixel; - display->var = *var; - vga_set_origin(var->yoffset/video_font_height*fb_fix.line_length); - } - - if (oldbpp != var->bits_per_pixel) { - if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) - return err; - do_install_cmap(con, info); - } - return 0; -} - - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int vgafb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - if (var->xoffset || var->yoffset+var->yres > var->yres_virtual) - return -EINVAL; - - vga_set_origin(var->yoffset/video_font_height*fb_fix.line_length); - return 0; -} - - - /* - * Get the Colormap - */ - -static int vgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - if (con == currcon) /* current console? */ - return fb_get_cmap(cmap, &fb_display[con].var, kspc, vgafb_getcolreg, - info); - else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); - return 0; -} - - - /* - * Set the Colormap - */ - -static int vgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - - if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<<fb_display[con].var.bits_per_pixel, 0))) - return err; - } - if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, &fb_display[con].var, kspc, vgafb_setcolreg, - info); - return err; - } else - fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); - return 0; -} - - -static int vgafb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info) -{ - return -EINVAL; -} - - - /* - * Move hardware vga cursor - */ - -static void fbcon_vgafb_cursor(struct display *p, int mode, int x, int y) -{ - switch (mode) { - case CM_ERASE: - vga_set_cursor(vga_video_mem_term - vga_video_mem_base - 1); - break; - - case CM_MOVE: - case CM_DRAW: - vga_set_cursor(y*p->next_line + (x << 1)); - break; - } -} - - - /* - * Initialisation - */ - -__initfunc(void vgafb_init(void)) -{ - u16 saved; - u16 *p; - - if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) - return; - - vga_video_num_lines = ORIG_VIDEO_LINES; - vga_video_num_columns = ORIG_VIDEO_COLS; - - if (ORIG_VIDEO_MODE == 7) { /* Is this a monochrome display? */ - vga_video_mem_base = 0xb0000 + VGA_OFFSET; - vga_video_port_reg = 0x3b4; - vga_video_port_val = 0x3b5; - if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { - vga_video_type = VIDEO_TYPE_EGAM; - vga_video_mem_term = 0xb8000 + VGA_OFFSET; - strcpy(fb_fix.id, "EGA+"); - request_region(0x3b0, 16, "ega"); - } else { - vga_video_type = VIDEO_TYPE_MDA; - vga_video_mem_term = 0xb1000 + VGA_OFFSET; - strcpy(fb_fix.id, "*MDA"); - request_region(0x3b0, 12, "mda"); - request_region(0x3bf, 1, "mda"); - } - } else { /* If not, it is color. */ - vga_can_do_color = 1; - vga_video_mem_base = 0xb8000 + VGA_OFFSET; - vga_video_port_reg = 0x3d4; - vga_video_port_val = 0x3d5; - if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { - int i; - - vga_video_mem_term = 0xc0000 + VGA_OFFSET; - - if (!ORIG_VIDEO_ISVGA) { - vga_video_type = VIDEO_TYPE_EGAC; - strcpy(fb_fix.id, "EGA"); - request_region(0x3c0, 32, "ega"); - } else { - vga_video_type = VIDEO_TYPE_VGAC; - strcpy(fb_fix.id, "VGA+"); - request_region(0x3c0, 32, "vga+"); - -#ifdef VGA_CAN_DO_64KB - /* - * get 64K rather than 32K of video RAM. - * This doesn't actually work on all "VGA" - * controllers (it seems like setting MM=01 - * and COE=1 isn't necessarily a good idea) - */ - vga_video_mem_base = 0xa0000 + VGA_OFFSET; - vga_video_mem_term = 0xb0000 + VGA_OFFSET; - outb_p(6, 0x3ce); - outb_p(6, 0x3cf); -#endif - - /* - * Normalise the palette registers, to point - * the 16 screen colours to the first 16 - * DAC entries. - */ - - for (i = 0; i < 16; i++) { - inb_p(0x3da); - outb_p(i, 0x3c0); - outb_p(i, 0x3c0); - } - outb_p(0x20, 0x3c0); - - /* now set the DAC registers back to their - * default values */ - - for (i = 0; i < 16; i++) { - vga_set_palreg(color_table[i], default_red[i], - default_grn[i], default_blu[i]); - } - } - } else { - vga_video_type = VIDEO_TYPE_CGA; - vga_video_mem_term = 0xba000 + VGA_OFFSET; - strcpy(fb_fix.id, "*CGA"); - request_region(0x3d4, 2, "cga"); - } - } - - /* - * Find out if there is a graphics card present. - * Are there smarter methods around? - */ - p = (u16 *)vga_video_mem_base; - saved = vga_readw(p); - vga_writew(0xAA55, p); - if (vga_readw(p) != 0xAA55) { - vga_writew(saved, p); - return; - } - vga_writew(0x55AA, p); - if (vga_readw(p) != 0x55AA) { - vga_writew(saved, p); - return; - } - vga_writew(saved, p); - - if (vga_video_type == VIDEO_TYPE_VGAC - || vga_video_type == VIDEO_TYPE_EGAC - || vga_video_type == VIDEO_TYPE_EGAM) { - video_font_height = ORIG_VIDEO_POINTS; - } else { - video_font_height = 16; - } - - /* This may be suboptimal but is a safe bet - go with it */ - video_scan_lines = video_font_height * vga_video_num_lines; - - fb_fix.smem_start = (char *) vga_video_mem_base; - fb_fix.smem_len = vga_video_mem_term - vga_video_mem_base; - fb_fix.type = FB_TYPE_TEXT; - fb_fix.type_aux = vga_can_do_color ? FB_AUX_TEXT_CGA : FB_AUX_TEXT_MDA; - fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; - fb_fix.xpanstep = 0; - fb_fix.ypanstep = video_font_height; - fb_fix.ywrapstep = 0; - fb_fix.line_length = 2*vga_video_num_columns; - fb_fix.mmio_start = NULL; - fb_fix.mmio_len = 0; - fb_fix.accel = FB_ACCEL_NONE; - - fb_var.xres = vga_video_num_columns*8; - fb_var.yres = vga_video_num_lines*video_font_height; - fb_var.xres_virtual = fb_var.xres; - /* the cursor is put at the end of the video memory, hence the -2 */ - fb_var.yres_virtual = ((fb_fix.smem_len-2)/fb_fix.line_length)* - video_font_height; - - fb_var.xoffset = fb_var.yoffset = 0; - fb_var.bits_per_pixel = vga_can_do_color ? 4 : 1; - fb_var.grayscale = !vga_can_do_color; - fb_var.red.offset = 0; - fb_var.red.length = 6; - fb_var.red.msb_right = 0; - fb_var.green.offset = 0; - fb_var.green.length = 6; - fb_var.green.msb_right = 0; - fb_var.blue.offset = 0; - fb_var.blue.length = 6; - fb_var.blue.msb_right = 0; - fb_var.transp.offset = 0; - fb_var.transp.length = 0; - fb_var.transp.msb_right = 0; - fb_var.nonstd = 0; - fb_var.activate = 0; - fb_var.height = fb_var.width = -1; - fb_var.accel_flags = FB_ACCELF_TEXT; - fb_var.pixclock = 39722; /* 25.175 MHz */ - fb_var.left_margin = 40; - fb_var.right_margin = 24; - fb_var.upper_margin = 39; - fb_var.lower_margin = 9; - fb_var.hsync_len = 96; - fb_var.vsync_len = 2; - fb_var.sync = 0; - fb_var.vmode = FB_VMODE_NONINTERLACED; - - disp.var = fb_var; - disp.cmap.start = 0; - disp.cmap.len = 0; - disp.cmap.red = NULL; - disp.cmap.green = NULL; - disp.cmap.blue = NULL; - disp.cmap.transp = NULL; - -#ifdef __i386__ - disp.screen_base = ioremap((unsigned long) fb_fix.smem_start, - fb_fix.smem_len); -#else - disp.screen_base = bus_to_virt((unsigned long) fb_fix.smem_start); -#endif - disp.visual = fb_fix.visual; - disp.type = fb_fix.type; - disp.type_aux = fb_fix.type_aux; - disp.ypanstep = fb_fix.ypanstep; - disp.ywrapstep = fb_fix.ywrapstep; - disp.line_length = fb_fix.line_length; - disp.can_soft_blank = vga_can_do_color; - disp.inverse = 0; - disp.dispsw = &fbcon_vgafb; - - strcpy(fb_info.modename, fb_fix.id); - fb_info.node = -1; - fb_info.fbops = &vgafb_ops; - fb_info.disp = &disp; - fb_info.fontname[0] = '\0'; - fb_info.changevar = NULL; - fb_info.switch_con = &vgafbcon_switch; - fb_info.updatevar = &vgafbcon_updatevar; - fb_info.blank = &vgafbcon_blank; - - vgafb_set_var(&fb_var, -1, &fb_info); - - if (register_framebuffer(&fb_info) < 0) - return; - - printk("fb%d: VGA frame buffer device, using %dK of video memory\n", - GET_FB_IDX(fb_info.node), fb_fix.smem_len>>10); -} - -__initfunc(void vgafb_setup(char *options, int *ints)) -{ - /* nothing yet */ -} - - /* - * Update the `var' structure (called by fbcon.c) - */ - -static int vgafbcon_updatevar(int con, struct fb_info *info) -{ - if (con == currcon) { - struct fb_var_screeninfo *var = &fb_display[currcon].var; - - /* hardware scrolling */ - - vga_set_origin(var->yoffset / video_font_height * - fb_fix.line_length); - - vga_set_split(var->yres - ((var->vmode & FB_VMODE_YWRAP) ? - var->yoffset+1 : 0)); - } - - return 0; -} - -static int vgafbcon_switch(int con, struct fb_info *info) -{ - /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - vgafb_getcolreg, info); - - currcon = con; - /* Install new colormap */ - do_install_cmap(con, info); - vgafbcon_updatevar(con, info); - return 0; -} - - /* - * Blank the display. - */ - -static void vgafbcon_blank(int blank, struct fb_info *info) -{ - int i; - - if (blank) - for (i = 0; i < 16; i++) { - vga_set_palreg(i, 0, 0, 0); - } - else - for (i = 0; i < 16; i++) { - vga_set_palreg(i, palette[i].red, palette[i].green, - palette[i].blue); - } -} - - - /* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ - -static int vgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ - if (regno > 15) - return 1; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; - return 0; -} - - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int vgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 15) - return 1; - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; - - vga_set_palreg(regno, red, green, blue); - - return 0; -} - -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - vgafb_setcolreg, info); - else - fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, vgafb_setcolreg, - info); -} - - - /* - * VGA text console with hardware cursor - */ - -static struct display_switch fbcon_vgafb = { - fbcon_vga_setup, fbcon_vga_bmove, fbcon_vga_clear, fbcon_vga_putc, - fbcon_vga_putcs, fbcon_vga_revc, fbcon_vgafb_cursor, NULL, NULL, - FONTWIDTH(8) -}; - - -#ifdef MODULE -int init_module(void) -{ - vgafb_init(); - return 0; -} - -void cleanup_module(void) -{ - unregister_framebuffer(&fb_info); -} -#endif /* MODULE */ diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c index 927fbb46d..59d16e90b 100644 --- a/drivers/video/virgefb.c +++ b/drivers/video/virgefb.c @@ -33,10 +33,10 @@ #include <asm/pgtable.h> #include <asm/amigahw.h> -#include "s3blit.h" -#include "fbcon.h" -#include "fbcon-cfb8.h" -#include "fbcon-cfb16.h" +#include <video/s3blit.h> +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> #ifdef VIRGEFBDEBUG @@ -147,11 +147,13 @@ static char virgefb_name[16] = "Cybervision/3D"; static unsigned int CyberKey = 0; -static unsigned char Cyber_colour_table [256][4]; +static unsigned char Cyber_colour_table [256][3]; static unsigned long CyberMem; static unsigned long CyberSize; static volatile char *CyberRegs; static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */ +static unsigned long CyberMem_phys; +static unsigned long CyberRegs_phys; /* @@ -208,6 +210,13 @@ static struct fb_videomode virgefb_predefined[] __initdata = { 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2, FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED } + }, { + "1024x768-16", { /* Cybervision 16 bpp */ + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } } }; @@ -323,7 +332,6 @@ static int Cyber_init(void) Cyber_colour_table [i][0] = i; Cyber_colour_table [i][1] = i; Cyber_colour_table [i][2] = i; - Cyber_colour_table [i][3] = 0; } /* @@ -372,9 +380,9 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, virgefb_name); - fix->smem_start = (char *)CyberMem; + fix->smem_start = (char*) CyberMem_phys; fix->smem_len = CyberSize; - fix->mmio_start = (char *)CyberRegs; + fix->mmio_start = (char*) CyberRegs_phys; fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */ fix->type = FB_TYPE_PACKED_PIXELS; @@ -382,7 +390,7 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, if (par->bpp == 8) fix->visual = FB_VISUAL_PSEUDOCOLOR; else - fix->visual = FB_VISUAL_DIRECTCOLOR; + fix->visual = FB_VISUAL_TRUECOLOR; fix->xpanstep = 0; fix->ypanstep = 0; @@ -445,7 +453,7 @@ static int Cyber_encode_var(struct fb_var_screeninfo *var, if (par->bpp == 8) { var->red.offset = 0; - var->red.length = 8; + var->red.length = 6; var->red.msb_right = 0; var->blue = var->green = var->red; } else { @@ -511,14 +519,17 @@ static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, */ vgawb_3d(0x3c8, (unsigned char) regno); - Cyber_colour_table [regno][0] = red & 0xff; - Cyber_colour_table [regno][1] = green & 0xff; - Cyber_colour_table [regno][2] = blue & 0xff; - Cyber_colour_table [regno][3] = transp; + red >>= 10; + green >>= 10; + blue >>= 10; - vgawb_3d(0x3c9, ((red & 0xff) >> 2)); - vgawb_3d(0x3c9, ((green & 0xff) >> 2)); - vgawb_3d(0x3c9, ((blue & 0xff) >> 2)); + Cyber_colour_table [regno][0] = red; + Cyber_colour_table [regno][1] = green; + Cyber_colour_table [regno][2] = blue; + + vgawb_3d(0x3c9, red); + vgawb_3d(0x3c9, green); + vgawb_3d(0x3c9, blue); return (0); } @@ -532,12 +543,17 @@ static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) { + int t; + if (regno >= 256) return (1); - *red = Cyber_colour_table [regno][0]; - *green = Cyber_colour_table [regno][1]; - *blue = Cyber_colour_table [regno][2]; - *transp = Cyber_colour_table [regno][3]; + t = Cyber_colour_table [regno][0]; + *red = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][1]; + *green = (t<<10) | (t<<4) | (t>>2); + t = Cyber_colour_table [regno][2]; + *blue = (t<<10) | (t<<4) | (t>>2); + *transp = 0; return (0); } @@ -565,9 +581,9 @@ void Cyber_blank(int blank) for (i = 0; i < 256; i++) { vgawb_3d(0x3c8, (unsigned char) i); - vgawb_3d(0x3c9, Cyber_colour_table[i][0] >> 2); - vgawb_3d(0x3c9, Cyber_colour_table[i][1] >> 2); - vgawb_3d(0x3c9, Cyber_colour_table[i][2] >> 2); + vgawb_3d(0x3c9, Cyber_colour_table[i][0]); + vgawb_3d(0x3c9, Cyber_colour_table[i][1]); + vgawb_3d(0x3c9, Cyber_colour_table[i][2]); } } } @@ -752,11 +768,10 @@ static void do_install_cmap(int con, struct fb_info *info) if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, - fbhw->setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - &fb_display[con].var, 1, fbhw->setcolreg, info); + 1, fbhw->setcolreg, info); } @@ -837,7 +852,7 @@ static void virgefb_set_disp(int con, struct fb_info *info) virgefb_get_fix(&fix, con, info); if (con == -1) con = 0; - display->screen_base = fix.smem_start; + display->screen_base = (char*) CyberMem; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -861,7 +876,7 @@ static void virgefb_set_disp(int con, struct fb_info *info) break; #endif default: - display->dispsw = NULL; + display->dispsw = &fbcon_dummy; break; } } @@ -910,8 +925,7 @@ static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { if (con == currcon) /* current console? */ - return(fb_get_cmap(cmap, &fb_display[con].var, - kspc, fbhw->getcolreg, info)); + return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info)); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else @@ -936,8 +950,7 @@ static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con, return(err); } if (con == currcon) /* current console? */ - return(fb_set_cmap(cmap, &fb_display[con].var, - kspc, fbhw->setcolreg, info)); + return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info)); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return(0); @@ -1029,7 +1042,8 @@ __initfunc(void virgefb_init(void)) * Ok we got the board running in Z2 space. */ - CyberMem = ZTWO_VADDR(board_addr); + CyberMem_phys = board_addr; + CyberMem = ZTWO_VADDR(CyberMem_phys); printk("CV3D detected running in Z2 mode ... not yet supported!\n"); return; } @@ -1037,10 +1051,13 @@ __initfunc(void virgefb_init(void)) { CyberVGARegs = kernel_map(board_addr +0x0c000000, 0x00010000, KERNELMAP_NOCACHE_SER, NULL); - CyberRegs = (char *)kernel_map(board_addr +0x05000000, + + CyberRegs_phys = board_addr + 0x05000000; + CyberMem_phys = board_addr + 0x04800000; + CyberRegs = (char *)kernel_map(CyberRegs_phys, 0x00010000, KERNELMAP_NOCACHE_SER, NULL); - CyberMem = kernel_map(board_addr + 0x04800000, 0x00400000, + CyberMem = kernel_map(CyberMem_phys, 0x00400000, KERNELMAP_NOCACHE_SER, NULL); printk("CV3D detected running in Z3 mode\n"); } @@ -1055,6 +1072,7 @@ __initfunc(void virgefb_init(void)) fb_info.switch_con = &Cyberfb_switch; fb_info.updatevar = &Cyberfb_updatevar; fb_info.blank = &Cyberfb_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; fbhw->init(); fbhw->decode_var(&virgefb_default, &par); @@ -1080,8 +1098,8 @@ static int Cyberfb_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, - fbhw->getcolreg, info); + fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg, + info); do_fb_set_var(&fb_display[con].var, 1); currcon = con; @@ -1143,9 +1161,9 @@ static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { sx *= 8; dx *= 8; width *= 8; - Cyber3D_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx, - (u_short)(dy*p->fontheight), (u_short)width, - (u_short)(height*p->fontheight)); + Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx, + (u_short)(dy*fontheight(p)), (u_short)width, + (u_short)(height*fontheight(p))); } static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy, @@ -1155,8 +1173,8 @@ static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy, sx *= 8; width *= 8; bg = attr_bgcol_ec(p,conp); - Cyber3D_RectFill((u_short)sx, (u_short)(sy*p->fontheight), - (u_short)width, (u_short)(height*p->fontheight), + Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)), + (u_short)width, (u_short)(height*fontheight(p)), (u_short)bg); } |