/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/gfx/tv_fs450.c,v 1.1 2002/12/10 15:12:27 alanh Exp $ */ /* * $Workfile: tv_fs450.c $ * * This file contains routines to control the FS450 tvout encoder. * * NSC_LIC_ALTERNATIVE_PREAMBLE * * Revision 1.0 * * National Semiconductor Alternative GPL-BSD License * * National Semiconductor Corporation licenses this software * ("Software"): * * Durango * * under one of the two following licenses, depending on how the * Software is received by the Licensee. * * If this Software is received as part of the Linux Framebuffer or * other GPL licensed software, then the GPL license designated * NSC_LIC_GPL applies to this Software; in all other circumstances * then the BSD-style license designated NSC_LIC_BSD shall apply. * * END_NSC_LIC_ALTERNATIVE_PREAMBLE */ /* NSC_LIC_BSD * * National Semiconductor Corporation Open Source License for Durango * * (BSD License with Export Notice) * * Copyright (c) 1999-2001 * National Semiconductor Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * * Neither the name of the National Semiconductor Corporation nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE, * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF * YOUR JURISDICTION. It is licensee's responsibility to comply with * any export regulations applicable in licensee's jurisdiction. Under * CURRENT (2001) U.S. export regulations this software * is eligible for export from the U.S. and can be downloaded by or * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed * destinations which include Cuba, Iraq, Libya, North Korea, Iran, * Syria, Sudan, Afghanistan and any other country to which the U.S. * has embargoed goods and services. * * END_NSC_LIC_BSD */ /* NSC_LIC_GPL * * National Semiconductor Corporation Gnu General Public License for Durango * * (GPL License with Export Notice) * * Copyright (c) 1999-2001 * National Semiconductor Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted 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 * * In addition to the terms of the GNU General Public License, neither * the name of the National Semiconductor Corporation nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE, * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. See the GNU General Public License for more details. * * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF * YOUR JURISDICTION. It is licensee's responsibility to comply with * any export regulations applicable in licensee's jurisdiction. Under * CURRENT (2001) U.S. export regulations this software * is eligible for export from the U.S. and can be downloaded by or * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed * destinations which include Cuba, Iraq, Libya, North Korea, Iran, * Syria, Sudan, Afghanistan and any other country to which the U.S. * has embargoed goods and services. * * You should have received a copy of the GNU General Public License * along with this file; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * END_NSC_LIC_GPL */ #define FS450_DIRECTREG 0 #include "tv_fs450.h" /*========================================================================== * * Macros * *========================================================================== */ #undef fsmax #undef fsmin #define fsmax(a, b) ((a) > (b) ? (a) : (b)) #define fsmin(a, b) ((a) < (b) ? (a) : (b)) #undef range_limit #define range_limit(val,min_val,max_val) (fsmax((min_val),fsmin((val),(max_val)))) /*========================================================================== * * Registers * *========================================================================== */ #define MAX_REGISTERS 32 #define MAX_BITS 32 #define READ 1 #define WRITE 2 #define READ_WRITE (READ | WRITE) typedef struct { char *name; unsigned long offset; unsigned char bit_length; unsigned char valid_bits; unsigned char read_write; char *bitfield_names[MAX_BITS]; } S_REGISTER_DESCRIP; typedef struct { int source; char *name; S_REGISTER_DESCRIP registers[MAX_REGISTERS]; } S_SET_DESCRIP; const S_SET_DESCRIP *houston_regs(void); const S_SET_DESCRIP *encoder_regs(void); const S_SET_DESCRIP *macrovision_regs(void); const S_SET_DESCRIP *gcc_regs(void); /*========================================================================== * * Houston Register Addresses & Bit Definitions * *========================================================================== */ #define HOUSTON_IHO 0x00 /*Input Horizontal Offset */ #define HOUSTON_IVO 0x02 /*Input Vertical Offset */ #define HOUSTON_IHA 0x04 /*Input Horizontal Active Width */ #define HOUSTON_VSC 0x06 /*Vertical Scaling Coeficient */ #define HOUSTON_HSC 0x08 /*Horizontal Scaling Coeficient */ #define HOUSTON_BYP 0x0A /*Bypass Register */ #define HOUSTON_CR 0x0C /*Control Register */ #define HOUSTON_SP 0x0E /*Status */ #define HOUSTON_NCONL 0x10 /*NCO numerator low word */ #define HOUSTON_NCONH 0x12 /*NCO numerator high word */ #define HOUSTON_NCODL 0x14 /*NCO denominator low word */ #define HOUSTON_NCODH 0x16 /*NCO denominator high word */ #define HOUSTON_APO 0x18 /**/ #define HOUSTON_ALO 0x1A /**/ #define HOUSTON_AFO 0x1C /**/ #define HOUSTON_HSOUTWID 0x1E /**/ #define HOUSTON_HSOUTST 0x20 /**/ #define HOUSTON_HSOUTEND 0x22 /**/ #define HOUSTON_SHP 0x24 /*Sharpness */ #define HOUSTON_FLK 0x26 /*Flicker Filter */ #define HOUSTON_BCONTL 0x28 /**/ #define HOUSTON_BCONTH 0x2A /**/ #define HOUSTON_BDONE 0x2C /**/ #define HOUSTON_BDIAGL 0x2E /**/ #define HOUSTON_BDIAGH 0x30 /**/ #define HOUSTON_REV 0x32 /**/ #define HOUSTON_MISC 0x34 /**/ #define HOUSTON_FFO 0x36 /**/ #define HOUSTON_FFO_LAT 0x38 /**/ #define HOUSTON_VSOUTWID 0x3A #define HOUSTON_VSOUTST 0x3C #define HOUSTON_VSOUTEND 0x3E /*// BYP Register Bits*/ #define BYP_RGB_BYPASS 0x0001 #define BYP_HDS_BYPASS 0x0002 #define BYP_HDS_TBYPASS 0x0004 #define BYP_CAC_BYPASS 0x0008 #define BYP_R2V_SBYPASS 0x0010 #define BYP_R2V_BYPASS 0x0020 #define BYP_VDS_BYPASS 0x0040 #define BYP_FFT_BYPASS 0x0080 #define BYP_FIF_BYPASS 0x0100 #define BYP_FIF_TBYPASS 0x0200 #define BYP_HUS_BYPASS 0x0400 #define BYP_HUS_TBYPASS 0x0800 #define BYP_CCR_BYPASS 0x1000 #define BYP_PLL_BYPASS 0x2000 #define BYP_NCO_BYPASS 0x4000 #define BYP_ENC_BYPASS 0x8000 /*// CR Register Bits*/ #define CR_RESET 0x0001 #define CR_CLKOFF 0x0002 #define CR_NCO_EN 0x0004 #define CR_COMPOFF 0x0008 #define CR_YCOFF 0x0010 #define CR_LP_EN 0x0020 #define CR_CACQ_CLR 0x0040 #define CR_FFO_CLR 0x0080 #define CR_656_PAL_NTSC 0x0100 #define CR_656_STD_VMI 0x0200 #define CR_OFMT 0x0400 #define CR_UIM_CLK 0x0800 #define CR_UIM_DEC 0x1000 #define CR_BIPGEN_EN1 0x2000 #define CR_UIM_MOD0 0x4000 #define CR_UIM_MOD1 0x8000 /*// Status Register Bits*/ #define SP_CACQ_ST 0x0001 #define SP_FFO_ST 0x0002 #define SP_REVID_MASK 0x7FFC #define SP_MV_EN 0x8000 /*// BDONE Register Bits*/ #define BDONE_BIST_DONE_A 0x0001 #define BDONE_BIST_DONE_B 0x0002 #define BDONE_BIST_DONE_C 0x0004 #define BDONE_BIST_DONE_D 0x0008 #define BDONE_BIST_DONE_E 0x0010 #define BDONE_BIST_DONE_F 0x0020 #define BDONE_BIST_DONE_G 0x0040 /*// BDIAGL Register Bits*/ #define BDIAGL_BIST_DIAG_A 0x000F #define BDIAGL_BIST_DIAG_B 0x00F0 #define BDIAGL_BIST_DIAG_C 0x0F00 #define BDIAGL_BIST_DIAG_D 0xF000 /*// BDIAGH Register Bits*/ #define BDIAGH_BIST_DIAG_E 0x000F #define BDIAGH_BIST_DIAG_F 0x000F #define BDIAGH_BIST_DIAG_G 0x000F /*// MISC Register Bits*/ #define MISC_TV_SHORT_FLD 0x0001 #define MISC_ENC_TEST 0x0002 #define MISC_DAC_TEST 0x0004 #define MISC_MV_SOFT_EN 0x0008 #define MISC_NCO_LOAD0 0x0010 #define MISC_NCO_LOAD1 0x0020 #define MISC_VGACKDIV 0x0200 #define MISC_BRIDGE_SYNC 0x0400 #define MISC_GTLIO_PD 0x8000 /*========================================================================== * * Encoder Registers & Bit Definitions * *========================================================================== */ #define ENC_CHROMA_FREQ 0x40 #define ENC_CHROMA_PHASE 0x44 #define ENC_REG05 0x45 #define ENC_REG06 0x46 #define ENC_REG07 0x47 #define ENC_HSYNC_WIDTH 0x48 #define ENC_BURST_WIDTH 0x49 #define ENC_BACK_PORCH 0x4A #define ENC_CB_BURST_LEVEL 0x4B #define ENC_CR_BURST_LEVEL 0x4C #define ENC_SLAVE_MODE 0x4D #define ENC_BLACK_LEVEL 0x4e #define ENC_BLANK_LEVEL 0x50 #define ENC_NUM_LINES 0x57 #define ENC_WHITE_LEVEL 0x5e #define ENC_CB_GAIN 0x60 #define ENC_CR_GAIN 0x62 #define ENC_TINT 0x65 #define ENC_BREEZE_WAY 0x69 #define ENC_FRONT_PORCH 0x6C #define ENC_ACTIVELINE 0x71 #define ENC_FIRST_LINE 0x73 #define ENC_REG34 0x74 #define ENC_SYNC_LEVEL 0x75 #define ENC_VBI_BLANK_LEVEL 0x7C #define ENC_RESET 0x7e #define ENC_NOTCH_FILTER 0x8d /*========================================================================== * * Macrovision Registers & Bit Definitions * *========================================================================== */ #define MV_N0 0x59 #define MV_N1 0x52 #define MV_N2 0x7b #define MV_N3 0x53 #define MV_N4 0x79 #define MV_N5 0x5d #define MV_N6 0x7a #define MV_N7 0x64 #define MV_N8 0x54 #define MV_N9 0x55 #define MV_N10 0x56 #define MV_N11 0x6d #define MV_N12 0x6f #define MV_N13 0x5a #define MV_N14 0x5b #define MV_N15 0x5c #define MV_N16 0x63 #define MV_N17 0x66 #define MV_N18 0x68 #define MV_N19 0x67 #define MV_N20 0x61 #define MV_N21 0x6a #define MV_N22 0x76 #define MV_AGC_PULSE_LEVEL 0x77 #define MV_BP_PULSE_LEVEL 0x78 /*========================================================================== * * The TRACE macro can be used to display debug information. It can display * one or more parameters in a formatted string like printf. No code will be * generated for a release build. Use double parentheses for compatibility * with C #define statements. Newline characters are not added * automatically. Usage example: * * TRACE(("Number is %d, Name is %s.\n",iNumber,lpszName)) * *========================================================================== */ /*//#ifdef _DEBUG*/ /*//void trace(const char *p_fmt,...);*/ /*//#define TRACE(parameters) {trace parameters;}*/ /*//#else*/ #define TRACE(parameters) {} /*//#endif*/ /****/ /*// GCC timing structure.*/ /****/ typedef struct _S_TIMING_SPECS { int vga_width; int vga_lines; int tv_width; int tv_lines; int h_total; int h_sync; int v_total; int v_sync; } S_TIMING_SPECS; /****/ /*// Revision of Houston chip*/ /****/ #define HOUSTON_REV_A 0 #define HOUSTON_REV_B 1 static int houston_Rev(void); /*========================================================================== * * Functions * *========================================================================== */ static int houston_init(void); static unsigned char PLAL_FS450_i2c_address(void); static int PLAL_FS450_UIM_mode(void); static int PLAL_ReadRegister(S_REG_INFO * p_reg); static int PLAL_WriteRegister(const S_REG_INFO * p_reg); static int PLAL_IsTVOn(void); static int PLAL_EnableVga(void); static int PLAL_PrepForTVout(void); static int PLAL_SetTVTimingRegisters(const S_TIMING_SPECS * p_specs); static int PLAL_FinalEnableTVout(unsigned long vga_mode); /****/ /*Direct Memory Access Functions*/ /****/ /*NOTE: Cx5530 is assumed hardcoded at 0x10000 offset*/ /*from MediaGX base. F4Bar is bogus as described in the*/ /*Cx5530 datasheet (actually points to GX frame buffer).*/ /****/ static int DMAL_ReadUInt32(unsigned long phys_addr, unsigned long *p_data) { *p_data = READ_REG32(phys_addr); return 0; } static int DMAL_WriteUInt32(unsigned long phys_addr, unsigned long data) { WRITE_REG32(phys_addr, data); return 0; } /****/ /*Houston register access functions.*/ /****/ static int houston_ReadReg(unsigned int reg, unsigned long *p_value, unsigned int bytes) { return gfx_i2c_read(1, PLAL_FS450_i2c_address(), (unsigned char)reg, (unsigned char)bytes, (unsigned char *)p_value); } static int houston_WriteReg(unsigned int reg, unsigned long value, unsigned int bytes) { return gfx_i2c_write(1, PLAL_FS450_i2c_address(), (unsigned char)reg, (unsigned char)bytes, (unsigned char *)&value); } /****/ /*TV configuration functions.*/ /****/ static int config_init(void); static const S_TIMING_SPECS *p_specs(void); static void config_power(int on); static void config_vga_mode(unsigned long vga_mode); static void config_tv_std(unsigned long tv_std, unsigned int trigger_bits); static void conget_tv_std(unsigned long *p_tv_std); static unsigned long supported_standards(void); static void config_tvout_mode(unsigned long tvout_mode); static void conget_tvout_mode(unsigned long *p_tvout_mode); static void config_overscan_xy(unsigned long tv_std, unsigned long vga_mode, int overscan_x, int overscan_y, int pos_x, int pos_y); static void config_nco(unsigned long tv_std, unsigned long vga_mode); static void config_sharpness(int sharpness); static void conget_sharpness(int *p_sharpness); static void config_flicker(int flicker); static void conget_flicker(int *p_flicker); static void config_color(int color); static void conget_color(int *p_color); static void config_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits, int brightness, int contrast); static void conget_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits, int *p_brightness, int *p_contrast); static void config_yc_filter(unsigned long tv_std, int luma_filter, int chroma_filter); static void conget_yc_filter(int *p_luma_filter, int *p_chroma_filter); static void config_macrovision(unsigned long tv_std, unsigned int cp_trigger_bits); static void conget_macrovision(unsigned long tv_std, unsigned int *p_cp_trigger_bits); /****/ /*Device settings.*/ /****/ typedef struct _S_DEVICE_SETTINGS { int tv_on; unsigned long vga_mode; unsigned long tv_std; unsigned long tvout_mode; int overscan_x; int overscan_y; int position_x; int position_y; int sharpness; int flicker; int color; int brightness; int contrast; unsigned char yc_filter; unsigned int aps_trigger_bits; int last_overscan_y; } S_DEVICE_SETTINGS; static S_DEVICE_SETTINGS d; /*//==========================================================================*/ /****/ /*TV Setup Parameters*/ /****/ /*//==========================================================================*/ static const struct { unsigned long chroma_freq[5]; unsigned short chroma_phase[5]; unsigned short cphase_rst[5]; unsigned short color[5]; unsigned short cr_burst_level[5]; unsigned short cb_burst_level[5]; unsigned short sys625_50[5]; unsigned short vsync5[5]; unsigned short pal_mode[5]; unsigned short hsync_width[5]; unsigned short burst_width[5]; unsigned short back_porch[5]; unsigned short front_porch[5]; unsigned short breeze_way[5]; unsigned short activeline[5]; unsigned short blank_level[5]; unsigned short vbi_blank_level[5]; unsigned short black_level[5]; unsigned short white_level[5]; unsigned short hamp_offset[5]; unsigned short sync_level[5]; unsigned short tv_lines[5]; unsigned short tv_width[5]; unsigned short tv_active_lines[5]; unsigned short tv_active_width[5]; unsigned char notch_filter[5]; unsigned short houston_cr[5]; unsigned short houston_ncodl[5]; unsigned short houston_ncodh[5]; } tvsetup = { /* ntsc, pal, ntsc-eij, pal-m, pal-n */ { 0x1f7cf021, 0xcb8a092a, 0x1f7cf021, 0xe3efe621, 0xcb8a092a} , /*chroma_freq */ { 0, 0, 0, 0, 0} , /*chroma_phase */ { 2, 0, 2, 0, 0} , /*cphase_rst */ { 54, 43, 54, 43, 43} , /*color */ { 0, 31, 0, 29, 29} , /*cr_burst_level */ { 59, 44, 59, 41, 41} , /*cb_burst_level */ { 0, 1, 0, 0, 1} , /*sys625_50 */ { 0, 1, 0, 0, 0} , /*vsync5 */ { 0, 1, 0, 1, 1} , /*pal_mode */ { 0x7a, 0x7a, 0x7a, 0x7a, 0x7a} , /*hsync_width */ { 0x40, 0x3c, 0x40, 0x40, 0x3c} , /*burst_width */ { 0x80, 0x9a, 0x80, 0x80, 0x9a} , /*back_porch */ { 0x24, 0x1e, 0x24, 0x24, 0x1e} , /*front_porch */ { 0x19, 0x1a, 0x19, 0x12, 0x1a} , /*breeze_way */ { 0xb4, 0xb4, 0xb4, 0xb4, 0xb4} , /*active_line */ { 240, 251, 240, 240, 240} , /*blank_level */ { 240, 251, 240, 240, 240} , /*vbi_blank_level */ { 284, 252, 240, 252, 252} , /*black_level */ { 823, 821, 823, 821, 821} , /*white_level */ { 60, 48, 60, 48, 48} , /*hamp_offset */ { 0x08, 0x08, 0x08, 0x08, 0x08} , /*sync_level */ { 525, 625, 525, 525, 625} , /*tv_lines */ { 858, 864, 858, 858, 864} , /*tv_width */ { 487, 576, 487, 487, 576} , /*tv_active_lines */ { 800, 800, 800, 800, 800} , /*tv_active_width */ { 0x1a, 0x1d, 0x1a, 0x1d, 0x1d} , /*notch filter enabled */ { 0x0000, 0x0100, 0x0000, 0x0000, 0x0100} , /*houston cr pal */ { 0x7e48, 0xf580, 0x7e48, 0x7e48, 0xf580} , /*houston ncodl */ { 0x001b, 0x0020, 0x001b, 0x001b, 0x0020} /*houston ncodh */ }; /****/ /*MediaGX default underscan and centered position setups.*/ /****/ #define SCANTABLE_ENTRIES 5 struct _scantable { unsigned long mode; unsigned short v_total[5]; unsigned short v_sync[5]; unsigned short iha[5]; signed short iho[5]; signed short hsc[5]; }; static struct _scantable scantable[SCANTABLE_ENTRIES] = { { GFX_VGA_MODE_640X480, {617, 624, 617, 624, 624}, /*v_total */ {69, 88, 69, 88, 88}, /*v_sync */ {720, 720, 720, 720, 720}, /*iha */ {0, 0, 0, 0, 0}, /*iho */ {-12, 0, -6, 0, 0} /*hsc */ }, { GFX_VGA_MODE_800X600, {740, 740, 740, 740, 740}, /*v_total */ {90, 88, 90, 88, 88}, /*v_sync */ {720, 720, 508, 720, 720}, /*iha */ {-8, 11, -8, -8, 11}, /*iho */ {-27, -27, -27, -27, -27} /*hsc */ }, { GFX_VGA_MODE_720X487, {525, 720, 525, 720, 720}, /*v_total */ {23, 230, 23, 230, 230}, /*v_sync */ {720, 720, 720, 720, 720}, /*iha */ {0xa2, 0xa2, 0xa2, 0xa2, 0xa2}, /*iho */ {0, 0, 0, 0, 0} /*hsc */ }, { GFX_VGA_MODE_720X576, {720, 625, 720, 625, 625}, /*v_total */ {129, 25, 129, 25, 25}, /*v_sync */ {720, 720, 720, 720, 720}, /*iha */ {0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, /*iho */ {0, 0, 0, 0, 0} /*hsc */ }, { GFX_VGA_MODE_1024X768, {933, 942, 933, 806, 806}, /*v_total */ {121, 112, 121, 88, 88}, /*v_sync */ {600, 600, 600, 600, 600}, /*iha */ {0x3c, 0x23, 0x3c, 0x65, 0x65}, /*iho */ {35, 26, 35, 26, 26} /*hsc */ }, }; /****/ /*Houston fifo configuration constants.*/ /****/ struct _ffolat { int v_total; unsigned short ffolat; }; struct _ffolativo { int v_total; unsigned short ivo; unsigned short ffolat; }; /*h_total=832, ivo=40, tv_width=858, tv_lines=525, vga_lines=480*/ #define SIZE6X4NTSC 66 static struct _ffolat ffo6x4ntsc[SIZE6X4NTSC + 1] = { {541, 0x40}, {545, 0x40}, {549, 0x40}, {553, 0x40}, {557, 0x58}, {561, 0x40}, {565, 0x40}, {569, 0x40}, {573, 0x48}, {577, 0x40}, {581, 0x40}, {585, 0x40}, {589, 0x40}, {593, 0x48}, {597, 0x40}, {601, 0x40}, {605, 0x40}, {609, 0x40}, {613, 0x5b}, {617, 0x48}, {621, 0x60}, {625, 0x48}, {629, 0x48}, {633, 0x40}, {637, 0x5e}, {641, 0x40}, {645, 0x50}, {649, 0x56}, {653, 0x58}, {657, 0x6c}, {661, 0x40}, {665, 0x40}, {669, 0x40}, {673, 0x40}, {677, 0x40}, {681, 0x40}, {685, 0x40}, {689, 0x40}, {693, 0x40}, {697, 0x40}, {701, 0x40}, {705, 0x40}, {709, 0x40}, {713, 0x40}, {717, 0x40}, {721, 0x40}, {725, 0x40}, {729, 0x40}, {733, 0x40}, {737, 0x40}, {741, 0x40}, {745, 0x40}, {749, 0x40}, {753, 0x40}, {757, 0x40}, {761, 0x40}, {765, 0x40}, {769, 0x40}, {773, 0x40}, {777, 0x40}, {781, 0x40}, {785, 0x40}, {789, 0x40}, {793, 0x40}, {797, 0x30}, {801, 0x40}, {-1, 0} }; #define SIZE6X4PAL 45 static struct _ffolat ffo6x4pal[SIZE6X4PAL + 1] = { {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60}, {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60}, {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60}, {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60}, {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60}, {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60}, {721, 0x60}, {725, 0x60}, {729, 0x60}, {733, 0x60}, {737, 0x60}, {741, 0x60}, {745, 0x60}, {749, 0x60}, {753, 0x60}, {757, 0x60}, {761, 0x60}, {765, 0x60}, {769, 0x60}, {773, 0x60}, {777, 0x60}, {781, 0x60}, {785, 0x60}, {789, 0x60}, {793, 0x60}, {797, 0x60}, {801, 0x60}, {-1, 0} }; #define SIZE7X4NTSC 40 static struct _ffolat ffo7x4ntsc[SIZE7X4NTSC + 1] = { {525, 0x52}, {529, 0x52}, {533, 0x52}, {537, 0x52}, {541, 0x52}, {545, 0x40}, {549, 0x40}, {553, 0x40}, {557, 0x58}, {561, 0x40}, {565, 0x58}, {569, 0x40}, {573, 0x48}, {577, 0x40}, {581, 0x40}, {585, 0x40}, {589, 0x40}, {593, 0x48}, {597, 0x40}, {601, 0x40}, {605, 0x40}, {609, 0x40}, {613, 0x5b}, {617, 0x48}, {621, 0x60}, {625, 0x48}, {629, 0x48}, {633, 0x40}, {637, 0x5e}, {641, 0x40}, {645, 0x50}, {649, 0x56}, {653, 0x58}, {657, 0x6c}, {661, 0x40}, {665, 0x40}, {669, 0x40}, {673, 0x40}, {677, 0x40}, {681, 0x40}, {-1, 0} }; #define SIZE7X4PAL 24 static struct _ffolat ffo7x4pal[SIZE7X4PAL + 1] = { {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60}, {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60}, {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60}, {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60}, {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60}, {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60}, {-1, 0} }; #define SIZE7X5NTSC 54 static struct _ffolat ffo7x5ntsc[SIZE7X5NTSC + 1] = { {590, 0x40}, {594, 0x48}, {598, 0x40}, {602, 0x40}, {606, 0x40}, {610, 0x40}, {614, 0x5b}, {618, 0x48}, {622, 0x60}, {626, 0x48}, {630, 0x48}, {634, 0x40}, {638, 0x5e}, {642, 0x40}, {646, 0x50}, {650, 0x56}, {654, 0x58}, {658, 0x6c}, {662, 0x40}, {666, 0x40}, {670, 0x40}, {674, 0x40}, {678, 0x40}, {682, 0x40}, {686, 0x40}, {690, 0x40}, {694, 0x40}, {698, 0x40}, {702, 0x40}, {706, 0x40}, {710, 0x40}, {714, 0x40}, {718, 0x40}, {722, 0x40}, {726, 0x40}, {730, 0x40}, {734, 0x40}, {738, 0x40}, {742, 0x40}, {746, 0x40}, {750, 0x40}, {754, 0x40}, {758, 0x40}, {762, 0x40}, {766, 0x40}, {770, 0x40}, {774, 0x40}, {778, 0x40}, {782, 0x40}, {786, 0x40}, {790, 0x40}, {794, 0x40}, {798, 0x30}, {802, 0x40}, {-1, 0} }; #define SIZE7X5PAL 45 static struct _ffolat ffo7x5pal[SIZE7X5PAL + 1] = { {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60}, {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60}, {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60}, {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60}, {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60}, {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60}, {721, 0x60}, {725, 0x60}, {729, 0x60}, {733, 0x60}, {737, 0x60}, {741, 0x60}, {745, 0x60}, {749, 0x60}, {753, 0x60}, {757, 0x60}, {761, 0x60}, {765, 0x60}, {769, 0x60}, {773, 0x60}, {777, 0x60}, {781, 0x60}, {785, 0x60}, {789, 0x60}, {793, 0x60}, {797, 0x60}, {801, 0x60}, {-1, 0} }; /*h_total=1056, vga_lines=600*/ #define SIZE8X6NTSC 37 static struct _ffolat ffo8x6ntsc[SIZE8X6NTSC + 1] = { {620, 0x40}, /*v_total_min >= vsync+10 >= vga_lines+10 = 610 */ {625, 0x58}, {630, 0x40}, {635, 0x40}, {640, 0x40}, {645, 0x46}, {650, 0x46}, {655, 0x4f}, {660, 0x4c}, {665, 0x4a}, {670, 0x50}, {675, 0x2f}, {680, 0x48}, {685, 0x38}, {690, 0x31}, {695, 0x40}, {700, 0x21}, {705, 0x25}, {710, 0x40}, {715, 0x48}, {720, 0x50}, {725, 0x30}, {730, 0x50}, {735, 0x50}, {740, 0x50}, {745, 0x40}, {750, 0x38}, {755, 0x50}, {760, 0x50}, {765, 0x40}, {770, 0x38}, {775, 0x40}, {780, 0x40}, {785, 0x40}, {790, 0x38}, {795, 0x50}, {800, 0x50}, {-1, 0} }; /*h_total=1056, vga_lines=600*/ #define SIZE8X6PAL 36 static struct _ffolat ffo8x6pal[SIZE8X6PAL + 1] = { {625, 0x80}, {630, 0x80}, {635, 0x5a}, {640, 0x55}, {645, 0x48}, {650, 0x65}, {655, 0x65}, {660, 0x50}, {665, 0x80}, {670, 0x70}, {675, 0x56}, {680, 0x80}, {685, 0x58}, {690, 0x31}, {695, 0x80}, {700, 0x60}, {705, 0x45}, {710, 0x4a}, {715, 0x50}, {720, 0x50}, {725, 0x50}, {730, 0x45}, {735, 0x50}, {740, 0x50}, {745, 0x50}, {750, 0x50}, {755, 0x50}, {760, 0x50}, {765, 0x50}, {770, 0x50}, {775, 0x50}, {780, 0x50}, {785, 0x50}, {790, 0x50}, {795, 0x50}, {800, 0x50}, {-1, 0} }; /*h_total=1344, vga_lines=768*/ #define SIZE10X7NTSC 45 static struct _ffolativo ffo10x7ntsc[SIZE10X7NTSC] = { {783, 0x4d, 0x40}, {789, 0x47, 0x14}, {795, 0x47, 0x7f}, {801, 0x47, 0x53}, {807, 0x47, 0x11}, {813, 0x47, 0x78}, {819, 0x47, 0x54}, {825, 0x47, 0x40}, {831, 0x47, 0x0f}, {837, 0x4d, 0x40}, {843, 0x47, 0x5a}, {849, 0x4d, 0x40}, {855, 0x47, 0x4b}, {861, 0x4d, 0x40}, {867, 0x47, 0x4b}, {873, 0x4d, 0x40}, {879, 0x47, 0x07}, {885, 0x48, 0x20}, {891, 0x47, 0x82}, {897, 0x47, 0x60}, {903, 0x47, 0x7f}, {909, 0x4d, 0x40}, {915, 0x48, 0x40}, {921, 0x4c, 0x40}, {927, 0x49, 0x40}, {933, 0x48, 0x40}, {939, 0x4a, 0x40}, {945, 0x46, 0x40}, {951, 0x4a, 0x40}, {957, 0x4a, 0x40}, {963, 0x4b, 0x40}, {969, 0x4b, 0x40}, {975, 0x48, 0x40}, {981, 0x47, 0x40}, {987, 0x47, 0x40}, {993, 0x47, 0x40}, {999, 0x48, 0x40}, {1005, 0x48, 0x40}, {1011, 0x47, 0x40}, {1017, 0x47, 0x40}, {1023, 0x48, 0x40}, {1029, 0x48, 0x40}, {1035, 0x46, 0x40}, {1041, 0x47, 0x40}, {1047, 0x47, 0x40} }; /*h_total=1344, vga_lines=768*/ #define SIZE10X7PAL 46 static struct _ffolativo ffo10x7pal[SIZE10X7PAL] = { {781, 0x49, 0x40}, {787, 0x46, 0x40}, {793, 0x48, 0x40}, {799, 0x46, 0x40}, {805, 0x49, 0x40}, {811, 0x47, 0x40}, {817, 0x46, 0x40}, {823, 0x46, 0x56}, {829, 0x46, 0x2d}, {835, 0x46, 0x40}, {841, 0x46, 0x2d}, {847, 0x46, 0x3f}, {853, 0x46, 0x10}, {859, 0x46, 0x86}, {865, 0x46, 0xc9}, {871, 0x46, 0x83}, {877, 0x46, 0xa8}, {883, 0x46, 0x81}, {889, 0x46, 0xa5}, {895, 0x46, 0xa9}, {901, 0x46, 0x81}, {907, 0x46, 0xa4}, {913, 0x46, 0xa5}, {919, 0x46, 0x7f}, {925, 0x46, 0xa2}, {931, 0x46, 0x9d}, {937, 0x46, 0xc1}, {943, 0x46, 0x96}, {949, 0x46, 0xb7}, {955, 0x46, 0xb1}, {961, 0x46, 0x8a}, {967, 0x46, 0xa9}, {973, 0x46, 0xa0}, {979, 0x46, 0x40}, {985, 0x46, 0x97}, {991, 0x46, 0xb5}, {997, 0x46, 0xaa}, {1003, 0x46, 0x83}, {1009, 0x46, 0x9f}, {1015, 0x47, 0x40}, {1021, 0x46, 0xad}, {1027, 0x46, 0x87}, {1033, 0x46, 0xa2}, {1039, 0x47, 0x40}, {1045, 0x46, 0xac}, {1051, 0x46, 0x86} }; /*//==========================================================================*/ /****/ /*FS450 API Functions.*/ /****/ /*//==========================================================================*/ /****/ /*Initialize device settings*/ /****/ static void initialize_houston_static_registers(void) { houston_WriteReg(HOUSTON_BYP, 0, 2); houston_WriteReg(HOUSTON_APO, 0, 2); houston_WriteReg(HOUSTON_ALO, 0, 2); houston_WriteReg(HOUSTON_AFO, 0, 2); houston_WriteReg(HOUSTON_BCONTL, 0, 2); houston_WriteReg(HOUSTON_BCONTH, 0, 2); houston_WriteReg(HOUSTON_BDONE, 0, 2); houston_WriteReg(HOUSTON_BDIAGL, 0, 2); houston_WriteReg(HOUSTON_BDIAGH, 0, 2); houston_WriteReg(HOUSTON_MISC, 0, 2); } int FS450_init(void) { int err; TRACE(("FS450_Init()\n")) err = houston_init(); if (err) return err; initialize_houston_static_registers(); #if 1 d.tv_on = PLAL_IsTVOn()? 1 : 0; #else d.tv_on = 0; #endif #if 1 /*get the current tv standard */ conget_tv_std(&d.tv_std); #else /*default to VP_TV_STANDARD_NTSC_M */ d.tv_std = VP_TV_STANDARD_NTSC_M; config_tv_std(d.tv_std); #endif d.vga_mode = 0; #if 0 /*get the current tvout mode */ conget_tvout_mode(&d.tvout_mode); #else /*default to VP_TVOUT_MODE_CVBS_YC */ d.tvout_mode = GFX_TVOUT_MODE_CVBS_YC; #endif #if 0 /*get the current sharpness */ conget_sharpness(d.sharpness); #else /*default to 1000 out of 1000 */ d.sharpness = 1000; config_sharpness(d.sharpness); #endif #if 0 /*get the current flicker */ conget_flicker(d.flicker); #else /*default to 800 out of 1000 */ d.flicker = 800; config_flicker(d.flicker); #endif #if 0 /*get the current size and position */ #else /*default to zeros */ d.overscan_x = 0; d.overscan_y = 0; d.position_x = 0; d.position_y = 0; #endif #if 0 /*get the current color */ conget_color(d.color); #else d.color = 50; /*//d.color = tvsetup.color[k]; */ config_color(d.color); #endif #if 0 /*get the current brightness and contrast */ conget_brightness_contrast(d.tv_std, d.aps_trigger_bits, d.brightness, d.contrast); #else /*default */ d.brightness = 50; d.contrast = 60; config_brightness_contrast(d.tv_std, d.aps_trigger_bits, d.brightness, d.contrast); #endif #if 1 /*get the current yc filtering */ { int luma_filter, chroma_filter; conget_yc_filter(&luma_filter, &chroma_filter); d.yc_filter = 0; if (luma_filter) d.yc_filter |= GFX_LUMA_FILTER; if (chroma_filter) d.yc_filter |= GFX_CHROMA_FILTER; } #else /*default */ d.yc_filter = GFX_LUMA_FILTER + GFX_CHROMA_FILTER; #endif #if 0 /*get the current cp settings */ conget_macrovision(d.tv_std, &d.aps_trigger_bits); #else d.aps_trigger_bits = 0; config_macrovision(d.tv_std, d.aps_trigger_bits); #endif d.last_overscan_y = -10000; return 0; } void FS450_cleanup(void) { } /*//==========================================================================*/ /****/ /*// Required configuration calls to write new settings to the device*/ #define REQ_TV_STANDARD_BIT 0x0002 #define REQ_VGA_MODE_BIT 0x0004 #define REQ_TVOUT_MODE_BIT 0x0008 #define REQ_SHARPNESS_BIT 0x0010 #define REQ_FLICKER_BIT 0x0020 #define REQ_OVERSCAN_POSITION_BIT 0x0040 #define REQ_COLOR_BIT 0x0080 #define REQ_BRIGHTNESS_CONTRAST_BIT 0x0100 #define REQ_YC_FILTER_BIT 0x0200 #define REQ_MACROVISION_BIT 0x0400 #define REQ_NCO_BIT 0x1000 #define REQ_TV_STANDARD (REQ_TV_STANDARD_BIT | REQ_OVERSCAN_POSITION | REQ_BRIGHTNESS_CONTRAST | REQ_MACROVISION_BIT | REQ_YC_FILTER) #define REQ_VGA_MODE (REQ_VGA_MODE_BIT | REQ_OVERSCAN_POSITION) #define REQ_TVOUT_MODE (REQ_TVOUT_MODE_BIT) #define REQ_SHARPNESS (REQ_SHARPNESS_BIT) #define REQ_FLICKER (REQ_FLICKER_BIT) #define REQ_OVERSCAN_POSITION (REQ_OVERSCAN_POSITION_BIT | REQ_NCO) #define REQ_COLOR (REQ_COLOR_BIT) #define REQ_BRIGHTNESS_CONTRAST (REQ_BRIGHTNESS_CONTRAST_BIT) #define REQ_YC_FILTER (REQ_YC_FILTER_BIT) #define REQ_MACROVISION (REQ_TV_STANDARD_BIT | REQ_BRIGHTNESS_CONTRAST_BIT | REQ_MACROVISION_BIT) #define REQ_NCO (REQ_NCO_BIT) #define REQ_ENCODER (REQ_TV_STANDARD | REQ_COLOR | REQ_BRIGHTNESS_CONTRAST | REQ_YC_FILTER) static int write_config(int req) { unsigned long reg, reg_encoder_reset = 0; int reset; /*if we're changing the nco, and the vertical scaling has changed... */ reset = ((REQ_NCO_BIT & req) && (d.overscan_y != d.last_overscan_y)); if (reset) { /*put the encoder into reset while making changes */ houston_ReadReg(ENC_RESET, ®, 1); houston_WriteReg(ENC_RESET, reg | 0x01, 1); reg_encoder_reset = reg & 0x01; } if (REQ_TV_STANDARD_BIT & req) config_tv_std(d.tv_std, d.aps_trigger_bits); if (REQ_VGA_MODE_BIT & req) config_vga_mode(d.vga_mode); if (REQ_TVOUT_MODE_BIT & req) config_tvout_mode(d.tvout_mode); if (REQ_OVERSCAN_POSITION_BIT & req) { config_overscan_xy(d.tv_std, d.vga_mode, d.overscan_x, d.overscan_y, d.position_x, d.position_y); /*h_timing and v_timing and syncs. */ if (PLAL_IsTVOn()) PLAL_SetTVTimingRegisters(p_specs()); } if (REQ_NCO_BIT & req) config_nco(d.tv_std, d.vga_mode); if (REQ_SHARPNESS_BIT & req) config_sharpness(d.sharpness); if (REQ_FLICKER_BIT & req) config_flicker(d.flicker); if (REQ_COLOR_BIT & req) config_color(d.color); if (REQ_BRIGHTNESS_CONTRAST_BIT & req) { config_brightness_contrast(d.tv_std, d.aps_trigger_bits, d.brightness, d.contrast); } if (REQ_YC_FILTER_BIT & req) { config_yc_filter(d.tv_std, (d.yc_filter & GFX_LUMA_FILTER), (d.yc_filter & GFX_CHROMA_FILTER)); } if (REQ_MACROVISION_BIT & req) config_macrovision(d.tv_std, d.aps_trigger_bits); /*if we decided to put the encoder into reset, put it back */ if (reset) { houston_ReadReg(ENC_RESET, ®, 1); houston_WriteReg(ENC_RESET, reg_encoder_reset | (reg & ~0x01), 1); d.last_overscan_y = d.overscan_y; } return 0; } /*==========================================================================*/ /****/ /*// TV On*/ #if GFX_TV_DYNAMIC int fs450_get_tv_enable(unsigned int *p_on) #else int gfx_get_tv_enable(unsigned int *p_on) #endif { if (!p_on) return ERR_INVALID_PARAMETER; *p_on = d.tv_on; return 0; } /*//int FS450_set_tv_on(unsigned int on)*/ #if GFX_TV_DYNAMIC int fs450_set_tv_enable(int on) #else int gfx_set_tv_enable(int on) #endif { unsigned long reg; /*if not mode change, just return */ if ((d.tv_on && on) || (!d.tv_on && !on)) return 0; /*if turning off... */ if (!on) { /*reenable vga. */ PLAL_EnableVga(); /*power down houston */ config_power(0); d.tv_on = 0; return 0; } /*turning on... */ /*power up houston */ config_power(1); /*assert encoder reset. */ houston_WriteReg(ENC_RESET, 0x01, 1); /*initial platform preparation */ PLAL_PrepForTVout(); /*configure encoder and nco. */ write_config(REQ_VGA_MODE | REQ_TV_STANDARD | REQ_TVOUT_MODE | REQ_OVERSCAN_POSITION | REQ_YC_FILTER | REQ_MACROVISION); /*set LP_EN and UIM */ houston_ReadReg(HOUSTON_CR, ®, 2); reg |= CR_LP_EN; reg &= ~(CR_UIM_MOD0 | CR_UIM_MOD1); reg |= (PLAL_FS450_UIM_mode() << 14); houston_WriteReg(HOUSTON_CR, reg, 2); /*set platform timing registers */ PLAL_SetTVTimingRegisters(p_specs()); PLAL_FinalEnableTVout(d.vga_mode); /*sync bridge */ { int retry_count = 0; /*sync 50 times */ while (retry_count++ < 50) { /*sync bridge. */ houston_ReadReg(HOUSTON_MISC, ®, 2); reg |= MISC_BRIDGE_SYNC; houston_WriteReg(HOUSTON_MISC, reg, 2); reg &= ~MISC_BRIDGE_SYNC; houston_WriteReg(HOUSTON_MISC, reg, 2); } } /*deassert encoder reset. */ houston_WriteReg(ENC_RESET, 0x00, 1); d.tv_on = 1; return 0; } #if GFX_TV_DYNAMIC int fs450_set_tv_defaults(int format) #else int gfx_set_tv_defaults(int format) #endif { return 0; } /*==========================================================================*/ /****/ /*// TV standard*/ #if GFX_TV_DYNAMIC int fs450_get_tv_standard(unsigned long *p_standard) #else int gfx_get_tv_standard(unsigned long *p_standard) #endif { if (!p_standard) return ERR_INVALID_PARAMETER; *p_standard = d.tv_std; return 0; } #if GFX_TV_DYNAMIC int fs450_get_available_tv_standards(unsigned long *p_standards) #else int gfx_get_available_tv_standards(unsigned long *p_standards) #endif { if (!p_standards) return ERR_INVALID_PARAMETER; *p_standards = supported_standards(); return 0; } #if GFX_TV_DYNAMIC int fs450_set_tv_standard(unsigned long standard) #else int gfx_set_tv_standard(unsigned long standard) #endif { /*verify supported standard. */ if (!(standard & supported_standards())) return ERR_INVALID_PARAMETER; /*disallow if tv is on */ if (d.tv_on) return ERR_CANNOT_CHANGE_WHILE_TV_ON; d.tv_std = standard; /*// d.color = tvsetup.color[k];*/ return write_config(REQ_TV_STANDARD); } /*==========================================================================*/ /****/ /*// vga mode as known by the driver*/ #if GFX_TV_DYNAMIC int fs450_get_tv_vga_mode(unsigned long *p_vga_mode) #else int gfx_get_tv_vga_mode(unsigned long *p_vga_mode) #endif { if (!p_vga_mode) return ERR_INVALID_PARAMETER; *p_vga_mode = d.vga_mode; return 0; } #if GFX_TV_DYNAMIC int fs450_get_available_tv_vga_modes(unsigned long *p_vga_modes) #else int gfx_get_available_tv_vga_modes(unsigned long *p_vga_modes) #endif { if (!p_vga_modes) return ERR_INVALID_PARAMETER; *p_vga_modes = GFX_VGA_MODE_640X480 | GFX_VGA_MODE_720X487 | GFX_VGA_MODE_720X576 | GFX_VGA_MODE_800X600; if (houston_Rev() >= HOUSTON_REV_B) *p_vga_modes |= GFX_VGA_MODE_1024X768; return 0; } #if GFX_TV_DYNAMIC int fs450_set_tv_vga_mode(unsigned long vga_mode) #else int gfx_set_tv_vga_mode(unsigned long vga_mode) #endif { /*reject if not a single valid VGA mode */ switch (vga_mode) { default: return ERR_INVALID_PARAMETER; case GFX_VGA_MODE_640X480: case GFX_VGA_MODE_720X487: case GFX_VGA_MODE_720X576: case GFX_VGA_MODE_800X600: break; case GFX_VGA_MODE_1024X768: if (houston_Rev() >= HOUSTON_REV_B) break; return ERR_INVALID_PARAMETER; } /*if the mode has changed... */ if (vga_mode != d.vga_mode) { d.vga_mode = vga_mode; return write_config(REQ_VGA_MODE); } return 0; } /*==========================================================================*/ /****/ /*// tvout mode*/ #if GFX_TV_DYNAMIC int fs450_get_tvout_mode(unsigned long *p_tvout_mode) #else int gfx_get_tvout_mode(unsigned long *p_tvout_mode) #endif { if (!p_tvout_mode) return ERR_INVALID_PARAMETER; *p_tvout_mode = d.tvout_mode; return 0; } #if GFX_TV_DYNAMIC int fs450_set_tvout_mode(unsigned long tvout_mode) #else int gfx_set_tvout_mode(unsigned long tvout_mode) #endif { d.tvout_mode = tvout_mode; return write_config(REQ_TVOUT_MODE); } /*==========================================================================*/ /****/ /*// Sharpness*/ #if GFX_TV_DYNAMIC int fs450_get_sharpness(int *p_sharpness) #else int gfx_get_sharpness(int *p_sharpness) #endif { if (!p_sharpness) return ERR_INVALID_PARAMETER; *p_sharpness = d.sharpness; return 0; } #if GFX_TV_DYNAMIC int fs450_set_sharpness(int sharpness) #else int gfx_set_sharpness(int sharpness) #endif { d.sharpness = range_limit(sharpness, 0, 1000); return write_config(REQ_SHARPNESS); } /*==========================================================================*/ /****/ /*flicker filter control.*/ #if GFX_TV_DYNAMIC int fs450_get_flicker_filter(int *p_flicker) #else int gfx_get_flicker_filter(int *p_flicker) #endif { if (!p_flicker) return ERR_INVALID_PARAMETER; *p_flicker = d.flicker; return 0; } #if GFX_TV_DYNAMIC int fs450_set_flicker_filter(int flicker) #else int gfx_set_flicker_filter(int flicker) #endif { d.flicker = range_limit(flicker, 0, 1000); return write_config(REQ_FLICKER); } /*==========================================================================*/ /****/ /*// Overscan and Position*/ #if GFX_TV_DYNAMIC int fs450_get_overscan(int *p_x, int *p_y) #else int gfx_get_overscan(int *p_x, int *p_y) #endif { if (!p_x || !p_y) return ERR_INVALID_PARAMETER; *p_x = d.overscan_x; *p_y = d.overscan_y; return 0; } #if GFX_TV_DYNAMIC int fs450_set_overscan(int x, int y) #else int gfx_set_overscan(int x, int y) #endif { d.overscan_x = range_limit(x, -1000, 1000); d.overscan_y = range_limit(y, -1000, 1000); return write_config(REQ_OVERSCAN_POSITION); } #if GFX_TV_DYNAMIC int fs450_get_position(int *p_x, int *p_y) #else int gfx_get_position(int *p_x, int *p_y) #endif { if (!p_x || !p_y) return ERR_INVALID_PARAMETER; *p_x = d.position_x; *p_y = d.position_y; return 0; } #if GFX_TV_DYNAMIC int fs450_set_position(int x, int y) #else int gfx_set_position(int x, int y) #endif { d.position_x = range_limit(x, -1000, 1000); d.position_y = range_limit(y, -1000, 1000); return write_config(REQ_OVERSCAN_POSITION); } /*==========================================================================*/ /****/ /*// Color, Brightness, and Contrast*/ #if GFX_TV_DYNAMIC int fs450_get_color(int *p_color) #else int gfx_get_color(int *p_color) #endif { if (!p_color) return ERR_INVALID_PARAMETER; *p_color = d.color; return 0; } #if GFX_TV_DYNAMIC int fs450_set_color(int color) #else int gfx_set_color(int color) #endif { d.color = range_limit(color, 0, 100); return write_config(REQ_COLOR); } #if GFX_TV_DYNAMIC int fs450_get_brightness(int *p_brightness) #else int gfx_get_brightness(int *p_brightness) #endif { if (!p_brightness) return ERR_INVALID_PARAMETER; *p_brightness = d.brightness; return 0; } #if GFX_TV_DYNAMIC int fs450_set_brightness(int brightness) #else int gfx_set_brightness(int brightness) #endif { d.brightness = range_limit(brightness, 0, 100); return write_config(REQ_BRIGHTNESS_CONTRAST); } #if GFX_TV_DYNAMIC int fs450_get_contrast(int *p_contrast) #else int gfx_get_contrast(int *p_contrast) #endif { if (!p_contrast) return ERR_INVALID_PARAMETER; *p_contrast = d.contrast; return 0; } #if GFX_TV_DYNAMIC int fs450_set_contrast(int constrast) #else int gfx_set_contrast(int constrast) #endif { d.contrast = range_limit(constrast, 0, 100); return write_config(REQ_BRIGHTNESS_CONTRAST); } /*==========================================================================*/ /****/ /*// YC filters*/ #if GFX_TV_DYNAMIC int fs450_get_yc_filter(unsigned int *p_yc_filter) #else int gfx_get_yc_filter(unsigned int *p_yc_filter) #endif { if (!p_yc_filter) return ERR_INVALID_PARAMETER; if (houston_Rev() < HOUSTON_REV_B) return ERR_NOT_SUPPORTED; *p_yc_filter = d.yc_filter; return 0; } #if GFX_TV_DYNAMIC int fs450_set_yc_filter(unsigned int yc_filter) #else int gfx_set_yc_filter(unsigned int yc_filter) #endif { if (houston_Rev() < HOUSTON_REV_B) return ERR_NOT_SUPPORTED; /*luma filter. */ if (yc_filter & GFX_LUMA_FILTER) d.yc_filter |= GFX_LUMA_FILTER; else d.yc_filter &= ~GFX_LUMA_FILTER; /*chroma filter. */ if (yc_filter & GFX_CHROMA_FILTER) d.yc_filter |= GFX_CHROMA_FILTER; else d.yc_filter &= ~GFX_CHROMA_FILTER; return write_config(REQ_YC_FILTER); } #if GFX_TV_DYNAMIC int fs450_get_aps_trigger_bits(unsigned int *p_trigger_bits) #else int gfx_get_aps_trigger_bits(unsigned int *p_trigger_bits) #endif { if (!p_trigger_bits) return ERR_INVALID_PARAMETER; *p_trigger_bits = d.aps_trigger_bits; return 0; } #if GFX_TV_DYNAMIC int fs450_set_aps_trigger_bits(unsigned int trigger_bits) #else int gfx_set_aps_trigger_bits(unsigned int trigger_bits) #endif { d.aps_trigger_bits = trigger_bits; return write_config(REQ_MACROVISION); } /*----------------------------------------------------------------------------- * gfx_set_tv_format * * This routine sets the TV encoder registers to the specified format * and resolution. * Currently only NTSC 640x480 is supported. *----------------------------------------------------------------------------- */ #if GFX_TV_DYNAMIC int fs450_set_tv_format(TVStandardType format, GfxOnTVType resolution) #else int gfx_set_tv_format(TVStandardType format, GfxOnTVType resolution) #endif { /* ### ADD ### IMPLEMENTATION */ return (0); } /*----------------------------------------------------------------------------- * gfx_set_tv_output * * This routine sets the TV encoder registers to the specified output type. * Supported output types are : S-VIDEO and Composite. *----------------------------------------------------------------------------- */ #if GFX_TV_DYNAMIC int fs450_set_tv_output(int output) #else int gfx_set_tv_output(int output) #endif { /* ### ADD ### IMPLEMENTATION */ return (0); } /*----------------------------------------------------------------------------- * gfx_set_tv_cc_enable * * This routine enables or disables the use of the hardware CC registers * in the TV encoder. *----------------------------------------------------------------------------- */ #if GFX_TV_DYNAMIC int fs450_set_tv_cc_enable(int enable) #else int gfx_set_tv_cc_enable(int enable) #endif { /* ### ADD ### IMPLEMENTATION */ return (0); } /*----------------------------------------------------------------------------- * gfx_set_tv_cc_data * * This routine writes the two specified characters to the CC data register * of the TV encoder. *----------------------------------------------------------------------------- */ #if GFX_TV_DYNAMIC int fs450_set_tv_cc_data(unsigned char data1, unsigned char data2) #else int gfx_set_tv_cc_data(unsigned char data1, unsigned char data2) #endif { /* ### ADD ### IMPLEMENTATION */ return (0); } #ifdef FS450_DIRECTREG /*//==========================================================================*/ /****/ /*// Direct Read and Write registers*/ int FS450_ReadRegister(S_REG_INFO * p_reg) { unsigned long tmp; if (PLAL_ReadRegister(p_reg)) return 0; if (SOURCE_HOUSTON == p_reg->source) { switch (p_reg->size) { case 1: case 2: { houston_ReadReg((int)p_reg->offset, &tmp, (int)p_reg->size); p_reg->value = tmp; } return 0; case 4: { houston_ReadReg((unsigned int)p_reg->offset, &tmp, 2); p_reg->value = (tmp << 16); houston_ReadReg((unsigned int)(p_reg->offset + 2), &tmp, 2); p_reg->value |= tmp; } return 0; } } return ERR_INVALID_PARAMETER; } int FS450_WriteRegister(S_REG_INFO * p_reg) { if (PLAL_WriteRegister(p_reg)) return 0; if (SOURCE_HOUSTON == p_reg->source) { houston_WriteReg((unsigned int)p_reg->offset, p_reg->value, p_reg->size); return 0; } return ERR_INVALID_PARAMETER; } #endif /****/ /*Houston initialization function.*/ /****/ static int g_houston_rev = -1; static int houston_init(void) { /*//int errc; */ unsigned long write, read; TRACE(("houston_init()\n")) /*initialize I2C */ /*errc = I2C_init(); * if (errc) * return errc; */ /*Before we begin, we must enable power to the TFT */ read = READ_VID32(CS5530_DISPLAY_CONFIG); read |= CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN; WRITE_VID32(CS5530_DISPLAY_CONFIG, read); /*simple w/r test. */ write = 0x0055; read = 0; houston_WriteReg(HOUSTON_IHO, write, 2); houston_ReadReg(HOUSTON_IHO, &read, 2); if (read != write) { houston_WriteReg(HOUSTON_IHO, write, 2); houston_ReadReg(HOUSTON_IHO, &read, 2); if (read != write) { /*chip is not there, do something appropriate? */ TRACE(("wrote HOUSTON_IHO=0x0055, read 0x%04x\n", read)) return ERR_DEVICE_NOT_FOUND; } } /*read chip revision. */ houston_ReadReg(HOUSTON_REV, &read, 2); g_houston_rev = (int)read; /*ok. */ return 0; } static int houston_Rev(void) { return g_houston_rev; } static S_TIMING_SPECS g_specs; static const S_TIMING_SPECS * p_specs(void) { return &g_specs; } /*//==========================================================================*/ /****/ /*FS450 configuration functions.*/ /****/ /*//==========================================================================*/ static int config_init(void) { int err; TRACE(("config_init()\n")) err = houston_init(); if (err) return err; return 0; } /*==========================================================================*/ /****/ /*convert word to encoder 10 bit value.*/ static unsigned short w10bit2z(unsigned short w) { return (w >> 2) | ((w & 0x03) << 8); } static unsigned short z2w10bit(unsigned short z) { return (0x03 & (z >> 8)) | ((0xFF & z) << 2); } /*==========================================================================*/ /****/ /*// TV Standards*/ static const struct { unsigned long standard; int tvsetup_index; } g_tv_standards[] = { { GFX_TV_STANDARD_NTSC_M, 0} , { GFX_TV_STANDARD_NTSC_M_J, 2} , { GFX_TV_STANDARD_PAL_B, 1} , { GFX_TV_STANDARD_PAL_D, 1} , { GFX_TV_STANDARD_PAL_H, 1} , { GFX_TV_STANDARD_PAL_I, 1} , { GFX_TV_STANDARD_PAL_M, 3} , { GFX_TV_STANDARD_PAL_N, 4} , { GFX_TV_STANDARD_PAL_G, 1} ,}; static int map_tvstd_to_index(unsigned long tv_std) { unsigned int i; for (i = 0; i < sizeof(g_tv_standards) / sizeof(*g_tv_standards); i++) { if (tv_std == g_tv_standards[i].standard) return g_tv_standards[i].tvsetup_index; } return -1; } static unsigned long supported_standards(void) { unsigned long standards = 0; unsigned int i; for (i = 0; i < sizeof(g_tv_standards) / sizeof(*g_tv_standards); i++) { if (g_tv_standards[i].tvsetup_index >= 0) standards |= g_tv_standards[i].standard; } return standards; } /*==========================================================================*/ static void config_power(int on) { unsigned long reg; if (houston_Rev() < HOUSTON_REV_B) { /*no power down supported, but still turn of clock in off mode */ if (on) { houston_ReadReg(HOUSTON_CR, ®, 2); reg &= ~(CR_CLKOFF | CR_RESET); houston_WriteReg(HOUSTON_CR, reg, 2); reg |= CR_RESET; houston_WriteReg(HOUSTON_CR, reg, 2); reg &= ~CR_RESET; houston_WriteReg(HOUSTON_CR, reg, 2); } else { houston_ReadReg(HOUSTON_CR, ®, 2); reg |= CR_CLKOFF; houston_WriteReg(HOUSTON_CR, reg, 2); } return; } if (on) { /*!CLKOFF, !COMPOFF, !YCOFF */ /*and reset Houston */ houston_ReadReg(HOUSTON_CR, ®, 2); reg &= ~(CR_CLKOFF | CR_RESET | CR_COMPOFF | CR_YCOFF); houston_WriteReg(HOUSTON_CR, reg, 2); reg |= CR_RESET; houston_WriteReg(HOUSTON_CR, reg, 2); reg &= ~CR_RESET; houston_WriteReg(HOUSTON_CR, reg, 2); /*!GTLIO_PD */ houston_ReadReg(HOUSTON_MISC, ®, 2); reg &= ~MISC_GTLIO_PD; houston_WriteReg(HOUSTON_MISC, reg, 2); } else { /*CLKOFF, COMPOFF, YCOFF */ houston_ReadReg(HOUSTON_CR, ®, 2); reg |= (CR_CLKOFF | CR_COMPOFF | CR_YCOFF); houston_WriteReg(HOUSTON_CR, reg, 2); /*GTLIO_PD */ houston_ReadReg(HOUSTON_MISC, ®, 2); reg |= MISC_GTLIO_PD; houston_WriteReg(HOUSTON_MISC, reg, 2); } } /*==========================================================================*/ /****/ /*// VGA mode*/ static void config_vga_mode(unsigned long vga_mode) { /*h_total must be evenly divisible by 32? */ static struct { unsigned long mode; int width; int lines; int h_total; } vgaparams[] = { { GFX_VGA_MODE_640X480, 640, 480, 1056} , { GFX_VGA_MODE_720X487, 720, 487, 1056} , { GFX_VGA_MODE_720X576, 720, 576, 1056} , { GFX_VGA_MODE_800X600, 800, 600, 1056} , { GFX_VGA_MODE_1024X768, 1024, 768, 1344} ,}; unsigned long cr, misc, byp; unsigned int i; g_specs.vga_width = 0; g_specs.vga_lines = 0; g_specs.h_total = 0; for (i = 0; i < sizeof(vgaparams) / sizeof(*vgaparams); i++) { if (vga_mode == vgaparams[i].mode) { g_specs.vga_width = vgaparams[i].width; g_specs.vga_lines = vgaparams[i].lines; g_specs.h_total = vgaparams[i].h_total; break; } } if (!g_specs.h_total) return; /*clock mux decimator and vga dual. */ houston_ReadReg(HOUSTON_CR, &cr, 2); houston_ReadReg(HOUSTON_MISC, &misc, 2); houston_ReadReg(HOUSTON_BYP, &byp, 2); if (vga_mode == GFX_VGA_MODE_1024X768) { /*XGA*/ cr |= CR_UIM_DEC; misc |= MISC_VGACKDIV; byp |= (BYP_HDS_BYPASS | BYP_CAC_BYPASS); } else { /*VGA,SVGA */ cr &= ~CR_UIM_DEC; misc &= ~MISC_VGACKDIV; byp &= ~(BYP_HDS_BYPASS | BYP_CAC_BYPASS); } houston_WriteReg(HOUSTON_CR, cr, 2); houston_WriteReg(HOUSTON_MISC, misc, 2); houston_WriteReg(HOUSTON_BYP, byp, 2); } /*==========================================================================*/ /****/ /*// Write settings for TV standard to device*/ static void config_tv_std(unsigned long tv_std, unsigned int trigger_bits) { int k; unsigned short reg34; unsigned long cr, w; unsigned long l; /*verify supported standard. */ k = map_tvstd_to_index(tv_std); if (k < 0) return; /*store tv width and lines */ g_specs.tv_width = tvsetup.tv_width[k]; g_specs.tv_lines = tvsetup.tv_lines[k]; /*houston CR register. */ houston_ReadReg(HOUSTON_CR, &cr, 2); cr &= ~CR_656_PAL_NTSC; cr |= tvsetup.houston_cr[k]; houston_WriteReg(HOUSTON_CR, cr, 2); /*setup the encoder. */ l = tvsetup.chroma_freq[k]; houston_WriteReg(ENC_CHROMA_FREQ, (int)(l & 0x00ff), 1); houston_WriteReg(ENC_CHROMA_FREQ + 1, (int)((l >> 8) & 0x00ff), 1); houston_WriteReg(ENC_CHROMA_FREQ + 2, (int)((l >> 16) & 0x00ff), 1); houston_WriteReg(ENC_CHROMA_FREQ + 3, (int)((l >> 24) & 0x00ff), 1); houston_WriteReg(ENC_CHROMA_PHASE, tvsetup.chroma_phase[k], 1); houston_WriteReg(ENC_REG05, 0x00, 1); /*reg 0x05 */ houston_WriteReg(ENC_REG06, 0x89, 1); /*reg 0x06 */ houston_WriteReg(ENC_REG07, 0x00, 1); /*reg 0x07 */ houston_WriteReg(ENC_HSYNC_WIDTH, tvsetup.hsync_width[k], 1); houston_WriteReg(ENC_BURST_WIDTH, tvsetup.burst_width[k], 1); houston_WriteReg(ENC_BACK_PORCH, tvsetup.back_porch[k], 1); houston_WriteReg(ENC_CB_BURST_LEVEL, tvsetup.cb_burst_level[k], 1); houston_WriteReg(ENC_CR_BURST_LEVEL, tvsetup.cr_burst_level[k], 1); houston_WriteReg(ENC_SLAVE_MODE, 0x01, 1); /*slave mode */ if (trigger_bits == 0) w = w10bit2z(tvsetup.blank_level[k]); /*blank level */ else w = w10bit2z((unsigned short)(tvsetup.blank_level[k] - tvsetup.hamp_offset[k])); houston_WriteReg(ENC_BLANK_LEVEL, w & 0x00ff, 1); houston_WriteReg(ENC_BLANK_LEVEL + 1, w >> 8, 1); w = w10bit2z(tvsetup.tv_lines[k]); /*num_lines */ houston_WriteReg(ENC_NUM_LINES, w & 0x00ff, 1); houston_WriteReg(ENC_NUM_LINES + 1, w >> 8, 1); houston_WriteReg(ENC_TINT, 0x00, 1); /*tint */ houston_WriteReg(ENC_BREEZE_WAY, tvsetup.breeze_way[k], 1); houston_WriteReg(ENC_FRONT_PORCH, tvsetup.front_porch[k], 1); houston_WriteReg(ENC_ACTIVELINE, tvsetup.activeline[k], 1); houston_WriteReg(ENC_FIRST_LINE, 0x15, 1); /*firstvideoline */ reg34 = 0x80 | (tvsetup.pal_mode[k] << 6) | (tvsetup.sys625_50[k] << 3) | (tvsetup.cphase_rst[k] << 1) | (tvsetup.vsync5[k]); houston_WriteReg(ENC_REG34, reg34, 1); /*reg 0x34 */ houston_WriteReg(ENC_SYNC_LEVEL, tvsetup.sync_level[k], 1); if (trigger_bits == 0) w = w10bit2z(tvsetup.vbi_blank_level[k]); /*blank level */ else w = w10bit2z((unsigned short)(tvsetup.vbi_blank_level[k] - 1)); houston_WriteReg(ENC_VBI_BLANK_LEVEL, w & 0x00ff, 1); houston_WriteReg(ENC_VBI_BLANK_LEVEL + 1, w >> 8, 1); } static void conget_tv_std(unsigned long *p_tv_standard) { unsigned long cr; if (!p_tv_standard) return; /*just pick between NTSC and PAL */ houston_ReadReg(HOUSTON_CR, &cr, 2); if (CR_656_PAL_NTSC & cr) *p_tv_standard = GFX_TV_STANDARD_PAL_B; else *p_tv_standard = GFX_TV_STANDARD_NTSC_M; } /*==========================================================================*/ /****/ /*// TVout mode*/ static void config_tvout_mode(unsigned long tvout_mode) { unsigned long cr; houston_ReadReg(HOUSTON_CR, &cr, 2); /*all dacs off */ cr |= (CR_COMPOFF | CR_YCOFF); /*not rgb */ cr &= ~CR_OFMT; /*turn on requested output */ if (GFX_TVOUT_MODE_CVBS & tvout_mode) cr &= ~CR_COMPOFF; if (GFX_TVOUT_MODE_YC & tvout_mode) cr &= ~CR_YCOFF; if (GFX_TVOUT_MODE_RGB & tvout_mode) { cr &= ~(CR_COMPOFF | CR_YCOFF); cr |= CR_OFMT; } houston_WriteReg(HOUSTON_CR, cr, 2); } static void conget_tvout_mode(unsigned long *p_tvout_mode) { unsigned long cr; if (!p_tvout_mode) return; houston_ReadReg(HOUSTON_CR, &cr, 2); if (CR_OFMT & cr) *p_tvout_mode = GFX_TVOUT_MODE_RGB; else { *p_tvout_mode = 0; if (!(CR_YCOFF & cr)) *p_tvout_mode |= GFX_TVOUT_MODE_YC; if (!(CR_COMPOFF & cr)) *p_tvout_mode |= GFX_TVOUT_MODE_CVBS; } } /*==========================================================================*/ /****/ /*// Size & Position*/ #define IS_NTSC(tv_std) (tv_std & ( \ GFX_TV_STANDARD_NTSC_M | \ GFX_TV_STANDARD_NTSC_M_J | \ GFX_TV_STANDARD_PAL_M)) #define IS_PAL(tv_std) (tv_std & ( \ GFX_TV_STANDARD_PAL_B | \ GFX_TV_STANDARD_PAL_D | \ GFX_TV_STANDARD_PAL_H | \ GFX_TV_STANDARD_PAL_I | \ GFX_TV_STANDARD_PAL_N | \ GFX_TV_STANDARD_PAL_G)) /*return fifo delay setting for mode, std, and total lines.*/ static void get_ffolat_ivo(unsigned long vga_mode, unsigned long tv_std, long i, unsigned short *ffolat, unsigned short *ivo) { switch (vga_mode) { case GFX_VGA_MODE_640X480: if (IS_NTSC(tv_std)) { if (i > SIZE6X4NTSC - 1) i = SIZE6X4NTSC - 1; *ffolat = ffo6x4ntsc[i].ffolat; *ivo = 0x20; } else { if (i > SIZE6X4PAL - 1) i = SIZE6X4PAL - 1; *ffolat = ffo6x4pal[i].ffolat; *ivo = 0x28; } break; case GFX_VGA_MODE_800X600: if (IS_NTSC(tv_std)) { if (i > SIZE8X6NTSC - 1) i = SIZE8X6NTSC - 1; *ffolat = ffo8x6ntsc[i].ffolat; *ivo = 0x3a; } else { if (i > SIZE8X6PAL - 1) i = SIZE8X6PAL - 1; *ffolat = ffo8x6pal[i].ffolat; *ivo = 0x39; } break; case GFX_VGA_MODE_720X487: *ffolat = 0x40; /*//FFO7x4; */ *ivo = 0x1a; break; case GFX_VGA_MODE_720X576: *ffolat = 0x40; /*//FFO7x5; */ *ivo = 0x1a; break; case GFX_VGA_MODE_1024X768: default: if (IS_NTSC(tv_std)) { if (i > SIZE10X7NTSC - 1) i = SIZE10X7NTSC - 1; *ffolat = ffo10x7ntsc[i].ffolat; *ivo = ffo10x7ntsc[i].ivo; } else { if (i > SIZE10X7PAL - 1) i = SIZE10X7PAL - 1; *ffolat = ffo10x7pal[i].ffolat; *ivo = ffo10x7pal[i].ivo; } break; } } /*get vertical line min and max for mode and std.*/ static void get_vtotal_min_max(unsigned long vga_mode, unsigned long tv_std, int *v_total_min, int *v_total_max, int *v_step) { int k = map_tvstd_to_index(tv_std); switch (vga_mode) { case GFX_VGA_MODE_640X480: if (IS_NTSC(tv_std)) { *v_total_min = ffo6x4ntsc[0].v_total; *v_total_max = ffo6x4ntsc[SIZE6X4NTSC - 1].v_total; } else { *v_total_min = ffo6x4pal[0].v_total; *v_total_max = ffo6x4pal[SIZE6X4PAL - 1].v_total; } *v_step = 4; break; case GFX_VGA_MODE_800X600: if (IS_NTSC(tv_std)) { *v_total_min = ffo8x6ntsc[0].v_total; *v_total_max = ffo8x6ntsc[SIZE8X6NTSC - 1].v_total; } else { *v_total_min = ffo8x6pal[0].v_total; *v_total_max = ffo8x6pal[SIZE8X6PAL - 1].v_total; } *v_step = 5; break; case GFX_VGA_MODE_720X487: case GFX_VGA_MODE_720X576: *v_total_min = tvsetup.tv_lines[k]; *v_total_max = tvsetup.tv_lines[k]; *v_step = 4; break; case GFX_VGA_MODE_1024X768: if (IS_NTSC(tv_std)) { *v_total_min = ffo10x7ntsc[0].v_total; *v_total_max = ffo10x7ntsc[SIZE10X7NTSC - 1].v_total; } else { *v_total_min = ffo10x7pal[0].v_total; *v_total_max = ffo10x7pal[SIZE10X7PAL - 1].v_total; } *v_step = 6; break; } } static void config_overscan_xy(unsigned long tv_std, unsigned long vga_mode, int overscan_x, int overscan_y, int pos_x, int pos_y) { unsigned int vga_index; unsigned long reg; double vsc; int k; unsigned short ffolat, ivo; int base_v_total, range, v_offset; int v_total_min, v_total_max, v_step; float r, f; int vga_pixels, pre_pixels; float hscale, hscale_min, hscale_max; int hsc; int iho, iho_max, ihw; /*tv_std is valid. */ k = map_tvstd_to_index(tv_std); /*store tv width and lines */ g_specs.tv_width = tvsetup.tv_width[k]; g_specs.tv_lines = tvsetup.tv_lines[k]; /*determine vga mode index */ for (vga_index = 0; vga_index < SCANTABLE_ENTRIES; vga_index++) { if (scantable[vga_index].mode == vga_mode) break; } if (vga_index >= SCANTABLE_ENTRIES) return; /****/ /*vertical scaling (v_total setup). */ /****/ /*calculate vertical range. */ get_vtotal_min_max(vga_mode, tv_std, &v_total_min, &v_total_max, &v_step); TRACE(("v_total min=%d, max=%d\n", v_total_min, v_total_max)) base_v_total = scantable[vga_index].v_total[k]; range = fsmax(base_v_total - v_total_min, v_total_max - base_v_total); TRACE(("v_total range = %d\n", range)) /*map +/-1000 overscan y into +/-range. */ v_offset = (int)((((float)overscan_y * range) / 1000.f) + .5f); TRACE(("v_offset = %d\n", v_offset)) /*range limit v_total. */ g_specs.v_total = range_limit(base_v_total + v_offset, v_total_min, v_total_max); /*round to calibrated value. */ v_offset = (g_specs.v_total - v_total_min + (v_step / 2)) / v_step; g_specs.v_total = v_total_min + v_offset * v_step; TRACE(("desired v_total=%d\n", g_specs.v_total)) /****/ /*vertical positioning (vsync setup). */ /****/ get_ffolat_ivo(vga_mode, tv_std, v_offset, &ffolat, &ivo); houston_WriteReg(HOUSTON_IVO, ivo, 2); /*scale base sync offset by scaling ratio. */ r = (float)g_specs.v_total / (float)base_v_total; v_offset = (int)(r * (float)scantable[vga_index].v_sync[k]); /*scale ivo. */ f = (float)ivo; v_offset -= (int)(f - f / r); /*compensate for center screen. */ f = (float)tvsetup.tv_active_lines[k] / 2.f; v_offset += (int)(f * r - f); /*calculate vsync. */ g_specs.v_sync = g_specs.v_total - v_offset + pos_y; TRACE(("desired v_total=%d, desired v_sync=%d\n", g_specs.v_total, g_specs.v_sync)) if (g_specs.v_sync < g_specs.vga_lines + 10) { TRACE(("vsync too low\n")) /*//d.v_total += d.vga_lines+10-d.v_sync; */ g_specs.v_sync = g_specs.vga_lines + 10; } else if (g_specs.v_sync > g_specs.v_total - 10) { TRACE(("vsync too high\n")) g_specs.v_sync = g_specs.v_total - 10; } TRACE(("v_total=%d v_sync=%d\n", g_specs.v_total, g_specs.v_sync)) /*FFOLAT. */ houston_WriteReg(HOUSTON_FFO_LAT, ffolat, 2); /*VSC. */ vsc = (65536.0f * (1.0f - (double)g_specs.tv_lines / (double)g_specs.v_total)) + 0.5f; reg = ((unsigned long)-vsc) & 0xffff; TRACE(("vsc=%04x, tv_lines=%d, v_total=%d\n", reg, g_specs.tv_lines, g_specs.v_total)) houston_WriteReg(HOUSTON_VSC, (int)reg, 2); /****/ /*horizontal scaling. */ /****/ /*vga pixels is vga width, except in 1024x768, where it's half that. */ vga_pixels = g_specs.vga_width; if (1024 == vga_pixels) vga_pixels /= 2; /*maximum scaling coefficient is tv_width / vga_pixels */ /*minimum is about 1/2, but that is quite small. arbitrarily set minimum at 75% maximum. */ hscale_max = (720.0f / vga_pixels); hscale_min = fsmax((0.75f * hscale_max), (1.0f - (63.0f / 128.0f))); TRACE(("hscale_min = %u.%u, hscale_max = %u.%u\n", (int)hscale_min, (int)((hscale_min - (int)hscale_min) * 1000), (int)hscale_max, (int)((hscale_max - (int)hscale_max) * 1000))) /*map overscan_x into min to max. */ hscale = hscale_min + ((overscan_x + 1000.0f) / 2000.0f) * (hscale_max - hscale_min); TRACE(("hscale = %u.%u\n", (int)hscale, (int)((hscale - (int)hscale) * 1000))) /*determine hsc where hscale = (1 + hsc/128) */ if (hscale >= 1.0f) hsc = (int)(128.f * (hscale - 1.0f) + .5f); else hsc = (int)(128.f * (hscale - 1.0f) - .5f); TRACE(("hsc = %d\n", hsc)) if (hsc >= 0) houston_WriteReg(HOUSTON_HSC, hsc << 8, 2); else houston_WriteReg(HOUSTON_HSC, hsc & 0xFF, 2); /*recalculate hscale for future formulas */ hscale = 1.0f + (hsc / 128.0f); TRACE(("recalculated hscale = %u.%u\n", (int)hscale, (int)((hscale - (int)hscale) * 1000))) /****/ /*horizontal offset. */ /****/ /*place hsync 40 before halfway from vga_width to htotal */ /*but not less than vga_width + 10 */ g_specs.h_sync = fsmax((g_specs.h_total + g_specs.vga_width) / 2 - 40, g_specs.vga_width + 10); /*also, make it even */ g_specs.h_sync &= ~1; TRACE(("hsync = %u\n", g_specs.h_sync)) /*iho range is 0 to iho_max. */ /*iho_max is 2 * iho_center. */ /*iho_center is pre_pixels - (tvwidth / hscale - vga pixels) / 2. */ /*pre_pixels = (htotal - hsync) * (vga_pixels / vga_width) */ /*note that the range is inverted also, because it specifies the number of pixels */ /*to skip, or subtract. iho=0 maps to farthest right. */ /*map -pos_x = +/-1000 into (0 to iho_max) */ pre_pixels = (int)((long)(g_specs.h_total - g_specs.h_sync) * vga_pixels / g_specs.vga_width); iho_max = (2 * pre_pixels) - ((int)(720.0f / hscale + 0.5f) - vga_pixels); TRACE(("iho_max = %u\n", iho_max)) iho = (int)range_limit(((long)(1000 - pos_x) * iho_max / 2000) + scantable[vga_index].iho[k], 0, iho_max); TRACE(("iho = %u\n", iho)) houston_WriteReg(HOUSTON_IHO, iho, 2); /****/ /*input horizontal width. */ /****/ /*input horizontal width is vga pixels + pre_pixels - iho */ /*additionally, ihw cannot exceed tv width / hscale */ /*and if hsc is negative, (ihw)(-hsc/128) cannot exceed ~250. */ /*and ihw should be even. */ ihw = fsmin(vga_pixels + pre_pixels - iho, (int)(720.0f / hscale)); if (hsc < 0) ihw = (int)fsmin(ihw, 253L * 128 / (-hsc)); ihw &= ~1; TRACE(("ihw = %u\n", ihw)) houston_WriteReg(HOUSTON_IHA, ihw, 2); f = (((float)g_specs.h_total * g_specs.v_total) * 27.f) / ((float)g_specs.tv_width * g_specs.tv_lines); TRACE(("freq=%u.%uMHz\n", (int)f, (int)((f - (int)f) * 1000))) } /*==========================================================================*/ /****/ /*configure houston nco.*/ static void config_nco(unsigned long tv_std, unsigned long vga_mode) { unsigned long cr, misc; unsigned long reg; int k = map_tvstd_to_index(tv_std); /*read and store CR. */ houston_ReadReg(HOUSTON_CR, &cr, 2); /*make sure NCO_EN (enable latch) bit is clear */ cr &= ~CR_NCO_EN; houston_WriteReg(HOUSTON_CR, cr, 2); /*clear NCO_LOADX. */ houston_ReadReg(HOUSTON_MISC, &misc, 2); misc &= ~(MISC_NCO_LOAD1 + MISC_NCO_LOAD0); houston_WriteReg(HOUSTON_MISC, misc, 2); if (vga_mode == GFX_VGA_MODE_1024X768) { /*setup for M and N load (Nco_load=1). */ misc |= (MISC_NCO_LOAD0); houston_WriteReg(HOUSTON_MISC, misc, 2); /*M and N. */ houston_WriteReg(HOUSTON_NCONL, 1024 - 2, 2); houston_WriteReg(HOUSTON_NCODL, 128 - 1, 2); /*latch M/N in. */ cr |= CR_NCO_EN; houston_WriteReg(HOUSTON_CR, cr, 2); cr &= ~CR_NCO_EN; houston_WriteReg(HOUSTON_CR, cr, 2); /*setup ncon and ncod load (Nco_load=0). */ misc &= ~(MISC_NCO_LOAD1 + MISC_NCO_LOAD0); houston_WriteReg(HOUSTON_MISC, misc, 2); /*NCON. */ reg = ((unsigned long)g_specs.v_total * g_specs.h_total) / 2; houston_WriteReg(HOUSTON_NCONH, reg >> 16, 2); houston_WriteReg(HOUSTON_NCONL, reg & 0xffff, 2); /*NCOD. */ houston_WriteReg(HOUSTON_NCODL, tvsetup.houston_ncodl[k], 2); houston_WriteReg(HOUSTON_NCODH, tvsetup.houston_ncodh[k], 2); } else { /*setup for M and N load (Nco_load=2). */ misc |= (MISC_NCO_LOAD1); houston_WriteReg(HOUSTON_MISC, misc, 2); /*NCON. */ reg = (unsigned long)g_specs.v_total * g_specs.h_total; houston_WriteReg(HOUSTON_NCONH, reg >> 16, 2); houston_WriteReg(HOUSTON_NCONL, reg & 0xffff, 2); /*NCOD. */ houston_WriteReg(HOUSTON_NCODL, tvsetup.houston_ncodl[k], 2); houston_WriteReg(HOUSTON_NCODH, tvsetup.houston_ncodh[k], 2); TRACE(("NCON = %lu (0x%08lx), NCOD = %lu (0x%08lx)\n", reg, reg, ((unsigned long)tvsetup.houston_ncodh[k] << 16) + tvsetup.houston_ncodl[k], ((unsigned long)tvsetup.houston_ncodh[k] << 16) + tvsetup.houston_ncodl[k])) } /*latch M/N and NCON/NCOD in. */ cr |= CR_NCO_EN; houston_WriteReg(HOUSTON_CR, cr, 2); cr &= ~CR_NCO_EN; houston_WriteReg(HOUSTON_CR, cr, 2); } /*==========================================================================*/ /****/ /*// Write sharpness settings to device*/ static void config_sharpness(int sharpness) { unsigned int shp; /*map 0-1000 to 0-20. */ shp = (unsigned int)(0.5f + ((float)sharpness * 20.0f / 1000.0f)); shp = range_limit(shp, 0, 20); houston_WriteReg(HOUSTON_SHP, shp, 2); } static void conget_sharpness(int *p_sharpness) { unsigned long shp; if (!p_sharpness) return; houston_ReadReg(HOUSTON_SHP, &shp, 2); /*map 0-20 to 0-1000. */ *p_sharpness = (int)(0.5f + ((float)shp * 1000.0f / 20.0f)); } /*==========================================================================*/ /****/ /*// Write flicker settings to device*/ static void config_flicker(int flicker) { unsigned int flk; /*map 0-1000 to 0-16. */ flk = (unsigned int)(0.5f + ((float)flicker * 16.0f / 1000.0f)); flk = range_limit(flk, 0, 16); houston_WriteReg(HOUSTON_FLK, flk, 2); } static void conget_flicker(int *p_flicker) { unsigned long flk; if (!p_flicker) return; houston_ReadReg(HOUSTON_FLK, &flk, 2); /*map 0-16 to 0-1000. */ *p_flicker = (int)(0.5f + ((float)flk * 1000.0f / 16.0f)); } /*==========================================================================*/ /****/ /*// Write color settings to device*/ static void config_color(int color) { unsigned long clr; /*map 0-100 to 0-255. */ /*montreal production test needs 169 to be mappable, so */ /*use .8 rounding factor, 169=(int)(66.*2.55+.8). */ clr = (unsigned long)(0.8f + ((float)color * 255.0f / 100.0f)); clr = range_limit(clr, 0, 255); houston_WriteReg(ENC_CR_GAIN, clr, 1); houston_WriteReg(ENC_CB_GAIN, clr, 1); } static void conget_color(int *p_color) { unsigned long cr_gain; if (!p_color) return; /*just get CR GAIN, CB GAIN should match. */ houston_ReadReg(ENC_CR_GAIN, &cr_gain, 1); /*map 0-255 to 0-100. */ *p_color = (int)(0.5f + ((float)cr_gain * 100.0f / 255.0f)); } /*==========================================================================*/ /****/ /*// Write brightness and contrast settings to device*/ #define NTSC_BLANK_LEVEL 240 static const int min_black_level = NTSC_BLANK_LEVEL + 1; static const int max_white_level = 1023; static void config_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits, int brightness, int contrast) { int brightness_off; float contrast_mult; int black, white; unsigned short w; int k = map_tvstd_to_index(tv_std); /*0-100 maps to +/-220. */ brightness_off = (int)(0.5f + ((float)brightness * 440.0f / 100.0f)) - 220; /*0-100 maps to .75-1.25. */ contrast_mult = ((float)contrast * 0.5f / 100.0f) + 0.75f; black = tvsetup.black_level[k]; if (trigger_bits != 0) black -= tvsetup.hamp_offset[k]; white = tvsetup.white_level[k]; if (trigger_bits != 0) white -= tvsetup.hamp_offset[k]; black = (int)((float)(black + brightness_off) * contrast_mult); white = (int)((float)(white + brightness_off) * contrast_mult); if (black < min_black_level) black = min_black_level; if (white > max_white_level) white = max_white_level; w = w10bit2z((unsigned short)black); houston_WriteReg(ENC_BLACK_LEVEL, w & 0x00ff, 1); houston_WriteReg(ENC_BLACK_LEVEL + 1, w >> 8, 1); w = w10bit2z((unsigned short)white); houston_WriteReg(ENC_WHITE_LEVEL, w & 0x00ff, 1); houston_WriteReg(ENC_WHITE_LEVEL + 1, w >> 8, 1); } static void conget_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits, int *p_brightness, int *p_contrast) { int brightness_off; float contrast_mult; unsigned short black, white; unsigned long zh, zl; int k; if (!p_brightness || !p_contrast) return; k = map_tvstd_to_index(tv_std); houston_ReadReg(ENC_BLACK_LEVEL, &zl, 1); houston_ReadReg(ENC_BLACK_LEVEL + 1, &zh, 1); black = z2w10bit((unsigned short)(zl + (zh << 8))); if (trigger_bits != 0) black += tvsetup.hamp_offset[k]; houston_ReadReg(ENC_WHITE_LEVEL, &zl, 1); houston_ReadReg(ENC_WHITE_LEVEL + 1, &zh, 1); white = z2w10bit((unsigned short)(zl + (zh << 8))); if (trigger_bits != 0) white += tvsetup.hamp_offset[k]; /*this reverse computation does not account for clipping, but should */ /*provide somewhat reasonable numbers */ contrast_mult = ((float)white - (float)black) / ((float)tvsetup.white_level[k] - (float)tvsetup.black_level[k]); brightness_off = (int)(((float)black / contrast_mult) - tvsetup.black_level[k]); /*+/-220 maps to 0-100. */ *p_brightness = range_limit((int) (0.5f + ((float)(brightness_off + 220) * 100.0f / 440.0f)), 0, 100); /*.75-1.25 maps to 0-100. */ *p_contrast = range_limit((int) (0.5f + ((float)(contrast_mult - 0.75f) * 100.0f / 0.5f)), 0, 100); } /*==========================================================================*/ /****/ /*configure luma/chroma filters.*/ static void config_yc_filter(unsigned long tv_std, int luma_filter, int chroma_filter) { unsigned long reg, reg07, reg34; if (houston_Rev() < HOUSTON_REV_B) return; /*luma filter. */ if (luma_filter) reg = tvsetup.notch_filter[map_tvstd_to_index(tv_std)]; else reg = 0; houston_WriteReg(ENC_NOTCH_FILTER, reg, 1); /*chroma filter. */ houston_ReadReg(ENC_REG07, ®07, 1); houston_ReadReg(ENC_REG34, ®34, 1); if (chroma_filter) { reg07 &= ~0x08; reg34 &= ~0x20; } else { reg07 |= 0x08; reg34 |= 0x20; } houston_WriteReg(ENC_REG07, reg07, 1); houston_WriteReg(ENC_REG34, reg34, 1); } static void conget_yc_filter(int *p_luma_filter, int *p_chroma_filter) { unsigned long reg, reg07, reg34; if (!p_luma_filter || !p_chroma_filter) return; if (houston_Rev() < HOUSTON_REV_B) { *p_luma_filter = 0; *p_chroma_filter = 0; return; } /*luma filter. */ houston_ReadReg(ENC_NOTCH_FILTER, ®, 1); *p_luma_filter = (reg ? 1 : 0); /*chroma filter. */ houston_ReadReg(ENC_REG07, ®07, 1); houston_ReadReg(ENC_REG34, ®34, 1); *p_chroma_filter = !((0x08 & reg07) || (0x20 & reg34)); } /*==========================================================================*/ /****/ /*// Macrovision*/ static void config_macrovision(unsigned long tv_std, unsigned int trigger_bits) { /****/ /*Constants to index into mvsetup columns.*/ /****/ #define nNTSC_APS00 0 /*ntsc mv off. */ #define nNTSC_APS01 1 /*ntsc AGC only. */ #define nNTSC_APS10 2 /*ntsc AGC + 2-line CS. */ #define nNTSC_APS11 3 /*ntsc AGC + 4-line CS. */ #define nPAL_APS00 4 /*pal mv off. */ #define nPAL_APSXX 5 /*pal mv on. */ #define nMVModes 6 /****/ /*Macrovision setup table.*/ /****/ static const struct mvparms { unsigned short n0[nMVModes]; unsigned short n1[nMVModes]; unsigned short n2[nMVModes]; unsigned short n3[nMVModes]; unsigned short n4[nMVModes]; unsigned short n5[nMVModes]; unsigned short n6[nMVModes]; unsigned short n7[nMVModes]; unsigned short n8[nMVModes]; unsigned short n9[nMVModes]; unsigned short n10[nMVModes]; unsigned short n11[nMVModes]; unsigned short n12[nMVModes]; unsigned short n13[nMVModes]; unsigned short n14[nMVModes]; unsigned short n15[nMVModes]; unsigned short n16[nMVModes]; unsigned short n17[nMVModes]; unsigned short n18[nMVModes]; unsigned short n19[nMVModes]; unsigned short n20[nMVModes]; unsigned short n21[nMVModes]; unsigned short n22[nMVModes]; unsigned short agc_pulse_level[nMVModes]; unsigned short bp_pulse_level[nMVModes]; } mvsetup = { /*// ntsc ntsc ntsc ntsc pal pal */ /*// MV AGC AGC + AGC + MV MV */ /*// off. only 2-line 4-line off. on. */ /*// CS. CS. */ { 0x00, 0x36, 0x3e, 0x3e, 0x00, 0x3e} , /*n0 */ { 0x1d, 0x1d, 0x1d, 0x17, 0x1a, 0x1a} , /*n1 */ { 0x11, 0x11, 0x11, 0x15, 0x22, 0x22} , /*n2 */ { 0x25, 0x25, 0x25, 0x21, 0x2a, 0x2a} , /*n3 */ { 0x11, 0x11, 0x11, 0x15, 0x22, 0x22} , /*n4 */ { 0x01, 0x01, 0x01, 0x05, 0x05, 0x05} , /*n5 */ { 0x07, 0x07, 0x07, 0x05, 0x02, 0x02} , /*n6 */ { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00} , /*n7 */ { 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c} , /*n8 */ { 0x1b, 0x1b, 0x1b, 0x1b, 0x3d, 0x3d} , /*n9 */ { 0x24, 0x24, 0x24, 0x24, 0x14, 0x14} , /*n10 */ { 0x780f, 0x780f, 0x780f, 0x780f, 0x7e07, 0x7e07} , /*n11 */ { 0x0000, 0x0000, 0x0000, 0x0000, 0x5402, 0x5402} , /*n12 */ { 0x0f, 0x0f, 0x0f, 0x0f, 0xfe, 0xfe} , /*n13 */ { 0x0f, 0x0f, 0x0f, 0x0f, 0x7e, 0x7e} , /*n14 */ { 0x60, 0x60, 0x60, 0x60, 0x60, 0x60} , /*n15 */ { 0x01, 0x01, 0x01, 0x01, 0x00, 0x00} , /*n16 */ { 0x0a, 0x0a, 0x0a, 0x0a, 0x08, 0x08} , /*n17 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} , /*n18 */ { 0x05, 0x05, 0x05, 0x05, 0x04, 0x04} , /*n19 */ { 0x04, 0x04, 0x04, 0x04, 0x07, 0x07} , /*n20 */ { 0x03ff, 0x03ff, 0x03ff, 0x03ff, 0x0155, 0x0155} , /*n21 */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} , /*n22 */ { 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3} , /*agc_pulse_level */ { 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8} , /*bp_pulse_level */ }; int nMode; unsigned long misc; unsigned short n0; trigger_bits &= 0x3; /*Determine the OEM Macrovision Program Mode and Register 0 Data. */ if (IS_NTSC(tv_std)) { /*NTSC TV Standard. */ if (trigger_bits == 0) { /*turn Macrovision OFF. */ nMode = nNTSC_APS00; } else if (trigger_bits == 1) { /*AGC Only. */ nMode = nNTSC_APS01; } else if (trigger_bits == 2) { /*AGC + 2-line CS. */ nMode = nNTSC_APS10; } else { /*AGC + 4-line CS. */ nMode = nNTSC_APS11; } } else { /*PAL TV Standard. */ if (trigger_bits == 0) { /*turn Macrovision OFF. */ nMode = nPAL_APS00; } else { /*APS 01, 10, or 11. */ nMode = nPAL_APSXX; } } /*Retrieve the Macrovision Program Mode Data */ if (tv_std != GFX_TV_STANDARD_PAL_M) n0 = mvsetup.n0[nMode]; else { /*PAL-M sets up like NTSC except for n0. */ if ((trigger_bits & 0x03) == 0) n0 = mvsetup.n0[nPAL_APS00]; else n0 = mvsetup.n0[nPAL_APSXX]; } /*download settings now. */ houston_WriteReg(MV_N0, n0, 1); houston_WriteReg(MV_N1, mvsetup.n1[nMode], 1); houston_WriteReg(MV_N2, mvsetup.n2[nMode], 1); houston_WriteReg(MV_N3, mvsetup.n3[nMode], 1); houston_WriteReg(MV_N4, mvsetup.n4[nMode], 1); houston_WriteReg(MV_N5, mvsetup.n5[nMode], 1); houston_WriteReg(MV_N6, mvsetup.n6[nMode], 1); houston_WriteReg(MV_N7, mvsetup.n7[nMode], 1); houston_WriteReg(MV_N8, mvsetup.n8[nMode], 1); houston_WriteReg(MV_N9, mvsetup.n9[nMode], 1); houston_WriteReg(MV_N10, mvsetup.n10[nMode], 1); houston_WriteReg(MV_N11, mvsetup.n11[nMode] & 0xff, 1); houston_WriteReg(MV_N11 + 1, mvsetup.n11[nMode] >> 8, 1); houston_WriteReg(MV_N12, mvsetup.n12[nMode] & 0xff, 1); houston_WriteReg(MV_N12 + 1, mvsetup.n12[nMode] >> 8, 1); houston_WriteReg(MV_N13, mvsetup.n13[nMode], 1); houston_WriteReg(MV_N14, mvsetup.n14[nMode], 1); houston_WriteReg(MV_N15, mvsetup.n15[nMode], 1); houston_WriteReg(MV_N16, mvsetup.n16[nMode], 1); houston_WriteReg(MV_N17, mvsetup.n17[nMode], 1); houston_WriteReg(MV_N18, mvsetup.n18[nMode], 1); houston_WriteReg(MV_N19, mvsetup.n19[nMode], 1); houston_WriteReg(MV_N20, mvsetup.n20[nMode], 1); houston_WriteReg(MV_N21, mvsetup.n21[nMode] & 0xff, 1); houston_WriteReg(MV_N21 + 1, mvsetup.n21[nMode] >> 8, 1); houston_WriteReg(MV_N22, mvsetup.n22[nMode], 1); houston_WriteReg(MV_AGC_PULSE_LEVEL, mvsetup.agc_pulse_level[nMode], 1); houston_WriteReg(MV_BP_PULSE_LEVEL, mvsetup.bp_pulse_level[nMode], 1); houston_ReadReg(HOUSTON_MISC, &misc, 2); if (trigger_bits == 0) misc &= ~MISC_MV_SOFT_EN; else misc |= MISC_MV_SOFT_EN; houston_WriteReg(HOUSTON_MISC, misc, 2); } static void conget_macrovision(unsigned long tv_std, unsigned int *p_cp_trigger_bits) { unsigned long n0, n1; if (!p_cp_trigger_bits) return; houston_ReadReg(MV_N0, &n0, 1); houston_ReadReg(MV_N1, &n1, 1); *p_cp_trigger_bits = 0; if (IS_NTSC(tv_std)) { switch (n0) { case 0: *p_cp_trigger_bits = 0; break; case 0x36: *p_cp_trigger_bits = 1; break; case 0x3E: { if (0x1D == n1) *p_cp_trigger_bits = 2; else *p_cp_trigger_bits = 3; } break; } } else if (IS_PAL(tv_std)) { if (0 == n0) *p_cp_trigger_bits = 0; else { /*don't know here what the non-zero trigger bits were */ *p_cp_trigger_bits = 1; } } } /*// PLAL_MediaGX.cpp*/ /*//==========================================================================*/ /****/ /*These functions provides implementation of platform-specific functions*/ /*MediaGX platform.*/ /****/ /*//==========================================================================*/ /*MediaGX control registers.*/ #define CCR3 0xC3 #define GCR 0xb8 /*Media GX registers*/ /* #define DC_UNLOCK 0x8300 #define DC_GENERAL_CFG 0x8304 #define DC_TIMING_CFG 0x8308 #define DC_OUTPUT_CFG 0x830c #define DC_H_TIMING_1 0X8330 #define DC_H_TIMING_2 0X8334 #define DC_H_TIMING_3 0X8338 #define DC_FP_H_TIMING 0X833c #define DC_V_TIMING_1 0X8340 #define DC_V_TIMING_2 0X8344 #define DC_V_TIMING_3 0X8348 #define DC_FP_V_TIMING 0X834c */ /*Media GX general config register.*/ #define GX_DCLK_MUL 0x00c0 #define GX_DCLKx1 0x0040 #define GX_DCLKx2 0x0080 #define GX_DCLKx4 0x00c0 /*Media GX timing config register.*/ #define GX_TGEN 0x0020 /*Cx5530 register offsets (from GX_BASE).*/ #define CX_DISPLAY_CONFIG 0x10004 #define CX_DOT_CLK 0x10024 #define CX_TV_CONFIG 0x10028 /*Cx5530 display configuration register.*/ #define CX_FPVSYNC_POL 0x0800 #define CX_FPHSYNC_POL 0x0400 #define CX_FPDATA_ENB 0x0080 #define CX_FPPOWER_ENB 0x0040 #define CX_CRTVSYNC_POL 0x0200 #define CX_CRTHSYNC_POL 0x0100 /*Cx5530 dot clock configuration register.*/ #define CX_TVCLK_SELECT 0x0400 /*Cx5530 tv configuration register*/ #define CX_INVERT_FPCLK (1 << 6) /*//==========================================================================*/ /****/ /*// FS450 I2C Address*/ /****/ /*// There are two possible 7-bit addresses, 0x4A and 0x6A.*/ /*// The address if selectable via pins on the FS450.*/ /*// There are also two possible 10-bit addresses, 0x224 and 0x276, but this*/ /*// source is not designed to use them.*/ /****/ #define FS450_I2C_ADDRESS (0x4A) static unsigned char PLAL_FS450_i2c_address(void) { return FS450_I2C_ADDRESS; } /*//==========================================================================*/ /****/ /*// FS450 UIM mode*/ /****/ /*// This mode is programmed in the FS450 command register when enabling TV*/ /*// out.*/ static int PLAL_FS450_UIM_mode(void) { return 3; } /*//==========================================================================*/ /****/ /*// Read and Write MediaGX registers*/ static unsigned long ReadGx(unsigned long inRegAddr) { unsigned long data; DMAL_ReadUInt32(inRegAddr, &data); return data; } static void WriteGx(unsigned long inRegAddr, unsigned long inData) { int is_timing_register; unsigned long reg_timing_cfg; /*because the unlock register for the MediaGx video registers may not */ /*persist, we will write the unlock code before every write. */ DMAL_WriteUInt32(DC_UNLOCK, 0x4758); /*see if register is a timing register */ is_timing_register = (DC_H_TIMING_1 == inRegAddr) || (DC_H_TIMING_2 == inRegAddr) || (DC_H_TIMING_3 == inRegAddr) || (DC_FP_H_TIMING == inRegAddr) || (DC_V_TIMING_1 == inRegAddr) || (DC_V_TIMING_2 == inRegAddr) || (DC_V_TIMING_3 == inRegAddr) || (DC_FP_V_TIMING == inRegAddr); /*if the register is a timing register, clear the TGEN bit to allow modification */ if (is_timing_register) { DMAL_ReadUInt32(DC_TIMING_CFG, ®_timing_cfg); DMAL_WriteUInt32(DC_TIMING_CFG, reg_timing_cfg & ~GX_TGEN); } /*write the requested register */ DMAL_WriteUInt32(inRegAddr, inData); /*reset the TGEN bit to previous state */ if (is_timing_register) { DMAL_WriteUInt32(DC_TIMING_CFG, reg_timing_cfg); } } #ifdef FS450_DIRECTREG /*//==========================================================================*/ /****/ /*// Platform-specific processing for a Read or Write Register calls.*/ /*// The functions should return true if the specified register belongs to*/ /*// this platform.*/ static int PLAL_ReadRegister(S_REG_INFO * p_reg) { if (!p_reg) return 0; if (SOURCE_GCC == p_reg->source) { p_reg->value = ReadGx(p_reg->offset); return 1; } return 0; } static int PLAL_WriteRegister(const S_REG_INFO * p_reg) { if (!p_reg) return 0; if (SOURCE_GCC == p_reg->source) { WriteGx(p_reg->offset, p_reg->value); return 1; } return 0; } #endif /*//==========================================================================*/ /****/ /*// Determine if TV is on*/ static int PLAL_IsTVOn(void) { unsigned long reg; /*check Cx5530 dot clock */ reg = ReadGx(CX_DOT_CLK); return (reg & CX_TVCLK_SELECT) ? 1 : 0; } /*//==========================================================================*/ /****/ /*// Platform-specific actions to reset to VGA mode*/ static int PLAL_EnableVga(void) { unsigned long reg; /*2 x dclk */ reg = ReadGx(DC_GENERAL_CFG); reg &= ~GX_DCLK_MUL; reg |= GX_DCLKx2; WriteGx(DC_GENERAL_CFG, reg); /*select pll dot clock. */ reg = ReadGx(CX_DOT_CLK); reg &= ~CX_TVCLK_SELECT; WriteGx(CX_DOT_CLK, reg); /*timing config, reset everything on dclk. */ reg = ReadGx(DC_TIMING_CFG); reg &= ~GX_TGEN; WriteGx(DC_TIMING_CFG, reg); reg |= GX_TGEN; WriteGx(DC_TIMING_CFG, reg); /*un-invert FP clock */ reg = ReadGx(CX_TV_CONFIG); reg &= ~CX_INVERT_FPCLK; WriteGx(CX_TV_CONFIG, reg); return 0; } /*//==========================================================================*/ /****/ /*// Platform-specific actions to enter TVout mode*/ static int PLAL_PrepForTVout(void) { unsigned int reg; /*Cx5530 tv config. */ reg = 0; WriteGx(CX_TV_CONFIG, reg); /*invert FP clock */ reg = (int)ReadGx(CX_TV_CONFIG); reg |= CX_INVERT_FPCLK; WriteGx(CX_TV_CONFIG, reg); return 0; } static int PLAL_SetTVTimingRegisters(const S_TIMING_SPECS * p_specs) { unsigned long reg; /*timing config, reset everything on dclk. */ reg = ReadGx(DC_TIMING_CFG); reg &= ~GX_TGEN; WriteGx(DC_TIMING_CFG, reg); /*htotal and hactive. */ reg = ((p_specs->h_total - 1) << 16) | (p_specs->vga_width - 1); WriteGx(DC_H_TIMING_1, reg); /*hblank. */ reg = ((p_specs->h_total - 1) << 16) | (p_specs->vga_width - 1); WriteGx(DC_H_TIMING_2, reg); /*hsync. */ reg = ((p_specs->h_sync + 63) << 16) | p_specs->h_sync; WriteGx(DC_H_TIMING_3, reg); /*fp hsync. */ WriteGx(DC_FP_H_TIMING, reg); /*vtotal and vactive. */ reg = ((p_specs->v_total - 1) << 16) | (p_specs->vga_lines - 1); WriteGx(DC_V_TIMING_1, reg); /*vblank. */ reg = ((p_specs->v_total - 1) << 16) | (p_specs->vga_lines - 1); WriteGx(DC_V_TIMING_2, reg); /*vsync. */ reg = ((p_specs->v_sync) << 16) | (p_specs->v_sync - 1); WriteGx(DC_V_TIMING_3, reg); /*fp vsync. */ reg = ((p_specs->v_sync - 1) << 16) | (p_specs->v_sync - 2); WriteGx(DC_FP_V_TIMING, reg); /*timing config, reenable all dclk stuff. */ reg = ReadGx(DC_TIMING_CFG); reg |= GX_TGEN; WriteGx(DC_TIMING_CFG, reg); return 0; } static int PLAL_FinalEnableTVout(unsigned long vga_mode) { unsigned int reg; /*Cx5530 select tv dot clock. */ reg = (int)ReadGx(CX_DOT_CLK); reg |= CX_TVCLK_SELECT; WriteGx(CX_DOT_CLK, reg); /*2 x dclk (actually 1x) */ reg = (int)ReadGx(DC_GENERAL_CFG); reg &= ~GX_DCLK_MUL; WriteGx(DC_GENERAL_CFG, reg); reg |= GX_DCLKx2; WriteGx(DC_GENERAL_CFG, reg); /*Cx5530 display configuration register. */ reg = (int)ReadGx(CX_DISPLAY_CONFIG); reg |= (CX_FPVSYNC_POL | CX_FPHSYNC_POL | CX_FPDATA_ENB | CX_FPPOWER_ENB); WriteGx(CX_DISPLAY_CONFIG, reg); /*disable, shouldn't be necessary*/ #if 0 /*kick MediaGX clock multiplier to clean up clock */ reg = ReadGx(DC_GENERAL_CFG); reg &= ~GX_DCLK_MUL; WriteGx(DC_GENERAL_CFG, reg); reg |= GX_DCLKx2; WriteGx(DC_GENERAL_CFG, reg); #endif return 0; }