tv_fs450.c revision f29dbc25
1/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26#define	FS450_DIRECTREG	0
27
28#include "tv_fs450.h"
29
30/*==========================================================================
31 *	Macros
32 *==========================================================================
33 */
34#undef		fsmax
35#undef		fsmin
36#define		fsmax(a, b)		((a) > (b) ? (a) : (b))
37#define		fsmin(a, b)		((a) < (b) ? (a) : (b))
38
39#undef range_limit
40#define range_limit(val,min_val,max_val) (fsmax((min_val),fsmin((val),(max_val))))
41
42/*==========================================================================
43 *	Registers
44 *==========================================================================
45 */
46
47#define MAX_REGISTERS	32
48#define MAX_BITS		32
49
50#define READ	1
51#define WRITE	2
52#define READ_WRITE (READ | WRITE)
53
54typedef struct
55{
56    char *name;
57    unsigned long offset;
58    unsigned char bit_length;
59    unsigned char valid_bits;
60    unsigned char read_write;
61    char *bitfield_names[MAX_BITS];
62} S_REGISTER_DESCRIP;
63
64typedef struct
65{
66    int source;
67    char *name;
68    S_REGISTER_DESCRIP registers[MAX_REGISTERS];
69} S_SET_DESCRIP;
70
71const S_SET_DESCRIP *houston_regs(void);
72const S_SET_DESCRIP *encoder_regs(void);
73const S_SET_DESCRIP *macrovision_regs(void);
74const S_SET_DESCRIP *gcc_regs(void);
75
76/*==========================================================================
77 *	Houston Register Addresses & Bit Definitions
78 *==========================================================================
79 */
80#define	HOUSTON_IHO				0x00    /* Input Horizontal Offset                      */
81#define	HOUSTON_IVO				0x02    /* Input Vertical Offset                        */
82#define	HOUSTON_IHA				0x04    /* Input Horizontal Active Width        */
83#define	HOUSTON_VSC				0x06    /* Vertical Scaling Coeficient          */
84#define	HOUSTON_HSC				0x08    /* Horizontal Scaling Coeficient        */
85#define	HOUSTON_BYP				0x0A    /* Bypass Register                                      */
86#define	HOUSTON_CR				0x0C    /* Control Register                             */
87#define	HOUSTON_SP				0x0E    /* Status                                                       */
88#define	HOUSTON_NCONL			0x10    /* NCO numerator low word                       */
89#define	HOUSTON_NCONH			0x12    /* NCO numerator high word                      */
90#define	HOUSTON_NCODL			0x14    /* NCO denominator low word             */
91#define	HOUSTON_NCODH			0x16    /* NCO denominator high word            */
92#define	HOUSTON_APO				0x18
93#define	HOUSTON_ALO				0x1A
94#define	HOUSTON_AFO				0x1C
95#define	HOUSTON_HSOUTWID		0x1E
96#define	HOUSTON_HSOUTST			0x20
97#define	HOUSTON_HSOUTEND		0x22
98#define	HOUSTON_SHP				0x24    /* Sharpness                                            */
99#define	HOUSTON_FLK				0x26    /* Flicker Filter                                       */
100#define	HOUSTON_BCONTL			0x28
101#define	HOUSTON_BCONTH			0x2A
102#define	HOUSTON_BDONE			0x2C
103#define	HOUSTON_BDIAGL			0x2E
104#define	HOUSTON_BDIAGH			0x30
105#define	HOUSTON_REV				0x32
106#define	HOUSTON_MISC			0x34
107#define	HOUSTON_FFO				0x36
108#define	HOUSTON_FFO_LAT			0x38
109#define HOUSTON_VSOUTWID		0x3A
110#define HOUSTON_VSOUTST			0x3C
111#define HOUSTON_VSOUTEND		0x3E
112/*		BYP Register Bits		*/
113#define	BYP_RGB_BYPASS			0x0001
114#define	BYP_HDS_BYPASS			0x0002
115#define	BYP_HDS_TBYPASS			0x0004
116#define	BYP_CAC_BYPASS			0x0008
117#define	BYP_R2V_SBYPASS			0x0010
118#define	BYP_R2V_BYPASS			0x0020
119#define	BYP_VDS_BYPASS			0x0040
120#define	BYP_FFT_BYPASS			0x0080
121#define	BYP_FIF_BYPASS			0x0100
122#define	BYP_FIF_TBYPASS			0x0200
123#define	BYP_HUS_BYPASS			0x0400
124#define	BYP_HUS_TBYPASS			0x0800
125#define	BYP_CCR_BYPASS			0x1000
126#define	BYP_PLL_BYPASS			0x2000
127#define	BYP_NCO_BYPASS			0x4000
128#define	BYP_ENC_BYPASS			0x8000
129/*		CR Register Bits		*/
130#define	CR_RESET				0x0001
131#define	CR_CLKOFF				0x0002
132#define	CR_NCO_EN				0x0004
133#define	CR_COMPOFF				0x0008
134#define	CR_YCOFF				0x0010
135#define	CR_LP_EN				0x0020
136#define	CR_CACQ_CLR				0x0040
137#define	CR_FFO_CLR				0x0080
138#define	CR_656_PAL_NTSC			0x0100
139#define	CR_656_STD_VMI			0x0200
140#define	CR_OFMT					0x0400
141#define	CR_UIM_CLK				0x0800
142#define	CR_UIM_DEC				0x1000
143#define	CR_BIPGEN_EN1			0x2000
144#define	CR_UIM_MOD0				0x4000
145#define	CR_UIM_MOD1				0x8000
146/*		Status Register Bits	*/
147#define	SP_CACQ_ST				0x0001
148#define	SP_FFO_ST				0x0002
149#define	SP_REVID_MASK			0x7FFC
150#define	SP_MV_EN				0x8000
151/*		BDONE Register Bits		*/
152#define	BDONE_BIST_DONE_A		0x0001
153#define	BDONE_BIST_DONE_B		0x0002
154#define	BDONE_BIST_DONE_C		0x0004
155#define	BDONE_BIST_DONE_D		0x0008
156#define	BDONE_BIST_DONE_E		0x0010
157#define	BDONE_BIST_DONE_F		0x0020
158#define	BDONE_BIST_DONE_G		0x0040
159/*		BDIAGL Register Bits	*/
160#define	BDIAGL_BIST_DIAG_A		0x000F
161#define	BDIAGL_BIST_DIAG_B		0x00F0
162#define	BDIAGL_BIST_DIAG_C		0x0F00
163#define	BDIAGL_BIST_DIAG_D		0xF000
164/*		BDIAGH Register Bits	*/
165#define	BDIAGH_BIST_DIAG_E		0x000F
166#define	BDIAGH_BIST_DIAG_F		0x000F
167#define	BDIAGH_BIST_DIAG_G		0x000F
168/*		MISC Register Bits		*/
169#define	MISC_TV_SHORT_FLD		0x0001
170#define	MISC_ENC_TEST			0x0002
171#define	MISC_DAC_TEST			0x0004
172#define	MISC_MV_SOFT_EN			0x0008
173#define	MISC_NCO_LOAD0			0x0010
174#define	MISC_NCO_LOAD1			0x0020
175#define	MISC_VGACKDIV			0x0200
176#define	MISC_BRIDGE_SYNC		0x0400
177#define	MISC_GTLIO_PD			0x8000
178/*==========================================================================
179 *	Encoder Registers & Bit Definitions
180 *==========================================================================
181 */
182#define	ENC_CHROMA_FREQ		0x40
183#define	ENC_CHROMA_PHASE	0x44
184#define	ENC_REG05			0x45
185#define	ENC_REG06			0x46
186#define	ENC_REG07			0x47
187#define	ENC_HSYNC_WIDTH		0x48
188#define	ENC_BURST_WIDTH		0x49
189#define	ENC_BACK_PORCH		0x4A
190#define	ENC_CB_BURST_LEVEL	0x4B
191#define	ENC_CR_BURST_LEVEL	0x4C
192#define	ENC_SLAVE_MODE		0x4D
193#define	ENC_BLACK_LEVEL		0x4e
194#define	ENC_BLANK_LEVEL		0x50
195#define	ENC_NUM_LINES		0x57
196#define	ENC_WHITE_LEVEL		0x5e
197#define	ENC_CB_GAIN			0x60
198#define	ENC_CR_GAIN			0x62
199#define	ENC_TINT			0x65
200#define	ENC_BREEZE_WAY		0x69
201#define	ENC_FRONT_PORCH		0x6C
202#define	ENC_ACTIVELINE		0x71
203#define	ENC_FIRST_LINE		0x73
204#define	ENC_REG34			0x74
205#define	ENC_SYNC_LEVEL		0x75
206#define	ENC_VBI_BLANK_LEVEL	0x7C
207#define	ENC_RESET			0x7e
208#define	ENC_NOTCH_FILTER	0x8d
209/*==========================================================================
210 * 	Macrovision Registers & Bit Definitions
211 *==========================================================================
212 */
213#define		MV_N0			0x59
214#define		MV_N1			0x52
215#define		MV_N2			0x7b
216#define		MV_N3			0x53
217#define		MV_N4			0x79
218#define		MV_N5			0x5d
219#define		MV_N6			0x7a
220#define		MV_N7			0x64
221#define		MV_N8			0x54
222#define		MV_N9			0x55
223#define		MV_N10			0x56
224#define		MV_N11			0x6d
225#define		MV_N12			0x6f
226#define		MV_N13			0x5a
227#define		MV_N14			0x5b
228#define		MV_N15			0x5c
229#define		MV_N16			0x63
230#define		MV_N17			0x66
231#define		MV_N18			0x68
232#define		MV_N19			0x67
233#define		MV_N20			0x61
234#define		MV_N21			0x6a
235#define		MV_N22			0x76
236#define		MV_AGC_PULSE_LEVEL	0x77
237#define		MV_BP_PULSE_LEVEL	0x78
238/*==========================================================================
239 *	The TRACE macro can be used to display debug information.  It can display
240 *	one or more parameters in a formatted string like printf.  No code will be
241 *	generated for a release build.  Use double parentheses for compatibility
242 *	with C #define statements.  Newline characters are not added
243 *	automatically.  Usage example:
244 *
245 *	TRACE(("Number is %d, Name is %s.\n",iNumber,lpszName))
246 *==========================================================================
247 */
248#define TRACE(parameters) {}
249/*		GCC timing structure		*/
250typedef struct _S_TIMING_SPECS
251{
252    int vga_width;
253    int vga_lines;
254    int tv_width;
255    int tv_lines;
256    int h_total;
257    int h_sync;
258    int v_total;
259    int v_sync;
260} S_TIMING_SPECS;
261
262/*		Revision of Houston chip	*/
263#define HOUSTON_REV_A 0
264#define HOUSTON_REV_B 1
265static int houston_Rev(void);
266
267/*==========================================================================
268 *	Functions
269 *==========================================================================
270 */
271static int houston_init(void);
272
273static unsigned char PLAL_FS450_i2c_address(void);
274static int PLAL_FS450_UIM_mode(void);
275static int PLAL_ReadRegister(S_REG_INFO * p_reg);
276static int PLAL_WriteRegister(const S_REG_INFO * p_reg);
277static int PLAL_IsTVOn(void);
278static int PLAL_EnableVga(void);
279static int PLAL_PrepForTVout(void);
280static int PLAL_SetTVTimingRegisters(const S_TIMING_SPECS * p_specs);
281static int PLAL_FinalEnableTVout(unsigned long vga_mode);
282
283/* Direct Memory Access Functions	*/
284/* NOTE: Cx5530 is assumed hardcoded at 0x10000 offset from MediaGX base.
285 * F4Bar is bogus as described in the Cx5530 datasheet (actually points to GX
286 * frame buffer).					*/
287static int
288DMAL_ReadUInt32(unsigned long phys_addr, unsigned long *p_data)
289{
290    *p_data = READ_REG32(phys_addr);
291    return 0;
292}
293
294static int
295DMAL_WriteUInt32(unsigned long phys_addr, unsigned long data)
296{
297    WRITE_REG32(phys_addr, data);
298    return 0;
299}
300
301/* Houston register access functions.	*/
302static int
303houston_ReadReg(unsigned int reg, unsigned long *p_value, unsigned int bytes)
304{
305    return gfx_i2c_read(1, PLAL_FS450_i2c_address(), (unsigned char)reg,
306        (unsigned char)bytes, (unsigned char *)p_value);
307}
308
309static int
310houston_WriteReg(unsigned int reg, unsigned long value, unsigned int bytes)
311{
312    return gfx_i2c_write(1, PLAL_FS450_i2c_address(), (unsigned char)reg,
313        (unsigned char)bytes, (unsigned char *)&value);
314}
315
316/* TV configuration functions.			*/
317static int config_init(void);
318static const S_TIMING_SPECS *p_specs(void);
319static void config_power(int on);
320static void config_vga_mode(unsigned long vga_mode);
321static void config_tv_std(unsigned long tv_std, unsigned int trigger_bits);
322static void conget_tv_std(unsigned long *p_tv_std);
323static unsigned long supported_standards(void);
324static void config_tvout_mode(unsigned long tvout_mode);
325static void conget_tvout_mode(unsigned long *p_tvout_mode);
326static void config_overscan_xy(unsigned long tv_std, unsigned long vga_mode,
327    int overscan_x, int overscan_y, int pos_x, int pos_y);
328static void config_nco(unsigned long tv_std, unsigned long vga_mode);
329static void config_sharpness(int sharpness);
330static void conget_sharpness(int *p_sharpness);
331static void config_flicker(int flicker);
332static void conget_flicker(int *p_flicker);
333static void config_color(int color);
334static void conget_color(int *p_color);
335static void config_brightness_contrast(unsigned long tv_std,
336    unsigned int trigger_bits, int brightness, int contrast);
337static void conget_brightness_contrast(unsigned long tv_std,
338    unsigned int trigger_bits, int *p_brightness, int *p_contrast);
339static void config_yc_filter(unsigned long tv_std, int luma_filter,
340    int chroma_filter);
341static void conget_yc_filter(int *p_luma_filter, int *p_chroma_filter);
342static void config_macrovision(unsigned long tv_std,
343    unsigned int cp_trigger_bits);
344static void conget_macrovision(unsigned long tv_std,
345    unsigned int *p_cp_trigger_bits);
346
347/* Device settings.			*/
348typedef struct _S_DEVICE_SETTINGS
349{
350    int tv_on;
351    unsigned long vga_mode;
352    unsigned long tv_std;
353    unsigned long tvout_mode;
354    int overscan_x;
355    int overscan_y;
356    int position_x;
357    int position_y;
358    int sharpness;
359    int flicker;
360    int color;
361    int brightness;
362    int contrast;
363    unsigned char yc_filter;
364    unsigned int aps_trigger_bits;
365    int last_overscan_y;
366} S_DEVICE_SETTINGS;
367
368static S_DEVICE_SETTINGS d;
369
370/*==========================================================================
371 * TV Setup Parameters
372 *==========================================================================
373 * */
374
375static const struct
376{
377    unsigned long chroma_freq[5];
378    unsigned short chroma_phase[5];
379    unsigned short cphase_rst[5];
380    unsigned short color[5];
381    unsigned short cr_burst_level[5];
382    unsigned short cb_burst_level[5];
383    unsigned short sys625_50[5];
384    unsigned short vsync5[5];
385    unsigned short pal_mode[5];
386    unsigned short hsync_width[5];
387    unsigned short burst_width[5];
388    unsigned short back_porch[5];
389    unsigned short front_porch[5];
390    unsigned short breeze_way[5];
391    unsigned short activeline[5];
392    unsigned short blank_level[5];
393    unsigned short vbi_blank_level[5];
394    unsigned short black_level[5];
395    unsigned short white_level[5];
396    unsigned short hamp_offset[5];
397    unsigned short sync_level[5];
398    unsigned short tv_lines[5];
399    unsigned short tv_width[5];
400    unsigned short tv_active_lines[5];
401    unsigned short tv_active_width[5];
402    unsigned char notch_filter[5];
403    unsigned short houston_cr[5];
404    unsigned short houston_ncodl[5];
405    unsigned short houston_ncodh[5];
406} tvsetup = {
407    /*     ntsc,    pal,                ntsc-eij,   pal-m,      pal-n */
408    {
409    0x1f7cf021, 0xcb8a092a, 0x1f7cf021, 0xe3efe621, 0xcb8a092a},
410        /* chroma_freq                  */
411    {
412    0, 0, 0, 0, 0},
413        /* chroma_phase                 */
414    {
415    2, 0, 2, 0, 0},
416        /* cphase_rst                   */
417    {
418    54, 43, 54, 43, 43},
419        /* color                                */
420    {
421    0, 31, 0, 29, 29},
422        /* cr_burst_level               */
423    {
424    59, 44, 59, 41, 41},
425        /* cb_burst_level               */
426    {
427    0, 1, 0, 0, 1},
428        /* sys625_50                    */
429    {
430    0, 1, 0, 0, 0},
431        /* vsync5                               */
432    {
433    0, 1, 0, 1, 1},
434        /* pal_mode                     */
435    {
436    0x7a, 0x7a, 0x7a, 0x7a, 0x7a},
437        /* hsync_width                  */
438    {
439    0x40, 0x3c, 0x40, 0x40, 0x3c},
440        /* burst_width                  */
441    {
442    0x80, 0x9a, 0x80, 0x80, 0x9a},
443        /* back_porch                   */
444    {
445    0x24, 0x1e, 0x24, 0x24, 0x1e},
446        /* front_porch                  */
447    {
448    0x19, 0x1a, 0x19, 0x12, 0x1a},
449        /* breeze_way                   */
450    {
451    0xb4, 0xb4, 0xb4, 0xb4, 0xb4},
452        /* active_line                  */
453    {
454    240, 251, 240, 240, 240},
455        /* blank_level                  */
456    {
457    240, 251, 240, 240, 240},
458        /* vbi_blank_level              */
459    {
460    284, 252, 240, 252, 252},
461        /* black_level                  */
462    {
463    823, 821, 823, 821, 821},
464        /* white_level                  */
465    {
466    60, 48, 60, 48, 48},
467        /* hamp_offset                  */
468    {
469    0x08, 0x08, 0x08, 0x08, 0x08},
470        /* sync_level                   */
471    {
472    525, 625, 525, 525, 625},
473        /* tv_lines                     */
474    {
475    858, 864, 858, 858, 864},
476        /* tv_width                     */
477    {
478    487, 576, 487, 487, 576},
479        /* tv_active_lines              */
480    {
481    800, 800, 800, 800, 800},
482        /* tv_active_width              */
483    {
484    0x1a, 0x1d, 0x1a, 0x1d, 0x1d},
485        /* notch filter enabled */
486    {
487    0x0000, 0x0100, 0x0000, 0x0000, 0x0100},
488        /* houston cr pal               */
489    {
490    0x7e48, 0xf580, 0x7e48, 0x7e48, 0xf580},
491        /* houston ncodl                */
492    {
493    0x001b, 0x0020, 0x001b, 0x001b, 0x0020}
494    /* houston ncodh                */
495};
496
497/* MediaGX default underscan and centered position setups. */
498#define	SCANTABLE_ENTRIES	5
499struct _scantable
500{
501    unsigned long mode;
502    unsigned short v_total[5];
503    unsigned short v_sync[5];
504    unsigned short iha[5];
505    signed short iho[5];
506    signed short hsc[5];
507};
508
509static struct _scantable scantable[SCANTABLE_ENTRIES] = {
510    {
511            GFX_VGA_MODE_640X480,
512            {617, 624, 617, 624, 624}, /* v_total      */
513            {69, 88, 69, 88, 88},      /* v_sync       */
514            {720, 720, 720, 720, 720}, /* iha          */
515            {0, 0, 0, 0, 0},           /* iho          */
516            {-12, 0, -6, 0, 0}         /* hsc          */
517        },
518    {
519            GFX_VGA_MODE_800X600,
520            {740, 740, 740, 740, 740}, /* v_total      */
521            {90, 88, 90, 88, 88},      /* v_sync       */
522            {720, 720, 508, 720, 720}, /* iha          */
523            {-8, 11, -8, -8, 11},      /* iho          */
524            {-27, -27, -27, -27, -27}  /* hsc          */
525        },
526    {
527            GFX_VGA_MODE_720X487,
528            {525, 720, 525, 720, 720}, /* v_total      */
529            {23, 230, 23, 230, 230},   /* v_sync       */
530            {720, 720, 720, 720, 720}, /* iha          */
531            {0xa2, 0xa2, 0xa2, 0xa2, 0xa2},     /* iho          */
532            {0, 0, 0, 0, 0}            /* hsc          */
533        },
534    {
535            GFX_VGA_MODE_720X576,
536            {720, 625, 720, 625, 625}, /* v_total      */
537            {129, 25, 129, 25, 25},    /* v_sync       */
538            {720, 720, 720, 720, 720}, /* iha          */
539            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa},     /* iho              */
540            {0, 0, 0, 0, 0}            /* hsc          */
541        },
542    {
543            GFX_VGA_MODE_1024X768,
544            {933, 942, 933, 806, 806}, /* v_total      */
545            {121, 112, 121, 88, 88},   /* v_sync       */
546            {600, 600, 600, 600, 600}, /* iha          */
547            {0x3c, 0x23, 0x3c, 0x65, 0x65},     /* iho              */
548            {35, 26, 35, 26, 26}       /* hsc          */
549        },
550};
551
552/* Houston fifo configuration constants. */
553struct _ffolat
554{
555    int v_total;
556    unsigned short ffolat;
557};
558
559struct _ffolativo
560{
561    int v_total;
562    unsigned short ivo;
563    unsigned short ffolat;
564};
565
566/* h_total=832, ivo=40, tv_width=858, tv_lines=525, vga_lines=480 */
567#define SIZE6X4NTSC		66
568static struct _ffolat ffo6x4ntsc[SIZE6X4NTSC + 1] = {
569    {541, 0x40}, {545, 0x40}, {549, 0x40}, {553, 0x40},
570    {557, 0x58}, {561, 0x40}, {565, 0x40}, {569, 0x40},
571    {573, 0x48}, {577, 0x40}, {581, 0x40}, {585, 0x40},
572    {589, 0x40}, {593, 0x48}, {597, 0x40}, {601, 0x40},
573    {605, 0x40}, {609, 0x40}, {613, 0x5b}, {617, 0x48},
574    {621, 0x60}, {625, 0x48}, {629, 0x48}, {633, 0x40},
575    {637, 0x5e}, {641, 0x40}, {645, 0x50}, {649, 0x56},
576    {653, 0x58}, {657, 0x6c}, {661, 0x40}, {665, 0x40},
577    {669, 0x40}, {673, 0x40}, {677, 0x40}, {681, 0x40},
578    {685, 0x40}, {689, 0x40}, {693, 0x40}, {697, 0x40},
579    {701, 0x40}, {705, 0x40}, {709, 0x40}, {713, 0x40},
580    {717, 0x40}, {721, 0x40}, {725, 0x40}, {729, 0x40},
581    {733, 0x40}, {737, 0x40}, {741, 0x40}, {745, 0x40},
582    {749, 0x40}, {753, 0x40}, {757, 0x40}, {761, 0x40},
583    {765, 0x40}, {769, 0x40}, {773, 0x40}, {777, 0x40},
584    {781, 0x40}, {785, 0x40}, {789, 0x40}, {793, 0x40},
585    {797, 0x30}, {801, 0x40},
586    {-1, 0}
587};
588
589#define SIZE6X4PAL		45
590static struct _ffolat ffo6x4pal[SIZE6X4PAL + 1] = {
591    {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60},
592    {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60},
593    {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60},
594    {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60},
595    {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60},
596    {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60},
597    {721, 0x60}, {725, 0x60}, {729, 0x60}, {733, 0x60},
598    {737, 0x60}, {741, 0x60}, {745, 0x60}, {749, 0x60},
599    {753, 0x60}, {757, 0x60}, {761, 0x60}, {765, 0x60},
600    {769, 0x60}, {773, 0x60}, {777, 0x60}, {781, 0x60},
601    {785, 0x60}, {789, 0x60}, {793, 0x60}, {797, 0x60},
602    {801, 0x60},
603    {-1, 0}
604};
605
606#define SIZE7X4NTSC		40
607static struct _ffolat ffo7x4ntsc[SIZE7X4NTSC + 1] = {
608    {525, 0x52}, {529, 0x52}, {533, 0x52}, {537, 0x52},
609    {541, 0x52}, {545, 0x40}, {549, 0x40}, {553, 0x40},
610    {557, 0x58}, {561, 0x40}, {565, 0x58}, {569, 0x40},
611    {573, 0x48}, {577, 0x40}, {581, 0x40}, {585, 0x40},
612    {589, 0x40}, {593, 0x48}, {597, 0x40}, {601, 0x40},
613    {605, 0x40}, {609, 0x40}, {613, 0x5b}, {617, 0x48},
614    {621, 0x60}, {625, 0x48}, {629, 0x48}, {633, 0x40},
615    {637, 0x5e}, {641, 0x40}, {645, 0x50}, {649, 0x56},
616    {653, 0x58}, {657, 0x6c}, {661, 0x40}, {665, 0x40},
617    {669, 0x40}, {673, 0x40}, {677, 0x40}, {681, 0x40},
618    {-1, 0}
619};
620
621#define SIZE7X4PAL		24
622static struct _ffolat ffo7x4pal[SIZE7X4PAL + 1] = {
623    {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60},
624    {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60},
625    {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60},
626    {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60},
627    {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60},
628    {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60},
629    {-1, 0}
630};
631
632#define SIZE7X5NTSC		54
633static struct _ffolat ffo7x5ntsc[SIZE7X5NTSC + 1] = {
634    {590, 0x40}, {594, 0x48}, {598, 0x40}, {602, 0x40},
635    {606, 0x40}, {610, 0x40}, {614, 0x5b}, {618, 0x48},
636    {622, 0x60}, {626, 0x48}, {630, 0x48}, {634, 0x40},
637    {638, 0x5e}, {642, 0x40}, {646, 0x50}, {650, 0x56},
638    {654, 0x58}, {658, 0x6c}, {662, 0x40}, {666, 0x40},
639    {670, 0x40}, {674, 0x40}, {678, 0x40}, {682, 0x40},
640    {686, 0x40}, {690, 0x40}, {694, 0x40}, {698, 0x40},
641    {702, 0x40}, {706, 0x40}, {710, 0x40}, {714, 0x40},
642    {718, 0x40}, {722, 0x40}, {726, 0x40}, {730, 0x40},
643    {734, 0x40}, {738, 0x40}, {742, 0x40}, {746, 0x40},
644    {750, 0x40}, {754, 0x40}, {758, 0x40}, {762, 0x40},
645    {766, 0x40}, {770, 0x40}, {774, 0x40}, {778, 0x40},
646    {782, 0x40}, {786, 0x40}, {790, 0x40}, {794, 0x40},
647    {798, 0x30}, {802, 0x40},
648    {-1, 0}
649};
650
651#define SIZE7X5PAL		45
652static struct _ffolat ffo7x5pal[SIZE7X5PAL + 1] = {
653    {625, 0x60}, {629, 0x60}, {633, 0x60}, {637, 0x60},
654    {641, 0x50}, {645, 0x60}, {649, 0x60}, {653, 0x60},
655    {657, 0x60}, {661, 0x60}, {665, 0x60}, {669, 0x60},
656    {673, 0x60}, {677, 0x60}, {681, 0x60}, {685, 0x60},
657    {689, 0x60}, {693, 0x60}, {697, 0x60}, {701, 0x60},
658    {705, 0x60}, {709, 0x60}, {713, 0x60}, {717, 0x60},
659    {721, 0x60}, {725, 0x60}, {729, 0x60}, {733, 0x60},
660    {737, 0x60}, {741, 0x60}, {745, 0x60}, {749, 0x60},
661    {753, 0x60}, {757, 0x60}, {761, 0x60}, {765, 0x60},
662    {769, 0x60}, {773, 0x60}, {777, 0x60}, {781, 0x60},
663    {785, 0x60}, {789, 0x60}, {793, 0x60}, {797, 0x60},
664    {801, 0x60},
665    {-1, 0}
666};
667
668/* h_total=1056, vga_lines=600 */
669#define	SIZE8X6NTSC		37
670static struct _ffolat ffo8x6ntsc[SIZE8X6NTSC + 1] = {
671    {620, 0x40},                       /* v_total_min >= vsync+10 >= vga_lines+10 = 610 */
672    {625, 0x58}, {630, 0x40}, {635, 0x40}, {640, 0x40},
673    {645, 0x46}, {650, 0x46}, {655, 0x4f}, {660, 0x4c},
674    {665, 0x4a}, {670, 0x50}, {675, 0x2f}, {680, 0x48},
675    {685, 0x38}, {690, 0x31}, {695, 0x40}, {700, 0x21},
676    {705, 0x25}, {710, 0x40}, {715, 0x48}, {720, 0x50},
677    {725, 0x30}, {730, 0x50}, {735, 0x50}, {740, 0x50},
678    {745, 0x40}, {750, 0x38}, {755, 0x50}, {760, 0x50},
679    {765, 0x40}, {770, 0x38}, {775, 0x40}, {780, 0x40},
680    {785, 0x40}, {790, 0x38}, {795, 0x50}, {800, 0x50},
681    {-1, 0}
682};
683
684/* h_total=1056, vga_lines=600 */
685#define	SIZE8X6PAL		36
686static struct _ffolat ffo8x6pal[SIZE8X6PAL + 1] = {
687    {625, 0x80}, {630, 0x80}, {635, 0x5a}, {640, 0x55},
688    {645, 0x48}, {650, 0x65}, {655, 0x65}, {660, 0x50},
689    {665, 0x80}, {670, 0x70}, {675, 0x56}, {680, 0x80},
690    {685, 0x58}, {690, 0x31}, {695, 0x80}, {700, 0x60},
691    {705, 0x45}, {710, 0x4a}, {715, 0x50}, {720, 0x50},
692    {725, 0x50}, {730, 0x45}, {735, 0x50}, {740, 0x50},
693    {745, 0x50}, {750, 0x50}, {755, 0x50}, {760, 0x50},
694    {765, 0x50}, {770, 0x50}, {775, 0x50}, {780, 0x50},
695    {785, 0x50}, {790, 0x50}, {795, 0x50}, {800, 0x50},
696    {-1, 0}
697};
698
699/* h_total=1344, vga_lines=768 */
700#define	SIZE10X7NTSC		45
701static struct _ffolativo ffo10x7ntsc[SIZE10X7NTSC] = {
702    {783, 0x4d, 0x40},
703    {789, 0x47, 0x14},
704    {795, 0x47, 0x7f},
705    {801, 0x47, 0x53},
706    {807, 0x47, 0x11},
707    {813, 0x47, 0x78},
708    {819, 0x47, 0x54},
709    {825, 0x47, 0x40},
710    {831, 0x47, 0x0f},
711    {837, 0x4d, 0x40},
712    {843, 0x47, 0x5a},
713    {849, 0x4d, 0x40},
714    {855, 0x47, 0x4b},
715    {861, 0x4d, 0x40},
716    {867, 0x47, 0x4b},
717    {873, 0x4d, 0x40},
718    {879, 0x47, 0x07},
719    {885, 0x48, 0x20},
720    {891, 0x47, 0x82},
721    {897, 0x47, 0x60},
722    {903, 0x47, 0x7f},
723    {909, 0x4d, 0x40},
724    {915, 0x48, 0x40},
725    {921, 0x4c, 0x40},
726    {927, 0x49, 0x40},
727    {933, 0x48, 0x40},
728    {939, 0x4a, 0x40},
729    {945, 0x46, 0x40},
730    {951, 0x4a, 0x40},
731    {957, 0x4a, 0x40},
732    {963, 0x4b, 0x40},
733    {969, 0x4b, 0x40},
734    {975, 0x48, 0x40},
735    {981, 0x47, 0x40},
736    {987, 0x47, 0x40},
737    {993, 0x47, 0x40},
738    {999, 0x48, 0x40},
739    {1005, 0x48, 0x40},
740    {1011, 0x47, 0x40},
741    {1017, 0x47, 0x40},
742    {1023, 0x48, 0x40},
743    {1029, 0x48, 0x40},
744    {1035, 0x46, 0x40},
745    {1041, 0x47, 0x40},
746    {1047, 0x47, 0x40}
747};
748
749/* h_total=1344, vga_lines=768 */
750#define	SIZE10X7PAL		46
751static struct _ffolativo ffo10x7pal[SIZE10X7PAL] = {
752    {781, 0x49, 0x40},
753    {787, 0x46, 0x40},
754    {793, 0x48, 0x40},
755    {799, 0x46, 0x40},
756    {805, 0x49, 0x40},
757    {811, 0x47, 0x40},
758    {817, 0x46, 0x40},
759    {823, 0x46, 0x56},
760    {829, 0x46, 0x2d},
761    {835, 0x46, 0x40},
762    {841, 0x46, 0x2d},
763    {847, 0x46, 0x3f},
764    {853, 0x46, 0x10},
765    {859, 0x46, 0x86},
766    {865, 0x46, 0xc9},
767    {871, 0x46, 0x83},
768    {877, 0x46, 0xa8},
769    {883, 0x46, 0x81},
770    {889, 0x46, 0xa5},
771    {895, 0x46, 0xa9},
772    {901, 0x46, 0x81},
773    {907, 0x46, 0xa4},
774    {913, 0x46, 0xa5},
775    {919, 0x46, 0x7f},
776    {925, 0x46, 0xa2},
777    {931, 0x46, 0x9d},
778    {937, 0x46, 0xc1},
779    {943, 0x46, 0x96},
780    {949, 0x46, 0xb7},
781    {955, 0x46, 0xb1},
782    {961, 0x46, 0x8a},
783    {967, 0x46, 0xa9},
784    {973, 0x46, 0xa0},
785    {979, 0x46, 0x40},
786    {985, 0x46, 0x97},
787    {991, 0x46, 0xb5},
788    {997, 0x46, 0xaa},
789    {1003, 0x46, 0x83},
790    {1009, 0x46, 0x9f},
791    {1015, 0x47, 0x40},
792    {1021, 0x46, 0xad},
793    {1027, 0x46, 0x87},
794    {1033, 0x46, 0xa2},
795    {1039, 0x47, 0x40},
796    {1045, 0x46, 0xac},
797    {1051, 0x46, 0x86}
798};
799
800/*==========================================================================*/
801/*FS450 API Functions.														*/
802/*==========================================================================*/
803
804/* Initialize device settings */
805static void
806initialize_houston_static_registers(void)
807{
808    houston_WriteReg(HOUSTON_BYP, 0, 2);
809    houston_WriteReg(HOUSTON_APO, 0, 2);
810    houston_WriteReg(HOUSTON_ALO, 0, 2);
811    houston_WriteReg(HOUSTON_AFO, 0, 2);
812    houston_WriteReg(HOUSTON_BCONTL, 0, 2);
813    houston_WriteReg(HOUSTON_BCONTH, 0, 2);
814    houston_WriteReg(HOUSTON_BDONE, 0, 2);
815    houston_WriteReg(HOUSTON_BDIAGL, 0, 2);
816    houston_WriteReg(HOUSTON_BDIAGH, 0, 2);
817    houston_WriteReg(HOUSTON_MISC, 0, 2);
818}
819
820int
821FS450_init(void)
822{
823    int err;
824
825    TRACE(("FS450_Init()\n"))
826
827        err = houston_init();
828    if (err)
829        return err;
830
831    initialize_houston_static_registers();
832
833    d.tv_on = PLAL_IsTVOn()? 1 : 0;
834
835    /* get the current tv standard */
836    conget_tv_std(&d.tv_std);
837
838    d.vga_mode = 0;
839
840    /* default to VP_TVOUT_MODE_CVBS_YC */
841    d.tvout_mode = GFX_TVOUT_MODE_CVBS_YC;
842
843    /* default to 1000 out of 1000 */
844    d.sharpness = 1000;
845    config_sharpness(d.sharpness);
846
847    /* default to 800 out of 1000 */
848    d.flicker = 800;
849    config_flicker(d.flicker);
850
851    /* default to zeros */
852    d.overscan_x = 0;
853    d.overscan_y = 0;
854    d.position_x = 0;
855    d.position_y = 0;
856
857    d.color = 50;
858    /* d.color = tvsetup.color[k]; */
859    config_color(d.color);
860
861    /* default */
862    d.brightness = 50;
863    d.contrast = 60;
864    config_brightness_contrast(d.tv_std, d.aps_trigger_bits, d.brightness,
865        d.contrast);
866
867    /* get the current yc filtering */
868    {
869        int luma_filter, chroma_filter;
870
871        conget_yc_filter(&luma_filter, &chroma_filter);
872        d.yc_filter = 0;
873        if (luma_filter)
874            d.yc_filter |= GFX_LUMA_FILTER;
875        if (chroma_filter)
876            d.yc_filter |= GFX_CHROMA_FILTER;
877    }
878
879    d.aps_trigger_bits = 0;
880    config_macrovision(d.tv_std, d.aps_trigger_bits);
881
882    d.last_overscan_y = -10000;
883
884    return 0;
885}
886
887void
888FS450_cleanup(void)
889{
890}
891
892/*==========================================================================*/
893/* Required configuration calls to write new settings to the device			*/
894/*==========================================================================*/
895
896#define REQ_TV_STANDARD_BIT			0x0002
897#define REQ_VGA_MODE_BIT			0x0004
898#define REQ_TVOUT_MODE_BIT			0x0008
899#define REQ_SHARPNESS_BIT			0x0010
900#define REQ_FLICKER_BIT				0x0020
901#define REQ_OVERSCAN_POSITION_BIT	0x0040
902#define REQ_COLOR_BIT				0x0080
903#define REQ_BRIGHTNESS_CONTRAST_BIT 0x0100
904#define REQ_YC_FILTER_BIT			0x0200
905#define REQ_MACROVISION_BIT			0x0400
906#define REQ_NCO_BIT					0x1000
907
908#define REQ_TV_STANDARD			(REQ_TV_STANDARD_BIT | REQ_OVERSCAN_POSITION \
909									| REQ_BRIGHTNESS_CONTRAST 				 \
910									| REQ_MACROVISION_BIT | REQ_YC_FILTER)
911#define REQ_VGA_MODE			(REQ_VGA_MODE_BIT | REQ_OVERSCAN_POSITION)
912#define REQ_TVOUT_MODE			(REQ_TVOUT_MODE_BIT)
913#define REQ_SHARPNESS			(REQ_SHARPNESS_BIT)
914#define REQ_FLICKER				(REQ_FLICKER_BIT)
915#define REQ_OVERSCAN_POSITION	(REQ_OVERSCAN_POSITION_BIT | REQ_NCO)
916#define REQ_COLOR				(REQ_COLOR_BIT)
917#define REQ_BRIGHTNESS_CONTRAST	(REQ_BRIGHTNESS_CONTRAST_BIT)
918#define REQ_YC_FILTER			(REQ_YC_FILTER_BIT)
919#define REQ_MACROVISION			(REQ_TV_STANDARD_BIT | 						 \
920									REQ_BRIGHTNESS_CONTRAST_BIT | 			 \
921									REQ_MACROVISION_BIT)
922#define REQ_NCO					(REQ_NCO_BIT)
923#define REQ_ENCODER				(REQ_TV_STANDARD | REQ_COLOR | 				 \
924									REQ_BRIGHTNESS_CONTRAST | REQ_YC_FILTER)
925
926static int
927write_config(int req)
928{
929    unsigned long reg, reg_encoder_reset = 0;
930    int reset;
931
932    /*if we're changing the nco, and the vertical scaling has changed... */
933    reset = ((REQ_NCO_BIT & req) && (d.overscan_y != d.last_overscan_y));
934    if (reset) {
935        /*put the encoder into reset while making changes */
936        houston_ReadReg(ENC_RESET, &reg, 1);
937        houston_WriteReg(ENC_RESET, reg | 0x01, 1);
938        reg_encoder_reset = reg & 0x01;
939    }
940
941    if (REQ_TV_STANDARD_BIT & req)
942        config_tv_std(d.tv_std, d.aps_trigger_bits);
943
944    if (REQ_VGA_MODE_BIT & req)
945        config_vga_mode(d.vga_mode);
946
947    if (REQ_TVOUT_MODE_BIT & req)
948        config_tvout_mode(d.tvout_mode);
949
950    if (REQ_OVERSCAN_POSITION_BIT & req) {
951        config_overscan_xy(d.tv_std,
952            d.vga_mode,
953            d.overscan_x, d.overscan_y, d.position_x, d.position_y);
954
955        /*h_timing and v_timing and syncs. */
956        if (PLAL_IsTVOn())
957            PLAL_SetTVTimingRegisters(p_specs());
958    }
959
960    if (REQ_NCO_BIT & req)
961        config_nco(d.tv_std, d.vga_mode);
962
963    if (REQ_SHARPNESS_BIT & req)
964        config_sharpness(d.sharpness);
965
966    if (REQ_FLICKER_BIT & req)
967        config_flicker(d.flicker);
968
969    if (REQ_COLOR_BIT & req)
970        config_color(d.color);
971
972    if (REQ_BRIGHTNESS_CONTRAST_BIT & req) {
973        config_brightness_contrast(d.tv_std,
974            d.aps_trigger_bits, d.brightness, d.contrast);
975    }
976
977    if (REQ_YC_FILTER_BIT & req) {
978        config_yc_filter(d.tv_std,
979            (d.yc_filter & GFX_LUMA_FILTER),
980            (d.yc_filter & GFX_CHROMA_FILTER));
981    }
982
983    if (REQ_MACROVISION_BIT & req)
984        config_macrovision(d.tv_std, d.aps_trigger_bits);
985
986    /*if we decided to put the encoder into reset, put it back */
987    if (reset) {
988        houston_ReadReg(ENC_RESET, &reg, 1);
989        houston_WriteReg(ENC_RESET, reg_encoder_reset | (reg & ~0x01), 1);
990
991        d.last_overscan_y = d.overscan_y;
992    }
993    return 0;
994}
995
996/*==========================================================================*/
997/* TV On																	*/
998/*==========================================================================*/
999
1000#if GFX_TV_DYNAMIC
1001int
1002fs450_get_tv_enable(unsigned int *p_on)
1003#else
1004int
1005gfx_get_tv_enable(unsigned int *p_on)
1006#endif
1007{
1008    if (!p_on)
1009        return ERR_INVALID_PARAMETER;
1010
1011    *p_on = d.tv_on;
1012
1013    return 0;
1014}
1015
1016/*//int FS450_set_tv_on(unsigned int on)*/
1017#if GFX_TV_DYNAMIC
1018int
1019fs450_set_tv_enable(int on)
1020#else
1021int
1022gfx_set_tv_enable(int on)
1023#endif
1024{
1025    unsigned long reg;
1026
1027    /*if not mode change, just return */
1028    if ((d.tv_on && on) || (!d.tv_on && !on))
1029        return 0;
1030
1031    /*if turning off... */
1032    if (!on) {
1033        /*reenable vga. */
1034        PLAL_EnableVga();
1035
1036        /*power down houston */
1037        config_power(0);
1038
1039        d.tv_on = 0;
1040
1041        return 0;
1042    }
1043
1044    /*turning on... */
1045
1046    /*power up houston      */
1047    config_power(1);
1048
1049    /*assert encoder reset. */
1050    houston_WriteReg(ENC_RESET, 0x01, 1);
1051
1052    /*initial platform preparation */
1053    PLAL_PrepForTVout();
1054
1055    /*configure encoder and nco. */
1056    write_config(REQ_VGA_MODE |
1057        REQ_TV_STANDARD |
1058        REQ_TVOUT_MODE |
1059        REQ_OVERSCAN_POSITION | REQ_YC_FILTER | REQ_MACROVISION);
1060
1061    /*set LP_EN and UIM */
1062    houston_ReadReg(HOUSTON_CR, &reg, 2);
1063    reg |= CR_LP_EN;
1064    reg &= ~(CR_UIM_MOD0 | CR_UIM_MOD1);
1065    reg |= (PLAL_FS450_UIM_mode() << 14);
1066    houston_WriteReg(HOUSTON_CR, reg, 2);
1067
1068    /*set platform timing registers */
1069    PLAL_SetTVTimingRegisters(p_specs());
1070
1071    PLAL_FinalEnableTVout(d.vga_mode);
1072
1073    /*sync bridge */
1074    {
1075        int retry_count = 0;
1076
1077        /*sync 50 times */
1078        while (retry_count++ < 50) {
1079            /*sync bridge. */
1080            houston_ReadReg(HOUSTON_MISC, &reg, 2);
1081            reg |= MISC_BRIDGE_SYNC;
1082            houston_WriteReg(HOUSTON_MISC, reg, 2);
1083            reg &= ~MISC_BRIDGE_SYNC;
1084            houston_WriteReg(HOUSTON_MISC, reg, 2);
1085        }
1086    }
1087
1088    /*deassert encoder reset. */
1089    houston_WriteReg(ENC_RESET, 0x00, 1);
1090
1091    d.tv_on = 1;
1092
1093    return 0;
1094}
1095
1096#if GFX_TV_DYNAMIC
1097int
1098fs450_set_tv_defaults(int format)
1099#else
1100int
1101gfx_set_tv_defaults(int format)
1102#endif
1103{
1104    return 0;
1105}
1106
1107/*==========================================================================*/
1108/* TV standard																*/
1109/*==========================================================================*/
1110
1111#if GFX_TV_DYNAMIC
1112int
1113fs450_get_tv_standard(unsigned long *p_standard)
1114#else
1115int
1116gfx_get_tv_standard(unsigned long *p_standard)
1117#endif
1118{
1119    if (!p_standard)
1120        return ERR_INVALID_PARAMETER;
1121
1122    *p_standard = d.tv_std;
1123
1124    return 0;
1125}
1126
1127#if GFX_TV_DYNAMIC
1128int
1129fs450_get_available_tv_standards(unsigned long *p_standards)
1130#else
1131int
1132gfx_get_available_tv_standards(unsigned long *p_standards)
1133#endif
1134{
1135    if (!p_standards)
1136        return ERR_INVALID_PARAMETER;
1137
1138    *p_standards = supported_standards();
1139
1140    return 0;
1141}
1142
1143#if GFX_TV_DYNAMIC
1144int
1145fs450_set_tv_standard(unsigned long standard)
1146#else
1147int
1148gfx_set_tv_standard(unsigned long standard)
1149#endif
1150{
1151    /* verify supported standard. */
1152    if (!(standard & supported_standards()))
1153        return ERR_INVALID_PARAMETER;
1154
1155    /* disallow if tv is on */
1156    if (d.tv_on)
1157        return ERR_CANNOT_CHANGE_WHILE_TV_ON;
1158
1159    d.tv_std = standard;
1160    /* d.color = tvsetup.color[k]; */
1161
1162    return write_config(REQ_TV_STANDARD);
1163}
1164
1165/*==========================================================================*/
1166/* vga mode as known by the driver											*/
1167/*==========================================================================*/
1168
1169#if GFX_TV_DYNAMIC
1170int
1171fs450_get_tv_vga_mode(unsigned long *p_vga_mode)
1172#else
1173int
1174gfx_get_tv_vga_mode(unsigned long *p_vga_mode)
1175#endif
1176{
1177    if (!p_vga_mode)
1178        return ERR_INVALID_PARAMETER;
1179
1180    *p_vga_mode = d.vga_mode;
1181
1182    return 0;
1183}
1184
1185#if GFX_TV_DYNAMIC
1186int
1187fs450_get_available_tv_vga_modes(unsigned long *p_vga_modes)
1188#else
1189int
1190gfx_get_available_tv_vga_modes(unsigned long *p_vga_modes)
1191#endif
1192{
1193    if (!p_vga_modes)
1194        return ERR_INVALID_PARAMETER;
1195
1196    *p_vga_modes =
1197        GFX_VGA_MODE_640X480 |
1198        GFX_VGA_MODE_720X487 | GFX_VGA_MODE_720X576 | GFX_VGA_MODE_800X600;
1199    if (houston_Rev() >= HOUSTON_REV_B)
1200        *p_vga_modes |= GFX_VGA_MODE_1024X768;
1201
1202    return 0;
1203}
1204
1205#if GFX_TV_DYNAMIC
1206int
1207fs450_set_tv_vga_mode(unsigned long vga_mode)
1208#else
1209int
1210gfx_set_tv_vga_mode(unsigned long vga_mode)
1211#endif
1212{
1213    /*reject if not a single valid VGA mode */
1214    switch (vga_mode) {
1215    default:
1216        return ERR_INVALID_PARAMETER;
1217    case GFX_VGA_MODE_640X480:
1218    case GFX_VGA_MODE_720X487:
1219    case GFX_VGA_MODE_720X576:
1220    case GFX_VGA_MODE_800X600:
1221        break;
1222    case GFX_VGA_MODE_1024X768:
1223        if (houston_Rev() >= HOUSTON_REV_B)
1224            break;
1225        return ERR_INVALID_PARAMETER;
1226    }
1227
1228    /*if the mode has changed... */
1229    if (vga_mode != d.vga_mode) {
1230        d.vga_mode = vga_mode;
1231
1232        return write_config(REQ_VGA_MODE);
1233    }
1234
1235    return 0;
1236}
1237
1238/*==========================================================================*/
1239/* tvout mode																*/
1240/*==========================================================================*/
1241
1242#if GFX_TV_DYNAMIC
1243int
1244fs450_get_tvout_mode(unsigned long *p_tvout_mode)
1245#else
1246int
1247gfx_get_tvout_mode(unsigned long *p_tvout_mode)
1248#endif
1249{
1250    if (!p_tvout_mode)
1251        return ERR_INVALID_PARAMETER;
1252
1253    *p_tvout_mode = d.tvout_mode;
1254
1255    return 0;
1256}
1257
1258#if GFX_TV_DYNAMIC
1259int
1260fs450_set_tvout_mode(unsigned long tvout_mode)
1261#else
1262int
1263gfx_set_tvout_mode(unsigned long tvout_mode)
1264#endif
1265{
1266    d.tvout_mode = tvout_mode;
1267
1268    return write_config(REQ_TVOUT_MODE);
1269}
1270
1271/*==========================================================================*/
1272/* Sharpness																*/
1273/*==========================================================================*/
1274
1275#if GFX_TV_DYNAMIC
1276int
1277fs450_get_sharpness(int *p_sharpness)
1278#else
1279int
1280gfx_get_sharpness(int *p_sharpness)
1281#endif
1282{
1283    if (!p_sharpness)
1284        return ERR_INVALID_PARAMETER;
1285
1286    *p_sharpness = d.sharpness;
1287
1288    return 0;
1289}
1290
1291#if GFX_TV_DYNAMIC
1292int
1293fs450_set_sharpness(int sharpness)
1294#else
1295int
1296gfx_set_sharpness(int sharpness)
1297#endif
1298{
1299    d.sharpness = range_limit(sharpness, 0, 1000);
1300
1301    return write_config(REQ_SHARPNESS);
1302}
1303
1304/*==========================================================================*/
1305/* flicker filter control.													*/
1306/*==========================================================================*/
1307
1308#if GFX_TV_DYNAMIC
1309int
1310fs450_get_flicker_filter(int *p_flicker)
1311#else
1312int
1313gfx_get_flicker_filter(int *p_flicker)
1314#endif
1315{
1316    if (!p_flicker)
1317        return ERR_INVALID_PARAMETER;
1318
1319    *p_flicker = d.flicker;
1320
1321    return 0;
1322}
1323
1324#if GFX_TV_DYNAMIC
1325int
1326fs450_set_flicker_filter(int flicker)
1327#else
1328int
1329gfx_set_flicker_filter(int flicker)
1330#endif
1331{
1332    d.flicker = range_limit(flicker, 0, 1000);
1333
1334    return write_config(REQ_FLICKER);
1335}
1336
1337/*==========================================================================*/
1338/* Overscan and Position													*/
1339/*==========================================================================*/
1340
1341#if GFX_TV_DYNAMIC
1342int
1343fs450_get_overscan(int *p_x, int *p_y)
1344#else
1345int
1346gfx_get_overscan(int *p_x, int *p_y)
1347#endif
1348{
1349    if (!p_x || !p_y)
1350        return ERR_INVALID_PARAMETER;
1351
1352    *p_x = d.overscan_x;
1353    *p_y = d.overscan_y;
1354
1355    return 0;
1356}
1357
1358#if GFX_TV_DYNAMIC
1359int
1360fs450_set_overscan(int x, int y)
1361#else
1362int
1363gfx_set_overscan(int x, int y)
1364#endif
1365{
1366    d.overscan_x = range_limit(x, -1000, 1000);
1367    d.overscan_y = range_limit(y, -1000, 1000);
1368
1369    return write_config(REQ_OVERSCAN_POSITION);
1370}
1371
1372#if GFX_TV_DYNAMIC
1373int
1374fs450_get_position(int *p_x, int *p_y)
1375#else
1376int
1377gfx_get_position(int *p_x, int *p_y)
1378#endif
1379{
1380    if (!p_x || !p_y)
1381        return ERR_INVALID_PARAMETER;
1382
1383    *p_x = d.position_x;
1384    *p_y = d.position_y;
1385
1386    return 0;
1387}
1388
1389#if GFX_TV_DYNAMIC
1390int
1391fs450_set_position(int x, int y)
1392#else
1393int
1394gfx_set_position(int x, int y)
1395#endif
1396{
1397    d.position_x = range_limit(x, -1000, 1000);
1398    d.position_y = range_limit(y, -1000, 1000);
1399
1400    return write_config(REQ_OVERSCAN_POSITION);
1401}
1402
1403/*==========================================================================*/
1404/* Color, Brightness, and Contrast											*/
1405/*==========================================================================*/
1406
1407#if GFX_TV_DYNAMIC
1408int
1409fs450_get_color(int *p_color)
1410#else
1411int
1412gfx_get_color(int *p_color)
1413#endif
1414{
1415    if (!p_color)
1416        return ERR_INVALID_PARAMETER;
1417
1418    *p_color = d.color;
1419
1420    return 0;
1421}
1422
1423#if GFX_TV_DYNAMIC
1424int
1425fs450_set_color(int color)
1426#else
1427int
1428gfx_set_color(int color)
1429#endif
1430{
1431    d.color = range_limit(color, 0, 100);
1432
1433    return write_config(REQ_COLOR);
1434}
1435
1436#if GFX_TV_DYNAMIC
1437int
1438fs450_get_brightness(int *p_brightness)
1439#else
1440int
1441gfx_get_brightness(int *p_brightness)
1442#endif
1443{
1444    if (!p_brightness)
1445        return ERR_INVALID_PARAMETER;
1446
1447    *p_brightness = d.brightness;
1448
1449    return 0;
1450}
1451
1452#if GFX_TV_DYNAMIC
1453int
1454fs450_set_brightness(int brightness)
1455#else
1456int
1457gfx_set_brightness(int brightness)
1458#endif
1459{
1460    d.brightness = range_limit(brightness, 0, 100);
1461
1462    return write_config(REQ_BRIGHTNESS_CONTRAST);
1463}
1464
1465#if GFX_TV_DYNAMIC
1466int
1467fs450_get_contrast(int *p_contrast)
1468#else
1469int
1470gfx_get_contrast(int *p_contrast)
1471#endif
1472{
1473    if (!p_contrast)
1474        return ERR_INVALID_PARAMETER;
1475
1476    *p_contrast = d.contrast;
1477
1478    return 0;
1479}
1480
1481#if GFX_TV_DYNAMIC
1482int
1483fs450_set_contrast(int constrast)
1484#else
1485int
1486gfx_set_contrast(int constrast)
1487#endif
1488{
1489    d.contrast = range_limit(constrast, 0, 100);
1490
1491    return write_config(REQ_BRIGHTNESS_CONTRAST);
1492}
1493
1494/*==========================================================================*/
1495/* YC filters																*/
1496/*==========================================================================*/
1497
1498#if GFX_TV_DYNAMIC
1499int
1500fs450_get_yc_filter(unsigned int *p_yc_filter)
1501#else
1502int
1503gfx_get_yc_filter(unsigned int *p_yc_filter)
1504#endif
1505{
1506    if (!p_yc_filter)
1507        return ERR_INVALID_PARAMETER;
1508
1509    if (houston_Rev() < HOUSTON_REV_B)
1510        return ERR_NOT_SUPPORTED;
1511
1512    *p_yc_filter = d.yc_filter;
1513
1514    return 0;
1515}
1516
1517#if GFX_TV_DYNAMIC
1518int
1519fs450_set_yc_filter(unsigned int yc_filter)
1520#else
1521int
1522gfx_set_yc_filter(unsigned int yc_filter)
1523#endif
1524{
1525    if (houston_Rev() < HOUSTON_REV_B)
1526        return ERR_NOT_SUPPORTED;
1527
1528    /*luma filter. */
1529    if (yc_filter & GFX_LUMA_FILTER)
1530        d.yc_filter |= GFX_LUMA_FILTER;
1531    else
1532        d.yc_filter &= ~GFX_LUMA_FILTER;
1533
1534    /*chroma filter. */
1535    if (yc_filter & GFX_CHROMA_FILTER)
1536        d.yc_filter |= GFX_CHROMA_FILTER;
1537    else
1538        d.yc_filter &= ~GFX_CHROMA_FILTER;
1539
1540    return write_config(REQ_YC_FILTER);
1541}
1542
1543#if GFX_TV_DYNAMIC
1544int
1545fs450_get_aps_trigger_bits(unsigned int *p_trigger_bits)
1546#else
1547int
1548gfx_get_aps_trigger_bits(unsigned int *p_trigger_bits)
1549#endif
1550{
1551    if (!p_trigger_bits)
1552        return ERR_INVALID_PARAMETER;
1553
1554    *p_trigger_bits = d.aps_trigger_bits;
1555
1556    return 0;
1557}
1558
1559#if GFX_TV_DYNAMIC
1560int
1561fs450_set_aps_trigger_bits(unsigned int trigger_bits)
1562#else
1563int
1564gfx_set_aps_trigger_bits(unsigned int trigger_bits)
1565#endif
1566{
1567    d.aps_trigger_bits = trigger_bits;
1568
1569    return write_config(REQ_MACROVISION);
1570}
1571
1572/*----------------------------------------------------------------------------
1573 * gfx_set_tv_format
1574 *
1575 * This routine sets the TV encoder registers to the specified format
1576 * and resolution.
1577 * Currently only NTSC 640x480 is supported.
1578 *----------------------------------------------------------------------------
1579 */
1580#if GFX_TV_DYNAMIC
1581int
1582fs450_set_tv_format(TVStandardType format, GfxOnTVType resolution)
1583#else
1584int
1585gfx_set_tv_format(TVStandardType format, GfxOnTVType resolution)
1586#endif
1587{
1588    /* ### ADD ### IMPLEMENTATION */
1589    return (0);
1590}
1591
1592/*----------------------------------------------------------------------------
1593 * gfx_set_tv_output
1594 *
1595 * This routine sets the TV encoder registers to the specified output type.
1596 * Supported output types are : S-VIDEO and Composite.
1597 *----------------------------------------------------------------------------
1598 */
1599#if GFX_TV_DYNAMIC
1600int
1601fs450_set_tv_output(int output)
1602#else
1603int
1604gfx_set_tv_output(int output)
1605#endif
1606{
1607    /* ### ADD ### IMPLEMENTATION */
1608    return (0);
1609}
1610
1611/*----------------------------------------------------------------------------
1612 * gfx_set_tv_cc_enable
1613 *
1614 * This routine enables or disables the use of the hardware CC registers
1615 * in the TV encoder.
1616 *----------------------------------------------------------------------------
1617 */
1618#if GFX_TV_DYNAMIC
1619int
1620fs450_set_tv_cc_enable(int enable)
1621#else
1622int
1623gfx_set_tv_cc_enable(int enable)
1624#endif
1625{
1626    /* ### ADD ### IMPLEMENTATION */
1627    return (0);
1628}
1629
1630/*----------------------------------------------------------------------------
1631 * gfx_set_tv_cc_data
1632 *
1633 * This routine writes the two specified characters to the CC data register
1634 * of the TV encoder.
1635 *----------------------------------------------------------------------------
1636 */
1637#if GFX_TV_DYNAMIC
1638int
1639fs450_set_tv_cc_data(unsigned char data1, unsigned char data2)
1640#else
1641int
1642gfx_set_tv_cc_data(unsigned char data1, unsigned char data2)
1643#endif
1644{
1645    /* ### ADD ### IMPLEMENTATION */
1646    return (0);
1647}
1648
1649#ifdef FS450_DIRECTREG
1650
1651/*==========================================================================*/
1652/* Direct Read and Write registers											*/
1653/*==========================================================================*/
1654
1655int
1656FS450_ReadRegister(S_REG_INFO * p_reg)
1657{
1658    unsigned long tmp;
1659
1660    if (PLAL_ReadRegister(p_reg))
1661        return 0;
1662
1663    if (SOURCE_HOUSTON == p_reg->source) {
1664        switch (p_reg->size) {
1665        case 1:
1666        case 2:
1667            {
1668                houston_ReadReg((int)p_reg->offset, &tmp, (int)p_reg->size);
1669                p_reg->value = tmp;
1670            }
1671            return 0;
1672
1673        case 4:
1674            {
1675                houston_ReadReg((unsigned int)p_reg->offset, &tmp, 2);
1676                p_reg->value = (tmp << 16);
1677                houston_ReadReg((unsigned int)(p_reg->offset + 2), &tmp, 2);
1678                p_reg->value |= tmp;
1679            }
1680            return 0;
1681        }
1682    }
1683
1684    return ERR_INVALID_PARAMETER;
1685}
1686
1687int
1688FS450_WriteRegister(S_REG_INFO * p_reg)
1689{
1690    if (PLAL_WriteRegister(p_reg))
1691        return 0;
1692
1693    if (SOURCE_HOUSTON == p_reg->source) {
1694        houston_WriteReg((unsigned int)p_reg->offset, p_reg->value,
1695            p_reg->size);
1696
1697        return 0;
1698    }
1699
1700    return ERR_INVALID_PARAMETER;
1701}
1702
1703#endif
1704
1705/* Houston initialization function. */
1706static int g_houston_rev = -1;
1707
1708static int
1709houston_init(void)
1710{
1711    /*//int errc; */
1712    unsigned long write, read;
1713
1714    TRACE(("houston_init()\n"))
1715
1716        /*Before we begin, we must enable power to the TFT */
1717        read = READ_VID32(CS5530_DISPLAY_CONFIG);
1718    read |= CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN;
1719    WRITE_VID32(CS5530_DISPLAY_CONFIG, read);
1720
1721    /*simple w/r test. */
1722    write = 0x0055;
1723    read = 0;
1724
1725    houston_WriteReg(HOUSTON_IHO, write, 2);
1726    houston_ReadReg(HOUSTON_IHO, &read, 2);
1727    if (read != write) {
1728        houston_WriteReg(HOUSTON_IHO, write, 2);
1729        houston_ReadReg(HOUSTON_IHO, &read, 2);
1730        if (read != write) {
1731            /*chip is not there, do something appropriate? */
1732            TRACE(("wrote HOUSTON_IHO=0x0055, read 0x%04x\n", read))
1733                return ERR_DEVICE_NOT_FOUND;
1734        }
1735    }
1736
1737    /*read chip revision. */
1738    houston_ReadReg(HOUSTON_REV, &read, 2);
1739    g_houston_rev = (int)read;
1740
1741    /*ok. */
1742    return 0;
1743}
1744
1745static int
1746houston_Rev(void)
1747{
1748    return g_houston_rev;
1749}
1750
1751static S_TIMING_SPECS g_specs;
1752
1753static const S_TIMING_SPECS *
1754p_specs(void)
1755{
1756    return &g_specs;
1757}
1758
1759/*==========================================================================*/
1760/* FS450 configuration functions.											*/
1761/*==========================================================================*/
1762static int
1763config_init(void)
1764{
1765    int err;
1766
1767    TRACE(("config_init()\n"))
1768
1769        err = houston_init();
1770    if (err)
1771        return err;
1772
1773    return 0;
1774}
1775
1776/*==========================================================================*/
1777/* convert word to encoder 10 bit value.									*/
1778/*==========================================================================*/
1779
1780static unsigned short
1781w10bit2z(unsigned short w)
1782{
1783    return (w >> 2) | ((w & 0x03) << 8);
1784}
1785
1786static unsigned short
1787z2w10bit(unsigned short z)
1788{
1789    return (0x03 & (z >> 8)) | ((0xFF & z) << 2);
1790}
1791
1792/*==========================================================================*/
1793/* TV Standards																*/
1794/*==========================================================================*/
1795
1796static const struct
1797{
1798    unsigned long standard;
1799    int tvsetup_index;
1800} g_tv_standards[] = {
1801    {
1802    GFX_TV_STANDARD_NTSC_M, 0}, {
1803    GFX_TV_STANDARD_NTSC_M_J, 2}, {
1804    GFX_TV_STANDARD_PAL_B, 1}, {
1805    GFX_TV_STANDARD_PAL_D, 1}, {
1806    GFX_TV_STANDARD_PAL_H, 1}, {
1807    GFX_TV_STANDARD_PAL_I, 1}, {
1808    GFX_TV_STANDARD_PAL_M, 3}, {
1809    GFX_TV_STANDARD_PAL_N, 4}, {
1810GFX_TV_STANDARD_PAL_G, 1},};
1811
1812static int
1813map_tvstd_to_index(unsigned long tv_std)
1814{
1815    unsigned int i;
1816
1817    for (i = 0; i < sizeof(g_tv_standards) / sizeof(*g_tv_standards); i++) {
1818        if (tv_std == g_tv_standards[i].standard)
1819            return g_tv_standards[i].tvsetup_index;
1820    }
1821
1822    return -1;
1823}
1824
1825static unsigned long
1826supported_standards(void)
1827{
1828    unsigned long standards = 0;
1829    unsigned int i;
1830
1831    for (i = 0; i < sizeof(g_tv_standards) / sizeof(*g_tv_standards); i++) {
1832        if (g_tv_standards[i].tvsetup_index >= 0)
1833            standards |= g_tv_standards[i].standard;
1834    }
1835
1836    return standards;
1837}
1838
1839/*==========================================================================*/
1840
1841static void
1842config_power(int on)
1843{
1844    unsigned long reg;
1845
1846    if (houston_Rev() < HOUSTON_REV_B) {
1847        /* no power down supported, but still turn of clock in off mode */
1848        if (on) {
1849            houston_ReadReg(HOUSTON_CR, &reg, 2);
1850            reg &= ~(CR_CLKOFF | CR_RESET);
1851            houston_WriteReg(HOUSTON_CR, reg, 2);
1852            reg |= CR_RESET;
1853            houston_WriteReg(HOUSTON_CR, reg, 2);
1854            reg &= ~CR_RESET;
1855            houston_WriteReg(HOUSTON_CR, reg, 2);
1856        } else {
1857            houston_ReadReg(HOUSTON_CR, &reg, 2);
1858            reg |= CR_CLKOFF;
1859            houston_WriteReg(HOUSTON_CR, reg, 2);
1860        }
1861
1862        return;
1863    }
1864
1865    if (on) {
1866        /* !CLKOFF, !COMPOFF, !YCOFF */
1867        /* and reset Houston */
1868        houston_ReadReg(HOUSTON_CR, &reg, 2);
1869        reg &= ~(CR_CLKOFF | CR_RESET | CR_COMPOFF | CR_YCOFF);
1870        houston_WriteReg(HOUSTON_CR, reg, 2);
1871        reg |= CR_RESET;
1872        houston_WriteReg(HOUSTON_CR, reg, 2);
1873        reg &= ~CR_RESET;
1874        houston_WriteReg(HOUSTON_CR, reg, 2);
1875
1876        /* !GTLIO_PD */
1877        houston_ReadReg(HOUSTON_MISC, &reg, 2);
1878        reg &= ~MISC_GTLIO_PD;
1879        houston_WriteReg(HOUSTON_MISC, reg, 2);
1880    } else {
1881        /* CLKOFF, COMPOFF, YCOFF */
1882        houston_ReadReg(HOUSTON_CR, &reg, 2);
1883        reg |= (CR_CLKOFF | CR_COMPOFF | CR_YCOFF);
1884        houston_WriteReg(HOUSTON_CR, reg, 2);
1885
1886        /* GTLIO_PD */
1887        houston_ReadReg(HOUSTON_MISC, &reg, 2);
1888        reg |= MISC_GTLIO_PD;
1889        houston_WriteReg(HOUSTON_MISC, reg, 2);
1890    }
1891}
1892
1893/*==========================================================================*/
1894/* VGA mode																	*/
1895/*==========================================================================*/
1896
1897static void
1898config_vga_mode(unsigned long vga_mode)
1899{
1900    /*h_total must be evenly divisible by 32? */
1901
1902    static struct
1903    {
1904        unsigned long mode;
1905        int width;
1906        int lines;
1907        int h_total;
1908    } vgaparams[] = {
1909        {
1910        GFX_VGA_MODE_640X480, 640, 480, 1056}, {
1911        GFX_VGA_MODE_720X487, 720, 487, 1056}, {
1912        GFX_VGA_MODE_720X576, 720, 576, 1056}, {
1913        GFX_VGA_MODE_800X600, 800, 600, 1056}, {
1914    GFX_VGA_MODE_1024X768, 1024, 768, 1344},};
1915
1916    unsigned long cr, misc, byp;
1917    unsigned int i;
1918
1919    g_specs.vga_width = 0;
1920    g_specs.vga_lines = 0;
1921    g_specs.h_total = 0;
1922
1923    for (i = 0; i < sizeof(vgaparams) / sizeof(*vgaparams); i++) {
1924        if (vga_mode == vgaparams[i].mode) {
1925            g_specs.vga_width = vgaparams[i].width;
1926            g_specs.vga_lines = vgaparams[i].lines;
1927            g_specs.h_total = vgaparams[i].h_total;
1928            break;
1929        }
1930    }
1931    if (!g_specs.h_total)
1932        return;
1933
1934    /*clock mux decimator and vga dual. */
1935    houston_ReadReg(HOUSTON_CR, &cr, 2);
1936    houston_ReadReg(HOUSTON_MISC, &misc, 2);
1937    houston_ReadReg(HOUSTON_BYP, &byp, 2);
1938
1939    if (vga_mode == GFX_VGA_MODE_1024X768) {
1940         /*XGA*/ cr |= CR_UIM_DEC;
1941        misc |= MISC_VGACKDIV;
1942        byp |= (BYP_HDS_BYPASS | BYP_CAC_BYPASS);
1943    } else {
1944        /*VGA,SVGA */
1945        cr &= ~CR_UIM_DEC;
1946        misc &= ~MISC_VGACKDIV;
1947        byp &= ~(BYP_HDS_BYPASS | BYP_CAC_BYPASS);
1948    }
1949
1950    houston_WriteReg(HOUSTON_CR, cr, 2);
1951    houston_WriteReg(HOUSTON_MISC, misc, 2);
1952    houston_WriteReg(HOUSTON_BYP, byp, 2);
1953}
1954
1955/*==========================================================================*/
1956/* Write settings for TV standard to device									*/
1957/*==========================================================================*/
1958
1959static void
1960config_tv_std(unsigned long tv_std, unsigned int trigger_bits)
1961{
1962    int k;
1963    unsigned short reg34;
1964    unsigned long cr, w;
1965    unsigned long l;
1966
1967    /*verify supported standard. */
1968    k = map_tvstd_to_index(tv_std);
1969    if (k < 0)
1970        return;
1971
1972    /*store tv width and lines */
1973    g_specs.tv_width = tvsetup.tv_width[k];
1974    g_specs.tv_lines = tvsetup.tv_lines[k];
1975
1976    /*houston CR register. */
1977    houston_ReadReg(HOUSTON_CR, &cr, 2);
1978    cr &= ~CR_656_PAL_NTSC;
1979    cr |= tvsetup.houston_cr[k];
1980    houston_WriteReg(HOUSTON_CR, cr, 2);
1981
1982    /*setup the encoder. */
1983    l = tvsetup.chroma_freq[k];
1984    houston_WriteReg(ENC_CHROMA_FREQ, (int)(l & 0x00ff), 1);
1985    houston_WriteReg(ENC_CHROMA_FREQ + 1, (int)((l >> 8) & 0x00ff), 1);
1986    houston_WriteReg(ENC_CHROMA_FREQ + 2, (int)((l >> 16) & 0x00ff), 1);
1987    houston_WriteReg(ENC_CHROMA_FREQ + 3, (int)((l >> 24) & 0x00ff), 1);
1988
1989    houston_WriteReg(ENC_CHROMA_PHASE, tvsetup.chroma_phase[k], 1);
1990    houston_WriteReg(ENC_REG05, 0x00, 1);       /*reg 0x05 */
1991    houston_WriteReg(ENC_REG06, 0x89, 1);       /*reg 0x06 */
1992    houston_WriteReg(ENC_REG07, 0x00, 1);       /*reg 0x07 */
1993    houston_WriteReg(ENC_HSYNC_WIDTH, tvsetup.hsync_width[k], 1);
1994    houston_WriteReg(ENC_BURST_WIDTH, tvsetup.burst_width[k], 1);
1995    houston_WriteReg(ENC_BACK_PORCH, tvsetup.back_porch[k], 1);
1996    houston_WriteReg(ENC_CB_BURST_LEVEL, tvsetup.cb_burst_level[k], 1);
1997    houston_WriteReg(ENC_CR_BURST_LEVEL, tvsetup.cr_burst_level[k], 1);
1998    houston_WriteReg(ENC_SLAVE_MODE, 0x01, 1);  /*slave mode */
1999    if (trigger_bits == 0)
2000        w = w10bit2z(tvsetup.blank_level[k]);   /*blank level */
2001    else
2002        w = w10bit2z((unsigned short)(tvsetup.blank_level[k] -
2003                tvsetup.hamp_offset[k]));
2004    houston_WriteReg(ENC_BLANK_LEVEL, w & 0x00ff, 1);
2005    houston_WriteReg(ENC_BLANK_LEVEL + 1, w >> 8, 1);
2006    w = w10bit2z(tvsetup.tv_lines[k]); /*num_lines */
2007    houston_WriteReg(ENC_NUM_LINES, w & 0x00ff, 1);
2008    houston_WriteReg(ENC_NUM_LINES + 1, w >> 8, 1);
2009
2010    houston_WriteReg(ENC_TINT, 0x00, 1);        /*tint */
2011    houston_WriteReg(ENC_BREEZE_WAY, tvsetup.breeze_way[k], 1);
2012    houston_WriteReg(ENC_FRONT_PORCH, tvsetup.front_porch[k], 1);
2013    houston_WriteReg(ENC_ACTIVELINE, tvsetup.activeline[k], 1);
2014    houston_WriteReg(ENC_FIRST_LINE, 0x15, 1);  /*firstvideoline */
2015    reg34 =
2016        0x80 |
2017        (tvsetup.pal_mode[k] << 6) |
2018        (tvsetup.sys625_50[k] << 3) |
2019        (tvsetup.cphase_rst[k] << 1) | (tvsetup.vsync5[k]);
2020    houston_WriteReg(ENC_REG34, reg34, 1);      /*reg 0x34 */
2021    houston_WriteReg(ENC_SYNC_LEVEL, tvsetup.sync_level[k], 1);
2022    if (trigger_bits == 0)
2023        w = w10bit2z(tvsetup.vbi_blank_level[k]);       /*blank level */
2024    else
2025        w = w10bit2z((unsigned short)(tvsetup.vbi_blank_level[k] - 1));
2026    houston_WriteReg(ENC_VBI_BLANK_LEVEL, w & 0x00ff, 1);
2027    houston_WriteReg(ENC_VBI_BLANK_LEVEL + 1, w >> 8, 1);
2028}
2029
2030static void
2031conget_tv_std(unsigned long *p_tv_standard)
2032{
2033    unsigned long cr;
2034
2035    if (!p_tv_standard)
2036        return;
2037
2038    /*just pick between NTSC and PAL */
2039    houston_ReadReg(HOUSTON_CR, &cr, 2);
2040    if (CR_656_PAL_NTSC & cr)
2041        *p_tv_standard = GFX_TV_STANDARD_PAL_B;
2042    else
2043        *p_tv_standard = GFX_TV_STANDARD_NTSC_M;
2044}
2045
2046/*==========================================================================*/
2047/* TVout mode																*/
2048/*==========================================================================*/
2049
2050static void
2051config_tvout_mode(unsigned long tvout_mode)
2052{
2053    unsigned long cr;
2054
2055    houston_ReadReg(HOUSTON_CR, &cr, 2);
2056
2057    /*all dacs off */
2058    cr |= (CR_COMPOFF | CR_YCOFF);
2059    /*not rgb */
2060    cr &= ~CR_OFMT;
2061
2062    /*turn on requested output */
2063    if (GFX_TVOUT_MODE_CVBS & tvout_mode)
2064        cr &= ~CR_COMPOFF;
2065    if (GFX_TVOUT_MODE_YC & tvout_mode)
2066        cr &= ~CR_YCOFF;
2067    if (GFX_TVOUT_MODE_RGB & tvout_mode) {
2068        cr &= ~(CR_COMPOFF | CR_YCOFF);
2069        cr |= CR_OFMT;
2070    }
2071
2072    houston_WriteReg(HOUSTON_CR, cr, 2);
2073}
2074
2075static void
2076conget_tvout_mode(unsigned long *p_tvout_mode)
2077{
2078    unsigned long cr;
2079
2080    if (!p_tvout_mode)
2081        return;
2082
2083    houston_ReadReg(HOUSTON_CR, &cr, 2);
2084
2085    if (CR_OFMT & cr)
2086        *p_tvout_mode = GFX_TVOUT_MODE_RGB;
2087    else {
2088        *p_tvout_mode = 0;
2089        if (!(CR_YCOFF & cr))
2090            *p_tvout_mode |= GFX_TVOUT_MODE_YC;
2091        if (!(CR_COMPOFF & cr))
2092            *p_tvout_mode |= GFX_TVOUT_MODE_CVBS;
2093    }
2094}
2095
2096/*==========================================================================*/
2097/* Size & Position															*/
2098/*==========================================================================*/
2099
2100#define IS_NTSC(tv_std) 		\
2101	(tv_std & ( 				\
2102	GFX_TV_STANDARD_NTSC_M |   	\
2103	GFX_TV_STANDARD_NTSC_M_J | 	\
2104	GFX_TV_STANDARD_PAL_M))
2105#define IS_PAL(tv_std) 			\
2106	(tv_std & ( 				\
2107	GFX_TV_STANDARD_PAL_B | 	\
2108	GFX_TV_STANDARD_PAL_D | 	\
2109	GFX_TV_STANDARD_PAL_H | 	\
2110	GFX_TV_STANDARD_PAL_I | 	\
2111	GFX_TV_STANDARD_PAL_N | 	\
2112	GFX_TV_STANDARD_PAL_G))
2113
2114/*return fifo delay setting for mode, std, and total lines.*/
2115
2116static void
2117get_ffolat_ivo(unsigned long vga_mode,
2118    unsigned long tv_std, long i, unsigned short *ffolat, unsigned short *ivo)
2119{
2120    switch (vga_mode) {
2121    case GFX_VGA_MODE_640X480:
2122        if (IS_NTSC(tv_std)) {
2123            if (i > SIZE6X4NTSC - 1)
2124                i = SIZE6X4NTSC - 1;
2125            *ffolat = ffo6x4ntsc[i].ffolat;
2126            *ivo = 0x20;
2127        } else {
2128            if (i > SIZE6X4PAL - 1)
2129                i = SIZE6X4PAL - 1;
2130            *ffolat = ffo6x4pal[i].ffolat;
2131            *ivo = 0x28;
2132        }
2133        break;
2134
2135    case GFX_VGA_MODE_800X600:
2136        if (IS_NTSC(tv_std)) {
2137            if (i > SIZE8X6NTSC - 1)
2138                i = SIZE8X6NTSC - 1;
2139            *ffolat = ffo8x6ntsc[i].ffolat;
2140            *ivo = 0x3a;
2141        } else {
2142            if (i > SIZE8X6PAL - 1)
2143                i = SIZE8X6PAL - 1;
2144            *ffolat = ffo8x6pal[i].ffolat;
2145            *ivo = 0x39;
2146        }
2147        break;
2148
2149    case GFX_VGA_MODE_720X487:
2150        *ffolat = 0x40;                /*FFO7x4; */
2151        *ivo = 0x1a;
2152        break;
2153
2154    case GFX_VGA_MODE_720X576:
2155        *ffolat = 0x40;                /*FFO7x5; */
2156        *ivo = 0x1a;
2157        break;
2158
2159    case GFX_VGA_MODE_1024X768:
2160    default:
2161        if (IS_NTSC(tv_std)) {
2162            if (i > SIZE10X7NTSC - 1)
2163                i = SIZE10X7NTSC - 1;
2164            *ffolat = ffo10x7ntsc[i].ffolat;
2165            *ivo = ffo10x7ntsc[i].ivo;
2166        } else {
2167            if (i > SIZE10X7PAL - 1)
2168                i = SIZE10X7PAL - 1;
2169            *ffolat = ffo10x7pal[i].ffolat;
2170            *ivo = ffo10x7pal[i].ivo;
2171        }
2172        break;
2173    }
2174}
2175
2176/*get vertical line min and max for mode and std.*/
2177
2178static void
2179get_vtotal_min_max(unsigned long vga_mode,
2180    unsigned long tv_std, int *v_total_min, int *v_total_max, int *v_step)
2181{
2182    int k = map_tvstd_to_index(tv_std);
2183
2184    switch (vga_mode) {
2185    case GFX_VGA_MODE_640X480:
2186        if (IS_NTSC(tv_std)) {
2187            *v_total_min = ffo6x4ntsc[0].v_total;
2188            *v_total_max = ffo6x4ntsc[SIZE6X4NTSC - 1].v_total;
2189        } else {
2190            *v_total_min = ffo6x4pal[0].v_total;
2191            *v_total_max = ffo6x4pal[SIZE6X4PAL - 1].v_total;
2192        }
2193        *v_step = 4;
2194        break;
2195
2196    case GFX_VGA_MODE_800X600:
2197        if (IS_NTSC(tv_std)) {
2198            *v_total_min = ffo8x6ntsc[0].v_total;
2199            *v_total_max = ffo8x6ntsc[SIZE8X6NTSC - 1].v_total;
2200        } else {
2201            *v_total_min = ffo8x6pal[0].v_total;
2202            *v_total_max = ffo8x6pal[SIZE8X6PAL - 1].v_total;
2203        }
2204        *v_step = 5;
2205        break;
2206
2207    case GFX_VGA_MODE_720X487:
2208    case GFX_VGA_MODE_720X576:
2209        *v_total_min = tvsetup.tv_lines[k];
2210        *v_total_max = tvsetup.tv_lines[k];
2211        *v_step = 4;
2212        break;
2213
2214    case GFX_VGA_MODE_1024X768:
2215        if (IS_NTSC(tv_std)) {
2216            *v_total_min = ffo10x7ntsc[0].v_total;
2217            *v_total_max = ffo10x7ntsc[SIZE10X7NTSC - 1].v_total;
2218        } else {
2219            *v_total_min = ffo10x7pal[0].v_total;
2220            *v_total_max = ffo10x7pal[SIZE10X7PAL - 1].v_total;
2221        }
2222        *v_step = 6;
2223        break;
2224    }
2225}
2226
2227static void
2228config_overscan_xy(unsigned long tv_std,
2229    unsigned long vga_mode,
2230    int overscan_x, int overscan_y, int pos_x, int pos_y)
2231{
2232    unsigned int vga_index;
2233    unsigned long reg;
2234    double vsc;
2235    int k;
2236    unsigned short ffolat, ivo;
2237    int base_v_total, range, v_offset;
2238    int v_total_min, v_total_max, v_step;
2239    float r, f;
2240    int vga_pixels, pre_pixels;
2241    float hscale, hscale_min, hscale_max;
2242    int hsc;
2243    int iho, iho_max, ihw;
2244
2245    /*tv_std is valid. */
2246    k = map_tvstd_to_index(tv_std);
2247
2248    /*store tv width and lines */
2249    g_specs.tv_width = tvsetup.tv_width[k];
2250    g_specs.tv_lines = tvsetup.tv_lines[k];
2251
2252    /*determine vga mode index */
2253    for (vga_index = 0; vga_index < SCANTABLE_ENTRIES; vga_index++) {
2254        if (scantable[vga_index].mode == vga_mode)
2255            break;
2256    }
2257    if (vga_index >= SCANTABLE_ENTRIES)
2258        return;
2259
2260    /*vertical scaling (v_total setup). */
2261    /*calculate vertical range. */
2262    get_vtotal_min_max(vga_mode, tv_std, &v_total_min, &v_total_max, &v_step);
2263    TRACE(("v_total min=%d, max=%d\n", v_total_min, v_total_max))
2264        base_v_total = scantable[vga_index].v_total[k];
2265    range = fsmax(base_v_total - v_total_min, v_total_max - base_v_total);
2266    TRACE(("v_total range = %d\n", range))
2267
2268        /*map +/-1000 overscan y into +/-range. */
2269        v_offset = (int)((((float)overscan_y * range) / 1000.f) + .5f);
2270    TRACE(("v_offset = %d\n", v_offset))
2271
2272        /*range limit v_total. */
2273        g_specs.v_total =
2274        range_limit(base_v_total + v_offset, v_total_min, v_total_max);
2275
2276    /*round to calibrated value. */
2277    v_offset = (g_specs.v_total - v_total_min + (v_step / 2)) / v_step;
2278    g_specs.v_total = v_total_min + v_offset * v_step;
2279    TRACE(("desired v_total=%d\n", g_specs.v_total))
2280
2281        /*vertical positioning (vsync setup). */
2282        get_ffolat_ivo(vga_mode, tv_std, v_offset, &ffolat, &ivo);
2283    houston_WriteReg(HOUSTON_IVO, ivo, 2);
2284
2285    /*scale base sync offset by scaling ratio. */
2286    r = (float)g_specs.v_total / (float)base_v_total;
2287    v_offset = (int)(r * (float)scantable[vga_index].v_sync[k]);
2288
2289    /*scale ivo. */
2290    f = (float)ivo;
2291    v_offset -= (int)(f - f / r);
2292
2293    /*compensate for center screen. */
2294    f = (float)tvsetup.tv_active_lines[k] / 2.f;
2295    v_offset += (int)(f * r - f);
2296
2297    /*calculate vsync. */
2298    g_specs.v_sync = g_specs.v_total - v_offset + pos_y;
2299    TRACE(("desired v_total=%d, desired v_sync=%d\n", g_specs.v_total,
2300            g_specs.v_sync))
2301        if (g_specs.v_sync < g_specs.vga_lines + 10) {
2302        TRACE(("vsync too low\n"))
2303            /*d.v_total += d.vga_lines+10-d.v_sync; */
2304            g_specs.v_sync = g_specs.vga_lines + 10;
2305    } else if (g_specs.v_sync > g_specs.v_total - 10) {
2306        TRACE(("vsync too high\n"))
2307            g_specs.v_sync = g_specs.v_total - 10;
2308    }
2309    TRACE(("v_total=%d v_sync=%d\n", g_specs.v_total, g_specs.v_sync))
2310
2311        /* FFOLAT. */
2312        houston_WriteReg(HOUSTON_FFO_LAT, ffolat, 2);
2313
2314    /* VSC. */
2315    vsc =
2316        (65536.0f * (1.0f -
2317            (double)g_specs.tv_lines / (double)g_specs.v_total)) + 0.5f;
2318    reg = ((unsigned long)-vsc) & 0xffff;
2319    TRACE(("vsc=%04x, tv_lines=%d, v_total=%d\n", reg, g_specs.tv_lines,
2320            g_specs.v_total))
2321        houston_WriteReg(HOUSTON_VSC, (int)reg, 2);
2322
2323    /* horizontal scaling. */
2324
2325    /* vga pixels is vga width, except in 1024x768, where it's half that. */
2326    vga_pixels = g_specs.vga_width;
2327    if (1024 == vga_pixels)
2328        vga_pixels /= 2;
2329
2330    /* maximum scaling coefficient is tv_width / vga_pixels */
2331    /* minimum is about 1/2, but that is quite small.  arbitrarily set
2332     * minimum at 75% maximum. */
2333    hscale_max = (720.0f / vga_pixels);
2334    hscale_min = fsmax((0.75f * hscale_max), (1.0f - (63.0f / 128.0f)));
2335    TRACE(("hscale_min = %u.%u, hscale_max = %u.%u\n",
2336            (int)hscale_min,
2337            (int)((hscale_min - (int)hscale_min) * 1000),
2338            (int)hscale_max, (int)((hscale_max - (int)hscale_max) * 1000)))
2339
2340        /* map overscan_x into min to max. */
2341        hscale =
2342        hscale_min + ((overscan_x + 1000.0f) / 2000.0f) * (hscale_max -
2343        hscale_min);
2344    TRACE(("hscale = %u.%u\n", (int)hscale,
2345            (int)((hscale - (int)hscale) * 1000)))
2346
2347        /* determine hsc where hscale = (1 + hsc/128) */
2348        if (hscale >= 1.0f)
2349        hsc = (int)(128.f * (hscale - 1.0f) + .5f);
2350    else
2351        hsc = (int)(128.f * (hscale - 1.0f) - .5f);
2352
2353    TRACE(("hsc = %d\n", hsc))
2354        if (hsc >= 0)
2355        houston_WriteReg(HOUSTON_HSC, hsc << 8, 2);
2356    else
2357        houston_WriteReg(HOUSTON_HSC, hsc & 0xFF, 2);
2358
2359    /* recalculate hscale for future formulas */
2360    hscale = 1.0f + (hsc / 128.0f);
2361    TRACE(("recalculated hscale = %u.%u\n", (int)hscale,
2362            (int)((hscale - (int)hscale) * 1000)))
2363
2364        /* horizontal offset. */
2365        /* place hsync 40 before halfway from vga_width to htotal */
2366        /* but not less than vga_width + 10 */
2367        g_specs.h_sync =
2368        fsmax((g_specs.h_total + g_specs.vga_width) / 2 - 40,
2369        g_specs.vga_width + 10);
2370    /* also, make it even */
2371    g_specs.h_sync &= ~1;
2372    TRACE(("hsync = %u\n", g_specs.h_sync))
2373
2374        /* iho range is 0 to iho_max. */
2375        /* iho_max is 2 * iho_center. */
2376        /* iho_center is pre_pixels - (tvwidth / hscale - vga pixels) / 2. */
2377        /* pre_pixels = (htotal - hsync) * (vga_pixels / vga_width) */
2378        /* note that the range is inverted also, because it specifies the number
2379         * of pixels */
2380        /* to skip, or subtract.  iho=0 maps to farthest right. */
2381        /* map -pos_x = +/-1000 into (0 to iho_max) */
2382        pre_pixels =
2383        (int)((long)(g_specs.h_total -
2384            g_specs.h_sync) * vga_pixels / g_specs.vga_width);
2385    iho_max = (2 * pre_pixels) - ((int)(720.0f / hscale + 0.5f) - vga_pixels);
2386    TRACE(("iho_max = %u\n", iho_max))
2387        iho =
2388        (int)range_limit(((long)(1000 - pos_x) * iho_max / 2000) +
2389        scantable[vga_index].iho[k], 0, iho_max);
2390    TRACE(("iho = %u\n", iho))
2391        houston_WriteReg(HOUSTON_IHO, iho, 2);
2392
2393    /* input horizontal width. */
2394
2395    /* input horizontal width is vga pixels + pre_pixels - iho */
2396    /* additionally, ihw cannot exceed tv width / hscale */
2397    /* and if hsc is negative, (ihw)(-hsc/128) cannot exceed ~250. */
2398    /* and ihw should be even. */
2399    ihw = fsmin(vga_pixels + pre_pixels - iho, (int)(720.0f / hscale));
2400    if (hsc < 0)
2401        ihw = (int)fsmin(ihw, 253L * 128 / (-hsc));
2402    ihw &= ~1;
2403    TRACE(("ihw = %u\n", ihw))
2404        houston_WriteReg(HOUSTON_IHA, ihw, 2);
2405
2406    f = (((float)g_specs.h_total * g_specs.v_total) * 27.f) /
2407        ((float)g_specs.tv_width * g_specs.tv_lines);
2408
2409    TRACE(("freq=%u.%uMHz\n", (int)f, (int)((f - (int)f) * 1000)))
2410}
2411
2412/*==========================================================================*/
2413/* configure houston nco.													*/
2414/*==========================================================================*/
2415
2416static void
2417config_nco(unsigned long tv_std, unsigned long vga_mode)
2418{
2419    unsigned long cr, misc;
2420    unsigned long reg;
2421    int k = map_tvstd_to_index(tv_std);
2422
2423    /*read and store CR. */
2424    houston_ReadReg(HOUSTON_CR, &cr, 2);
2425
2426    /*make sure NCO_EN (enable latch) bit is clear */
2427    cr &= ~CR_NCO_EN;
2428    houston_WriteReg(HOUSTON_CR, cr, 2);
2429
2430    /*clear NCO_LOADX. */
2431    houston_ReadReg(HOUSTON_MISC, &misc, 2);
2432    misc &= ~(MISC_NCO_LOAD1 + MISC_NCO_LOAD0);
2433    houston_WriteReg(HOUSTON_MISC, misc, 2);
2434
2435    if (vga_mode == GFX_VGA_MODE_1024X768) {
2436        /*setup for M and N load (Nco_load=1). */
2437        misc |= (MISC_NCO_LOAD0);
2438        houston_WriteReg(HOUSTON_MISC, misc, 2);
2439
2440        /*M and N. */
2441        houston_WriteReg(HOUSTON_NCONL, 1024 - 2, 2);
2442        houston_WriteReg(HOUSTON_NCODL, 128 - 1, 2);
2443
2444        /*latch M/N in. */
2445        cr |= CR_NCO_EN;
2446        houston_WriteReg(HOUSTON_CR, cr, 2);
2447        cr &= ~CR_NCO_EN;
2448        houston_WriteReg(HOUSTON_CR, cr, 2);
2449
2450        /*setup ncon and ncod load (Nco_load=0). */
2451        misc &= ~(MISC_NCO_LOAD1 + MISC_NCO_LOAD0);
2452        houston_WriteReg(HOUSTON_MISC, misc, 2);
2453
2454        /*NCON. */
2455        reg = ((unsigned long)g_specs.v_total * g_specs.h_total) / 2;
2456        houston_WriteReg(HOUSTON_NCONH, reg >> 16, 2);
2457        houston_WriteReg(HOUSTON_NCONL, reg & 0xffff, 2);
2458
2459        /*NCOD. */
2460        houston_WriteReg(HOUSTON_NCODL, tvsetup.houston_ncodl[k], 2);
2461        houston_WriteReg(HOUSTON_NCODH, tvsetup.houston_ncodh[k], 2);
2462    } else {
2463        /*setup for M and N load (Nco_load=2). */
2464        misc |= (MISC_NCO_LOAD1);
2465        houston_WriteReg(HOUSTON_MISC, misc, 2);
2466
2467        /*NCON. */
2468        reg = (unsigned long)g_specs.v_total * g_specs.h_total;
2469        houston_WriteReg(HOUSTON_NCONH, reg >> 16, 2);
2470        houston_WriteReg(HOUSTON_NCONL, reg & 0xffff, 2);
2471
2472        /*NCOD. */
2473        houston_WriteReg(HOUSTON_NCODL, tvsetup.houston_ncodl[k], 2);
2474        houston_WriteReg(HOUSTON_NCODH, tvsetup.houston_ncodh[k], 2);
2475
2476        TRACE(("NCON = %lu (0x%08lx), NCOD = %lu (0x%08lx)\n",
2477                reg,
2478                reg,
2479                ((unsigned long)tvsetup.houston_ncodh[k] << 16) +
2480                tvsetup.houston_ncodl[k],
2481                ((unsigned long)tvsetup.houston_ncodh[k] << 16) +
2482                tvsetup.houston_ncodl[k]))
2483    }
2484
2485    /*latch M/N and NCON/NCOD in. */
2486    cr |= CR_NCO_EN;
2487    houston_WriteReg(HOUSTON_CR, cr, 2);
2488    cr &= ~CR_NCO_EN;
2489    houston_WriteReg(HOUSTON_CR, cr, 2);
2490}
2491
2492/*==========================================================================*/
2493/* Write sharpness settings to device										*/
2494/*==========================================================================*/
2495
2496static void
2497config_sharpness(int sharpness)
2498{
2499    unsigned int shp;
2500
2501    /*map 0-1000 to 0-20. */
2502    shp = (unsigned int)(0.5f + ((float)sharpness * 20.0f / 1000.0f));
2503    shp = range_limit(shp, 0, 20);
2504
2505    houston_WriteReg(HOUSTON_SHP, shp, 2);
2506}
2507
2508static void
2509conget_sharpness(int *p_sharpness)
2510{
2511    unsigned long shp;
2512
2513    if (!p_sharpness)
2514        return;
2515
2516    houston_ReadReg(HOUSTON_SHP, &shp, 2);
2517
2518    /*map 0-20 to 0-1000. */
2519    *p_sharpness = (int)(0.5f + ((float)shp * 1000.0f / 20.0f));
2520}
2521
2522/*==========================================================================*/
2523/* Write flicker settings to device											*/
2524/*==========================================================================*/
2525
2526static void
2527config_flicker(int flicker)
2528{
2529    unsigned int flk;
2530
2531    /*map 0-1000 to 0-16. */
2532    flk = (unsigned int)(0.5f + ((float)flicker * 16.0f / 1000.0f));
2533    flk = range_limit(flk, 0, 16);
2534
2535    houston_WriteReg(HOUSTON_FLK, flk, 2);
2536}
2537
2538static void
2539conget_flicker(int *p_flicker)
2540{
2541    unsigned long flk;
2542
2543    if (!p_flicker)
2544        return;
2545
2546    houston_ReadReg(HOUSTON_FLK, &flk, 2);
2547
2548    /*map 0-16 to 0-1000. */
2549    *p_flicker = (int)(0.5f + ((float)flk * 1000.0f / 16.0f));
2550}
2551
2552/*==========================================================================*/
2553/* Write color settings to device											*/
2554/*==========================================================================*/
2555
2556static void
2557config_color(int color)
2558{
2559    unsigned long clr;
2560
2561    /*map 0-100 to 0-255. */
2562    /*montreal production test needs 169 to be mappable, so */
2563    /*use .8 rounding factor, 169=(int)(66.*2.55+.8). */
2564    clr = (unsigned long)(0.8f + ((float)color * 255.0f / 100.0f));
2565    clr = range_limit(clr, 0, 255);
2566
2567    houston_WriteReg(ENC_CR_GAIN, clr, 1);
2568    houston_WriteReg(ENC_CB_GAIN, clr, 1);
2569}
2570
2571static void
2572conget_color(int *p_color)
2573{
2574    unsigned long cr_gain;
2575
2576    if (!p_color)
2577        return;
2578
2579    /*just get CR GAIN, CB GAIN should match. */
2580    houston_ReadReg(ENC_CR_GAIN, &cr_gain, 1);
2581
2582    /*map 0-255 to 0-100. */
2583    *p_color = (int)(0.5f + ((float)cr_gain * 100.0f / 255.0f));
2584}
2585
2586/*==========================================================================*/
2587/* Write brightness and contrast settings to device							*/
2588/*==========================================================================*/
2589
2590#define	NTSC_BLANK_LEVEL	240
2591
2592static const int min_black_level = NTSC_BLANK_LEVEL + 1;
2593static const int max_white_level = 1023;
2594
2595static void
2596config_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits,
2597    int brightness, int contrast)
2598{
2599    int brightness_off;
2600    float contrast_mult;
2601    int black, white;
2602    unsigned short w;
2603    int k = map_tvstd_to_index(tv_std);
2604
2605    /*0-100 maps to +/-220. */
2606    brightness_off =
2607        (int)(0.5f + ((float)brightness * 440.0f / 100.0f)) - 220;
2608
2609    /*0-100 maps to .75-1.25. */
2610    contrast_mult = ((float)contrast * 0.5f / 100.0f) + 0.75f;
2611
2612    black = tvsetup.black_level[k];
2613    if (trigger_bits != 0)
2614        black -= tvsetup.hamp_offset[k];
2615
2616    white = tvsetup.white_level[k];
2617    if (trigger_bits != 0)
2618        white -= tvsetup.hamp_offset[k];
2619
2620    black = (int)((float)(black + brightness_off) * contrast_mult);
2621    white = (int)((float)(white + brightness_off) * contrast_mult);
2622    if (black < min_black_level)
2623        black = min_black_level;
2624    if (white > max_white_level)
2625        white = max_white_level;
2626
2627    w = w10bit2z((unsigned short)black);
2628    houston_WriteReg(ENC_BLACK_LEVEL, w & 0x00ff, 1);
2629    houston_WriteReg(ENC_BLACK_LEVEL + 1, w >> 8, 1);
2630    w = w10bit2z((unsigned short)white);
2631    houston_WriteReg(ENC_WHITE_LEVEL, w & 0x00ff, 1);
2632    houston_WriteReg(ENC_WHITE_LEVEL + 1, w >> 8, 1);
2633}
2634
2635static void
2636conget_brightness_contrast(unsigned long tv_std, unsigned int trigger_bits,
2637    int *p_brightness, int *p_contrast)
2638{
2639    int brightness_off;
2640    float contrast_mult;
2641    unsigned short black, white;
2642    unsigned long zh, zl;
2643    int k;
2644
2645    if (!p_brightness || !p_contrast)
2646        return;
2647
2648    k = map_tvstd_to_index(tv_std);
2649
2650    houston_ReadReg(ENC_BLACK_LEVEL, &zl, 1);
2651    houston_ReadReg(ENC_BLACK_LEVEL + 1, &zh, 1);
2652    black = z2w10bit((unsigned short)(zl + (zh << 8)));
2653    if (trigger_bits != 0)
2654        black += tvsetup.hamp_offset[k];
2655    houston_ReadReg(ENC_WHITE_LEVEL, &zl, 1);
2656    houston_ReadReg(ENC_WHITE_LEVEL + 1, &zh, 1);
2657    white = z2w10bit((unsigned short)(zl + (zh << 8)));
2658    if (trigger_bits != 0)
2659        white += tvsetup.hamp_offset[k];
2660
2661    /*this reverse computation does not account for clipping, but should */
2662    /*provide somewhat reasonable numbers */
2663    contrast_mult =
2664        ((float)white - (float)black) / ((float)tvsetup.white_level[k] -
2665        (float)tvsetup.black_level[k]);
2666    brightness_off =
2667        (int)(((float)black / contrast_mult) - tvsetup.black_level[k]);
2668
2669    /*+/-220 maps to 0-100. */
2670    *p_brightness =
2671        range_limit((int)(0.5f + ((float)(brightness_off +
2672                    220) * 100.0f / 440.0f)), 0, 100);
2673
2674    /*.75-1.25 maps to 0-100. */
2675    *p_contrast =
2676        range_limit((int)(0.5f + ((float)(contrast_mult -
2677                    0.75f) * 100.0f / 0.5f)), 0, 100);
2678}
2679
2680/*==========================================================================*/
2681/* configure luma/chroma filters.											*/
2682/*==========================================================================*/
2683
2684static void
2685config_yc_filter(unsigned long tv_std, int luma_filter, int chroma_filter)
2686{
2687    unsigned long reg, reg07, reg34;
2688
2689    if (houston_Rev() < HOUSTON_REV_B)
2690        return;
2691
2692    /*luma filter. */
2693    if (luma_filter)
2694        reg = tvsetup.notch_filter[map_tvstd_to_index(tv_std)];
2695    else
2696        reg = 0;
2697    houston_WriteReg(ENC_NOTCH_FILTER, reg, 1);
2698
2699    /*chroma filter. */
2700    houston_ReadReg(ENC_REG07, &reg07, 1);
2701    houston_ReadReg(ENC_REG34, &reg34, 1);
2702    if (chroma_filter) {
2703        reg07 &= ~0x08;
2704        reg34 &= ~0x20;
2705    } else {
2706        reg07 |= 0x08;
2707        reg34 |= 0x20;
2708    }
2709    houston_WriteReg(ENC_REG07, reg07, 1);
2710    houston_WriteReg(ENC_REG34, reg34, 1);
2711}
2712
2713static void
2714conget_yc_filter(int *p_luma_filter, int *p_chroma_filter)
2715{
2716    unsigned long reg, reg07, reg34;
2717
2718    if (!p_luma_filter || !p_chroma_filter)
2719        return;
2720
2721    if (houston_Rev() < HOUSTON_REV_B) {
2722        *p_luma_filter = 0;
2723        *p_chroma_filter = 0;
2724        return;
2725    }
2726
2727    /*luma filter. */
2728    houston_ReadReg(ENC_NOTCH_FILTER, &reg, 1);
2729    *p_luma_filter = (reg ? 1 : 0);
2730
2731    /*chroma filter. */
2732    houston_ReadReg(ENC_REG07, &reg07, 1);
2733    houston_ReadReg(ENC_REG34, &reg34, 1);
2734    *p_chroma_filter = !((0x08 & reg07) || (0x20 & reg34));
2735}
2736
2737/*==========================================================================*/
2738/* Macrovision																*/
2739/*==========================================================================*/
2740
2741static void
2742config_macrovision(unsigned long tv_std, unsigned int trigger_bits)
2743{
2744/*Constants to index into mvsetup columns.*/
2745#define	nNTSC_APS00		0      /*ntsc mv off.                   */
2746#define	nNTSC_APS01		1      /*ntsc AGC only.                 */
2747#define	nNTSC_APS10		2      /*ntsc AGC + 2-line CS.  */
2748#define	nNTSC_APS11		3      /*ntsc AGC + 4-line CS.  */
2749#define	nPAL_APS00		4      /*pal mv off.                    */
2750#define	nPAL_APSXX		5      /*pal mv on.                     */
2751#define	nMVModes		6
2752
2753    /*Macrovision setup table. */
2754    static const struct mvparms
2755    {
2756        unsigned short n0[nMVModes];
2757        unsigned short n1[nMVModes];
2758        unsigned short n2[nMVModes];
2759        unsigned short n3[nMVModes];
2760        unsigned short n4[nMVModes];
2761        unsigned short n5[nMVModes];
2762        unsigned short n6[nMVModes];
2763        unsigned short n7[nMVModes];
2764        unsigned short n8[nMVModes];
2765        unsigned short n9[nMVModes];
2766        unsigned short n10[nMVModes];
2767        unsigned short n11[nMVModes];
2768        unsigned short n12[nMVModes];
2769        unsigned short n13[nMVModes];
2770        unsigned short n14[nMVModes];
2771        unsigned short n15[nMVModes];
2772        unsigned short n16[nMVModes];
2773        unsigned short n17[nMVModes];
2774        unsigned short n18[nMVModes];
2775        unsigned short n19[nMVModes];
2776        unsigned short n20[nMVModes];
2777        unsigned short n21[nMVModes];
2778        unsigned short n22[nMVModes];
2779        unsigned short agc_pulse_level[nMVModes];
2780        unsigned short bp_pulse_level[nMVModes];
2781    }
2782
2783    mvsetup = {
2784        /*    ntsc    ntsc    ntsc    ntsc    pal             pal */
2785        /*    MV      AGC     AGC +   AGC +   MV              MV */
2786        /*    off.    only    2-line  4-line  off.    on. */
2787        /*    CS.             CS. */
2788        {
2789        0x00, 0x36, 0x3e, 0x3e, 0x00, 0x3e},    /*n0 */
2790        {
2791        0x1d, 0x1d, 0x1d, 0x17, 0x1a, 0x1a},    /*n1 */
2792        {
2793        0x11, 0x11, 0x11, 0x15, 0x22, 0x22},    /*n2 */
2794        {
2795        0x25, 0x25, 0x25, 0x21, 0x2a, 0x2a},    /*n3 */
2796        {
2797        0x11, 0x11, 0x11, 0x15, 0x22, 0x22},    /*n4 */
2798        {
2799        0x01, 0x01, 0x01, 0x05, 0x05, 0x05},    /*n5 */
2800        {
2801        0x07, 0x07, 0x07, 0x05, 0x02, 0x02},    /*n6 */
2802        {
2803        0x00, 0x00, 0x00, 0x02, 0x00, 0x00},    /*n7 */
2804        {
2805        0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c},    /*n8 */
2806        {
2807        0x1b, 0x1b, 0x1b, 0x1b, 0x3d, 0x3d},    /*n9 */
2808        {
2809        0x24, 0x24, 0x24, 0x24, 0x14, 0x14},    /*n10 */
2810        {
2811        0x780f, 0x780f, 0x780f, 0x780f, 0x7e07, 0x7e07},        /*n11 */
2812        {
2813        0x0000, 0x0000, 0x0000, 0x0000, 0x5402, 0x5402},        /*n12 */
2814        {
2815        0x0f, 0x0f, 0x0f, 0x0f, 0xfe, 0xfe},    /*n13 */
2816        {
2817        0x0f, 0x0f, 0x0f, 0x0f, 0x7e, 0x7e},    /*n14 */
2818        {
2819        0x60, 0x60, 0x60, 0x60, 0x60, 0x60},    /*n15 */
2820        {
2821        0x01, 0x01, 0x01, 0x01, 0x00, 0x00},    /*n16 */
2822        {
2823        0x0a, 0x0a, 0x0a, 0x0a, 0x08, 0x08},    /*n17 */
2824        {
2825        0x00, 0x00, 0x00, 0x00, 0x00, 0x00},    /*n18 */
2826        {
2827        0x05, 0x05, 0x05, 0x05, 0x04, 0x04},    /*n19 */
2828        {
2829        0x04, 0x04, 0x04, 0x04, 0x07, 0x07},    /*n20 */
2830        {
2831        0x03ff, 0x03ff, 0x03ff, 0x03ff, 0x0155, 0x0155},        /*n21 */
2832        {
2833        0x00, 0x00, 0x00, 0x00, 0x00, 0x00},    /*n22 */
2834        {
2835        0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3},    /*agc_pulse_level */
2836        {
2837        0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8},    /*bp_pulse_level */
2838    };
2839
2840    int nMode;
2841    unsigned long misc;
2842    unsigned short n0;
2843
2844    trigger_bits &= 0x3;
2845
2846    /*Determine the OEM Macrovision Program Mode and Register 0 Data. */
2847    if (IS_NTSC(tv_std)) {
2848        /*NTSC TV Standard. */
2849        if (trigger_bits == 0) {
2850            /*turn Macrovision OFF. */
2851            nMode = nNTSC_APS00;
2852        } else if (trigger_bits == 1) {
2853            /*AGC Only. */
2854            nMode = nNTSC_APS01;
2855        } else if (trigger_bits == 2) {
2856            /*AGC + 2-line CS. */
2857            nMode = nNTSC_APS10;
2858        } else {
2859            /*AGC + 4-line CS. */
2860            nMode = nNTSC_APS11;
2861        }
2862    } else {
2863        /*PAL TV Standard. */
2864        if (trigger_bits == 0) {
2865            /*turn Macrovision OFF. */
2866            nMode = nPAL_APS00;
2867        } else {
2868            /*APS 01, 10, or 11. */
2869            nMode = nPAL_APSXX;
2870        }
2871    }
2872
2873    /*Retrieve the Macrovision Program Mode Data */
2874    if (tv_std != GFX_TV_STANDARD_PAL_M)
2875        n0 = mvsetup.n0[nMode];
2876    else {
2877        /*PAL-M sets up like NTSC except for n0. */
2878        if ((trigger_bits & 0x03) == 0)
2879            n0 = mvsetup.n0[nPAL_APS00];
2880        else
2881            n0 = mvsetup.n0[nPAL_APSXX];
2882    }
2883
2884    /*download settings now. */
2885    houston_WriteReg(MV_N0, n0, 1);
2886    houston_WriteReg(MV_N1, mvsetup.n1[nMode], 1);
2887    houston_WriteReg(MV_N2, mvsetup.n2[nMode], 1);
2888    houston_WriteReg(MV_N3, mvsetup.n3[nMode], 1);
2889    houston_WriteReg(MV_N4, mvsetup.n4[nMode], 1);
2890    houston_WriteReg(MV_N5, mvsetup.n5[nMode], 1);
2891    houston_WriteReg(MV_N6, mvsetup.n6[nMode], 1);
2892    houston_WriteReg(MV_N7, mvsetup.n7[nMode], 1);
2893    houston_WriteReg(MV_N8, mvsetup.n8[nMode], 1);
2894    houston_WriteReg(MV_N9, mvsetup.n9[nMode], 1);
2895    houston_WriteReg(MV_N10, mvsetup.n10[nMode], 1);
2896    houston_WriteReg(MV_N11, mvsetup.n11[nMode] & 0xff, 1);
2897    houston_WriteReg(MV_N11 + 1, mvsetup.n11[nMode] >> 8, 1);
2898    houston_WriteReg(MV_N12, mvsetup.n12[nMode] & 0xff, 1);
2899    houston_WriteReg(MV_N12 + 1, mvsetup.n12[nMode] >> 8, 1);
2900    houston_WriteReg(MV_N13, mvsetup.n13[nMode], 1);
2901    houston_WriteReg(MV_N14, mvsetup.n14[nMode], 1);
2902    houston_WriteReg(MV_N15, mvsetup.n15[nMode], 1);
2903    houston_WriteReg(MV_N16, mvsetup.n16[nMode], 1);
2904    houston_WriteReg(MV_N17, mvsetup.n17[nMode], 1);
2905    houston_WriteReg(MV_N18, mvsetup.n18[nMode], 1);
2906    houston_WriteReg(MV_N19, mvsetup.n19[nMode], 1);
2907    houston_WriteReg(MV_N20, mvsetup.n20[nMode], 1);
2908    houston_WriteReg(MV_N21, mvsetup.n21[nMode] & 0xff, 1);
2909    houston_WriteReg(MV_N21 + 1, mvsetup.n21[nMode] >> 8, 1);
2910    houston_WriteReg(MV_N22, mvsetup.n22[nMode], 1);
2911    houston_WriteReg(MV_AGC_PULSE_LEVEL, mvsetup.agc_pulse_level[nMode], 1);
2912    houston_WriteReg(MV_BP_PULSE_LEVEL, mvsetup.bp_pulse_level[nMode], 1);
2913
2914    houston_ReadReg(HOUSTON_MISC, &misc, 2);
2915    if (trigger_bits == 0)
2916        misc &= ~MISC_MV_SOFT_EN;
2917    else
2918        misc |= MISC_MV_SOFT_EN;
2919    houston_WriteReg(HOUSTON_MISC, misc, 2);
2920}
2921
2922static void
2923conget_macrovision(unsigned long tv_std, unsigned int *p_cp_trigger_bits)
2924{
2925    unsigned long n0, n1;
2926
2927    if (!p_cp_trigger_bits)
2928        return;
2929
2930    houston_ReadReg(MV_N0, &n0, 1);
2931    houston_ReadReg(MV_N1, &n1, 1);
2932
2933    *p_cp_trigger_bits = 0;
2934
2935    if (IS_NTSC(tv_std)) {
2936        switch (n0) {
2937        case 0:
2938            *p_cp_trigger_bits = 0;
2939            break;
2940
2941        case 0x36:
2942            *p_cp_trigger_bits = 1;
2943            break;
2944
2945        case 0x3E:
2946            {
2947                if (0x1D == n1)
2948                    *p_cp_trigger_bits = 2;
2949                else
2950                    *p_cp_trigger_bits = 3;
2951            }
2952            break;
2953        }
2954    } else if (IS_PAL(tv_std)) {
2955        if (0 == n0)
2956            *p_cp_trigger_bits = 0;
2957        else {
2958            /*don't know here what the non-zero trigger bits were */
2959            *p_cp_trigger_bits = 1;
2960        }
2961    }
2962}
2963
2964/* PLAL_MediaGX.cpp															*/
2965/*==========================================================================*/
2966/* These functions provides implementation of platform-specific functions	*/
2967/* MediaGX platform.														*/
2968/*==========================================================================*/
2969
2970/*MediaGX control registers.*/
2971#define CCR3	0xC3
2972#define	GCR		0xb8
2973
2974/*Media GX general config register.*/
2975#define	GX_DCLK_MUL			0x00c0
2976#define	GX_DCLKx1			0x0040
2977#define	GX_DCLKx2			0x0080
2978#define GX_DCLKx4			0x00c0
2979
2980/*Media GX timing config register.*/
2981#define	GX_TGEN				0x0020
2982
2983/*Cx5530 register offsets (from GX_BASE).*/
2984#define	CX_DISPLAY_CONFIG	0x10004
2985#define	CX_DOT_CLK			0x10024
2986#define	CX_TV_CONFIG		0x10028
2987
2988/*Cx5530 display configuration register.*/
2989#define	CX_FPVSYNC_POL		0x0800
2990#define	CX_FPHSYNC_POL		0x0400
2991#define	CX_FPDATA_ENB		0x0080
2992#define	CX_FPPOWER_ENB		0x0040
2993#define CX_CRTVSYNC_POL		0x0200
2994#define CX_CRTHSYNC_POL		0x0100
2995
2996/*Cx5530 dot clock configuration register.*/
2997#define	CX_TVCLK_SELECT		0x0400
2998
2999/*Cx5530 tv configuration register*/
3000#define CX_INVERT_FPCLK (1 << 6)
3001
3002/*==========================================================================
3003 *	FS450 I2C Address
3004 *	There are two possible 7-bit addresses, 0x4A and 0x6A.
3005 *	The address if selectable via pins on the FS450.
3006 *	There are also two possible 10-bit addresses, 0x224 and 0x276, but this
3007 *	source is not designed to use them.
3008 *==========================================================================*/
3009
3010#define	FS450_I2C_ADDRESS (0x4A)
3011
3012static unsigned char
3013PLAL_FS450_i2c_address(void)
3014{
3015    return FS450_I2C_ADDRESS;
3016}
3017
3018/*==========================================================================
3019 *	FS450 UIM mode
3020 *	This mode is programmed in the FS450 command register when enabling TV
3021 *	out.
3022 *==========================================================================
3023 */
3024static int
3025PLAL_FS450_UIM_mode(void)
3026{
3027    return 3;
3028}
3029
3030/*==========================================================================*/
3031/* Read and Write MediaGX registers											*/
3032/*==========================================================================*/
3033static unsigned long
3034ReadGx(unsigned long inRegAddr)
3035{
3036    unsigned long data;
3037
3038    DMAL_ReadUInt32(inRegAddr, &data);
3039
3040    return data;
3041}
3042
3043static void
3044WriteGx(unsigned long inRegAddr, unsigned long inData)
3045{
3046    int is_timing_register;
3047    unsigned long reg_timing_cfg;
3048
3049    /*because the unlock register for the MediaGx video registers may not */
3050    /*persist, we will write the unlock code before every write. */
3051    DMAL_WriteUInt32(DC_UNLOCK, 0x4758);
3052
3053    /*see if register is a timing register */
3054    is_timing_register =
3055        (DC_H_TIMING_1 == inRegAddr) ||
3056        (DC_H_TIMING_2 == inRegAddr) ||
3057        (DC_H_TIMING_3 == inRegAddr) ||
3058        (DC_FP_H_TIMING == inRegAddr) ||
3059        (DC_V_TIMING_1 == inRegAddr) ||
3060        (DC_V_TIMING_2 == inRegAddr) ||
3061        (DC_V_TIMING_3 == inRegAddr) || (DC_FP_V_TIMING == inRegAddr);
3062
3063    /*if the register is a timing register, clear the TGEN bit to allow
3064     * modification */
3065    if (is_timing_register) {
3066        DMAL_ReadUInt32(DC_TIMING_CFG, &reg_timing_cfg);
3067        DMAL_WriteUInt32(DC_TIMING_CFG, reg_timing_cfg & ~GX_TGEN);
3068    }
3069
3070    /*write the requested register */
3071    DMAL_WriteUInt32(inRegAddr, inData);
3072
3073    /*reset the TGEN bit to previous state */
3074    if (is_timing_register) {
3075        DMAL_WriteUInt32(DC_TIMING_CFG, reg_timing_cfg);
3076    }
3077}
3078
3079#ifdef FS450_DIRECTREG
3080
3081/*==========================================================================*/
3082/*	Platform-specific processing for a Read or Write Register calls.		*/
3083/*	The functions should return true if the specified register belongs to	*/
3084/*	this platform.															*/
3085/*==========================================================================*/
3086
3087static int
3088PLAL_ReadRegister(S_REG_INFO * p_reg)
3089{
3090    if (!p_reg)
3091        return 0;
3092
3093    if (SOURCE_GCC == p_reg->source) {
3094        p_reg->value = ReadGx(p_reg->offset);
3095
3096        return 1;
3097    }
3098
3099    return 0;
3100}
3101
3102static int
3103PLAL_WriteRegister(const S_REG_INFO * p_reg)
3104{
3105    if (!p_reg)
3106        return 0;
3107
3108    if (SOURCE_GCC == p_reg->source) {
3109        WriteGx(p_reg->offset, p_reg->value);
3110
3111        return 1;
3112    }
3113
3114    return 0;
3115}
3116
3117#endif
3118
3119/*==========================================================================
3120 *	Determine if TV is on
3121 *==========================================================================*/
3122static int
3123PLAL_IsTVOn(void)
3124{
3125    unsigned long reg;
3126
3127    /*check Cx5530 dot clock */
3128    reg = ReadGx(CX_DOT_CLK);
3129    return (reg & CX_TVCLK_SELECT) ? 1 : 0;
3130}
3131
3132/*==========================================================================
3133 * Platform-specific actions to reset to VGA mode
3134 *==========================================================================*/
3135
3136static int
3137PLAL_EnableVga(void)
3138{
3139    unsigned long reg;
3140
3141    /*2 x dclk */
3142    reg = ReadGx(DC_GENERAL_CFG);
3143    reg &= ~GX_DCLK_MUL;
3144    reg |= GX_DCLKx2;
3145    WriteGx(DC_GENERAL_CFG, reg);
3146
3147    /*select pll dot clock. */
3148    reg = ReadGx(CX_DOT_CLK);
3149    reg &= ~CX_TVCLK_SELECT;
3150    WriteGx(CX_DOT_CLK, reg);
3151
3152    /*timing config, reset everything on dclk. */
3153    reg = ReadGx(DC_TIMING_CFG);
3154    reg &= ~GX_TGEN;
3155    WriteGx(DC_TIMING_CFG, reg);
3156    reg |= GX_TGEN;
3157    WriteGx(DC_TIMING_CFG, reg);
3158
3159    /*un-invert FP clock */
3160    reg = ReadGx(CX_TV_CONFIG);
3161    reg &= ~CX_INVERT_FPCLK;
3162    WriteGx(CX_TV_CONFIG, reg);
3163
3164    return 0;
3165}
3166
3167/*==========================================================================*/
3168/*Platform-specific actions to enter TVout mode								*/
3169/*==========================================================================*/
3170
3171static int
3172PLAL_PrepForTVout(void)
3173{
3174    unsigned int reg;
3175
3176    /*Cx5530 tv config. */
3177    reg = 0;
3178    WriteGx(CX_TV_CONFIG, reg);
3179
3180    /*invert FP clock */
3181    reg = (int)ReadGx(CX_TV_CONFIG);
3182    reg |= CX_INVERT_FPCLK;
3183    WriteGx(CX_TV_CONFIG, reg);
3184
3185    return 0;
3186}
3187
3188static int
3189PLAL_SetTVTimingRegisters(const S_TIMING_SPECS * p_specs)
3190{
3191    unsigned long reg;
3192
3193    /*timing config, reset everything on dclk. */
3194    reg = ReadGx(DC_TIMING_CFG);
3195    reg &= ~GX_TGEN;
3196    WriteGx(DC_TIMING_CFG, reg);
3197
3198    /*htotal and hactive. */
3199    reg = ((p_specs->h_total - 1) << 16) | (p_specs->vga_width - 1);
3200    WriteGx(DC_H_TIMING_1, reg);
3201
3202    /*hblank. */
3203    reg = ((p_specs->h_total - 1) << 16) | (p_specs->vga_width - 1);
3204    WriteGx(DC_H_TIMING_2, reg);
3205
3206    /*hsync. */
3207    reg = ((p_specs->h_sync + 63) << 16) | p_specs->h_sync;
3208    WriteGx(DC_H_TIMING_3, reg);
3209
3210    /*fp hsync. */
3211    WriteGx(DC_FP_H_TIMING, reg);
3212
3213    /*vtotal and vactive. */
3214    reg = ((p_specs->v_total - 1) << 16) | (p_specs->vga_lines - 1);
3215    WriteGx(DC_V_TIMING_1, reg);
3216
3217    /*vblank. */
3218    reg = ((p_specs->v_total - 1) << 16) | (p_specs->vga_lines - 1);
3219    WriteGx(DC_V_TIMING_2, reg);
3220
3221    /*vsync. */
3222    reg = ((p_specs->v_sync) << 16) | (p_specs->v_sync - 1);
3223    WriteGx(DC_V_TIMING_3, reg);
3224
3225    /*fp vsync. */
3226    reg = ((p_specs->v_sync - 1) << 16) | (p_specs->v_sync - 2);
3227    WriteGx(DC_FP_V_TIMING, reg);
3228
3229    /*timing config, reenable all dclk stuff. */
3230    reg = ReadGx(DC_TIMING_CFG);
3231    reg |= GX_TGEN;
3232    WriteGx(DC_TIMING_CFG, reg);
3233
3234    return 0;
3235}
3236
3237static int
3238PLAL_FinalEnableTVout(unsigned long vga_mode)
3239{
3240    unsigned int reg;
3241
3242    /*Cx5530 select tv dot clock. */
3243    reg = (int)ReadGx(CX_DOT_CLK);
3244    reg |= CX_TVCLK_SELECT;
3245    WriteGx(CX_DOT_CLK, reg);
3246
3247    /*2 x dclk (actually 1x) */
3248    reg = (int)ReadGx(DC_GENERAL_CFG);
3249    reg &= ~GX_DCLK_MUL;
3250    WriteGx(DC_GENERAL_CFG, reg);
3251
3252    reg |= GX_DCLKx2;
3253    WriteGx(DC_GENERAL_CFG, reg);
3254
3255    /*Cx5530 display configuration register. */
3256    reg = (int)ReadGx(CX_DISPLAY_CONFIG);
3257    reg |= (CX_FPVSYNC_POL | CX_FPHSYNC_POL | CX_FPDATA_ENB | CX_FPPOWER_ENB);
3258    WriteGx(CX_DISPLAY_CONFIG, reg);
3259
3260    return 0;
3261}
3262