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