summaryrefslogtreecommitdiff
path: root/src/gfx/tv_fs450.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gfx/tv_fs450.c')
-rw-r--r--src/gfx/tv_fs450.c3261
1 files changed, 3261 insertions, 0 deletions
diff --git a/src/gfx/tv_fs450.c b/src/gfx/tv_fs450.c
new file mode 100644
index 0000000..942907b
--- /dev/null
+++ b/src/gfx/tv_fs450.c
@@ -0,0 +1,3261 @@
+/* Copyright (c) 2005 Advanced Micro Devices, Inc.
+ *
+ * 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * */
+
+#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))
+ *==========================================================================
+ */
+#define TRACE(parameters) {}
+/* 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();
+
+ d.tv_on = PLAL_IsTVOn()? 1 : 0;
+
+ /* get the current tv standard */
+ conget_tv_std(&d.tv_std);
+
+ d.vga_mode = 0;
+
+ /* default to VP_TVOUT_MODE_CVBS_YC */
+ d.tvout_mode = GFX_TVOUT_MODE_CVBS_YC;
+
+ /* default to 1000 out of 1000 */
+ d.sharpness = 1000;
+ config_sharpness(d.sharpness);
+
+ /* default to 800 out of 1000 */
+ d.flicker = 800;
+ config_flicker(d.flicker);
+
+ /* default to zeros */
+ d.overscan_x = 0;
+ d.overscan_y = 0;
+ d.position_x = 0;
+ d.position_y = 0;
+
+ d.color = 50;
+ /* d.color = tvsetup.color[k]; */
+ config_color(d.color);
+
+ /* default */
+ d.brightness = 50;
+ d.contrast = 60;
+ config_brightness_contrast(d.tv_std, d.aps_trigger_bits, d.brightness,
+ d.contrast);
+
+ /* 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;
+ }
+
+ d.aps_trigger_bits = 0;
+ config_macrovision(d.tv_std, d.aps_trigger_bits);
+
+ 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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"))
+
+ /*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, &reg, 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, &reg, 2);
+ reg |= CR_CLKOFF;
+ houston_WriteReg(HOUSTON_CR, reg, 2);
+ }
+
+ return;
+ }
+
+ if (on) {
+ /* !CLKOFF, !COMPOFF, !YCOFF */
+ /* and reset Houston */
+ houston_ReadReg(HOUSTON_CR, &reg, 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, &reg, 2);
+ reg &= ~MISC_GTLIO_PD;
+ houston_WriteReg(HOUSTON_MISC, reg, 2);
+ } else {
+ /* CLKOFF, COMPOFF, YCOFF */
+ houston_ReadReg(HOUSTON_CR, &reg, 2);
+ reg |= (CR_CLKOFF | CR_COMPOFF | CR_YCOFF);
+ houston_WriteReg(HOUSTON_CR, reg, 2);
+
+ /* GTLIO_PD */
+ houston_ReadReg(HOUSTON_MISC, &reg, 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, &reg07, 1);
+ houston_ReadReg(ENC_REG34, &reg34, 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, &reg, 1);
+ *p_luma_filter = (reg ? 1 : 0);
+
+ /*chroma filter. */
+ houston_ReadReg(ENC_REG07, &reg07, 1);
+ houston_ReadReg(ENC_REG34, &reg34, 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 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, &reg_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);
+
+ return 0;
+}