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