/drivers/video/sis/sis_main.c
C | 6893 lines | 5707 code | 912 blank | 274 comment | 1588 complexity | b7a04ec041fc4b313d8bc981fab44fb9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * SiS 300/540/630[S]/730[S],
- * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
- * XGI V3XT/V5/V8, Z7
- * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
- *
- * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the named License,
- * or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
- *
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
- *
- * Author of (practically wiped) code base:
- * SiS (www.sis.com)
- * Copyright (C) 1999 Silicon Integrated Systems, Inc.
- *
- * See http://www.winischhofer.net/ for more information and updates
- *
- * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
- * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/spinlock.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/screen_info.h>
- #include <linux/slab.h>
- #include <linux/fb.h>
- #include <linux/selection.h>
- #include <linux/ioport.h>
- #include <linux/init.h>
- #include <linux/pci.h>
- #include <linux/vmalloc.h>
- #include <linux/capability.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/uaccess.h>
- #include <asm/io.h>
- #ifdef CONFIG_MTRR
- #include <asm/mtrr.h>
- #endif
- #include "sis.h"
- #include "sis_main.h"
- #if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
- #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
- #warning sisfb will not work!
- #endif
- static void sisfb_handle_command(struct sis_video_info *ivideo,
- struct sisfb_cmd *sisfb_command);
- /* ------------------ Internal helper routines ----------------- */
- static void __init
- sisfb_setdefaultparms(void)
- {
- sisfb_off = 0;
- sisfb_parm_mem = 0;
- sisfb_accel = -1;
- sisfb_ypan = -1;
- sisfb_max = -1;
- sisfb_userom = -1;
- sisfb_useoem = -1;
- sisfb_mode_idx = -1;
- sisfb_parm_rate = -1;
- sisfb_crt1off = 0;
- sisfb_forcecrt1 = -1;
- sisfb_crt2type = -1;
- sisfb_crt2flags = 0;
- sisfb_pdc = 0xff;
- sisfb_pdca = 0xff;
- sisfb_scalelcd = -1;
- sisfb_specialtiming = CUT_NONE;
- sisfb_lvdshl = -1;
- sisfb_dstn = 0;
- sisfb_fstn = 0;
- sisfb_tvplug = -1;
- sisfb_tvstd = -1;
- sisfb_tvxposoffset = 0;
- sisfb_tvyposoffset = 0;
- sisfb_nocrt2rate = 0;
- #if !defined(__i386__) && !defined(__x86_64__)
- sisfb_resetcard = 0;
- sisfb_videoram = 0;
- #endif
- }
- /* ------------- Parameter parsing -------------- */
- static void __devinit
- sisfb_search_vesamode(unsigned int vesamode, bool quiet)
- {
- int i = 0, j = 0;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(vesamode == 0) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
- while(sisbios_mode[i++].mode_no[0] != 0) {
- if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
- (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
- if(sisfb_fstn) {
- if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
- sisbios_mode[i-1].mode_no[1] == 0x56 ||
- sisbios_mode[i-1].mode_no[1] == 0x53)
- continue;
- } else {
- if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
- sisbios_mode[i-1].mode_no[1] == 0x5b)
- continue;
- }
- sisfb_mode_idx = i - 1;
- j = 1;
- break;
- }
- }
- if((!j) && !quiet)
- printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
- }
- static void __devinit
- sisfb_search_mode(char *name, bool quiet)
- {
- unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
- int i = 0;
- char strbuf[16], strbuf1[20];
- char *nameptr = name;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(name == NULL) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- if(strlen(name) <= 19) {
- strcpy(strbuf1, name);
- for(i = 0; i < strlen(strbuf1); i++) {
- if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
- }
- /* This does some fuzzy mode naming detection */
- if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
- if((rate <= 32) || (depth > 32)) {
- j = rate; rate = depth; depth = j;
- }
- sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
- nameptr = strbuf;
- sisfb_parm_rate = rate;
- } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
- sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
- nameptr = strbuf;
- } else {
- xres = 0;
- if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
- sprintf(strbuf, "%ux%ux8", xres, yres);
- nameptr = strbuf;
- } else {
- sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
- return;
- }
- }
- }
- i = 0; j = 0;
- while(sisbios_mode[i].mode_no[0] != 0) {
- if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
- if(sisfb_fstn) {
- if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
- sisbios_mode[i-1].mode_no[1] == 0x56 ||
- sisbios_mode[i-1].mode_no[1] == 0x53)
- continue;
- } else {
- if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
- sisbios_mode[i-1].mode_no[1] == 0x5b)
- continue;
- }
- sisfb_mode_idx = i - 1;
- j = 1;
- break;
- }
- }
- if((!j) && !quiet)
- printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
- }
- #ifndef MODULE
- static void __devinit
- sisfb_get_vga_mode_from_kernel(void)
- {
- #ifdef CONFIG_X86
- char mymode[32];
- int mydepth = screen_info.lfb_depth;
- if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
- if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
- (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
- (mydepth >= 8) && (mydepth <= 32) ) {
- if(mydepth == 24) mydepth = 32;
- sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
- screen_info.lfb_height,
- mydepth);
- printk(KERN_DEBUG
- "sisfb: Using vga mode %s pre-set by kernel as default\n",
- mymode);
- sisfb_search_mode(mymode, true);
- }
- #endif
- return;
- }
- #endif
- static void __init
- sisfb_search_crt2type(const char *name)
- {
- int i = 0;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(name == NULL) return;
- while(sis_crt2type[i].type_no != -1) {
- if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
- sisfb_crt2type = sis_crt2type[i].type_no;
- sisfb_tvplug = sis_crt2type[i].tvplug_no;
- sisfb_crt2flags = sis_crt2type[i].flags;
- break;
- }
- i++;
- }
- sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
- sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
- if(sisfb_crt2type < 0)
- printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
- }
- static void __init
- sisfb_search_tvstd(const char *name)
- {
- int i = 0;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(name == NULL)
- return;
- while(sis_tvtype[i].type_no != -1) {
- if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
- sisfb_tvstd = sis_tvtype[i].type_no;
- break;
- }
- i++;
- }
- }
- static void __init
- sisfb_search_specialtiming(const char *name)
- {
- int i = 0;
- bool found = false;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(name == NULL)
- return;
- if(!strnicmp(name, "none", 4)) {
- sisfb_specialtiming = CUT_FORCENONE;
- printk(KERN_DEBUG "sisfb: Special timing disabled\n");
- } else {
- while(mycustomttable[i].chipID != 0) {
- if(!strnicmp(name,mycustomttable[i].optionName,
- strlen(mycustomttable[i].optionName))) {
- sisfb_specialtiming = mycustomttable[i].SpecialID;
- found = true;
- printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
- mycustomttable[i].vendorName,
- mycustomttable[i].cardName,
- mycustomttable[i].optionName);
- break;
- }
- i++;
- }
- if(!found) {
- printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
- printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
- i = 0;
- while(mycustomttable[i].chipID != 0) {
- printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
- mycustomttable[i].optionName,
- mycustomttable[i].vendorName,
- mycustomttable[i].cardName);
- i++;
- }
- }
- }
- }
- /* ----------- Various detection routines ----------- */
- static void __devinit
- sisfb_detect_custom_timing(struct sis_video_info *ivideo)
- {
- unsigned char *biosver = NULL;
- unsigned char *biosdate = NULL;
- bool footprint;
- u32 chksum = 0;
- int i, j;
- if(ivideo->SiS_Pr.UseROM) {
- biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
- biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
- for(i = 0; i < 32768; i++)
- chksum += ivideo->SiS_Pr.VirtualRomBase[i];
- }
- i = 0;
- do {
- if( (mycustomttable[i].chipID == ivideo->chip) &&
- ((!strlen(mycustomttable[i].biosversion)) ||
- (ivideo->SiS_Pr.UseROM &&
- (!strncmp(mycustomttable[i].biosversion, biosver,
- strlen(mycustomttable[i].biosversion))))) &&
- ((!strlen(mycustomttable[i].biosdate)) ||
- (ivideo->SiS_Pr.UseROM &&
- (!strncmp(mycustomttable[i].biosdate, biosdate,
- strlen(mycustomttable[i].biosdate))))) &&
- ((!mycustomttable[i].bioschksum) ||
- (ivideo->SiS_Pr.UseROM &&
- (mycustomttable[i].bioschksum == chksum))) &&
- (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
- (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
- footprint = true;
- for(j = 0; j < 5; j++) {
- if(mycustomttable[i].biosFootprintAddr[j]) {
- if(ivideo->SiS_Pr.UseROM) {
- if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
- mycustomttable[i].biosFootprintData[j]) {
- footprint = false;
- }
- } else
- footprint = false;
- }
- }
- if(footprint) {
- ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
- printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
- mycustomttable[i].vendorName,
- mycustomttable[i].cardName);
- printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
- mycustomttable[i].optionName);
- break;
- }
- }
- i++;
- } while(mycustomttable[i].chipID);
- }
- static bool __devinit
- sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
- {
- int i, j, xres, yres, refresh, index;
- u32 emodes;
- if(buffer[0] != 0x00 || buffer[1] != 0xff ||
- buffer[2] != 0xff || buffer[3] != 0xff ||
- buffer[4] != 0xff || buffer[5] != 0xff ||
- buffer[6] != 0xff || buffer[7] != 0x00) {
- printk(KERN_DEBUG "sisfb: Bad EDID header\n");
- return false;
- }
- if(buffer[0x12] != 0x01) {
- printk(KERN_INFO "sisfb: EDID version %d not supported\n",
- buffer[0x12]);
- return false;
- }
- monitor->feature = buffer[0x18];
- if(!(buffer[0x14] & 0x80)) {
- if(!(buffer[0x14] & 0x08)) {
- printk(KERN_INFO
- "sisfb: WARNING: Monitor does not support separate syncs\n");
- }
- }
- if(buffer[0x13] >= 0x01) {
- /* EDID V1 rev 1 and 2: Search for monitor descriptor
- * to extract ranges
- */
- j = 0x36;
- for(i=0; i<4; i++) {
- if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
- buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
- buffer[j + 4] == 0x00) {
- monitor->hmin = buffer[j + 7];
- monitor->hmax = buffer[j + 8];
- monitor->vmin = buffer[j + 5];
- monitor->vmax = buffer[j + 6];
- monitor->dclockmax = buffer[j + 9] * 10 * 1000;
- monitor->datavalid = true;
- break;
- }
- j += 18;
- }
- }
- if(!monitor->datavalid) {
- /* Otherwise: Get a range from the list of supported
- * Estabished Timings. This is not entirely accurate,
- * because fixed frequency monitors are not supported
- * that way.
- */
- monitor->hmin = 65535; monitor->hmax = 0;
- monitor->vmin = 65535; monitor->vmax = 0;
- monitor->dclockmax = 0;
- emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
- for(i = 0; i < 13; i++) {
- if(emodes & sisfb_ddcsmodes[i].mask) {
- if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
- if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
- if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
- if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
- if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
- }
- }
- index = 0x26;
- for(i = 0; i < 8; i++) {
- xres = (buffer[index] + 31) * 8;
- switch(buffer[index + 1] & 0xc0) {
- case 0xc0: yres = (xres * 9) / 16; break;
- case 0x80: yres = (xres * 4) / 5; break;
- case 0x40: yres = (xres * 3) / 4; break;
- default: yres = xres; break;
- }
- refresh = (buffer[index + 1] & 0x3f) + 60;
- if((xres >= 640) && (yres >= 480)) {
- for(j = 0; j < 8; j++) {
- if((xres == sisfb_ddcfmodes[j].x) &&
- (yres == sisfb_ddcfmodes[j].y) &&
- (refresh == sisfb_ddcfmodes[j].v)) {
- if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
- if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
- if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
- if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
- if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
- }
- }
- }
- index += 2;
- }
- if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
- monitor->datavalid = true;
- }
- }
- return monitor->datavalid;
- }
- static void __devinit
- sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
- {
- unsigned short temp, i, realcrtno = crtno;
- unsigned char buffer[256];
- monitor->datavalid = false;
- if(crtno) {
- if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
- else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
- else return;
- }
- if((ivideo->sisfb_crt1off) && (!crtno))
- return;
- temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
- realcrtno, 0, &buffer[0], ivideo->vbflags2);
- if((!temp) || (temp == 0xffff)) {
- printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
- return;
- } else {
- printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
- printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
- crtno + 1,
- (temp & 0x1a) ? "" : "[none of the supported]",
- (temp & 0x02) ? "2 " : "",
- (temp & 0x08) ? "D&P" : "",
- (temp & 0x10) ? "FPDI-2" : "");
- if(temp & 0x02) {
- i = 3; /* Number of retrys */
- do {
- temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
- realcrtno, 1, &buffer[0], ivideo->vbflags2);
- } while((temp) && i--);
- if(!temp) {
- if(sisfb_interpret_edid(monitor, &buffer[0])) {
- printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
- monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
- monitor->dclockmax / 1000);
- } else {
- printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
- }
- } else {
- printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
- }
- } else {
- printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
- }
- }
- }
- /* -------------- Mode validation --------------- */
- static bool
- sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
- int mode_idx, int rate_idx, int rate)
- {
- int htotal, vtotal;
- unsigned int dclock, hsync;
- if(!monitor->datavalid)
- return true;
- if(mode_idx < 0)
- return false;
- /* Skip for 320x200, 320x240, 640x400 */
- switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
- case 0x59:
- case 0x41:
- case 0x4f:
- case 0x50:
- case 0x56:
- case 0x53:
- case 0x2f:
- case 0x5d:
- case 0x5e:
- return true;
- #ifdef CONFIG_FB_SIS_315
- case 0x5a:
- case 0x5b:
- if(ivideo->sisvga_engine == SIS_315_VGA) return true;
- #endif
- }
- if(rate < (monitor->vmin - 1))
- return false;
- if(rate > (monitor->vmax + 1))
- return false;
- if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
- sisbios_mode[mode_idx].mode_no[ivideo->mni],
- &htotal, &vtotal, rate_idx)) {
- dclock = (htotal * vtotal * rate) / 1000;
- if(dclock > (monitor->dclockmax + 1000))
- return false;
- hsync = dclock / htotal;
- if(hsync < (monitor->hmin - 1))
- return false;
- if(hsync > (monitor->hmax + 1))
- return false;
- } else {
- return false;
- }
- return true;
- }
- static int
- sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
- {
- u16 xres=0, yres, myres;
- #ifdef CONFIG_FB_SIS_300
- if(ivideo->sisvga_engine == SIS_300_VGA) {
- if(!(sisbios_mode[myindex].chipset & MD_SIS300))
- return -1 ;
- }
- #endif
- #ifdef CONFIG_FB_SIS_315
- if(ivideo->sisvga_engine == SIS_315_VGA) {
- if(!(sisbios_mode[myindex].chipset & MD_SIS315))
- return -1;
- }
- #endif
- myres = sisbios_mode[myindex].yres;
- switch(vbflags & VB_DISPTYPE_DISP2) {
- case CRT2_LCD:
- xres = ivideo->lcdxres; yres = ivideo->lcdyres;
- if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
- (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
- if(sisbios_mode[myindex].xres > xres)
- return -1;
- if(myres > yres)
- return -1;
- }
- if(ivideo->sisfb_fstn) {
- if(sisbios_mode[myindex].xres == 320) {
- if(myres == 240) {
- switch(sisbios_mode[myindex].mode_no[1]) {
- case 0x50: myindex = MODE_FSTN_8; break;
- case 0x56: myindex = MODE_FSTN_16; break;
- case 0x53: return -1;
- }
- }
- }
- }
- if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
- sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
- ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
- return -1;
- }
- break;
- case CRT2_TV:
- if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
- sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
- return -1;
- }
- break;
- case CRT2_VGA:
- if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
- sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
- return -1;
- }
- break;
- }
- return myindex;
- }
- static u8
- sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
- {
- int i = 0;
- u16 xres = sisbios_mode[mode_idx].xres;
- u16 yres = sisbios_mode[mode_idx].yres;
- ivideo->rate_idx = 0;
- while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
- if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
- if(sisfb_vrate[i].refresh == rate) {
- ivideo->rate_idx = sisfb_vrate[i].idx;
- break;
- } else if(sisfb_vrate[i].refresh > rate) {
- if((sisfb_vrate[i].refresh - rate) <= 3) {
- DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
- rate, sisfb_vrate[i].refresh);
- ivideo->rate_idx = sisfb_vrate[i].idx;
- ivideo->refresh_rate = sisfb_vrate[i].refresh;
- } else if((sisfb_vrate[i].idx != 1) &&
- ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
- DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
- rate, sisfb_vrate[i-1].refresh);
- ivideo->rate_idx = sisfb_vrate[i-1].idx;
- ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
- }
- break;
- } else if((rate - sisfb_vrate[i].refresh) <= 2) {
- DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
- rate, sisfb_vrate[i].refresh);
- ivideo->rate_idx = sisfb_vrate[i].idx;
- break;
- }
- }
- i++;
- }
- if(ivideo->rate_idx > 0) {
- return ivideo->rate_idx;
- } else {
- printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
- rate, xres, yres);
- return 0;
- }
- }
- static bool
- sisfb_bridgeisslave(struct sis_video_info *ivideo)
- {
- unsigned char P1_00;
- if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
- return false;
- P1_00 = SiS_GetReg(SISPART1, 0x00);
- if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
- ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
- return true;
- } else {
- return false;
- }
- }
- static bool
- sisfballowretracecrt1(struct sis_video_info *ivideo)
- {
- u8 temp;
- temp = SiS_GetReg(SISCR, 0x17);
- if(!(temp & 0x80))
- return false;
- temp = SiS_GetReg(SISSR, 0x1f);
- if(temp & 0xc0)
- return false;
- return true;
- }
- static bool
- sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
- {
- if(!sisfballowretracecrt1(ivideo))
- return false;
- if (SiS_GetRegByte(SISINPSTAT) & 0x08)
- return true;
- else
- return false;
- }
- static void
- sisfbwaitretracecrt1(struct sis_video_info *ivideo)
- {
- int watchdog;
- if(!sisfballowretracecrt1(ivideo))
- return;
- watchdog = 65536;
- while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
- watchdog = 65536;
- while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
- }
- static bool
- sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
- {
- unsigned char temp, reg;
- switch(ivideo->sisvga_engine) {
- case SIS_300_VGA: reg = 0x25; break;
- case SIS_315_VGA: reg = 0x30; break;
- default: return false;
- }
- temp = SiS_GetReg(SISPART1, reg);
- if(temp & 0x02)
- return true;
- else
- return false;
- }
- static bool
- sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
- {
- if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
- if(!sisfb_bridgeisslave(ivideo)) {
- return sisfbcheckvretracecrt2(ivideo);
- }
- }
- return sisfbcheckvretracecrt1(ivideo);
- }
- static u32
- sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
- {
- u8 idx, reg1, reg2, reg3, reg4;
- u32 ret = 0;
- (*vcount) = (*hcount) = 0;
- if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
- ret |= (FB_VBLANK_HAVE_VSYNC |
- FB_VBLANK_HAVE_HBLANK |
- FB_VBLANK_HAVE_VBLANK |
- FB_VBLANK_HAVE_VCOUNT |
- FB_VBLANK_HAVE_HCOUNT);
- switch(ivideo->sisvga_engine) {
- case SIS_300_VGA: idx = 0x25; break;
- default:
- case SIS_315_VGA: idx = 0x30; break;
- }
- reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
- reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
- reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
- reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
- if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
- if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
- if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
- (*vcount) = reg3 | ((reg4 & 0x70) << 4);
- (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
- } else if(sisfballowretracecrt1(ivideo)) {
- ret |= (FB_VBLANK_HAVE_VSYNC |
- FB_VBLANK_HAVE_VBLANK |
- FB_VBLANK_HAVE_VCOUNT |
- FB_VBLANK_HAVE_HCOUNT);
- reg1 = SiS_GetRegByte(SISINPSTAT);
- if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
- if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
- reg1 = SiS_GetReg(SISCR, 0x20);
- reg1 = SiS_GetReg(SISCR, 0x1b);
- reg2 = SiS_GetReg(SISCR, 0x1c);
- reg3 = SiS_GetReg(SISCR, 0x1d);
- (*vcount) = reg2 | ((reg3 & 0x07) << 8);
- (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
- }
- return ret;
- }
- static int
- sisfb_myblank(struct sis_video_info *ivideo, int blank)
- {
- u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
- bool backlight = true;
- switch(blank) {
- case FB_BLANK_UNBLANK: /* on */
- sr01 = 0x00;
- sr11 = 0x00;
- sr1f = 0x00;
- cr63 = 0x00;
- p2_0 = 0x20;
- p1_13 = 0x00;
- backlight = true;
- break;
- case FB_BLANK_NORMAL: /* blank */
- sr01 = 0x20;
- sr11 = 0x00;
- sr1f = 0x00;
- cr63 = 0x00;
- p2_0 = 0x20;
- p1_13 = 0x00;
- backlight = true;
- break;
- case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
- sr01 = 0x20;
- sr11 = 0x08;
- sr1f = 0x80;
- cr63 = 0x40;
- p2_0 = 0x40;
- p1_13 = 0x80;
- backlight = false;
- break;
- case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
- sr01 = 0x20;
- sr11 = 0x08;
- sr1f = 0x40;
- cr63 = 0x40;
- p2_0 = 0x80;
- p1_13 = 0x40;
- backlight = false;
- break;
- case FB_BLANK_POWERDOWN: /* off */
- sr01 = 0x20;
- sr11 = 0x08;
- sr1f = 0xc0;
- cr63 = 0x40;
- p2_0 = 0xc0;
- p1_13 = 0xc0;
- backlight = false;
- break;
- default:
- return 1;
- }
- if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
- if( (!ivideo->sisfb_thismonitor.datavalid) ||
- ((ivideo->sisfb_thismonitor.datavalid) &&
- (ivideo->sisfb_thismonitor.feature & 0xe0))) {
- if(ivideo->sisvga_engine == SIS_315_VGA) {
- SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
- }
- if(!(sisfb_bridgeisslave(ivideo))) {
- SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
- SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
- }
- }
- }
- if(ivideo->currentvbflags & CRT2_LCD) {
- if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
- if(backlight) {
- SiS_SiS30xBLOn(&ivideo->SiS_Pr);
- } else {
- SiS_SiS30xBLOff(&ivideo->SiS_Pr);
- }
- } else if(ivideo->sisvga_engine == SIS_315_VGA) {
- #ifdef CONFIG_FB_SIS_315
- if(ivideo->vbflags2 & VB2_CHRONTEL) {
- if(backlight) {
- SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
- } else {
- SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
- }
- }
- #endif
- }
- if(((ivideo->sisvga_engine == SIS_300_VGA) &&
- (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
- ((ivideo->sisvga_engine == SIS_315_VGA) &&
- ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
- SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
- }
- if(ivideo->sisvga_engine == SIS_300_VGA) {
- if((ivideo->vbflags2 & VB2_30xB) &&
- (!(ivideo->vbflags2 & VB2_30xBDH))) {
- SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
- }
- } else if(ivideo->sisvga_engine == SIS_315_VGA) {
- if((ivideo->vbflags2 & VB2_30xB) &&
- (!(ivideo->vbflags2 & VB2_30xBDH))) {
- SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
- }
- }
- } else if(ivideo->currentvbflags & CRT2_VGA) {
- if(ivideo->vbflags2 & VB2_30xB) {
- SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
- }
- }
- return 0;
- }
- /* ------------- Callbacks from init.c/init301.c -------------- */
- #ifdef CONFIG_FB_SIS_300
- unsigned int
- sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
- u32 val = 0;
- pci_read_config_dword(ivideo->nbridge, reg, &val);
- return (unsigned int)val;
- }
- void
- sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
- pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
- }
- unsigned int
- sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
- u32 val = 0;
- if(!ivideo->lpcdev) return 0;
- pci_read_config_dword(ivideo->lpcdev, reg, &val);
- return (unsigned int)val;
- }
- #endif
- #ifdef CONFIG_FB_SIS_315
- void
- sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
- pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
- }
- unsigned int
- sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
- u16 val = 0;
- if(!ivideo->lpcdev) return 0;
- pci_read_config_word(ivideo->lpcdev, reg, &val);
- return (unsigned int)val;
- }
- #endif
- /* ----------- FBDev related routines for all series ----------- */
- static int
- sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
- {
- return (var->bits_per_pixel == 8) ? 256 : 16;
- }
- static void
- sisfb_set_vparms(struct sis_video_info *ivideo)
- {
- 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 depth %d", ivideo->video_bpp);
- ivideo->accel = 0;
- }
- }
- static int
- sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
- {
- int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
- if(maxyres > 32767) maxyres = 32767;
- return maxyres;
- }
- static void
- sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
- {
- ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
- ivideo->scrnpitchCRT1 = ivideo->video_linelength;
- if(!(ivideo->currentvbflags & CRT1_LCDA)) {
- if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- ivideo->scrnpitchCRT1 <<= 1;
- }
- }
- }
- static void
- sisfb_set_pitch(struct sis_video_info *ivideo)
- {
- bool isslavemode = false;
- unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
- unsigned short HDisplay2 = ivideo->video_linelength >> 3;
- if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
- /* We need to set pitch for CRT1 if bridge is in slave mode, too */
- if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
- SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
- SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
- }
- /* We must not set the pitch for CRT2 if bridge is in slave mode */
- if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
- SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
- SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
- SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
- }
- }
- static void
- sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
- {
- ivideo->video_cmap_len = sisfb_get_cmap_len(var);
- switch(var->bits_per_pixel) {
- case 8:
- var->red.offset = var->green.offset = var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length = 8;
- 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;
- 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;
- break;
- }
- }
- static int
- sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
- {
- unsigned short modeno = ivideo->mode_no;
- /* >=2.6.12's fbcon clears the screen anyway */
- modeno |= 0x80;
- SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
- sisfb_pre_setmode(ivideo);
- if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
- printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
- return -EINVAL;
- }
- SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
- sisfb_post_setmode(ivideo);
- return 0;
- }
- static int
- sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- unsigned int htotal = 0, vtotal = 0;
- unsigned int drate = 0, hrate = 0;
- int found_mode = 0, ret;
- int old_mode;
- u32 pixclock;
- htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
- vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
- pixclock = var->pixclock;
- if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
- vtotal += var->yres;
- vtotal <<= 1;
- } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- vtotal += var->yres;
- vtotal <<= 2;
- } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- vtotal += var->yres;
- vtotal <<= 1;
- } else vtotal += var->yres;
- if(!(htotal) || !(vtotal)) {
- DPRINTK("sisfb: Invalid 'var' information\n");
- return -EINVAL;
- }
- if(pixclock && htotal && vtotal) {
- drate = 1000000000 / pixclock;
- hrate = (drate * 1000) / htotal;
- ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
- } else {
- ivideo->refresh_rate = 60;
- }
- old_mode = ivideo->sisfb_mode_idx;
- ivideo->sisfb_mode_idx = 0;
- while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
- (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
- if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
- (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
- (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
- ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
- found_mode = 1;
- break;
- }
- ivideo->sisfb_mode_idx++;
- }
- if(found_mode) {
- ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
- ivideo->sisfb_mode_idx, ivideo->currentvbflags);
- } else {
- ivideo->sisfb_mode_idx = -1;
- }
- if(ivideo->sisfb_mode_idx < 0) {
- printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
- var->yres, var->bits_per_pixel);
- ivideo->sisfb_mode_idx = old_mode;
- return -EINVAL;
- }
- ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
- if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
- ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
- ivideo->refresh_rate = 60;
- }
- if(isactive) {
- /* If acceleration to be used? Need to know
- * before pre/post_set_mode()
- */
- ivideo->accel = 0;
- #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
- #ifdef STUPID_ACCELF_TEXT_SHIT
- if(var->accel_flags & FB_ACCELF_TEXT) {
- info->flags &= ~FBINFO_HWACCEL_DISABLED;
- } else {
- info->flags |= FBINFO_HWACCEL_DISABLED;
- }
- #endif
- if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
- #else
- if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
- #endif
- if((ret = sisfb_set_mode(ivideo, 1))) {
- return ret;
- }
- ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
- ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
- ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
- sisfb_calc_pitch(ivideo, var);
- sisfb_set_pitch(ivideo);
- sisfb_set_vparms(ivideo);
- ivideo->current_width = ivideo->video_width;
- ivideo->current_height = ivideo->video_height;
- ivideo->current_bpp = ivideo->video_bpp;
- ivideo->current_htotal = htotal;
- ivideo->current_vtotal = vtotal;
- ivideo->current_linelength = ivideo->video_linelength;
- ivideo->current_pixclock = var->pixclock;
- ivideo->current_refresh_rate = ivideo->refresh_rate;
- ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
- }
- return 0;
- }
- static void
- sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
- {
- SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
- SiS_SetReg(SISCR, 0x0D, base & 0xFF);
- SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
- SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
- if(ivideo->sisvga_engine == SIS_315_VGA) {
- SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
- }
- }
- static void
- sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
- {
- if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
- SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
- SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
- SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
- SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
- if(ivideo->sisvga_engine == SIS_315_VGA) {
- SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
- }
- }
- }
- static int
- sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
- {
- if(var->xoffset > (var->xres_virtual - var->xres)) {
- return -EINVAL;
- }
- if(var->yoffset > (var->yres_virtual - var->yres)) {
- return -EINVAL;
- }
- ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
- /* calculate base bpp dep. */
- switch(var->bits_per_pixel) {
- case 32:
- break;
- case 16:
- ivideo->current_base >>= 1;
- break;
- case 8:
- default:
- ivideo->current_base >>= 2;
- break;
- }
- ivideo->current_base += (ivideo->video_offset >> 2);
- sisfb_set_base_CRT1(ivideo, ivideo->current_base);
- sisfb_set_base_CRT2(ivideo, ivideo->current_base);
- return 0;
- }
- static int
- sisfb_open(struct fb_info *info, int user)
- {
- return 0;
- }
- static int
- sisfb_release(struct fb_info *info, int user)
- {
- return 0;
- }
- static int
- sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
- unsigned transp, struct fb_info *info)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- if(regno >= sisfb_get_cmap_len(&info->var))
- return 1;
- switch(info->var.bits_per_pixel) {
- case 8:
- SiS_SetRegByte(SISDACA, regno);
- SiS_SetRegByte(SISDACD, (red >> 10));
- SiS_SetRegByte(SISDACD, (green >> 10));
- SiS_SetRegByte(SISDACD, (blue >> 10));
- if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
- SiS_SetRegByte(SISDAC2A, regno);
- SiS_SetRegByte(SISDAC2D, (red >> 8));
- SiS_SetRegByte(SISDAC2D, (green >> 8));
- SiS_SetRegByte(SISDAC2D, (blue >> 8));
- }
- break;
- case 16:
- if (regno >= 16)
- break;
- ((u32 *)(info->pseudo_palette))[regno] =
- (red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11);
- break;
- case 32:
- if (regno >= 16)
- break;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(info->pseudo_palette))[regno] =
- (red << 16) | (green << 8) | (blue);
- break;
- }
- return 0;
- }
- static int
- sisfb_set_par(struct fb_info *info)
- {
- int err;
- if((err = sisfb_do_set_var(&info->var, 1, info)))
- return err;
- sisfb_get_fix(&info->fix, -1, info);
- return 0;
- }
- static int
- sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
- unsigned int drate = 0, hrate = 0, maxyres;
- int found_mode = 0;
- int refresh_rate, search_idx, tidx;
- bool recalc_clock = false;
- u32 pixclock;
- htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
- vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
- pixclock = var->pixclock;
- if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
- vtotal += var->yres;
- vtotal <<= 1;
- } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- vtotal += var->yres;
- vtotal <<= 2;
- } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- vtotal += var->yres;
- vtotal <<= 1;
- } else
- vtotal += var->yres;
- if(!(htotal) || !(vtotal)) {
- SISFAIL("sisfb: no valid timing data");
- }
- search_idx = 0;
- while( (sisbios_mode[search_idx].mode_no[0] != 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)) {
- if((tidx = sisfb_validate_mode(ivideo, search_idx,
- ivideo->currentvbflags)) > 0) {
- found_mode = 1;
- search_idx = tidx;
- break;
- }
- }
- search_idx++;
- }
- if(!found_mode) {
- search_idx = 0;
- while(sisbios_mode[search_idx].mode_no[0] != 0) {
- if( (var->xres <= sisbios_mode[search_idx].xres) &&
- (var->yres <= sisbios_mode[search_idx].yres) &&
- (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
- if((tidx = sisfb_validate_mode(ivideo,search_idx,
- ivideo->currentvbflags)) > 0) {
- found_mode = 1;
- search_idx = tidx;
- break;
- }
- }
- search_idx++;
- }
- if(found_mode) {
- printk(KERN_DEBUG
- "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
- var->xres, var->yres, var->bits_per_pixel,
- sisbios_mode[search_idx].xres,
- sisbios_mode[search_idx].yres,
- var->bits_per_pixel);
- var->xres = sisbios_mode[search_idx].xres;
- var->yres = sisbios_mode[search_idx].yres;
- } else {
- printk(KERN_ERR
- "sisfb: Failed to find supported mode near %dx%dx%d\n",
- var->xres, var->yres, var->bits_per_pixel);
- return -EINVAL;
- }
- }
- if( ((ivideo->vbflags2 & VB2_LVDS) ||
- ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
- (var->bits_per_pixel == 8) ) {
- /* Slave modes on LVDS and 301B-DH */
- refresh_rate = 60;
- recalc_clock = true;
- } else if( (ivideo->current_htotal == htotal) &&
- (ivideo->current_vtotal == vtotal) &&
- (ivideo->current_pixclock == pixclock) ) {
- /* x=x & y=y & c=c -> assume depth change */
- drate = 1000000000 / pixclock;
- hrate = (drate * 1000) / htotal;
- refresh_rate = (unsigned int) (hrate * 2 / vtotal);
- } else if( ( (ivideo->current_htotal != htotal) ||
- (ivideo->current_vtotal != vtotal) ) &&
- (ivideo->current_pixclock == var->pixclock) ) {
- /* x!=x | y!=y & c=c -> invalid pixclock */
- if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
- refresh_rate =
- ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
- } else if(ivideo->sisfb_parm_rate != -1) {
- /* Sic, sisfb_parm_rate - want to know originally desired rate here */
- refresh_rate = ivideo->sisfb_parm_rate;
- } else {
- refresh_rate = 60;
- }
- recalc_clock = true;
- } else if((pixclock) && (htotal) && (vtotal)) {
- drate = 1000000000 / pixclock;
- hrate = (drate * 1000) / htotal;
- refresh_rate = (unsigned int) (hrate * 2 / vtotal);
- } else if(ivideo->current_refresh_rate) {
- refresh_rate = ivideo->current_refresh_rate;
- recalc_clock = true;
- } else {
- refresh_rate = 60;
- recalc_clock = true;
- }
- myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
- /* Eventually recalculate timing and clock */
- if(recalc_clock) {
- if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
- var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
- sisbios_mode[search_idx].mode_no[ivideo->mni],
- myrateindex));
- sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
- sisbios_mode[search_idx].mode_no[ivideo->mni],
- myrateindex, var);
- if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- var->pixclock <<= 1;
- }
- }
- if(ivideo->sisfb_thismonitor.datavalid) {
- if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
- myrateindex, refresh_rate)) {
- printk(KERN_INFO
- "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
- }
- }
- /* Adapt RGB settings */
- sisfb_bpp_to_var(ivideo, var);
- /* Sanity check for offsets */
- if(var->xoffset < 0) var->xoffset = 0;
- if(var->yoffset < 0) var->yoffset = 0;
- if(var->xres > var->xres_virtual)
- var->xres_virtual = var->xres;
- if(ivideo->sisfb_ypan) {
- maxyres = sisfb_calc_maxyres(ivideo, var);
- if(ivideo->sisfb_max) {
- var->yres_virtual = maxyres;
- } else {
- if(var->yres_virtual > maxyres) {
- var->yres_virtual = maxyres;
- }
- }
- if(var->yres_virtual <= var->yres) {
- var->yres_virtual = var->yres;
- }
- } else {
- if(var->yres != var->yres_virtual) {
- var->yres_virtual = var->yres;
- }
- var->xoffset = 0;
- var->yoffset = 0;
- }
- /* Truncate offsets to maximum if too high */
- if(var->xoffset > var->xres_virtual - var->xres) {
- var->xoffset = var->xres_virtual - var->xres - 1;
- }
- if(var->yoffset > var->yres_virtual - var->yres) {
- var->yoffset = var->yres_virtual - var->yres - 1;
- }
- /* Set everything else to 0 */
- var->red.msb_right =
- var->green.msb_right =
- var->blue.msb_right =
- var->transp.offset =
- var->transp.length =
- var->transp.msb_right = 0;
- return 0;
- }
- static int
- sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- int err;
- if(var->xoffset > (var->xres_virtual - var->xres))
- return -EINVAL;
- if(var->yoffset > (var->yres_virtual - var->yres))
- return -EINVAL;
- if(var->vmode & FB_VMODE_YWRAP)
- return -EINVAL;
- if(var->xoffset + info->var.xres > info->var.xres_virtual ||
- var->yoffset + info->var.yres > info->var.yres_virtual)
- return -EINVAL;
- if((err = sisfb_pan_var(ivideo, var)) < 0)
- return err;
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
- return 0;
- }
- static int
- sisfb_blank(int blank, struct fb_info *info)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- return sisfb_myblank(ivideo, blank);
- }
- /* ----------- FBDev related routines for all series ---------- */
- static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
- {
- struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
- struct sis_memreq sismemreq;
- struct fb_vblank sisvbblank;
- u32 gpu32 = 0;
- #ifndef __user
- #define __user
- #endif
- u32 __user *argp = (u32 __user *)arg;
- switch(cmd) {
- case FBIO_ALLOC:
- if(!capable(CAP_SYS_RAWIO))
- return -EPERM;
- if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
- return -EFAULT;
- sis_malloc(&sismemreq);
- if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
- sis_free((u32)sismemreq.offset);
- return -EFAULT;
- }
- break;
- case FBIO_FREE:
- if(!capable(CAP_SYS_RAWIO))
- return -EPERM;
- if(get_user(gpu32, argp))
- return -EFAULT;
- sis_free(gpu32);
- break;
- case FBIOGET_VBLANK:
- memset(&sisvbblank, 0, sizeof(struct fb_vblank));
- sisvbblank.count = 0;
- sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
- if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
- return -EFAULT;
- break;
- case SISFB_GET_INFO_SIZE:
- return put_user(sizeof(struct sisfb_info), argp);
- case SISFB_GET_INFO_OLD:
- if(ivideo->warncount++ < 10)
- printk(KERN_INFO
- "sisfb: Deprecated ioctl call received - update your application!\n");
- case SISFB_GET_INFO: /* For communication with X driver */
- ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
- ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
- ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
- ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
- ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
- ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
- ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
- ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
- if(ivideo->modechanged) {
- ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
- } else {
- ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
- }
- ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
- ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
- ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
- ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
- ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
- ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
- ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
- ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
- ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
- ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
- ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
- ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
- ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
- ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
- ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
- ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
- ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
- ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
- ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
- ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
- ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
- ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
- ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
- ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
- ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
- ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
- ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
- ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
- if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
- sizeof(ivideo->sisfb_infoblock)))
- return -EFAULT;
- break;
- case SISFB_GET_VBRSTATUS_OLD:
- if(ivideo->warncount++ < 10)
- printk(KERN_INFO
- "sisfb: Deprecated ioctl call received - update your application!\n");
- case SISFB_GET_VBRSTATUS:
- if(sisfb_CheckVBRetrace(ivideo))
- return put_user((u32)1, argp);
- else
- return put_user((u32)0, argp);
- case SISFB_GET_AUTOMAXIMIZE_OLD:
- if(ivideo->warncount++ < 10)
- printk(KERN_INFO
- "sisfb: Deprecated ioctl call received - update your application!\n");
- case SISFB_GET_AUTOMAXIMIZE:
- if(ivideo->sisfb_max)
- return put_user((u32)1, argp);
- else
- return put_user((u32)0, argp);
- case SISFB_SET_AUTOMAXIMIZE_OLD:
- if(ivideo->warncount++ < 10)
- printk(KERN_INFO
- "sisfb: Deprecated ioctl call received - update your application!\n");
- case SISFB_SET_AUTOMAXIMIZE:
- if(get_user(gpu32, argp))
- return -EFAULT;
- ivideo->sisfb_max = (gpu32) ? 1 : 0;
- break;
- case SISFB_SET_TVPOSOFFSET:
- if(get_user(gpu32, argp))
- return -EFAULT;
- sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
- sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
- break;
- case SISFB_GET_TVPOSOFFSET:
- return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
- argp);
- case SISFB_COMMAND:
- if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
- sizeof(struct sisfb_cmd)))
- return -EFAULT;
- sisfb_handle_command(ivideo, &ivideo->sisfb_command);
- if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
- sizeof(struct sisfb_cmd)))
- return -EFAULT;
- break;
- case SISFB_SET_LOCK:
- if(get_user(gp…
Large files files are truncated, but you can click here to view the full file