xref: /haiku/src/add-ons/accelerants/radeon/internal_tv_out.c (revision 1e36cfc2721ef13a187c6f7354dc9cbc485e89d3)
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
23 typedef 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
32 static 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
42 static 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
50 static 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
76 static 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
90 static 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
107 static 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
126 static 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
158 static 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
187 void 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
230 static 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
248 static 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
264 void 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