Mercurial > mplayer.hg
changeset 11038:3bac281db5a1
SiS 650/651/740/etc driver by Jake Page <jake@CS.Stanford.EDU>
author | alex |
---|---|
date | Tue, 07 Oct 2003 23:12:16 +0000 |
parents | 77ed12a4f0b1 |
children | 68945d785aca |
files | vidix/drivers/Makefile vidix/drivers/sis_bridge.c vidix/drivers/sis_defs.h vidix/drivers/sis_regs.h vidix/drivers/sis_vid.c |
diffstat | 5 files changed, 2919 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/vidix/drivers/Makefile Tue Oct 07 22:41:56 2003 +0000 +++ b/vidix/drivers/Makefile Tue Oct 07 23:12:16 2003 +0000 @@ -52,7 +52,13 @@ NVIDIA_LIBS=-L../../libdha -ldha -lm NVIDIA_CFLAGS=$(OPTFLAGS) -fPIC -I. -I.. -all: $(CYBERBLADE_VID) $(RADEON_VID) $(RAGE128_VID) $(MACH64_VID) $(NVIDIA_VID) $(GENFB_VID) $(MGA_VID) $(MGA_CRTC2_VID) $(PM3_VID) +SIS_VID=sis_vid.so +SIS_SRCS=sis_vid.c sis_bridge.c +SIS_OBJS=sis_vid.o sis_bridge.o +SIS_LIBS=-L../../libdha -ldha +SIS_CFLAGS=$(OPTFLAGS) -fPIC -I. -I.. + +all: $(CYBERBLADE_VID) $(RADEON_VID) $(RAGE128_VID) $(MACH64_VID) $(NVIDIA_VID) $(GENFB_VID) $(MGA_VID) $(MGA_CRTC2_VID) $(PM3_VID) $(SIS_VID) .SUFFIXES: .c .o @@ -113,6 +119,12 @@ $(MGA_CRTC2_VID): $(MGA_CRTC2_OBJS) $(CC) -shared $(MGA_CRTC2_OBJS) $(MGA_CRTC2_LIBS) -Wl,-soname,$(MGA_CRTC2_VID) -o $(MGA_CRTC2_VID) +$(SIS_OBJS): $(SIS_SRCS) + $(CC) -c $(SIS_CFLAGS) -o $@ $(basename $@).c + +$(SIS_VID): $(SIS_OBJS) + $(LD) -g $(SIS_LIBS) -shared -soname $(SIS_VID) -o $(SIS_VID) $(SIS_OBJS) + clean: rm -f *.o *.so *~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidix/drivers/sis_bridge.c Tue Oct 07 23:12:16 2003 +0000 @@ -0,0 +1,827 @@ +/** + Video bridge detection for SiS 300 and 310/325 series chips. + + Copyright 2003 Jake Page, Sugar Media. + + Based on SiS Xv driver: + Copyright 2002-2003 by 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 License, or + (at your option) 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 + +**/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#include "sis_regs.h" +#include "sis_defs.h" + + +static void sis_ddc2_delay(unsigned short delaytime) +{ + unsigned short i; + int temp; + + for (i = 0; i < delaytime; i++) { + inSISIDXREG(SISSR, 0x05, temp); + } +} + + +static int sis_do_sense(int tempbl, int tempbh, int tempcl, int tempch) +{ + int temp; + + outSISIDXREG(SISPART4, 0x11, tempbl); + temp = tempbh | tempcl; + setSISIDXREG(SISPART4, 0x10, 0xe0, temp); + //usleep(200000); + sis_ddc2_delay(0x1000); + tempch &= 0x7f; + inSISIDXREG(SISPART4, 0x03, temp); + temp ^= 0x0e; + temp &= tempch; + return (temp == tempch); +} + + +/* sense connected devices on 30x bridge */ +static void sis_sense_30x() +{ + unsigned char backupP4_0d, backupP2_00, biosflag; + unsigned char testsvhs_tempbl, testsvhs_tempbh; + unsigned char testsvhs_tempcl, testsvhs_tempch; + unsigned char testcvbs_tempbl, testcvbs_tempbh; + unsigned char testcvbs_tempcl, testcvbs_tempch; + unsigned char testvga2_tempbl, testvga2_tempbh; + unsigned char testvga2_tempcl, testvga2_tempch; + int myflag, result = 0, i, j, haveresult; + unsigned short temp; + + inSISIDXREG(SISPART4, 0x0d, backupP4_0d); + outSISIDXREG(SISPART4, 0x0d, (backupP4_0d | 0x04)); + + inSISIDXREG(SISPART2, 0x00, backupP2_00); + outSISIDXREG(SISPART2, 0x00, (backupP2_00 | 0x1c)); + + sis_do_sense(0, 0, 0, 0); + + if ((sis_vga_engine == SIS_315_VGA) || + (sis_device_id == DEVICE_SIS_300)) { +#if 0 + if (0 /*pSiS->sishw_ext.UseROM */ ) { + if (sis_vga_engine == SIS_300_VGA) + temp = 0xfe; + else { + temp = 0xf3; + if (sis_device_id == DEVICE_SIS_330) + temp = 0x11b; + } + if (pSiS->BIOS[temp] & 0x08) { + if (sis_verbose > 1) { + printf + ("[SiS] SiS30x: Video bridge has DVI-I TMDS/VGA combo connector\n"); + } + orSISIDXREG(SISCR, 0x32, 0x80); + } else { + andSISIDXREG(SISCR, 0x32, 0x7f); + } + } +#endif + } + + if (sis_vga_engine == SIS_300_VGA) { + if (0 /*pSiS->sishw_ext.UseROM */ ) { +#if 0 + testvga2_tempbh = pSiS->BIOS[0xf9]; + testvga2_tempbl = pSiS->BIOS[0xf8]; + testsvhs_tempbh = pSiS->BIOS[0xfb]; + testsvhs_tempbl = pSiS->BIOS[0xfa]; + testcvbs_tempbh = pSiS->BIOS[0xfd]; + testcvbs_tempbl = pSiS->BIOS[0xfc]; + biosflag = pSiS->BIOS[0xfe]; +#endif + } else { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0xd1; + testsvhs_tempbh = 0x00; + testsvhs_tempbl = 0xb9; + testcvbs_tempbh = 0x00; + testcvbs_tempbl = 0xb3; + biosflag = 0; + } + if (sis_vbflags & (VB_301B | VB_302B | VB_301LV | VB_302LV)) { + testvga2_tempbh = 0x01; + testvga2_tempbl = 0x90; + testsvhs_tempbh = 0x01; + testsvhs_tempbl = 0x6b; + testcvbs_tempbh = 0x01; + testcvbs_tempbl = 0x74; + } + inSISIDXREG(SISPART4, 0x01, myflag); + if (myflag & 0x04) { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0xfd; + testsvhs_tempbh = 0x00; + testsvhs_tempbl = 0xdd; + testcvbs_tempbh = 0x00; + testcvbs_tempbl = 0xee; + } + testvga2_tempch = 0x0e; + testvga2_tempcl = 0x08; + testsvhs_tempch = 0x06; + testsvhs_tempcl = 0x04; + testcvbs_tempch = 0x08; + testcvbs_tempcl = 0x04; + + if (sis_device_id == DEVICE_SIS_300) { + inSISIDXREG(SISSR, 0x3b, myflag); + if (!(myflag & 0x01)) { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0x00; + testvga2_tempch = 0x00; + testvga2_tempcl = 0x00; + } + } + } else { + if (0 /*pSiS->sishw_ext.UseROM */ ) { +#if 0 + if (sis_device_id == DEVICE_SIS_330) { + testvga2_tempbh = pSiS->BIOS[0xe6]; + testvga2_tempbl = pSiS->BIOS[0xe5]; + testsvhs_tempbh = pSiS->BIOS[0xe8]; + testsvhs_tempbl = pSiS->BIOS[0xe7]; + testcvbs_tempbh = pSiS->BIOS[0xea]; + testcvbs_tempbl = pSiS->BIOS[0xe9]; + biosflag = pSiS->BIOS[0x11b]; + } else { + testvga2_tempbh = pSiS->BIOS[0xbe]; + testvga2_tempbl = pSiS->BIOS[0xbd]; + testsvhs_tempbh = pSiS->BIOS[0xc0]; + testsvhs_tempbl = pSiS->BIOS[0xbf]; + testcvbs_tempbh = pSiS->BIOS[0xc2]; + testcvbs_tempbl = pSiS->BIOS[0xc1]; + biosflag = pSiS->BIOS[0xf3]; + } +#endif + } else { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0xd1; + testsvhs_tempbh = 0x00; + testsvhs_tempbl = 0xb9; + testcvbs_tempbh = 0x00; + testcvbs_tempbl = 0xb3; + biosflag = 0; + } + + if (sis_vbflags & (VB_301B | VB_302B | VB_301LV | VB_302LV)) { + if (0 /*pSiS->sishw_ext.UseROM */ ) { +#if 0 + if (sis_device_id == DEVICE_SIS_330) { + testvga2_tempbh = pSiS->BIOS[0xec]; + testvga2_tempbl = pSiS->BIOS[0xeb]; + testsvhs_tempbh = pSiS->BIOS[0xee]; + testsvhs_tempbl = pSiS->BIOS[0xed]; + testcvbs_tempbh = pSiS->BIOS[0xf0]; + testcvbs_tempbl = pSiS->BIOS[0xef]; + } else { + testvga2_tempbh = pSiS->BIOS[0xc4]; + testvga2_tempbl = pSiS->BIOS[0xc3]; + testsvhs_tempbh = pSiS->BIOS[0xc6]; + testsvhs_tempbl = pSiS->BIOS[0xc5]; + testcvbs_tempbh = pSiS->BIOS[0xc8]; + testcvbs_tempbl = pSiS->BIOS[0xc7]; + } +#endif + } else { + if (sis_vbflags & (VB_301B | VB_302B)) { + testvga2_tempbh = 0x01; + testvga2_tempbl = 0x90; + testsvhs_tempbh = 0x01; + testsvhs_tempbl = 0x6b; + testcvbs_tempbh = 0x01; + testcvbs_tempbl = 0x74; + } else { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0x00; + testsvhs_tempbh = 0x02; + testsvhs_tempbl = 0x00; + testcvbs_tempbh = 0x01; + testcvbs_tempbl = 0x00; + } + } + } + if (sis_vbflags & (VB_301 | VB_301B | VB_302B)) { + inSISIDXREG(SISPART4, 0x01, myflag); + if (myflag & 0x04) { + testvga2_tempbh = 0x00; + testvga2_tempbl = 0xfd; + testsvhs_tempbh = 0x00; + testsvhs_tempbl = 0xdd; + testcvbs_tempbh = 0x00; + testcvbs_tempbl = 0xee; + } + } + if (sis_vbflags & (VB_301LV | VB_302LV)) { + /* TW: No VGA2 or SCART on LV bridges */ + testvga2_tempbh = 0x00; + testvga2_tempbl = 0x00; + testvga2_tempch = 0x00; + testvga2_tempcl = 0x00; + testsvhs_tempch = 0x04; + testsvhs_tempcl = 0x08; + testcvbs_tempch = 0x08; + testcvbs_tempcl = 0x08; + } else { + testvga2_tempch = 0x0e; + testvga2_tempcl = 0x08; + testsvhs_tempch = 0x06; + testsvhs_tempcl = 0x04; + testcvbs_tempch = 0x08; + testcvbs_tempcl = 0x04; + } + } + + /* XXX: ?? andSISIDXREG(SISCR, 0x32, ~0x14); */ + /* pSiS->postVBCR32 &= ~0x14; */ + + /* scan for VGA2/SCART */ + if (testvga2_tempch || testvga2_tempcl || + testvga2_tempbh || testvga2_tempbl) { + + haveresult = 0; + for (j = 0; j < 10; j++) { + result = 0; + for (i = 0; i < 3; i++) { + if (sis_do_sense(testvga2_tempbl, testvga2_tempbh, + testvga2_tempcl, testvga2_tempch)) + result++; + } + if ((result == 0) || (result >= 2)) + break; + } + if (result) { + if (biosflag & 0x01) { + if (sis_verbose > 1) { + printf + ("[SiS] SiS30x: Detected TV connected to SCART output\n"); + } + sis_vbflags |= TV_SCART; + orSISIDXREG(SISCR, 0x32, 0x04); + /*pSiS->postVBCR32 |= 0x04; */ + } else { + if (sis_verbose > 1) { + printf + ("[SiS] SiS30x: Detected secondary VGA connection\n"); + } + sis_vbflags |= VGA2_CONNECTED; + orSISIDXREG(SISCR, 0x32, 0x10); + /*pSiS->postVBCR32 |= 0x10; */ + } + } + } + + /* scanning for TV */ + + /* XXX: ?? andSISIDXREG(SISCR, 0x32, ~0x03); */ + /* pSiS->postVBCR32 &= ~0x03; */ + + result = sis_do_sense(testsvhs_tempbl, testsvhs_tempbh, + testsvhs_tempcl, testsvhs_tempch); + + + haveresult = 0; + for (j = 0; j < 10; j++) { + result = 0; + for (i = 0; i < 3; i++) { + if (sis_do_sense(testsvhs_tempbl, testsvhs_tempbh, + testsvhs_tempcl, testsvhs_tempch)) + result++; + } + if ((result == 0) || (result >= 2)) + break; + } + if (result) { + if (sis_verbose > 1) { + printf + ("[SiS] SiS30x: Detected TV connected to SVIDEO output\n"); + } + /* TW: So we can be sure that there IS a SVIDEO output */ + sis_vbflags |= TV_SVIDEO; + orSISIDXREG(SISCR, 0x32, 0x02); + //pSiS->postVBCR32 |= 0x02; + } + + if ((biosflag & 0x02) || (!(result))) { + haveresult = 0; + for (j = 0; j < 10; j++) { + result = 0; + for (i = 0; i < 3; i++) { + if (sis_do_sense(testcvbs_tempbl, testcvbs_tempbh, + testcvbs_tempcl, testcvbs_tempch)) + result++; + } + if ((result == 0) || (result >= 2)) + break; + } + if (result) { + if (sis_verbose > 1) { + printf + ("[SiS] SiS30x: Detected TV connected to COMPOSITE output\n"); + } + sis_vbflags |= TV_AVIDEO; + orSISIDXREG(SISCR, 0x32, 0x01); + //pSiS->postVBCR32 |= 0x01; + } + } + + sis_do_sense(0, 0, 0, 0); + + outSISIDXREG(SISPART2, 0x00, backupP2_00); + outSISIDXREG(SISPART4, 0x0d, backupP4_0d); +} + + +static void sis_detect_crt1() +{ + unsigned char CR32; + unsigned char CRT1Detected = 0; + unsigned char OtherDevices = 0; + + if (!(sis_vbflags & VB_VIDEOBRIDGE)) { + sis_crt1_off = 0; + return; + } + + inSISIDXREG(SISCR, 0x32, CR32); + + if (CR32 & 0x20) + CRT1Detected = 1; + if (CR32 & 0x5F) + OtherDevices = 1; + + if (sis_crt1_off == -1) { + if (!CRT1Detected) { + /* BIOS detected no CRT1. */ + /* If other devices exist, switch it off */ + if (OtherDevices) + sis_crt1_off = 1; + else + sis_crt1_off = 0; + } else { + /* BIOS detected CRT1, leave/switch it on */ + sis_crt1_off = 0; + } + } + if (sis_verbose > 0) { + printf("[SiS] %sCRT1 connection detected\n", + sis_crt1_off ? "No " : ""); + } +} + + +static void sis_detect_lcd() +{ + unsigned char CR32, CR36, CR37; + + if (!(sis_vbflags & VB_VIDEOBRIDGE)) { + return; + } + + inSISIDXREG(SISCR, 0x32, CR32); + + if (CR32 & 0x08) + sis_vbflags |= CRT2_LCD; + + /* DDC detection of LCD - not supported yet */ + + /* Get other misc info about LCD - not supported */ +} + + +static void sis_detect_tv() +{ + unsigned char SR16, SR38, CR32, CR38 = 0, CR79; + int temp = 0; + + if (!(sis_vbflags & VB_VIDEOBRIDGE)) + return; + + inSISIDXREG(SISCR, 0x32, CR32); + inSISIDXREG(SISSR, 0x16, SR16); + inSISIDXREG(SISSR, 0x38, SR38); + switch (sis_vga_engine) { + case SIS_300_VGA: + if (sis_device_id == DEVICE_SIS_630_VGA) + temp = 0x35; + break; + case SIS_315_VGA: + temp = 0x38; + break; + } + if (temp) { + inSISIDXREG(SISCR, temp, CR38); + } + + if (CR32 & 0x47) + sis_vbflags |= CRT2_TV; + + if (CR32 & 0x04) + sis_vbflags |= TV_SCART; + else if (CR32 & 0x02) + sis_vbflags |= TV_SVIDEO; + else if (CR32 & 0x01) + sis_vbflags |= TV_AVIDEO; + else if (CR32 & 0x40) + sis_vbflags |= (TV_SVIDEO | TV_HIVISION); + else if ((CR38 & 0x04) && (sis_vbflags & (VB_301LV | VB_302LV))) + sis_vbflags |= TV_HIVISION_LV; + else if ((CR38 & 0x04) && (sis_vbflags & VB_CHRONTEL)) + sis_vbflags |= (TV_CHSCART | TV_PAL); + else if ((CR38 & 0x08) && (sis_vbflags & VB_CHRONTEL)) + sis_vbflags |= (TV_CHHDTV | TV_NTSC); + + if (sis_vbflags & (TV_SCART | TV_SVIDEO | TV_AVIDEO | TV_HIVISION)) { + if (sis_vga_engine == SIS_300_VGA) { + /* TW: Should be SR38 here as well, but this + * does not work. Looks like a BIOS bug (2.04.5c). + */ + if (SR16 & 0x20) + sis_vbflags |= TV_PAL; + else + sis_vbflags |= TV_NTSC; + } else if ((sis_device_id == DEVICE_SIS_550_VGA)) { + inSISIDXREG(SISCR, 0x79, CR79); + if (CR79 & 0x08) { + inSISIDXREG(SISCR, 0x79, CR79); + CR79 >>= 5; + } + if (CR79 & 0x01) { + sis_vbflags |= TV_PAL; + if (CR38 & 0x40) + sis_vbflags |= TV_PALM; + else if (CR38 & 0x80) + sis_vbflags |= TV_PALN; + } else + sis_vbflags |= TV_NTSC; + } else if ((sis_device_id == DEVICE_SIS_650_VGA)) { + inSISIDXREG(SISCR, 0x79, CR79); + if (CR79 & 0x20) { + sis_vbflags |= TV_PAL; + if (CR38 & 0x40) + sis_vbflags |= TV_PALM; + else if (CR38 & 0x80) + sis_vbflags |= TV_PALN; + } else + sis_vbflags |= TV_NTSC; + } else { /* 315, 330 */ + if (SR38 & 0x01) { + sis_vbflags |= TV_PAL; + if (CR38 & 0x40) + sis_vbflags |= TV_PALM; + else if (CR38 & 0x80) + sis_vbflags |= TV_PALN; + } else + sis_vbflags |= TV_NTSC; + } + } + + if (sis_vbflags & + (TV_SCART | TV_SVIDEO | TV_AVIDEO | TV_HIVISION | TV_CHSCART | + TV_CHHDTV)) { + if (sis_verbose > 0) { + printf("[SiS] %sTV standard %s\n", + (sis_vbflags & (TV_CHSCART | TV_CHHDTV)) ? "Using " : + "Detected default ", + (sis_vbflags & TV_NTSC) ? ((sis_vbflags & TV_CHHDTV) ? + "480i HDTV" : "NTSC") + : ((sis_vbflags & TV_PALM) ? "PALM" + : ((sis_vbflags & TV_PALN) ? "PALN" : "PAL"))); + } + } + +} + + +static void sis_detect_crt2() +{ + unsigned char CR32; + + if (!(sis_vbflags & VB_VIDEOBRIDGE)) + return; + + /* CRT2-VGA not supported on LVDS and 30xLV */ + if (sis_vbflags & (VB_LVDS | VB_301LV | VB_302LV)) + return; + + inSISIDXREG(SISCR, 0x32, CR32); + + if (CR32 & 0x10) + sis_vbflags |= CRT2_VGA; + +#if 0 + if (!(pSiS->nocrt2ddcdetection)) { + if (sis_vbflags & (VB_301B | VB_302B)) { + if (!(sis_vbflags & (CRT2_VGA | CRT2_LCD))) { + printf + ("[SiS] BIOS detected no secondary VGA, sensing via DDC\n"); + if (SiS_SenseVGA2DDC(pSiS->SiS_Pr, pSiS)) { + printf + ("[SiS] DDC error during secondary VGA detection\n"); + } else { + inSISIDXREG(SISCR, 0x32, CR32); + if (CR32 & 0x10) { + sis_vbflags |= CRT2_VGA; + /*pSiS->postVBCR32 |= 0x10; */ + printf + ("[SiS] Detected secondary VGA connection\n"); + } else { + printf + ("[SiS] No secondary VGA connection detected\n"); + } + } + } + } + } +#endif + +} + + +/* Preinit: detect video bridge and sense connected devs */ +static void sis_detect_video_bridge() +{ + int temp, temp1, temp2; + + + sis_vbflags = 0; + + if (sis_vga_engine != SIS_300_VGA && sis_vga_engine != SIS_315_VGA) + return; + + inSISIDXREG(SISPART4, 0x00, temp); + temp &= 0x0F; + if (temp == 1) { + inSISIDXREG(SISPART4, 0x01, temp1); + temp1 &= 0xff; + if (temp1 >= 0xE0) { + sis_vbflags |= VB_302LV; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_302LV; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS302LV video bridge (ID 1; Revision 0x%x)\n", + temp1); + } + + } else if (temp1 >= 0xD0) { + sis_vbflags |= VB_301LV; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_301LV; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS301LV video bridge (ID 1; Revision 0x%x)\n", + temp1); + } + } else if (temp1 >= 0xB0) { + sis_vbflags |= VB_301B; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_301B; + inSISIDXREG(SISPART4, 0x23, temp2); + if (!(temp2 & 0x02)) + sis_vbflags |= VB_30xBDH; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS301B%s video bridge (Revision 0x%x)\n", + (temp2 & 0x02) ? "" : " (DH)", temp1); + } + } else { + sis_vbflags |= VB_301; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_301; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS301 video bridge (Revision 0x%x)\n", + temp1); + } + } + + sis_sense_30x(); + + } else if (temp == 2) { + + inSISIDXREG(SISPART4, 0x01, temp1); + temp1 &= 0xff; + if (temp1 >= 0xE0) { + sis_vbflags |= VB_302LV; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_302LV; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS302LV video bridge (ID 2; Revision 0x%x)\n", + temp1); + } + } else if (temp1 >= 0xD0) { + sis_vbflags |= VB_301LV; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_301LV; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS301LV video bridge (ID 2; Revision 0x%x)\n", + temp1); + } + } else { + sis_vbflags |= VB_302B; + //pSiS->sishw_ext.ujVBChipID = VB_CHIP_302B; + inSISIDXREG(SISPART4, 0x23, temp2); + if (!(temp & 0x02)) + sis_vbflags |= VB_30xBDH; + if (sis_verbose > 1) { + printf + ("[SiS] Detected SiS302B%s video bridge (Revision 0x%x)\n", + (temp2 & 0x02) ? "" : " (DH)", temp1); + } + } + + sis_sense_30x(); + + } else if (temp == 3) { + if (sis_verbose > 1) { + printf("[SiS] Detected SiS303 video bridge - not supported\n"); + } + } else { + /* big scary mess of code to handle unknown or Chrontel LVDS */ + /* skipping it for now */ + if (sis_verbose > 1) { + printf + ("[SiS] Detected Chrontel video bridge - not supported\n"); + } + } + + /* this is probably not relevant to video overlay driver... */ + /* detects if brdige uses LCDA for low res text modes */ + if (sis_vga_engine == SIS_315_VGA) { + if (sis_vbflags & (VB_302B | VB_301LV | VB_302LV)) { +#if 0 + if (pSiS->sisfblcda != 0xff) { + if ((pSiS->sisfblcda & 0x03) == 0x03) { + //pSiS->SiS_Pr->SiS_UseLCDA = TRUE; + sis_vbflags |= VB_USELCDA; + } + } else +#endif + { + inSISIDXREG(SISCR, 0x34, temp); + if (temp <= 0x13) { + inSISIDXREG(SISCR, 0x38, temp); + if ((temp & 0x03) == 0x03) { + //pSiS->SiS_Pr->SiS_UseLCDA = TRUE; + sis_vbflags |= VB_USELCDA; + } else { + inSISIDXREG(SISCR, 0x30, temp); + if (temp & 0x20) { + inSISIDXREG(SISPART1, 0x13, temp); + if (temp & 0x40) { + //pSiS->SiS_Pr->SiS_UseLCDA = TRUE; + sis_vbflags |= VB_USELCDA; + } + } + } + } + } + if (sis_vbflags & VB_USELCDA) { + /* printf("Bridge uses LCDA for low resolution and text modes\n"); */ + } + } + } + + +} + + +/* detect video bridge type and sense connected devices */ +void sis_init_video_bridge() +{ + + sis_detect_video_bridge(); + + sis_detect_crt1(); + //sis_detect_lcd(); + sis_detect_tv(); + sis_detect_crt2(); + + sis_detected_crt2_devices = + sis_vbflags & (CRT2_LCD | CRT2_TV | CRT2_VGA); + + // force crt2 type + if (sis_force_crt2_type == CRT2_DEFAULT) { + if (sis_vbflags & CRT2_VGA) + sis_force_crt2_type = CRT2_VGA; + else if (sis_vbflags & CRT2_LCD) + sis_force_crt2_type = CRT2_LCD; + else if (sis_vbflags & CRT2_TV) + sis_force_crt2_type = CRT2_TV; + } + + switch (sis_force_crt2_type) { + case CRT2_TV: + sis_vbflags = sis_vbflags & ~(CRT2_LCD | CRT2_VGA); + if (sis_vbflags & VB_VIDEOBRIDGE) + sis_vbflags = sis_vbflags | CRT2_TV; + else + sis_vbflags = sis_vbflags & ~(CRT2_TV); + break; + case CRT2_LCD: + sis_vbflags = sis_vbflags & ~(CRT2_TV | CRT2_VGA); + if ((sis_vbflags & VB_VIDEOBRIDGE) /* XXX: && (pSiS->VBLCDFlags) */ + ) + sis_vbflags = sis_vbflags | CRT2_LCD; + else { + sis_vbflags = sis_vbflags & ~(CRT2_LCD); + if (sis_verbose > 0) { + printf + ("[SiS] Can't force CRT2 to LCD, no panel detected\n"); + } + } + break; + case CRT2_VGA: + if (sis_vbflags & VB_LVDS) { + if (sis_verbose > 0) { + printf("[SiS] LVDS does not support secondary VGA\n"); + } + break; + } + if (sis_vbflags & (VB_301LV | VB_302LV)) { + if (sis_verbose > 0) { + printf + ("[SiS] SiS30xLV bridge does not support secondary VGA\n"); + } + break; + } + sis_vbflags = sis_vbflags & ~(CRT2_TV | CRT2_LCD); + if (sis_vbflags & VB_VIDEOBRIDGE) + sis_vbflags = sis_vbflags | CRT2_VGA; + else + sis_vbflags = sis_vbflags & ~(CRT2_VGA); + break; + default: + sis_vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA); + } + + /* CRT2 gamma correction?? */ + + /* other force modes: */ + /* have a 'force tv type' (svideo, composite, scart) option? */ + /* have a 'force crt1 type' (to turn it off, etc??) */ + + /* TW: Check if CRT1 used (or needed; this eg. if no CRT2 detected) */ + if (sis_vbflags & VB_VIDEOBRIDGE) { + + /* TW: No CRT2 output? Then we NEED CRT1! + * We also need CRT1 if depth = 8 and bridge=LVDS|630+301B + */ + if ((!(sis_vbflags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) || ( /*(pScrn->bitsPerPixel == 8) && */ + ((sis_vbflags & (VB_LVDS | VB_CHRONTEL)) || ((sis_vga_engine == SIS_300_VGA) && (sis_vbflags & VB_301B))))) { + sis_crt1_off = 0; + } + /* TW: No CRT2 output? Then we can't use hw overlay on CRT2 */ + if (!(sis_vbflags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) + sis_overlay_on_crt1 = 1; + + } else { /* TW: no video bridge? */ + + /* Then we NEED CRT1... */ + sis_crt1_off = 0; + /* ... and can't use CRT2 for overlay output */ + sis_overlay_on_crt1 = 1; + } + + /* tvstandard options ? */ + + // determine using CRT1 or CRT2? + /* -> NO dualhead right now... */ + if (sis_vbflags & DISPTYPE_DISP2) { + if (sis_crt1_off) { + sis_vbflags |= VB_DISPMODE_SINGLE; + /* TW: No CRT1? Then we use the video overlay on CRT2 */ + sis_overlay_on_crt1 = 0; + } else /* TW: CRT1 and CRT2 - mirror or dual head ----- */ + sis_vbflags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1); + } else { /* TW: CRT1 only ------------------------------- */ + sis_vbflags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1); + } + + if (sis_verbose > 0) { + printf("[SiS] Using hardware overlay on CRT%d\n", + sis_overlay_on_crt1 ? 1 : 2); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidix/drivers/sis_defs.h Tue Oct 07 23:12:16 2003 +0000 @@ -0,0 +1,106 @@ +/** + SiS graphics misc definitions. + + Taken from SiS Xv driver: + Copyright 2002-2003 by 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 License, or + (at your option) 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 + +**/ + +#ifndef VIDIX_SIS_DEFS_H +#define VIDIX_SIS_DEFS_H + +/** PCI IDs **/ +#define VENDOR_SIS 0x1039 + +#define DEVICE_SIS_300 0x0300 +#define DEVICE_SIS_315H 0x0310 +#define DEVICE_SIS_315 0x0315 +#define DEVICE_SIS_315PRO 0x0325 +#define DEVICE_SIS_330 0x0330 +#define DEVICE_SIS_540 0x0540 +#define DEVICE_SIS_540_VGA 0x5300 +#define DEVICE_SIS_550 0x0550 +#define DEVICE_SIS_550_VGA 0x5315 +#define DEVICE_SIS_630 0x0630 +#define DEVICE_SIS_630_VGA 0x6300 +#define DEVICE_SIS_650 0x0650 +#define DEVICE_SIS_650_VGA 0x6325 +#define DEVICE_SIS_730 0x0730 + + +/* TW: VBFlags */ +#define CRT2_DEFAULT 0x00000001 +#define CRT2_LCD 0x00000002 /* TW: Never change the order of the CRT2_XXX entries */ +#define CRT2_TV 0x00000004 /* (see SISCycleCRT2Type()) */ +#define CRT2_VGA 0x00000008 +#define CRT2_ENABLE (CRT2_LCD | CRT2_TV | CRT2_VGA) +#define DISPTYPE_DISP2 CRT2_ENABLE +#define TV_NTSC 0x00000010 +#define TV_PAL 0x00000020 +#define TV_HIVISION 0x00000040 +#define TV_HIVISION_LV 0x00000080 +#define TV_TYPE (TV_NTSC | TV_PAL | TV_HIVISION | TV_HIVISION_LV) +#define TV_AVIDEO 0x00000100 +#define TV_SVIDEO 0x00000200 +#define TV_SCART 0x00000400 +#define TV_INTERFACE (TV_AVIDEO | TV_SVIDEO | TV_SCART | TV_CHSCART | TV_CHHDTV) +#define VB_USELCDA 0x00000800 +#define TV_PALM 0x00001000 +#define TV_PALN 0x00002000 +#define TV_CHSCART 0x00008000 +#define TV_CHHDTV 0x00010000 +#define VGA2_CONNECTED 0x00040000 +#define DISPTYPE_CRT1 0x00080000 /* TW: CRT1 connected and used */ +#define DISPTYPE_DISP1 DISPTYPE_CRT1 +#define VB_301 0x00100000 /* Video bridge type */ +#define VB_301B 0x00200000 +#define VB_302B 0x00400000 +#define VB_30xBDH 0x00800000 /* 30xB DH version (w/o LCD support) */ +#define VB_LVDS 0x01000000 +#define VB_CHRONTEL 0x02000000 +#define VB_301LV 0x04000000 +#define VB_302LV 0x08000000 +#define VB_30xLV VB_301LV +#define VB_30xLVX VB_302LV +#define VB_TRUMPION 0x10000000 +#define VB_VIDEOBRIDGE (VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV| \ + VB_LVDS|VB_CHRONTEL|VB_TRUMPION) /* TW */ +#define VB_SISBRIDGE (VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV) +#define SINGLE_MODE 0x20000000 /* TW: CRT1 or CRT2; determined by DISPTYPE_CRTx */ +#define VB_DISPMODE_SINGLE SINGLE_MODE /* TW: alias */ +#define MIRROR_MODE 0x40000000 /* TW: CRT1 + CRT2 identical (mirror mode) */ +#define VB_DISPMODE_MIRROR MIRROR_MODE /* TW: alias */ +#define DUALVIEW_MODE 0x80000000 /* TW: CRT1 + CRT2 independent (dual head mode) */ +#define VB_DISPMODE_DUAL DUALVIEW_MODE /* TW: alias */ +#define DISPLAY_MODE (SINGLE_MODE | MIRROR_MODE | DUALVIEW_MODE) /* TW */ + +/* SiS vga engine type */ +#define UNKNOWN_VGA 0 +#define SIS_300_VGA 1 +#define SIS_315_VGA 2 + +extern unsigned int sis_verbose; +extern unsigned short sis_iobase; +extern unsigned int sis_vga_engine; +extern unsigned int sis_vbflags; +extern unsigned int sis_overlay_on_crt1; +extern unsigned int sis_crt1_off; +extern unsigned int sis_detected_crt2_devices; +extern unsigned int sis_force_crt2_type; +extern unsigned int sis_device_id; + +#endif /* VIDIX_SIS_DEFS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidix/drivers/sis_regs.h Tue Oct 07 23:12:16 2003 +0000 @@ -0,0 +1,412 @@ +/** + SiS register definitions and access macros. + From SiS X11 driver. + + Copyright 2001-2003 by 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 License, or + (at your option) 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 + +**/ + +#ifndef VIDIX_SIS_REGS_H +#define VIDIX_SIS_REGS_H + +#define inSISREG(base) INPORT8(base) +#define outSISREG(base,val) OUTPORT8(base, val) +#define orSISREG(base,val) do { \ + unsigned char __Temp = INPORT8(base); \ + outSISREG(base, __Temp | (val)); \ + } while (0) +#define andSISREG(base,val) do { \ + unsigned char __Temp = INPORT8(base); \ + outSISREG(base, __Temp & (val)); \ + } while (0) + +#define inSISIDXREG(base,idx,var) do { \ + OUTPORT8(base, idx); var=INPORT8((base)+1); \ + } while (0) +#define outSISIDXREG(base,idx,val) do { \ + OUTPORT8(base, idx); OUTPORT8((base)+1, val); \ + } while (0) +#define orSISIDXREG(base,idx,val) do { \ + unsigned char __Temp; \ + OUTPORT8(base, idx); \ + __Temp = INPORT8((base)+1)|(val); \ + outSISIDXREG(base,idx,__Temp); \ + } while (0) +#define andSISIDXREG(base,idx,and) do { \ + unsigned char __Temp; \ + OUTPORT8(base, idx); \ + __Temp = INPORT8((base)+1)&(and); \ + outSISIDXREG(base,idx,__Temp); \ + } while (0) +#define setSISIDXREG(base,idx,and,or) do { \ + unsigned char __Temp; \ + OUTPORT8(base, idx); \ + __Temp = (INPORT8((base)+1)&(and))|(or); \ + outSISIDXREG(base,idx,__Temp); \ + } while (0) + +#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) +#define GENMASK(mask) BITMASK(1?mask,0?mask) + +#define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) +#define SETBITS(val,mask) ((val) << (0?mask)) +#define SETBIT(n) (1<<(n)) + +#define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) +#define SETVARBITS(var,val,from,to) (((var)&(~(GENMASK(to)))) | \ + GETBITSTR(val,from,to)) +#define GETVAR8(var) ((var)&0xFF) +#define SETVAR8(var,val) (var) = GETVAR8(val) + +/* #define VGA_RELIO_BASE 0x380 */ + +#define AROFFSET 0x40 /* VGA_ATTR_INDEX - VGA_RELIO_BASE */ +#define ARROFFSET 0x41 /* VGA_ATTR_DATA_R - VGA_RELIO_BASE */ +#define GROFFSET 0x4e /* VGA_GRAPH_INDEX - VGA_RELIO_BASE */ +#define SROFFSET 0x44 /* VGA_SEQ_INDEX - VGA_RELIO_BASE */ +#define CROFFSET 0x54 /* VGA_CRTC_INDEX_OFFSET + VGA_IOBASE_COLOR - VGA_RELIO_BASE */ +#define MISCROFFSET 0x4c /* VGA_MISC_OUT_R - VGA_RELIO_BASE */ +#define MISCWOFFSET 0x42 /* VGA_MISC_OUT_W - VGA_RELIO_BASE */ +#define INPUTSTATOFFSET 0x5A +#define PART1OFFSET 0x04 +#define PART2OFFSET 0x10 +#define PART3OFFSET 0x12 +#define PART4OFFSET 0x14 +#define PART5OFFSET 0x16 +#define VIDEOOFFSET 0x02 +#define COLREGOFFSET 0x48 + +#define SIS_IOBASE sis_iobase /* var defined in sis_vid.c */ +#define SISAR SIS_IOBASE + AROFFSET +#define SISARR SIS_IOBASE + ARROFFSET +#define SISGR SIS_IOBASE + GROFFSET +#define SISSR SIS_IOBASE + SROFFSET +#define SISCR SIS_IOBASE + CROFFSET +#define SISMISCR SIS_IOBASE + MISCROFFSET +#define SISMISCW SIS_IOBASE + MISCWOFFSET +#define SISINPSTAT SIS_IOBASE + INPUTSTATOFFSET +#define SISPART1 SIS_IOBASE + PART1OFFSET +#define SISPART2 SIS_IOBASE + PART2OFFSET +#define SISPART3 SIS_IOBASE + PART3OFFSET +#define SISPART4 SIS_IOBASE + PART4OFFSET +#define SISPART5 SIS_IOBASE + PART5OFFSET +#define SISVID SIS_IOBASE + VIDEOOFFSET +#define SISCOLIDX SIS_IOBASE + COLREGOFFSET +#define SISCOLDATA SIS_IOBASE + COLREGOFFSET + 1 +#define SISCOL2IDX SISPART5 +#define SISCOL2DATA SISPART5 + 1 + + +#define vc_index_offset 0x00 /* Video capture - unused */ +#define vc_data_offset 0x01 +#define vi_index_offset VIDEOOFFSET +#define vi_data_offset (VIDEOOFFSET + 1) +#define crt2_index_offset PART1OFFSET +#define crt2_port_offset (PART1OFFSET + 1) +#define sr_index_offset SROFFSET +#define sr_data_offset (SROFFSET + 1) +#define cr_index_offset CROFFSET +#define cr_data_offset (CROFFSET + 1) +#define input_stat INPUTSTATOFFSET + +/* For old chipsets (5597/5598, 6326, 530/620) ------------ */ +/* SR (3C4) */ +#define BankReg 0x06 +#define ClockReg 0x07 +#define CPUThreshold 0x08 +#define CRTThreshold 0x09 +#define CRTCOff 0x0A +#define DualBanks 0x0B +#define MMIOEnable 0x0B +#define RAMSize 0x0C +#define Mode64 0x0C +#define ExtConfStatus1 0x0E +#define ClockBase 0x13 +#define LinearAdd0 0x20 +#define LinearAdd1 0x21 +#define GraphEng 0x27 +#define MemClock0 0x28 +#define MemClock1 0x29 +#define XR2A 0x2A +#define XR2B 0x2B +#define TurboQueueBase 0x2C +#define FBSize 0x2F +#define ExtMiscCont5 0x34 +#define ExtMiscCont9 0x3C + +/* 3x4 */ +#define Offset 0x13 + +/* SiS Registers for 300, 540, 630, 730, 315, 550, 650, 740 */ + +/* VGA standard register */ +#define Index_SR_Graphic_Mode 0x06 +#define Index_SR_RAMDAC_Ctrl 0x07 +#define Index_SR_Threshold_Ctrl1 0x08 +#define Index_SR_Threshold_Ctrl2 0x09 +#define Index_SR_Misc_Ctrl 0x0F +#define Index_SR_DDC 0x11 +#define Index_SR_Feature_Connector_Ctrl 0x12 +#define Index_SR_DRAM_Sizing 0x14 +#define Index_SR_DRAM_State_Machine_Ctrl 0x15 +#define Index_SR_AGP_PCI_State_Machine 0x21 +#define Index_SR_Internal_MCLK0 0x28 +#define Index_SR_Internal_MCLK1 0x29 +#define Index_SR_Internal_DCLK1 0x2B +#define Index_SR_Internal_DCLK2 0x2C +#define Index_SR_Internal_DCLK3 0x2D +#define Index_SR_Ext_Clock_Sel 0x32 +#define Index_SR_Int_Status 0x34 +#define Index_SR_Int_Enable 0x35 +#define Index_SR_Int_Reset 0x36 +#define Index_SR_Power_On_Trap 0x38 +#define Index_SR_Power_On_Trap2 0x39 +#define Index_SR_Power_On_Trap3 0x3A + +/* video registers (300/630/730/315/550/650/740 only) */ +#define Index_VI_Passwd 0x00 + +/* Video overlay horizontal start/end, unit=screen pixels */ +#define Index_VI_Win_Hor_Disp_Start_Low 0x01 +#define Index_VI_Win_Hor_Disp_End_Low 0x02 +#define Index_VI_Win_Hor_Over 0x03 /* Overflow */ + +/* Video overlay vertical start/end, unit=screen pixels */ +#define Index_VI_Win_Ver_Disp_Start_Low 0x04 +#define Index_VI_Win_Ver_Disp_End_Low 0x05 +#define Index_VI_Win_Ver_Over 0x06 /* Overflow */ + +/* Y Plane (4:2:0) or YUV (4:2:2) buffer start address, unit=word */ +#define Index_VI_Disp_Y_Buf_Start_Low 0x07 +#define Index_VI_Disp_Y_Buf_Start_Middle 0x08 +#define Index_VI_Disp_Y_Buf_Start_High 0x09 + +/* U Plane (4:2:0) buffer start address, unit=word */ +#define Index_VI_U_Buf_Start_Low 0x0A +#define Index_VI_U_Buf_Start_Middle 0x0B +#define Index_VI_U_Buf_Start_High 0x0C + +/* V Plane (4:2:0) buffer start address, unit=word */ +#define Index_VI_V_Buf_Start_Low 0x0D +#define Index_VI_V_Buf_Start_Middle 0x0E +#define Index_VI_V_Buf_Start_High 0x0F + +/* Pitch for Y, UV Planes, unit=word */ +#define Index_VI_Disp_Y_Buf_Pitch_Low 0x10 +#define Index_VI_Disp_UV_Buf_Pitch_Low 0x11 +#define Index_VI_Disp_Y_UV_Buf_Pitch_Middle 0x12 + +/* What is this ? */ +#define Index_VI_Disp_Y_Buf_Preset_Low 0x13 +#define Index_VI_Disp_Y_Buf_Preset_Middle 0x14 + +#define Index_VI_UV_Buf_Preset_Low 0x15 +#define Index_VI_UV_Buf_Preset_Middle 0x16 +#define Index_VI_Disp_Y_UV_Buf_Preset_High 0x17 + +/* Scaling control registers */ +#define Index_VI_Hor_Post_Up_Scale_Low 0x18 +#define Index_VI_Hor_Post_Up_Scale_High 0x19 +#define Index_VI_Ver_Up_Scale_Low 0x1A +#define Index_VI_Ver_Up_Scale_High 0x1B +#define Index_VI_Scale_Control 0x1C + +/* Playback line buffer control */ +#define Index_VI_Play_Threshold_Low 0x1D +#define Index_VI_Play_Threshold_High 0x1E +#define Index_VI_Line_Buffer_Size 0x1F + +/* Destination color key */ +#define Index_VI_Overlay_ColorKey_Red_Min 0x20 +#define Index_VI_Overlay_ColorKey_Green_Min 0x21 +#define Index_VI_Overlay_ColorKey_Blue_Min 0x22 +#define Index_VI_Overlay_ColorKey_Red_Max 0x23 +#define Index_VI_Overlay_ColorKey_Green_Max 0x24 +#define Index_VI_Overlay_ColorKey_Blue_Max 0x25 + +/* Source color key, YUV color space */ +#define Index_VI_Overlay_ChromaKey_Red_Y_Min 0x26 +#define Index_VI_Overlay_ChromaKey_Green_U_Min 0x27 +#define Index_VI_Overlay_ChromaKey_Blue_V_Min 0x28 +#define Index_VI_Overlay_ChromaKey_Red_Y_Max 0x29 +#define Index_VI_Overlay_ChromaKey_Green_U_Max 0x2A +#define Index_VI_Overlay_ChromaKey_Blue_V_Max 0x2B + +/* Contrast enhancement and brightness control */ +#define Index_VI_Contrast_Factor 0x2C /* obviously unused/undefined */ +#define Index_VI_Brightness 0x2D +#define Index_VI_Contrast_Enh_Ctrl 0x2E + +#define Index_VI_Key_Overlay_OP 0x2F + +#define Index_VI_Control_Misc0 0x30 +#define Index_VI_Control_Misc1 0x31 +#define Index_VI_Control_Misc2 0x32 + +/* TW: Subpicture registers */ +#define Index_VI_SubPict_Buf_Start_Low 0x33 +#define Index_VI_SubPict_Buf_Start_Middle 0x34 +#define Index_VI_SubPict_Buf_Start_High 0x35 + +/* TW: What is this ? */ +#define Index_VI_SubPict_Buf_Preset_Low 0x36 +#define Index_VI_SubPict_Buf_Preset_Middle 0x37 + +/* TW: Subpicture pitch, unit=16 bytes */ +#define Index_VI_SubPict_Buf_Pitch 0x38 + +/* TW: Subpicture scaling control */ +#define Index_VI_SubPict_Hor_Scale_Low 0x39 +#define Index_VI_SubPict_Hor_Scale_High 0x3A +#define Index_VI_SubPict_Vert_Scale_Low 0x3B +#define Index_VI_SubPict_Vert_Scale_High 0x3C + +#define Index_VI_SubPict_Scale_Control 0x3D +/* (0x40 = enable/disable subpicture) */ + +/* TW: Subpicture line buffer control */ +#define Index_VI_SubPict_Threshold 0x3E + +/* TW: What is this? */ +#define Index_VI_FIFO_Max 0x3F + +/* TW: Subpicture palette; 16 colors, total 32 bytes address space */ +#define Index_VI_SubPict_Pal_Base_Low 0x40 +#define Index_VI_SubPict_Pal_Base_High 0x41 + +/* I wish I knew how to use these ... */ +#define Index_MPEG_Read_Ctrl0 0x60 /* MPEG auto flip */ +#define Index_MPEG_Read_Ctrl1 0x61 /* MPEG auto flip */ +#define Index_MPEG_Read_Ctrl2 0x62 /* MPEG auto flip */ +#define Index_MPEG_Read_Ctrl3 0x63 /* MPEG auto flip */ + +/* TW: MPEG AutoFlip scale */ +#define Index_MPEG_Ver_Up_Scale_Low 0x64 +#define Index_MPEG_Ver_Up_Scale_High 0x65 + +#define Index_MPEG_Y_Buf_Preset_Low 0x66 +#define Index_MPEG_Y_Buf_Preset_Middle 0x67 +#define Index_MPEG_UV_Buf_Preset_Low 0x68 +#define Index_MPEG_UV_Buf_Preset_Middle 0x69 +#define Index_MPEG_Y_UV_Buf_Preset_High 0x6A + +/* TW: The following registers only exist on the 310/325 series */ + +/* TW: Bit 16:24 of Y_U_V buf start address (?) */ +#define Index_VI_Y_Buf_Start_Over 0x6B +#define Index_VI_U_Buf_Start_Over 0x6C +#define Index_VI_V_Buf_Start_Over 0x6D + +#define Index_VI_Disp_Y_Buf_Pitch_High 0x6E +#define Index_VI_Disp_UV_Buf_Pitch_High 0x6F + +/* Hue and saturation */ +#define Index_VI_Hue 0x70 +#define Index_VI_Saturation 0x71 + +#define Index_VI_SubPict_Start_Over 0x72 +#define Index_VI_SubPict_Buf_Pitch_High 0x73 + +#define Index_VI_Control_Misc3 0x74 + + +/* TW: Bits (and helpers) for Index_VI_Control_Misc0 */ +#define VI_Misc0_Enable_Overlay 0x02 +#define VI_Misc0_420_Plane_Enable 0x04 /* Select Plane or Packed mode */ +#define VI_Misc0_422_Enable 0x20 /* Select 422 or 411 mode */ +#define VI_Misc0_Fmt_YVU420P 0x0C /* YUV420 Planar (I420, YV12) */ +#define VI_Misc0_Fmt_YUYV 0x28 /* YUYV Packed (YUY2) */ +#define VI_Misc0_Fmt_UYVY 0x08 /* (UYVY) */ + +/* TW: Bits for Index_VI_Control_Misc1 */ +/* #define VI_Misc1_? 0x01 */ +#define VI_Misc1_BOB_Enable 0x02 +#define VI_Misc1_Line_Merge 0x04 +#define VI_Misc1_Field_Mode 0x08 +/* #define VI_Misc1_? 0x10 */ +#define VI_Misc1_Non_Interleave 0x20 /* 300 series only? */ +#define VI_Misc1_Buf_Addr_Lock 0x20 /* 310 series only? */ +/* #define VI_Misc1_? 0x40 */ +/* #define VI_Misc1_? 0x80 */ + +/* TW: Bits for Index_VI_Control_Misc2 */ +#define VI_Misc2_Select_Video2 0x01 +#define VI_Misc2_Video2_On_Top 0x02 +/* #define VI_Misc2_? 0x04 */ +#define VI_Misc2_Vertical_Interpol 0x08 +#define VI_Misc2_Dual_Line_Merge 0x10 +#define VI_Misc2_All_Line_Merge 0x20 /* 310 series only? */ +#define VI_Misc2_Auto_Flip_Enable 0x40 /* 300 series only? */ +#define VI_Misc2_Video_Reg_Write_Enable 0x80 /* 310 series only? */ + +/* TW: Bits for Index_VI_Control_Misc3 */ +#define VI_Misc3_Submit_Video_1 0x01 /* AKA "address ready" */ +#define VI_Misc3_Submit_Video_2 0x02 /* AKA "address ready" */ +#define VI_Misc3_Submit_SubPict 0x04 /* AKA "address ready" */ + +/* TW: Values for Index_VI_Key_Overlay_OP (0x2F) */ +#define VI_ROP_Never 0x00 +#define VI_ROP_DestKey 0x03 +#define VI_ROP_Always 0x0F + +/* + * CRT_2 function control register --------------------------------- + */ +#define Index_CRT2_FC_CONTROL 0x00 +#define Index_CRT2_FC_SCREEN_HIGH 0x04 +#define Index_CRT2_FC_SCREEN_MID 0x05 +#define Index_CRT2_FC_SCREEN_LOW 0x06 +#define Index_CRT2_FC_ENABLE_WRITE 0x24 +#define Index_CRT2_FC_VR 0x25 +#define Index_CRT2_FC_VCount 0x27 +#define Index_CRT2_FC_VCount1 0x28 + +#define Index_310_CRT2_FC_VR 0x30 /* d[1] = vertical retrace */ +#define Index_310_CRT2_FC_RT 0x33 /* d[7] = retrace in progress */ + +/* video attributes - these should probably be configurable on the fly + * so users with different desktop sizes can keep + * captured data off the desktop + */ +#define _VINWID 704 +#define _VINHGT _VINHGT_NTSC +#define _VINHGT_NTSC 240 +#define _VINHGT_PAL 290 +#define _VIN_WINDOW (704 * 291 * 2) +#define _VBI_WINDOW (704 * 64 * 2) + +#define _VIN_FIELD_EVEN 1 +#define _VIN_FIELD_ODD 2 +#define _VIN_FIELD_BOTH 4 + + +/* i2c registers (TW; not on 300/310/325 series) */ +#define X_INDEXREG 0x14 +#define X_PORTREG 0x15 +#define X_DATA 0x0f +#define I2C_SCL 0x00 +#define I2C_SDA 0x01 +#define I2C_DELAY 10 + +/* mmio registers for video */ +#define REG_PRIM_CRT_COUNTER 0x8514 + +/* TW: MPEG MMIO registers (630 and later) ----------------------------*/ + +/* Not public (yet?) */ + +#endif /* VIDIX_SIS_REGS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidix/drivers/sis_vid.c Tue Oct 07 23:12:16 2003 +0000 @@ -0,0 +1,1561 @@ +/** + VIDIX driver for SiS 300 and 310/325 series chips. + + Copyright 2003 Jake Page, Sugar Media. + + Based on SiS Xv driver: + Copyright 2002-2003 by 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 License, or + (at your option) 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 + + 2003/10/08 integrated into mplayer/vidix architecture -- Alex Beregszaszi +**/ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <unistd.h> +#include <sys/io.h> + +#include "../vidix.h" +#include "../fourcc.h" +#include "../../libdha/libdha.h" +#include "../../libdha/pci_ids.h" +#include "../../libdha/pci_names.h" +#include "../../config.h" + +#include "sis_regs.h" +#include "sis_defs.h" + + +/** Random defines **/ + +#define WATCHDOG_DELAY 500000 /* Watchdog counter for retrace waiting */ +#define IMAGE_MIN_WIDTH 32 /* Min and max source image sizes */ +#define IMAGE_MIN_HEIGHT 24 +#define IMAGE_MAX_WIDTH 720 +#define IMAGE_MAX_HEIGHT 576 +#define IMAGE_MAX_WIDTH_M650 1920 +#define IMAGE_MAX_HEIGHT_M650 1080 + +#define OVERLAY_MIN_WIDTH 32 /* Minimum overlay sizes */ +#define OVERLAY_MIN_HEIGHT 24 + +#define DISPMODE_SINGLE1 0x1 /* TW: CRT1 only */ +#define DISPMODE_SINGLE2 0x2 /* TW: CRT2 only */ +#define DISPMODE_MIRROR 0x4 /* TW: CRT1 + CRT2 MIRROR */ + +#define VMODE_INTERLACED 0x1 +#define VMODE_DOUBLESCAN 0x2 + +typedef struct { + short x1, y1, x2, y2; +} BoxRec; + +typedef struct { + int pixelFormat; + + uint16_t pitch; + uint16_t origPitch; + + uint8_t keyOP; + uint16_t HUSF; + uint16_t VUSF; + uint8_t IntBit; + uint8_t wHPre; + + uint16_t srcW; + uint16_t srcH; + + BoxRec dstBox; + + uint32_t PSY; + uint32_t PSV; + uint32_t PSU; + uint8_t bobEnable; + + uint8_t contrastCtrl; + uint8_t contrastFactor; + + uint8_t lineBufSize; + + uint8_t(*VBlankActiveFunc) (); + + uint16_t SCREENheight; + +} SISOverlayRec, *SISOverlayPtr; + + +/** static variable definitions **/ +static int sis_probed = 0; +static pciinfo_t pci_info; +unsigned int sis_verbose = 0; + +static void *sis_mem_base; +/* static void *sis_reg_base; */ +unsigned short sis_iobase; + +unsigned int sis_vga_engine = UNKNOWN_VGA; +static unsigned int sis_displaymode = DISPMODE_SINGLE1; +static unsigned int sis_has_two_overlays = 0; +static unsigned int sis_bridge_is_slave = 0; +static unsigned int sis_shift_value = 1; +static unsigned int sis_vmode = 0; +unsigned int sis_vbflags = DISPTYPE_DISP1; +unsigned int sis_overlay_on_crt1 = 1; +unsigned int sis_crt1_off = -1; +unsigned int sis_detected_crt2_devices; +unsigned int sis_force_crt2_type = CRT2_DEFAULT; +unsigned int sis_device_id = -1; + +static int sis_format; +static int sis_Yoff = 0; +static int sis_Voff = 0; +static int sis_Uoff = 0; +static int sis_screen_width = 640; +static int sis_screen_height = 480; + +static int sis_frames[VID_PLAY_MAXFRAMES]; + +static vidix_grkey_t sis_grkey; + +static vidix_capability_t sis_cap = { + "SiS 300/310/325 Video Driver", + "Jake Page", + TYPE_OUTPUT, + {0, 0, 0, 0}, + 2048, + 2048, + 4, + 4, + -1, + FLAG_UPSCALER | FLAG_DOWNSCALER | FLAG_EQUALIZER, + VENDOR_SIS, + -1, + {0, 0, 0, 0} +}; + +vidix_video_eq_t sis_equal = { + VEQ_CAP_BRIGHTNESS | VEQ_CAP_CONTRAST, + 200, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned short sis_card_ids[] = { + DEVICE_SIS_300, + DEVICE_SIS_315H, + DEVICE_SIS_315, + DEVICE_SIS_315PRO, + DEVICE_SIS_330, + DEVICE_SIS_540_VGA, + DEVICE_SIS_550_VGA, + DEVICE_SIS_630_VGA, + DEVICE_SIS_650_VGA +}; + +/** function declarations **/ + +extern void sis_init_video_bridge(); + + +static void set_overlay(SISOverlayPtr pOverlay, int index); +static void close_overlay(); +static void calc_scale_factor(SISOverlayPtr pOverlay, + int index, int iscrt2); +static void set_line_buf_size(SISOverlayPtr pOverlay); +static void merge_line_buf(int enable); +static void set_format(SISOverlayPtr pOverlay); +static void set_colorkey(); + +static void set_brightness(uint8_t brightness); +static void set_contrast(uint8_t contrast); +static void set_saturation(char saturation); +static void set_hue(uint8_t hue); +#if 0 +static void set_alpha(uint8_t alpha); +#endif + +/* IO Port access functions */ +static uint8_t getvideoreg(uint8_t reg) +{ + uint8_t ret; + inSISIDXREG(SISVID, reg, ret); + return (ret); +} + +static void setvideoreg(uint8_t reg, uint8_t data) +{ + outSISIDXREG(SISVID, reg, data); +} + +static void setvideoregmask(uint8_t reg, uint8_t data, uint8_t mask) +{ + uint8_t old; + + inSISIDXREG(SISVID, reg, old); + data = (data & mask) | (old & (~mask)); + outSISIDXREG(SISVID, reg, data); +} + +static void setsrregmask(uint8_t reg, uint8_t data, uint8_t mask) +{ + uint8_t old; + + inSISIDXREG(SISSR, reg, old); + data = (data & mask) | (old & (~mask)); + outSISIDXREG(SISSR, reg, data); +} + +/* vblank checking*/ +static uint8_t vblank_active_CRT1() +{ + /* this may be too simplistic? */ + return (inSISREG(SISINPSTAT) & 0x08); +} + +static uint8_t vblank_active_CRT2() +{ + uint8_t ret; + if (sis_vga_engine == SIS_315_VGA) { + inSISIDXREG(SISPART1, Index_310_CRT2_FC_VR, ret); + } else { + inSISIDXREG(SISPART1, Index_CRT2_FC_VR, ret); + } + return ((ret & 0x02) ^ 0x02); +} + + +unsigned int vixGetVersion(void) +{ + return (VIDIX_VERSION); +} + +static int find_chip(unsigned chip_id) +{ + unsigned i; + for (i = 0; i < sizeof(sis_card_ids) / sizeof(unsigned short); i++) { + if (chip_id == sis_card_ids[i]) + return i; + } + return -1; +} + +int vixProbe(int verbose, int force) +{ + pciinfo_t lst[MAX_PCI_DEVICES]; + unsigned i, num_pci; + int err; + + sis_verbose = verbose; + force = force; + err = pci_scan(lst, &num_pci); + if (err) { + printf("[SiS] Error occured during pci scan: %s\n", strerror(err)); + return err; + } else { + err = ENXIO; + for (i = 0; i < num_pci; i++) { + if (lst[i].vendor == VENDOR_SIS) { + int idx; + const char *dname; + idx = find_chip(lst[i].device); + if (idx == -1) + continue; + dname = pci_device_name(VENDOR_SIS, lst[i].device); + dname = dname ? dname : "Unknown chip"; + if (sis_verbose > 0) + printf("[SiS] Found chip: %s (0x%X)\n", + dname, lst[i].device); + sis_device_id = sis_cap.device_id = lst[i].device; + err = 0; + memcpy(&pci_info, &lst[i], sizeof(pciinfo_t)); + + sis_has_two_overlays = 0; + switch (sis_cap.device_id) { + case DEVICE_SIS_300: + case DEVICE_SIS_630_VGA: + sis_has_two_overlays = 1; + case DEVICE_SIS_540_VGA: + sis_vga_engine = SIS_300_VGA; + break; + case DEVICE_SIS_330: + case DEVICE_SIS_550_VGA: + sis_has_two_overlays = 1; + case DEVICE_SIS_315H: + case DEVICE_SIS_315: + case DEVICE_SIS_315PRO: + case DEVICE_SIS_650_VGA: + /* M650 & 651 have 2 overlays */ + /* JCP: I think this works, but not really tested yet */ + { + unsigned char CR5F; + unsigned char tempreg1, tempreg2; + + inSISIDXREG(SISCR, 0x5F, CR5F); + CR5F &= 0xf0; + andSISIDXREG(SISCR, 0x5c, 0x07); + inSISIDXREG(SISCR, 0x5c, tempreg1); + tempreg1 &= 0xf8; + setSISIDXREG(SISCR, 0x5c, 0x07, 0xf8); + inSISIDXREG(SISCR, 0x5c, tempreg2); + tempreg2 &= 0xf8; + if ((!tempreg1) || (tempreg2)) { + if (CR5F & 0x80) { + sis_has_two_overlays = 1; + } + } else { + sis_has_two_overlays = 1; /* ? */ + } + if (sis_has_two_overlays) { + if (sis_verbose > 0) + printf + ("[SiS] detected M650/651 with 2 overlays\n"); + } + } + sis_vga_engine = SIS_315_VGA; + break; + default: + /* should never get here */ + sis_vga_engine = UNKNOWN_VGA; + break; + } + } + } + } + if (err && sis_verbose) { + printf("[SiS] Can't find chip\n"); + } else { + sis_probed = 1; + } + + return err; +} + +int vixInit(void) +{ + uint8_t sr_data, cr_data, cr_data2; + char *env_overlay_crt; + + if (!sis_probed) { + printf("[SiS] driver was not probed but is being initialized\n"); + return (EINTR); + } + + /* JCP: this is WRONG. Need to coordinate w/ sisfb to use correct mem */ + /* map 16MB scary hack for now. */ + sis_mem_base = map_phys_mem(pci_info.base0, 0x1000000); + /* sis_reg_base = map_phys_mem(pci_info.base1, 0x20000); */ + sis_iobase = pci_info.base2 & 0xFFFC; + + /* would like to use fb ioctl - or some other method - here to get + current resolution. */ + inSISIDXREG(SISCR, 0x12, cr_data); + inSISIDXREG(SISCR, 0x07, cr_data2); + sis_screen_height = + ((cr_data & 0xff) | ((uint16_t) (cr_data2 & 0x02) << 7) | + ((uint16_t) (cr_data2 & 0x40) << 3) | ((uint16_t) (sr_data & 0x02) + << 9)) + 1; + + inSISIDXREG(SISSR, 0x0b, sr_data); + inSISIDXREG(SISCR, 0x01, cr_data); + sis_screen_width = (((cr_data & 0xff) | + ((uint16_t) (sr_data & 0x0C) << 6)) + 1) * 8; + + inSISIDXREG(SISSR, Index_SR_Graphic_Mode, sr_data); + if (sr_data & 0x20) /* interlaced mode */ + sis_vmode |= VMODE_INTERLACED; + +#if 0 /* getting back false data here... */ + /* CR9 bit 7 set = double scan active */ + inSISIDXREG(SISCR, 0x09, cr_data); + if (cr_data & 0x40) { + sis_vmode |= VMODE_DOUBLESCAN; + } +#endif + + /* JCP: eventually I'd like to replace this with a call to sisfb + SISFB_GET_INFO ioctl to get video bridge info. Not for now, + since it requires a very new and not widely distributed version. */ + sis_init_video_bridge(); + + env_overlay_crt = getenv("VIDIX_CRT"); + if (env_overlay_crt) { + int crt = atoi(env_overlay_crt); + if (crt == 1 || crt == 2) { + sis_overlay_on_crt1 = (crt == 1); + if (sis_verbose > 0) { + printf + ("[SiS] override: using overlay on CRT%d from VIDIX_CRT\n", + crt); + } + } + } + + return 0; +} + +void vixDestroy(void) +{ + /* unmap_phys_mem(sis_reg_base, 0x20000); */ + /* JCP: see above, hence also a hack. */ + unmap_phys_mem(sis_mem_base, 0x1000000); +} + +int vixGetCapability(vidix_capability_t * to) +{ + memcpy(to, &sis_cap, sizeof(vidix_capability_t)); + return 0; +} + +static int is_supported_fourcc(uint32_t fourcc) +{ + switch (fourcc) { + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_UYVY: + case IMGFMT_YUY2: + case IMGFMT_RGB15: + case IMGFMT_RGB16: + return 1; + default: + return 0; + } +} + +int vixQueryFourcc(vidix_fourcc_t * to) +{ + if (is_supported_fourcc(to->fourcc)) { + to->depth = VID_DEPTH_8BPP | VID_DEPTH_16BPP | VID_DEPTH_32BPP; + to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY; + return 0; + } else + to->depth = to->flags = 0; + return ENOSYS; +} + +static int bridge_in_slave_mode() +{ + unsigned char usScratchP1_00; + + if (!(sis_vbflags & VB_VIDEOBRIDGE)) + return 0; + + inSISIDXREG(SISPART1, 0x00, usScratchP1_00); + if (((sis_vga_engine == SIS_300_VGA) + && (usScratchP1_00 & 0xa0) == 0x20) + || ((sis_vga_engine == SIS_315_VGA) + && (usScratchP1_00 & 0x50) == 0x10)) { + return 1; + } else { + return 0; + } +} + +/* This does not handle X dual head mode, since 1) vidix doesn't support it + and 2) it doesn't make sense for other gfx drivers */ +static void set_dispmode() +{ + sis_bridge_is_slave = 0; + + if (bridge_in_slave_mode()) + sis_bridge_is_slave = 1; + + if ((sis_vbflags & VB_DISPMODE_MIRROR) || + (sis_bridge_is_slave && (sis_vbflags & DISPTYPE_DISP2))) { + if (sis_has_two_overlays) + sis_displaymode = DISPMODE_MIRROR; /* TW: CRT1+CRT2 (2 overlays) */ + else if (!sis_overlay_on_crt1) + sis_displaymode = DISPMODE_SINGLE2; + else + sis_displaymode = DISPMODE_SINGLE1; + } else { + if (sis_vbflags & DISPTYPE_DISP1) { + sis_displaymode = DISPMODE_SINGLE1; /* TW: CRT1 only */ + } else { + sis_displaymode = DISPMODE_SINGLE2; /* TW: CRT2 only */ + } + } +} + +static void set_disptype_regs() +{ + switch (sis_displaymode) { + case DISPMODE_SINGLE1: /* TW: CRT1 only */ + if (sis_verbose > 2) { + printf("[SiS] Setting up overlay on CRT1\n"); + } + if (sis_has_two_overlays) { + setsrregmask(0x06, 0x00, 0xc0); + setsrregmask(0x32, 0x00, 0xc0); + } else { + setsrregmask(0x06, 0x00, 0xc0); + setsrregmask(0x32, 0x00, 0xc0); + } + break; + case DISPMODE_SINGLE2: /* TW: CRT2 only */ + if (sis_verbose > 2) { + printf("[SiS] Setting up overlay on CRT2\n"); + } + if (sis_has_two_overlays) { + setsrregmask(0x06, 0x80, 0xc0); + setsrregmask(0x32, 0x80, 0xc0); + } else { + setsrregmask(0x06, 0x40, 0xc0); + setsrregmask(0x32, 0x40, 0xc0); + } + break; + case DISPMODE_MIRROR: /* TW: CRT1 + CRT2 */ + default: + if (sis_verbose > 2) { + printf("[SiS] Setting up overlay on CRT1 AND CRT2!\n"); + } + setsrregmask(0x06, 0x80, 0xc0); + setsrregmask(0x32, 0x80, 0xc0); + break; + } +} + +static void init_overlay() +{ + /* Initialize first overlay (CRT1) */ + + /* Write-enable video registers */ + setvideoregmask(Index_VI_Control_Misc2, 0x80, 0x81); + + /* Disable overlay */ + setvideoregmask(Index_VI_Control_Misc0, 0x00, 0x02); + + /* Disable bobEnable */ + setvideoregmask(Index_VI_Control_Misc1, 0x02, 0x02); + + /* Reset scale control and contrast */ + setvideoregmask(Index_VI_Scale_Control, 0x60, 0x60); + setvideoregmask(Index_VI_Contrast_Enh_Ctrl, 0x04, 0x1F); + + setvideoreg(Index_VI_Disp_Y_Buf_Preset_Low, 0x00); + setvideoreg(Index_VI_Disp_Y_Buf_Preset_Middle, 0x00); + setvideoreg(Index_VI_UV_Buf_Preset_Low, 0x00); + setvideoreg(Index_VI_UV_Buf_Preset_Middle, 0x00); + setvideoreg(Index_VI_Disp_Y_UV_Buf_Preset_High, 0x00); + setvideoreg(Index_VI_Play_Threshold_Low, 0x00); + setvideoreg(Index_VI_Play_Threshold_High, 0x00); + + /* may not want to init these here, could already be set to other + values by app? */ + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x01); + setvideoregmask(Index_VI_Contrast_Enh_Ctrl, 0x04, 0x07); + setvideoreg(Index_VI_Brightness, 0x20); + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_Hue, 0x00); + setvideoreg(Index_VI_Saturation, 0x00); + } + + /* Initialize second overlay (CRT2) */ + if (sis_has_two_overlays) { + /* Write-enable video registers */ + setvideoregmask(Index_VI_Control_Misc2, 0x81, 0x81); + + /* Disable overlay */ + setvideoregmask(Index_VI_Control_Misc0, 0x00, 0x02); + + /* Disable bobEnable */ + setvideoregmask(Index_VI_Control_Misc1, 0x02, 0x02); + + /* Reset scale control and contrast */ + setvideoregmask(Index_VI_Scale_Control, 0x60, 0x60); + setvideoregmask(Index_VI_Contrast_Enh_Ctrl, 0x04, 0x1F); + + setvideoreg(Index_VI_Disp_Y_Buf_Preset_Low, 0x00); + setvideoreg(Index_VI_Disp_Y_Buf_Preset_Middle, 0x00); + setvideoreg(Index_VI_UV_Buf_Preset_Low, 0x00); + setvideoreg(Index_VI_UV_Buf_Preset_Middle, 0x00); + setvideoreg(Index_VI_Disp_Y_UV_Buf_Preset_High, 0x00); + setvideoreg(Index_VI_Play_Threshold_Low, 0x00); + setvideoreg(Index_VI_Play_Threshold_High, 0x00); + + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x01); + setvideoregmask(Index_VI_Contrast_Enh_Ctrl, 0x04, 0x07); + setvideoreg(Index_VI_Brightness, 0x20); + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_Hue, 0x00); + setvideoreg(Index_VI_Saturation, 0x00); + } + } +} + +int vixConfigPlayback(vidix_playback_t * info) +{ + SISOverlayRec overlay; + int srcOffsetX = 0, srcOffsetY = 0; + int sx, sy; + int index = 0, iscrt2 = 0; + int total_size; + + short src_w, drw_w; + short src_h, drw_h; + short src_x, drw_x; + short src_y, drw_y; + long dga_offset; + int pitch; + unsigned int i; + + if (!is_supported_fourcc(info->fourcc)) + return -1; + + /* set chipset/engine.dependent config info */ + /* which CRT to use, etc.? */ + switch (sis_vga_engine) { + case SIS_315_VGA: + sis_shift_value = 1; + sis_equal.cap |= VEQ_CAP_SATURATION | VEQ_CAP_HUE; + break; + case SIS_300_VGA: + default: + sis_shift_value = 2; + break; + } + + sis_displaymode = DISPMODE_SINGLE1; /* xV driver code in set_dispmode() */ + set_dispmode(); + + set_disptype_regs(); + + init_overlay(); + + /* get basic dimension info */ + src_x = info->src.x; + src_y = info->src.y; + src_w = info->src.w; + src_h = info->src.h; + + drw_x = info->dest.x; + drw_y = info->dest.y; + drw_w = info->dest.w; + drw_h = info->dest.h; + + switch (info->fourcc) { + case IMGFMT_YV12: + case IMGFMT_I420: + pitch = (src_w + 7) & ~7; + total_size = (pitch * src_h * 3) >> 1; + break; + case IMGFMT_YUY2: + case IMGFMT_UYVY: + case IMGFMT_RGB15: + case IMGFMT_RGB16: + pitch = ((src_w << 1) + 3) & ~3; + total_size = pitch * src_h; + break; + default: + return -1; + } + + /* "allocate" memory for overlay! */ + /* start at 8MB = sisfb's "dri reserved space" - + really shouldn't hardcode though */ + /* XXX: JCP - this can use the sisfb FBIO_ALLOC ioctl to safely + allocate "video heap" memory... */ + dga_offset = 0x800000; + + /* use 7MB for now. need to calc/get real info from sisfb? */ + /* this can result in a LOT of frames - probably not necessary */ + info->num_frames = 0x700000 / (total_size * 2); + if (info->num_frames > VID_PLAY_MAXFRAMES) + info->num_frames = VID_PLAY_MAXFRAMES; + + info->dga_addr = sis_mem_base + dga_offset; + info->dest.pitch.y = 16; + info->dest.pitch.u = 16; + info->dest.pitch.v = 16; + info->offset.y = 0; + info->offset.u = 0; + info->offset.v = 0; + info->frame_size = (total_size * 2); /* why times 2 ? */ + for (i = 0; i < info->num_frames; i++) { + info->offsets[i] = info->frame_size * i; + /* save ptrs to mem buffers */ + sis_frames[i] = (dga_offset + info->offsets[i]); + } + + memset(&overlay, 0, sizeof(overlay)); + overlay.pixelFormat = sis_format = info->fourcc; + overlay.pitch = overlay.origPitch = pitch; + + + overlay.keyOP = (sis_grkey.ckey.op == CKEY_TRUE ? + VI_ROP_DestKey : VI_ROP_Always); + + overlay.bobEnable = 0x00; + + overlay.SCREENheight = sis_screen_height; + + /* probably will not support X virtual screen > phys very well? */ + overlay.dstBox.x1 = drw_x; /* - pScrn->frameX0; */ + overlay.dstBox.x2 = drw_x + drw_w; /* - pScrn->frameX0; ??? */ + overlay.dstBox.y1 = drw_y; /* - pScrn->frameY0; */ + overlay.dstBox.y2 = drw_y + drw_h; /* - pScrn->frameY0; ??? */ + + if ((overlay.dstBox.x1 > overlay.dstBox.x2) || + (overlay.dstBox.y1 > overlay.dstBox.y2)) + return -1; + + if ((overlay.dstBox.x2 < 0) || (overlay.dstBox.y2 < 0)) + return -1; + + if (overlay.dstBox.x1 < 0) { + srcOffsetX = src_w * (-overlay.dstBox.x1) / drw_w; + overlay.dstBox.x1 = 0; + } + if (overlay.dstBox.y1 < 0) { + srcOffsetY = src_h * (-overlay.dstBox.y1) / drw_h; + overlay.dstBox.y1 = 0; + } + + switch (info->fourcc) { + case IMGFMT_YV12: + info->dest.pitch.y = 16; + sx = (src_x + srcOffsetX) & ~7; + sy = (src_y + srcOffsetY) & ~1; + info->offset.y = sis_Yoff = sx + sy * pitch; + /* JCP: NOTE reversed u & v here! Not sure why this is needed. + maybe mplayer & sis define U & V differently?? */ + info->offset.u = sis_Voff = + src_h * pitch + ((sx + sy * pitch / 2) >> 1); + info->offset.v = sis_Uoff = + src_h * pitch * 5 / 4 + ((sx + sy * pitch / 2) >> 1); + + overlay.PSY = (sis_frames[0] + sis_Yoff) >> sis_shift_value; + overlay.PSV = (sis_frames[0] + sis_Voff) >> sis_shift_value; + overlay.PSU = (sis_frames[0] + sis_Uoff) >> sis_shift_value; + break; + case IMGFMT_I420: + sx = (src_x + srcOffsetX) & ~7; + sy = (src_y + srcOffsetY) & ~1; + info->offset.y = sis_Yoff = sx + sy * pitch; + /* JCP: see above... */ + info->offset.u = sis_Voff = + src_h * pitch * 5 / 4 + ((sx + sy * pitch / 2) >> 1); + info->offset.v = sis_Uoff = + src_h * pitch + ((sx + sy * pitch / 2) >> 1); + + overlay.PSY = (sis_frames[0] + sis_Yoff) >> sis_shift_value; + overlay.PSV = (sis_frames[0] + sis_Voff) >> sis_shift_value; + overlay.PSU = (sis_frames[0] + sis_Uoff) >> sis_shift_value; + break; + case IMGFMT_YUY2: + case IMGFMT_UYVY: + case IMGFMT_RGB16: + case IMGFMT_RGB15: + default: + sx = (src_x + srcOffsetX) & ~1; + sy = (src_y + srcOffsetY); + info->offset.y = sis_Yoff = sx * 2 + sy * pitch; + + overlay.PSY = (sis_frames[0] + sis_Yoff) >> sis_shift_value; + break; + } + + /* FIXME: is it possible that srcW < 0? */ + overlay.srcW = src_w - (sx - src_x); + overlay.srcH = src_h - (sy - src_y); + + /* JCP: what to do about this? */ +#if 0 + if ((pPriv->oldx1 != overlay.dstBox.x1) || + (pPriv->oldx2 != overlay.dstBox.x2) || + (pPriv->oldy1 != overlay.dstBox.y1) || + (pPriv->oldy2 != overlay.dstBox.y2)) { + pPriv->mustwait = 1; + pPriv->oldx1 = overlay.dstBox.x1; + pPriv->oldx2 = overlay.dstBox.x2; + pPriv->oldy1 = overlay.dstBox.y1; + pPriv->oldy2 = overlay.dstBox.y2; + } +#endif + + /* set merge line buffer */ + merge_line_buf(overlay.srcW > 384); + + /* calculate line buffer length */ + set_line_buf_size(&overlay); + + if (sis_displaymode == DISPMODE_SINGLE2) { + if (sis_has_two_overlays) { + /* TW: On chips with two overlays we use + * overlay 2 for CRT2 */ + index = 1; + iscrt2 = 1; + } else { + /* TW: On chips with only one overlay we + * use that only overlay for CRT2 */ + index = 0; + iscrt2 = 1; + } + overlay.VBlankActiveFunc = vblank_active_CRT2; + /* overlay.GetScanLineFunc = get_scanline_CRT2; */ + } else { + index = 0; + iscrt2 = 0; + overlay.VBlankActiveFunc = vblank_active_CRT1; + /* overlay.GetScanLineFunc = get_scanline_CRT1; */ + } + + /* calc scale factor (to use below) */ + calc_scale_factor(&overlay, index, iscrt2); + + /* Select video1 (used for CRT1) or video2 (used for CRT2) */ + setvideoregmask(Index_VI_Control_Misc2, index, 0x01); + + set_format(&overlay); + + set_colorkey(); + + vixPlaybackSetEq(&sis_equal); + + /* set up video overlay registers */ + set_overlay(&overlay, index); + + /* prevent badness if bits are not at default setting */ + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x01); + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x04); + + /* JCP: Xv driver implementation loops back over above code to + setup mirror CRT2 */ + + return 0; +} + +int vixPlaybackOn(void) +{ + setvideoregmask(Index_VI_Control_Misc0, 0x02, 0x02); + return 0; +} + +int vixPlaybackOff(void) +{ + unsigned char sridx, cridx; + sridx = inSISREG(SISSR); + cridx = inSISREG(SISCR); + close_overlay(); + outSISREG(SISSR, sridx); + outSISREG(SISCR, cridx); + + return 0; +} + +int vixPlaybackFrameSelect(unsigned int frame) +{ + uint8_t data; + int index = 0; + uint32_t PSY; + + if (sis_displaymode == DISPMODE_SINGLE2 && sis_has_two_overlays) { + index = 1; + } + + PSY = (sis_frames[frame] + sis_Yoff) >> sis_shift_value; + + /* Unlock address registers */ + data = getvideoreg(Index_VI_Control_Misc1); + setvideoreg(Index_VI_Control_Misc1, data | 0x20); + /* TEST: Is this required? */ + setvideoreg(Index_VI_Control_Misc1, data | 0x20); + /* TEST end */ + /* TEST: Is this required? */ + if (sis_vga_engine == SIS_315_VGA) + setvideoreg(Index_VI_Control_Misc3, 0x00); + /* TEST end */ + + /* set Y start address */ + setvideoreg(Index_VI_Disp_Y_Buf_Start_Low, (uint8_t) (PSY)); + setvideoreg(Index_VI_Disp_Y_Buf_Start_Middle, (uint8_t) ((PSY) >> 8)); + setvideoreg(Index_VI_Disp_Y_Buf_Start_High, (uint8_t) ((PSY) >> 16)); + /* set 310/325 series overflow bits for Y plane */ + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_Y_Buf_Start_Over, + ((uint8_t) ((PSY) >> 24) & 0x01)); + } + + /* Set U/V data if using plane formats */ + if ((sis_format == IMGFMT_YV12) || (sis_format == IMGFMT_I420)) { + + uint32_t PSU, PSV; + + PSU = (sis_frames[frame] + sis_Uoff) >> sis_shift_value; + PSV = (sis_frames[frame] + sis_Voff) >> sis_shift_value; + + /* set U/V start address */ + setvideoreg(Index_VI_U_Buf_Start_Low, (uint8_t) PSU); + setvideoreg(Index_VI_U_Buf_Start_Middle, (uint8_t) (PSU >> 8)); + setvideoreg(Index_VI_U_Buf_Start_High, (uint8_t) (PSU >> 16)); + + setvideoreg(Index_VI_V_Buf_Start_Low, (uint8_t) PSV); + setvideoreg(Index_VI_V_Buf_Start_Middle, (uint8_t) (PSV >> 8)); + setvideoreg(Index_VI_V_Buf_Start_High, (uint8_t) (PSV >> 16)); + + /* 310/325 series overflow bits */ + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_U_Buf_Start_Over, + ((uint8_t) (PSU >> 24) & 0x01)); + setvideoreg(Index_VI_V_Buf_Start_Over, + ((uint8_t) (PSV >> 24) & 0x01)); + } + } + + if (sis_vga_engine == SIS_315_VGA) { + /* Trigger register copy for 310 series */ + setvideoreg(Index_VI_Control_Misc3, 1 << index); + } + + /* Lock the address registers */ + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x20); + + return 0; +} + +int vixGetGrKeys(vidix_grkey_t * grkey) +{ + memcpy(grkey, &sis_grkey, sizeof(vidix_grkey_t)); + return 0; +} + +int vixSetGrKeys(const vidix_grkey_t * grkey) +{ + memcpy(&sis_grkey, grkey, sizeof(vidix_grkey_t)); + set_colorkey(); + return 0; +} + +int vixPlaybackGetEq(vidix_video_eq_t * eq) +{ + memcpy(eq, &sis_equal, sizeof(vidix_video_eq_t)); + return 0; +} + +int vixPlaybackSetEq(const vidix_video_eq_t * eq) +{ + int br, sat, cr, hue; + if (eq->cap & VEQ_CAP_BRIGHTNESS) + sis_equal.brightness = eq->brightness; + if (eq->cap & VEQ_CAP_CONTRAST) + sis_equal.contrast = eq->contrast; + if (eq->cap & VEQ_CAP_SATURATION) + sis_equal.saturation = eq->saturation; + if (eq->cap & VEQ_CAP_HUE) + sis_equal.hue = eq->hue; + if (eq->cap & VEQ_CAP_RGB_INTENSITY) { + sis_equal.red_intensity = eq->red_intensity; + sis_equal.green_intensity = eq->green_intensity; + sis_equal.blue_intensity = eq->blue_intensity; + } + sis_equal.flags = eq->flags; + + cr = (sis_equal.contrast + 1000) * 7 / 2000; + if (cr < 0) + cr = 0; + if (cr > 7) + cr = 7; + + br = sis_equal.brightness * 127 / 1000; + if (br < -128) + br = -128; + if (br > 127) + br = 127; + + sat = (sis_equal.saturation * 7) / 1000; + if (sat < -7) + sat = -7; + if (sat > 7) + sat = 7; + + hue = sis_equal.hue * 7 / 1000; + if (hue < -8) + hue = -8; + if (hue > 7) + hue = 7; + + set_brightness(br); + set_contrast(cr); + if (sis_vga_engine == SIS_315_VGA) { + set_saturation(sat); + set_hue(hue); + } + + return 0; +} + +static void set_overlay(SISOverlayPtr pOverlay, int index) +{ + uint16_t pitch = 0; + uint8_t h_over = 0, v_over = 0; + uint16_t top, bottom, left, right; + uint16_t screenX = sis_screen_width; + uint16_t screenY = sis_screen_height; + uint8_t data; + uint32_t watchdog; + + top = pOverlay->dstBox.y1; + bottom = pOverlay->dstBox.y2; + if (bottom > screenY) { + bottom = screenY; + } + + left = pOverlay->dstBox.x1; + right = pOverlay->dstBox.x2; + if (right > screenX) { + right = screenX; + } + + /* JCP: these aren't really tested... */ + /* TW: DoubleScan modes require Y coordinates * 2 */ + if (sis_vmode & VMODE_DOUBLESCAN) { + top <<= 1; + bottom <<= 1; + } + /* TW: Interlace modes require Y coordinates / 2 */ + if (sis_vmode & VMODE_INTERLACED) { + top >>= 1; + bottom >>= 1; + } + + h_over = (((left >> 8) & 0x0f) | ((right >> 4) & 0xf0)); + v_over = (((top >> 8) & 0x0f) | ((bottom >> 4) & 0xf0)); + + pitch = pOverlay->pitch >> sis_shift_value; + + /* set line buffer size */ + setvideoreg(Index_VI_Line_Buffer_Size, pOverlay->lineBufSize); + + /* set color key mode */ + setvideoregmask(Index_VI_Key_Overlay_OP, pOverlay->keyOP, 0x0F); + + /* TW: We don't have to wait for vertical retrace in all cases */ + /* JCP: be safe for now. */ + if (1 /*pPriv->mustwait */ ) { + watchdog = WATCHDOG_DELAY; + while (pOverlay->VBlankActiveFunc() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!pOverlay->VBlankActiveFunc()) && --watchdog); + if (!watchdog && sis_verbose > 0) { + printf("[SiS]: timed out waiting for vertical retrace\n"); + } + } + + /* Unlock address registers */ + data = getvideoreg(Index_VI_Control_Misc1); + setvideoreg(Index_VI_Control_Misc1, data | 0x20); + /* TEST: Is this required? */ + setvideoreg(Index_VI_Control_Misc1, data | 0x20); + /* TEST end */ + + /* TEST: Is this required? */ + if (sis_vga_engine == SIS_315_VGA) + setvideoreg(Index_VI_Control_Misc3, 0x00); + /* TEST end */ + + /* Set Y buf pitch */ + setvideoreg(Index_VI_Disp_Y_Buf_Pitch_Low, (uint8_t) (pitch)); + setvideoregmask(Index_VI_Disp_Y_UV_Buf_Pitch_Middle, + (uint8_t) (pitch >> 8), 0x0f); + + /* Set Y start address */ + setvideoreg(Index_VI_Disp_Y_Buf_Start_Low, (uint8_t) (pOverlay->PSY)); + setvideoreg(Index_VI_Disp_Y_Buf_Start_Middle, + (uint8_t) ((pOverlay->PSY) >> 8)); + setvideoreg(Index_VI_Disp_Y_Buf_Start_High, + (uint8_t) ((pOverlay->PSY) >> 16)); + + /* set 310/325 series overflow bits for Y plane */ + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_Disp_Y_Buf_Pitch_High, + (uint8_t) (pitch >> 12)); + setvideoreg(Index_VI_Y_Buf_Start_Over, + ((uint8_t) ((pOverlay->PSY) >> 24) & 0x01)); + } + + /* Set U/V data if using plane formats */ + if ((pOverlay->pixelFormat == IMGFMT_YV12) || + (pOverlay->pixelFormat == IMGFMT_I420)) { + + uint32_t PSU, PSV; + + PSU = pOverlay->PSU; + PSV = pOverlay->PSV; + + /* Set U/V pitch */ + setvideoreg(Index_VI_Disp_UV_Buf_Pitch_Low, + (uint8_t) (pitch >> 1)); + setvideoregmask(Index_VI_Disp_Y_UV_Buf_Pitch_Middle, + (uint8_t) (pitch >> 5), 0xf0); + + /* set U/V start address */ + setvideoreg(Index_VI_U_Buf_Start_Low, (uint8_t) PSU); + setvideoreg(Index_VI_U_Buf_Start_Middle, (uint8_t) (PSU >> 8)); + setvideoreg(Index_VI_U_Buf_Start_High, (uint8_t) (PSU >> 16)); + + setvideoreg(Index_VI_V_Buf_Start_Low, (uint8_t) PSV); + setvideoreg(Index_VI_V_Buf_Start_Middle, (uint8_t) (PSV >> 8)); + setvideoreg(Index_VI_V_Buf_Start_High, (uint8_t) (PSV >> 16)); + + /* 310/325 series overflow bits */ + if (sis_vga_engine == SIS_315_VGA) { + setvideoreg(Index_VI_Disp_UV_Buf_Pitch_High, + (uint8_t) (pitch >> 13)); + setvideoreg(Index_VI_U_Buf_Start_Over, + ((uint8_t) (PSU >> 24) & 0x01)); + setvideoreg(Index_VI_V_Buf_Start_Over, + ((uint8_t) (PSV >> 24) & 0x01)); + } + } + + if (sis_vga_engine == SIS_315_VGA) { + /* Trigger register copy for 310 series */ + setvideoreg(Index_VI_Control_Misc3, 1 << index); + } + + /* set scale factor */ + setvideoreg(Index_VI_Hor_Post_Up_Scale_Low, + (uint8_t) (pOverlay->HUSF)); + setvideoreg(Index_VI_Hor_Post_Up_Scale_High, + (uint8_t) ((pOverlay->HUSF) >> 8)); + setvideoreg(Index_VI_Ver_Up_Scale_Low, (uint8_t) (pOverlay->VUSF)); + setvideoreg(Index_VI_Ver_Up_Scale_High, + (uint8_t) ((pOverlay->VUSF) >> 8)); + + setvideoregmask(Index_VI_Scale_Control, (pOverlay->IntBit << 3) + | (pOverlay->wHPre), 0x7f); + + /* set destination window position */ + setvideoreg(Index_VI_Win_Hor_Disp_Start_Low, (uint8_t) left); + setvideoreg(Index_VI_Win_Hor_Disp_End_Low, (uint8_t) right); + setvideoreg(Index_VI_Win_Hor_Over, (uint8_t) h_over); + + setvideoreg(Index_VI_Win_Ver_Disp_Start_Low, (uint8_t) top); + setvideoreg(Index_VI_Win_Ver_Disp_End_Low, (uint8_t) bottom); + setvideoreg(Index_VI_Win_Ver_Over, (uint8_t) v_over); + + setvideoregmask(Index_VI_Control_Misc1, pOverlay->bobEnable, 0x1a); + + /* Lock the address registers */ + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x20); +} + + +/* TW: Overlay MUST NOT be switched off while beam is over it */ +static void close_overlay() +{ + uint32_t watchdog; + + if ((sis_displaymode == DISPMODE_SINGLE2) || + (sis_displaymode == DISPMODE_MIRROR)) { + if (sis_has_two_overlays) { + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x01); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT2() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT2()) && --watchdog); + setvideoregmask(Index_VI_Control_Misc0, 0x00, 0x02); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT2() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT2()) && --watchdog); + } else if (sis_displaymode == DISPMODE_SINGLE2) { + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x01); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT1() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT1()) && --watchdog); + setvideoregmask(Index_VI_Control_Misc0, 0x00, 0x02); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT1() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT1()) && --watchdog); + } + } + if ((sis_displaymode == DISPMODE_SINGLE1) || + (sis_displaymode == DISPMODE_MIRROR)) { + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x01); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT1() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT1()) && --watchdog); + setvideoregmask(Index_VI_Control_Misc0, 0x00, 0x02); + watchdog = WATCHDOG_DELAY; + while (vblank_active_CRT1() && --watchdog); + watchdog = WATCHDOG_DELAY; + while ((!vblank_active_CRT1()) && --watchdog); + } +} + + +static void +calc_scale_factor(SISOverlayPtr pOverlay, int index, int iscrt2) +{ + uint32_t i = 0, mult = 0; + int flag = 0; + + int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1; + int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1; + int srcW = pOverlay->srcW; + int srcH = pOverlay->srcH; + /* uint16_t LCDheight = pSiS->LCDheight; */ + int srcPitch = pOverlay->origPitch; + int origdstH = dstH; + + /* get rid of warnings for now */ + index = index; + iscrt2 = iscrt2; + +#if 0 /* JCP: don't bother with this for now. */ + /* TW: Stretch image due to idiotic LCD "auto"-scaling on LVDS (and 630+301B) */ + if (pSiS->VBFlags & CRT2_LCD) { + if (sis_bridge_is_slave) { + if (pSiS->VBFlags & VB_LVDS) { + dstH = (dstH * LCDheight) / pOverlay->SCREENheight; + } else if ((sis_vga_engine == SIS_300_VGA) && + (pSiS-> + VBFlags & (VB_301B | VB_302B | VB_301LV | + VB_302LV))) { + dstH = (dstH * LCDheight) / pOverlay->SCREENheight; + } + } else if (iscrt2) { + if (pSiS->VBFlags & VB_LVDS) { + dstH = (dstH * LCDheight) / pOverlay->SCREENheight; + if (sis_displaymode == DISPMODE_MIRROR) + flag = 1; + } else if ((sis_vga_engine == SIS_300_VGA) && + (pSiS-> + VBFlags & (VB_301B | VB_302B | VB_301LV | + VB_302LV))) { + dstH = (dstH * LCDheight) / pOverlay->SCREENheight; + if (sis_displaymode == DISPMODE_MIRROR) + flag = 1; + } + } + } +#endif + + /* TW: For double scan modes, we need to double the height + * (Perhaps we also need to scale LVDS, but I'm not sure.) + * On 310/325 series, we need to double the width as well. + * Interlace mode vice versa. + */ + if (sis_vmode & VMODE_DOUBLESCAN) { + dstH = origdstH << 1; + flag = 0; + if (sis_vga_engine == SIS_315_VGA) { + dstW <<= 1; + } + } + if (sis_vmode & VMODE_INTERLACED) { + dstH = origdstH >> 1; + flag = 0; + } + + if (dstW < OVERLAY_MIN_WIDTH) + dstW = OVERLAY_MIN_WIDTH; + if (dstW == srcW) { + pOverlay->HUSF = 0x00; + pOverlay->IntBit = 0x05; + pOverlay->wHPre = 0; + } else if (dstW > srcW) { + dstW += 2; + pOverlay->HUSF = (srcW << 16) / dstW; + pOverlay->IntBit = 0x04; + pOverlay->wHPre = 0; + } else { + int tmpW = dstW; + + /* TW: It seems, the hardware can't scale below factor .125 (=1/8) if the + pitch isn't a multiple of 256. + TODO: Test this on the 310/325 series! + */ + if ((srcPitch % 256) || (srcPitch < 256)) { + if (((dstW * 1000) / srcW) < 125) + dstW = tmpW = ((srcW * 125) / 1000) + 1; + } + + i = 0; + pOverlay->IntBit = 0x01; + while (srcW >= tmpW) { + tmpW <<= 1; + i++; + } + pOverlay->wHPre = (uint8_t) (i - 1); + dstW <<= (i - 1); + if ((srcW % dstW)) + pOverlay->HUSF = ((srcW - dstW) << 16) / dstW; + else + pOverlay->HUSF = 0x00; + } + + if (dstH < OVERLAY_MIN_HEIGHT) + dstH = OVERLAY_MIN_HEIGHT; + if (dstH == srcH) { + pOverlay->VUSF = 0x00; + pOverlay->IntBit |= 0x0A; + } else if (dstH > srcH) { + dstH += 0x02; + pOverlay->VUSF = (srcH << 16) / dstH; + pOverlay->IntBit |= 0x08; + } else { + uint32_t realI; + + i = realI = srcH / dstH; + pOverlay->IntBit |= 0x02; + + if (i < 2) { + pOverlay->VUSF = ((srcH - dstH) << 16) / dstH; + /* TW: Needed for LCD-scaling modes */ + if ((flag) && (mult = (srcH / origdstH)) >= 2) + pOverlay->pitch /= mult; + } else { +#if 0 + if (((pOverlay->bobEnable & 0x08) == 0x00) && + (((srcPitch * i) >> 2) > 0xFFF)) { + pOverlay->bobEnable |= 0x08; + srcPitch >>= 1; + } +#endif + if (((srcPitch * i) >> 2) > 0xFFF) { + i = (0xFFF * 2 / srcPitch); + pOverlay->VUSF = 0xFFFF; + } else { + dstH = i * dstH; + if (srcH % dstH) + pOverlay->VUSF = ((srcH - dstH) << 16) / dstH; + else + pOverlay->VUSF = 0x00; + } + /* set video frame buffer offset */ + pOverlay->pitch = (uint16_t) (srcPitch * i); + } + } +} + +static void set_line_buf_size(SISOverlayPtr pOverlay) +{ + uint8_t preHIDF; + uint32_t i; + uint32_t line = pOverlay->srcW; + + if ((pOverlay->pixelFormat == IMGFMT_YV12) || + (pOverlay->pixelFormat == IMGFMT_I420)) { + preHIDF = pOverlay->wHPre & 0x07; + switch (preHIDF) { + case 3: + if ((line & 0xffffff00) == line) + i = (line >> 8); + else + i = (line >> 8) + 1; + pOverlay->lineBufSize = (uint8_t) (i * 32 - 1); + break; + case 4: + if ((line & 0xfffffe00) == line) + i = (line >> 9); + else + i = (line >> 9) + 1; + pOverlay->lineBufSize = (uint8_t) (i * 64 - 1); + break; + case 5: + if ((line & 0xfffffc00) == line) + i = (line >> 10); + else + i = (line >> 10) + 1; + pOverlay->lineBufSize = (uint8_t) (i * 128 - 1); + break; + case 6: + if ((line & 0xfffff800) == line) + i = (line >> 11); + else + i = (line >> 11) + 1; + pOverlay->lineBufSize = (uint8_t) (i * 256 - 1); + break; + default: + if ((line & 0xffffff80) == line) + i = (line >> 7); + else + i = (line >> 7) + 1; + pOverlay->lineBufSize = (uint8_t) (i * 16 - 1); + break; + } + } else { /* YUV2, UYVY */ + if ((line & 0xffffff8) == line) + i = (line >> 3); + else + i = (line >> 3) + 1; + pOverlay->lineBufSize = (uint8_t) (i - 1); + } +} + +static void merge_line_buf(int enable) +{ + if (enable) { + switch (sis_displaymode) { + case DISPMODE_SINGLE1: + if (sis_has_two_overlays) { + /* dual line merge */ + setvideoregmask(Index_VI_Control_Misc2, 0x10, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } else { + setvideoregmask(Index_VI_Control_Misc2, 0x10, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } + break; + case DISPMODE_SINGLE2: + if (sis_has_two_overlays) { + /* line merge */ + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x04, 0x04); + } else { + setvideoregmask(Index_VI_Control_Misc2, 0x10, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } + break; + case DISPMODE_MIRROR: + default: + /* line merge */ + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x04, 0x04); + if (sis_has_two_overlays) { + /* line merge */ + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x04, 0x04); + } + break; + } + } else { + switch (sis_displaymode) { + case DISPMODE_SINGLE1: + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + break; + case DISPMODE_SINGLE2: + if (sis_has_two_overlays) { + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } else { + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } + break; + case DISPMODE_MIRROR: + default: + setvideoregmask(Index_VI_Control_Misc2, 0x00, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + if (sis_has_two_overlays) { + setvideoregmask(Index_VI_Control_Misc2, 0x01, 0x11); + setvideoregmask(Index_VI_Control_Misc1, 0x00, 0x04); + } + break; + } + } +} + + +static void set_format(SISOverlayPtr pOverlay) +{ + uint8_t fmt; + + switch (pOverlay->pixelFormat) { + case IMGFMT_YV12: + case IMGFMT_I420: + fmt = 0x0c; + break; + case IMGFMT_YUY2: + fmt = 0x28; + break; + case IMGFMT_UYVY: + fmt = 0x08; + break; + case IMGFMT_RGB15: /* D[5:4] : 00 RGB555, 01 RGB 565 */ + fmt = 0x00; + break; + case IMGFMT_RGB16: + fmt = 0x10; + break; + default: + fmt = 0x00; + break; + } + setvideoregmask(Index_VI_Control_Misc0, fmt, 0x7c); +} + +static void set_colorkey() +{ + uint8_t r, g, b; + + b = (uint8_t) sis_grkey.ckey.blue; + g = (uint8_t) sis_grkey.ckey.green; + r = (uint8_t) sis_grkey.ckey.red; + + /* set color key mode */ + setvideoregmask(Index_VI_Key_Overlay_OP, + sis_grkey.ckey.op == CKEY_TRUE ? + VI_ROP_DestKey : VI_ROP_Always, 0x0F); + + /* set colorkey values */ + setvideoreg(Index_VI_Overlay_ColorKey_Blue_Min, (uint8_t) b); + setvideoreg(Index_VI_Overlay_ColorKey_Green_Min, (uint8_t) g); + setvideoreg(Index_VI_Overlay_ColorKey_Red_Min, (uint8_t) r); + + setvideoreg(Index_VI_Overlay_ColorKey_Blue_Max, (uint8_t) b); + setvideoreg(Index_VI_Overlay_ColorKey_Green_Max, (uint8_t) g); + setvideoreg(Index_VI_Overlay_ColorKey_Red_Max, (uint8_t) r); +} + +static void set_brightness(uint8_t brightness) +{ + setvideoreg(Index_VI_Brightness, brightness); +} + +static void set_contrast(uint8_t contrast) +{ + setvideoregmask(Index_VI_Contrast_Enh_Ctrl, contrast, 0x07); +} + +/* Next 3 functions are 310/325 series only */ + +static void set_saturation(char saturation) +{ + uint8_t temp = 0; + + if (saturation < 0) { + temp |= 0x88; + saturation = -saturation; + } + temp |= (saturation & 0x07); + temp |= ((saturation & 0x07) << 4); + + setvideoreg(Index_VI_Saturation, temp); +} + +static void set_hue(uint8_t hue) +{ + setvideoreg(Index_VI_Hue, (hue & 0x08) ? (hue ^ 0x07) : hue); +} + +#if 0 +/* JCP: not used (I don't think it's correct anyway) */ +static void set_alpha(uint8_t alpha) +{ + uint8_t data; + + data = getvideoreg(Index_VI_Key_Overlay_OP); + data &= 0x0F; + setvideoreg(Index_VI_Key_Overlay_OP, data | (alpha << 4)); +} +#endif