| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* This file is part of the coreboot project. */ |
| |
| /* |
| * Code taken from the Linux xgifb driver (v3.18.5) |
| * Select functions taken from the Linux xgifb driver file XGI_main_26.c |
| * |
| * Original file header: |
| * XG20, XG21, XG40, XG42 frame buffer device |
| * for Linux kernels 2.5.x, 2.6.x |
| * Base on TW's sis fbdev code. |
| */ |
| |
| |
| #define Index_CR_GPIO_Reg1 0x48 |
| #define Index_CR_GPIO_Reg3 0x4a |
| |
| #define GPIOG_EN (1<<6) |
| #define GPIOG_READ (1<<1) |
| |
| // static char *mode; |
| static int vesa = -1; |
| static unsigned int refresh_rate; |
| |
| /* ---------------- Chip generation dependent routines ---------------- */ |
| |
| /* for XGI 315/550/650/740/330 */ |
| |
| static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info) |
| { |
| |
| u8 ChannelNum, tmp; |
| u8 reg = 0; |
| |
| /* xorg driver sets 32MB * 1 channel */ |
| if (xgifb_info->chip == XG27) |
| xgifb_reg_set(XGISR, IND_SIS_DRAM_SIZE, 0x51); |
| |
| reg = xgifb_reg_get(XGISR, IND_SIS_DRAM_SIZE); |
| if (!reg) |
| return -1; |
| |
| switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) { |
| case XGI_DRAM_SIZE_1MB: |
| xgifb_info->video_size = 0x100000; |
| break; |
| case XGI_DRAM_SIZE_2MB: |
| xgifb_info->video_size = 0x200000; |
| break; |
| case XGI_DRAM_SIZE_4MB: |
| xgifb_info->video_size = 0x400000; |
| break; |
| case XGI_DRAM_SIZE_8MB: |
| xgifb_info->video_size = 0x800000; |
| break; |
| case XGI_DRAM_SIZE_16MB: |
| xgifb_info->video_size = 0x1000000; |
| break; |
| case XGI_DRAM_SIZE_32MB: |
| xgifb_info->video_size = 0x2000000; |
| break; |
| case XGI_DRAM_SIZE_64MB: |
| xgifb_info->video_size = 0x4000000; |
| break; |
| case XGI_DRAM_SIZE_128MB: |
| xgifb_info->video_size = 0x8000000; |
| break; |
| case XGI_DRAM_SIZE_256MB: |
| xgifb_info->video_size = 0x10000000; |
| break; |
| default: |
| return -1; |
| } |
| |
| tmp = (reg & 0x0c) >> 2; |
| switch (xgifb_info->chip) { |
| case XG20: |
| case XG21: |
| case XG27: |
| ChannelNum = 1; |
| break; |
| |
| case XG42: |
| if (reg & 0x04) |
| ChannelNum = 2; |
| else |
| ChannelNum = 1; |
| break; |
| |
| case XG40: |
| default: |
| if (tmp == 2) |
| ChannelNum = 2; |
| else if (tmp == 3) |
| ChannelNum = 3; |
| else |
| ChannelNum = 1; |
| break; |
| } |
| |
| xgifb_info->video_size = xgifb_info->video_size * ChannelNum; |
| |
| pr_info("SR14=%x DramSize %x ChannelNum %x\n", |
| reg, |
| xgifb_info->video_size, ChannelNum); |
| return 0; |
| |
| } |
| |
| void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr) |
| { |
| XGI_Pr->P3c4 = BaseAddr + 0x14; |
| XGI_Pr->P3d4 = BaseAddr + 0x24; |
| XGI_Pr->P3c0 = BaseAddr + 0x10; |
| XGI_Pr->P3ce = BaseAddr + 0x1e; |
| XGI_Pr->P3c2 = BaseAddr + 0x12; |
| XGI_Pr->P3cc = BaseAddr + 0x1c; |
| XGI_Pr->P3ca = BaseAddr + 0x1a; |
| XGI_Pr->P3c6 = BaseAddr + 0x16; |
| XGI_Pr->P3c7 = BaseAddr + 0x17; |
| XGI_Pr->P3c8 = BaseAddr + 0x18; |
| XGI_Pr->P3c9 = BaseAddr + 0x19; |
| XGI_Pr->P3da = BaseAddr + 0x2A; |
| XGI_Pr->Part0Port = BaseAddr + XGI_CRT2_PORT_00; |
| /* Digital video interface registers (LCD) */ |
| XGI_Pr->Part1Port = BaseAddr + SIS_CRT2_PORT_04; |
| /* 301 TV Encoder registers */ |
| XGI_Pr->Part2Port = BaseAddr + SIS_CRT2_PORT_10; |
| /* 301 Macrovision registers */ |
| XGI_Pr->Part3Port = BaseAddr + SIS_CRT2_PORT_12; |
| /* 301 VGA2 (and LCD) registers */ |
| XGI_Pr->Part4Port = BaseAddr + SIS_CRT2_PORT_14; |
| /* 301 palette address port registers */ |
| XGI_Pr->Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; |
| |
| } |
| |
| /* ------------------ Internal helper routines ----------------- */ |
| |
| static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info) |
| { |
| int i = 0; |
| |
| while ((XGIbios_mode[i].mode_no != 0) |
| && (XGIbios_mode[i].xres <= xgifb_info->lvds_data.LVDSHDE)) { |
| if ((XGIbios_mode[i].xres == xgifb_info->lvds_data.LVDSHDE) |
| && (XGIbios_mode[i].yres == xgifb_info->lvds_data.LVDSVDE) |
| && (XGIbios_mode[i].bpp == 8)) { |
| return i; |
| } |
| i++; |
| } |
| |
| return -1; |
| } |
| |
| static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info, |
| unsigned int rate) |
| { |
| u16 xres, yres; |
| int i = 0; |
| |
| xres = XGIbios_mode[xgifb_info->mode_idx].xres; |
| yres = XGIbios_mode[xgifb_info->mode_idx].yres; |
| |
| xgifb_info->rate_idx = 0; |
| while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) { |
| if ((XGIfb_vrate[i].xres == xres) && |
| (XGIfb_vrate[i].yres == yres)) { |
| if (XGIfb_vrate[i].refresh == rate) { |
| xgifb_info->rate_idx = XGIfb_vrate[i].idx; |
| break; |
| } else if (XGIfb_vrate[i].refresh > rate) { |
| if ((XGIfb_vrate[i].refresh - rate) <= 3) { |
| pr_debug("Adjusting rate from %d up to %d\n", |
| rate, XGIfb_vrate[i].refresh); |
| xgifb_info->rate_idx = |
| XGIfb_vrate[i].idx; |
| xgifb_info->refresh_rate = |
| XGIfb_vrate[i].refresh; |
| } else if (((rate - XGIfb_vrate[i - 1].refresh) |
| <= 2) && (XGIfb_vrate[i].idx |
| != 1)) { |
| pr_debug("Adjusting rate from %d down to %d\n", |
| rate, |
| XGIfb_vrate[i-1].refresh); |
| xgifb_info->rate_idx = |
| XGIfb_vrate[i - 1].idx; |
| xgifb_info->refresh_rate = |
| XGIfb_vrate[i - 1].refresh; |
| } |
| break; |
| } else if ((rate - XGIfb_vrate[i].refresh) <= 2) { |
| pr_debug("Adjusting rate from %d down to %d\n", |
| rate, XGIfb_vrate[i].refresh); |
| xgifb_info->rate_idx = XGIfb_vrate[i].idx; |
| break; |
| } |
| } |
| i++; |
| } |
| if (xgifb_info->rate_idx > 0) |
| return xgifb_info->rate_idx; |
| pr_info("Unsupported rate %d for %dx%d\n", |
| rate, xres, yres); |
| return 0; |
| } |
| |
| static void XGIfb_detect_VB(struct xgifb_video_info *xgifb_info) |
| { |
| u8 cr32, temp = 0; |
| |
| xgifb_info->TV_plug = xgifb_info->TV_type = 0; |
| |
| cr32 = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR32); |
| |
| if ((cr32 & SIS_CRT1) && !XGIfb_crt1off) |
| XGIfb_crt1off = 0; |
| else { |
| if (cr32 & 0x5F) |
| XGIfb_crt1off = 1; |
| else |
| XGIfb_crt1off = 0; |
| } |
| |
| if (!xgifb_info->display2_force) { |
| if (cr32 & SIS_VB_TV) |
| xgifb_info->display2 = XGIFB_DISP_TV; |
| else if (cr32 & SIS_VB_LCD) |
| xgifb_info->display2 = XGIFB_DISP_LCD; |
| else if (cr32 & SIS_VB_CRT2) |
| xgifb_info->display2 = XGIFB_DISP_CRT; |
| else |
| xgifb_info->display2 = XGIFB_DISP_NONE; |
| } |
| |
| if (XGIfb_tvplug != -1) |
| /* Override with option */ |
| xgifb_info->TV_plug = XGIfb_tvplug; |
| else if (cr32 & SIS_VB_HIVISION) { |
| xgifb_info->TV_type = TVMODE_HIVISION; |
| xgifb_info->TV_plug = TVPLUG_SVIDEO; |
| } else if (cr32 & SIS_VB_SVIDEO) |
| xgifb_info->TV_plug = TVPLUG_SVIDEO; |
| else if (cr32 & SIS_VB_COMPOSITE) |
| xgifb_info->TV_plug = TVPLUG_COMPOSITE; |
| else if (cr32 & SIS_VB_SCART) |
| xgifb_info->TV_plug = TVPLUG_SCART; |
| |
| if (xgifb_info->TV_type == 0) { |
| temp = xgifb_reg_get(XGICR, 0x38); |
| if (temp & 0x10) |
| xgifb_info->TV_type = TVMODE_PAL; |
| else |
| xgifb_info->TV_type = TVMODE_NTSC; |
| } |
| |
| /* Copy forceCRT1 option to CRT1off if option is given */ |
| if (XGIfb_forcecrt1 != -1) { |
| if (XGIfb_forcecrt1) |
| XGIfb_crt1off = 0; |
| else |
| XGIfb_crt1off = 1; |
| } |
| } |
| |
| static int XGIfb_has_VB(struct xgifb_video_info *xgifb_info) |
| { |
| u8 vb_chipid; |
| |
| vb_chipid = xgifb_reg_get(XGIPART4, 0x00); |
| switch (vb_chipid) { |
| case 0x01: |
| xgifb_info->hasVB = HASVB_301; |
| break; |
| case 0x02: |
| xgifb_info->hasVB = HASVB_302; |
| break; |
| default: |
| xgifb_info->hasVB = HASVB_NONE; |
| return 0; |
| } |
| return 1; |
| } |
| |
| static void XGIfb_get_VB_type(struct xgifb_video_info *xgifb_info) |
| { |
| u8 reg; |
| |
| if (!XGIfb_has_VB(xgifb_info)) { |
| reg = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR37); |
| switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) { |
| case SIS_EXTERNAL_CHIP_LVDS: |
| xgifb_info->hasVB = HASVB_LVDS; |
| break; |
| case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: |
| xgifb_info->hasVB = HASVB_LVDS_CHRONTEL; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| #if 0 |
| static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info, |
| const char *name) |
| { |
| unsigned int xres; |
| unsigned int yres; |
| unsigned int bpp; |
| int i; |
| |
| if (sscanf(name, "%ux%ux%u", &xres, &yres, &bpp) != 3) |
| goto invalid_mode; |
| |
| if (bpp == 24) |
| bpp = 32; /* That's for people who mix up color and fb depth. */ |
| |
| for (i = 0; XGIbios_mode[i].mode_no != 0; i++) |
| if (XGIbios_mode[i].xres == xres && |
| XGIbios_mode[i].yres == yres && |
| XGIbios_mode[i].bpp == bpp) { |
| xgifb_info->mode_idx = i; |
| return; |
| } |
| invalid_mode: |
| pr_info("Invalid mode '%s'\n", name); |
| } |
| #endif |
| |
| static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info, |
| unsigned int vesamode) |
| { |
| int i = 0; |
| |
| if (vesamode == 0) |
| goto invalid; |
| |
| vesamode &= 0x1dff; /* Clean VESA mode number from other flags */ |
| |
| while (XGIbios_mode[i].mode_no != 0) { |
| if ((XGIbios_mode[i].vesa_mode_no_1 == vesamode) || |
| (XGIbios_mode[i].vesa_mode_no_2 == vesamode)) { |
| xgifb_info->mode_idx = i; |
| return; |
| } |
| i++; |
| } |
| |
| invalid: |
| pr_info("Invalid VESA mode 0x%x'\n", vesamode); |
| } |
| |
| static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) |
| { |
| u16 xres, yres; |
| struct xgi_hw_device_info *hw_info = &xgifb_info->hw_info; |
| unsigned long required_mem; |
| |
| if (xgifb_info->chip == XG21) { |
| if (xgifb_info->display2 == XGIFB_DISP_LCD) { |
| xres = xgifb_info->lvds_data.LVDSHDE; |
| yres = xgifb_info->lvds_data.LVDSVDE; |
| if (XGIbios_mode[myindex].xres > xres) |
| return -1; |
| if (XGIbios_mode[myindex].yres > yres) |
| return -1; |
| if ((XGIbios_mode[myindex].xres < xres) && |
| (XGIbios_mode[myindex].yres < yres)) { |
| if (XGIbios_mode[myindex].bpp > 8) |
| return -1; |
| } |
| |
| } |
| goto check_memory; |
| |
| } |
| |
| /* FIXME: for now, all is valid on XG27 */ |
| if (xgifb_info->chip == XG27) |
| goto check_memory; |
| |
| if (!(XGIbios_mode[myindex].chipset & MD_XGI315)) |
| return -1; |
| |
| switch (xgifb_info->display2) { |
| case XGIFB_DISP_LCD: |
| switch (hw_info->ulCRT2LCDType) { |
| case LCD_640x480: |
| xres = 640; |
| yres = 480; |
| break; |
| case LCD_800x600: |
| xres = 800; |
| yres = 600; |
| break; |
| case LCD_1024x600: |
| xres = 1024; |
| yres = 600; |
| break; |
| case LCD_1024x768: |
| xres = 1024; |
| yres = 768; |
| break; |
| case LCD_1152x768: |
| xres = 1152; |
| yres = 768; |
| break; |
| case LCD_1280x960: |
| xres = 1280; |
| yres = 960; |
| break; |
| case LCD_1280x768: |
| xres = 1280; |
| yres = 768; |
| break; |
| case LCD_1280x1024: |
| xres = 1280; |
| yres = 1024; |
| break; |
| case LCD_1400x1050: |
| xres = 1400; |
| yres = 1050; |
| break; |
| case LCD_1600x1200: |
| xres = 1600; |
| yres = 1200; |
| break; |
| default: |
| xres = 0; |
| yres = 0; |
| break; |
| } |
| if (XGIbios_mode[myindex].xres > xres) |
| return -1; |
| if (XGIbios_mode[myindex].yres > yres) |
| return -1; |
| if ((hw_info->ulExternalChip == 0x01) || /* LVDS */ |
| (hw_info->ulExternalChip == 0x05)) { /* LVDS+Chrontel */ |
| switch (XGIbios_mode[myindex].xres) { |
| case 512: |
| if (XGIbios_mode[myindex].yres != 512) |
| return -1; |
| if (hw_info->ulCRT2LCDType == LCD_1024x600) |
| return -1; |
| break; |
| case 640: |
| if ((XGIbios_mode[myindex].yres != 400) |
| && (XGIbios_mode[myindex].yres |
| != 480)) |
| return -1; |
| break; |
| case 800: |
| if (XGIbios_mode[myindex].yres != 600) |
| return -1; |
| break; |
| case 1024: |
| if ((XGIbios_mode[myindex].yres != 600) && |
| (XGIbios_mode[myindex].yres != 768)) |
| return -1; |
| if ((XGIbios_mode[myindex].yres == 600) && |
| (hw_info->ulCRT2LCDType != LCD_1024x600)) |
| return -1; |
| break; |
| case 1152: |
| if ((XGIbios_mode[myindex].yres) != 768) |
| return -1; |
| if (hw_info->ulCRT2LCDType != LCD_1152x768) |
| return -1; |
| break; |
| case 1280: |
| if ((XGIbios_mode[myindex].yres != 768) && |
| (XGIbios_mode[myindex].yres != 1024)) |
| return -1; |
| if ((XGIbios_mode[myindex].yres == 768) && |
| (hw_info->ulCRT2LCDType != LCD_1280x768)) |
| return -1; |
| break; |
| case 1400: |
| if (XGIbios_mode[myindex].yres != 1050) |
| return -1; |
| break; |
| case 1600: |
| if (XGIbios_mode[myindex].yres != 1200) |
| return -1; |
| break; |
| default: |
| return -1; |
| } |
| } else { |
| switch (XGIbios_mode[myindex].xres) { |
| case 512: |
| if (XGIbios_mode[myindex].yres != 512) |
| return -1; |
| break; |
| case 640: |
| if ((XGIbios_mode[myindex].yres != 400) && |
| (XGIbios_mode[myindex].yres != 480)) |
| return -1; |
| break; |
| case 800: |
| if (XGIbios_mode[myindex].yres != 600) |
| return -1; |
| break; |
| case 1024: |
| if (XGIbios_mode[myindex].yres != 768) |
| return -1; |
| break; |
| case 1280: |
| if ((XGIbios_mode[myindex].yres != 960) && |
| (XGIbios_mode[myindex].yres != 1024)) |
| return -1; |
| if (XGIbios_mode[myindex].yres == 960) { |
| if (hw_info->ulCRT2LCDType == |
| LCD_1400x1050) |
| return -1; |
| } |
| break; |
| case 1400: |
| if (XGIbios_mode[myindex].yres != 1050) |
| return -1; |
| break; |
| case 1600: |
| if (XGIbios_mode[myindex].yres != 1200) |
| return -1; |
| break; |
| default: |
| return -1; |
| } |
| } |
| break; |
| case XGIFB_DISP_TV: |
| switch (XGIbios_mode[myindex].xres) { |
| case 512: |
| case 640: |
| case 800: |
| break; |
| case 720: |
| if (xgifb_info->TV_type == TVMODE_NTSC) { |
| if (XGIbios_mode[myindex].yres != 480) |
| return -1; |
| } else if (xgifb_info->TV_type == TVMODE_PAL) { |
| if (XGIbios_mode[myindex].yres != 576) |
| return -1; |
| } |
| /* LVDS/CHRONTEL does not support 720 */ |
| if (xgifb_info->hasVB == HASVB_LVDS_CHRONTEL || |
| xgifb_info->hasVB == HASVB_CHRONTEL) { |
| return -1; |
| } |
| break; |
| case 1024: |
| if (xgifb_info->TV_type == TVMODE_NTSC) { |
| if (XGIbios_mode[myindex].bpp == 32) |
| return -1; |
| } |
| break; |
| default: |
| return -1; |
| } |
| break; |
| case XGIFB_DISP_CRT: |
| if (XGIbios_mode[myindex].xres > 1280) |
| return -1; |
| break; |
| case XGIFB_DISP_NONE: |
| break; |
| } |
| |
| check_memory: |
| required_mem = XGIbios_mode[myindex].xres * XGIbios_mode[myindex].yres * |
| XGIbios_mode[myindex].bpp / 8; |
| if (required_mem > xgifb_info->video_size) |
| return -1; |
| return myindex; |
| |
| } |
| |
| /* --------------------- SetMode routines ------------------------- */ |
| |
| static void XGIfb_pre_setmode(struct xgifb_video_info *xgifb_info) |
| { |
| u8 cr30 = 0, cr31 = 0; |
| |
| cr31 = xgifb_reg_get(XGICR, 0x31); |
| cr31 &= ~0x60; |
| |
| switch (xgifb_info->display2) { |
| case XGIFB_DISP_CRT: |
| cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| cr31 |= SIS_DRIVER_MODE; |
| break; |
| case XGIFB_DISP_LCD: |
| cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| cr31 |= SIS_DRIVER_MODE; |
| break; |
| case XGIFB_DISP_TV: |
| if (xgifb_info->TV_type == TVMODE_HIVISION) |
| cr30 = (SIS_VB_OUTPUT_HIVISION |
| | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| else if (xgifb_info->TV_plug == TVPLUG_SVIDEO) |
| cr30 = (SIS_VB_OUTPUT_SVIDEO |
| | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| else if (xgifb_info->TV_plug == TVPLUG_COMPOSITE) |
| cr30 = (SIS_VB_OUTPUT_COMPOSITE |
| | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| else if (xgifb_info->TV_plug == TVPLUG_SCART) |
| cr30 = (SIS_VB_OUTPUT_SCART |
| | SIS_SIMULTANEOUS_VIEW_ENABLE); |
| cr31 |= SIS_DRIVER_MODE; |
| |
| if (XGIfb_tvmode == 1 || xgifb_info->TV_type == TVMODE_PAL) |
| cr31 |= 0x01; |
| else |
| cr31 &= ~0x01; |
| break; |
| default: /* disable CRT2 */ |
| cr30 = 0x00; |
| cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE); |
| } |
| |
| xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR30, cr30); |
| xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR31, cr31); |
| xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR33, |
| (xgifb_info->rate_idx & 0x0F)); |
| } |
| |
| static void XGIfb_post_setmode(struct xgifb_video_info *xgifb_info) |
| { |
| u8 reg; |
| unsigned char doit = 1; |
| |
| if (xgifb_info->video_bpp == 8) { |
| /* |
| * We can't switch off CRT1 on LVDS/Chrontel |
| * in 8bpp Modes |
| */ |
| if ((xgifb_info->hasVB == HASVB_LVDS) || |
| (xgifb_info->hasVB == HASVB_LVDS_CHRONTEL)) { |
| doit = 0; |
| } |
| /* |
| * We can't switch off CRT1 on 301B-DH |
| * in 8bpp Modes if using LCD |
| */ |
| if (xgifb_info->display2 == XGIFB_DISP_LCD) |
| doit = 0; |
| } |
| |
| /* We can't switch off CRT1 if bridge is in slave mode */ |
| if (xgifb_info->hasVB != HASVB_NONE) { |
| reg = xgifb_reg_get(XGIPART1, 0x00); |
| |
| if ((reg & 0x50) == 0x10) |
| doit = 0; |
| |
| } else { |
| XGIfb_crt1off = 0; |
| } |
| |
| reg = xgifb_reg_get(XGICR, 0x17); |
| if ((XGIfb_crt1off) && (doit)) |
| reg &= ~0x80; |
| else |
| reg |= 0x80; |
| xgifb_reg_set(XGICR, 0x17, reg); |
| |
| xgifb_reg_and(XGISR, IND_SIS_RAMDAC_CONTROL, ~0x04); |
| |
| if (xgifb_info->display2 == XGIFB_DISP_TV && |
| xgifb_info->hasVB == HASVB_301) { |
| |
| reg = xgifb_reg_get(XGIPART4, 0x01); |
| |
| if (reg < 0xB0) { /* Set filter for XGI301 */ |
| int filter_tb; |
| |
| switch (xgifb_info->video_width) { |
| case 320: |
| filter_tb = (xgifb_info->TV_type == |
| TVMODE_NTSC) ? 4 : 12; |
| break; |
| case 640: |
| filter_tb = (xgifb_info->TV_type == |
| TVMODE_NTSC) ? 5 : 13; |
| break; |
| case 720: |
| filter_tb = (xgifb_info->TV_type == |
| TVMODE_NTSC) ? 6 : 14; |
| break; |
| case 800: |
| filter_tb = (xgifb_info->TV_type == |
| TVMODE_NTSC) ? 7 : 15; |
| break; |
| default: |
| filter_tb = 0; |
| filter = -1; |
| break; |
| } |
| xgifb_reg_or(XGIPART1, |
| SIS_CRT2_WENABLE_315, |
| 0x01); |
| |
| if (xgifb_info->TV_type == TVMODE_NTSC) { |
| |
| xgifb_reg_and(XGIPART2, 0x3a, 0x1f); |
| |
| if (xgifb_info->TV_plug == TVPLUG_SVIDEO) { |
| |
| xgifb_reg_and(XGIPART2, 0x30, 0xdf); |
| |
| } else if (xgifb_info->TV_plug |
| == TVPLUG_COMPOSITE) { |
| |
| xgifb_reg_or(XGIPART2, 0x30, 0x20); |
| |
| switch (xgifb_info->video_width) { |
| case 640: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xEB); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0x04); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x25); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0x18); |
| break; |
| case 720: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xEE); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0x0C); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x22); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0x08); |
| break; |
| case 800: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xEB); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0x15); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x25); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0xF6); |
| break; |
| } |
| } |
| |
| } else if (xgifb_info->TV_type == TVMODE_PAL) { |
| |
| xgifb_reg_and(XGIPART2, 0x3A, 0x1F); |
| |
| if (xgifb_info->TV_plug == TVPLUG_SVIDEO) { |
| |
| xgifb_reg_and(XGIPART2, 0x30, 0xDF); |
| |
| } else if (xgifb_info->TV_plug |
| == TVPLUG_COMPOSITE) { |
| |
| xgifb_reg_or(XGIPART2, 0x30, 0x20); |
| |
| switch (xgifb_info->video_width) { |
| case 640: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xF1); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0xF7); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x1F); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0x32); |
| break; |
| case 720: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xF3); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0x00); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x1D); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0x20); |
| break; |
| case 800: |
| xgifb_reg_set(XGIPART2, |
| 0x35, |
| 0xFC); |
| xgifb_reg_set(XGIPART2, |
| 0x36, |
| 0xFB); |
| xgifb_reg_set(XGIPART2, |
| 0x37, |
| 0x14); |
| xgifb_reg_set(XGIPART2, |
| 0x38, |
| 0x2A); |
| break; |
| } |
| } |
| } |
| |
| if ((filter >= 0) && (filter <= 7)) { |
| pr_debug("FilterTable[%d]-%d: %*ph\n", |
| filter_tb, filter, |
| 4, XGI_TV_filter[filter_tb]. |
| filter[filter]); |
| xgifb_reg_set( |
| XGIPART2, |
| 0x35, |
| (XGI_TV_filter[filter_tb]. |
| filter[filter][0])); |
| xgifb_reg_set( |
| XGIPART2, |
| 0x36, |
| (XGI_TV_filter[filter_tb]. |
| filter[filter][1])); |
| xgifb_reg_set( |
| XGIPART2, |
| 0x37, |
| (XGI_TV_filter[filter_tb]. |
| filter[filter][2])); |
| xgifb_reg_set( |
| XGIPART2, |
| 0x38, |
| (XGI_TV_filter[filter_tb]. |
| filter[filter][3])); |
| } |
| } |
| } |
| } |