patch-2.4.20 linux-2.4.20/drivers/video/sis/sis_main.c
Next file: linux-2.4.20/drivers/video/sis/sis_main.h
Previous file: linux-2.4.20/drivers/video/sis/sis_accel.h
Back to the patch index
Back to the overall index
- Lines: 5929
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/drivers/video/sis/sis_main.c
- Orig date:
Fri Aug 2 17:39:45 2002
diff -urN linux-2.4.19/drivers/video/sis/sis_main.c linux-2.4.20/drivers/video/sis/sis_main.c
@@ -8,11 +8,16 @@
* Authors: SiS (www.sis.com.tw)
* (Various others)
* Thomas Winischhofer <thomas@winischhofer.net>:
- * - many fixes and enhancements for 630 & 310 series,
- * - extended bridge handling, TV output for Chrontel
+ * - many fixes and enhancements for all chipset series,
+ * - extended bridge handling, TV output for Chrontel 7005
+ * - 650/LVDS support (for LCD panels up to 1400x1050)
+ * - 650/Chrontel 7019 support
+ * - 301B/301LV(x)/302B/302LV(x) LCD and TV support
* - memory queue handling enhancements,
- * - everything marked with "TW"
- * (see http://www.winischhofer.net/linuxsis630.shtml
+ * - 2D acceleration and y-panning,
+ * - portation to 2.5 API (yet incomplete)
+ * - everything marked with "TW" and more
+ * (see http://www.winischhofer.net/
* for more information and updates)
*/
@@ -36,6 +41,11 @@
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/agp_backend.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+#include <linux/spinlock.h>
+#endif
+
+#include "osdef.h"
#include <linux/types.h>
#include <linux/sisfb.h>
@@ -49,68 +59,52 @@
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
-#include "osdef.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+#include "../fbcon-accel.h"
+#endif
+
#include "vgatypes.h"
#include "sis_main.h"
+#include "sis.h"
//#ifdef LINUXBIOS
//#include "bios.h"
//#endif
/* -------------------- Macro definitions ---------------------------- */
-// #define SISFBDEBUG
-#undef SISFBDEBUG /* TW */
+#undef SISFBDEBUG /* TW: no debugging */
+
#ifdef SISFBDEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
-#define vgawb(reg,data) \
- (outb(data, ivideo.vga_base+reg))
-#define vgaww(reg,data) \
- (outw(data, ivideo.vga_base+reg))
-#define vgawl(reg,data) \
- (outl(data, ivideo.vga_base+reg))
-#define vgarb(reg) \
- (inb(ivideo.vga_base+reg))
-
-/* --------------- Hardware Access Routines -------------------------- */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+#ifdef SISFBACCEL
+#ifdef FBCON_HAS_CFB8
+extern struct display_switch fbcon_sis8;
+#endif
+#ifdef FBCON_HAS_CFB16
+extern struct display_switch fbcon_sis16;
+#endif
+#ifdef FBCON_HAS_CFB32
+extern struct display_switch fbcon_sis32;
+#endif
+#endif
+#endif
-void sisfb_set_reg1(u16 port, u16 index, u16 data)
-{
- outb((u8) (index & 0xff), port);
- port++;
- outb((u8) (data & 0xff), port);
-}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+/* TEMP */
+void my_cfb_imageblit(struct fb_info *info, struct fb_image *image);
+#endif
-void sisfb_set_reg3(u16 port, u16 data)
-{
- outb((u8) (data & 0xff), port);
-}
+/* --------------- Hardware Access Routines -------------------------- */
void sisfb_set_reg4(u16 port, unsigned long data)
{
outl((u32) (data & 0xffffffff), port);
}
-u8 sisfb_get_reg1(u16 port, u16 index)
-{
- u8 data;
-
- outb((u8) (index & 0xff), port);
- port += 1;
- data = inb(port);
- return (data);
-}
-
-u8 sisfb_get_reg2(u16 port)
-{
- u8 data;
-
- data = inb(port);
- return (data);
-}
-
u32 sisfb_get_reg3(u16 port)
{
u32 data;
@@ -119,25 +113,7 @@
return (data);
}
-// Eden Chen
-//void sisfb_clear_DAC(u16 port)
-//{
-// int i,j;
-//
-// vgawb(DAC_ADR, 0x00);
-// for(i=0; i<256; i++)
-// for(j=0; j<3; j++)
-// vgawb(DAC_DATA, 0);
-//}
-
-//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext)
-//{
-// memset((char *) ivideo.video_vbase, 0,
-// video_linelength * ivideo.video_height);
-//}
-// ~Eden Chen
-
-/* --------------- Interface to BIOS code ---------------------------- */
+/* -------------------- Interface to BIOS code -------------------- */
BOOLEAN
sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext,
@@ -178,7 +154,7 @@
return TRUE;
}
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
+BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
unsigned long offset, unsigned long set, unsigned long *value)
{
static struct pci_dev *pdev = NULL;
@@ -233,10 +209,13 @@
return TRUE;
}
-/* -------------------- Export functions ----------------------------- */
+/* -------------------- Exported functions ----------------------------- */
-static void sis_get_glyph(SIS_GLYINFO *gly)
+static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
struct display *p = &fb_display[currcon];
u16 c;
u8 *cdat;
@@ -244,7 +223,7 @@
u8 *gbuf = gly->gmask;
int size;
-
+ TWDEBUG("Inside get_glyph");
gly->fontheight = fontheight(p);
gly->fontwidth = fontwidth(p);
widthb = (fontwidth(p) + 7) / 8;
@@ -258,10 +237,15 @@
size = fontheight(p) * widthb;
memcpy(gbuf, cdat, size);
gly->ngmask = size;
+ TWDEBUG("End of get_glyph");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
}
void sis_dispinfo(struct ap_data *rec)
{
+ TWDEBUG("Inside dispinfo");
rec->minfo.bpp = ivideo.video_bpp;
rec->minfo.xres = ivideo.video_width;
rec->minfo.yres = ivideo.video_height;
@@ -278,125 +262,175 @@
rec->TV_type = ivideo.TV_type;
rec->TV_plug = ivideo.TV_plug;
rec->chip = ivideo.chip;
+ TWDEBUG("End of dispinfo");
}
/* ------------------ Internal Routines ------------------------------ */
static void sisfb_search_mode(const char *name)
{
- int i = 0;
+ int i = 0, j = 0;
- if (name == NULL)
+ if(name == NULL)
return;
- while (sisbios_mode[i].mode_no != 0) {
+ while(sisbios_mode[i].mode_no != 0) {
if (!strcmp(name, sisbios_mode[i].name)) {
sisfb_mode_idx = i;
+ j = 1;
break;
}
i++;
}
- if (sisfb_mode_idx < 0)
- printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
+ if(!j) printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
}
-static void sisfb_validate_mode(void)
+static void sisfb_search_vesamode(unsigned int vesamode)
{
- switch (ivideo.disp_state & DISPTYPE_DISP2) {
- case DISPTYPE_LCD:
- switch (sishw_ext.ulCRT2LCDType) {
- case LCD_1024x768:
- if (sisbios_mode[sisfb_mode_idx].xres > 1024)
- sisfb_mode_idx = -1;
- break;
- case LCD_1280x1024:
- case LCD_1280x960:
- if (sisbios_mode[sisfb_mode_idx].xres > 1280)
- sisfb_mode_idx = -1;
- break;
- case LCD_2048x1536:
- if (sisbios_mode[sisfb_mode_idx].xres > 2048)
- sisfb_mode_idx = -1;
- break;
- case LCD_1920x1440:
- if (sisbios_mode[sisfb_mode_idx].xres > 1920)
- sisfb_mode_idx = -1;
- break;
- case LCD_1600x1200:
- if (sisbios_mode[sisfb_mode_idx].xres > 1600)
- sisfb_mode_idx = -1;
- break;
- case LCD_800x600:
- if (sisbios_mode[sisfb_mode_idx].xres > 800)
- sisfb_mode_idx = -1;
- break;
- case LCD_640x480:
- if (sisbios_mode[sisfb_mode_idx].xres > 640)
- sisfb_mode_idx = -1;
- break;
- case LCD_320x480: /* TW: FSTN */
- if (sisbios_mode[sisfb_mode_idx].xres > 320)
- sisfb_mode_idx = -1;
+ int i = 0, j = 0;
+
+ if(vesamode == 0) {
+ sisfb_mode_idx = MODE_INDEX_NONE;
+ return;
+ }
+
+ vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
+
+ while(sisbios_mode[i].mode_no != 0) {
+ if( (sisbios_mode[i].vesa_mode_no_1 == vesamode) ||
+ (sisbios_mode[i].vesa_mode_no_2 == vesamode) ) {
+ sisfb_mode_idx = i;
+ j = 1;
break;
- default:
- sisfb_mode_idx = -1;
}
- if (sisbios_mode[sisfb_mode_idx].xres == 720)
- sisfb_mode_idx = -1;
+ i++;
+ }
+ if(!j) printk(KERN_INFO "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
+
+static int sisfb_validate_mode(int myindex)
+{
+ u16 xres, yres;
+
+#ifdef CONFIG_FB_SIS_300
+ if(sisvga_engine == SIS_300_VGA) {
+ if(!(sisbios_mode[sisfb_mode_idx].chipset & MD_SIS300)) {
+ return(-1);
+ }
+ }
+#endif
+#ifdef CONFIG_FB_SIS_315
+ if(sisvga_engine == SIS_315_VGA) {
+ if(!(sisbios_mode[myindex].chipset & MD_SIS315)) {
+ return(-1);
+ }
+ }
+#endif
+
+ switch (ivideo.disp_state & DISPTYPE_DISP2) {
+ case DISPTYPE_LCD:
+ switch (sishw_ext.ulCRT2LCDType) {
+ case LCD_1024x768:
+ xres = 1024; yres = 768; break;
+ case LCD_1280x1024:
+ xres = 1280; yres = 1024; break;
+ case LCD_1280x960:
+ xres = 1280; yres = 960; break;
+ case LCD_2048x1536:
+ xres = 2048; yres = 1536; break;
+ case LCD_1920x1440:
+ xres = 1920; yres = 1440; break;
+ case LCD_1600x1200:
+ xres = 1600; yres = 1200; break;
+ case LCD_800x600:
+ xres = 800; yres = 600; break;
+ case LCD_640x480:
+ xres = 640; yres = 480; break;
+ case LCD_320x480: /* TW: FSTN */
+ xres = 320; yres = 480; break;
+ case LCD_1024x600:
+ xres = 1024; yres = 600; break;
+ case LCD_1152x864:
+ xres = 1152; yres = 864; break;
+ case LCD_1152x768:
+ xres = 1152; yres = 768; break;
+ case LCD_1280x768:
+ xres = 1280; yres = 768; break;
+ case LCD_1400x1050:
+ xres = 1400; yres = 1050; break;
+ default:
+ xres = 0; yres = 0; break;
+ }
+ if(sisbios_mode[myindex].xres > xres) {
+ return(-1);
+ }
+ if(sisbios_mode[myindex].yres > yres) {
+ return(-1);
+ }
+ if (sisbios_mode[myindex].xres == 720) {
+ return(-1);
+ }
+ break;
+ case DISPTYPE_TV:
+ switch (sisbios_mode[myindex].xres) {
+ case 512:
+ case 640:
+ case 800:
break;
- case DISPTYPE_TV:
- switch (sisbios_mode[sisfb_mode_idx].xres) {
- case 800:
- case 640:
- break;
- case 720:
- if (ivideo.TV_type == TVMODE_NTSC) {
- if (sisbios_mode[sisfb_mode_idx].yres != 480)
- sisfb_mode_idx = -1;
- } else if (ivideo.TV_type == TVMODE_PAL) {
- if (sisbios_mode[sisfb_mode_idx].yres != 576)
- sisfb_mode_idx = -1;
- }
- /* TW: LVDS/CHRONTEL only supports 640 and 800 */
- if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
- ivideo.hasVB == HASVB_CHRONTEL)
- sisfb_mode_idx = -1;
- break;
- case 1024:
- if (ivideo.TV_type == TVMODE_NTSC) {
- if(sisbios_mode[sisfb_mode_idx].bpp == 32)
- sisfb_mode_idx = -1; /* TW; was -= 1 */
- /* TW: Should this mean a switch-back to
- * 16bpp or simply 'illegal mode'?
- */
- }
- /* TW: LVDS/CHRONTEL only supports 640 and 800 */
- if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
- ivideo.hasVB == HASVB_CHRONTEL)
- sisfb_mode_idx = -1;
- break;
- default:
- sisfb_mode_idx = -1;
+ case 720:
+ if (ivideo.TV_type == TVMODE_NTSC) {
+ if (sisbios_mode[myindex].yres != 480) {
+ return(-1);
+ }
+ } else if (ivideo.TV_type == TVMODE_PAL) {
+ if (sisbios_mode[myindex].yres != 576) {
+ return(-1);
+ }
+ }
+ /* TW: LVDS/CHRONTEL does not support 720 */
+ if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+ ivideo.hasVB == HASVB_CHRONTEL) {
+ return(-1);
+ }
+ break;
+ case 1024:
+ if (ivideo.TV_type == TVMODE_NTSC) {
+ if(sisbios_mode[myindex].bpp == 32) {
+ return(-1);
+ }
+ }
+ /* TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019)*/
+ if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+ ivideo.hasVB == HASVB_CHRONTEL) {
+ if(ivideo.chip < SIS_315H) {
+ return(-1);
+ }
}
break;
+ default:
+ return(-1);
}
+ break;
+ }
+ return(myindex);
}
static void sisfb_search_crt2type(const char *name)
{
int i = 0;
- if (name == NULL)
+ if(name == NULL)
return;
- while (sis_crt2type[i].type_no != -1) {
+ while(sis_crt2type[i].type_no != -1) {
if (!strcmp(name, sis_crt2type[i].name)) {
sisfb_crt2type = sis_crt2type[i].type_no;
+ sisfb_tvplug = sis_crt2type[i].tvplug_no;
break;
}
i++;
}
- if (sisfb_crt2type < 0)
+ if(sisfb_crt2type < 0)
printk(KERN_INFO "sisfb: Invalid CRT2 type: %s\n", name);
}
@@ -404,7 +438,7 @@
{
int i = 0;
- if (name == NULL)
+ if(name == NULL)
return;
while (sis_queuemode[i].type_no != -1) {
@@ -459,50 +493,51 @@
}
}
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
unsigned *transp, struct fb_info *fb_info)
{
- if (regno >= video_cmap_len)
+ if (regno >= ivideo.video_cmap_len)
return 1;
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
+ *red = sis_palette[regno].red;
+ *green = sis_palette[regno].green;
+ *blue = sis_palette[regno].blue;
*transp = 0;
return 0;
}
+#endif
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
- unsigned transp, struct fb_info *fb_info)
+static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *fb_info)
{
- if (regno >= video_cmap_len)
+ if (regno >= ivideo.video_cmap_len)
return 1;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
+ sis_palette[regno].red = red;
+ sis_palette[regno].green = green;
+ sis_palette[regno].blue = blue;
switch (ivideo.video_bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
- vgawb(DAC_ADR, regno);
- vgawb(DAC_DATA, red >> 10);
- vgawb(DAC_DATA, green >> 10);
- vgawb(DAC_DATA, blue >> 10);
+ outSISREG(SISDACA, regno);
+ outSISREG(SISDACD, (red >> 10));
+ outSISREG(SISDACD, (green >> 10));
+ outSISREG(SISDACD, (blue >> 10));
if (ivideo.disp_state & DISPTYPE_DISP2) {
- vgawb(DAC2_ADR, regno);
- vgawb(DAC2_DATA, red >> 8);
- vgawb(DAC2_DATA, green >> 8);
- vgawb(DAC2_DATA, blue >> 8);
+ outSISREG(SISDAC2A, regno);
+ outSISREG(SISDAC2D, (red >> 8));
+ outSISREG(SISDAC2D, (green >> 8));
+ outSISREG(SISDAC2D, (blue >> 8));
}
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
case 16:
- fbcon_cmap.cfb16[regno] =
- ((red & 0xf800)) |
- ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+ sis_fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
break;
#endif
#ifdef FBCON_HAS_CFB24
@@ -510,8 +545,7 @@
red >>= 8;
green >>= 8;
blue >>= 8;
- fbcon_cmap.cfb24[regno] =
- (red << 16) | (green << 8) | (blue);
+ sis_fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue);
break;
#endif
#ifdef FBCON_HAS_CFB32
@@ -519,8 +553,7 @@
red >>= 8;
green >>= 8;
blue >>= 8;
- fbcon_cmap.cfb32[regno] =
- (red << 16) | (green << 8) | (blue);
+ sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
break;
#endif
}
@@ -540,22 +573,24 @@
int found_mode = 0;
int old_mode;
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+ TWDEBUG("Inside do_set_var");
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
vtotal = var->upper_margin + var->yres + var->lower_margin +
var->vsync_len; /* TW */
vtotal <<= 1;
- } else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
vtotal = var->upper_margin + var->yres + var->lower_margin +
var->vsync_len; /* TW */
vtotal <<= 2;
- } else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
var->vsync_len; /* TW */
/* var->yres <<= 1; */ /* TW */
} else vtotal = var->upper_margin + var->yres + var->lower_margin +
var->vsync_len;
- if (!(htotal) || !(vtotal)) {
+ if(!(htotal) || !(vtotal)) {
DPRINTK("sisfb: Invalid 'var' information\n");
return -EINVAL;
}
@@ -564,17 +599,20 @@
hrate = drate / htotal;
ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
- DPRINTK("sisfb: Change mode to %dx%dx%d-%dMHz\n",
+ /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+ if((var->xres == 1024) && (var->yres == 600)) ivideo.refresh_rate = 60;
+
+ printk("sisfb: Change mode to %dx%dx%d-%dHz\n",
var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
old_mode = sisfb_mode_idx;
sisfb_mode_idx = 0;
- while ((sisbios_mode[sisfb_mode_idx].mode_no != 0)
- && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) {
- if ((sisbios_mode[sisfb_mode_idx].xres == var->xres)
- && (sisbios_mode[sisfb_mode_idx].yres == var->yres)
- && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
+ while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) &&
+ (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) {
+ if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
+ (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
+ (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
found_mode = 1;
break;
@@ -582,66 +620,97 @@
sisfb_mode_idx++;
}
- if (found_mode)
- sisfb_validate_mode();
+ if(found_mode)
+ sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
else
sisfb_mode_idx = -1;
- if (sisfb_mode_idx < 0) {
- DPRINTK("sisfb: sisfb does not support mode %dx%d-%d\n", var->xres,
+ if(sisfb_mode_idx < 0) {
+ printk("sisfb: Mode %dx%dx%d not supported\n", var->xres,
var->yres, var->bits_per_pixel);
sisfb_mode_idx = old_mode;
return -EINVAL;
}
- if (sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
+ if(sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
ivideo.refresh_rate = 60;
}
- if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
-
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+ if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+#else
+ if(isactive) {
+#endif
sisfb_pre_setmode();
- if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
- DPRINTK("sisfb: Setting mode[0x%x]: failed\n", sisfb_mode_no);
- return -1;
+ if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+ printk("sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
+ return -EINVAL;
}
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sisfb_post_setmode();
- DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n", sisbios_mode[sisfb_mode_idx].xres,
- sisbios_mode[sisfb_mode_idx].yres, sisbios_mode[sisfb_mode_idx].bpp,
+ DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n",
+ sisbios_mode[sisfb_mode_idx].xres,
+ sisbios_mode[sisfb_mode_idx].yres,
+ sisbios_mode[sisfb_mode_idx].bpp,
ivideo.refresh_rate);
ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
ivideo.org_x = ivideo.org_y = 0;
- video_linelength =
- ivideo.video_width * (ivideo.video_bpp >> 3);
+ ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+ switch(ivideo.video_bpp) {
+ case 8:
+ ivideo.DstColor = 0x0000;
+ ivideo.SiS310_AccelDepth = 0x00000000;
+ ivideo.video_cmap_len = 256;
+ break;
+ case 16:
+ ivideo.DstColor = 0x8000;
+ ivideo.SiS310_AccelDepth = 0x00010000;
+ ivideo.video_cmap_len = 16;
+ break;
+ case 32:
+ ivideo.DstColor = 0xC000;
+ ivideo.SiS310_AccelDepth = 0x00020000;
+ ivideo.video_cmap_len = 16;
+ break;
+ default:
+ ivideo.video_cmap_len = 16;
+ printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+ break;
+ }
}
+ TWDEBUG("End of do_set_var");
return 0;
}
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
+/* ------ Internal functions only for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct fb_fix_screeninfo fix;
+ long flags;
struct display *display;
struct display_switch *sw;
- u32 flags;
- if (con >= 0)
+ if(con >= 0)
display = &fb_display[con];
else
- display = &disp;
+ display = &sis_disp;
sisfb_get_fix(&fix, con, 0);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
display->screen_base = ivideo.video_vbase;
+#endif
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
@@ -654,29 +723,42 @@
display->var = *var;
save_flags(flags);
+
switch (ivideo.video_bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
+#ifdef SISFBACCEL
+ sw = sisfb_accel ? &fbcon_sis8 : &fbcon_cfb8;
+#else
sw = &fbcon_cfb8;
+#endif
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
case 16:
+#ifdef SISFBACCEL
+ sw = sisfb_accel ? &fbcon_sis16 : &fbcon_cfb16;
+#else
sw = &fbcon_cfb16;
- display->dispsw_data = fbcon_cmap.cfb16;
+#endif
+ display->dispsw_data = sis_fbcon_cmap.cfb16;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
sw = &fbcon_cfb24;
- display->dispsw_data = fbcon_cmap.cfb24;
+ display->dispsw_data = sis_fbcon_cmap.cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
+#ifdef SISFBACCEL
+ sw = sisfb_accel ? &fbcon_sis32 : &fbcon_cfb32;
+#else
sw = &fbcon_cfb32;
- display->dispsw_data = fbcon_cmap.cfb32;
+#endif
+ display->dispsw_data = sis_fbcon_cmap.cfb32;
break;
#endif
default:
@@ -687,1922 +769,2349 @@
display->dispsw = &sisfb_sw;
restore_flags(flags);
+#ifdef SISFB_PAN
+ if(sisfb_ypan) {
+ /* display->scrollmode = SCROLL_YPAN; - not defined */
+ } else {
+ display->scrollmode = SCROLL_YREDRAW;
+ sisfb_sw.bmove = fbcon_redraw_bmove;
+ }
+#else
display->scrollmode = SCROLL_YREDRAW;
sisfb_sw.bmove = fbcon_redraw_bmove;
+#endif
}
static void sisfb_do_install_cmap(int con, struct fb_info *info)
{
- if (con != currcon)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+ if (con != info->currcon)
return;
- if (fb_display[con].cmap.len)
- fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
- else
- fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
- sis_setcolreg, info);
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, info);
+ else
+ fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, info);
+#else
+ if (con != currcon)
+ return;
+
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
+ sisfb_setcolreg, info);
+#endif
}
+#endif
+/* ------ functions for all series ------ */
-/* --------------- Chip-dependent Routines --------------------------- */
+#ifdef SISFB_PAN
+static void sisfb_pan_var(struct fb_var_screeninfo *var)
+{
+ unsigned int base;
-#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
-static int sisfb_get_dram_size_300(void)
+ TWDEBUG("Inside pan_var");
+
+ base = var->yoffset * var->xres_virtual + var->xoffset;
+
+ /* calculate base bpp dep. */
+ switch(var->bits_per_pixel) {
+ case 16:
+ base >>= 1;
+ break;
+ case 32:
+ break;
+ case 8:
+ default:
+ base >>= 2;
+ break;
+ }
+
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+ outSISIDXREG(SISCR, 0x0D, base & 0xFF);
+ outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
+ outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
+ if(sisvga_engine == SIS_315_VGA) {
+ setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+ }
+ if(ivideo.disp_state & DISPTYPE_DISP2) {
+ orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+ outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+ outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+ outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+ if(sisvga_engine == SIS_315_VGA) {
+ setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+ }
+ }
+ TWDEBUG("End of pan_var");
+}
+#endif
+
+static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
{
- struct pci_dev *pdev = NULL;
- int pdev_valid = 0;
- u8 pci_data, reg;
- u16 nbridge_id;
+ u16 VRE, VBE, VRS, VBS, VDE, VT;
+ u16 HRE, HBE, HRS, HBS, HDE, HT;
+ u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
+ int A, B, C, D, E, F, temp;
+ double hrate, drate;
- switch (ivideo.chip) {
- case SIS_540:
- nbridge_id = PCI_DEVICE_ID_SI_540;
- break;
- case SIS_630:
- nbridge_id = PCI_DEVICE_ID_SI_630;
+ TWDEBUG("Inside crtc_to_var");
+ inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+
+ if (sr_data & SIS_INTERLACED_MODE)
+ var->vmode = FB_VMODE_INTERLACED;
+ else
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ switch ((sr_data & 0x1C) >> 2) {
+ case SIS_8BPP_COLOR_MODE:
+ var->bits_per_pixel = 8;
break;
- case SIS_730:
- nbridge_id = PCI_DEVICE_ID_SI_730;
+ case SIS_16BPP_COLOR_MODE:
+ var->bits_per_pixel = 16;
break;
- default:
- nbridge_id = 0;
+ case SIS_32BPP_COLOR_MODE:
+ var->bits_per_pixel = 32;
break;
}
- if (nbridge_id == 0) { /* 300 */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- ivideo.video_size =
- ((unsigned int) ((vgarb(SEQ_DATA) & SIS_DRAM_SIZE_MASK) + 1) << 20);
- } else { /* 540, 630, 730 */
- pci_for_each_dev(pdev) {
- if ((pdev->vendor == PCI_VENDOR_ID_SI)
- && (pdev->device == nbridge_id)) {
- pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
- pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
- ivideo.video_size = (unsigned int)(1 << (pci_data+21));
- pdev_valid = 1;
-
- reg = SIS_DATA_BUS_64 << 6;
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- switch (pci_data) {
- case BRI_DRAM_SIZE_2MB:
- reg |= SIS_DRAM_SIZE_2MB;
- break;
- case BRI_DRAM_SIZE_4MB:
- reg |= SIS_DRAM_SIZE_4MB;
- break;
- case BRI_DRAM_SIZE_8MB:
- reg |= SIS_DRAM_SIZE_8MB;
- break;
- case BRI_DRAM_SIZE_16MB:
- reg |= SIS_DRAM_SIZE_16MB;
- break;
- case BRI_DRAM_SIZE_32MB:
- reg |= SIS_DRAM_SIZE_32MB;
- break;
- case BRI_DRAM_SIZE_64MB:
- reg |= SIS_DRAM_SIZE_64MB;
- break;
- }
- vgawb(SEQ_DATA, reg);
- break;
- }
- }
-
- if (!pdev_valid)
- return -1;
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ ivideo.video_cmap_len = 256;
+ break;
+ case 16:
+ 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;
+ ivideo.video_cmap_len = 16;
+ break;
+ case 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;
+ ivideo.video_cmap_len = 16;
+ break;
+ case 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;
+ ivideo.video_cmap_len = 16;
+ break;
}
- return 0;
-}
-static void sisfb_detect_VB_connect_300()
-{
- u8 sr16, sr17, cr32, temp;
+ inSISIDXREG(SISSR, 0x0A, sr_data);
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
- sr17 = vgarb(SEQ_DATA);
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
- cr32 = vgarb(CRTC_DATA);
+ inSISIDXREG(SISCR, 0x06, cr_data);
- ivideo.TV_plug = ivideo.TV_type = 0;
- if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
- if ((sr17 & 0x01) && !sisfb_crt1off)
- sisfb_crt1off = 0;
- else {
- if (sr17 & 0x0E)
- sisfb_crt1off = 1;
- else
- sisfb_crt1off = 0;
- }
+ inSISIDXREG(SISCR, 0x07, cr_data2);
- if (sisfb_crt2type != -1)
- /* TW: override detected CRT2 type */
- ivideo.disp_state = sisfb_crt2type;
- else if (sr17 & 0x08 )
- ivideo.disp_state = DISPTYPE_CRT2;
- else if (sr17 & 0x02)
- ivideo.disp_state = DISPTYPE_LCD;
- else if (sr17 & 0x04)
- ivideo.disp_state = DISPTYPE_TV;
- else
- ivideo.disp_state = 0;
+ VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
+ ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10);
+ A = VT + 2;
- if (sr17 & 0x20)
- ivideo.TV_plug = TVPLUG_SVIDEO;
- else if (sr17 & 0x10)
- ivideo.TV_plug = TVPLUG_COMPOSITE;
+ inSISIDXREG(SISCR, 0x12, cr_data);
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_16);
- sr16 = vgarb(SEQ_DATA);
- if (sr16 & 0x20)
- ivideo.TV_type = TVMODE_PAL;
- else
- ivideo.TV_type = TVMODE_NTSC;
- } else {
- if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
- sisfb_crt1off = 0;
- else {
- if (cr32 & 0x5F)
- sisfb_crt1off = 1;
- else
- sisfb_crt1off = 0;
- }
+ VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
+ ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
+ E = VDE + 1;
- if (sisfb_crt2type != -1)
- /* TW: override detected CRT2 type */
- ivideo.disp_state = sisfb_crt2type;
- else if (cr32 & SIS_VB_CRT2)
- ivideo.disp_state = DISPTYPE_CRT2;
- else if (cr32 & SIS_VB_LCD)
- ivideo.disp_state = DISPTYPE_LCD;
- else if (cr32 & SIS_VB_TV)
- ivideo.disp_state = DISPTYPE_TV;
- else
- ivideo.disp_state = 0;
+ inSISIDXREG(SISCR, 0x10, cr_data);
- /* TW: Detect TV plug & type anyway */
- if (cr32 & SIS_VB_HIVISION) {
- ivideo.TV_type = TVMODE_HIVISION;
- ivideo.TV_plug = TVPLUG_SVIDEO;
- }
- else if (cr32 & SIS_VB_SVIDEO)
- ivideo.TV_plug = TVPLUG_SVIDEO;
- else if (cr32 & SIS_VB_COMPOSITE)
- ivideo.TV_plug = TVPLUG_COMPOSITE;
- else if (cr32 & SIS_VB_SCART)
- ivideo.TV_plug = TVPLUG_SCART;
+ VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
+ ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
+ F = VRS + 1 - E;
- if (ivideo.TV_type == 0) {
- // Eden Chen
- //temp = *((u8 *)(sishw_ext.VirtualRomBase+0x52));
- //if (temp&0x40) {
- // temp=*((u8 *)(sishw_ext.VirtualRomBase+0x53));
- //} else {
- vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
- temp = vgarb(SEQ_DATA);
- //}
- // ~Eden Chen
- if (temp & 0x01)
- ivideo.TV_type = TVMODE_PAL;
- else
- ivideo.TV_type = TVMODE_NTSC;
- }
- }
+ inSISIDXREG(SISCR, 0x15, cr_data);
- /* TW: Copy forceCRT1 option to CRT1off if option is given */
- if (sisfb_forcecrt1 != -1) {
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
- sr17 = vgarb(SEQ_DATA);
- if (sisfb_forcecrt1) {
- sisfb_crt1off=0;
- sr17 |= 0x80;
- } else {
- sisfb_crt1off=1;
- sr17 &= ~0x80;
- }
- vgawb(SEQ_DATA, sr17);
- }
-}
+ inSISIDXREG(SISCR, 0x09, cr_data3);
-static void sisfb_get_VB_type_300(void)
-{
- u8 reg;
+ VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
+ ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
- if (ivideo.chip != SIS_300) {
- if (!sisfb_has_VB_300()) {
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
- reg = vgarb(CRTC_DATA);
+ inSISIDXREG(SISCR, 0x16, cr_data);
- switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
- case SIS_EXTERNAL_CHIP_SIS301:
- ivideo.hasVB = HASVB_301;
- break;
- case SIS_EXTERNAL_CHIP_LVDS:
- ivideo.hasVB = HASVB_LVDS;
- break;
- case SIS_EXTERNAL_CHIP_TRUMPION:
- ivideo.hasVB = HASVB_TRUMPION;
- break;
- case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
- ivideo.hasVB = HASVB_LVDS_CHRONTEL;
- break;
- case SIS_EXTERNAL_CHIP_CHRONTEL:
- ivideo.hasVB = HASVB_CHRONTEL;
- break;
- default:
- break;
- }
- }
- } else {
- sisfb_has_VB_300();
+ VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
+ temp = VBE - ((E - 1) & 511);
+ B = (temp > 0) ? temp : (temp + 512);
+
+ inSISIDXREG(SISCR, 0x11, cr_data);
+
+ VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+ temp = VRE - ((E + F - 1) & 31);
+ C = (temp > 0) ? temp : (temp + 32);
+
+ D = B - F - C;
+
+
+ var->yres = E;
+#ifndef SISFB_PAN
+ var->yres_virtual = E;
+#endif
+ /* TW: We have to report the physical dimension to the console! */
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ var->yres <<= 1;
+#ifndef SISFB_PAN
+ var->yres_virtual <<= 1;
+#endif
}
- //sishw_ext.hasVB = ivideo.hasVB;
+ /* TW end */
+ var->upper_margin = D;
+ var->lower_margin = F;
+ var->vsync_len = C;
+
+ inSISIDXREG(SISSR, 0x0b, sr_data);
+
+ inSISIDXREG(SISCR, 0x00, cr_data);
+
+ HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
+ A = HT + 5;
+
+ inSISIDXREG(SISCR, 0x01, cr_data);
+
+ HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
+ E = HDE + 1;
+
+ inSISIDXREG(SISCR, 0x04, cr_data);
+
+ HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
+ F = HRS - E - 3;
+
+ inSISIDXREG(SISCR, 0x02, cr_data);
+
+ HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+
+ inSISIDXREG(SISSR, 0x0c, sr_data);
+
+ inSISIDXREG(SISCR, 0x03, cr_data);
+
+ inSISIDXREG(SISCR, 0x15, cr_data2);
+
+ HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
+ ((u16) (sr_data & 0x03) << 6);
+ HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+ temp = HBE - ((E - 1) & 255);
+ B = (temp > 0) ? temp : (temp + 256);
+
+ temp = HRE - ((E + F + 3) & 63);
+ C = (temp > 0) ? temp : (temp + 64);
+
+ D = B - F - C;
+
+ var->xres = var->xres_virtual = E * 8;
+ var->left_margin = D * 8;
+ var->right_margin = F * 8;
+ var->hsync_len = C * 8;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ var->sync = 0;
+
+ mr_data = inSISREG(SISMISCR);
+#if 0
+ mr_data = vgarb(0x1C);
+#endif
+ if (mr_data & 0x80)
+ var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if (mr_data & 0x40)
+ var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ VT += 2;
+ VT <<= 1;
+ HT = (HT + 5) * 8;
+
+ hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+ drate = hrate * HT;
+ var->pixclock = (u32) (1E12 / drate);
+
+#ifdef SISFB_PAN
+ if(sisfb_ypan) {
+ var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+ if(var->yres_virtual <= var->yres) {
+ var->yres_virtual = var->yres;
+ }
+ } else
+#endif
+ var->yres_virtual = var->yres;
+
+ TWDEBUG("end of crtc_to_var");
}
-static int sisfb_has_VB_300(void)
+/* ------------------ Public Routines -------------------------------- */
+
+/* -------- functions only for for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
- // Eden Chen
- //u8 sr38, sr39, vb_chipid;
- u8 vb_chipid;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+ int err;
+ unsigned int cols, rows;
- //vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
- //sr38 = vgarb(SEQ_DATA);
- //vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP2);
- //sr39 = vgarb(SEQ_DATA);
- vgawb(VB_PART4_ADR, 0x0);
- vb_chipid = vgarb(VB_PART4_DATA);
-
- switch (vb_chipid) {
- case 0x01:
- ivideo.hasVB = HASVB_301;
- break;
- case 0x02:
- ivideo.hasVB = HASVB_302;
- break;
- case 0x03:
- ivideo.hasVB = HASVB_303;
- break;
- default:
- ivideo.hasVB = HASVB_NONE;
- return FALSE;
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+ if(sisfb_do_set_var(var, con == currcon, info)) {
+ sisfb_crtc_to_var(var);
+ return -EINVAL;
}
- return TRUE;
- //if (
- // ( (ivideo.chip == SIS_300) && (sr38 & 0x20) )
- // ||
- // ( (ivideo.chip == SIS_540) && (sr38 & 0x20) && (!(sr39 & 0x80)) )
- // ||
- // ( (ivideo.chip == SIS_630 ) && (sr38 & 0x20) && (!(sr39 & 0x80)) &&
- // ((ivideo.revision_id & 0xf0) < 0x30) && (vb_chipid == 1) )
- // ||
- // ( (ivideo.chip == SIS_630 ) && ((ivideo.revision_id & 0xf0) >= 0x30) &&
- // (vb_chipid == 1) )
- // ||
- // ( (ivideo.chip == SIS_730) && (vb_chipid == 1) ) /* 730 */
- //) {
- // ivideo.hasVB = HASVB_301;
- // return TRUE;
- //} else {
- // ivideo.hasVB = HASVB_NONE;
- // return FALSE;
- //}
+ sisfb_crtc_to_var(var);
+
+ sisfb_set_disp(con, var, info);
+
+ if(info->changevar)
+ (*info->changevar) (con);
+
+ if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+ return err;
+
+ sisfb_do_install_cmap(con, info);
+
+ cols = sisbios_mode[sisfb_mode_idx].cols;
+ rows = sisbios_mode[sisfb_mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
- // ~Eden Chen
+ return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
}
-#endif /* CONFIG_FB_SIS_300 */
-#ifdef CONFIG_FB_SIS_315 /* for SiS 315H/315PRO/550/650/740 */
-static int sisfb_get_dram_size_315(void)
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
- struct pci_dev *pdev = NULL;
- int pdev_valid = 0;
- u8 pci_data;
- u8 reg = 0;
-
- if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-#ifdef LINUXBIOS
- pci_for_each_dev(pdev) {
- if ( (pdev->vendor == PCI_VENDOR_ID_SI)
- && ( (pdev->device == PCI_DEVICE_ID_SI_550)
- || (pdev->device == PCI_DEVICE_ID_SI_650))) {
- pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
- &pci_data);
- pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
- ivideo.video_size =
- (unsigned int)(1 << (pci_data+21));
- pdev_valid = 1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+ if (con == currcon)
+ return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
- /* TW: Initialize SR14 "by hand" */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- reg = vgarb(SEQ_DATA) & 0xC0;
+ else if (fb_display[con].cmap.len)
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
- switch (pci_data) {
- //case BRI_DRAM_SIZE_2MB:
- // reg |= (SIS315_DRAM_SIZE_2MB << 4); break;
- case BRI_DRAM_SIZE_4MB:
- reg |= SIS550_DRAM_SIZE_4MB;
- break;
- case BRI_DRAM_SIZE_8MB:
- reg |= SIS550_DRAM_SIZE_8MB;
- break;
- case BRI_DRAM_SIZE_16MB:
- reg |= SIS550_DRAM_SIZE_16MB;
- break;
- case BRI_DRAM_SIZE_32MB:
- reg |= SIS550_DRAM_SIZE_32MB;
- break;
- case BRI_DRAM_SIZE_64MB:
- reg |= SIS550_DRAM_SIZE_64MB;
- break;
- /* case BRI_DRAM_SIZE_128MB:
- reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
- }
+ return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
- /* TODO : set Dual channel and bus width bits here */
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
- vgawb(SEQ_DATA, reg);
- break;
- }
- }
-
- if (!pdev_valid)
- return -1;
+ if (!fb_display[con].cmap.len) {
+ err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
+ if (err)
+ return err;
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+ if (con == info->currcon)
+ return fb_set_cmap(cmap, kspc, info);
#else
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- reg = vgarb(SEQ_DATA);
- switch (reg & SIS550_DRAM_SIZE_MASK) {
- case SIS550_DRAM_SIZE_4MB:
- ivideo.video_size = 0x400000; break;
- case SIS550_DRAM_SIZE_8MB:
- ivideo.video_size = 0x800000; break;
- case SIS550_DRAM_SIZE_16MB:
- ivideo.video_size = 0x1000000; break;
- case SIS550_DRAM_SIZE_24MB:
- ivideo.video_size = 0x1800000; break;
- case SIS550_DRAM_SIZE_32MB:
- ivideo.video_size = 0x2000000; break;
- case SIS550_DRAM_SIZE_64MB:
- ivideo.video_size = 0x4000000; break;
- case SIS550_DRAM_SIZE_96MB:
- ivideo.video_size = 0x6000000; break;
- case SIS550_DRAM_SIZE_128MB:
- ivideo.video_size = 0x8000000; break;
- case SIS550_DRAM_SIZE_256MB:
- ivideo.video_size = 0x10000000; break;
- default:
- /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),
- * do it the hard way ourselves in this case. Unfortunately, we don't
- * support 24, 48, 96 and other "odd" amounts here. I don't know if
- * this work-around is required for 650/740 as well, but do it in case
- * for now.
- */
- printk(KERN_INFO
- "sisfb: Warning: Could not determine memory size, "
- "now reading from PCI config\n");
- pdev_valid = 0;
- pci_for_each_dev(pdev) {
- if ( (pdev->vendor == PCI_VENDOR_ID_SI)
- && ( (pdev->device == PCI_DEVICE_ID_SI_550)
- || (pdev->device == PCI_DEVICE_ID_SI_650) ) ) {
- pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
- &pci_data);
- pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
- ivideo.video_size = (unsigned int)(1 << (pci_data+21));
- pdev_valid = 1;
- /* TW: Initialize SR14=IND_SIS_DRAM_SIZE */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- reg = vgarb(SEQ_DATA) & 0xC0;
- switch (pci_data) {
- case BRI_DRAM_SIZE_4MB:
- reg |= SIS550_DRAM_SIZE_4MB; break;
- case BRI_DRAM_SIZE_8MB:
- reg |= SIS550_DRAM_SIZE_8MB; break;
- case BRI_DRAM_SIZE_16MB:
- reg |= SIS550_DRAM_SIZE_16MB; break;
- case BRI_DRAM_SIZE_32MB:
- reg |= SIS550_DRAM_SIZE_32MB; break;
- case BRI_DRAM_SIZE_64MB:
- reg |= SIS550_DRAM_SIZE_64MB; break;
- /* case BRI_DRAM_SIZE_128MB:
- reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
- default:
- printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");
- return -1;
- }
- vgawb(SEQ_DATA, reg);
- }
- }
- if (!pdev_valid) {
- printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");
- return -1;
- }
- return 0;
- }
+ if (con == currcon)
+ return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
#endif
- return 0;
- } else { /* 315 */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- reg = vgarb(SEQ_DATA);
- switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
- case SIS315_DRAM_SIZE_2MB:
- ivideo.video_size = 0x200000;
- break;
- case SIS315_DRAM_SIZE_4MB:
- ivideo.video_size = 0x400000;
- break;
- case SIS315_DRAM_SIZE_8MB:
- ivideo.video_size = 0x800000;
- break;
- case SIS315_DRAM_SIZE_16MB:
- ivideo.video_size = 0x1000000;
- break;
- case SIS315_DRAM_SIZE_32MB:
- ivideo.video_size = 0x2000000;
- break;
- case SIS315_DRAM_SIZE_64MB:
- ivideo.video_size = 0x4000000;
- break;
- case SIS315_DRAM_SIZE_128MB:
- ivideo.video_size = 0x8000000;
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+#endif
+
+/* -------- functions only for 2.5 series ------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int sisfb_set_par(struct fb_info *info)
+{
+ int err;
+
+ TWDEBUG("inside set_par\n");
+ if((err = sisfb_do_set_var(&info->var, 1, info)))
+ return err;
+
+ sisfb_get_fix(&info->fix, info->currcon, info);
+
+ TWDEBUG("end of set_par");
+ return 0;
+}
+
+static int sisfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned int htotal =
+ var->left_margin + var->xres + var->right_margin +
+ var->hsync_len;
+ unsigned int vtotal = 0;
+ double drate = 0, hrate = 0;
+ int found_mode = 0;
+ int refresh_rate, search_idx;
+
+ TWDEBUG("Inside check_var");
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+ vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len; /* TW */
+ vtotal <<= 1;
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len; /* TW */
+ vtotal <<= 2;
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+ var->vsync_len; /* TW */
+ /* var->yres <<= 1; */ /* TW */
+ } else vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+
+ if(!(htotal) || !(vtotal)) {
+ SISFAIL("sisfb: no valid timing data");
+ }
+
+ drate = 1E12 / var->pixclock;
+ hrate = drate / htotal;
+ refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+
+ /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+ if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60;
+
+ search_idx = 0;
+ while( (sisbios_mode[search_idx].mode_no != 0) &&
+ (sisbios_mode[search_idx].xres <= var->xres) ) {
+ if( (sisbios_mode[search_idx].xres == var->xres) &&
+ (sisbios_mode[search_idx].yres == var->yres) &&
+ (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+ found_mode = 1;
break;
- default:
- return -1;
}
+ search_idx++;
}
- reg &= SIS315_DUAL_CHANNEL_MASK;
- reg >>= 2;
- switch (reg) {
- case SIS315_SINGLE_CHANNEL_2_RANK:
- ivideo.video_size <<= 1;
+ /* TW: TODO: Check the refresh rate */
+
+ if(found_mode)
+ search_idx = sisfb_validate_mode(search_idx);
+ else
+ SISFAIL("sisfb: no valid mode");
+
+ if(sisfb_mode_idx < 0) {
+ SISFAIL("sisfb: mode not supported");
+ }
+
+ /* TW: Horiz-panning not supported */
+ if(var->xres != var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if(!sisfb_ypan) {
+ if(var->yres != var->yres_virtual)
+ var->yres_virtual = var->yres;
+ } else {
+ /* TW: Now patch yres_virtual if we use panning */
+ /* *** May I do this? *** */
+ var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+ if(var->yres_virtual <= var->yres) {
+ /* TW: Paranoia check */
+ var->yres_virtual = var->yres;
+ }
+ }
+ TWDEBUG("end of check_var");
+ return 0;
+}
+#endif
+
+/* -------- functions for all series ------- */
+
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ TWDEBUG("inside get_fix");
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, sis_fb_info.modename);
+
+ fix->smem_start = ivideo.video_base;
+
+ /* TW */
+ if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+ if (ivideo.video_size > 0x1000000) {
+ fix->smem_len = 0xc00000;
+ } else if (ivideo.video_size > 0x800000)
+ fix->smem_len = 0x800000;
+ else
+ fix->smem_len = 0x400000;
+ } else
+ fix->smem_len = sisfb_mem * 1024;
+
+ fix->type = video_type;
+ fix->type_aux = 0;
+ if(ivideo.video_bpp == 8)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+#ifdef SISFB_PAN
+ if(sisfb_ypan) fix->ypanstep = 1;
+#endif
+ fix->ywrapstep = 0;
+ fix->line_length = ivideo.video_linelength;
+ fix->mmio_start = ivideo.mmio_base;
+ fix->mmio_len = sisfb_mmio_size;
+ fix->accel = FB_ACCEL_SIS_GLAMOUR;
+ fix->reserved[0] = ivideo.video_size & 0xFFFF;
+ fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+ fix->reserved[2] = sisfb_caps;
+ TWDEBUG("end of get_fix");
+ return 0;
+}
+
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ TWDEBUG("inside get_var");
+ if(con == -1)
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ else
+ *var = fb_display[con].var;
+
+ /* JennyLee 2001126: for FSTN */
+ if (var->xres == 320 && var->yres == 480)
+ var->yres = 240;
+ /* ~JennyLee */
+ TWDEBUG("end of get_var");
+ return 0;
+}
+
+#ifdef SISFB_PAN
+static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info* info)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+ TWDEBUG("inside 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 == currcon)
+ sisfb_pan_var(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;
+
+ TWDEBUG("end of pan_display");
+ return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+#endif
+
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ TWDEBUG("inside ioctl");
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_malloc((struct sis_memreq *) arg);
break;
- case SIS315_DUAL_CHANNEL_1_RANK:
- ivideo.video_size <<= 1;
+ case FBIO_FREE:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_free(*(unsigned long *) arg);
break;
- case SIS315_ASYM_DDR: /* TW: DDR asymentric */
- ivideo.video_size += ivideo.video_size/2;
+ case FBIOGET_GLYPH:
+ sis_get_glyph(info,(SIS_GLYINFO *) arg);
+ break;
+ case FBIOGET_HWCINFO:
+ {
+ unsigned long *hwc_offset = (unsigned long *) arg;
+
+ if (sisfb_caps & HW_CURSOR_CAP)
+ *hwc_offset = sisfb_hwcursor_vbase -
+ (unsigned long) ivideo.video_vbase;
+ else
+ *hwc_offset = 0;
+
+ break;
+ }
+ case FBIOPUT_MODEINFO:
+ {
+ struct mode_info *x = (struct mode_info *)arg;
+
+ ivideo.video_bpp = x->bpp;
+ ivideo.video_width = x->xres;
+ ivideo.video_height = x->yres;
+ ivideo.video_vwidth = x->v_xres;
+ ivideo.video_vheight = x->v_yres;
+ ivideo.org_x = x->org_x;
+ ivideo.org_y = x->org_y;
+ ivideo.refresh_rate = x->vrate;
+ ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+ switch(ivideo.video_bpp) {
+ case 8:
+ ivideo.DstColor = 0x0000;
+ ivideo.SiS310_AccelDepth = 0x00000000;
+ ivideo.video_cmap_len = 256;
+ break;
+ case 16:
+ ivideo.DstColor = 0x8000;
+ ivideo.SiS310_AccelDepth = 0x00010000;
+ ivideo.video_cmap_len = 16;
+ break;
+ case 32:
+ ivideo.DstColor = 0xC000;
+ ivideo.SiS310_AccelDepth = 0x00020000;
+ ivideo.video_cmap_len = 16;
+ break;
+ default:
+ ivideo.video_cmap_len = 16;
+ printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+ break;
+ }
+
+ break;
+ }
+ case FBIOGET_DISPINFO:
+ sis_dispinfo((struct ap_data *)arg);
break;
+ case SISFB_GET_INFO: /* TW: New for communication with X driver */
+ {
+ sisfb_info *x = (sisfb_info *)arg;
+
+ x->sisfb_id = SISFB_ID;
+ x->sisfb_version = VER_MAJOR;
+ x->sisfb_revision = VER_MINOR;
+ x->sisfb_patchlevel = VER_LEVEL;
+ x->chip_id = ivideo.chip_id;
+ x->memory = ivideo.video_size / 1024;
+ x->heapstart = ivideo.heapstart / 1024;
+ x->fbvidmode = sisfb_mode_no;
+ x->sisfb_caps = sisfb_caps;
+ x->sisfb_tqlen = 512; /* yet unused */
+ break;
+ }
+ default:
+ return -EINVAL;
}
+ TWDEBUG("end of ioctl");
+ return 0;
+
+}
+static int sisfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+ struct fb_var_screeninfo var;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ TWDEBUG("inside mmap");
+ if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ start = (unsigned long) ivideo.video_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+
+ if (off >= len) {
+ off -= len;
+ sisfb_get_var(&var, currcon, info);
+ if(var.accel_flags) return -EINVAL;
+
+ start = (unsigned long) ivideo.mmio_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+ }
+
+ start &= PAGE_MASK;
+ if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL;
+
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+#else /* TW: 2.5 API */
+ if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+#endif
+ return -EAGAIN;
+
+ TWDEBUG("end of mmap");
+ return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static struct fb_ops sisfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_var = gen_set_var,
+ .fb_get_cmap = gen_get_cmap,
+ .fb_set_cmap = gen_set_cmap,
+
+ .fb_check_var = sisfb_check_var,
+ .fb_set_par = sisfb_set_par,
+ .fb_setcolreg = sisfb_setcolreg,
+ .fb_blank = sisfb_blank,
+#ifdef SISFB_PAN
+ .fb_pan_display = sisfb_pan_display,
+#endif
+ .fb_fillrect = fbcon_sis_fillrect,
+ .fb_copyarea = fbcon_sis_copyarea,
+ .fb_imageblit = my_cfb_imageblit,
+ .fb_ioctl = sisfb_ioctl,
+ .fb_mmap = sisfb_mmap,
+};
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static struct fb_ops sisfb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: sisfb_get_fix,
+ fb_get_var: sisfb_get_var,
+ fb_set_var: sisfb_set_var,
+ fb_get_cmap: sisfb_get_cmap,
+ fb_set_cmap: sisfb_set_cmap,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+ fb_setcolreg: sisfb_setcolreg,
+ fb_blank: sisfb_blank,
+#endif
+#ifdef SISFB_PAN
+ fb_pan_display: sisfb_pan_display,
+#endif
+ fb_ioctl: sisfb_ioctl,
+ fb_mmap: sisfb_mmap,
+};
+#endif
+
+/* ------------ Interface to the low level console driver -------------*/
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) /* --------- for 2.4 series --------- */
+static int sisfb_update_var(int con, struct fb_info *info)
+{
+#ifdef SISFB_PAN
+ sisfb_pan_var(&fb_display[con].var);
+#endif
return 0;
}
-static void sisfb_detect_VB_connect_315(void)
-{
- u8 sr17, cr32, temp;
+static int sisfb_switch(int con, struct fb_info *info)
+{
+ int cols, rows;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+
+ if(fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+ if(!memcmp(&fb_display[con].var, &fb_display[currcon].var,
+ sizeof(struct fb_var_screeninfo))) {
+ currcon = con;
+ return 1;
+ }
+
+ currcon = con;
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
- cr32 = vgarb(CRTC_DATA);
+ sisfb_do_set_var(&fb_display[con].var, 1, info);
- ivideo.TV_plug = ivideo.TV_type = 0;
- if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
- sisfb_crt1off = 0;
- else {
- if (cr32 & 0x5F)
- sisfb_crt1off = 1;
- else
- sisfb_crt1off = 0;
- }
+ sisfb_set_disp(con, &fb_display[con].var, info);
- if (sisfb_crt2type != -1)
- /* TW: Override with option */
- ivideo.disp_state = sisfb_crt2type;
- else if (cr32 & SIS_VB_CRT2)
- ivideo.disp_state = DISPTYPE_CRT2;
- else if (cr32 & SIS_VB_LCD)
- ivideo.disp_state = DISPTYPE_LCD;
- else if (cr32 & SIS_VB_TV)
- ivideo.disp_state = DISPTYPE_TV;
- else
- ivideo.disp_state = 0;
+ sisfb_do_install_cmap(con, info);
- if (cr32 & SIS_VB_HIVISION) {
- ivideo.TV_type = TVMODE_HIVISION;
- ivideo.TV_plug = TVPLUG_SVIDEO;
- } else if (cr32 & SIS_VB_SVIDEO)
- ivideo.TV_plug = TVPLUG_SVIDEO;
- else if (cr32 & SIS_VB_COMPOSITE)
- ivideo.TV_plug = TVPLUG_COMPOSITE;
- else if (cr32 & SIS_VB_SCART)
- ivideo.TV_plug = TVPLUG_SCART;
+ cols = sisbios_mode[sisfb_mode_idx].cols;
+ rows = sisbios_mode[sisfb_mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
- if (ivideo.TV_type == 0) {
- vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
- temp = vgarb(SEQ_DATA);
- if (temp & 0x01)
- ivideo.TV_type = TVMODE_PAL;
- else
- ivideo.TV_type = TVMODE_NTSC;
- }
+ sisfb_update_var(con, info);
- /* TW: Copy forceCRT1 option to CRT1off if option is given */
- if (sisfb_forcecrt1 != -1) {
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
- sr17 = vgarb(SEQ_DATA);
- if (sisfb_forcecrt1) {
- sisfb_crt1off=0;
- sr17 |= 0x80;
- } else {
- sisfb_crt1off=1;
- sr17 &= ~0x80;
- }
- vgawb(SEQ_DATA, sr17);
- }
+ return 1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
}
-static void sisfb_get_VB_type_315(void)
+static void sisfb_blank(int blank, struct fb_info *info)
{
u8 reg;
- /* 550 has LVDS-like FSTN bridge (?) */
- if (ivideo.chip == SIS_550) {
- if (!sisfb_has_VB_315()) {
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
- reg = vgarb(CRTC_DATA);
+ inSISIDXREG(SISCR, 0x17, reg);
- switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
- case SIS_EXTERNAL_CHIP_SIS301:
- ivideo.hasVB = HASVB_301;
- break;
- case SIS_EXTERNAL_CHIP_LVDS:
- ivideo.hasVB = HASVB_LVDS;
- break;
- case SIS_EXTERNAL_CHIP_TRUMPION:
- ivideo.hasVB = HASVB_TRUMPION;
- break;
- case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
- ivideo.hasVB = HASVB_LVDS_CHRONTEL;
- break;
- case SIS_EXTERNAL_CHIP_CHRONTEL:
- ivideo.hasVB = HASVB_CHRONTEL;
- break;
- default:
- break;
- }
- }
- } else {
- sisfb_has_VB_315();
- }
+ if(blank > 0)
+ reg &= 0x7f;
+ else
+ reg |= 0x80;
+
+ outSISIDXREG(SISCR, 0x17, reg);
}
+#endif
-static int sisfb_has_VB_315(void)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) /* ---------- for 2.5 series -------- */
+static int sisfb_blank(int blank, struct fb_info *info)
{
- u8 vb_chipid;
-
- vgawb(VB_PART4_ADR, 0x0);
- vb_chipid = vgarb(VB_PART4_DATA);
+ u8 reg;
- switch (vb_chipid) {
- case 0x01:
- ivideo.hasVB = HASVB_301;
- break;
- case 0x02:
- ivideo.hasVB = HASVB_302;
- break;
- case 0x03:
- ivideo.hasVB = HASVB_303;
- break;
- default:
- ivideo.hasVB = HASVB_NONE;
- return FALSE;
- }
- // Eden Chen
- //sishw_ext.hasVB = ivideo.hasVB;
- // ~Eden Chen
- return TRUE;
-}
-#endif /* CONFIG_FB_SIS_315 */
+ inSISIDXREG(SISCR, 0x17, reg);
-/* --------------------- Heap Routines ------------------------------- */
+ if(blank > 0)
+ reg &= 0x7f;
+ else
+ reg |= 0x80;
-static int sisfb_heap_init(void)
-{
- SIS_OH *poh;
- u8 temp=0;
-#ifdef CONFIG_FB_SIS_315
- int agp_enabled = 1;
- u32 agp_size;
- unsigned long *cmdq_baseport = 0;
- unsigned long *read_port = 0;
- unsigned long *write_port = 0;
- SIS_CMDTYPE cmd_type;
-#ifndef AGPOFF
- agp_kern_info *agp_info;
- agp_memory *agp;
- u32 agp_phys;
-#endif
+ outSISIDXREG(SISCR, 0x17, reg);
+ return(0);
+}
#endif
-/* TW: If more than 8MB videoRAM detected, let our heap start at 8MB. If
- * there is less RAM available, let it start at 4MB. This can be overruled
- * by mem parameter.
- * This is for avoiding a clash with X driver which uses the beginning
- * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
- * in XF86Config-4.
- * The heap start can also be specified by parameter "mem" when starting the sisfb
- * driver. sisfb mem=1024 lets heap starts at 1MB, etc.
- */
- /*karl:10/01/2001*/
- if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
- if (ivideo.video_size > 0x800000) {
- sisfb_heap_start =
- (unsigned long) ivideo.video_vbase + 0x800000;
- printk(KERN_INFO "sisfb: Memory heap starting at 8192K\n");
- } else {
- sisfb_heap_start =
- (unsigned long) ivideo.video_vbase + 0x400000;
- printk(KERN_INFO "sisfb: Memory heap starting at 4096K\n");
- }
- } else {
- sisfb_heap_start =
- (unsigned long) (ivideo.video_vbase + (sisfb_mem * 1024));
- printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", sisfb_mem);
- }
- sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
- sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
+/* --------------- Chip-dependent Routines --------------------------- */
-#ifdef CONFIG_FB_SIS_315
- if (sisvga_engine == SIS_315_VGA) {
- /* TW: Now initlalize the 310 series' command queue mode.
- * On 310, there are three queue modes available which
- * are chosen by setting bits 7:5 in SR26:
- * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
- * track of the queue, the FIFO, command parsing and so
- * on. This is the one comparable to the 300 series.
- * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
- * have to do queue management himself. Register 0x85c4 will
- * hold the location of the next free queue slot, 0x85c8
- * is the "queue read pointer" whose way of working is
- * unknown to me. Anyway, this mode would require a
- * translation of the MMIO commands to some kind of
- * accelerator assembly and writing these commands
- * to the memory location pointed to by 0x85c4.
- * We will not use this, as nobody knows how this
- * "assembly" works, and as it would require a complete
- * re-write of the accelerator code.
- * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
- * queue in AGP memory space.
- *
- * SR26 bit 4 is called "Bypass H/W queue".
- * SR26 bit 1 is called "Enable Command Queue Auto Correction"
- * SR26 bit 0 resets the queue
- * Size of queue memory is encoded in bits 3:2 like this:
- * 00 (0x00) 512K
- * 01 (0x04) 1M
- * 10 (0x08) 2M
- * 11 (0x0C) 4M
- * The queue location is to be written to 0x85C0.
- *
- */
- cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
- write_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
- read_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
+#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
- DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
+static int sisfb_get_dram_size_300(void)
+{
+ struct pci_dev *pdev = NULL;
+ int pdev_valid = 0;
+ u8 pci_data, reg;
+ u16 nbridge_id;
- agp_size = COMMAND_QUEUE_AREA_SIZE;
+ switch (ivideo.chip) {
+ case SIS_540:
+ nbridge_id = PCI_DEVICE_ID_SI_540;
+ break;
+ case SIS_630:
+ nbridge_id = PCI_DEVICE_ID_SI_630;
+ break;
+ case SIS_730:
+ nbridge_id = PCI_DEVICE_ID_SI_730;
+ break;
+ default:
+ nbridge_id = 0;
+ break;
+ }
-#ifndef AGPOFF
- if (sisfb_queuemode == AGP_CMD_QUEUE) {
- agp_info = vmalloc(sizeof(agp_kern_info));
- memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
- agp_copy_info(agp_info);
+ if (nbridge_id == 0) { /* 300 */
- agp_backend_acquire();
+ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
+ ivideo.video_size =
+ ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);
- agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
- AGP_NORMAL_MEMORY);
- if (agp == NULL) {
- DPRINTK("sisfb: Allocating AGP buffer failed.\n");
- agp_enabled = 0;
- } else {
- if (agp_bind_memory(agp, agp->pg_start) != 0) {
- DPRINTK("sisfb: AGP: Failed to bind memory\n");
- /* TODO: Free AGP memory here */
- agp_enabled = 0;
- } else {
- agp_enable(0);
- }
- }
- }
-#else
- agp_enabled= 0;
-#endif
+ } else { /* 540, 630, 730 */
- /* TW: Now select the queue mode */
+ pci_for_each_dev(pdev) {
- if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
- cmd_type = AGP_CMD_QUEUE;
- printk(KERN_INFO "sisfb: Using AGP queue mode\n");
-/* } else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */
- } else if (sisfb_queuemode == VM_CMD_QUEUE) {
- cmd_type = VM_CMD_QUEUE;
- printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
- } else {
- printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
- cmd_type = MMIO_CMD;
+ if ((pdev->vendor == PCI_VENDOR_ID_SI)
+ && (pdev->device == nbridge_id)) {
+ pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
+ pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+ ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+ pdev_valid = 1;
+
+ reg = SIS_DATA_BUS_64 << 6;
+ switch (pci_data) {
+ case BRI_DRAM_SIZE_2MB:
+ reg |= SIS_DRAM_SIZE_2MB;
+ break;
+ case BRI_DRAM_SIZE_4MB:
+ reg |= SIS_DRAM_SIZE_4MB;
+ break;
+ case BRI_DRAM_SIZE_8MB:
+ reg |= SIS_DRAM_SIZE_8MB;
+ break;
+ case BRI_DRAM_SIZE_16MB:
+ reg |= SIS_DRAM_SIZE_16MB;
+ break;
+ case BRI_DRAM_SIZE_32MB:
+ reg |= SIS_DRAM_SIZE_32MB;
+ break;
+ case BRI_DRAM_SIZE_64MB:
+ reg |= SIS_DRAM_SIZE_64MB;
+ break;
+ }
+ outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ break;
+ }
+ }
+
+ if (!pdev_valid) return -1;
}
+ return 0;
+}
- switch (agp_size) {
- case 0x80000:
- temp = SIS_CMD_QUEUE_SIZE_512k;
- break;
- case 0x100000:
- temp = SIS_CMD_QUEUE_SIZE_1M;
- break;
- case 0x200000:
- temp = SIS_CMD_QUEUE_SIZE_2M;
- break;
- case 0x400000:
- temp = SIS_CMD_QUEUE_SIZE_4M;
- break;
+static void sisfb_detect_VB_connect_300()
+{
+ u8 sr16, sr17, cr32, temp;
+
+ ivideo.TV_plug = ivideo.TV_type = 0;
+
+ switch(ivideo.hasVB) {
+ case HASVB_LVDS_CHRONTEL:
+ case HASVB_CHRONTEL:
+ SiS_SenseCh();
+ break;
+ case HASVB_301:
+ case HASVB_302:
+ SiS_Sense30x();
+ break;
}
- switch (cmd_type) {
- case AGP_CMD_QUEUE:
-#ifndef AGPOFF
- DPRINTK("sisfb: AGP buffer base:0x%lx, offset:0x%x, size: %dK\n",
- agp_info->aper_base, agp->physical, agp_size/1024);
+ inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
+ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
- agp_phys = agp_info->aper_base + agp->physical;
+ if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
- vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD);
- vgawb(CRTC_DATA, 0);
- vgawb(CRTC_DATA, SIS_AGP_2X);
+ if ((sr17 & 0x01) && !sisfb_crt1off)
+ sisfb_crt1off = 0;
+ else {
+ if (sr17 & 0x0E)
+ sisfb_crt1off = 1;
+ else
+ sisfb_crt1off = 0;
+ }
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
- vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+ if (sisfb_crt2type != -1)
+ /* TW: override detected CRT2 type */
+ ivideo.disp_state = sisfb_crt2type;
+ else if (sr17 & 0x08 )
+ ivideo.disp_state = DISPTYPE_CRT2;
+ else if (sr17 & 0x02)
+ ivideo.disp_state = DISPTYPE_LCD;
+ else if (sr17 & 0x04)
+ ivideo.disp_state = DISPTYPE_TV;
+ else
+ ivideo.disp_state = 0;
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+ if(sisfb_tvplug != -1)
+ /* PR/TW: override detected TV type */
+ ivideo.TV_plug = sisfb_tvplug;
+ else if (sr17 & 0x20)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if (sr17 & 0x10)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
- *write_port = *read_port;
+ inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
+ if (sr16 & 0x20)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
- temp |= SIS_AGP_CMDQUEUE_ENABLE;
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, temp);
+ } else {
- *cmdq_baseport = agp_phys;
+ if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
+ sisfb_crt1off = 0;
+ else {
+ if (cr32 & 0x5F)
+ sisfb_crt1off = 1;
+ else
+ sisfb_crt1off = 0;
+ }
- sisfb_caps |= AGP_CMD_QUEUE_CAP;
-#endif
- break;
+ if (sisfb_crt2type != -1)
+ /* TW: override detected CRT2 type */
+ ivideo.disp_state = sisfb_crt2type;
+ else if (cr32 & SIS_VB_CRT2)
+ ivideo.disp_state = DISPTYPE_CRT2;
+ else if (cr32 & SIS_VB_LCD)
+ ivideo.disp_state = DISPTYPE_LCD;
+ else if (cr32 & SIS_VB_TV)
+ ivideo.disp_state = DISPTYPE_TV;
+ else
+ ivideo.disp_state = 0;
- case VM_CMD_QUEUE:
- sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
- sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+ /* TW: Detect TV plug & type */
+ if(sisfb_tvplug != -1)
+ /* PR/TW: override with option */
+ ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+ else if (cr32 & SIS_VB_HIVISION) {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+#endif
+ else if (cr32 & SIS_VB_SVIDEO)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if (cr32 & SIS_VB_COMPOSITE)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if (cr32 & SIS_VB_SCART)
+ ivideo.TV_plug = TVPLUG_SCART;
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
- vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+ if (ivideo.TV_type == 0) {
+ inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
+ if (temp & 0x01)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+ }
- *write_port = *read_port;
+ /* TW: Copy forceCRT1 option to CRT1off if option is given */
+ if (sisfb_forcecrt1 != -1) {
+ if(sisfb_forcecrt1) sisfb_crt1off = 0;
+ else sisfb_crt1off = 1;
+ }
+}
- temp |= SIS_VRAM_CMDQUEUE_ENABLE;
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, temp);
+static void sisfb_get_VB_type_300(void)
+{
+ u8 reg;
- *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+ if(ivideo.chip != SIS_300) {
+ if(!sisfb_has_VB_300()) {
+ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+ switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+ case SIS_EXTERNAL_CHIP_SIS301:
+ ivideo.hasVB = HASVB_301;
+ break;
+ case SIS_EXTERNAL_CHIP_LVDS:
+ ivideo.hasVB = HASVB_LVDS;
+ break;
+ case SIS_EXTERNAL_CHIP_TRUMPION:
+ ivideo.hasVB = HASVB_TRUMPION;
+ break;
+ case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+ ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+ break;
+ case SIS_EXTERNAL_CHIP_CHRONTEL:
+ ivideo.hasVB = HASVB_CHRONTEL;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ sisfb_has_VB_300();
+ }
+}
- sisfb_caps |= VM_CMD_QUEUE_CAP;
+static int sisfb_has_VB_300(void)
+{
+ u8 vb_chipid;
- DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
- *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
+ inSISIDXREG(SISPART4, 0x00, vb_chipid);
+ switch (vb_chipid) {
+ case 0x01:
+ ivideo.hasVB = HASVB_301;
+ break;
+ case 0x02:
+ ivideo.hasVB = HASVB_302;
break;
+ case 0x03:
+ ivideo.hasVB = HASVB_303;
+ break;
+ default:
+ ivideo.hasVB = HASVB_NONE;
+ return FALSE;
+ }
+ return TRUE;
- default: /* MMIO */
- /* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
- * to IND_SIS_CMDQUEUE_SET. I doubt that this is
- * enough. Reserve memory in any way.
- */
- sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
- sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+}
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
- vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+#endif /* CONFIG_FB_SIS_300 */
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
- *write_port = *read_port;
+#ifdef CONFIG_FB_SIS_315 /* for SiS 315/550/650/740 */
- /* TW: Set Auto_Correction bit; this works in sisfb lite,
- * so why not.
- */
- temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
- vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
- vgawb(SEQ_DATA, temp);
+static int sisfb_get_dram_size_315(void)
+{
+ struct pci_dev *pdev = NULL;
+ int pdev_valid = 0;
+ u8 pci_data;
+ u8 reg = 0;
- *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+ if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
- DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
- *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
- break;
- }
- } /* sisvga_engine = 315 */
-#endif
+#ifdef LINUXBIOS
-#ifdef CONFIG_FB_SIS_300
- if (sisvga_engine == SIS_300_VGA) {
- /* TW: Now initialize TurboQueue. TB is always located at the very
- * top of the video RAM. */
- if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
- unsigned int tqueue_pos;
- u8 tq_state;
+ pci_for_each_dev(pdev) {
- tqueue_pos = (ivideo.video_size -
- TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
- temp = (u8) (tqueue_pos & 0xff);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
- tq_state = vgarb(SEQ_DATA);
- tq_state |= 0xf0;
- tq_state &= 0xfc;
- tq_state |= (u8) (tqueue_pos >> 8);
- vgawb(SEQ_DATA, tq_state);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
- vgawb(SEQ_DATA, temp);
+ if ( (pdev->vendor == PCI_VENDOR_ID_SI)
+ && ( (pdev->device == PCI_DEVICE_ID_SI_550) ||
+ (pdev->device == PCI_DEVICE_ID_SI_650))) {
+ pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+ &pci_data);
+ pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+ ivideo.video_size = (unsigned int)(1 << (pci_data + 21));
+ pdev_valid = 1;
+
+ /* TW: Initialize SR14 "by hand" */
+ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ reg &= 0xC0;
+ switch (pci_data) {
+ case BRI_DRAM_SIZE_4MB:
+ reg |= SIS550_DRAM_SIZE_4MB;
+ break;
+ case BRI_DRAM_SIZE_8MB:
+ reg |= SIS550_DRAM_SIZE_8MB;
+ break;
+ case BRI_DRAM_SIZE_16MB:
+ reg |= SIS550_DRAM_SIZE_16MB;
+ break;
+ case BRI_DRAM_SIZE_32MB:
+ reg |= SIS550_DRAM_SIZE_32MB;
+ break;
+ case BRI_DRAM_SIZE_64MB:
+ reg |= SIS550_DRAM_SIZE_64MB;
+ break;
+ }
+
+ /* TODO: set Dual channel and bus width bits here */
+
+ outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ break;
+ }
+ }
+
+ if (!pdev_valid) return -1;
+
+#else
+
+ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ switch (reg & SIS550_DRAM_SIZE_MASK) {
+ case SIS550_DRAM_SIZE_4MB:
+ ivideo.video_size = 0x400000; break;
+ case SIS550_DRAM_SIZE_8MB:
+ ivideo.video_size = 0x800000; break;
+ case SIS550_DRAM_SIZE_16MB:
+ ivideo.video_size = 0x1000000; break;
+ case SIS550_DRAM_SIZE_24MB:
+ ivideo.video_size = 0x1800000; break;
+ case SIS550_DRAM_SIZE_32MB:
+ ivideo.video_size = 0x2000000; break;
+ case SIS550_DRAM_SIZE_64MB:
+ ivideo.video_size = 0x4000000; break;
+ case SIS550_DRAM_SIZE_96MB:
+ ivideo.video_size = 0x6000000; break;
+ case SIS550_DRAM_SIZE_128MB:
+ ivideo.video_size = 0x8000000; break;
+ case SIS550_DRAM_SIZE_256MB:
+ ivideo.video_size = 0x10000000; break;
+ default:
+ /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),
+ * do it the hard way ourselves in this case. Unfortunately, we don't
+ * support 24, 48, 96 and other "odd" amounts here.
+ */
+ printk(KERN_INFO
+ "sisfb: Warning: Could not determine memory size, "
+ "now reading from PCI config\n");
+ pdev_valid = 0;
- sisfb_caps |= TURBO_QUEUE_CAP;
+ pci_for_each_dev(pdev) {
- sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
- sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
- DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
- sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
- }
- }
+ if ( (pdev->vendor == PCI_VENDOR_ID_SI)
+ && (pdev->device == PCI_DEVICE_ID_SI_550) ) {
+
+ pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
+ &pci_data);
+ pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+ ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+ pdev_valid = 1;
+ /* TW: Initialize SR14=IND_SIS_DRAM_SIZE */
+ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ reg &= 0xC0;
+ switch (pci_data) {
+ case BRI_DRAM_SIZE_4MB:
+ reg |= SIS550_DRAM_SIZE_4MB; break;
+ case BRI_DRAM_SIZE_8MB:
+ reg |= SIS550_DRAM_SIZE_8MB; break;
+ case BRI_DRAM_SIZE_16MB:
+ reg |= SIS550_DRAM_SIZE_16MB; break;
+ case BRI_DRAM_SIZE_32MB:
+ reg |= SIS550_DRAM_SIZE_32MB; break;
+ case BRI_DRAM_SIZE_64MB:
+ reg |= SIS550_DRAM_SIZE_64MB; break;
+ default:
+ printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");
+ return -1;
+ }
+ outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ }
+ }
+ if (!pdev_valid) {
+ printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");
+ return -1;
+ }
+ return 0;
+ }
#endif
- /* TW: Now reserve memory for the HWCursor. It is always located at the very
- top of the videoRAM, right below the TB memory area (if used). */
- if (sisfb_heap_size >= sisfb_hwcursor_size) {
- sisfb_heap_end -= sisfb_hwcursor_size;
- sisfb_heap_size -= sisfb_hwcursor_size;
- sisfb_hwcursor_vbase = sisfb_heap_end;
+ return 0;
- sisfb_caps |= HW_CURSOR_CAP;
+ } else { /* 315 */
- DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
- sisfb_heap_end, sisfb_hwcursor_size/1024);
+ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+ switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
+ case SIS315_DRAM_SIZE_2MB:
+ ivideo.video_size = 0x200000;
+ break;
+ case SIS315_DRAM_SIZE_4MB:
+ ivideo.video_size = 0x400000;
+ break;
+ case SIS315_DRAM_SIZE_8MB:
+ ivideo.video_size = 0x800000;
+ break;
+ case SIS315_DRAM_SIZE_16MB:
+ ivideo.video_size = 0x1000000;
+ break;
+ case SIS315_DRAM_SIZE_32MB:
+ ivideo.video_size = 0x2000000;
+ break;
+ case SIS315_DRAM_SIZE_64MB:
+ ivideo.video_size = 0x4000000;
+ break;
+ case SIS315_DRAM_SIZE_128MB:
+ ivideo.video_size = 0x8000000;
+ break;
+ default:
+ return -1;
+ }
}
- sisfb_heap.poha_chain = NULL;
- sisfb_heap.poh_freelist = NULL;
-
- poh = sisfb_poh_new_node();
-
- if (poh == NULL)
- return 1;
-
- poh->poh_next = &sisfb_heap.oh_free;
- poh->poh_prev = &sisfb_heap.oh_free;
- poh->size = sisfb_heap_end - sisfb_heap_start + 1;
- poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
-
- DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
- (char *) sisfb_heap_start, (char *) sisfb_heap_end,
- (unsigned int) poh->size / 1024);
-
- DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
- (unsigned int) poh->offset, (unsigned int) poh->size / 1024);
-
- sisfb_heap.oh_free.poh_next = poh;
- sisfb_heap.oh_free.poh_prev = poh;
- sisfb_heap.oh_free.size = 0;
- sisfb_heap.max_freesize = poh->size;
-
- sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
- sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
- sisfb_heap.oh_used.size = SENTINEL;
+ reg &= SIS315_DUAL_CHANNEL_MASK;
+ reg >>= 2;
+ switch (reg) {
+ case SIS315_SINGLE_CHANNEL_2_RANK:
+ ivideo.video_size <<= 1;
+ break;
+ case SIS315_DUAL_CHANNEL_1_RANK:
+ ivideo.video_size <<= 1;
+ break;
+ case SIS315_ASYM_DDR: /* TW: DDR asymentric */
+ ivideo.video_size += (ivideo.video_size/2);
+ break;
+ }
return 0;
}
-static SIS_OH *sisfb_poh_new_node(void)
+static void sisfb_detect_VB_connect_315(void)
{
- int i;
- unsigned long cOhs;
- SIS_OHALLOC *poha;
- SIS_OH *poh;
-
- if (sisfb_heap.poh_freelist == NULL) {
- poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+ u8 cr32, temp=0;
- poha->poha_next = sisfb_heap.poha_chain;
- sisfb_heap.poha_chain = poha;
+ ivideo.TV_plug = ivideo.TV_type = 0;
- cOhs =
- (OH_ALLOC_SIZE -
- sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+ switch(ivideo.hasVB) {
+ case HASVB_LVDS_CHRONTEL:
+ case HASVB_CHRONTEL:
+ SiS_SenseCh();
+ break;
+ case HASVB_301:
+ case HASVB_302:
+ SiS_Sense30x();
+ break;
+ }
- poh = &poha->aoh[0];
- for (i = cOhs - 1; i != 0; i--) {
- poh->poh_next = poh + 1;
- poh = poh + 1;
- }
+ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
- poh->poh_next = NULL;
- sisfb_heap.poh_freelist = &poha->aoh[0];
+ if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
+ sisfb_crt1off = 0;
+ else {
+ if (cr32 & 0x5F)
+ sisfb_crt1off = 1;
+ else
+ sisfb_crt1off = 0;
}
- poh = sisfb_heap.poh_freelist;
- sisfb_heap.poh_freelist = poh->poh_next;
+ if (sisfb_crt2type != -1)
+ /* TW: Override with option */
+ ivideo.disp_state = sisfb_crt2type;
+ else if (cr32 & SIS_VB_CRT2)
+ ivideo.disp_state = DISPTYPE_CRT2;
+ else if (cr32 & SIS_VB_LCD)
+ ivideo.disp_state = DISPTYPE_LCD;
+ else if (cr32 & SIS_VB_TV)
+ ivideo.disp_state = DISPTYPE_TV;
+ else
+ ivideo.disp_state = 0;
- return (poh);
-}
+ if(sisfb_tvplug != -1)
+ /* PR/TW: Override with option */
+ ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+ else if (cr32 & SIS_VB_HIVISION) {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+#endif
+ else if (cr32 & SIS_VB_SVIDEO)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if (cr32 & SIS_VB_COMPOSITE)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if (cr32 & SIS_VB_SCART)
+ ivideo.TV_plug = TVPLUG_SCART;
-static SIS_OH *sisfb_poh_allocate(unsigned long size)
-{
- SIS_OH *pohThis;
- SIS_OH *pohRoot;
- int bAllocated = 0;
+ if(ivideo.TV_type == 0) {
+ /* TW: PAL/NTSC changed for 650 */
+ if(ivideo.chip <= SIS_315PRO) {
- if (size > sisfb_heap.max_freesize) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
+ inSISIDXREG(SISCR, 0x38, temp);
+ if(temp & 0x10)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
- pohThis = sisfb_heap.oh_free.poh_next;
+ } else {
- while (pohThis != &sisfb_heap.oh_free) {
- if (size <= pohThis->size) {
- bAllocated = 1;
- break;
- }
- pohThis = pohThis->poh_next;
+ inSISIDXREG(SISCR, 0x79, temp);
+ if(temp & 0x20)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
}
- if (!bAllocated) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
+ /* TW: Copy forceCRT1 option to CRT1off if option is given */
+ if (sisfb_forcecrt1 != -1) {
+ if (sisfb_forcecrt1) sisfb_crt1off = 0;
+ else sisfb_crt1off = 1;
+ }
+}
- if (size == pohThis->size) {
- pohRoot = pohThis;
- sisfb_delete_node(pohThis);
- } else {
- pohRoot = sisfb_poh_new_node();
+static void sisfb_get_VB_type_315(void)
+{
+ u8 reg;
- if (pohRoot == NULL) {
- return (NULL);
+ if (!sisfb_has_VB_315()) {
+ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+ /* TW: CR37 changed on 310/325 series */
+ switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
+ case SIS_EXTERNAL_CHIP_SIS301:
+ ivideo.hasVB = HASVB_301;
+ break;
+ case SIS310_EXTERNAL_CHIP_LVDS:
+ ivideo.hasVB = HASVB_LVDS;
+ break;
+ case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+ ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+ break;
+ default:
+ break;
+ }
}
+}
- pohRoot->offset = pohThis->offset;
- pohRoot->size = size;
-
- pohThis->offset += size;
- pohThis->size -= size;
- }
-
- sisfb_heap.max_freesize -= size;
- pohThis = &sisfb_heap.oh_used;
- sisfb_insert_node(pohThis, pohRoot);
+static int sisfb_has_VB_315(void)
+{
+ u8 vb_chipid;
- return (pohRoot);
+ inSISIDXREG(SISPART4, 0x00, vb_chipid);
+ switch (vb_chipid) {
+ case 0x01:
+ ivideo.hasVB = HASVB_301;
+ break;
+ case 0x02:
+ ivideo.hasVB = HASVB_302;
+ break;
+ case 0x03:
+ ivideo.hasVB = HASVB_303;
+ break;
+ default:
+ ivideo.hasVB = HASVB_NONE;
+ return FALSE;
+ }
+ return TRUE;
}
-static void sisfb_delete_node(SIS_OH *poh)
-{
- SIS_OH *poh_prev;
- SIS_OH *poh_next;
+#endif /* CONFIG_FB_SIS_315 */
+/* -------------- Sensing routines --------------- */
- poh_prev = poh->poh_prev;
- poh_next = poh->poh_next;
+/* TW: Determine and detect attached devices on SiS30x */
+int
+SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+{
+ int temp,i;
+
+ outSISIDXREG(SISPART4,0x11,tempbl);
+ temp = tempbh | tempcl;
+ setSISIDXREG(SISPART4,0x10,0xe0,temp);
+ for(i=0; i<10; i++) SiS_LongWait(&SiS_Pr);
+ tempch &= 0x7f;
+ inSISIDXREG(SISPART4,0x03,temp);
+ temp ^= 0x0e;
+ temp &= tempch;
+ return(temp);
+}
+
+void
+SiS_Sense30x(void)
+{
+ u8 backupP4_0d;
+ u8 testsvhs_tempbl, testsvhs_tempbh;
+ u8 testsvhs_tempcl, testsvhs_tempch;
+ u8 testcvbs_tempbl, testcvbs_tempbh;
+ u8 testcvbs_tempcl, testcvbs_tempch;
+ int myflag, result;
+
+ inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+ outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
+
+ if(sisvga_engine == SIS_300_VGA) {
+
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+ if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+ (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+ testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+ testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+ }
+ inSISIDXREG(SISPART4,0x01,myflag);
+ if(myflag & 0x04) {
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+ }
+ testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04;
+ testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+ } else if((ivideo.chip == SIS_315) ||
+ (ivideo.chip == SIS_315H) ||
+ (ivideo.chip == SIS_315PRO)) {
+
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+ if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+ (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+ testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+ testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+ }
+ inSISIDXREG(SISPART4,0x01,myflag);
+ if(myflag & 0x04) {
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+ }
+ testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04;
+ testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+ } else {
+
+ testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
+ testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
+
+ testsvhs_tempch = 0x04; testsvhs_tempcl = 0x08;
+ testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08;
+
+ }
+
+ result = SISDoSense(testsvhs_tempbl, testsvhs_tempbh,
+ testsvhs_tempcl, testsvhs_tempch);
+ if(result) {
+ printk(KERN_INFO "sisfb: Detected TV connected to SVHS output\n");
+ /* TW: So we can be sure that there IS a SVHS output */
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ orSISIDXREG(SISCR, 0x32, 0x02);
+ }
+
+ if(!result) {
+ result = SISDoSense(testcvbs_tempbl, testcvbs_tempbh,
+ testcvbs_tempcl, testcvbs_tempch);
+ if(result) {
+ printk(KERN_INFO "sisfb: Detected TV connected to CVBS output\n");
+ /* TW: So we can be sure that there IS a CVBS output */
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ orSISIDXREG(SISCR, 0x32, 0x01);
+ }
+ }
+ SISDoSense(0, 0, 0, 0);
+
+ outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+}
+
+/* TW: Determine and detect attached TV's on Chrontel */
+void
+SiS_SenseCh(void)
+{
- poh_prev->poh_next = poh_next;
- poh_next->poh_prev = poh_prev;
+ u8 temp1;
+#ifdef CONFIG_FB_SIS_315
+ u8 temp2;
+#endif
- return;
-}
+ if(ivideo.chip < SIS_315H) {
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
-{
- SIS_OH *pohTemp;
+#ifdef CONFIG_FB_SIS_300
+ SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* TW: Chrontel 7005 */
+ temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
+ if ((temp1 >= 50) && (temp1 <= 100)) {
+ /* TW: Read power status */
+ temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+ if((temp1 & 0x03) != 0x03) {
+ /* TW: Power all outputs */
+ SiS_SetCH70xxANDOR(&SiS_Pr, 0x030E,0xF8);
+ }
+ /* TW: Sense connected TV devices */
+ SiS_SetCH700x(&SiS_Pr, 0x0110);
+ SiS_SetCH700x(&SiS_Pr, 0x0010);
+ temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
+ if(!(temp1 & 0x08)) {
+ printk(KERN_INFO
+ "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+ /* TW: So we can be sure that there IS a SVHS output */
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ orSISIDXREG(SISCR, 0x32, 0x02);
+ } else if (!(temp1 & 0x02)) {
+ printk(KERN_INFO
+ "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+ /* TW: So we can be sure that there IS a CVBS output */
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ orSISIDXREG(SISCR, 0x32, 0x01);
+ } else {
+ SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+ }
+ } else if(temp1 == 0) {
+ SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+ }
+#endif
- pohTemp = pohList->poh_next;
+ } else {
- pohList->poh_next = poh;
- pohTemp->poh_prev = poh;
+#ifdef CONFIG_FB_SIS_315
+ SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* TW: Chrontel 7019 */
+ temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
+ SiS_SetCH701x(&SiS_Pr, 0x2049);
+ SiS_DDC2Delay(&SiS_Pr, 0x96);
+ temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+ temp2 |= 0x01;
+ SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+ SiS_DDC2Delay(&SiS_Pr, 0x96);
+ temp2 ^= 0x01;
+ SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+ SiS_DDC2Delay(&SiS_Pr, 0x96);
+ temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+ SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49);
+ temp1 = 0;
+ if(temp2 & 0x02) temp1 |= 0x01;
+ if(temp2 & 0x10) temp1 |= 0x01;
+ if(temp2 & 0x04) temp1 |= 0x02;
+ if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
+ switch(temp1) {
+ case 0x01:
+ printk(KERN_INFO
+ "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ orSISIDXREG(SISCR, 0x32, 0x01);
+ break;
+ case 0x02:
+ printk(KERN_INFO
+ "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ orSISIDXREG(SISCR, 0x32, 0x02);
+ break;
+ case 0x04:
+ /* TW: This should not happen */
+ printk(KERN_INFO
+ "sisfb: Chrontel: Detected TV connected to SCART output!?\n");
+ break;
+ }
+#endif
- poh->poh_prev = pohList;
- poh->poh_next = pohTemp;
+ }
}
-static SIS_OH *sisfb_poh_free(unsigned long base)
-{
- SIS_OH *pohThis;
- SIS_OH *poh_freed;
- SIS_OH *poh_prev;
- SIS_OH *poh_next;
- unsigned long ulUpper;
- unsigned long ulLower;
- int foundNode = 0;
-
- poh_freed = sisfb_heap.oh_used.poh_next;
- while (poh_freed != &sisfb_heap.oh_used) {
- if (poh_freed->offset == base) {
- foundNode = 1;
- break;
- }
+/* --------------------- Heap Routines ------------------------------- */
- poh_freed = poh_freed->poh_next;
+static int sisfb_heap_init(void)
+{
+ SIS_OH *poh;
+ u8 temp=0;
+#ifdef CONFIG_FB_SIS_315
+ int agp_enabled = 1;
+ u32 agp_size;
+ unsigned long *cmdq_baseport = 0;
+ unsigned long *read_port = 0;
+ unsigned long *write_port = 0;
+ SIS_CMDTYPE cmd_type;
+#ifndef AGPOFF
+ agp_kern_info *agp_info;
+ agp_memory *agp;
+ u32 agp_phys;
+#endif
+#endif
+/* TW: The heap start is either set manually using the "mem" parameter, or
+ * defaults as follows:
+ * -) If more than 16MB videoRAM available, let our heap start at 12MB.
+ * -) If more than 8MB videoRAM available, let our heap start at 8MB.
+ * -) If 4MB or less is available, let it start at 4MB.
+ * This is for avoiding a clash with X driver which uses the beginning
+ * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
+ * in XF86Config-4.
+ * The heap start can also be specified by parameter "mem" when starting the sisfb
+ * driver. sisfb mem=1024 lets heap starts at 1MB, etc.
+ */
+ if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+ if (ivideo.video_size > 0x1000000) {
+ ivideo.heapstart = 0xc00000;
+ } else if (ivideo.video_size > 0x800000) {
+ ivideo.heapstart = 0x800000;
+ } else {
+ ivideo.heapstart = 0x400000;
}
+ } else {
+ ivideo.heapstart = sisfb_mem * 1024;
+ }
+ sisfb_heap_start =
+ (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
+ printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
+ (int)(ivideo.heapstart / 1024));
- if (!foundNode)
- return (NULL);
+ sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
+ sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
- sisfb_heap.max_freesize += poh_freed->size;
+#ifdef CONFIG_FB_SIS_315
+ if (sisvga_engine == SIS_315_VGA) {
+ /* TW: Now initialize the 310 series' command queue mode.
+ * On 310/325, there are three queue modes available which
+ * are chosen by setting bits 7:5 in SR26:
+ * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
+ * track of the queue, the FIFO, command parsing and so
+ * on. This is the one comparable to the 300 series.
+ * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
+ * have to do queue management himself. Register 0x85c4 will
+ * hold the location of the next free queue slot, 0x85c8
+ * is the "queue read pointer" whose way of working is
+ * unknown to me. Anyway, this mode would require a
+ * translation of the MMIO commands to some kind of
+ * accelerator assembly and writing these commands
+ * to the memory location pointed to by 0x85c4.
+ * We will not use this, as nobody knows how this
+ * "assembly" works, and as it would require a complete
+ * re-write of the accelerator code.
+ * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
+ * queue in AGP memory space.
+ *
+ * SR26 bit 4 is called "Bypass H/W queue".
+ * SR26 bit 1 is called "Enable Command Queue Auto Correction"
+ * SR26 bit 0 resets the queue
+ * Size of queue memory is encoded in bits 3:2 like this:
+ * 00 (0x00) 512K
+ * 01 (0x04) 1M
+ * 10 (0x08) 2M
+ * 11 (0x0C) 4M
+ * The queue location is to be written to 0x85C0.
+ *
+ */
+ cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
+ write_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
+ read_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
- poh_prev = poh_next = NULL;
- ulUpper = poh_freed->offset + poh_freed->size;
- ulLower = poh_freed->offset;
+ DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
- pohThis = sisfb_heap.oh_free.poh_next;
+ agp_size = COMMAND_QUEUE_AREA_SIZE;
- while (pohThis != &sisfb_heap.oh_free) {
- if (pohThis->offset == ulUpper) {
- poh_next = pohThis;
- }
- else if ((pohThis->offset + pohThis->size) ==
- ulLower) {
- poh_prev = pohThis;
- }
- pohThis = pohThis->poh_next;
- }
+#ifndef AGPOFF
+ if (sisfb_queuemode == AGP_CMD_QUEUE) {
+ agp_info = vmalloc(sizeof(agp_kern_info));
+ memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
+ agp_copy_info(agp_info);
- sisfb_delete_node(poh_freed);
+ agp_backend_acquire();
- if (poh_prev && poh_next) {
- poh_prev->size += (poh_freed->size + poh_next->size);
- sisfb_delete_node(poh_next);
- sisfb_free_node(poh_freed);
- sisfb_free_node(poh_next);
- return (poh_prev);
+ agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
+ AGP_NORMAL_MEMORY);
+ if (agp == NULL) {
+ DPRINTK("sisfb: Allocating AGP buffer failed.\n");
+ agp_enabled = 0;
+ } else {
+ if (agp_bind_memory(agp, agp->pg_start) != 0) {
+ DPRINTK("sisfb: AGP: Failed to bind memory\n");
+ /* TODO: Free AGP memory here */
+ agp_enabled = 0;
+ } else {
+ agp_enable(0);
+ }
+ }
}
+#else
+ agp_enabled = 0;
+#endif
- if (poh_prev) {
- poh_prev->size += poh_freed->size;
- sisfb_free_node(poh_freed);
- return (poh_prev);
+ /* TW: Now select the queue mode */
+
+ if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
+ cmd_type = AGP_CMD_QUEUE;
+ printk(KERN_INFO "sisfb: Using AGP queue mode\n");
+/* } else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */
+ } else if (sisfb_queuemode == VM_CMD_QUEUE) {
+ cmd_type = VM_CMD_QUEUE;
+ printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
+ } else {
+ printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
+ cmd_type = MMIO_CMD;
}
- if (poh_next) {
- poh_next->size += poh_freed->size;
- poh_next->offset = poh_freed->offset;
- sisfb_free_node(poh_freed);
- return (poh_next);
+ switch (agp_size) {
+ case 0x80000:
+ temp = SIS_CMD_QUEUE_SIZE_512k;
+ break;
+ case 0x100000:
+ temp = SIS_CMD_QUEUE_SIZE_1M;
+ break;
+ case 0x200000:
+ temp = SIS_CMD_QUEUE_SIZE_2M;
+ break;
+ case 0x400000:
+ temp = SIS_CMD_QUEUE_SIZE_4M;
+ break;
}
- sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
+ switch (cmd_type) {
+ case AGP_CMD_QUEUE:
+#ifndef AGPOFF
+ DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
+ agp_info->aper_base, agp->physical, agp_size/1024);
- return (poh_freed);
-}
+ agp_phys = agp_info->aper_base + agp->physical;
-static void sisfb_free_node(SIS_OH *poh)
-{
- if (poh == NULL) {
- return;
- }
+ outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, 0);
+ outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, SIS_AGP_2X);
- poh->poh_next = sisfb_heap.poh_freelist;
- sisfb_heap.poh_freelist = poh;
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
- return;
-}
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
-void sis_malloc(struct sis_memreq *req)
-{
- SIS_OH *poh;
+ *write_port = *read_port;
- poh = sisfb_poh_allocate(req->size);
+ temp |= SIS_AGP_CMDQUEUE_ENABLE;
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
- if (poh == NULL) {
- req->offset = 0;
- req->size = 0;
- DPRINTK("sisfb: Video RAM allocation failed\n");
- } else {
- DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
- (char *) (poh->offset +
- (unsigned long) ivideo.video_vbase));
+ *cmdq_baseport = agp_phys;
- req->offset = poh->offset;
- req->size = poh->size;
- }
+ sisfb_caps |= AGP_CMD_QUEUE_CAP;
+#endif
+ break;
-}
+ case VM_CMD_QUEUE:
+ sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+ sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
-void sis_free(unsigned long base)
-{
- SIS_OH *poh;
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
- poh = sisfb_poh_free(base);
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
- if (poh == NULL) {
- DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
- (unsigned int) base);
- }
-}
+ *write_port = *read_port;
-/* ------------------ SetMode Routines ------------------------------- */
+ temp |= SIS_VRAM_CMDQUEUE_ENABLE;
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
-static void sisfb_pre_setmode(void)
-{
- u8 cr30 = 0, cr31 = 0;
+ *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
- vgawb(CRTC_ADR, 0x31);
- cr31 = vgarb(CRTC_DATA) & ~0x60;
+ sisfb_caps |= VM_CMD_QUEUE_CAP;
- switch (ivideo.disp_state & DISPTYPE_DISP2) {
- case DISPTYPE_CRT2:
- printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
- cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
- cr31 |= SIS_DRIVER_MODE;
- break;
- case DISPTYPE_LCD:
- printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
- cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
- cr31 |= SIS_DRIVER_MODE;
+ DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
+ *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
break;
- case DISPTYPE_TV:
- printk(KERN_INFO "sisfb: CRT2 type is TV\n");
- if (ivideo.TV_type == TVMODE_HIVISION)
- cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
- else if (ivideo.TV_plug == TVPLUG_SVIDEO)
- cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
- else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
- cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
- else if (ivideo.TV_plug == TVPLUG_SCART)
- cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
- cr31 |= SIS_DRIVER_MODE;
- cr31 &= ~0x04; /* TW: No Slavemode by default */
- /*karl*/
- if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
- cr31 |= 0x1;
- if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC)
- cr31 &= ~0x1;
+
+ default: /* MMIO */
+ /* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
+ * to IND_SIS_CMDQUEUE_SET. I doubt that this is
+ * enough. Reserve memory in any way.
+ */
+ sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+ sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+
+ *write_port = *read_port;
+
+ /* TW: Set Auto_Correction bit */
+ temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+ outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+
+ *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+
+ sisfb_caps |= MMIO_CMD_QUEUE_CAP;
+
+ DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
+ *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
break;
- default: /* CRT2 disable */
- printk(KERN_INFO "sisfb: CRT2 is disabled\n");
- cr30 = 0x00;
- cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
}
+ } /* sisvga_engine = 315 */
+#endif
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR30);
- vgawb(CRTC_DATA, cr30);
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR31);
- vgawb(CRTC_DATA, cr31);
- /* printk(KERN_INFO "sisfb: 0x30=%x 0x31=%x\n", cr30, cr31); */
- vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR33);
-/*
- if (ivideo.disp_state & DISPTYPE_CRT2) {
- sisfb_rate_idx &= 0x0F;
- sisfb_rate_idx |= (sisfb_rate_idx << 4);
- vgawb(CRTC_DATA, sisfb_rate_idx);
- } else {
- vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
- }
-*/
- vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
-}
+#ifdef CONFIG_FB_SIS_300
+ if (sisvga_engine == SIS_300_VGA) {
+ /* TW: Now initialize TurboQueue. TB is always located at the very
+ * top of the video RAM. */
+ if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
+ unsigned int tqueue_pos;
+ u8 tq_state;
-static void sisfb_post_setmode(void)
-{
- u8 reg;
+ tqueue_pos = (ivideo.video_size -
+ TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
- vgawb(CRTC_ADR, 0x17);
- reg = vgarb(CRTC_DATA);
+ temp = (u8) (tqueue_pos & 0xff);
- if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL))
- if (ivideo.video_bpp == 8)
- sisfb_crt1off = 0;
+ inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+ tq_state |= 0xf0;
+ tq_state &= 0xfc;
+ tq_state |= (u8) (tqueue_pos >> 8);
+ outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
- if (sisfb_crt1off)
- reg &= ~0x80;
- else
- reg |= 0x80;
- vgawb(CRTC_DATA, reg);
+ outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
+
+ sisfb_caps |= TURBO_QUEUE_CAP;
+
+ sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
+ sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
+ DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
+ sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
+ }
+ }
+#endif
+ /* TW: Now reserve memory for the HWCursor. It is always located at the very
+ top of the videoRAM, right below the TB memory area (if used). */
+ if (sisfb_heap_size >= sisfb_hwcursor_size) {
+ sisfb_heap_end -= sisfb_hwcursor_size;
+ sisfb_heap_size -= sisfb_hwcursor_size;
+ sisfb_hwcursor_vbase = sisfb_heap_end;
+
+ sisfb_caps |= HW_CURSOR_CAP;
+
+ DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
+ sisfb_heap_end, sisfb_hwcursor_size/1024);
+ }
+
+ sisfb_heap.poha_chain = NULL;
+ sisfb_heap.poh_freelist = NULL;
+
+ poh = sisfb_poh_new_node();
+
+ if(poh == NULL) return 1;
- vgawb(SEQ_ADR, IND_SIS_RAMDAC_CONTROL);
- reg = vgarb(SEQ_DATA);
- reg &= ~0x04;
- vgawb(SEQ_DATA, reg);
-
- if ((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
- /*karl*/
- vgawb(VB_PART4_ADR,0x01);
- reg = vgarb(VB_PART4_DATA);
-
- if ((reg != 0xB1) && (reg != 0xB0)) /*301B Revision ID*/
- {
- // Eden Chen
- switch (ivideo.video_width) {
- case 320:
- filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
- break;
- case 640:
- filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
- break;
- case 720:
- filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
- break;
- case 800:
- filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
- break;
- default:
- filter = -1;
- break;
- }
- // ~Eden Chen
+ poh->poh_next = &sisfb_heap.oh_free;
+ poh->poh_prev = &sisfb_heap.oh_free;
+ poh->size = sisfb_heap_end - sisfb_heap_start + 1;
+ poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
- // Eden Chen
- //vgawb(VB_PART1_ADR, 0x24);
- vgawb(VB_PART1_ADR, sisfb_CRT2_write_enable);
- // ~Eden Chen
- vgawb(VB_PART1_DATA, 0x1);
-
- // Eden Chen for Debug
-/*
- if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
- vgawb(VB_PART1_ADR, 0x2D);
- vgawb(VB_PART1_DATA, 0x11);
-
- if (sisfb_mode_no == 0x63) {
- vgawb(VB_PART2_ADR, 0x15);
- vgawb(VB_PART2_DATA, 0x0A);
- vgawb(VB_PART2_ADR, 0x28);
- vgawb(VB_PART2_DATA, 0x62);
- vgawb(VB_PART2_ADR, 0x2D);
- vgawb(VB_PART2_DATA, 0xF8);
- vgawb(VB_PART2_ADR, 0x2E);
- vgawb(VB_PART2_DATA, 0x14);
- vgawb(VB_PART2_ADR, 0x33);
- vgawb(VB_PART2_DATA, 0x8A);
-
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xF4);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0x10);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x1C);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x00);
- vgawb(VB_PART2_ADR, 0x44);
- vgawb(VB_PART2_DATA, 0x29);
- vgawb(VB_PART2_ADR, 0x45);
- vgawb(VB_PART2_DATA, 0x54);
-
- vgawb(VB_PART4_ADR, 0x0D);
- vgawb(VB_PART4_DATA, 0x0F);
- vgawb(VB_PART4_ADR, 0x0F);
- vgawb(VB_PART4_DATA, 0x0F);
- vgawb(VB_PART4_ADR, 0x10);
- vgawb(VB_PART4_DATA, 0x83);
- vgawb(VB_PART4_ADR, 0x11);
- vgawb(VB_PART4_DATA, 0xFF);
- vgawb(VB_PART4_ADR, 0x18);
- vgawb(VB_PART4_DATA, 0x20);
- vgawb(VB_PART4_ADR, 0x19);
- vgawb(VB_PART4_DATA, 0x52);
- }
- }
-*/
- // ~Eden Chen
+ DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
+ (char *) sisfb_heap_start, (char *) sisfb_heap_end,
+ (unsigned int) poh->size / 1024);
- if (ivideo.TV_type == TVMODE_NTSC) {
- vgawb(VB_PART2_ADR, 0x3A);
- reg = vgarb(VB_PART2_DATA);
- reg &= 0x1F;
- vgawb(VB_PART2_DATA, reg);
+ DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
+ (unsigned int) poh->offset, (unsigned int) poh->size / 1024);
- if (ivideo.TV_plug == TVPLUG_SVIDEO) {
- vgawb(VB_PART2_ADR, 0x30);
- reg = vgarb(VB_PART2_DATA);
- reg &= 0xDF;
- vgawb(VB_PART2_DATA, reg);
- } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
- vgawb(VB_PART2_ADR, 0x30);
- reg = vgarb(VB_PART2_DATA);
- reg |= 0x20;
- vgawb(VB_PART2_DATA, reg);
+ sisfb_heap.oh_free.poh_next = poh;
+ sisfb_heap.oh_free.poh_prev = poh;
+ sisfb_heap.oh_free.size = 0;
+ sisfb_heap.max_freesize = poh->size;
+
+ sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
+ sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
+ sisfb_heap.oh_used.size = SENTINEL;
- switch (ivideo.video_width) {
- case 640:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xEB);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0x04);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x25);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x18);
- break;
- case 720:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xEE);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0x0C);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x22);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x08);
- break;
- case 800:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xEB);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0x15);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x25);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0xF6);
- break;
- }
- }
- } else if (ivideo.TV_type == TVMODE_PAL) {
- vgawb(VB_PART2_ADR, 0x3A);
- reg = vgarb(VB_PART2_DATA);
- reg &= 0x1F;
- vgawb(VB_PART2_DATA, reg);
+ return 0;
+}
- if (ivideo.TV_plug == TVPLUG_SVIDEO) {
- vgawb(VB_PART2_ADR, 0x30);
- reg = vgarb(VB_PART2_DATA);
- reg &= 0xDF;
- vgawb(VB_PART2_DATA, reg);
- } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
- vgawb(VB_PART2_ADR, 0x30);
- reg = vgarb(VB_PART2_DATA);
- reg |= 0x20;
- vgawb(VB_PART2_DATA, reg);
+static SIS_OH *sisfb_poh_new_node(void)
+{
+ int i;
+ unsigned long cOhs;
+ SIS_OHALLOC *poha;
+ SIS_OH *poh;
- switch (ivideo.video_width) {
- case 640:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xF1);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0xF7);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x1F);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x32);
- break;
- case 720:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xF3);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0x00);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x1D);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x20);
- break;
- case 800:
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, 0xFC);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, 0xFB);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, 0x14);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, 0x2A);
- break;
- }
- }
- }
+ if (sisfb_heap.poh_freelist == NULL) {
+ poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+ if(!poha) return NULL;
- // Eden
- if ((filter >= 0) && (filter <=7)) {
- DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
- sis_TV_filter[filter_tb].filter[filter][0],
- sis_TV_filter[filter_tb].filter[filter][1],
- sis_TV_filter[filter_tb].filter[filter][2],
- sis_TV_filter[filter_tb].filter[filter][3]
- );
- vgawb(VB_PART2_ADR, 0x35);
- vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][0]);
- vgawb(VB_PART2_ADR, 0x36);
- vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][1]);
- vgawb(VB_PART2_ADR, 0x37);
- vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][2]);
- vgawb(VB_PART2_ADR, 0x38);
- vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][3]);
+ poha->poha_next = sisfb_heap.poha_chain;
+ sisfb_heap.poha_chain = poha;
+
+ cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+
+ poh = &poha->aoh[0];
+ for (i = cOhs - 1; i != 0; i--) {
+ poh->poh_next = poh + 1;
+ poh = poh + 1;
}
- // ~Eden
- } /*karl:endif (reg != 0xB1)*/
-
+
+ poh->poh_next = NULL;
+ sisfb_heap.poh_freelist = &poha->aoh[0];
}
+ poh = sisfb_heap.poh_freelist;
+ sisfb_heap.poh_freelist = poh->poh_next;
+
+ return (poh);
}
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
+static SIS_OH *sisfb_poh_allocate(unsigned long size)
{
- u16 VRE, VBE, VRS, VBS, VDE, VT;
- u16 HRE, HBE, HRS, HBS, HDE, HT;
- u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
- int A, B, C, D, E, F, temp;
- double hrate, drate;
+ SIS_OH *pohThis;
+ SIS_OH *pohRoot;
+ int bAllocated = 0;
- vgawb(SEQ_ADR, IND_SIS_COLOR_MODE);
- sr_data = vgarb(SEQ_DATA);
+ if (size > sisfb_heap.max_freesize) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
- if (sr_data & SIS_INTERLACED_MODE)
- var->vmode = FB_VMODE_INTERLACED;
- else
- var->vmode = FB_VMODE_NONINTERLACED;
+ pohThis = sisfb_heap.oh_free.poh_next;
- switch ((sr_data & 0x1C) >> 2) {
- case SIS_8BPP_COLOR_MODE:
- var->bits_per_pixel = 8;
- break;
- case SIS_16BPP_COLOR_MODE:
- var->bits_per_pixel = 16;
- break;
- case SIS_32BPP_COLOR_MODE:
- var->bits_per_pixel = 32;
- break;
+ while (pohThis != &sisfb_heap.oh_free) {
+ if (size <= pohThis->size) {
+ bAllocated = 1;
+ break;
+ }
+ pohThis = pohThis->poh_next;
}
- switch (var->bits_per_pixel) {
- case 8:
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- video_cmap_len = 256;
- break;
- case 16:
- 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;
- video_cmap_len = 16;
- break;
- case 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;
- video_cmap_len = 16;
- break;
- case 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;
- video_cmap_len = 16;
- break;
+ if (!bAllocated) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
}
- vgawb(SEQ_ADR, 0xA);
- sr_data = vgarb(SEQ_DATA);
+ if (size == pohThis->size) {
+ pohRoot = pohThis;
+ sisfb_delete_node(pohThis);
+ } else {
+ pohRoot = sisfb_poh_new_node();
- vgawb(CRTC_ADR, 0x6);
- cr_data = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x7);
- cr_data2 = vgarb(CRTC_DATA);
- VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
- ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) <<
- 10);
- A = VT + 2;
+ if (pohRoot == NULL) {
+ return (NULL);
+ }
- vgawb(CRTC_ADR, 0x12);
- cr_data = vgarb(CRTC_DATA);
- VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
- ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
- E = VDE + 1;
+ pohRoot->offset = pohThis->offset;
+ pohRoot->size = size;
- vgawb(CRTC_ADR, 0x10);
- cr_data = vgarb(CRTC_DATA);
- VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
- ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
- F = VRS + 1 - E;
+ pohThis->offset += size;
+ pohThis->size -= size;
+ }
- vgawb(CRTC_ADR, 0x15);
- cr_data = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x9);
- cr_data3 = vgarb(CRTC_DATA);
- VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
- ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
+ sisfb_heap.max_freesize -= size;
- vgawb(CRTC_ADR, 0x16);
- cr_data = vgarb(CRTC_DATA);
- VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
- temp = VBE - ((E - 1) & 511);
- B = (temp > 0) ? temp : (temp + 512);
+ pohThis = &sisfb_heap.oh_used;
+ sisfb_insert_node(pohThis, pohRoot);
- vgawb(CRTC_ADR, 0x11);
- cr_data = vgarb(CRTC_DATA);
- VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
- temp = VRE - ((E + F - 1) & 31);
- C = (temp > 0) ? temp : (temp + 32);
+ return (pohRoot);
+}
- D = B - F - C;
+static void sisfb_delete_node(SIS_OH *poh)
+{
+ SIS_OH *poh_prev;
+ SIS_OH *poh_next;
- var->yres = var->yres_virtual = E;
- /* TW: We have to report the physical dimension to the console! */
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- var->yres <<= 1;
- var->yres_virtual <<=1;
- }
- /* TW end */
- var->upper_margin = D;
- var->lower_margin = F;
- var->vsync_len = C;
+ poh_prev = poh->poh_prev;
+ poh_next = poh->poh_next;
- vgawb(SEQ_ADR, 0xb);
- sr_data = vgarb(SEQ_DATA);
+ poh_prev->poh_next = poh_next;
+ poh_next->poh_prev = poh_prev;
- vgawb(CRTC_ADR, 0x0);
- cr_data = vgarb(CRTC_DATA);
- HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
- A = HT + 5;
+}
- vgawb(CRTC_ADR, 0x1);
- cr_data = vgarb(CRTC_DATA);
- HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
- E = HDE + 1;
+static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+{
+ SIS_OH *pohTemp;
- vgawb(CRTC_ADR, 0x4);
- cr_data = vgarb(CRTC_DATA);
- HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
- F = HRS - E - 3;
+ pohTemp = pohList->poh_next;
- vgawb(CRTC_ADR, 0x2);
- cr_data = vgarb(CRTC_DATA);
- HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+ pohList->poh_next = poh;
+ pohTemp->poh_prev = poh;
- vgawb(SEQ_ADR, 0xc);
- sr_data = vgarb(SEQ_DATA);
- vgawb(CRTC_ADR, 0x3);
- cr_data = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x5);
- cr_data2 = vgarb(CRTC_DATA);
- HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
- ((u16) (sr_data & 0x03) << 6);
- HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+ poh->poh_prev = pohList;
+ poh->poh_next = pohTemp;
+}
- temp = HBE - ((E - 1) & 255);
- B = (temp > 0) ? temp : (temp + 256);
+static SIS_OH *sisfb_poh_free(unsigned long base)
+{
+ SIS_OH *pohThis;
+ SIS_OH *poh_freed;
+ SIS_OH *poh_prev;
+ SIS_OH *poh_next;
+ unsigned long ulUpper;
+ unsigned long ulLower;
+ int foundNode = 0;
- temp = HRE - ((E + F + 3) & 63);
- C = (temp > 0) ? temp : (temp + 64);
+ poh_freed = sisfb_heap.oh_used.poh_next;
- D = B - F - C;
+ while(poh_freed != &sisfb_heap.oh_used) {
+ if(poh_freed->offset == base) {
+ foundNode = 1;
+ break;
+ }
- var->xres = var->xres_virtual = E * 8;
- var->left_margin = D * 8;
- var->right_margin = F * 8;
- var->hsync_len = C * 8;
+ poh_freed = poh_freed->poh_next;
+ }
- var->activate = FB_ACTIVATE_NOW;
+ if (!foundNode) return (NULL);
- var->sync = 0;
+ sisfb_heap.max_freesize += poh_freed->size;
- mr_data = vgarb(0x1C);
- if (mr_data & 0x80)
- var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
- else
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
+ poh_prev = poh_next = NULL;
+ ulUpper = poh_freed->offset + poh_freed->size;
+ ulLower = poh_freed->offset;
- if (mr_data & 0x40)
- var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
- else
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
+ pohThis = sisfb_heap.oh_free.poh_next;
- VT += 2;
- VT <<= 1;
- HT = (HT + 5) * 8;
+ while (pohThis != &sisfb_heap.oh_free) {
+ if (pohThis->offset == ulUpper) {
+ poh_next = pohThis;
+ }
+ else if ((pohThis->offset + pohThis->size) ==
+ ulLower) {
+ poh_prev = pohThis;
+ }
+ pohThis = pohThis->poh_next;
+ }
- hrate = (double) ivideo.refresh_rate * (double) VT / 2;
- drate = hrate * HT;
- var->pixclock = (u32) (1E12 / drate);
-}
+ sisfb_delete_node(poh_freed);
-/* ------------------ Public Routines -------------------------------- */
+ if (poh_prev && poh_next) {
+ poh_prev->size += (poh_freed->size + poh_next->size);
+ sisfb_delete_node(poh_next);
+ sisfb_free_node(poh_freed);
+ sisfb_free_node(poh_next);
+ return (poh_prev);
+ }
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, fb_info.modename);
+ if (poh_prev) {
+ poh_prev->size += poh_freed->size;
+ sisfb_free_node(poh_freed);
+ return (poh_prev);
+ }
- fix->smem_start = ivideo.video_base;
-
- /*karl:10/01/2001*/ /* TW */
- if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
- if (ivideo.video_size > 0x800000)
- fix->smem_len = 0x800000;
- else
- fix->smem_len = 0x400000;
- } else
- fix->smem_len = sisfb_mem * 1024;
+ if (poh_next) {
+ poh_next->size += poh_freed->size;
+ poh_next->offset = poh_freed->offset;
+ sisfb_free_node(poh_freed);
+ return (poh_next);
+ }
- fix->type = video_type;
- fix->type_aux = 0;
- if (ivideo.video_bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_TRUECOLOR;
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = video_linelength;
- fix->mmio_start = ivideo.mmio_base;
- fix->mmio_len = sisfb_mmio_size;
- fix->accel = FB_ACCEL_SIS_GLAMOUR;
- fix->reserved[0] = ivideo.video_size & 0xFFFF;
- fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
- fix->reserved[2] = sisfb_caps;
+ sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
- return 0;
+ return (poh_freed);
}
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static void sisfb_free_node(SIS_OH *poh)
{
- if (con == -1)
- memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
- else
- *var = fb_display[con].var;
+ if(poh == NULL) return;
- /* JennyLee 2001126: for FSTN */
- if (var->xres == 320 && var->yres == 480)
- var->yres = 240;
- /* ~JennyLee */
+ poh->poh_next = sisfb_heap.poh_freelist;
+ sisfb_heap.poh_freelist = poh;
- return 0;
}
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+void sis_malloc(struct sis_memreq *req)
{
- int err;
- unsigned int cols, rows;
-
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
- if (sisfb_do_set_var(var, con == currcon, info)) {
- sisfb_crtc_to_var(var);
- return -EINVAL;
- }
-
- sisfb_crtc_to_var(var);
-
- sisfb_set_disp(con, var);
+ SIS_OH *poh;
- if (info->changevar)
- (*info->changevar) (con);
+ poh = sisfb_poh_allocate(req->size);
- if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
- return err;
+ if(poh == NULL) {
+ req->offset = 0;
+ req->size = 0;
+ DPRINTK("sisfb: Video RAM allocation failed\n");
+ } else {
+ DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
+ (char *) (poh->offset + (unsigned long) ivideo.video_vbase));
- sisfb_do_install_cmap(con, info);
-
- cols = sisbios_mode[sisfb_mode_idx].cols;
- rows = sisbios_mode[sisfb_mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+ req->offset = poh->offset;
+ req->size = poh->size;
+ }
- return 0;
}
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
+void sis_free(unsigned long base)
{
- if (con == currcon)
- return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
- else if (fb_display[con].cmap.len)
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
-
- return 0;
-}
+ SIS_OH *poh;
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
+ poh = sisfb_poh_free(base);
- if (!fb_display[con].cmap.len) {
- err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
- if (err)
- return err;
+ if(poh == NULL) {
+ DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
+ (unsigned int) base);
}
- if (con == currcon)
- return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
- else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
}
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
+/* ------------------ SetMode Routines ------------------------------- */
+
+static void sisfb_pre_setmode(void)
{
- switch (cmd) {
- case FBIO_ALLOC:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_malloc((struct sis_memreq *) arg);
+ u8 cr30 = 0, cr31 = 0;
+
+ inSISIDXREG(SISCR, 0x31, cr31);
+ cr31 &= ~0x60;
+
+ switch (ivideo.disp_state & DISPTYPE_DISP2) {
+ case DISPTYPE_CRT2:
+ printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
+ cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= SIS_DRIVER_MODE;
break;
- case FBIO_FREE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_free(*(unsigned long *) arg);
+ case DISPTYPE_LCD:
+ printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
+ cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= SIS_DRIVER_MODE;
break;
- case FBIOGET_GLYPH:
- sis_get_glyph((SIS_GLYINFO *) arg);
+ case DISPTYPE_TV:
+ printk(KERN_INFO "sisfb: CRT2 type is TV\n");
+ if (ivideo.TV_type == TVMODE_HIVISION)
+ cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ else if (ivideo.TV_plug == TVPLUG_SVIDEO)
+ cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
+ cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ else if (ivideo.TV_plug == TVPLUG_SCART)
+ cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= SIS_DRIVER_MODE;
+
+ if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
+ cr31 |= 0x01;
+ else /* if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC) - nonsense */
+ cr31 &= ~0x01;
break;
- case FBIOGET_HWCINFO:
- {
- unsigned long *hwc_offset = (unsigned long *) arg;
+ default: /* CRT2 disable */
+ printk(KERN_INFO "sisfb: CRT2 is disabled\n");
+ cr30 = 0x00;
+ cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
+ }
- if (sisfb_caps & HW_CURSOR_CAP)
- *hwc_offset = sisfb_hwcursor_vbase -
- (unsigned long) ivideo.video_vbase;
- else
- *hwc_offset = 0;
+ outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
+ outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
- break;
- }
- case FBIOPUT_MODEINFO:
- {
- struct mode_info *x = (struct mode_info *)arg;
-
- ivideo.video_bpp = x->bpp;
- ivideo.video_width = x->xres;
- ivideo.video_height = x->yres;
- ivideo.video_vwidth = x->v_xres;
- ivideo.video_vheight = x->v_yres;
- ivideo.org_x = x->org_x;
- ivideo.org_y = x->org_y;
- ivideo.refresh_rate = x->vrate;
-
- break;
+ outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, (sisfb_rate_idx & 0x0F));
+
+}
+
+static void sisfb_post_setmode(void)
+{
+ u8 reg;
+ BOOLEAN doit = TRUE;
+
+ /* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
+ if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) {
+ if (ivideo.video_bpp == 8) {
+ doit = FALSE;
}
- case FBIOGET_DISPINFO:
- sis_dispinfo((struct ap_data *)arg);
- break;
- default:
- return -EINVAL;
}
- return 0;
-}
+ /* TW: We can't switch off CRT1 on 630+301B in 8bpp Modes */
+ if ( (sishw_ext.ujVBChipID == VB_CHIP_301B) && (sisvga_engine == SIS_300_VGA) &&
+ (ivideo.disp_state & DISPTYPE_LCD) ) {
+ if (ivideo.video_bpp == 8) {
+ doit = FALSE;
+ }
+ }
+
+ /* TW: We can't switch off CRT1 if bridge is in slave mode */
+ if(ivideo.hasVB != HASVB_NONE) {
+ inSISIDXREG(SISPART1, 0x00, reg);
+ if(sisvga_engine == SIS_300_VGA) {
+ if((reg & 0xa0) == 0x20) {
+ doit = FALSE;
+ }
+ }
+ if(sisvga_engine == SIS_315_VGA) {
+ if((reg & 0x50) == 0x10) {
+ doit = FALSE;
+ }
+ }
+ } else sisfb_crt1off = 0;
+
+ inSISIDXREG(SISCR, 0x17, reg);
+ if((sisfb_crt1off) && (doit))
+ reg &= ~0x80;
+ else
+ reg |= 0x80;
+ outSISIDXREG(SISCR, 0x17, reg);
-static int sisfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
-{
- struct fb_var_screeninfo var;
- unsigned long start;
- unsigned long off;
- u32 len;
+ andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- start = (unsigned long) ivideo.video_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+ if((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
- if (off >= len) {
- off -= len;
- sisfb_get_var(&var, currcon, info);
- if (var.accel_flags)
- return -EINVAL;
- start = (unsigned long) ivideo.mmio_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
- }
+ inSISIDXREG(SISPART4, 0x01, reg);
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
+ if(reg < 0xB0) { /* Set filter for SiS301 */
-#if defined(__i386__)
- if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
-#else /* TW: 2.5 API */
- if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
-#endif
- return -EAGAIN;
- return 0;
+ switch (ivideo.video_width) {
+ case 320:
+ filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
+ break;
+ case 640:
+ filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
+ break;
+ case 720:
+ filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
+ break;
+ case 800:
+ filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
+ break;
+ default:
+ filter = -1;
+ break;
+ }
-}
+ orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
-static struct fb_ops sisfb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: sisfb_get_fix,
- fb_get_var: sisfb_get_var,
- fb_set_var: sisfb_set_var,
- fb_get_cmap: sisfb_get_cmap,
- fb_set_cmap: sisfb_set_cmap,
- fb_ioctl: sisfb_ioctl,
- fb_mmap: sisfb_mmap,
-};
+ if(ivideo.TV_type == TVMODE_NTSC) {
-/* ------------ Interface to the low level console driver -------------*/
+ andSISIDXREG(SISPART2, 0x3a, 0x1f);
-static int sisfb_update_var(int con, struct fb_info *info)
-{
- return 0;
-}
+ if (ivideo.TV_plug == TVPLUG_SVIDEO) {
-static int sisfb_switch(int con, struct fb_info *info)
-{
- int cols, rows;
+ andSISIDXREG(SISPART2, 0x30, 0xdf);
- if (fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+ } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
+ orSISIDXREG(SISPART2, 0x30, 0x20);
- if (!memcmp(&fb_display[con].var, &fb_display[currcon].var,
- sizeof(struct fb_var_screeninfo))) {
- currcon = con;
- return 1;
- }
+ switch (ivideo.video_width) {
+ case 640:
+ outSISIDXREG(SISPART2, 0x35, 0xEB);
+ outSISIDXREG(SISPART2, 0x36, 0x04);
+ outSISIDXREG(SISPART2, 0x37, 0x25);
+ outSISIDXREG(SISPART2, 0x38, 0x18);
+ break;
+ case 720:
+ outSISIDXREG(SISPART2, 0x35, 0xEE);
+ outSISIDXREG(SISPART2, 0x36, 0x0C);
+ outSISIDXREG(SISPART2, 0x37, 0x22);
+ outSISIDXREG(SISPART2, 0x38, 0x08);
+ break;
+ case 800:
+ outSISIDXREG(SISPART2, 0x35, 0xEB);
+ outSISIDXREG(SISPART2, 0x36, 0x15);
+ outSISIDXREG(SISPART2, 0x37, 0x25);
+ outSISIDXREG(SISPART2, 0x38, 0xF6);
+ break;
+ }
+ }
- currcon = con;
+ } else if(ivideo.TV_type == TVMODE_PAL) {
- sisfb_do_set_var(&fb_display[con].var, 1, info);
+ andSISIDXREG(SISPART2, 0x3A, 0x1F);
- sisfb_set_disp(con, &fb_display[con].var);
-
- sisfb_do_install_cmap(con, info);
+ if (ivideo.TV_plug == TVPLUG_SVIDEO) {
- cols = sisbios_mode[sisfb_mode_idx].cols;
- rows = sisbios_mode[sisfb_mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+ andSISIDXREG(SISPART2, 0x30, 0xDF);
- sisfb_update_var(con, info);
+ } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
- return 1;
-}
+ orSISIDXREG(SISPART2, 0x30, 0x20);
-static void sisfb_blank(int blank, struct fb_info *info)
-{
- u8 reg;
+ switch (ivideo.video_width) {
+ case 640:
+ outSISIDXREG(SISPART2, 0x35, 0xF1);
+ outSISIDXREG(SISPART2, 0x36, 0xF7);
+ outSISIDXREG(SISPART2, 0x37, 0x1F);
+ outSISIDXREG(SISPART2, 0x38, 0x32);
+ break;
+ case 720:
+ outSISIDXREG(SISPART2, 0x35, 0xF3);
+ outSISIDXREG(SISPART2, 0x36, 0x00);
+ outSISIDXREG(SISPART2, 0x37, 0x1D);
+ outSISIDXREG(SISPART2, 0x38, 0x20);
+ break;
+ case 800:
+ outSISIDXREG(SISPART2, 0x35, 0xFC);
+ outSISIDXREG(SISPART2, 0x36, 0xFB);
+ outSISIDXREG(SISPART2, 0x37, 0x14);
+ outSISIDXREG(SISPART2, 0x38, 0x2A);
+ break;
+ }
+ }
+ }
- vgawb(CRTC_ADR, 0x17);
- reg = vgarb(CRTC_DATA);
+ if ((filter >= 0) && (filter <=7)) {
+ DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
+ sis_TV_filter[filter_tb].filter[filter][0],
+ sis_TV_filter[filter_tb].filter[filter][1],
+ sis_TV_filter[filter_tb].filter[filter][2],
+ sis_TV_filter[filter_tb].filter[filter][3]
+ );
+ outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
+ outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
+ outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
+ outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
+ }
- if (blank > 0)
- reg &= 0x7f;
- else
- reg |= 0x80;
+ }
+
+ }
- vgawb(CRTC_ADR, 0x17);
- vgawb(CRTC_DATA, reg);
}
+#ifndef MODULE
int sisfb_setup(char *options)
{
char *this_opt;
- fb_info.fontname[0] = '\0';
+ sis_fb_info.fontname[0] = '\0';
ivideo.refresh_rate = 0;
+ printk(KERN_INFO "sisfb: Options %s\n", options);
+
if (!options || !*options)
return 0;
-#if 0 /* TW (Alex Tribble): Change for 2.5 series */
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
-#endif
- while((this_opt = strsep(&options, ","))) {
- if (!*this_opt)
- continue;
+ while((this_opt = strsep(&options, ",")) != NULL) {
+
+ if (!*this_opt) continue;
if (!strcmp(this_opt, "inverse")) {
sisfb_inverse = 1;
- fb_invert_cmaps();
+ /* fb_invert_cmaps(); */
} else if (!strncmp(this_opt, "font:", 5)) {
- strcpy(fb_info.fontname, this_opt + 5);
+ strcpy(sis_fb_info.fontname, this_opt + 5);
} else if (!strncmp(this_opt, "mode:", 5)) {
sisfb_search_mode(this_opt + 5);
+ } else if (!strncmp(this_opt, "vesa:", 5)) {
+ sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
} else if (!strncmp(this_opt, "vrate:", 6)) {
ivideo.refresh_rate =
simple_strtoul(this_opt + 6, NULL, 0);
@@ -2619,42 +3128,60 @@
sisfb_search_crt2type(this_opt + 14);
} else if (!strncmp(this_opt, "forcecrt1:", 10)) {
sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
- /*karl*/
} else if (!strncmp(this_opt, "tvmode:",7)) {
if (!strncmp(this_opt + 7, "pal",3))
sisfb_tvmode = 1;
if (!strncmp(this_opt + 7, "ntsc",4))
sisfb_tvmode = 2;
- }
- /*karl:10/01/2001*/
- else if (!strncmp(this_opt, "mem:",4)) {
+ } else if (!strncmp(this_opt, "tvstandard:",11)) {
+ if (!strncmp(this_opt + 11, "pal",3))
+ sisfb_tvmode = 1;
+ else if (!strncmp(this_opt + 11, "ntsc",4))
+ sisfb_tvmode = 2;
+ }else if (!strncmp(this_opt, "mem:",4)) {
sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
- }
- /* JennyLee 20011211 */
- else if (!strncmp(this_opt, "dstn:", 5)) {
- enable_dstn = simple_strtoul(this_opt + 5, NULL, 0);
- }
- /* ~JennyLee 20011211 */
- else if (!strncmp(this_opt, "queuemode:", 10)) {
+ } else if (!strncmp(this_opt, "dstn", 4)) {
+ enable_dstn = 1;
+ /* TW: DSTN overrules forcecrt2type */
+ sisfb_crt2type = DISPTYPE_LCD;
+ } else if (!strncmp(this_opt, "queuemode:", 10)) {
sisfb_search_queuemode(this_opt + 10);
+ } else if (!strncmp(this_opt, "pdc:", 4)) {
+ sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+ if(sisfb_pdc & ~0x3c) {
+ printk(KERN_INFO "sisfb: Illegal pdc parameter\n");
+ sisfb_pdc = 0;
+ }
+ } else if (!strncmp(this_opt, "noaccel", 7)) {
+ sisfb_accel = 0;
+ } else if (!strncmp(this_opt, "noypan", 6)) {
+ sisfb_ypan = 0;
+ } else {
+ printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
}
- else
- printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
+ /* TW: Acceleration only with MMIO mode */
+ if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+ sisfb_ypan = 0;
+ sisfb_accel = 0;
+ }
+ /* TW: Panning only with acceleration */
+ if(sisfb_accel == 0) sisfb_ypan = 0;
+
}
return 0;
}
+#endif
int __init sisfb_init(void)
{
struct pci_dev *pdev = NULL;
struct board *b;
int pdev_valid = 0;
- //unsigned long rom_vbase;
+ /* unsigned long rom_vbase; */
u32 reg32;
u16 reg16;
u8 reg;
- int temp1, temp2;
outb(0x77, 0x80);
@@ -2670,25 +3197,24 @@
if (sisfb_off)
return -ENXIO;
-// printk("20011213:enable_dstn=%d \n", enable_dstn);
if (enable_dstn)
- SetEnableDstn();
+ SetEnableDstn(&SiS_Pr);
+
+ memset(&sis_fb_info, 0, sizeof(sis_fb_info));
+ memset(&sis_disp, 0, sizeof(sis_disp));
pci_for_each_dev(pdev) {
for (b = sisdev_list; b->vendor; b++) {
if ((b->vendor == pdev->vendor)
&& (b->device == pdev->device)) {
pdev_valid = 1;
- strcpy(fb_info.modename, b->name);
+ strcpy(sis_fb_info.modename, b->name);
ivideo.chip_id = pdev->device;
pci_read_config_byte(pdev, PCI_REVISION_ID,
&ivideo.revision_id);
pci_read_config_word(pdev, PCI_COMMAND, ®16);
- // Eden Chen
- //sishw_ext.uRevisionID = ivideo.revision_id;
sishw_ext.jChipRevision = ivideo.revision_id;
- // ~Eden Chen
- sisvga_enabled = reg16 & 0x1;
+ sisvga_enabled = reg16 & 0x01;
break;
}
}
@@ -2698,9 +3224,8 @@
}
if (!pdev_valid)
- return -1;
+ return -ENODEV;
-// Eden Chen
switch (ivideo.chip_id) {
case PCI_DEVICE_ID_SI_300:
ivideo.chip = SIS_300;
@@ -2712,9 +3237,9 @@
{
sisfb_set_reg4(0xCF8, 0x80000000);
reg32 = sisfb_get_reg3(0xCFC);
- if (reg32 == 0x07301039) {
+ if(reg32 == 0x07301039) {
ivideo.chip = SIS_730;
- strcpy(fb_info.modename, "SIS 730");
+ strcpy(sis_fb_info.modename, "SIS 730");
} else
ivideo.chip = SIS_630;
@@ -2760,31 +3285,28 @@
sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
break;
}
- // Eden Chen
- //sishw_ext.jChipID = ivideo.chip;
sishw_ext.jChipType = ivideo.chip;
- // for Debug
+
+ /* for Debug */
if ((sishw_ext.jChipType == SIS_315PRO)
|| (sishw_ext.jChipType == SIS_315) )
sishw_ext.jChipType = SIS_315H;
- // ~Eden Chen
- DPRINTK("%s is used as %s device(VGA Engine %d).\n",
- fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
+ DPRINTK("%s is used as %s device (VGA Engine %d).\n",
+ sis_fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
ivideo.video_base = pci_resource_start(pdev, 0);
ivideo.mmio_base = pci_resource_start(pdev, 1);
- // Eden Chen
- //sishw_ext.IOAddress = (unsigned short) ivideo.vga_base
- // = pci_resource_start(pdev, 2) + 0x30;
- sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base
- = pci_resource_start(pdev, 2) + 0x30;
- // ~Eden Chen
+ sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base =
+ (unsigned short) SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
sisfb_mmio_size = pci_resource_len(pdev, 1);
- if (!sisvga_enabled)
+ if(!sisvga_enabled) {
if (pci_enable_device(pdev)) return -EIO;
+ }
+
+ SiSRegInit(&SiS_Pr, (USHORT)sishw_ext.ulIOAddress);
// Eden Eden
//#ifdef LINUXBIOS
@@ -2799,37 +3321,30 @@
// }
//#endif
// ~Eden Chen
-
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
#ifdef LINUXBIOS
+
#ifdef CONFIG_FB_SIS_300
if (sisvga_engine == SIS_300_VGA) {
- vgawb(SEQ_ADR, 0x28);
- vgawb(SEQ_DATA, 0x37);
+ outSISIDXREG(SISSR, 0x28, 0x37);
- vgawb(SEQ_ADR, 0x29);
- vgawb(SEQ_DATA, 0x61);
+ outSISIDXREG(SISSR, 0x29, 0x61);
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
- reg = vgarb(SEQ_DATA);
- reg |= SIS_SCRATCH_REG_1A_MASK;
- vgawb(SEQ_DATA, reg);
+ orSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, SIS_SCRATCH_REG_1A_MASK);
}
#endif
#ifdef CONFIG_FB_SIS_315
if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
- vgawb(SEQ_ADR, 0x28);
- vgawb(SEQ_DATA, 0x5A);
+ outSISIDXREG(SISSR, 0x28, 0x5a);
- vgawb(SEQ_ADR, 0x29);
- vgawb(SEQ_DATA, 0x64);
+ outSISIDXREG(SISSR, 0x29, 0x64);
- vgawb(CRTC_ADR, 0x3A);
- vgawb(CRTC_DATA, 0x00);
+ outSISIDXREG(SISCR, 0x3a, 0x00);
}
#endif
+
#endif /* LinuxBIOS */
if (sisvga_engine == SIS_315_VGA) {
@@ -2840,16 +3355,7 @@
break;
case SIS_550:
case SIS_650:
- // Eden Chen
- //vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
- //reg = vgarb(SEQ_DATA);
- //if (reg & SIS_SCRATCH_REG_1A_MASK)
- // sishw_ext.bIntegratedMMEnabled = TRUE;
- //else
- // sishw_ext.bIntegratedMMEnabled = FALSE;
- //for Debug
sishw_ext.bIntegratedMMEnabled = TRUE;
- // ~Eden Chen
break;
default:
break;
@@ -2858,8 +3364,7 @@
if (ivideo.chip == SIS_300) {
sishw_ext.bIntegratedMMEnabled = TRUE;
} else {
- vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
- reg = vgarb(SEQ_DATA);
+ inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
if (reg & SIS_SCRATCH_REG_1A_MASK)
sishw_ext.bIntegratedMMEnabled = TRUE;
else
@@ -2867,7 +3372,6 @@
}
}
- // Eden Chen
sishw_ext.pDevice = NULL;
sishw_ext.pjVirtualRomBase = NULL;
sishw_ext.pjCustomizedROMImage = NULL;
@@ -2876,33 +3380,38 @@
sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
strcpy(sishw_ext.szVBIOSVer, "0.84");
+ /* TW: Mode numbers for 1280x960 are different for 300 and 310/325 series */
+ if(sisvga_engine == SIS_300_VGA) {
+ sisbios_mode[MODEINDEX_1280x960].mode_no = 0x6e;
+ sisbios_mode[MODEINDEX_1280x960+1].mode_no = 0x6f;
+ sisbios_mode[MODEINDEX_1280x960+2].mode_no = 0x7b;
+ sisbios_mode[MODEINDEX_1280x960+3].mode_no = 0x7b;
+ }
+
sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
if (sishw_ext.pSR == NULL) {
- printk(KERN_INFO "sisfb: Fatal error: Allocating SRReg space failed.\n");
+ printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
return -ENODEV;
}
sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
if (sishw_ext.pCR == NULL) {
- printk(KERN_INFO "sisfb: Fatal error: Allocating CRReg space failed.\n");
+ vfree(sishw_ext.pSR);
+ printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
return -ENODEV;
}
sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
- // ~Eden Chen
#ifdef CONFIG_FB_SIS_300
- if (sisvga_engine == SIS_300_VGA) {
- if (!sisvga_enabled) {
- // Eden Chen
- sishw_ext.pjVideoMemoryAddress
+ if(sisvga_engine == SIS_300_VGA) {
+ if(!sisvga_enabled) {
+ sishw_ext.pjVideoMemoryAddress
= ioremap(ivideo.video_base, 0x2000000);
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- //SiSInit300(&sishw_ext);
- SiSInit(&sishw_ext);
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
- // ~Eden Chen
+ /* TW: SiSInit now for LinuxBIOS only */
+ /* SiSInit(&SiS_Pr, &sishw_ext); */
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
}
}
#ifdef LINUXBIOS
@@ -2910,20 +3419,18 @@
sishw_ext.pjVideoMemoryAddress
= ioremap(ivideo.video_base, 0x2000000);
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- SiSInit(&sishw_ext);
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+ SiSInit(&SiS_Pr, &sishw_ext);
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
}
}
- if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- vgawb(SEQ_ADR, 0x7);
- reg = vgarb(SEQ_DATA);
- reg |= 0x10;
- vgawb(SEQ_DATA, reg);
+ if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
+ orSISIDXREG(SISSR, 0x07, 0x10);
}
#endif
- if (sisfb_get_dram_size_300()) {
- printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size\n");
+ if(sisfb_get_dram_size_300()) {
+ vfree(sishw_ext.pSR);
+ vfree(sishw_ext.pCR);
+ printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
return -ENODEV;
}
}
@@ -2938,19 +3445,17 @@
sishw_ext.pjVideoMemoryAddress
= ioremap(ivideo.video_base, 0x8000000);
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- SiSInit(&sishw_ext);
+ /* TW: SISInit is now for LINUXBIOS only */
+ /* SiSInit(&SiS_Pr, &sishw_ext); */
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sishw_ext.bSkipDramSizing = TRUE;
- vgawb(SEQ_ADR, 0x13);
sishw_ext.pSR[0].jIdx = 0x13;
- sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
- vgawb(SEQ_ADR, 0x14);
sishw_ext.pSR[1].jIdx = 0x14;
- sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
sishw_ext.pSR[2].jIdx = 0xFF;
+ inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+ inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
sishw_ext.pSR[2].jVal = 0xFF;
}
}
@@ -2959,123 +3464,130 @@
sishw_ext.pjVideoMemoryAddress
= ioremap(ivideo.video_base, 0x8000000);
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- SiSInit(&sishw_ext);
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+
+ SiSInit(&SiS_Pr, &sishw_ext);
+
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sishw_ext.bSkipDramSizing = TRUE;
- vgawb(SEQ_ADR, 0x13);
sishw_ext.pSR[0].jIdx = 0x13;
- sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
- vgawb(SEQ_ADR, 0x14);
sishw_ext.pSR[1].jIdx = 0x14;
- sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
sishw_ext.pSR[2].jIdx = 0xFF;
+ inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+ inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
sishw_ext.pSR[2].jVal = 0xFF;
}
}
#endif
if (sisfb_get_dram_size_315()) {
+ vfree(sishw_ext.pSR);
+ vfree(sishw_ext.pCR);
printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
return -ENODEV;
}
}
#endif
+
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- //Eden Chen
- vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
- reg = vgarb(SEQ_DATA);
- reg |= SIS_PCI_ADDR_ENABLE; /* Enable PCI_LINEAR_ADDRESSING */
- reg |= SIS_MEM_MAP_IO_ENABLE; /* Enable MMIO_ENABLE */
- vgawb(SEQ_DATA, reg);
-
- vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
- reg = vgarb(SEQ_DATA);
- reg |= SIS_ENABLE_2D; /* Enable 2D accelerator engine */
- vgawb(SEQ_DATA, reg);
- //~Eden Chen
+
+ /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
+ orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+
+ /* Enable 2D accelerator engine */
+ orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+
}
- // Eden Chen
sishw_ext.ulVideoMemorySize = ivideo.video_size;
- // ~Eden Chen
+
+ if(sisfb_pdc) {
+ sishw_ext.pdc = sisfb_pdc;
+ } else {
+ sishw_ext.pdc = 0;
+ }
+
if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
+ printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
+ vfree(sishw_ext.pSR);
+ vfree(sishw_ext.pCR);
return -ENODEV;
}
if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
release_mem_region(ivideo.video_base, ivideo.video_size);
+ vfree(sishw_ext.pSR);
+ vfree(sishw_ext.pCR);
return -ENODEV;
}
- // Eden Chen
- //sishw_ext.VirtualVideoMemoryAddress = ivideo.video_vbase
- sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase
+
+ sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase
= ioremap(ivideo.video_base, ivideo.video_size);
- // Eden Chen
ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
- printk(KERN_INFO
- "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
ivideo.video_base, ivideo.video_vbase,
ivideo.video_size / 1024);
- printk(KERN_INFO
- "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
+ printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
ivideo.mmio_base, ivideo.mmio_vbase,
sisfb_mmio_size / 1024);
+ if(sisfb_heap_init()) {
+ printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
+ }
+
+ ivideo.mtrr = (unsigned int) 0;
+
if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
#ifdef CONFIG_FB_SIS_300
if (sisvga_engine == SIS_300_VGA) {
sisfb_get_VB_type_300();
- if (ivideo.hasVB != HASVB_NONE) {
- sisfb_detect_VB_connect_300();
- }
}
#endif
#ifdef CONFIG_FB_SIS_315
if (sisvga_engine == SIS_315_VGA) {
sisfb_get_VB_type_315();
- if (ivideo.hasVB != HASVB_NONE) {
- sisfb_detect_VB_connect_315();
- }
}
#endif
- // Eden Chen
sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
sishw_ext.usExternalChip = 0;
switch (ivideo.hasVB) {
case HASVB_301:
- /*karl*/
- vgawb(VB_PART4_ADR,0x01);
- reg = vgarb(VB_PART4_DATA);
- if (reg >= 0xD0) {
- sishw_ext.ujVBChipID = VB_CHIP_301B;
- printk(KERN_INFO "sisfb: SiS301LV bridge detected\n");
+ inSISIDXREG(SISPART4, 0x01, reg);
+ if (reg >= 0xE0) {
+ sishw_ext.ujVBChipID = VB_CHIP_301LVX;
+ printk(KERN_INFO "sisfb: SiS301LVX bridge detected (revision 0x%02x)\n",reg);
+ } else if (reg >= 0xD0) {
+ sishw_ext.ujVBChipID = VB_CHIP_301LV;
+ printk(KERN_INFO "sisfb: SiS301LV bridge detected (revision 0x%02x)\n",reg);
} else if (reg >= 0xB0) {
sishw_ext.ujVBChipID = VB_CHIP_301B;
- printk(KERN_INFO "sisfb: SiS301B bridge detected\n");
+ printk(KERN_INFO "sisfb: SiS301B bridge detected (revision 0x%02x\n",reg);
} else {
sishw_ext.ujVBChipID = VB_CHIP_301;
printk(KERN_INFO "sisfb: SiS301 bridge detected\n");
}
break;
case HASVB_302:
- vgawb(VB_PART4_ADR,0x01);
- reg = vgarb(VB_PART4_DATA);
- sishw_ext.ujVBChipID = VB_CHIP_302;
- if (reg >= 0xD0) {
- printk(KERN_INFO "sisfb: SiS302LV bridge detected\n");
+ inSISIDXREG(SISPART4, 0x01, reg);
+ if (reg >= 0xE0) {
+ sishw_ext.ujVBChipID = VB_CHIP_302LVX;
+ printk(KERN_INFO "sisfb: SiS302LVX bridge detected (revision 0x%02x)\n",reg);
+ } else if (reg >= 0xD0) {
+ sishw_ext.ujVBChipID = VB_CHIP_302LV;
+ printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
} else if (reg >= 0xB0) {
- printk(KERN_INFO "sisfb: SiS302B bridge detected\n");
+ sishw_ext.ujVBChipID = VB_CHIP_302B;
+ printk(KERN_INFO "sisfb: SiS302B bridge detected (revision 0x%02x)\n",reg);
} else {
+ sishw_ext.ujVBChipID = VB_CHIP_302;
printk(KERN_INFO "sisfb: SiS302 bridge detected\n");
}
break;
@@ -3085,108 +3597,64 @@
break;
case HASVB_LVDS:
sishw_ext.usExternalChip = 0x1;
- printk(KERN_INFO "sisfb: LVDS bridge detected\n");
+ printk(KERN_INFO "sisfb: LVDS transmitter detected\n");
break;
case HASVB_TRUMPION:
sishw_ext.usExternalChip = 0x2;
- printk(KERN_INFO "sisfb: TRUMPION TV converter detected\n");
+ printk(KERN_INFO "sisfb: Trumpion Zurac LVDS scaler detected\n");
break;
case HASVB_CHRONTEL:
sishw_ext.usExternalChip = 0x4;
- printk(KERN_INFO "sisfb: Chrontel TV converter detected\n");
+ printk(KERN_INFO "sisfb: Chrontel TV encoder detected\n");
break;
case HASVB_LVDS_CHRONTEL:
sishw_ext.usExternalChip = 0x5;
- printk(KERN_INFO "sisfb: LVDS bridge and Chrontel TV converter detected\n");
+ printk(KERN_INFO "sisfb: LVDS transmitter and Chrontel TV encoder detected\n");
break;
default:
printk(KERN_INFO "sisfb: No or unknown bridge type detected\n");
break;
}
- // ~Eden Chen
- /* TW: Determine and detect attached TV's on Chrontel */
- if (sishw_ext.usExternalChip == 0x04 || sishw_ext.usExternalChip == 0x05) {
- SiSRegInit(sishw_ext.ulIOAddress);
- temp1=SiS_GetCH7005(0x25);
- if ((temp1 >= 50) && (temp1 <= 100)) {
- /* TW: Read power status */
- temp1 = SiS_GetCH7005(0x0e);
- if ((temp1&0x03)!=0x03) {
- /* TW: Power all outputs */
- SiS_SetCHTVRegANDOR(0x030E,0xF8);
- }
- /* TW: Sense connected TV devices */
- SiS_SetCH7005(0x0110);
- SiS_SetCH7005(0x0010);
- temp1 = SiS_GetCH7005(0x10);
- if (!(temp1 & 0x08)) {
- /* TW: So we can be sure that there IS a SVHS output */
- printk(KERN_INFO
- "sisfb: Chrontel: Detected TV connected to SVHS output\n");
- ivideo.TV_plug = TVPLUG_SVIDEO;
- vgawb(CRTC_ADR, 0x32);
- temp2 = vgarb(CRTC_DATA) | 0x02;
- vgawb(CRTC_DATA, temp2);
- } else if (!(temp1 & 0x02)) {
- /* TW: So we can be sure that there IS a CVBS output */
- printk(KERN_INFO
- "sisfb: Chrontel: Detected TV connected to CVBS output\n");
- ivideo.TV_plug = TVPLUG_COMPOSITE;
- vgawb(CRTC_ADR, 0x32);
- temp2 = vgarb(CRTC_DATA) | 0x01;
- vgawb(CRTC_DATA, temp2);
- } else {
- SiS_SetCHTVRegANDOR(0x010E,0xF8);
- }
- } else if (temp1==0) {
- SiS_SetCHTVRegANDOR(0x010E,0xF8);
- }
- }
+ if (ivideo.hasVB != HASVB_NONE) {
+#ifdef CONFIG_FB_SIS_300
+ if (sisvga_engine == SIS_300_VGA) {
+ sisfb_detect_VB_connect_300();
+ }
+#endif
+#ifdef CONFIG_FB_SIS_315
+ if (sisvga_engine == SIS_315_VGA) {
+ sisfb_detect_VB_connect_315();
+ }
+#endif
+ }
if (ivideo.disp_state & DISPTYPE_DISP2) {
if (sisfb_crt1off)
ivideo.disp_state |= DISPMODE_SINGLE;
else
ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
- } else
+ } else {
ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+ }
if (ivideo.disp_state & DISPTYPE_LCD) {
- vgawb(CRTC_ADR, IND_SIS_LCD_PANEL);
- reg = vgarb(CRTC_DATA);
- // Eden Chen
- switch (reg) {
- case SIS_LCD_PANEL_800X600:
- sishw_ext.ulCRT2LCDType = LCD_800x600;
- break;
- case SIS_LCD_PANEL_1024X768:
- sishw_ext.ulCRT2LCDType = LCD_1024x768;
- break;
- case SIS_LCD_PANEL_1280X1024:
- sishw_ext.ulCRT2LCDType = LCD_1280x1024;
- break;
- case SIS_LCD_PANEL_640X480:
- sishw_ext.ulCRT2LCDType = LCD_640x480;
- break;
- case SIS_LCD_PANEL_1280X960:
- sishw_ext.ulCRT2LCDType = LCD_1280x960;
- break;
- case SIS_LCD_PANEL_1600x1200: /* TW */
- sishw_ext.ulCRT2LCDType = LCD_1600x1200;
- break;
- case SIS_LCD_PANEL_320x480: /* TW: FSTN */
- sishw_ext.ulCRT2LCDType = LCD_320x480;
- break;
- default:
- sishw_ext.ulCRT2LCDType = LCD_1024x768;
- break;
+ if (!enable_dstn) {
+ inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
+ reg &= 0x0f;
+ if (sisvga_engine == SIS_300_VGA) {
+ sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+ } else {
+ sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
}
- // ~Eden Chen
+ } else {
+ /* TW: FSTN/DSTN */
+ sishw_ext.ulCRT2LCDType = LCD_320x480;
+ }
}
if (sisfb_mode_idx >= 0)
- sisfb_validate_mode();
+ sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
if (sisfb_mode_idx < 0) {
switch (ivideo.disp_state & DISPTYPE_DISP2) {
@@ -3216,195 +3684,404 @@
ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
ivideo.org_x = ivideo.org_y = 0;
- video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+ ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+ switch(ivideo.video_bpp) {
+ case 8:
+ ivideo.DstColor = 0x0000;
+ ivideo.SiS310_AccelDepth = 0x00000000;
+ ivideo.video_cmap_len = 256;
+ break;
+ case 16:
+ ivideo.DstColor = 0x8000;
+ ivideo.SiS310_AccelDepth = 0x00010000;
+ ivideo.video_cmap_len = 16;
+ break;
+ case 32:
+ ivideo.DstColor = 0xC000;
+ ivideo.SiS310_AccelDepth = 0x00020000;
+ ivideo.video_cmap_len = 16;
+ break;
+ default:
+ ivideo.video_cmap_len = 16;
+ printk(KERN_INFO "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+ sisfb_accel = 0;
+ break;
+ }
- printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz), linelength=%d\n",
+ printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
- ivideo.refresh_rate, video_linelength);
-
- // Eden Chen
- // Check interface correction For Debug
- DPRINTK("VM Adr=0x%p\n", sishw_ext.pjVideoMemoryAddress);
- DPRINTK("VM Size=%ldK\n", sishw_ext.ulVideoMemorySize/1024);
- DPRINTK("IO Adr=0x%lx\n", sishw_ext.ulIOAddress);
- DPRINTK("Chip=%d\n", sishw_ext.jChipType);
- DPRINTK("ChipRevision=%d\n", sishw_ext.jChipRevision);
- DPRINTK("VBChip=%d\n", sishw_ext.ujVBChipID);
- DPRINTK("ExtVB=%d\n", sishw_ext.usExternalChip);
- DPRINTK("LCD=%ld\n", sishw_ext.ulCRT2LCDType);
- DPRINTK("bIntegratedMMEnabled=%d\n", sishw_ext.bIntegratedMMEnabled);
- // ~Eden Chen
+ ivideo.refresh_rate);
sisfb_pre_setmode();
- if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
- DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no);
+ if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+ printk("sisfb: Setting mode[0x%x] failed, using default mode\n", sisfb_mode_no);
return -1;
}
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
+ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
sisfb_post_setmode();
sisfb_crtc_to_var(&default_var);
- fb_info.changevar = NULL;
+ if(sisfb_accel) {
+ sisfb_initaccel();
+ }
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) /* ---- 2.4 series init ---- */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+ sis_fb_info.screen_base = ivideo.video_vbase;
+ sis_fb_info.currcon = -1;
+#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- fb_info.node = -1;
+ sis_fb_info.node = -1;
#else
- fb_info.node = NODEV;
+ sis_fb_info.node = NODEV;
+#endif
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
+ sis_fb_info.blank = &sisfb_blank;
#endif
- fb_info.fbops = &sisfb_ops;
- fb_info.disp = &disp;
- fb_info.switch_con = &sisfb_switch;
- fb_info.updatevar = &sisfb_update_var;
- fb_info.blank = &sisfb_blank;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
+ sis_fb_info.fbops = &sisfb_ops;
+ sis_fb_info.switch_con = &sisfb_switch;
+ sis_fb_info.updatevar = &sisfb_update_var;
+ sis_fb_info.changevar = NULL;
+ sis_fb_info.disp = &sis_disp;
+ sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
- sisfb_set_disp(-1, &default_var);
+ sisfb_set_disp(-1, &default_var, &sis_fb_info);
+#endif
- } /* TW: if mode = "none" */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) /* ---- 2.5 series init ---- */
+ sis_fb_info.screen_base = ivideo.video_vbase;
+ sis_fb_info.node = NODEV;
+ sis_fb_info.fbops = &sisfb_ops;
+ sisfb_get_fix(&sis_fb_info.fix, -1, &sis_fb_info);
+ sis_fb_info.pseudo_palette = pseudo_palette;
+ sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ sis_fb_info.changevar = NULL;
+ sis_fb_info.currcon = -1;
+ sis_fb_info.disp = &sis_disp;
+ sis_fb_info.switch_con = gen_switch;
+ sis_fb_info.updatevar = gen_update_var;
- if (sisfb_heap_init()) {
- printk("sisfb: Failed to initialize offscreen memory heap\n");
- }
+ fb_alloc_cmap(&sis_fb_info.cmap, 256, 0);
- ivideo.mtrr = (unsigned int) 0;
- if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { /* TW: for mode "none" */
- /*H.C.*/
+ sis_fb_info.var = default_var;
+#endif
+
+#ifdef CONFIG_MTRR
ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
(unsigned int) ivideo.video_size,
MTRR_TYPE_WRCOMB, 1);
- /*
- if (ivideo.mtrr >= 0) {
- printk(KERN_INFO "Succeed to turn on Write-Combining on VideoMemory %08XH, Size: %08XH\n",
- ivideo.video_base, ivideo.video_size);
- } else {
- printk(KERN_INFO "Fail to turn on Write-Combining on Video Memory 0x%08X, Size: 0x%08X\n",
- ivideo.video_base, ivideo.video_size);
- }
- */
- vc_resize_con(1, 1, 0);
+ if(ivideo.mtrr) {
+ printk(KERN_INFO "sisfb: Added MTRRs\n");
+ }
+#endif
- if (register_framebuffer(&fb_info) < 0)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+ vc_resize_con(1, 1, 0);
+#endif
+ TWDEBUG("Before calling register_framebuffer");
+ if(register_framebuffer(&sis_fb_info) < 0)
return -EINVAL;
+ printk(KERN_INFO "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+ printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
+ sisfb_accel ? "enabled" : "disabled",
+ sisfb_ypan ? "ypan" : "redraw");
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+ printk(KERN_INFO "sisfb: 2D acceleration is %s\n",
+ sisfb_accel ? "enabled" : "disabled");
+#endif
+
printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
- GET_FB_IDX(fb_info.node), fb_info.modename, VER_MAJOR, VER_MINOR,
+ GET_FB_IDX(sis_fb_info.node), sis_fb_info.modename, VER_MAJOR, VER_MINOR,
VER_LEVEL);
+
} /* TW: if mode = "none" */
return 0;
}
+/* ------------------------------------------------------------------------------ */
+
+/* TW: As long as the generic framebuffer parts don't work as modules, we use
+ our own stuff here. I can't debug a fb driver if I need to compile the driver
+ into the kernel. It simply drives me nuts.
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#include <video/fbcon.h>
+
+void my_cfb_imageblit(struct fb_info *p, struct fb_image *image)
+{
+ int pad, ppw;
+ int x2, y2, n, i, j, k, l = 7;
+ unsigned long tmp = ~0 << (BITS_PER_LONG - p->var.bits_per_pixel);
+ unsigned long fgx, bgx, fgcolor, bgcolor, eorx;
+ unsigned long end_mask;
+ unsigned long *dst = NULL;
+ u8 *dst1;
+ u8 *src;
+
+ /*
+ * We could use hardware clipping but on many cards you get around hardware
+ * clipping by writing to framebuffer directly like we are doing here.
+ */
+ x2 = image->dx + image->width;
+ y2 = image->dy + image->height;
+ image->dx = image->dx > 0 ? image->dx : 0;
+ image->dy = image->dy > 0 ? image->dy : 0;
+ x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+ y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+ image->width = x2 - image->dx;
+ image->height = y2 - image->dy;
+
+ dst1 = p->screen_base + image->dy * p->fix.line_length +
+ ((image->dx * p->var.bits_per_pixel) >> 3);
+
+ ppw = BITS_PER_LONG/p->var.bits_per_pixel;
+
+ src = image->data;
+
+ if (image->depth == 1) {
+
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
+ fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
+ bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
+ } else {
+ fgx = fgcolor = image->fg_color;
+ bgx = bgcolor = image->bg_color;
+ }
+
+ for (i = 0; i < ppw-1; i++) {
+ fgx <<= p->var.bits_per_pixel;
+ bgx <<= p->var.bits_per_pixel;
+ fgx |= fgcolor;
+ bgx |= bgcolor;
+ }
+ eorx = fgx ^ bgx;
+ n = ((image->width + 7) >> 3);
+ pad = (n << 3) - image->width;
+ n = image->width % ppw;
+
+ for (i = 0; i < image->height; i++) {
+ dst = (unsigned long *) dst1;
+
+ for (j = image->width/ppw; j > 0; j--) {
+ end_mask = 0;
+
+ for (k = ppw; k > 0; k--) {
+ if (test_bit(l, (unsigned long *) src))
+ end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+ l--;
+ if (l < 0) { l = 7; src++; }
+ }
+ fb_writel((end_mask & eorx)^bgx, dst);
+ dst++;
+ }
+
+ if (n) {
+ end_mask = 0;
+ for (j = n; j > 0; j--) {
+ if (test_bit(l, (unsigned long *) src))
+ end_mask |= (tmp >> (p->var.bits_per_pixel*(j-1)));
+ l--;
+ if (l < 0) { l = 7; src++; }
+ }
+ fb_writel((end_mask & eorx)^bgx, dst);
+ dst++;
+ }
+ l -= pad;
+ dst1 += p->fix.line_length;
+ }
+ } else {
+ /* Draw the penguin */
+ n = ((image->width * p->var.bits_per_pixel) >> 3);
+ end_mask = 0;
+ }
+}
+#endif
+/* -------------------------------------------------------------------------------- */
+
+
#ifdef MODULE
-static char *mode = NULL;
+static char *mode = NULL;
+static int vesa = -1;
static unsigned int rate = 0;
static unsigned int crt1off = 1;
static unsigned int mem = 0;
static unsigned int dstn = 0;
-static char *forcecrt2type = NULL;
-static int forcecrt1 = -1;
-static char *queuemode = NULL;
+static char *forcecrt2type = NULL;
+static int forcecrt1 = -1;
+static char *queuemode = NULL;
+static int pdc = 0;
+static int noaccel = -1;
+static int noypan = -1;
+static int inverse = 0;
MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740 framebuffer driver");
-MODULE_LICENSE("GPL"); /* TW (Code is officially open says SiS) */
-MODULE_AUTHOR("Various; SiS; Some parts by Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Various; SiS; Thomas Winischhofer <thomas@winischhofer.net>");
MODULE_PARM(mode, "s");
MODULE_PARM_DESC(mode,
- "Selects the desired display mode in the format [X]x[Y]x[Depth], eg. 800x600x16 "
- "(default: none; this leaves the console untouched and the driver will only do "
- "the video memory management for eg. DRM/DRI)");
+ "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+ "800x600x16 (default: none if sisfb is a module; this leaves the\n"
+ "console untouched and the driver will only do the video memory\n"
+ "management for eg. DRM/DRI; 800x600x8 if sisfb is in the kernel)");
+
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa,
+ "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+ "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+ "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+ "0x0103 if sisfb is in the kernel)");
MODULE_PARM(rate, "i");
MODULE_PARM_DESC(rate,
- "Selects the desired vertical refresh rate for CRT1 (external VGA) in Hz. "
+ "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
"(default: 60)");
MODULE_PARM(crt1off, "i");
MODULE_PARM_DESC(crt1off,
- "If this option is set, the driver will switch off CRT1 (external VGA). "
"(Deprecated, please use forcecrt1)");
MODULE_PARM(filter, "i");
MODULE_PARM_DESC(filter,
- "Selects TV flicker filter type (only for SiS30x video bridges). "
- "(Possible values 0-7, default: [no filter])");
+ "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+ "(Possible values 0-7, default: [no filter])");
MODULE_PARM(dstn, "i"); /* JennyLee 20011211 */
MODULE_PARM_DESC(dstn,
- "Selects DSTN display mode (1=ON, 0=OFF) (default: 0)");
+ "\nSelects DSTN/FSTN display mode for SiS550. This sets CRT2 type to LCD and\n"
+ "overrides forcecrt2type setting. (1=ON, 0=OFF) (default: 0)");
MODULE_PARM(queuemode, "s");
MODULE_PARM_DESC(queuemode,
- "Selects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM "
- "or MMIO. AGP is only available if the kernel has AGP support. "
- "The queue mode is important to programs using the 2D/3D accelerator of "
- "the SiS chip. The modes require a totally different way of programming "
- "the engines. On 300/540/630/730, this option is ignored. (default: MMIO)");
+ "\nSelects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM or\n"
+ "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
+ "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
+ "require a totally different way of programming the engines. If any mode than\n"
+ "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
+ "300/540/630/730, this option is ignored. (default: MMIO)");
/* TW: "Import" the options from the X driver */
MODULE_PARM(mem, "i");
MODULE_PARM_DESC(mem,
- "Determines the beginning of the video memory heap in KB. This heap is used for "
- "video RAM management for eg. DRM/DRI. The default depends on the amount of video "
- "memory available. If 8MB of video RAM or less is available, "
- "the heap starts at 4096KB, otherwise at 8192KB. The value is to be specified "
- "without 'KB' and should match MaxXFBMem setting for XFree 4.x (x>=2). "
- "See http://www.winischhofer.net/linuxsis630.shtml for a closer description.");
+ "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+ "for video RAM management for eg. DRM/DRI. The default depends on the amount\n"
+ "of video RAM available. If 8MB of video RAM or less is available, the heap\n"
+ "starts at 4096KB, if between 8 and 16MB are available at 8192KB, otherwise\n"
+ "at 12288KB. The value is to be specified without 'KB' and should match\n"
+ "the MaxXFBMem setting for XFree 4.x (x>=2).");
MODULE_PARM(forcecrt2type, "s");
MODULE_PARM_DESC(forcecrt2type,
- "If this option is omitted, the driver autodetects CRT2 output devices, such as LCD, "
- "TV or secondary VGA (in this order; so if eg. an LCD is there, it will be used regardless "
- "of a connected TV set). With this option, this autodetection can be overridden. "
- "Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2 and makes it "
- "possible to use higher resolutions on CRT1 than eg. your LCD panel supports. TV "
- "selects TV output (only resolutions 640x480 and 800x600 are supported for TV!). "
- "VGA refers to _secondary_ VGA which is unlikely to be available; the VGA plug found "
- "on most machines is CRT1. (default: [autodetected])");
+ "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
+ "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
+ "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
+ "On systems with a 301(B) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
+ "used instead of TV to override the TV detection. (default: [autodetected])");
MODULE_PARM(forcecrt1, "i");
MODULE_PARM_DESC(forcecrt1,
- "Normally, the driver autodetects whether or not CRT1 (external VGA) is connected. "
- "With this option, the detection can be overridden (1=CRT1 ON, 0=CRT1 off) "
- "(default: [autodetected])");
+ "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+ "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+ " 0=CRT1 off) (default: [autodetected])");
+
+MODULE_PARM(pdc, "i");
+MODULE_PARM_DESC(pdc,
+ "\n(300 series only) This is for manually selecting the LCD panel delay\n"
+ "compensation. The driver should detect this correctly in most cases; however,\n"
+ "sometimes this is not possible. If you see 'small waves' on the LCD, try\n"
+ "setting this to 4, 32 or 24. If the problem persists, try other values\n"
+ "between 4 and 60 in steps of 4. (default: [autodetected])");
+
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel,
+ "\nIf set to anything other than 0, 2D acceleration and y-panning will be\n"
+ "disabled. (default: 0)");
+
+MODULE_PARM(noypan, "i");
+MODULE_PARM_DESC(noypan,
+ "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+ "will be performed by redrawing the screen. This required 2D acceleration, so\n"
+ "if the option noaccel is set, y-panning will be disabled. (default: 0)");
+
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse,
+ "\nSetting this to anything but 0 should invert the display colors, but this\n"
+ "does not seem to work. (default: 0)");
int init_module(void)
{
- if (mode)
+ if(mode)
sisfb_search_mode(mode);
- else /* TW: set mode=none if no mode parameter is given */
+ else if(vesa != -1)
+ sisfb_search_vesamode(vesa);
+ else /* TW: set mode=none if no mode is given - we do this only if we are a module */
sisfb_mode_idx = MODE_INDEX_NONE;
ivideo.refresh_rate = rate;
- if (forcecrt2type)
+ if(forcecrt2type)
sisfb_search_crt2type(forcecrt2type);
- if (crt1off == 0)
+ if(crt1off == 0)
sisfb_crt1off = 1;
else
sisfb_crt1off = 0;
sisfb_forcecrt1 = forcecrt1;
- if (forcecrt1 == 1)
+ if(forcecrt1 == 1)
sisfb_crt1off = 0;
- else if (forcecrt1 == 0)
+ else if(forcecrt1 == 0)
sisfb_crt1off = 1;
- if (mem)
- sisfb_mem = mem;
+ if(noaccel == 1) sisfb_accel = 0;
+ else if(noaccel == 0) sisfb_accel = 1;
+
+ if(noypan == 1) sisfb_ypan = 0;
+ else if(noypan == 0) sisfb_ypan = 1;
+
+ /* TW: Panning only with acceleration */
+ if(sisfb_accel == 0) sisfb_ypan = 0;
- enable_dstn = dstn; /* JennyLee 20011211 */
+ if(inverse) sisfb_inverse = 1;
- if (queuemode)
- sisfb_search_queuemode(queuemode);
+ if(mem) sisfb_mem = mem;
- sisfb_init();
+ enable_dstn = dstn;
+
+ /* TW: DSTN overrules forcecrt2type */
+ if (enable_dstn) sisfb_crt2type = DISPTYPE_LCD;
+
+ if (queuemode) sisfb_search_queuemode(queuemode);
+ /* TW: If other queuemode than MMIO, disable 2D accel any ypan */
+ if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+ sisfb_accel = 0;
+ sisfb_ypan = 0;
+ }
+
+ if(pdc) {
+ if(!(pdc & ~0x3c)) {
+ sisfb_pdc = pdc & 0x3c;
+ }
+ }
+
+ if(sisfb_init() < 0) return -ENODEV;
return 0;
}
@@ -3414,14 +4091,17 @@
/* TW: Release mem regions */
release_mem_region(ivideo.video_base, ivideo.video_size);
release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+#ifdef CONFIG_MTRR
/* TW: Release MTRR region */
- if (ivideo.mtrr) mtrr_del(ivideo.mtrr,
+ if(ivideo.mtrr) mtrr_del(ivideo.mtrr,
(unsigned int)ivideo.video_base,
(unsigned int)ivideo.video_size);
+#endif
/* Unregister the framebuffer */
- unregister_framebuffer(&fb_info);
+ unregister_framebuffer(&sis_fb_info);
printk(KERN_INFO "sisfb: Module unloaded\n");
}
+
#endif
EXPORT_SYMBOL(sis_malloc);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)