1/*
2	Copyright (c) 2002/03, Thomas Kurschel
3
4
5	Part of Radeon accelerant
6
7	Programming of internal TV-out unit
8*/
9
10#include "radeon_interface.h"
11#include "radeon_accelerant.h"
12
13#include "tv_out_regs.h"
14#include "pll_access.h"
15#include "mmio.h"
16#include "utils.h"
17#include "set_mode.h"
18
19#include <stdlib.h>
20
21
22// mapping of offset in impactv_regs to register address
23typedef struct register_mapping {
24	uint16		address;			// register address
25	uint16		offset;				// offset in impactv_regs
26} register_mapping;
27
28
29// internal TV-encoder:
30
31// registers to write before programming PLL
32static const register_mapping intern_reg_mapping_before_pll[] = {
33	{ RADEON_TV_MASTER_CNTL,		offsetof( impactv_regs, tv_master_cntl ) },
34	{ RADEON_TV_HRESTART,			offsetof( impactv_regs, tv_hrestart ) },
35	{ RADEON_TV_VRESTART,			offsetof( impactv_regs, tv_vrestart ) },
36	{ RADEON_TV_FRESTART,			offsetof( impactv_regs, tv_frestart ) },
37	{ RADEON_TV_FTOTAL,				offsetof( impactv_regs, tv_ftotal ) },
38	{ 0, 0 }
39};
40
41// PLL registers to program
42static const register_mapping intern_reg_mapping_pll[] = {
43	{ RADEON_TV_PLL_CNTL,			offsetof( impactv_regs, tv_tv_pll_cntl ) },
44	{ RADEON_TV_PLL_CNTL1,			offsetof( impactv_regs, tv_pll_cntl1 ) },
45	{ RADEON_TV_PLL_FINE_CNTL,		offsetof( impactv_regs, tv_pll_fine_cntl ) },
46	{ 0, 0 }
47};
48
49// registers to write after programming of PLL
50static const register_mapping intern_reg_mapping_after_pll[] = {
51	{ RADEON_TV_HTOTAL,				offsetof( impactv_regs, tv_htotal ) },
52	{ RADEON_TV_HDISP,				offsetof( impactv_regs, tv_hdisp ) },
53	{ RADEON_TV_HSTART,				offsetof( impactv_regs, tv_hstart ) },
54	{ RADEON_TV_VTOTAL,				offsetof( impactv_regs, tv_vtotal ) },
55	{ RADEON_TV_VDISP,				offsetof( impactv_regs, tv_vdisp ) },
56
57	{ RADEON_TV_TIMING_CNTL,		offsetof( impactv_regs, tv_timing_cntl ) },
58
59	{ RADEON_TV_VSCALER_CNTL1,		offsetof( impactv_regs, tv_vscaler_cntl1 ) },
60	{ RADEON_TV_VSCALER_CNTL2,		offsetof( impactv_regs, tv_vscaler_cntl2 ) },
61
62	{ RADEON_TV_Y_SAW_TOOTH_CNTL,	offsetof( impactv_regs, tv_y_saw_tooth_cntl ) },
63	{ RADEON_TV_Y_RISE_CNTL,		offsetof( impactv_regs, tv_y_rise_cntl ) },
64	{ RADEON_TV_Y_FALL_CNTL,		offsetof( impactv_regs, tv_y_fall_cntl ) },
65
66	{ RADEON_TV_MODULATOR_CNTL1,	offsetof( impactv_regs, tv_modulator_cntl1 ) },
67	{ RADEON_TV_MODULATOR_CNTL2,	offsetof( impactv_regs, tv_modulator_cntl2 ) },
68	{ RADEON_TV_RGB_CNTL,			offsetof( impactv_regs, tv_rgb_cntl ) },
69	{ RADEON_TV_UV_ADR,				offsetof( impactv_regs, tv_uv_adr ) },
70	{ RADEON_TV_PRE_DAC_MUX_CNTL, 	offsetof( impactv_regs, tv_pre_dac_mux_cntl ) },
71	{ RADEON_TV_CRC_CNTL,			offsetof( impactv_regs, tv_crc_cntl ) },
72	{ 0, 0 }
73};
74
75// registers to write when things settled down
76static const register_mapping intern_reg_mapping_finish[] = {
77	{ RADEON_TV_GAIN_LIMIT_SETTINGS,  offsetof( impactv_regs, tv_gain_limit_settings ) },
78	{ RADEON_TV_LINEAR_GAIN_SETTINGS, offsetof( impactv_regs, tv_linear_gain_settings ) },
79	{ RADEON_TV_UPSAMP_AND_GAIN_CNTL, offsetof( impactv_regs, tv_upsamp_and_gain_cntl ) },
80
81	{ RADEON_TV_DAC_CNTL,			offsetof( impactv_regs, tv_dac_cntl ) },
82	{ RADEON_TV_MASTER_CNTL,		offsetof( impactv_regs, tv_master_cntl ) },
83	{ 0, 0 }
84};
85
86
87
88
89// write list of MM I/O registers
90static void writeMMIORegList(
91	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
92{
93	vuint8 *regs = ai->regs;
94
95	for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
96		/*SHOW_FLOW( 2, "%x=%x", mapping->address,
97			*(uint32 *)((char *)(values) + mapping->offset) );*/
98
99		OUTREG( regs, mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
100	}
101
102	//snooze( 1000000 );
103}
104
105
106// write list of PLL registers
107static void writePLLRegList(
108	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
109{
110	for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
111		/*SHOW_FLOW( 2, "%x=%x", mapping->address,
112			*(uint32 *)((char *)(values) + mapping->offset) );*/
113
114		Radeon_OUTPLL( ai->regs, ai->si->asic,
115			mapping->address, *(uint32 *)((char *)(values) + mapping->offset) );
116	}
117
118	//snooze( 1000000 );
119}
120
121
122
123
124// read timing FIFO
125#if 0
126static uint32 Radeon_InternalTVOutReadFIFO(
127	accelerator_info *ai, uint16 addr )
128{
129	vuint8 *regs = ai->regs;
130	bigtime_t start_time;
131	uint32 res = ~0;
132
133	//SHOW_FLOW( 2, "addr=%d", addr );
134
135	OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_RD);
136
137	start_time = system_time();
138
139	do {
140		uint32 status;
141
142		status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL );
143
144		if( (status & RADEON_TV_HOST_RD_WT_CNTL_RD_ACK) != 0 )
145			break;
146	} while( system_time() - start_time < 2000000 );
147
148	OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0);
149	res = INREG( regs, RADEON_TV_HOST_READ_DATA );
150
151	//SHOW_FLOW( 2, "res=%x %x", res >> 14, res & 0x3fff );
152
153	return res;
154}
155#endif
156
157// write to timing FIFO
158static void Radeon_InternalTVOutWriteFIFO(
159	accelerator_info *ai, uint16 addr, uint32 value )
160{
161	vuint8 *regs = ai->regs;
162	bigtime_t start_time;
163
164	//readFIFO( ai, addr, internal_encoder );
165
166	//SHOW_FLOW( 2, "addr=%d, value=%x %x", addr, value >> 14, value & 0x3fff );
167
168	OUTREG( regs, RADEON_TV_HOST_WRITE_DATA, value );
169	OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_TV_HOST_RD_WT_CNTL_WT );
170
171	start_time = system_time();
172
173	do {
174		uint32 status;
175
176		status = INREG( regs, RADEON_TV_HOST_RD_WT_CNTL );
177
178		if( (status & RADEON_TV_HOST_RD_WT_CNTL_WT_ACK) != 0 )
179			break;
180	} while( system_time() - start_time < 2000000 );
181
182	OUTREG( regs, RADEON_TV_HOST_RD_WT_CNTL, 0 );
183}
184
185
186// program TV-Out registers
187void Radeon_InternalTVOutProgramRegisters(
188	accelerator_info *ai, impactv_regs *values )
189{
190	uint32 orig_tv_master_cntl = values->tv_master_cntl;
191
192	SHOW_FLOW0( 2, "" );
193
194	// disable TV-out when registers are setup
195	// it gets enabled again when things have settled down
196	values->tv_master_cntl |=
197		RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
198		RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
199		RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST |
200
201		RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
202		RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
203		RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST;
204
205	writeMMIORegList( ai, values, intern_reg_mapping_before_pll );
206	writePLLRegList( ai, values, intern_reg_mapping_pll );
207	writeMMIORegList( ai, values, intern_reg_mapping_after_pll );
208
209	// un-reset FIFO to access timing table
210	OUTREG( ai->regs, RADEON_TV_MASTER_CNTL,
211		orig_tv_master_cntl |
212		RADEON_TV_MASTER_CNTL_TV_ASYNC_RST |
213		RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST |
214
215		RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
216		RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
217		RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST );
218
219	Radeon_ImpacTVwriteHorTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values, true );
220	Radeon_ImpacTVwriteVertTimingTable( ai, Radeon_InternalTVOutWriteFIFO, values );
221
222	snooze( 50000 );
223
224	values->tv_master_cntl = orig_tv_master_cntl;
225	writeMMIORegList( ai, values, intern_reg_mapping_finish );
226}
227
228
229// read list of MM I/O registers
230static void readMMIORegList(
231	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
232{
233	vuint8 *regs = ai->regs;
234
235	for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
236		*(uint32 *)((char *)(values) + mapping->offset) =
237			INREG( regs, mapping->address );
238
239		/*SHOW_FLOW( 2, "%x=%x", mapping->address,
240			*(uint32 *)((char *)(values) + mapping->offset) );*/
241	}
242
243	//snooze( 1000000 );
244}
245
246
247// read list of PLL registers
248static void readPLLRegList(
249	accelerator_info *ai, impactv_regs *values, const register_mapping *mapping )
250{
251	for( ; mapping->address != 0 && mapping->offset != 0; ++mapping ) {
252		*(uint32 *)((char *)(values) + mapping->offset) =
253			Radeon_INPLL( ai->regs, ai->si->asic, mapping->address );
254
255		/*SHOW_FLOW( 2, "%x=%x", mapping->address,
256			*(uint32 *)((char *)(values) + mapping->offset) );*/
257	}
258
259	//snooze( 1000000 );
260}
261
262
263// read TV-Out registers
264void Radeon_InternalTVOutReadRegisters(
265	accelerator_info *ai, impactv_regs *values )
266{
267	readMMIORegList( ai, values, intern_reg_mapping_before_pll );
268	readPLLRegList( ai, values, intern_reg_mapping_pll );
269	readMMIORegList( ai, values, intern_reg_mapping_after_pll );
270	readMMIORegList( ai, values, intern_reg_mapping_finish );
271
272	//snooze( 1000000 );
273}
274