From: Geert U. <ge...@li...> - 2007-04-30 08:38:07
|
---------- Forwarded message ---------- Date: Mon, 30 Apr 2007 13:20:59 +0800 From: Ed...@vi... To: lin...@li... Subject: [Linux-fbdev-devel] [PATCH 11/12] viafb: Framebuffer driver for VIA UniChrome/Chrome9 HC Dear All, Here is the part 11/12 of viafb. Best Regards, Eddy Fu diff -Nur linux-2.6.21-rc7/drivers/video/via/tv.c linux-2.6.21-rc7.viafb/drivers/video/via/tv.c --- linux-2.6.21-rc7/drivers/video/via/tv.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.21-rc7.viafb/drivers/video/via/tv.c 2007-04-26 19:52:32.000000000 -0400 @@ -0,0 +1,1567 @@ +/* + * Copyright 1998-2007 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2007 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#include <linux/config.h> +#endif +#include <linux/ioport.h> +#include <asm/io.h> + +#include "tv.h" +#include "chip.h" +#include "share.h" +#include "debug.h" +#include "ioctl.h" +#include "IntegratedTV.h" + +/* TV Encoder Extern Function */ +extern void vt1622_tv_disable(void); +extern void vt1622_tv_enable(void); +extern void load_vt1622_regs(int TVModeIndex); +extern int vt1622_tv_encoder_identify(void); +extern int vt1622_sense(void); +extern int vt1622_auto_sense(void); + +extern void vt1622a_tv_disable(void); +extern void vt1622a_tv_enable(void); +extern void load_vt1622a_regs(int TVModeIndex); +extern int vt1622a_tv_encoder_identify(void); +extern int vt1622a_sense(void); +extern int vt1622a_auto_sense(void); + +extern void vt1625_tv_disable(void); +extern void vt1625_tv_enable(void); +extern void load_vt1625_regs(int TVModeIndex); +extern int vt1625_tv_encoder_identify(void); +extern int vt1625_sense(void); +extern int vt1625_auto_sense(void); +extern void init_tv_vt1625(void); + +extern int integrated_tv_encoder_identify(void); +extern void integrated_tv_enable(void); +extern void integrated_tv_disable(void); +extern void set_integrated_tv_mode(int tv_mode_index); +extern void get_integrated_tv_default_status(void); +extern int get_integrated_tv_ffilter_status(int filter_type, int* filter_state); +extern void get_integrated_tv_pos(u32* current_hpos, u32* current_vpos); +extern void set_integrated_tv_ffilter_status(int filter_type, int filter_on_off, u32 desired_value); +extern void set_integrated_tv_hue(u32 desired_value); +extern void set_integrated_tv_brightness(u32 desired_value); +extern void set_integrated_tv_pos(u32 desired_hpos, u32 desired_vpos); +extern void set_integrated_tv_size(u32 desired_hsize, u32 desired_vsize); +extern int integrated_tv_sense(void); + + +extern void SetVCLK(u32 CLK, int set_iga); +extern inline void write_reg(u8 index, u16 io_port, u8 data); +extern void write_reg_mask(u8 index, int io_port, u8 data, u8 mask); +extern int i2cWriteByte(u8 bSlaveAddress, u8 bIndex, u8 bData); +extern int i2cReadByte(u8 bSlaveAddress, u8 bIndex, u8 *pbData); +extern void set_output_path(int device, int set_iga, int output_interface); +extern inline u8 read_reg(int io_port, u8 index); +extern void load_FIFO_reg(int set_iga, int hor_active, int ver_active); +extern void set_color_depth(int bpp_byte, int set_iga); +extern void set_integrated_tv_contrast(u32 desired_value); +extern void set_integrated_tv_saturation(u32 desired_value); + +bool is_tv_mode(struct tv_chip_information* ptv_chip_info, struct tv_setting_information* ptv_setting_info, + int video_index); +bool is_vt1625_mode(struct tv_chip_information* ptv_chip_info, struct tv_setting_information* ptv_setting_info, + int video_index); + +/* extern struct */ +extern struct chip_information chip_info; +extern struct tv_setting_information tv_setting_info; + +extern int HotPlug_TV; + +extern long tv_ffilter; +extern long tv_brightness; +extern long tv_contrast; +extern long tv_saturation; +extern long tv_tint; +extern long tv_pos_hor_current; +extern long tv_pos_ver_current; + +int tv_encoder_identify(void) +{ + chip_info.tv_chip_info.tv_chip_name = VT1622; + chip_info.tv_chip_info.tv_chip_slave_addr = VT1622_TV_I2C_ADDR; + + if (vt1622_tv_encoder_identify()!= FAIL) + { + DEBUG_MSG(KERN_INFO "\n VT1622 VT1622 ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + return(OK); + } + + chip_info.tv_chip_info.tv_chip_name = VT1622A; + chip_info.tv_chip_info.tv_chip_slave_addr = VT1622A_TV_I2C_ADDR; + + if (vt1622a_tv_encoder_identify()!= FAIL) + { + DEBUG_MSG(KERN_INFO "\n VT1622A VT1622A ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + return(OK); + } + + chip_info.tv_chip_info.tv_chip_name = VT1625; + chip_info.tv_chip_info.tv_chip_slave_addr = VT1625_TV_I2C_ADDR; + + if (vt1625_tv_encoder_identify()!= FAIL) + { + DEBUG_MSG(KERN_INFO "\n VT1625 VT1625 ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", chip_info.tv_chip_info.tv_chip_name); + return(OK); + } + + /* Check for VT3324 integrated TV. */ + chip_info.tv_chip_info.tv_chip_name = INTEGRATED_TV; + + if (integrated_tv_encoder_identify() != FAIL) + { + chip_info.tv_chip_info.output_interface = INTERFACE_NONE; + DEBUG_MSG(KERN_INFO "\n Found Integrated TV ! \n"); + return OK; + } + + + + chip_info.tv_chip_info.tv_chip_name = NON_TV_ENCODER; + chip_info.tv_chip_info.tv_chip_slave_addr = NON_TV_ENCODER; + return(FAIL); +} + +void tv_disable(void) +{ + /* Disable HW Reset */ + outb(0x6b,VIACR); + outb(0,VIACR+1); /* clear CR6B=0 */ + outb(0x6c,VIACR); + outb(0,VIACR+1); /* clear CR6C=0 */ + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + vt1622_tv_disable(); + break; + + case VT1622A: + vt1622a_tv_disable(); + break; + + case VT1625: + vt1625_tv_disable(); + break; + + case INTEGRATED_TV: + integrated_tv_disable(); + break; + + } +} + +void tv_load_timing_init(void) +{ + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + break; + + case VT1622A: + break; + + case VT1625: + init_tv_vt1625(); + break; + + } +} + +void VIAPitchAlignmentPatch(void) +{ + unsigned char cr13, cr35, cr65, cr66, cr67; + unsigned long dwScreenPitch= 0; + unsigned long dwPitch; + + dwPitch = tv_setting_info.h_active * (tv_setting_info.bpp >> 3); + dwPitch = tv_setting_info.h_active *(tv_setting_info.bpp>> 3); + if (dwPitch & 0x1F) + { /* Is 32 Byte Alignment ? */ + dwScreenPitch = ((dwPitch + 31) & ~31) >> 3; + if ( tv_setting_info.iga_path==IGA2) + { + if(tv_setting_info.bpp>8) { + /* When 8bpp 720xX,848xX will not do 32Byte alignment. */ + cr66 = (unsigned char)(dwScreenPitch & 0xFF); + write_reg(CR66, VIACR, cr66); + cr67 = read_reg(VIACR, CR67) & 0xFC; + cr67 |= (unsigned char)((dwScreenPitch & 0x300) >> 8); + write_reg(CR67, VIACR, cr67); + } + + /* Fetch Count */ + cr67 = read_reg(VIACR, CR67) & 0xF3; + cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7); + write_reg(CR67, VIACR, cr67); + cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF); + cr65 += 2; + write_reg(CR65, VIACR, cr65); + } + else + { + if(tv_setting_info.bpp>8) { + /* When 8bpp 720xX,848xX will not do 32Byte alignment. */ + cr13 = (unsigned char)(dwScreenPitch & 0xFF); + write_reg(CR13, VIACR, cr13); + cr35 = read_reg(VIACR, CR35) & 0x1F; + cr35 |= (unsigned char)((dwScreenPitch & 0x700) >> 3); + write_reg(CR35, VIACR, cr35); + } + } + } +} +void tv_load_timing(int TVModeIndex) +{ + unsigned char cr65, cr66, cr67; + unsigned char cr13, cr35, sr1c, sr1d; + int countWidthByQWord, offsetWidthByQWord; + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + load_vt1622_regs(TVModeIndex); + break; + + case VT1622A: + load_vt1622a_regs(TVModeIndex); + break; + + case VT1625: + load_vt1625_regs(TVModeIndex); + break; + + case INTEGRATED_TV: + set_integrated_tv_mode(TVModeIndex); + break; + + } + + /* Set Quadword offset,counter of primary and secondary screen.Fix colorkey + problem when using CRT+TV SAMM state. Not consider using virtual desktop */ + offsetWidthByQWord = (tv_setting_info.h_active*(tv_setting_info.bpp>> 3)) >> 3; + countWidthByQWord = (tv_setting_info.h_active *(tv_setting_info.bpp>> 3)) >> 3; + + if(tv_setting_info.iga_path==IGA2) + { + cr67 = read_reg(VIACR, CR67) & 0xFC; + cr66 = offsetWidthByQWord & 0xFF; + cr67 |= (offsetWidthByQWord & 0x300) >> 8; + + write_reg(CR66, VIACR, cr66); + write_reg(CR67, VIACR, cr67); + + cr67 = read_reg(VIACR, CR67) & 0xF3; + + cr67 |= (countWidthByQWord & 0x600) >> 7; + cr65 = (countWidthByQWord >> 1) & 0xff; + + write_reg(CR65, VIACR, cr65); + write_reg(CR67, VIACR, cr67); + + /* We also should set FIFO related registers if TV use IGA2, or TV display may incorrect.*/ + if((chip_info.gfx_chip_name != UNICHROME_CLE266) && (chip_info.gfx_chip_name != UNICHROME_K400)) { /* Because load_FIFO_reg() will load incorrect regs for CLE266&K400 */ + load_FIFO_reg(IGA2, tv_setting_info.h_active, tv_setting_info.v_active); + } + + set_color_depth(tv_setting_info.bpp >> 3, IGA2); + + /* Patch for non 32bit alignment mode */ + VIAPitchAlignmentPatch(); + } + else + { + cr35 = read_reg(VIACR, CR35) & 0x1F; + cr13 = offsetWidthByQWord & 0xFF; + cr35 |= (offsetWidthByQWord & 0x700) >> 3; /* bit 7:5: offset 10:8 */ + + sr1d = read_reg(VIASR, SR1D); + + /* Patch for non 32bit alignment mode */ + VIAPitchAlignmentPatch(); + + /* Enable Refresh to avoid data lose when enter screen saver */ + /* Refresh disable & 128-bit alignment */ + sr1d = (sr1d & 0xFC) | (countWidthByQWord >> 9); + sr1c = ((countWidthByQWord >> 1) + 1) & 0xFF; + /* sr1d = ((sr1d & 0xFC) | (widthByQWord >> 8)) | 0x80; */ + /* sr1c = widthByQWord & 0xFF; */ + + write_reg(CR13, VIACR, cr13); + write_reg(CR35, VIACR, cr35); + write_reg(SR1C, VIASR, sr1c); + write_reg(SR1D, VIASR, sr1d); + } +} + +void tv_load_timing_modify(void) +{ + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + break; + case VT1622A: + break; + case VT1625: + break; + + } +} + +void tv_patch(int tv_mode_index) +{ + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622A: + case VT1623: + switch(chip_info.gfx_chip_name) + { + case UNICHROME_K800: + tv_patch_skew_K800(); + break; + default: + break; + } + break; + + case VT1625: + switch(tv_setting_info.out_signal) + { + case TV_OUTPUT_SVIDEO: + case TV_OUTPUT_COMPOSITE_SVIDEO: + /* Set TV.65h = 51h, SVideo Luma Value. */ + tv_register_write(0x65, 0x51); + break; + default: + break; + } + + switch(chip_info.gfx_chip_name) + { + case UNICHROME_P880: + tv_patch_skew_p880(tv_mode_index); + break; + + case UNICHROME_CN900: + tv_patch_skew_cn900(tv_mode_index); + break; + + case UNICHROME_CX700: + tv_patch_skew_cx700(tv_mode_index); + break; + + /* Add to support VT3327 VT3336 VT3364 */ + case UNICHROME_K8M890: + tv_patch_skew_k8m890(tv_mode_index); + break; + + case UNICHROME_P4M890: + tv_patch_skew_p4m890(tv_mode_index); + break; + + case UNICHROME_P4M900: + tv_patch_skew_p4m900(tv_mode_index); + break; + + default: + break; + } + + break; + + default: + break; + } +} + +void tv_enable(void) +{ + switch(tv_setting_info.iga_path) + { + case IGA1: + set_output_path(DEVICE_TV, IGA1, chip_info.tv_chip_info.output_interface); + break; + + case IGA2: + set_output_path(DEVICE_TV, IGA2, chip_info.tv_chip_info.output_interface); + break; + + case IGA1_IGA2: + break; + } + + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + vt1622_tv_enable(); + break; + + case VT1622A: + vt1622a_tv_enable(); + break; + + case VT1625: + vt1625_tv_enable(); + break; + + case INTEGRATED_TV: + integrated_tv_enable(); + break; + + } + + /* For hot-plug issue: + If switch to TV, it would use TV auto-sense function to sense TV. */ + if(HotPlug_TV == 1) + { + if(chip_info.tv_chip_info.tv_chip_name == VT1625) + { + tv_register_write(0x1C, tv_register_read(0x1C) | BIT6); + tv_register_write(0x0E, 0x00); + } + else + { + tv_register_write(0x0E, 0x40); + } + } + +} + +void tv_register_write(int index, u8 data) +{ + i2cWriteByte(chip_info.tv_chip_info.tv_chip_slave_addr, index, data); +} + +int tv_register_read(int index) +{ + u8 data = 0; /* Fix me:should need another parameter to indicate whether read is successful */ + int status; + + status = i2cReadByte(chip_info.tv_chip_info.tv_chip_slave_addr, index, &data); + return(data); +} + +void load_tv_output_signal(u16 *tv_func_reg) +{ + int i=0; + + while(tv_func_reg[i]!= 0xFFFF) + { + tv_register_write(GET_LOW_BYTE(tv_func_reg[i]),GET_HIGH_BYTE(tv_func_reg[i])); + i++; + } + +} + +void write_tv_patch_table(u16 *tv_func_reg) +{ + int i=0; + + while(tv_func_reg[i]!= 0xFFFF) + { + tv_register_write(GET_LOW_BYTE(tv_func_reg[i]),GET_HIGH_BYTE(tv_func_reg[i])); + i++; + } +} + +bool is_tv_mode(struct tv_chip_information* ptv_chip_info, struct tv_setting_information* ptv_setting_info, + int video_index) +{ + bool re = FALSE; + switch(ptv_chip_info->tv_chip_name) + { + case VT1621: + if(VIA_RES_640X480 == video_index || VIA_RES_800X600 == video_index) + { + WARN_MSG(KERN_WARNING "The specified tv mode is not valid for currently used tv encoder\n"); + re = TRUE; + } + break; + case VT1622: + case VT1622A: + case VT1623: + if (VIA_RES_640X480 == video_index ||VIA_RES_800X600 == video_index || + VIA_RES_1024X768 == video_index || VIA_RES_720X480 == video_index || + VIA_RES_720X576== video_index || VIA_RES_848X480 == video_index) + { + WARN_MSG(KERN_WARNING "The specified tv mode is not valid for currently used tv encoder\n"); + re = TRUE; + } + break; + case VT1625: + re = is_vt1625_mode(ptv_chip_info, ptv_setting_info, video_index); + break; + case INTEGRATED_TV: + if(CX700_REVISION_700 == chip_info.gfx_chip_revision) + { + switch(ptv_setting_info->system) + { + case TVTYPE_480P: + case TVTYPE_576P: + case TVTYPE_720P: + case TVTYPE_1080I: + WARN_MSG(KERN_WARNING "HDTV is not supported for currently used tv encoder\n"); + re = FALSE; + return re; + break; + default: + break; + } + } + if (VIA_RES_640X480 == video_index ||VIA_RES_800X600 == video_index || + VIA_RES_1024X768 == video_index || VIA_RES_720X480 == video_index || + VIA_RES_720X576== video_index || VIA_RES_1280X720 == video_index || + VIA_RES_1920X1080 == video_index) + { + WARN_MSG(KERN_WARNING "The specified tv mode is not valid for currently used tv encoder\n"); + re = TRUE; + } + break; + } + return re; +} +/* TV Set Mode */ +void tv_set_mode(int video_index) +{ + if(is_tv_mode(&chip_info.tv_chip_info, &tv_setting_info, video_index)) + { + tv_encoder_identify(); + tv_disable(); + tv_load_timing_init(); + tv_load_timing(video_index); + tv_load_timing_modify(); + tv_patch(video_index); + tv_enable(); + tv_set_color(); + } + else + { + WARN_MSG(KERN_WARNING "TV will not be enabled\n"); + } +} + +/* Sense function only support VIA TV encoder */ +int tv_sense(void) +{ + int ret; + + DEBUG_MSG(KERN_INFO "tv_sense!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + ret = vt1622_sense(); + break; + + case VT1622A: + ret = vt1622a_sense(); + break; + + case VT1625: + ret = vt1625_sense(); + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + ret = integrated_tv_sense(); + break; + + default: + ret = TV_OUTPUT_NONE; + break; + } + + return ret; +} + +/* Auto sense function only support VIA TV encoder */ +int tv_auto_sense(void) +{ + int ret; + + DEBUG_MSG(KERN_INFO "tv_auto_sense!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + ret = vt1622_auto_sense(); + break; + case VT1622A: + ret = vt1622a_auto_sense(); + break; + case VT1625: + ret = vt1625_auto_sense(); + break; + default: + ret = TV_OUTPUT_NONE; + break; + } + + return ret; +} + +void tv_patch_skew_K800(void) +{ + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + write_reg_mask(CR96, VIACR, 0x07, BIT0+BIT1+BIT2); + break; + case INTERFACE_DVP1: + write_reg_mask(CR9B, VIACR, 0x07, BIT0+BIT1+BIT2); + break; + case INTERFACE_DFP_HIGH: + write_reg_mask(CR97, VIACR, 0x07, BIT0+BIT1+BIT2); + break; + case INTERFACE_DFP_LOW: + write_reg_mask(CR99, VIACR, 0x07, BIT0+BIT1+BIT2); + break; + } +} + +/* For VT3314 */ +void tv_patch_skew_cn900(int tv_mode_index) +{ + u8 data; + + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* Reset clock and data driving first: */ + write_reg_mask(SR2A, VIASR, 0, BIT4+BIT5); + write_reg_mask(SR1E, VIASR, 0, BIT2); + write_reg_mask(SR1B, VIASR, 0, BIT1); + + /* For TV display incorrect color */ + /* with VT5907A (VT1625-AMR) on VN800.*/ + if (tv_setting_info.system == TVTYPE_PAL) + { + /* It still has a little bit problem in this mode. */ + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + } + } + else if (tv_setting_info.system == TVTYPE_576P) + { + /* It still has a little bit problem in this mode. */ + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + } + } + else if (tv_setting_info.system == TVTYPE_720P) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + /* Adjust data driving: */ + write_reg_mask(SR2A, VIASR, BIT5, BIT5); + write_reg_mask(SR1B, VIASR, BIT1, BIT1); + + write_reg_mask(CR96, VIACR, 0x07, BIT0+BIT1+BIT2+BIT3); + + data = tv_register_read(0x05); + data = (data & 0xE0) | 0x1E; + tv_register_write(0x05, data); + } + } + else if (tv_setting_info.system == TVTYPE_1080I) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + + /* Adjust data driving: */ + write_reg_mask(SR2A, VIASR, BIT5, BIT5); + write_reg_mask(SR1B, VIASR, BIT1, BIT1); + + + write_reg_mask(CR96, VIACR, 0x07, BIT0+BIT1+BIT2+BIT3); + + data = tv_register_read(0x05); + data = (data & 0xF0) | 0x09; + tv_register_write(0x05, data); + } + else if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + } + else if(tv_mode_index == VIA_RES_1920X1080) + { + /* For both normal scan and over scan */ + /* It still has a little bit problem in this mode. */ + + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + + /* Adjust data driving: */ + write_reg_mask(SR2A, VIASR, 0, BIT5); + write_reg_mask(SR1B, VIASR, BIT1, BIT1); + + data = tv_register_read(0x05); + data = (data & 0xF0); + tv_register_write(0x05, data); + } + } + + break; + + case INTERFACE_DVP1: + break; + + case INTERFACE_DFP_HIGH: + break; + + case INTERFACE_DFP_LOW: + break; + } +} + +/* For VT3324 */ +void tv_patch_skew_cx700(int tv_mode_index) +{ + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* For TV display incorrect color */ + /* with VT5907A (VT1625-AMR) on CX700.*/ + if (tv_setting_info.system == TVTYPE_720P) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + write_reg_mask(CR96, VIACR, 0x0F, BIT0+BIT1+BIT2+BIT3); + } + } + + break; + + case INTERFACE_DVP1: + if (tv_setting_info.system == TVTYPE_720P) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + write_reg_mask(CR9B, VIACR, 0x02, BIT0+BIT1); + } + }else if (tv_setting_info.system == TVTYPE_1080I) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + write_reg_mask(CR9B, VIACR, 0x02, BIT0+BIT1); + } + } + break; + } +} + +/* For VT3259 */ +void tv_patch_skew_p880(int tv_mode_index) +{ + u8 data; + + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* Reset clock and data driving first: */ + write_reg_mask(SR2A, VIASR, 0, BIT4+BIT5); + write_reg_mask(SR1E, VIASR, 0, BIT2); + write_reg_mask(SR1B, VIASR, 0, BIT1); + + /* For TV display incorrect color */ + /* with VT5907A (VT1625-AMR) on CN400.*/ + if (tv_setting_info.system == TVTYPE_PAL) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + } + } + else if (tv_setting_info.system == TVTYPE_576P) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR2A, VIASR, BIT4, BIT4); + } + } + else if (tv_setting_info.system == TVTYPE_720P) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_NORMAL_SCAN)) + { + write_reg_mask(CR96, VIACR, BIT3, BIT0+BIT1+BIT2+BIT3); + + data = tv_register_read(0x05); + data = (data & 0xF0) | 0x0E; + tv_register_write(0x05, data); + } + } + else if (tv_setting_info.system == TVTYPE_1080I) + { + if ((tv_mode_index == VIA_RES_1024X768) && (tv_setting_info.level == TV_SIZE_OVER_SCAN)) + { + /* Adjust clock driving: */ + write_reg_mask(SR1E, VIASR, BIT2, BIT2); + } + } + + break; + + case INTERFACE_DVP1: + break; + + case INTERFACE_DFP_HIGH: + break; + + case INTERFACE_DFP_LOW: + break; + } +} + +/* Add for support VT3327 VT3336 VT3364. + * Modified from X driver's code. + */ +void tv_patch_skew_k8m890(int tv_mode_index) +{ + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* Fix TV display incorrect color when set 1080i TV mode */ + /* with VT5907A (VT1625-AMR) on VT3336. */ + if (tv_setting_info.system == TVTYPE_1080I) + { + if (tv_mode_index == VIA_RES_1024X768) + { + write_reg_mask(CR96, VIACR, 0x04, BIT0+BIT1+BIT2); + } + else if(tv_mode_index == VIA_RES_1920X1080) + { + write_reg_mask(CR96, VIACR, 0x00, BIT0+BIT1+BIT2); + } + } + + break; + case INTERFACE_DVP1: + break; + case INTERFACE_DFP_HIGH: + break; + case INTERFACE_DFP_LOW: + break; + } +} + + +void tv_patch_skew_p4m890(int tv_mode_index) +{ + + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* For TV display incorrect color */ + /* with VT5907A (VT1625-AMR) on P4M890.*/ + if (tv_setting_info.system == TVTYPE_1080I) + { + if (tv_mode_index == VIA_RES_1024X768) + { + write_reg_mask(CR96, VIACR, 0x04, BIT0+BIT1+BIT2); + } + } + + /* For TV display incorrect color */ + /* VT1625-AMR on P4M890.*/ + if (tv_setting_info.system == TVTYPE_720P) + { + if (tv_mode_index == VIA_RES_1024X768) + { + write_reg_mask(CR96, VIACR, 0x07, BIT0+BIT1+BIT2); + } + } + + break; + } +} + +void tv_patch_skew_p4m900(int tv_mode_index) +{ + + switch(chip_info.tv_chip_info.output_interface) + { + case INTERFACE_DVP0: + /* For TV display incorrect color */ + /* with VT5907A (VT1625-AMR) on P4M900.*/ + if (tv_setting_info.system == TVTYPE_1080I) + { + if (tv_mode_index == VIA_RES_1024X768) + { + write_reg_mask(CR96, VIACR, 0x04, BIT0+BIT1+BIT2); + } + } + + if (tv_setting_info.system == TVTYPE_720P) + { + if (tv_mode_index == VIA_RES_1024X768) + { + write_reg_mask(CR96, VIACR, 0x04, BIT0+BIT1+BIT2); + } + } + break; + } +} + + +void tv_set_color() +{ + /* Get TV color default, current value and level*/ + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tv_setting_info.DefaultFFilter = tv_register_read(0x03) & 0x03; + tv_setting_info.CurrentFFilter = tv_setting_info.DefaultFFilter; + if (chip_info.tv_chip_info.tv_chip_name == VT1625) + tv_setting_info.FFilterLevel = 3; + else + tv_setting_info.FFilterLevel = 2; + + tv_setting_info.DefaultBrightness = tv_register_read(0x0B); + tv_setting_info.CurrentBrightness = tv_setting_info.DefaultBrightness; + tv_setting_info.BrightnessLevel = 255; + if (tv_setting_info.out_signal == TV_OUTPUT_RGB) { + tv_setting_info.DefaultContrast = tv_register_read(0x65); + tv_setting_info.CurrentContrast = tv_setting_info.DefaultContrast; + tv_setting_info.ContrastLevel = 250; + tv_setting_info.DefaultSaturation = (tv_register_read(0x66) << 8) + tv_register_read(0x67); + tv_setting_info.CurrentSaturation = tv_setting_info.DefaultSaturation; + tv_setting_info.SaturationLevel = 65535; + tv_setting_info.DefaultTINT = 0; + tv_setting_info.CurrentTINT = tv_setting_info.DefaultTINT; + tv_setting_info.TINTLevel = 0; + } else if (tv_setting_info.out_signal == TV_OUTPUT_YPBPR) { + tv_setting_info.DefaultContrast = tv_register_read(0x65); + tv_setting_info.CurrentContrast = tv_setting_info.DefaultContrast; + tv_setting_info.ContrastLevel = 255; + tv_setting_info.DefaultSaturation = (tv_register_read(0x66) << 8) + tv_register_read(0x67); + tv_setting_info.CurrentSaturation = tv_setting_info.DefaultSaturation; + tv_setting_info.SaturationLevel = 65535; + tv_setting_info.DefaultTINT = 0; + tv_setting_info.CurrentTINT = tv_setting_info.DefaultTINT; + tv_setting_info.TINTLevel = 0; + } else { + tv_setting_info.DefaultContrast = tv_register_read(0x0C); + tv_setting_info.CurrentContrast = tv_setting_info.DefaultContrast; + tv_setting_info.ContrastLevel = 255; + tv_setting_info.DefaultSaturation = (tv_register_read(0x0D) << 8) + tv_register_read(0x0A); + tv_setting_info.CurrentSaturation = tv_setting_info.DefaultSaturation; + tv_setting_info.SaturationLevel = 65535; + tv_setting_info.DefaultTINT = tv_register_read(0x10) + ((tv_register_read(0x11) & 0x07) << 8); + tv_setting_info.CurrentTINT = tv_setting_info.DefaultTINT; + tv_setting_info.TINTLevel = 2047; + } + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + get_integrated_tv_default_status(); + break; + + default: + break; + } + + /* Set to user parameter*/ + if(tv_ffilter != 0) + tv_set_ffilter(STATE_ON, tv_ffilter); + if(tv_brightness != 0) + tv_set_brightness(tv_brightness); + if(tv_contrast!= 0) + tv_set_contrast(tv_contrast); + if(tv_saturation != 0) + tv_set_saturation(tv_saturation); + if(tv_tint != 0) + tv_set_tint(tv_tint); +} + +/* Set TV Brightness function only support VIA TV encoder */ +void tv_set_brightness(u32 value) +{ + DEBUG_MSG(KERN_INFO "tv_set_brightness!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tv_register_write(0x0B, (u8) value); + tv_setting_info.CurrentBrightness = value; + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + set_integrated_tv_brightness(value); + break; + + default: + break; + } +} + +/* Set TV Contrast function only support VIA TV encoder */ +void tv_set_contrast(u32 value) +{ + u32 tmp; + + DEBUG_MSG(KERN_INFO "tv_set_contrast!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tmp = (value - tv_setting_info.CurrentContrast); + if (tv_setting_info.out_signal == TV_OUTPUT_RGB) { + tv_register_write(0x65, (u8)(tv_register_read(0x65) + tmp)); + tv_register_write(0x66, (u8)(tv_register_read(0x66) + tmp)); + tv_register_write(0x67, (u8)(tv_register_read(0x67) + tmp)); + } else if (tv_setting_info.out_signal == TV_OUTPUT_YPBPR) { + tv_register_write(0x65, (u8)(tv_register_read(0x65) + tmp)); + } else { + tv_register_write(0x0C, (u8)(tv_register_read(0x0C) + tmp)); + tv_register_write(0x65, (u8)(value)); /* for VT1625 S-Video output */ + } + tv_setting_info.CurrentContrast = value; + break; + + case INTEGRATED_TV: + set_integrated_tv_contrast(value); + break; + } +} + +/* Set TV Saturation function only support VIA TV encoder */ +void tv_set_saturation(u32 value) +{ + DEBUG_MSG(KERN_INFO "tv_set_saturation!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tv_register_write(0x66, (u8)((value >> 8) & 0xFF)); + tv_register_write(0x67, (u8)(value & 0xFF)); + tv_register_write(0x0D, (u8)((value >> 8) & 0xFF)); + tv_register_write(0x0A, (u8)(value & 0xFF)); + tv_setting_info.CurrentSaturation = value; + break; + + case INTEGRATED_TV: + set_integrated_tv_saturation(value); + break; + } +} + +/* Set TV TINT function only support VIA TV encoder */ +void tv_set_tint(u32 value) +{ + DEBUG_MSG(KERN_INFO "tv_set_tint!!\n"); + + if ((tv_setting_info.out_signal == TV_OUTPUT_RGB) || + (tv_setting_info.out_signal == TV_OUTPUT_YPBPR)) + { + return; + } + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tv_register_write(0x10, (u8)(value & 0xFF)); + tv_register_write(0x11, (u8)((tv_register_read(0x11) & ~0x07) | (u8)((value >> 8) & 0xFF))); + tv_setting_info.CurrentTINT = value; + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + set_integrated_tv_hue(value); + break; + + default: + break; + } +} + +/* Set TV Flicker Filter function only support VIA TV encoder */ +void tv_set_ffilter(u32 state, u32 value) +{ + DEBUG_MSG(KERN_INFO "tv_set_ffilter!!\n"); + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + if (state == STATE_ON) + { + if ((value < 0) || (value > 3)) + break; + + if ((value == 3) && (chip_info.tv_chip_info.tv_chip_name != VT1625)) + break; + + /* Turn off adaptive ffilter. Adaptive ffilter is exclusive with ffilter */ + tv_register_write(0x62, (u8)(tv_register_read(0x62) & ~0x03)); + + /* Tuning the value of flicker filter. */ + if (value) + { + tv_register_write(0x03, (u8)((tv_register_read(0x03) & ~0x03) | (u8)(value))); + tv_setting_info.CurrentFFilter = value; + } + else /* value should be more than 0. */ + { + tv_register_write(0x03, (u8)((tv_register_read(0x03) & ~0x03) | (u8)(value+1))); + tv_setting_info.CurrentFFilter = value+1; + } + } + else /* turn off */ + { + tv_register_write(0x03, (u8)((tv_register_read(0x03) & ~0x03))); + tv_setting_info.CurrentFFilter = STATE_OFF; + } + + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + if (state == STATE_ON) + { + set_integrated_tv_ffilter_status(ITV_FILTER_TYPE_NORMAL, ITV_FILTER_ON, value); + } + else + { + set_integrated_tv_ffilter_status(ITV_FILTER_TYPE_NORMAL, ITV_FILTER_OFF, value); + } + break; + + default: + break; + } +} + + + +/* + * Purpose: + * Set status of TV Adaptive Flicker Filter and its degree. + * Currently, it only support VIA TV encoder. + * Parameter: + * status: ON/OFF tv adaptive flicker filter function. + * value: Degree of adaptive flicker filter. + */ +void tv_set_adaptive_ffilter(u32 status,u32 value) +{ + /* Adaptive FFilter ON */ + if (status == STATE_ON) + { + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + /* Turn off normal flicker filter before turn on adaptive ffilter */ + tv_set_ffilter(STATE_OFF, 0); + + /* Turn on adaptive flicker filter before change the value of deflicker threshold. */ + tv_register_write(0x62, (u8)((tv_register_read(0x62) & ~0x03)| 0x01)); + + /* Apply the value to deflicker threshold. */ + tv_register_write(0x61, (u8)value); + + /* Change adaptive ffilter state */ + tv_setting_info.AdaptiveFFilterOn = TRUE; + + break; + + case VT1625: + /* Turn off normal flicker filter before turn on adaptive ffilter */ + tv_set_ffilter(STATE_OFF, 0); + + /* VT1625 only use 62[7:2] to control ffilter threshold */ + if ((value > 0) && (value < 64)) + { + /* Turn on adaptive flicker filter and assign value */ + tv_register_write(0x62, (u8)(value<<2) | 0x01); + } + + /* Change adaptive ffilter state */ + tv_setting_info.AdaptiveFFilterOn = TRUE; + + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + set_integrated_tv_ffilter_status(ITV_FILTER_TYPE_ADAPTIVE, ITV_FILTER_ON, value); + break; + } + } + else /* Adaptive FFilter OFF */ + { + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + /* Turn off adaptive flicker filter and assign value */ + tv_register_write(0x62, (u8)(tv_register_read(0x62) & ~0x03)); + tv_setting_info.AdaptiveFFilterOn = FALSE; + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + set_integrated_tv_ffilter_status(ITV_FILTER_TYPE_ADAPTIVE, ITV_FILTER_OFF, 0); + break; + } + } +} + + + +/* +* Purpose: +* Get flicker filter value +* Parameter: +* ffilter_type: which type of flicker filter we want to get. +* ffilter_state: this can be used to receive the current ffilter state. +* Return: +* the value of flicker filter. +* +*/ +int tv_get_ffilter(int ffilter_type, int* ffilter_state) +{ + int ffilter_value = 0; + int tmp_ffilter_state = 0; + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + if (ffilter_type == TV_FFILTER_TYPE_NORMAL) + { + ffilter_value = (tv_register_read(0x03) & 0x03); + + /* flicker filter use 03[1:0]. */ + if (ffilter_value > 0) + { + *ffilter_state = STATE_ON; + } + else + { + *ffilter_state = STATE_OFF; + } + } + + if (ffilter_type == TV_FFILTER_TYPE_ADAPTIVE) + { + if (chip_info.tv_chip_info.tv_chip_name == VT1625) + { + /* VT1625 use 62[7:2] to save the value of deflicker threshold. */ + ffilter_value = (tv_register_read(0x62) & ~0x03)>>2; + tmp_ffilter_state= tv_register_read(0x62) & 0x03; + } + else + { + ffilter_value = tv_register_read(0x61); + tmp_ffilter_state= tv_register_read(0x62) & 0x03; + } + + if (tmp_ffilter_state > 0) + { + *ffilter_state = STATE_ON; + } + else + { + *ffilter_state = STATE_OFF; + } + } + break; + + /* Add for VT3324 Integrated TV. */ + case INTEGRATED_TV: + if (ffilter_type == TV_FFILTER_TYPE_NORMAL) + { + ffilter_value = get_integrated_tv_ffilter_status(ITV_FILTER_TYPE_NORMAL, ffilter_state); + } + else if (ffilter_type == TV_FFILTER_TYPE_ADAPTIVE) + { + ffilter_value = get_integrated_tv_ffilter_status(ITV_FILTER_TYPE_ADAPTIVE, ffilter_state); + } + break; + } + + return ffilter_value; +} + + + +/* + * Purpose: + * Set position of TV's screen. + * Parameter: + * HPos: Horizontal position of screen. + * VPos: Verticle position of screen. + */ +void tv_set_position(u32 HPos, u32 VPos) +{ + /* Registers of horizontal position : TV06[3:0] + TV08[7:0] + Registers of Vertical position: TV1C[3:1] + TV09[7:0] */ + int new_hor_pos; + int new_ver_pos; + unsigned char high_bytes; + unsigned char low_bytes; + + if (chip_info.tv_chip_info.tv_chip_name == INTEGRATED_TV) + { + /* Add for VT3324 Integrated TV. */ + set_integrated_tv_pos(HPos, VPos); + } + else /* VIA's TV encoder */ + { + /* First to get current postion */ + tv_get_position(&new_hor_pos, &new_ver_pos); + + switch(chip_info.tv_chip_info.tv_chip_name) + { + case VT1622: + case VT1622A: + case VT1623: + /* Origin position of vt1623 is at down-left corner + New position is current position + shift */ + new_hor_pos += HPos - tv_setting_info.CurrentPositionH; + new_ver_pos += VPos - tv_setting_info.CurrentPositionV; + + /* Write new value of horizontal position to register. */ + high_bytes = ((new_hor_pos >> 8) & 0x0F) | tv_register_read(0x06); + low_bytes = new_hor_pos & 0xFF; + tv_register_write(0x06, high_bytes); + tv_register_write(0x08, low_bytes); + + /* Write new value of vertical position to register. */ + high_bytes = (((new_ver_pos >> 8) & 0x07) << 1) | tv_register_read(0x1C); + low_bytes = new_ver_pos & 0xFF; + tv_register_write(0x1C, high_bytes); + tv_register_write(0x09, low_bytes); + break; + + case VT1625: + /* Origin position of vt1625 is at down-right corner + New position is current position + shift */ + new_hor_pos -= HPos - tv_setting_info.CurrentPositionH; + new_ver_pos += VPos - tv_setting_info.CurrentPositionV; + + /* Write new value of horizontal position to register. */ + high_bytes = ((new_hor_pos >> 8) & 0x0F) | tv_register_read(0x06); + low_bytes = new_hor_pos & 0xFF; + tv_register_write(0x06, high_bytes); + tv_register_write(0x08, low_bytes); + + /* Write new value of vertical position to register. */ + high_bytes = (((new_ver_pos >> 8) & 0x07) << 1) | tv_register_read(0x1C); + low_bytes = new_ver_pos & 0xFF; + tv_register_write(0x1C, high_bytes); + tv_register_write(0x09, low_bytes); + break; + + + } + + /* Save the value of current position */ + tv_setting_info.CurrentPositionH = HPos; + tv_setting_info.CurrentPositionV = VPos; + } +} + + + +/* +* Purpose: +* Get position of TV's screen. +* Parameter: +* HPos: Horizontal position of screen. +* VPos: Verticle position of screen. +*/ +void tv_get_position(u32* HPos, u32* VPos) +{ + if (chip_info.tv_chip_info.tv_chip_name == INTEGRATED_TV) + { + get_integrated_tv_pos(HPos, VPos); + } + else + { + *HPos = (((tv_register_read(0x06)&0x0F)<<8) | tv_register_read(0x08)) & 0x0FFF; + *VPos = (((tv_register_read(0x1C)&0x0E)<<7) | tv_register_read(0x09)) & 0x0FFF; + } + +} + +/* Set TV Flicker Filter function only support VIA TV encoder */ +void tv_set_size(u32 HPos, u32 VPos) +{ + + DEBUG_MSG(KERN_INFO "tv_set_size\n"); + DEBUG_MSG(KERN_INFO "tv_set_size: pSetViewSizeValue->dwX=%d\n", HPos); + DEBUG_MSG(KERN_INFO "tv_set_size: pSetViewSizeValue->dwY=%d\n", VPos); + + /* Add for VT3324 Integrated TV. */ + if (chip_info.tv_chip_info.tv_chip_name == INTEGRATED_TV) + { + set_integrated_tv_size(HPos, VPos); + return; + } + + tv_setting_info.CurrentScalH=HPos-1; + tv_setting_info.CurrentScalV=VPos-1; + + switch (chip_info.tv_chip_info.tv_chip_name) + { + case VT1621: + case VT1622: + case VT1622A: + case VT1623: + tv_setting_info.level = VPos - 1; + break; + + case VT1625: + if (VPos == 2) + tv_setting_info.level = 2; + else + tv_setting_info.level = VPos - 1; + break; + + + default: + tv_setting_info.CurrentPositionH = 0; + tv_setting_info.CurrentPositionV = 0; + break; + } + + DEBUG_MSG(KERN_INFO "tv_set_size:After set size, tv_setting_info.level=%d\n", tv_setting_info.level); +} + +/* Add this function to control TV clock source by case. */ +void set_tv_clock_source(void) +{ + if (chip_info.tv_chip_info.tv_chip_name == INTEGRATED_TV) + { + /* From TVPLL. */ + if (tv_setting_info.iga_path == IGA1) + { + write_reg(CR6C, VIACR, 0x50); + } + else + { + write_reg(CR6C, VIACR, 0x05); + } + } + else + { + /* External TV: */ + if ((chip_info.gfx_chip_name == UNICHROME_CLE266) && + (chip_info.gfx_chip_revision == CLE266_REVISION_AX)) + { + write_reg_mask(CR6C, VIACR, 0x01, BIT0); + } + else if (chip_info.gfx_chip_name == UNICHROME_CX700) + { + /* From DVP0 TV clock. */ + if (tv_setting_info.iga_path == IGA1) + { + write_reg(CR6C, VIACR, 0xb0); + } + else + { + write_reg(CR6C, VIACR, 0x0b); + } + } + else + { + write_reg_mask(CR6C, VIACR, BIT5+BIT0, BIT5+BIT0); + } + } +} +/*check_macrovision_enabled: to check if MV is enabled +* according to TV encoder's registers 0x0F and 0x30 +* Currently only support VT1622 and VT1623 VT1625 +* AlZhang[2006.04.24] +*/ +int check_macrovision_enabled(void) +{ + u8 tv_r0f = 0,tv_r30 = 0; + switch(chip_info.tv_chip_info.tv_chip_name) + { + + case VT1622: + case VT1622A: + case VT1623: + case VT1625: + tv_r0f = (u8)tv_register_read(0x0f); + tv_r30 = (u8)tv_register_read(0x30); + + break; + default: + break; + + } + if((tv_r0f&0x80) && (tv_r30&0x30)) + return TRUE; + else + return FALSE; +} diff -Nur linux-2.6.21-rc7/drivers/video/via/vt1625.c linux-2.6.21-rc7.viafb/drivers/video/via/vt1625.c --- linux-2.6.21-rc7/drivers/video/via/vt1625.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.21-rc7.viafb/drivers/video/via/vt1625.c 2007-04-26 19:52:32.000000000 -0400 @@ -0,0 +1,521 @@ +/* + * Copyright 1998-2007 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2007 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <linux/ioport.h> +#include <asm/io.h> + +#include "tv.h" +#include "tbl1625.h" +#include "share.h" +#include "chip.h" +#include "debug.h" + +extern inline void lock_crt(void); +extern inline void unlock_crt(void); +extern inline void write_reg(u8 index, u16 io_port, u8 data); +extern void write_reg_mask(u8 index, int io_port, u8 data, u8 mask); +extern void load_crtc_timing(struct display_timing device_timing, int set_iga); +extern void write_tv_patch_table(u16 *tv_func_reg); +extern void plus_vck_to_iga1_timing(unsigned long h_total); + +extern struct tv_setting_information tv_setting_info; +extern struct chip_information chip_info; + +int vt1625_tv_encoder_identify(void) +{ + int ver; + + ver = tv_register_read(VT1625_VERSION_REG); + if (ver == VT1625_VERSION) + { + DEBUG_MSG(KERN_INFO "\nFind VT1625 TV Encoder \n"); + return(OK); + } + else + return(FAIL); +} + +void vt1625_tv_disable(void) +{ + /* turn off TV's DAC */ + tv_register_write(0x0E, 0x3F); + /* reset TV */ + tv_register_write(0x1D, 0x00); + /* disable reset TV */ + tv_register_write(0x1D, 0x80); +} + +void write_vt1625_patch_table(vt1625_func_table *func_table, int func_index) +{ + u16 *tv_func_reg = NULL; + + if (tv_setting_info.level == TV_SIZE_NORMAL_SCAN) + { + tv_func_reg = func_table[func_index].tv_underscan; + } + else if (tv_setting_info.level == TV_SIZE_FIT_SCAN) + { + tv_func_reg = func_table[func_index].tv_fitscan; + } + else if (tv_setting_info.level == TV_SIZE_OVER_SCAN) + { + tv_func_reg = func_table[func_index].tv_overscan; + } + + if (tv_func_reg != NULL) + { + write_tv_patch_table(tv_func_reg); + } +} + +void load_vt1625_regs(int TVModeIndex) +{ + int i, index; + u8 tmp; + vt1625_func_table *vt1625_func; + struct display_timing tv_crtc_reg; + u16 *tv_reg = NULL; + + for(i=0;i<NUM_TOTAL_VT1625_TABLE;i++) + { + index = i; + + if(vt1625_tbl[i].tv_index == TVModeIndex) + break; + } + + switch (tv_setting_info.system) + { + case TVTYPE_NTSC: + case TVTYPE_480P: + { + /* For 480P, we use NTSC's mode table, and then do some patches later. */ + vt1625_func = vt1625_tbl[index].tv_mode_ntsc; + break; + } + + case TVTYPE_PAL: + case TVTYPE_576P: + { + /* For 576P, we use PAL's mode table, and then do some patches later. */ + vt1625_func = vt1625_tbl[index].tv_mode_pal; + break; + } + + case TVTYPE_720P: + { + vt1625_func = vt1625_tbl[index].tv_mode_720p; + break; + } + + case TVTYPE_1080I: + { + vt1625_func = vt1625_tbl[index].tv_mode_1080i; + break; + } + + default: + { + vt1625_func = vt1625_tbl[index].tv_mode_ntsc; + break; + } + } + + + if (tv_setting_info.level == TV_SIZE_NORMAL_SCAN) + { + tv_reg = vt1625_func[0].tv_underscan; + } + + if (tv_setting_info.level == TV_SIZE_FIT_SCAN) + { + tv_reg = vt1625_func[0].tv_fitscan; + } + + if (tv_setting_info.level == TV_SIZE_OVER_SCAN) + { + tv_reg = vt1625_func[0].tv_overscan; + } + + /* unlock CRTC Register */ + unlock_crt(); + + /* update starting address */ + write_reg(CR0C, VIACR, 0x00); + write_reg(CR0D, VIACR, 0x00); + + write_reg_mask(CR48, VIACR, 0x00, BIT0+BIT1); + + /* Load TV Encoder Regsiters */ + for (i=0;i<NUM_TOTAL_VT1625_REG;i++) + { + tv_register_write(GET_LOW_BYTE(tv_reg[i]),GET_HIGH_BYTE(tv_reg[i])); + } + + /* Load GFX CRTC timing when TV work on IGA1 */ + for (i=0; i< NUM_CRTC_TIMING; i++) + { + switch(i) + { + case H_TOTAL_INDEX: + tv_crtc_reg.hor_total = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case H_ADDR_INDEX: + tv_crtc_reg.hor_addr = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case H_BLANK_START_INDEX: + tv_crtc_reg.hor_blank_start = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case H_BLANK_END_INDEX: + tv_crtc_reg.hor_blank_end = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case H_SYNC_START_INDEX: + tv_crtc_reg.hor_sync_start = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case H_SYNC_END_INDEX: + tv_crtc_reg.hor_sync_end = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_TOTAL_INDEX: + tv_crtc_reg.ver_total = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_ADDR_INDEX: + tv_crtc_reg.ver_addr = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_BLANK_START_INDEX: + tv_crtc_reg.ver_blank_start = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_BLANK_END_INDEX: + tv_crtc_reg.ver_blank_end = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_SYNC_START_INDEX: + tv_crtc_reg.ver_sync_start = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + case V_SYNC_END_INDEX: + tv_crtc_reg.ver_sync_end = tv_reg[i+NUM_TOTAL_VT1625_REG]; + break; + } + } + + if (tv_setting_info.iga_path == IGA1) + { + load_crtc_timing(tv_crtc_reg, IGA1); + + /* patch TV IGA1 horizontal total can't be divided by 8 */ + if ((chip_info.tv_chip_info.tv_chip_name == VT1625) && + ((chip_info.gfx_chip_name == UNICHROME_P880) || (chip_info.gfx_chip_name == UNICHROME_CN900))) + { + plus_vck_to_iga1_timing(tv_crtc_reg.hor_total); + } + } + else + { + load_crtc_timing(tv_crtc_reg, IGA2); + write_reg(CR65, VIACR, 0x80); + write_reg(CR66, VIACR, 0x00); + write_reg(CR67, VIACR, 0x41); + } + + /* Load CGMS registers */ + for (i=0;i<NUM_TOTAL_VT1625_CGMS_TBL;i++) + { + tv_register_write(GET_LOW_BYTE(VT1625_CGMS_TBL[i]),GET_HIGH_BYTE(VT1625_CGMS_TBL[i])); + } + + DEBUG_MSG(KERN_INFO "\n tv_out_signal = %2d \n", tv_setting_info.out_signal); + + /* Patch for RGB/YPbPr connector */ + if (tv_settin... [truncated message content] |