Hi, Here are two patch for testing framebuffer support on O2. linux-O2-console.diff just adds dummy console/keyboard so that virtual consoles can be compiled. linux-O2-fb.diff is an experimental O2 framebuffer driver based on the sgivwfb driver. It currently supports 8 bit modes, except 800x600 (I tested 640x480,1024x768,1280x1024,1600x1200 @ 60Hz). 16 bit and 32 bit modes have wrong colors, but the pixels are in the right place ;) Feel free to test... You'll probably need all other patches I've sent to the list some time ago to get O2 booting. I've also included a patch needed to get the mips64 kernel compile on r4k with the new icache functions, that I've just sent to Ralf too for integration. Patches are against CVS/HEAD. regards, Vivien.
diff -Naur linux64/arch/mips64/config.in linux64.new/arch/mips64/config.in --- linux64/arch/mips64/config.in Thu May 16 19:55:57 2002 +++ linux64.new/arch/mips64/config.in Tue May 7 00:42:31 2002 @@ -293,6 +293,9 @@ else define_bool CONFIG_FONT_8x16 y fi + fi + if [ "$CONFIG_SGI_IP32" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y fi endmenu fi diff -Naur linux64/arch/mips64/kernel/setup.c linux64.new/arch/mips64/kernel/setup.c --- linux64/arch/mips64/kernel/setup.c Thu May 16 19:55:59 2002 +++ linux64.new/arch/mips64/kernel/setup.c Tue May 7 00:43:57 2002 @@ -78,8 +78,10 @@ extern struct rtc_ops no_rtc_ops; struct rtc_ops *rtc_ops; +#ifdef CONFIG_PC_KEYB extern struct kbd_ops no_kbd_ops; struct kbd_ops *kbd_ops; +#endif /* * Setup information @@ -721,6 +723,10 @@ void __init setup_arch(char **cmdline_p) { +#ifdef CONFIG_PC_KEYB + kbd_ops = &no_kbd_ops; +#endif + #ifdef CONFIG_SGI_IP22 ip22_setup(); #endif diff -Naur linux64/arch/mips64/sgi-ip32/ip32-setup.c linux64.new/arch/mips64/sgi-ip32/ip32-setup.c --- linux64/arch/mips64/sgi-ip32/ip32-setup.c Thu May 16 19:56:06 2002 +++ linux64.new/arch/mips64/sgi-ip32/ip32-setup.c Sun May 12 22:37:51 2002 @@ -12,6 +12,7 @@ #include <linux/mc146818rtc.h> #include <linux/param.h> #include <linux/init.h> +#include <linux/console.h> #include <asm/time.h> #include <asm/mipsregs.h>
--- linux64/include/asm-mips64/pgtable.h Thu May 16 20:01:12 2002 +++ linux64.new/include/asm-mips64/pgtable.h Sun May 5 21:52:18 2002 @@ -551,6 +551,8 @@ #define kern_addr_valid(addr) (1) #endif +#define io_remap_page_range remap_page_range + /* * No page table caches to initialise */ diff -Naur linux64/drivers/video/Config.in linux64.new/drivers/video/Config.in --- linux64/drivers/video/Config.in Thu May 16 19:59:49 2002 +++ linux64.new/drivers/video/Config.in Tue May 14 23:38:34 2002 @@ -97,6 +97,9 @@ tristate ' SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW define_bool CONFIG_BUS_I2C y fi + if [ "$CONFIG_SGI_IP32" = "y" ]; then + bool ' SGI O2 frame buffer support' CONFIG_FB_SGIO2 + fi if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then bool ' Sun3 framebuffer support' CONFIG_FB_SUN3 if [ "$CONFIG_FB_SUN3" != "n" ]; then @@ -196,6 +199,7 @@ if [ "$CONFIG_NINO" = "y" ]; then bool ' TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912 fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL fi @@ -264,11 +268,11 @@ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ - "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ + "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \ - "$CONFIG_FB_SIS" = "y" ]; then + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SGIO2" = "y"]; then define_tristate CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -284,11 +288,11 @@ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" \ "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \ "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_TX3912" = "m" ]; then + "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_SGIO2" = "m"]; then define_tristate CONFIG_FBCON_CFB8 m fi fi @@ -304,7 +308,8 @@ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ - "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then + "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \ + "$CONFIG_FB_SGIO2" = "y"]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -319,7 +324,8 @@ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ - "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then + "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \ + "$CONFIG_FB_SGIO2" = "m"]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -349,7 +355,7 @@ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ - "$CONFIG_FB_VOODOO1" = "y" ]; then + "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_SGIO2" = "y"]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -360,7 +366,8 @@ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then + "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \ + "$CONFIG_FB_SGIO2" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi fi diff -Naur linux64/drivers/video/Makefile linux64.new/drivers/video/Makefile --- linux64/drivers/video/Makefile Thu May 16 19:59:49 2002 +++ linux64.new/drivers/video/Makefile Tue May 7 22:02:32 2002 @@ -57,6 +57,7 @@ obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o +obj-$(CONFIG_FB_SGIO2) += sgio2fb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o obj-$(CONFIG_FB_HP300) += hpfb.o @@ -84,7 +85,6 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o obj-$(CONFIG_FB_TX3912) += tx3912fb.o - subdir-$(CONFIG_FB_MATROX) += matrox ifeq ($(CONFIG_FB_MATROX),y) diff -Naur linux64/drivers/video/fbmem.c linux64.new/drivers/video/fbmem.c --- linux64/drivers/video/fbmem.c Thu May 16 19:59:53 2002 +++ linux64.new/drivers/video/fbmem.c Thu May 16 19:47:37 2002 @@ -110,6 +110,8 @@ extern int sun3fb_setup(char *); extern int sgivwfb_init(void); extern int sgivwfb_setup(char*); +extern int sgio2fb_init(void); +extern int sgio2fb_setup(char*); extern int rivafb_init(void); extern int rivafb_setup(char*); extern int tdfxfb_init(void); @@ -237,6 +239,9 @@ #ifdef CONFIG_FB_SGIVW { "sgivw", sgivwfb_init, sgivwfb_setup }, #endif +#ifdef CONFIG_FB_SGIO2 + { "sgio2", sgio2fb_init, sgio2fb_setup }, +#endif #ifdef CONFIG_FB_ACORN { "acorn", acornfb_init, acornfb_setup }, #endif diff -Naur linux64/drivers/video/sgio2fb.c linux64.new/drivers/video/sgio2fb.c --- linux64/drivers/video/sgio2fb.c Thu Jan 1 01:00:00 1970 +++ linux64.new/drivers/video/sgio2fb.c Thu May 16 19:46:29 2002 @@ -0,0 +1,1199 @@ +/* + * linux/drivers/video/sgio2fb.c -- SGI GBE frame buffer device + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Jeffrey Newquist, newquist@engr.sgi.som + * Copyright (C) 2002 Vivien Chappelier, vivien.chappelier@enst-bretagne.fr + * modified from the original SGI VW DBE driver to support the O2 GBE + * + * 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/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <asm/io.h> + +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> + +#define INCLUDE_TIMING_TABLE_DATA +#define GBE_REG_BASE regs +#include "sgio2fb.h" + +struct sgio2fb_par { + struct fb_var_screeninfo var; + u_long timing_num; + int valid; +}; + +/* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + * + * The default can be overridden if the driver is compiled as a module + */ + +/* TODO: add an option */ +#define VIDEOMEMSIZE (2*1024*1024) /* 2 MB */ + +static u16 *sgio2fb_tiles_table; +static u_long sgio2fb_mem_phys; +static u_long sgio2fb_mem_size; + +static volatile char *fbmem; +static asregs *regs; +static struct fb_info fb_info; +static struct { u_char red, green, blue, pad; } palette[256]; +static char sgio2fb_name[16] = "SGI O2 FB"; +static u32 cmap_fifo; +static int ypan = 0; +static int ywrap = 0; +static int video_bpp; + +/* console related variables */ +static int currcon = 0; +static struct display disp; + +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +static struct sgio2fb_par par_current = { + // TEMP: for testing various modes +#if 0 + { /* var (screeninfo) */ + /* 640x480, 32 bpp */ + 640, 480, 640, 480, 0, 0, 32, 0, + {24, 8, 0}, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, + 0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + 0, /* timing_num */ + 0 /* par not activated */ +#endif +#if 0 + { /* var (screeninfo) */ + /* 640x480, 16 bpp */ + 640, 480, 640, 480, 0, 0, 16, 0, + {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + 0, /* timing_num */ + 0 /* par not activated */ +#endif +#if 1 + { /* var (screeninfo) */ + /* 640x480, 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, 0, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + 0, /* timing_num */ + 0 /* par not activated */ +#endif +#if 0 + { /* var (screeninfo) */ + /* 800x600, 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, 0, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + GBE_VT_800_600_75, /* timing_num */ + 0 /* par not activated */ +#endif +#if 0 + { /* var (screeninfo) */ + /* 800x600, 16 bpp */ + 800, 600, 800, 600, 0, 0, 16, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + GBE_VT_800_600_75, /* timing_num */ + 0 /* par not activated */ +#endif +#if 0 +{ /* var (screeninfo) */ + /* 1024x768, 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, 0, 15384, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + GBE_VT_1024_768_60, + 0 /* par not activated */ +#endif +#if 0 +{ /* var (screeninfo) */ + /* 1280x1024, 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, 0, 15384, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + GBE_VT_1280_1024_60, + 0 /* par not activated */ +#endif +#if 0 +{ /* var (screeninfo) */ + /* 1280x1024, 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, 0, 15384, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + GBE_VT_1600_1200_60, + 0 /* par not activated */ +#endif +}; + +/* + * Interface used by the world + */ +int sgio2fb_setup(char*); + +static int sgio2fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int sgio2fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sgio2fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sgio2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sgio2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sgio2fb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); + +static struct fb_ops sgio2fb_ops = { + owner: THIS_MODULE, + fb_get_fix: sgio2fb_get_fix, + fb_get_var: sgio2fb_get_var, + fb_set_var: sgio2fb_set_var, + fb_get_cmap: sgio2fb_get_cmap, + fb_set_cmap: sgio2fb_set_cmap, + fb_mmap: sgio2fb_mmap, +}; + +/* + * Interface to the low level console driver + */ +int sgio2fb_init(void); +static int sgio2fbcon_switch(int con, struct fb_info *info); +static int sgio2fbcon_updatevar(int con, struct fb_info *info); +static void sgio2fbcon_blank(int blank, struct fb_info *info); + +/* + * Internal routines + */ +static u_long get_line_length(int xres_virtual, int bpp); +static unsigned long bytes_per_pixel(int bpp); +static void activate_par(struct sgio2fb_par *par); +static void sgio2fb_encode_fix(struct fb_fix_screeninfo *fix, + struct fb_var_screeninfo *var); +static int sgio2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); +static int sgio2fb_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 unsigned long get_line_length(int xres_virtual, int bpp) +{ + return(xres_virtual * bytes_per_pixel(bpp)); +} + +static unsigned long bytes_per_pixel(int bpp) +{ + unsigned long length; + + switch (bpp) { + case 8: + length = 1; + break; + case 16: + length = 2; + break; + case 32: + length = 4; + break; + default: + printk(KERN_INFO "sgio2fb: unsupported bpp=%d\n", bpp); + length = 0; + break; + } + return(length); +} + +/* + * Function: gbe_TurnOffDma + * Parameters: (None) + * Description: This should turn off the monitor and gbe. This is used + * when switching between the serial console and the graphics + * console. + */ + +static void gbe_TurnOffDma(void) +{ + int i; + unsigned int readVal; + + // Check to see if things are already turned off: + // 1) Check to see if gbe is not using the internal dotclock. + // 2) Check to see if the xy counter in gbe is already off. + + GBE_GETREG(ctrlstat, readVal); + if (GET_GBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2) + return; + + GBE_GETREG(vt_xy, readVal); + if (GET_GBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) + return; + + // Otherwise, turn off gbe + GBE_GETREG(ovr_control, readVal); + SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0); + GBE_SETREG(ovr_control, readVal); + udelay(1000); + GBE_GETREG(frm_control, readVal); + SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0); + GBE_SETREG(frm_control, readVal); + udelay(1000); + GBE_GETREG(did_control, readVal); + SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0); + GBE_SETREG(did_control, readVal); + udelay(1000); + + // XXX HACK: + // + // This was necessary for GBE--we had to wait through two + // vertical retrace periods before the pixel DMA was + // turned off for sure. I've left this in for now, in + // case dbe needs it. + // [VC].. well now this is GBE ;) + + for (i = 0; i < 10000; i++) + { + GBE_GETREG(frm_inhwctrl, readVal); + if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == 0) { + udelay(10); + } + else + { + GBE_GETREG(ovr_inhwctrl, readVal); + if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) { + udelay(10); + } + else + { + GBE_GETREG(did_inhwctrl, readVal); + if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, readVal) == 0) { + udelay(10); + } + else + break; + } + } + } +} + +/* + * Set the hardware according to 'par'. + */ +static void activate_par(struct sgio2fb_par *par) +{ + int i,j, htmp, temp; + u32 readVal, outputVal; + int wholeTilesX, partTilesX, maxPixelsPerTileX; + int height_pix; + int frmWrite1, frmWrite2, frmWrite3b; + gbe_timing_info_t *currentTiming; /* Current Video Timing */ + int xpmax, ypmax; // Monitor resolution + int bytesPerPixel; // Bytes per pixel + + currentTiming = &gbeVTimings[par->timing_num]; + bytesPerPixel = bytes_per_pixel(par->var.bits_per_pixel); + xpmax = currentTiming->width; + ypmax = currentTiming->height; + + /* gbe_InitGraphicsBase(); */ + /* Turn on dotclock PLL */ + GBE_SETREG(ctrlstat, 0x30000000); + + gbe_TurnOffDma(); + + /* gbe_CalculateScreenParams(); */ + /* HACK: + The GBE hardware uses a tiled memory to screen mapping. Tiles are blocks of + 512x128, 256x128 or 128x128 pixels, respectively for 8bit, 16bit and 32 bit + modes (64 kB). They cover the screen with partial tiles on the right and/or + bottom of the screen if needed. For exemple in 640x480 8 bit mode the mapping + is: + + <-------- 640 -----> + <---- 512 ----><128|384 offscreen> + ^ ^ + | 128 [tile 0] [tile 1] + | v + ^ + 4 128 [tile 2] [tile 3] + 8 v + 0 ^ + 128 [tile 4] [tile 5] + | v + | ^ + v 96 [tile 6] [tile 7] + 32 offscreen + + Tiles have the advantage that they can be allocated individually in memory. + However, this mapping is not linear at all, which is not really convienient. + In order to support linear addressing, the GBE DMA hardware is fooled into + thinking the screen is only one tile large and but has a greater height, so + that the DMA transfer covers the same region. + First a continous region is allocated in memory to serve as the framebuffer. + Then the tile table is set up so that each tile reference a 64k block in this + memory: + GBE DMA ---> tile list framebuffer + [ tile 0 ] ---> [ 0x00000000:0x0000ffff ] + [ tile 1 ] ---> [ 0x00010000:0x0001ffff ] + [ tile 2 ] ---> [ 0x00020000:0x0002ffff ] + [ tile 3 ] ---> [ 0x00030000:0x0003ffff ] + ... ... + [ tile n ] ---> [ 0x000n0000:0x000nffff ] + + The GBE hardware is then told that the buffer is 512xtweaked_height, with + tweaked_height = real_widthxreal_height/pixels_per_tile + Thus the GBE hardware will scan the first tile, filing the first 64k covered + region of the screen, and then will proceed to the next tile, which is just + after the first one in memory, until the whole screen is covered. + + Here is what would happen at 640x480 8bit: + + normal tiling linear + ^ 11111111111111112222 11111111111111111111 ^ + 128 11111111111111112222 11111111111111111111 102 lines + 11111111111111112222 11111111111111111111 v + V 11111111111111112222 11111111222222222222 + 33333333333333334444 22222222222222222222 + 33333333333333334444 22222222222222222222 + < 512 > < 256 > 102*640+256 = 64k + + NOTE: The only mode for which this is not working is 800x600 8bit, as + 800*600/512 = 937.5 which is not integer and thus causes flickering. + I guess this is not so important as one can use 640x480 8bit or + 800x600 16bit anyway. + */ + maxPixelsPerTileX = 512/bytesPerPixel; + wholeTilesX = 1; + partTilesX = 0; + + /* Initialize tile pointers */ + for(i = 0; i < 128; i++) + sgio2fb_tiles_table[i] = (u16) (CPHYSADDR(sgio2fb_mem_phys) >> 16) + i; + + /* gbe_InitGammaMap(); */ + udelay(10); + for (i = 0; i < 256; i++) + GBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); + + /* gbe_TurnOn(); */ + GBE_GETREG(vt_xy, readVal); + if (GET_GBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) + { + GBE_SETREG(vt_xy, 0x00000000); + udelay(1); + } + else + gbe_TurnOffDma(); + + /* gbe_Initgbe(); */ + for (i = 0; i < 256; i++) + { + /* XXX: not working + for (j = 0; j < 100; j++) + { + GBE_GETREG(cm_fifo, cmap_fifo); + if (cmap_fifo != 0x00000000) + break; + else + udelay(10); + } + */ + GBE_ISETREG(cmap, i, (i<<8)|(i<<16)|(i<<24)); + udelay(1000); /* leave some delay instead */ + } + + /* gbe_InitFramebuffer(); */ + frmWrite1 = 0; + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, wholeTilesX); + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, partTilesX); + + switch(bytesPerPixel) + { + case 1: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_8); + break; + case 2: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_16); + break; + case 4: + SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_32); + break; + } + + frmWrite2 = 0; + // SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); + + /* compute tweaked height = real width x real height / pixels per tile */ + height_pix = xpmax*ypmax/maxPixelsPerTileX; + + if(height_pix * maxPixelsPerTileX != xpmax*ypmax) + printk(KERN_DEBUG "sgio2fb: this mode cannot be mapped linearly. Please use another one.\n"); + + SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, height_pix); + + // Tell gbe about the framebuffer location and type + /* tile_ptr -> [ tile 1 ] -> FB mem */ + /* [ tile 2 ] -> FB mem */ + /* ... */ + frmWrite3b = 0; + SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, ((u32)CPHYSADDR(sgio2fb_tiles_table))>>9); + SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); + + /* Initialize DIDs */ + outputVal = 0; + switch(bytesPerPixel) + { + case 1: + SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_I8); + break; + case 2: + SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_RGBA5); + break; + case 4: + SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_RGB8); + break; + } + SET_GBE_FIELD(WID, BUF, outputVal, GBE_BMODE_BOTH); + // SET_GBE_FIELD(WID, GAMMA, outputVal, 1); /* disable gamma correction */ + + for (i = 0; i < 32; i++) + { + GBE_ISETREG(mode_regs, i, outputVal); + } + + /* gbe_InitTiming(); */ + GBE_SETREG(vt_intr01, 0xffffffff); + GBE_SETREG(vt_intr23, 0xffffffff); + + GBE_GETREG(dotclock, readVal); + GBE_SETREG(dotclock, readVal & 0xffff); + + GBE_SETREG(vt_xymax, 0x00000000); + outputVal = 0; + SET_GBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, currentTiming->vsync_start); + SET_GBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, currentTiming->vsync_end); + GBE_SETREG(vt_vsync, outputVal); + outputVal = 0; + SET_GBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, currentTiming->hsync_start); + SET_GBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, currentTiming->hsync_end); + GBE_SETREG(vt_hsync, outputVal); + outputVal = 0; + SET_GBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, currentTiming->vblank_start); + SET_GBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, currentTiming->vblank_end); + GBE_SETREG(vt_vblank, outputVal); + outputVal = 0; + SET_GBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, currentTiming->hblank_start-5); + SET_GBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, currentTiming->hblank_end-3); + GBE_SETREG(vt_hblank, outputVal); + outputVal = 0; + SET_GBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, currentTiming->vblank_start); + SET_GBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, currentTiming->vblank_end); + GBE_SETREG(vt_vcmap, outputVal); + outputVal = 0; + SET_GBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, currentTiming->hblank_start); + SET_GBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, currentTiming->hblank_end-3); + GBE_SETREG(vt_hcmap, outputVal); + + /* turn off sync on green */ + outputVal = 0; + SET_GBE_FIELD(VT_FLAGS, VT_SYNC_LOW, outputVal, 1); + GBE_SETREG(vt_flags, outputVal); + + outputVal = 0; + temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; + if (temp > 0) + temp = -temp; + + SET_GBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32)temp); + if (currentTiming->hblank_end >= 20) + SET_GBE_FIELD(DID_START_XY, DID_STARTX, outputVal, + currentTiming->hblank_end - 20); + else + SET_GBE_FIELD(DID_START_XY, DID_STARTX, outputVal, + currentTiming->htotal - (20 - currentTiming->hblank_end)); + GBE_SETREG(did_start_xy, outputVal); + + outputVal = 0; + SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, (u32)(temp+1)); + if (currentTiming->hblank_end >= GBE_CRS_MAGIC) + SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, + currentTiming->hblank_end - GBE_CRS_MAGIC); + else + SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, + currentTiming->htotal - (GBE_CRS_MAGIC - currentTiming->hblank_end)); + GBE_SETREG(crs_start_xy, outputVal); + + outputVal = 0; + SET_GBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32)temp); + SET_GBE_FIELD(VC_START_XY, VC_STARTX, outputVal, + currentTiming->hblank_end - 4); + GBE_SETREG(vc_start_xy, outputVal); + + GBE_SETREG(frm_size_tile, frmWrite1); + GBE_SETREG(frm_size_pixel, frmWrite2); + + outputVal = 0; + SET_GBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m-1); + SET_GBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n-1); + SET_GBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); + SET_GBE_FIELD(DOTCLK, RUN, outputVal, 1); + GBE_SETREG(dotclock, outputVal); + + udelay(11*1000); + + GBE_SETREG(vt_vpixen, 0xffffff); + GBE_SETREG(vt_hpixen, 0xffffff); + + outputVal = 0; + SET_GBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); + SET_GBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); + GBE_SETREG(vt_xymax, outputVal); + + outputVal = frmWrite1; + // SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); + GBE_SETREG(frm_size_tile, outputVal); + GBE_SETREG(frm_size_tile, frmWrite1); + + outputVal = 0; + // SET_GBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); + GBE_SETREG(ovr_width_tile, outputVal); + GBE_SETREG(ovr_width_tile, 0); + + GBE_SETREG(frm_control, frmWrite3b); + GBE_SETREG(did_control, 0); + + // Wait for gbe to take frame settings + for (i=0; i<100000; i++) + { + GBE_GETREG(frm_inhwctrl, readVal); + if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != 0) + break; + else + udelay(1); + } + + if (i==100000) + printk(KERN_INFO "sgio2fb: timeout waiting for frame DMA enable.\n"); + + outputVal = 0; + htmp = currentTiming->hblank_end - 19; + if (htmp < 0) + htmp += currentTiming->htotal; /* allow blank to wrap around */ + SET_GBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); + SET_GBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, + ((htmp + currentTiming->width - 2) % currentTiming->htotal)); + GBE_SETREG(vt_hpixen, outputVal); + + outputVal = 0; + SET_GBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, + currentTiming->vblank_start); + SET_GBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, + currentTiming->vblank_end); + GBE_SETREG(vt_vpixen, outputVal); + + // Turn off mouse cursor + regs->crs_ctl = 0; + + // XXX What's this section for?? + GBE_GETREG(ctrlstat, readVal); + readVal &= 0x02000000; + + if (readVal != 0) + { + GBE_SETREG(ctrlstat, 0x30000000); + } +} + +static void sgio2fb_encode_fix(struct fb_fix_screeninfo *fix, + struct fb_var_screeninfo *var) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, sgio2fb_name); + fix->smem_start = sgio2fb_mem_phys; + fix->smem_len = sgio2fb_mem_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + switch (var->bits_per_pixel) { + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + default: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + } + fix->ywrapstep = ywrap; + fix->xpanstep = 0; + fix->ypanstep = ypan; + fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + fix->mmio_start = GBE_REG_PHYS; + fix->mmio_len = GBE_REG_SIZE; +} + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ +static int sgio2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + *red = palette[regno].red << 8; + *green = palette[regno].green << 8; + *blue = palette[regno].blue << 8; + *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. + */ + +static int sgio2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + int i; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + switch (video_bpp) { +#ifdef FBCON_HAS_CFB8 + case 8: + /* wait for the color map FIFO to have a free entry */ + /* XXX: doesn't seem to work, ignoring fifo state + (this may cause 'snow' artifacts on colormap change) + for(i = 0; i < 10000 && cmap_fifo == 0; i++) { + udelay(10); + cmap_fifo = regs->cm_fifo; + } + if(i == 10000) { + printk(KERN_ERR "sgio2fb: cmap FIFO timeout\n"); + return 1; + } + */ + regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); + udelay(1000); /* leave some delay instead */ + cmap_fifo--; /* assume FIFO is filling up */ + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 15: + case 16: + if(regno > 15) return 1; + fbcon_cmap.cfb16[regno] = + ((red & 0xf8) << 7) | + ((green & 0xf8) << 2) | + ((blue & 0xf8) >> 3); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + if(regno > 15) return 1; + fbcon_cmap.cfb32[regno] = + (red << 24) | + (green << 16) | + (blue << 8); + break; +#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, sgio2fb_setcolreg, info); + else + fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, + sgio2fb_setcolreg, info); +} + +/* ---------------------------------------------------- */ + +/* + * Get the Fixed Part of the Display + */ +static int sgio2fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct fb_var_screeninfo *var; + + if (con == -1) + var = &par_current.var; + else + var = &fb_display[con].var; + sgio2fb_encode_fix(fix, var); + return 0; +} + +/* + * Get the User Defined Part of the Display. If a real par get it form there + */ +static int sgio2fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (con == -1) + *var = par_current.var; + else + *var = fb_display[con].var; + return 0; +} + +/* + * Set the User Defined Part of the Display. Again if par use it to get + * real video mode. + */ +static int sgio2fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err, activate = var->activate; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp; + u_long line_length; + u_long min_mode; + int req_dot; + int test_mode; + + struct gbe_timing_info *timing; + + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = display->var.xoffset; + var->yoffset = display->var.yoffset; + } + + /* XXX FIXME - forcing var's */ + var->xoffset = 0; + var->yoffset = 0; + + /* Limit bpp to 8, 16, and 32 */ + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + video_bpp = var->bits_per_pixel; + + var->grayscale = 0; /* No grayscale for now */ + + /* determine valid resolution and timing */ + for (min_mode=0; min_mode<GBE_VT_SIZE; min_mode++) { + if (gbeVTimings[min_mode].width >= var->xres && + gbeVTimings[min_mode].height >= var->yres) + break; + } + + if (min_mode == GBE_VT_SIZE) + return -EINVAL; /* Resolution to high */ + + /* XXX FIXME - should try to pick best refresh rate */ + /* for now, pick closest dot-clock within 3MHz*/ + req_dot = 1000000000 / var->pixclock; + printk(KERN_INFO "sgio2fb: requested pixclock=%d ps (%d KHz)\n", var->pixclock, + req_dot); + test_mode=min_mode; + while (gbeVTimings[min_mode].width == gbeVTimings[test_mode].width) { + if (gbeVTimings[test_mode].cfreq+3000 > req_dot) + break; + test_mode++; + } + if (gbeVTimings[min_mode].width != gbeVTimings[test_mode].width) + test_mode--; + min_mode = test_mode; + timing = &gbeVTimings[min_mode]; + printk(KERN_INFO "sgio2fb: granted dot-clock=%d KHz\n", timing->cfreq); + + /* Adjust virtual resolution, if necessary */ + if (var->xres > var->xres_virtual || (!ywrap && !ypan)) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual || (!ywrap && !ypan)) + var->yres_virtual = var->yres; + + /* + * Memory limit + */ + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length*var->yres_virtual > sgio2fb_mem_size) + return -ENOMEM; /* Virtual resolution to high */ + + switch (var->bits_per_pixel) + { + case 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: /* RGBA 5551 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 5; + var->blue.offset = 1; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGB 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + 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; + + /* set video timing information */ + var->pixclock = (__u32)(1000000000/timing->cfreq); + var->left_margin = timing->htotal - timing->hsync_end; + var->right_margin = timing->hsync_start - timing->width; + var->upper_margin = timing->vtotal - timing->vsync_end; + var->lower_margin = timing->vsync_start - timing->height; + var->hsync_len = timing->hsync_end - timing->hsync_start; + var->vsync_len = timing->vsync_end - timing->vsync_start; + + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + 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; + par_current.var = *var; + par_current.timing_num = min_mode; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || !par_current.valid) { + struct fb_fix_screeninfo fix; + printk(KERN_INFO "sgio2fb: new video mode xres=%d yres=%d bpp=%d\n", + var->xres, var->yres, var->bits_per_pixel); + printk(KERN_INFO " vxres=%d vyres=%d\n", + var->xres_virtual, var->yres_virtual); + activate_par(&par_current); + sgio2fb_encode_fix(&fix, var); + + display->screen_base = (char *)fbmem; + 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; + if (oldbpp != var->bits_per_pixel || !par_current.valid) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, info); + } + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + display->dispsw = &fbcon_cfb8; + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + display->dispsw_data = fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + display->dispsw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } + par_current.valid = 1; + if (fb_info.changevar) + (*fb_info.changevar)(con); + } + } + + return 0; +} + +/* + * Get the Colormap + */ +static int sgio2fb_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, sgio2fb_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 sgio2fb_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 == 8 ? 256 : 16; + if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0))) + return err; + } + if (con == currcon) /* current console? */ + return fb_set_cmap(cmap, kspc, sgio2fb_setcolreg, info); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return 0; +} + +static int sgio2fb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (offset+size > sgio2fb_mem_size) + return -EINVAL; + offset += sgio2fb_mem_phys; + pgprot_val(vma->vm_page_prot) = + (pgprot_val(vma->vm_page_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED; + vma->vm_flags |= VM_IO; + if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot)) + return -EAGAIN; + vma->vm_file = file; + printk(KERN_DEBUG "sgio2fb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start); + return 0; +} + +int __init sgio2fb_setup(char *options) +{ + char *this_opt; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + } + return 0; +} + +/* + * Initialisation + */ +int __init sgio2fb_init(void) +{ + printk(KERN_INFO "sgio2fb: initializing\n"); + + sgio2fb_mem_size = VIDEOMEMSIZE; + + if (!(sgio2fb_mem_phys = (u_long)__get_free_pages(GFP_DMA, get_order(sgio2fb_mem_size)))) { + printk(KERN_ERR "sgio2fb: couldn't allocate %ld bytes for the framebuffer\n", + sgio2fb_mem_size); + return -ENOMEM; + } + + /* TEMP: Make sure the framebuffer is uncached */ + sgio2fb_mem_phys = KSEG1ADDR(CPHYSADDR(sgio2fb_mem_phys)); + + if (!(sgio2fb_tiles_table = (u16 *)__get_free_page(GFP_DMA))) { + printk("sgio2fb: could not allocate tiles table\n"); + return -ENOMEM; + } + + /* TEMP: Make sure tiles are uncached too */ + sgio2fb_tiles_table = (u16 *)KSEG1ADDR(CPHYSADDR(sgio2fb_tiles_table)); + + memset(sgio2fb_tiles_table, 0, 128*sizeof(u16)); + + printk(KERN_INFO "sgio2fb: I/O at 0x%08x\n", GBE_REG_PHYS); + printk(KERN_INFO "sgio2fb: framebuffer at 0x%lx, size %ldk\n", + sgio2fb_mem_phys, sgio2fb_mem_size/1024); + printk(KERN_INFO "sgio2fb: tiles at %p\n", + sgio2fb_tiles_table); + + regs = (asregs*)GBE_REG_PHYS; + if (!regs) { + printk(KERN_ERR "sgio2fb: couldn't ioremap registers\n"); + goto fail_ioremap_regs; + } + + /* [VC] TODO: change caching attributes to write combined? + mtrr_add((unsigned long)sgio2fb_mem_phys, sgio2fb_mem_size, MTRR_TYPE_WRCOMB, 1); + */ + + strcpy(fb_info.modename, sgio2fb_name); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &sgio2fb_ops; + fb_info.disp = &disp; + fb_info.switch_con = &sgio2fbcon_switch; + fb_info.updatevar = &sgio2fbcon_updatevar; + fb_info.blank = &sgio2fbcon_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; + + /* TODO: mark pages as uncached (or write combined) */ + fbmem = (char*)sgio2fb_mem_phys; + + /* turn on default video mode */ + sgio2fb_set_var(&par_current.var, -1, &fb_info); + + if (register_framebuffer(&fb_info) < 0) { + printk(KERN_ERR "sgio2fb: couldn't register framebuffer\n"); + goto fail_register_framebuffer; + } + + printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n", + GET_FB_IDX(fb_info.node), sgio2fb_mem_size>>10); + + return 0; + + fail_register_framebuffer: + fail_ioremap_regs: + return -ENXIO; +} + +static int sgio2fbcon_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, 1, sgio2fb_getcolreg, info); + + currcon = con; + + /* Install new colormap */ + do_install_cmap(con, info); + + return 0; +} + +/* + * Update the `var' structure (called by fbcon.c) + */ +static int sgio2fbcon_updatevar(int con, struct fb_info *info) +{ + /* Nothing */ + return 0; +} + +/* + * Blank the display. + */ +static void sgio2fbcon_blank(int blank, struct fb_info *info) +{ + /* Nothing */ + /* TODO: turn off DMA */ +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return sgio2fb_init(); +} + +void cleanup_module(void) +{ + unregister_framebuffer(&fb_info); + gbe_TurnOffDma(); + iounmap(regs); + iounmap(fbmem); +} + +#endif /* MODULE */ diff -Naur linux64/drivers/video/sgio2fb.h linux64.new/drivers/video/sgio2fb.h --- linux64/drivers/video/sgio2fb.h Thu Jan 1 01:00:00 1970 +++ linux64.new/drivers/video/sgio2fb.h Wed May 15 23:12:24 2002 @@ -0,0 +1,560 @@ +/* + * linux/drivers/video/sgivwfb.h -- SGI GBE frame buffer device header + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Jeffrey Newquist, newquist@engr.sgi.som + * + * 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 __SGIO2FB_H__ +#define __SGIO2FB_H__ + +#include <asm/ip32/crime.h> +#include <asm/addrspace.h> + +#define CRIME_FLUSH crime_read_64(CRIME_CONTROL) + +#define GBE_GETREG(reg, dest) ((dest) = GBE_REG_BASE->##reg) +#define GBE_SETREG(reg, src) (GBE_REG_BASE->##reg = (src));CRIME_FLUSH +#define GBE_IGETREG(reg, idx, dest) ((dest) = GBE_REG_BASE->##reg##[idx]) +#define GBE_ISETREG(reg, idx, src) (GBE_REG_BASE->##reg##[idx] = (src));CRIME_FLUSH + +#define MASK(msb, lsb) ( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) ) +#define GET(v, msb, lsb) ( ((u32)(v) & MASK(msb,lsb)) >> (lsb) ) +#define SET(v, f, msb, lsb) ( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) ) + +#define GET_GBE_FIELD(reg, field, v) GET((v), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB) +#define SET_GBE_FIELD(reg, field, v, f) SET((v), (f), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB) + +/* NOTE: All loads/stores must be 32 bits and uncached */ + +#define GBE_REG_PHYS KSEG1ADDR(0x16000000) +#define GBE_REG_SIZE 0x01000000 + +typedef struct { + volatile u32 ctrlstat; /* 0x000000 general control */ + volatile u32 dotclock; /* 0x000004 dot clock PLL control */ + volatile u32 i2c; /* 0x000008 crt I2C control */ + volatile u32 sysclk; /* 0x00000c system clock PLL control */ + volatile u32 i2cfp; /* 0x000010 flat panel I2C control */ + volatile u32 id; /* 0x000014 device id/chip revision */ + volatile u32 config; /* 0x000018 power on configuration */ + volatile u32 bist; /* 0x00001c internal bist status */ + + char _pad0[ 0x010000 - 0x000020 ]; + + volatile u32 vt_xy; /* 0x010000 current dot coords */ + volatile u32 vt_xymax; /* 0x010004 maximum dot coords */ + volatile u32 vt_vsync; /* 0x010008 vsync on/off */ + volatile u32 vt_hsync; /* 0x01000c hsync on/off */ + volatile u32 vt_vblank; /* 0x010010 vblank on/off */ + volatile u32 vt_hblank; /* 0x010014 hblank on/off */ + volatile u32 vt_flags; /* 0x010018 polarity of vt signals */ + volatile u32 vt_f2rf_lock; /* 0x01001c f2rf & framelck y coord */ + volatile u32 vt_intr01; /* 0x010020 intr 0,1 y coords */ + volatile u32 vt_intr23; /* 0x010024 intr 2,3 y coords */ + volatile u32 fp_hdrv; /* 0x010028 flat panel hdrv on/off */ + volatile u32 fp_vdrv; /* 0x01002c flat panel vdrv on/off */ + volatile u32 fp_de; /* 0x010030 flat panel de on/off */ + volatile u32 vt_hpixen; /* 0x010034 intrnl horiz pixel on/off*/ + volatile u32 vt_vpixen; /* 0x010038 intrnl vert pixel on/off */ + volatile u32 vt_hcmap; /* 0x01003c cmap write (horiz) */ + volatile u32 vt_vcmap; /* 0x010040 cmap write (vert) */ + volatile u32 did_start_xy; /* 0x010044 eol/f did/xy reset val */ + volatile u32 crs_start_xy; /* 0x010048 eol/f crs/xy reset val */ + volatile u32 vc_start_xy; /* 0x01004c eol/f vc/xy reset val */ + + char _pad1[ 0x020000 - 0x010050 ]; + + volatile u32 ovr_width_tile; /* 0x020000 overlay plane ctrl 0 */ + volatile u32 ovr_inhwctrl; /* 0x020004 overlay plane ctrl 1 */ + volatile u32 ovr_control; /* 0x020008 overlay plane ctrl 1 */ + + char _pad2[ 0x030000 - 0x02000C ]; + + volatile u32 frm_size_tile; /* 0x030000 normal plane ctrl 0 */ + volatile u32 frm_size_pixel; /* 0x030004 normal plane ctrl 1 */ + volatile u32 frm_inhwctrl; /* 0x030008 normal plane ctrl 2 */ + volatile u32 frm_control; /* 0x03000C normal plane ctrl 3 */ + + char _pad3[ 0x040000 - 0x030010 ]; + + volatile u32 did_inhwctrl; /* 0x040000 DID control */ + volatile u32 did_control; /* 0x040004 DID shadow */ + + char _pad4[ 0x048000 - 0x040008 ]; + + volatile u32 mode_regs[32]; /* 0x048000 - 0x04807c WID table */ + + char _pad5[ 0x050000 - 0x048080 ]; + + volatile u32 cmap[6144]; /* 0x050000 - 0x055ffc color map */ + + char _pad6[ 0x058000 - 0x056000 ]; + + volatile u32 cm_fifo; /* 0x058000 color map fifo status */ + + char _pad7[ 0x060000 - 0x058004 ]; + + volatile u32 gmap[256]; /* 0x060000 - 0x0603fc gamma map */ + + char _pad8[ 0x068000 - 0x060400 ]; + + volatile u32 gmap10[1024]; /* 0x068000 - 0x068ffc gamma map */ + + char _pad9[ 0x070000 - 0x069000 ]; + + volatile u32 crs_pos; /* 0x070000 cusror control 0 */ + volatile u32 crs_ctl; /* 0x070004 cusror control 1 */ + volatile u32 crs_cmap[3]; /* 0x070008 - 0x070010 crs cmap */ + + char _pad10[ 0x078000 - 0x070014 ]; + + volatile u32 crs_glyph[64]; /* 0x078000 - 0x0780fc crs glyph */ + + char _pad11[ 0x080000 - 0x078100 ]; + + volatile u32 vc_0; /* 0x080000 video capture crtl 0 */ + volatile u32 vc_1; /* 0x080004 video capture crtl 1 */ + volatile u32 vc_2; /* 0x080008 video capture crtl 2 */ + volatile u32 vc_3; /* 0x08000c video capture crtl 3 */ + volatile u32 vc_4; /* 0x080010 video capture crtl 3 */ + volatile u32 vc_5; /* 0x080014 video capture crtl 3 */ + volatile u32 vc_6; /* 0x080018 video capture crtl 3 */ + volatile u32 vc_7; /* 0x08001c video capture crtl 3 */ + volatile u32 vc_8; /* 0x08000c video capture crtl 3 */ +} asregs; + +/* Bit mask information */ + +#define GBE_CTRLSTAT_CHIPID_MSB 3 +#define GBE_CTRLSTAT_CHIPID_LSB 0 +#define GBE_CTRLSTAT_SENSE_N_MSB 4 +#define GBE_CTRLSTAT_SENSE_N_LSB 4 +#define GBE_CTRLSTAT_PCLKSEL_MSB 29 +#define GBE_CTRLSTAT_PCLKSEL_LSB 28 + +#define GBE_DOTCLK_M_MSB 7 +#define GBE_DOTCLK_M_LSB 0 +#define GBE_DOTCLK_N_MSB 13 +#define GBE_DOTCLK_N_LSB 8 +#define GBE_DOTCLK_P_MSB 15 +#define GBE_DOTCLK_P_LSB 14 +#define GBE_DOTCLK_RUN_MSB 20 +#define GBE_DOTCLK_RUN_LSB 20 + +#define GBE_VT_XY_VT_FREEZE_MSB 31 +#define GBE_VT_XY_VT_FREEZE_LSB 31 + +#define GBE_VT_VSYNC_VT_VSYNC_ON_MSB 23 +#define GBE_VT_VSYNC_VT_VSYNC_ON_LSB 12 +#define GBE_VT_VSYNC_VT_VSYNC_OFF_MSB 11 +#define GBE_VT_VSYNC_VT_VSYNC_OFF_LSB 0 + +#define GBE_VT_HSYNC_VT_HSYNC_ON_MSB 23 +#define GBE_VT_HSYNC_VT_HSYNC_ON_LSB 12 +#define GBE_VT_HSYNC_VT_HSYNC_OFF_MSB 11 +#define GBE_VT_HSYNC_VT_HSYNC_OFF_LSB 0 + +#define GBE_VT_VBLANK_VT_VBLANK_ON_MSB 23 +#define GBE_VT_VBLANK_VT_VBLANK_ON_LSB 12 +#define GBE_VT_VBLANK_VT_VBLANK_OFF_MSB 11 +#define GBE_VT_VBLANK_VT_VBLANK_OFF_LSB 0 + +#define GBE_VT_HBLANK_VT_HBLANK_ON_MSB 23 +#define GBE_VT_HBLANK_VT_HBLANK_ON_LSB 12 +#define GBE_VT_HBLANK_VT_HBLANK_OFF_MSB 11 +#define GBE_VT_HBLANK_VT_HBLANK_OFF_LSB 0 + +#define GBE_VT_FLAGS_VT_F2RF_HIGH_MSB 6 +#define GBE_VT_FLAGS_VT_F2RF_HIGH_LSB 6 +#define GBE_VT_FLAGS_VT_SYNC_LOW_MSB 5 +#define GBE_VT_FLAGS_VT_SYNC_LOW_LSB 5 +#define GBE_VT_FLAGS_VT_SYNC_HIGH_MSB 4 +#define GBE_VT_FLAGS_VT_SYNC_HIGH_LSB 4 +#define GBE_VT_FLAGS_VT_HDRV_LOW_MSB 3 +#define GBE_VT_FLAGS_VT_HDRV_LOW_LSB 3 +#define GBE_VT_FLAGS_VT_HDRV_INVERT_MSB 2 +#define GBE_VT_FLAGS_VT_HDRV_INVERT_LSB 2 +#define GBE_VT_FLAGS_VT_VDRV_LOW_MSB 1 +#define GBE_VT_FLAGS_VT_VDRV_LOW_LSB 1 +#define GBE_VT_FLAGS_VT_VDRV_INVERT_MSB 0 +#define GBE_VT_FLAGS_VT_VDRV_INVERT_LSB 0 + +#define GBE_VT_VCMAP_VT_VCMAP_ON_MSB 23 +#define GBE_VT_VCMAP_VT_VCMAP_ON_LSB 12 +#define GBE_VT_VCMAP_VT_VCMAP_OFF_MSB 11 +#define GBE_VT_VCMAP_VT_VCMAP_OFF_LSB 0 + +#define GBE_VT_HCMAP_VT_HCMAP_ON_MSB 23 +#define GBE_VT_HCMAP_VT_HCMAP_ON_LSB 12 +#define GBE_VT_HCMAP_VT_HCMAP_OFF_MSB 11 +#define GBE_VT_HCMAP_VT_HCMAP_OFF_LSB 0 + +#define GBE_VT_XYMAX_VT_MAXX_MSB 11 +#define GBE_VT_XYMAX_VT_MAXX_LSB 0 +#define GBE_VT_XYMAX_VT_MAXY_MSB 23 +#define GBE_VT_XYMAX_VT_MAXY_LSB 12 + +#define GBE_VT_HPIXEN_VT_HPIXEN_ON_MSB 23 +#define GBE_VT_HPIXEN_VT_HPIXEN_ON_LSB 12 +#define GBE_VT_HPIXEN_VT_HPIXEN_OFF_MSB 11 +#define GBE_VT_HPIXEN_VT_HPIXEN_OFF_LSB 0 + +#define GBE_VT_VPIXEN_VT_VPIXEN_ON_MSB 23 +#define GBE_VT_VPIXEN_VT_VPIXEN_ON_LSB 12 +#define GBE_VT_VPIXEN_VT_VPIXEN_OFF_MSB 11 +#define GBE_VT_VPIXEN_VT_VPIXEN_OFF_LSB 0 + +#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB 0 +#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB 0 + +#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB 0 +#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB 0 + +#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB 13 +#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB 13 + +#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB 0 +#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB 0 +#define GBE_FRM_CONTROL_FRM_TILE_PTR_MSB 31 +#define GBE_FRM_CONTROL_FRM_TILE_PTR_LSB 9 +#define GBE_FRM_CONTROL_FRM_LINEAR_MSB 1 +#define GBE_FRM_CONTROL_FRM_LINEAR_LSB 1 + +#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB 0 +#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB 0 + +#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB 12 +#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB 5 +#define GBE_FRM_SIZE_TILE_FRM_RHS_MSB 4 +#define GBE_FRM_SIZE_TILE_FRM_RHS_LSB 0 +#define GBE_FRM_SIZE_TILE_FRM_DEPTH_MSB 14 +#define GBE_FRM_SIZE_TILE_FRM_DEPTH_LSB 13 +#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB 15 +#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB 15 + +#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB 31 +#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB 16 + +#define GBE_DID_CONTROL_DID_DMA_ENABLE_MSB 0 +#define GBE_DID_CONTROL_DID_DMA_ENABLE_LSB 0 +#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB 0 +#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB 0 + +#define GBE_DID_START_XY_DID_STARTY_MSB 23 +#define GBE_DID_START_XY_DID_STARTY_LSB 12 +#define GBE_DID_START_XY_DID_STARTX_MSB 11 +#define GBE_DID_START_XY_DID_STARTX_LSB 0 + +#define GBE_CRS_START_XY_CRS_STARTY_MSB 23 +#define GBE_CRS_START_XY_CRS_STARTY_LSB 12 +#define GBE_CRS_START_XY_CRS_STARTX_MSB 11 +#define GBE_CRS_START_XY_CRS_STARTX_LSB 0 + +#define GBE_WID_AUX_MSB 12 +#define GBE_WID_AUX_LSB 11 +#define GBE_WID_GAMMA_MSB 10 +#define GBE_WID_GAMMA_LSB 10 +#define GBE_WID_CM_MSB 9 +#define GBE_WID_CM_LSB 5 +#define GBE_WID_TYP_MSB 4 +#define GBE_WID_TYP_LSB 2 +#define GBE_WID_BUF_MSB 1 +#define GBE_WID_BUF_LSB 0 + +#define GBE_VC_START_XY_VC_STARTY_MSB 23 +#define GBE_VC_START_XY_VC_STARTY_LSB 12 +#define GBE_VC_START_XY_VC_STARTX_MSB 11 +#define GBE_VC_START_XY_VC_STARTX_LSB 0 + +/* Constants */ + +#define GBE_FRM_DEPTH_8 0 +#define GBE_FRM_DEPTH_16 1 +#define GBE_FRM_DEPTH_32 2 + +#define GBE_CMODE_I8 0 +#define GBE_CMODE_I12 1 +#define GBE_CMODE_RG3B2 2 +#define GBE_CMODE_RGB4 3 +#define GBE_CMODE_ARGB5 4 +#define GBE_CMODE_RGB8 5 +#define GBE_CMODE_RGBA5 6 +#define GBE_CMODE_RGB10 7 + +#define GBE_BMODE_BOTH 3 + +#define GBE_CRS_MAGIC 54 + +/* Config Register (GBE Only) Definitions */ + +#define GBE_CONFIG_VDAC_ENABLE 0x00000001 +#define GBE_CONFIG_VDAC_GSYNC 0x00000002 +#define GBE_CONFIG_VDAC_PBLANK 0x00000004 +#define GBE_CONFIG_FPENABLE 0x00000008 +#define GBE_CONFIG_LENDIAN 0x00000020 +#define GBE_CONFIG_TILEHIST 0x00000040 +#define GBE_CONFIG_EXT_ADDR 0x00000080 + +#define GBE_CONFIG_FBDEV ( GBE_CONFIG_VDAC_ENABLE | \ + GBE_CONFIG_VDAC_GSYNC | \ + GBE_CONFIG_VDAC_PBLANK | \ + GBE_CONFIG_LENDIAN | \ + GBE_CONFIG_EXT_ADDR ) + +/* + * Available Video Timings and Corresponding Indices + */ + +typedef enum { + GBE_VT_640_480_60, + GBE_VT_800_600_60, + GBE_VT_800_600_75, + + GBE_VT_1024_768_60, + GBE_VT_1024_768_75, + GBE_VT_1024_768_85, + + GBE_VT_1280_1024_50, + GBE_VT_1280_1024_60, + GBE_VT_1280_1024_75, + GBE_VT_1280_1024_85, + + GBE_VT_1600_1024_60, + + GBE_VT_1600_1200_60, + GBE_VT_1600_1200_75, + + GBE_VT_1920_1080_60, + + GBE_VT_UNKNOWN +} gbe_timing_t; + + + +/* + * Crime Video Timing Data Structure + */ + +typedef struct gbe_timing_info +{ + gbe_timing_t type; + int flags; + short width; /* Monitor resolution */ + short height; + int fields_sec; /* fields/sec (Hz -3 dec. places */ + int cfreq; /* pixel clock frequency (MHz -3 dec. places) */ + short htotal; /* Horizontal total pixels */ + short hblank_start; /* Horizontal blank start */ + short hblank_end; /* Horizontal blank end */ + short hsync_start; /* Horizontal sync start */ + short hsync_end; /* Horizontal sync end */ + short vtotal; /* Vertical total lines */ + short vblank_start; /* Vertical blank start */ + short vblank_end; /* Vertical blank end */ + short vsync_start; /* Vertical sync start */ + short vsync_end; /* Vertical sync end */ + short pll_m; /* PLL M parameter */ + short pll_n; /* PLL P parameter */ + short pll_p; /* PLL N parameter */ +} gbe_timing_info_t; + +/* Defines for gbe_vof_info_t flags */ + +#define GBE_VOF_UNKNOWNMON 1 +#define GBE_VOF_STEREO 2 +#define GBE_VOF_DO_GENSYNC 4 /* enable incoming sync */ +#define GBE_VOF_SYNC_ON_GREEN 8 /* sync on green */ +#define GBE_VOF_FLATPANEL 0x1000 /* FLATPANEL Timing */ +#define GBE_VOF_MAGICKEY 0x2000 /* Backdoor key */ + +/* + * GBE Timing Tables + */ + +#ifdef INCLUDE_TIMING_TABLE_DATA + +/* GBE crystal runs at 20Mhz */ +/* pll_m, pll_n, pll_p define the following frequencies */ +/* fvco = pll_m * 20Mhz / pll_n */ +/* fout = fvco / (2**pll_p) */ + +struct gbe_timing_info gbeVTimings[] = { + /* TODO: update timings, since crystal clock is 20Mhz instead of 27Mhz */ + { + GBE_VT_640_480_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 640, 480, 59934, 25172, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 800, 640, 800, 664, 760, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 525, 480, 525, 491, 493, + /* pll_m, pll_n, pll_p */ + 146, 29, 2 + }, + + { + GBE_VT_800_600_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 800, 600, 60317, 40000, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1056, 800, 1056, 840, 968, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 628, 600, 628, 601, 605, + /* pll_m, pll_n, pll_p */ + 240, 30, 2 + }, + + { + GBE_VT_800_600_75, + /* flags, width, height, fields_sec, cfreq */ + 0, 800, 600, 75000, 50000, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1056, 800, 1056, 816, 896, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 625, 600, 625, 601, 604, + /* pll_m, pll_n, pll_p */ + 150, 30, 1 + }, + + { + GBE_VT_1024_768_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 1024, 768, 58663, 63548, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1344, 1024, 1344, 1048, 1184, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 806, 768, 806, 771, 777, + /* pll_m, pll_n, pll_p */ + 197, 31, 1 + }, + + { + GBE_VT_1024_768_75, + /* flags, width, height, fields_sec, cfreq */ + 0, 1024, 768, 75029, 78750, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1312, 1024, 1312, 1040, 1136, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 800, 768, 800, 769, 772, + /* pll_m, pll_n, pll_p */ + 252, 32, 1 + }, + + { + GBE_VT_1024_768_85, + /* flags, width, height, fields_sec, cfreq */ + 0, 1024, 768, 84997, 94500, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1376, 1024, 1376, 1072, 1168, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 808, 768, 808, 769, 772, + /* pll_m, pll_n, pll_p */ + 189, 20, 1 + }, + + { + GBE_VT_1280_1024_50, + /* flags, width, height, fields_sec, cfreq */ + 0, 1280, 1024, 50000, 89544, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1680, 1280, 1680, 1360, 1480, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1065, 1024, 1065, 1027, 1030, + /* pll_m, pll_n, pll_p */ + 197, 44, 0 + }, + + { + GBE_VT_1280_1024_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 1280, 1024, 59916, 107272, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1688, 1280, 1688, 1328, 1440, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1066, 1024, 1066, 1025, 1028, + /* pll_m, pll_n, pll_p */ + 177, 33, 0 + }, + + { + GBE_VT_1280_1024_75, + /* flags, width, height, fields_sec, cfreq */ + 0, 1280, 1024, 75025, 135000, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1688, 1280, 1688, 1296, 1440, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1066, 1024, 1066, 1025, 1028, + /* pll_m, pll_n, pll_p */ + 216, 32, 0 + }, + + { + GBE_VT_1280_1024_85, + /* flags, width, height, fields_sec, cfreq */ + 0, 1280, 1024, 85024, 157500, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1728, 1280, 1728, 1344, 1504, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1072, 1024, 1072, 1025, 1028, + /* pll_m, pll_n, pll_p */ + 63, 8, 0 + }, + + { + GBE_VT_1600_1024_60, + /* flags, width, height, fields_sec, cfreq */ + GBE_VOF_FLATPANEL, 1600, 1024, 60000, 162925, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 1670, 1600, 1670, 1630, 1650, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1067, 1024, 1067, 1027, 1030, + /* pll_m, pll_n, pll_p */ + 224, 27, 0 + }, + + { + GBE_VT_1600_1200_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 1600, 1200, 59940, 162000, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 2160, 1600, 2160, 1644, 1856, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1250, 1200, 1250, 1201, 1204, + /* pll_m, pll_n, pll_p */ + 81, 10, 0 + }, + + { + GBE_VT_1600_1200_75, + /* flags, width, height, fields_sec, cfreq */ + 0, 1600, 1200, 75000, 202500, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 2160, 1600, 2160, 1644, 1856, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1250, 1200, 1250, 1201, 1204, + /* pll_m, pll_n, pll_p */ + 81, 8, 0 + }, + + { + GBE_VT_1920_1080_60, + /* flags, width, height, fields_sec, cfreq */ + 0, 1920, 1080, 60060, 160000, + /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */ + 2368, 1920, 2368, 1952, 2096, + /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */ + 1125, 1080, 1125, 1083, 1086, + /* pll_m, pll_n, pll_p */ + 8, 1, 0 + }, +}; + +#define GBE_VT_SIZE (sizeof(gbeVTimings)/sizeof(gbeVTimings[0])) +#endif // INCLUDE_TIMING_TABLE_DATA + +#endif // ! __SGIO2FB_H__
diff -Naur /share/linux.cvs/arch/mips64/mm/loadmmu.c linux.patched/arch/mips64/mm/loadmmu.c --- /share/linux.cvs/arch/mips64/mm/loadmmu.c Sun Mar 3 19:50:39 2002 +++ linux.patched/arch/mips64/mm/loadmmu.c Thu May 16 23:12:21 2002 @@ -30,11 +30,14 @@ void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); void (*_flush_page_to_ram)(struct page * page); +void (*_flush_icache_range)(unsigned long start, unsigned long end); +void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page); +void (*_flush_icache_all)(void); + /* MIPS specific cache operations */ void (*_flush_cache_sigtramp)(unsigned long addr); void (*_flush_cache_l2)(void); void (*_flush_cache_l1)(void); - /* DMA cache operations. */ void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); diff -Naur /share/linux.cvs/arch/mips64/mm/r4xx0.c linux.patched/arch/mips64/mm/r4xx0.c --- /share/linux.cvs/arch/mips64/mm/r4xx0.c Sun May 5 15:03:17 2002 +++ linux.patched/arch/mips64/mm/r4xx0.c Thu May 16 23:05:53 2002 @@ -1621,6 +1621,34 @@ blast_dcache32_page((unsigned long)page_address(page)); } +static void +r4k_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +static void +r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) +{ + /* + * We did an scache flush therefore PI is already clean. + */ +} + +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + flush_cache_all(); +} + /* * Writeback and invalidate the primary cache dcache before DMA. * @@ -2119,7 +2147,7 @@ _flush_page_to_ram = r4k_flush_page_to_ram_d32; break; } - + _flush_icache_page = r4k_flush_icache_page_p; _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; _dma_cache_wback = r4k_dma_cache_wback; _dma_cache_inv = r4k_dma_cache_inv_pc; @@ -2201,6 +2229,7 @@ _copy_page = r4k_copy_page_s128; break; } + _flush_icache_page = r4k_flush_icache_page_s; _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; _dma_cache_wback = r4k_dma_cache_wback; _dma_cache_inv = r4k_dma_cache_inv_sc; @@ -2253,6 +2282,7 @@ if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; } + _flush_icache_range = r4k_flush_icache_range; /* Ouch */ _flush_cache_l2 = r4k_flush_cache_l2; diff -Naur /share/linux.cvs/include/asm-mips64/pgtable.h linux.patched/include/asm-mips64/pgtable.h --- /share/linux.cvs/include/asm-mips64/pgtable.h Sun May 5 15:03:39 2002 +++ linux.patched/include/asm-mips64/pgtable.h Thu May 16 23:01:46 2002 @@ -60,12 +60,22 @@ #else +extern void (*_flush_icache_all)(void); +extern void (*_flush_icache_range)(unsigned long start, unsigned long end); +extern void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page); + #define flush_cache_mm(mm) _flush_cache_mm(mm) #define flush_cache_range(mm,start,end) _flush_cache_range(mm,start,end) #define flush_cache_page(vma,page) _flush_cache_page(vma, page) #define flush_page_to_ram(page) _flush_page_to_ram(page) #define flush_icache_range(start, end) _flush_icache_range(start, end) #define flush_icache_page(vma, page) _flush_icache_page(vma, page) +#ifdef CONFIG_VTAG_ICACHE +#define flush_icache_all() _flush_icache_all() +#else +#define flush_icache_all() do { } while(0) +#endif + #endif /* !CONFIG_CPU_R10000 */