diff options
author | Dave Airlie <airlied@redhat.com> | 2009-08-13 02:32:14 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-09-07 19:24:37 -0400 |
commit | 4ce001abafafe77e5dd943d1480fc9f87894e96f (patch) | |
tree | 4a22b42c58a80450992fcf5d7625b19fe045855b /drivers/gpu/drm/radeon/radeon_legacy_tv.c | |
parent | 551ebd837c75fc75df81811a18b7136c39cab487 (diff) |
drm/radeon/kms: add initial radeon tv-out support.
This ports the tv-out code from the DDX to KMS.
adds a radeon.tv module option, radeon.tv=0 to disable tv
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_legacy_tv.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_legacy_tv.c | 904 |
1 files changed, 904 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c new file mode 100644 index 000000000000..3a12bb0c0563 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c | |||
@@ -0,0 +1,904 @@ | |||
1 | #include "drmP.h" | ||
2 | #include "drm_crtc_helper.h" | ||
3 | #include "radeon.h" | ||
4 | |||
5 | /* | ||
6 | * Integrated TV out support based on the GATOS code by | ||
7 | * Federico Ulivi <fulivi@lycos.com> | ||
8 | */ | ||
9 | |||
10 | |||
11 | /* | ||
12 | * Limits of h/v positions (hPos & vPos) | ||
13 | */ | ||
14 | #define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */ | ||
15 | #define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */ | ||
16 | |||
17 | /* | ||
18 | * Unit for hPos (in TV clock periods) | ||
19 | */ | ||
20 | #define H_POS_UNIT 10 | ||
21 | |||
22 | /* | ||
23 | * Indexes in h. code timing table for horizontal line position adjustment | ||
24 | */ | ||
25 | #define H_TABLE_POS1 6 | ||
26 | #define H_TABLE_POS2 8 | ||
27 | |||
28 | /* | ||
29 | * Limits of hor. size (hSize) | ||
30 | */ | ||
31 | #define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */ | ||
32 | |||
33 | /* tv standard constants */ | ||
34 | #define NTSC_TV_CLOCK_T 233 | ||
35 | #define NTSC_TV_VFTOTAL 1 | ||
36 | #define NTSC_TV_LINES_PER_FRAME 525 | ||
37 | #define NTSC_TV_ZERO_H_SIZE 479166 | ||
38 | #define NTSC_TV_H_SIZE_UNIT 9478 | ||
39 | |||
40 | #define PAL_TV_CLOCK_T 188 | ||
41 | #define PAL_TV_VFTOTAL 3 | ||
42 | #define PAL_TV_LINES_PER_FRAME 625 | ||
43 | #define PAL_TV_ZERO_H_SIZE 473200 | ||
44 | #define PAL_TV_H_SIZE_UNIT 9360 | ||
45 | |||
46 | /* tv pll setting for 27 mhz ref clk */ | ||
47 | #define NTSC_TV_PLL_M_27 22 | ||
48 | #define NTSC_TV_PLL_N_27 175 | ||
49 | #define NTSC_TV_PLL_P_27 5 | ||
50 | |||
51 | #define PAL_TV_PLL_M_27 113 | ||
52 | #define PAL_TV_PLL_N_27 668 | ||
53 | #define PAL_TV_PLL_P_27 3 | ||
54 | |||
55 | /* tv pll setting for 14 mhz ref clk */ | ||
56 | #define NTSC_TV_PLL_M_14 33 | ||
57 | #define NTSC_TV_PLL_N_14 693 | ||
58 | #define NTSC_TV_PLL_P_14 7 | ||
59 | |||
60 | #define VERT_LEAD_IN_LINES 2 | ||
61 | #define FRAC_BITS 0xe | ||
62 | #define FRAC_MASK 0x3fff | ||
63 | |||
64 | struct radeon_tv_mode_constants { | ||
65 | uint16_t hor_resolution; | ||
66 | uint16_t ver_resolution; | ||
67 | enum radeon_tv_std standard; | ||
68 | uint16_t hor_total; | ||
69 | uint16_t ver_total; | ||
70 | uint16_t hor_start; | ||
71 | uint16_t hor_syncstart; | ||
72 | uint16_t ver_syncstart; | ||
73 | unsigned def_restart; | ||
74 | uint16_t crtcPLL_N; | ||
75 | uint8_t crtcPLL_M; | ||
76 | uint8_t crtcPLL_post_div; | ||
77 | unsigned pix_to_tv; | ||
78 | }; | ||
79 | |||
80 | static const uint16_t hor_timing_NTSC[] = { | ||
81 | 0x0007, | ||
82 | 0x003f, | ||
83 | 0x0263, | ||
84 | 0x0a24, | ||
85 | 0x2a6b, | ||
86 | 0x0a36, | ||
87 | 0x126d, /* H_TABLE_POS1 */ | ||
88 | 0x1bfe, | ||
89 | 0x1a8f, /* H_TABLE_POS2 */ | ||
90 | 0x1ec7, | ||
91 | 0x3863, | ||
92 | 0x1bfe, | ||
93 | 0x1bfe, | ||
94 | 0x1a2a, | ||
95 | 0x1e95, | ||
96 | 0x0e31, | ||
97 | 0x201b, | ||
98 | 0 | ||
99 | }; | ||
100 | |||
101 | static const uint16_t vert_timing_NTSC[] = { | ||
102 | 0x2001, | ||
103 | 0x200d, | ||
104 | 0x1006, | ||
105 | 0x0c06, | ||
106 | 0x1006, | ||
107 | 0x1818, | ||
108 | 0x21e3, | ||
109 | 0x1006, | ||
110 | 0x0c06, | ||
111 | 0x1006, | ||
112 | 0x1817, | ||
113 | 0x21d4, | ||
114 | 0x0002, | ||
115 | 0 | ||
116 | }; | ||
117 | |||
118 | static const uint16_t hor_timing_PAL[] = { | ||
119 | 0x0007, | ||
120 | 0x0058, | ||
121 | 0x027c, | ||
122 | 0x0a31, | ||
123 | 0x2a77, | ||
124 | 0x0a95, | ||
125 | 0x124f, /* H_TABLE_POS1 */ | ||
126 | 0x1bfe, | ||
127 | 0x1b22, /* H_TABLE_POS2 */ | ||
128 | 0x1ef9, | ||
129 | 0x387c, | ||
130 | 0x1bfe, | ||
131 | 0x1bfe, | ||
132 | 0x1b31, | ||
133 | 0x1eb5, | ||
134 | 0x0e43, | ||
135 | 0x201b, | ||
136 | 0 | ||
137 | }; | ||
138 | |||
139 | static const uint16_t vert_timing_PAL[] = { | ||
140 | 0x2001, | ||
141 | 0x200c, | ||
142 | 0x1005, | ||
143 | 0x0c05, | ||
144 | 0x1005, | ||
145 | 0x1401, | ||
146 | 0x1821, | ||
147 | 0x2240, | ||
148 | 0x1005, | ||
149 | 0x0c05, | ||
150 | 0x1005, | ||
151 | 0x1401, | ||
152 | 0x1822, | ||
153 | 0x2230, | ||
154 | 0x0002, | ||
155 | 0 | ||
156 | }; | ||
157 | |||
158 | /********************************************************************** | ||
159 | * | ||
160 | * availableModes | ||
161 | * | ||
162 | * Table of all allowed modes for tv output | ||
163 | * | ||
164 | **********************************************************************/ | ||
165 | static const struct radeon_tv_mode_constants available_tv_modes[] = { | ||
166 | { /* NTSC timing for 27 Mhz ref clk */ | ||
167 | 800, /* horResolution */ | ||
168 | 600, /* verResolution */ | ||
169 | TV_STD_NTSC, /* standard */ | ||
170 | 990, /* horTotal */ | ||
171 | 740, /* verTotal */ | ||
172 | 813, /* horStart */ | ||
173 | 824, /* horSyncStart */ | ||
174 | 632, /* verSyncStart */ | ||
175 | 625592, /* defRestart */ | ||
176 | 592, /* crtcPLL_N */ | ||
177 | 91, /* crtcPLL_M */ | ||
178 | 4, /* crtcPLL_postDiv */ | ||
179 | 1022, /* pixToTV */ | ||
180 | }, | ||
181 | { /* PAL timing for 27 Mhz ref clk */ | ||
182 | 800, /* horResolution */ | ||
183 | 600, /* verResolution */ | ||
184 | TV_STD_PAL, /* standard */ | ||
185 | 1144, /* horTotal */ | ||
186 | 706, /* verTotal */ | ||
187 | 812, /* horStart */ | ||
188 | 824, /* horSyncStart */ | ||
189 | 669, /* verSyncStart */ | ||
190 | 696700, /* defRestart */ | ||
191 | 1382, /* crtcPLL_N */ | ||
192 | 231, /* crtcPLL_M */ | ||
193 | 4, /* crtcPLL_postDiv */ | ||
194 | 759, /* pixToTV */ | ||
195 | }, | ||
196 | { /* NTSC timing for 14 Mhz ref clk */ | ||
197 | 800, /* horResolution */ | ||
198 | 600, /* verResolution */ | ||
199 | TV_STD_NTSC, /* standard */ | ||
200 | 1018, /* horTotal */ | ||
201 | 727, /* verTotal */ | ||
202 | 813, /* horStart */ | ||
203 | 840, /* horSyncStart */ | ||
204 | 633, /* verSyncStart */ | ||
205 | 630627, /* defRestart */ | ||
206 | 347, /* crtcPLL_N */ | ||
207 | 14, /* crtcPLL_M */ | ||
208 | 8, /* crtcPLL_postDiv */ | ||
209 | 1022, /* pixToTV */ | ||
210 | }, | ||
211 | }; | ||
212 | |||
213 | #define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes) | ||
214 | |||
215 | static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder, | ||
216 | uint16_t *pll_ref_freq) | ||
217 | { | ||
218 | struct drm_device *dev = radeon_encoder->base.dev; | ||
219 | struct radeon_device *rdev = dev->dev_private; | ||
220 | struct radeon_crtc *radeon_crtc; | ||
221 | struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; | ||
222 | const struct radeon_tv_mode_constants *const_ptr; | ||
223 | struct radeon_pll *pll; | ||
224 | |||
225 | radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc); | ||
226 | if (radeon_crtc->crtc_id == 1) | ||
227 | pll = &rdev->clock.p2pll; | ||
228 | else | ||
229 | pll = &rdev->clock.p1pll; | ||
230 | |||
231 | if (pll_ref_freq) | ||
232 | *pll_ref_freq = pll->reference_freq; | ||
233 | |||
234 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
235 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
236 | tv_dac->tv_std == TV_STD_PAL_M) { | ||
237 | if (pll->reference_freq == 2700) | ||
238 | const_ptr = &available_tv_modes[0]; | ||
239 | else | ||
240 | const_ptr = &available_tv_modes[2]; | ||
241 | } else { | ||
242 | if (pll->reference_freq == 2700) | ||
243 | const_ptr = &available_tv_modes[1]; | ||
244 | else | ||
245 | const_ptr = &available_tv_modes[1]; /* FIX ME */ | ||
246 | } | ||
247 | return const_ptr; | ||
248 | } | ||
249 | |||
250 | static long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; | ||
251 | static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; | ||
252 | static long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; | ||
253 | static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; | ||
254 | |||
255 | static void radeon_wait_pll_lock(struct drm_encoder *encoder, unsigned n_tests, | ||
256 | unsigned n_wait_loops, unsigned cnt_threshold) | ||
257 | { | ||
258 | struct drm_device *dev = encoder->dev; | ||
259 | struct radeon_device *rdev = dev->dev_private; | ||
260 | uint32_t save_pll_test; | ||
261 | unsigned int i, j; | ||
262 | |||
263 | WREG32(RADEON_TEST_DEBUG_MUX, (RREG32(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); | ||
264 | save_pll_test = RREG32_PLL(RADEON_PLL_TEST_CNTL); | ||
265 | WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test & ~RADEON_PLL_MASK_READ_B); | ||
266 | |||
267 | WREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); | ||
268 | for (i = 0; i < n_tests; i++) { | ||
269 | WREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); | ||
270 | for (j = 0; j < n_wait_loops; j++) | ||
271 | if (RREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cnt_threshold) | ||
272 | break; | ||
273 | } | ||
274 | WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test); | ||
275 | WREG32(RADEON_TEST_DEBUG_MUX, RREG32(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); | ||
276 | } | ||
277 | |||
278 | |||
279 | static void radeon_legacy_tv_write_fifo(struct radeon_encoder *radeon_encoder, | ||
280 | uint16_t addr, uint32_t value) | ||
281 | { | ||
282 | struct drm_device *dev = radeon_encoder->base.dev; | ||
283 | struct radeon_device *rdev = dev->dev_private; | ||
284 | uint32_t tmp; | ||
285 | int i = 0; | ||
286 | |||
287 | WREG32(RADEON_TV_HOST_WRITE_DATA, value); | ||
288 | |||
289 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); | ||
290 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); | ||
291 | |||
292 | do { | ||
293 | tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); | ||
294 | if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) | ||
295 | break; | ||
296 | i++; | ||
297 | } while (i < 10000); | ||
298 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); | ||
299 | } | ||
300 | |||
301 | #if 0 /* included for completeness */ | ||
302 | static uint32_t radeon_legacy_tv_read_fifo(struct radeon_encoder *radeon_encoder, uint16_t addr) | ||
303 | { | ||
304 | struct drm_device *dev = radeon_encoder->base.dev; | ||
305 | struct radeon_device *rdev = dev->dev_private; | ||
306 | uint32_t tmp; | ||
307 | int i = 0; | ||
308 | |||
309 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); | ||
310 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); | ||
311 | |||
312 | do { | ||
313 | tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); | ||
314 | if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) | ||
315 | break; | ||
316 | i++; | ||
317 | } while (i < 10000); | ||
318 | WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); | ||
319 | return RREG32(RADEON_TV_HOST_READ_DATA); | ||
320 | } | ||
321 | #endif | ||
322 | |||
323 | static uint16_t radeon_get_htiming_tables_addr(uint32_t tv_uv_adr) | ||
324 | { | ||
325 | uint16_t h_table; | ||
326 | |||
327 | switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { | ||
328 | case 0: | ||
329 | h_table = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; | ||
330 | break; | ||
331 | case 1: | ||
332 | h_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; | ||
333 | break; | ||
334 | case 2: | ||
335 | h_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; | ||
336 | break; | ||
337 | default: | ||
338 | h_table = 0; | ||
339 | break; | ||
340 | } | ||
341 | return h_table; | ||
342 | } | ||
343 | |||
344 | static uint16_t radeon_get_vtiming_tables_addr(uint32_t tv_uv_adr) | ||
345 | { | ||
346 | uint16_t v_table; | ||
347 | |||
348 | switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { | ||
349 | case 0: | ||
350 | v_table = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; | ||
351 | break; | ||
352 | case 1: | ||
353 | v_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; | ||
354 | break; | ||
355 | case 2: | ||
356 | v_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; | ||
357 | break; | ||
358 | default: | ||
359 | v_table = 0; | ||
360 | break; | ||
361 | } | ||
362 | return v_table; | ||
363 | } | ||
364 | |||
365 | static void radeon_restore_tv_timing_tables(struct radeon_encoder *radeon_encoder) | ||
366 | { | ||
367 | struct drm_device *dev = radeon_encoder->base.dev; | ||
368 | struct radeon_device *rdev = dev->dev_private; | ||
369 | struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; | ||
370 | uint16_t h_table, v_table; | ||
371 | uint32_t tmp; | ||
372 | int i; | ||
373 | |||
374 | WREG32(RADEON_TV_UV_ADR, tv_dac->tv.tv_uv_adr); | ||
375 | h_table = radeon_get_htiming_tables_addr(tv_dac->tv.tv_uv_adr); | ||
376 | v_table = radeon_get_vtiming_tables_addr(tv_dac->tv.tv_uv_adr); | ||
377 | |||
378 | for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, h_table--) { | ||
379 | tmp = ((uint32_t)tv_dac->tv.h_code_timing[i] << 14) | ((uint32_t)tv_dac->tv.h_code_timing[i+1]); | ||
380 | radeon_legacy_tv_write_fifo(radeon_encoder, h_table, tmp); | ||
381 | if (tv_dac->tv.h_code_timing[i] == 0 || tv_dac->tv.h_code_timing[i + 1] == 0) | ||
382 | break; | ||
383 | } | ||
384 | for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, v_table++) { | ||
385 | tmp = ((uint32_t)tv_dac->tv.v_code_timing[i+1] << 14) | ((uint32_t)tv_dac->tv.v_code_timing[i]); | ||
386 | radeon_legacy_tv_write_fifo(radeon_encoder, v_table, tmp); | ||
387 | if (tv_dac->tv.v_code_timing[i] == 0 || tv_dac->tv.v_code_timing[i + 1] == 0) | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encoder) | ||
393 | { | ||
394 | struct drm_device *dev = radeon_encoder->base.dev; | ||
395 | struct radeon_device *rdev = dev->dev_private; | ||
396 | struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; | ||
397 | WREG32(RADEON_TV_FRESTART, tv_dac->tv.frestart); | ||
398 | WREG32(RADEON_TV_HRESTART, tv_dac->tv.hrestart); | ||
399 | WREG32(RADEON_TV_VRESTART, tv_dac->tv.vrestart); | ||
400 | } | ||
401 | |||
402 | static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder) | ||
403 | { | ||
404 | struct drm_device *dev = encoder->dev; | ||
405 | struct radeon_device *rdev = dev->dev_private; | ||
406 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
407 | struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; | ||
408 | struct radeon_crtc *radeon_crtc; | ||
409 | int restart; | ||
410 | unsigned int h_total, v_total, f_total; | ||
411 | int v_offset, h_offset; | ||
412 | u16 p1, p2, h_inc; | ||
413 | bool h_changed; | ||
414 | const struct radeon_tv_mode_constants *const_ptr; | ||
415 | struct radeon_pll *pll; | ||
416 | |||
417 | radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc); | ||
418 | if (radeon_crtc->crtc_id == 1) | ||
419 | pll = &rdev->clock.p2pll; | ||
420 | else | ||
421 | pll = &rdev->clock.p1pll; | ||
422 | |||
423 | const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); | ||
424 | if (!const_ptr) | ||
425 | return false; | ||
426 | |||
427 | h_total = const_ptr->hor_total; | ||
428 | v_total = const_ptr->ver_total; | ||
429 | |||
430 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
431 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
432 | tv_dac->tv_std == TV_STD_PAL_M || | ||
433 | tv_dac->tv_std == TV_STD_PAL_60) | ||
434 | f_total = NTSC_TV_VFTOTAL + 1; | ||
435 | else | ||
436 | f_total = PAL_TV_VFTOTAL + 1; | ||
437 | |||
438 | /* adjust positions 1&2 in hor. cod timing table */ | ||
439 | h_offset = tv_dac->h_pos * H_POS_UNIT; | ||
440 | |||
441 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
442 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
443 | tv_dac->tv_std == TV_STD_PAL_M) { | ||
444 | h_offset -= 50; | ||
445 | p1 = hor_timing_NTSC[H_TABLE_POS1]; | ||
446 | p2 = hor_timing_NTSC[H_TABLE_POS2]; | ||
447 | } else { | ||
448 | p1 = hor_timing_PAL[H_TABLE_POS1]; | ||
449 | p2 = hor_timing_PAL[H_TABLE_POS2]; | ||
450 | } | ||
451 | |||
452 | p1 = (u16)((int)p1 + h_offset); | ||
453 | p2 = (u16)((int)p2 - h_offset); | ||
454 | |||
455 | h_changed = (p1 != tv_dac->tv.h_code_timing[H_TABLE_POS1] || | ||
456 | p2 != tv_dac->tv.h_code_timing[H_TABLE_POS2]); | ||
457 | |||
458 | tv_dac->tv.h_code_timing[H_TABLE_POS1] = p1; | ||
459 | tv_dac->tv.h_code_timing[H_TABLE_POS2] = p2; | ||
460 | |||
461 | /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ | ||
462 | h_offset = (h_offset * (int)(const_ptr->pix_to_tv)) / 1000; | ||
463 | |||
464 | /* adjust restart */ | ||
465 | restart = const_ptr->def_restart; | ||
466 | |||
467 | /* | ||
468 | * convert v_pos TV lines to n. of CRTC pixels | ||
469 | */ | ||
470 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
471 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
472 | tv_dac->tv_std == TV_STD_PAL_M || | ||
473 | tv_dac->tv_std == TV_STD_PAL_60) | ||
474 | v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(NTSC_TV_LINES_PER_FRAME); | ||
475 | else | ||
476 | v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(PAL_TV_LINES_PER_FRAME); | ||
477 | |||
478 | restart -= v_offset + h_offset; | ||
479 | |||
480 | DRM_DEBUG("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n", | ||
481 | const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart); | ||
482 | |||
483 | tv_dac->tv.hrestart = restart % h_total; | ||
484 | restart /= h_total; | ||
485 | tv_dac->tv.vrestart = restart % v_total; | ||
486 | restart /= v_total; | ||
487 | tv_dac->tv.frestart = restart % f_total; | ||
488 | |||
489 | DRM_DEBUG("compute_restart: F/H/V=%u,%u,%u\n", | ||
490 | (unsigned)tv_dac->tv.frestart, | ||
491 | (unsigned)tv_dac->tv.vrestart, | ||
492 | (unsigned)tv_dac->tv.hrestart); | ||
493 | |||
494 | /* compute h_inc from hsize */ | ||
495 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
496 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
497 | tv_dac->tv_std == TV_STD_PAL_M) | ||
498 | h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * NTSC_TV_CLOCK_T) / | ||
499 | (tv_dac->h_size * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); | ||
500 | else | ||
501 | h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * PAL_TV_CLOCK_T) / | ||
502 | (tv_dac->h_size * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); | ||
503 | |||
504 | tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) | | ||
505 | ((u32)h_inc << RADEON_H_INC_SHIFT); | ||
506 | |||
507 | DRM_DEBUG("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc); | ||
508 | |||
509 | return h_changed; | ||
510 | } | ||
511 | |||
512 | void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, | ||
513 | struct drm_display_mode *mode, | ||
514 | struct drm_display_mode *adjusted_mode) | ||
515 | { | ||
516 | struct drm_device *dev = encoder->dev; | ||
517 | struct radeon_device *rdev = dev->dev_private; | ||
518 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
519 | struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; | ||
520 | const struct radeon_tv_mode_constants *const_ptr; | ||
521 | struct radeon_crtc *radeon_crtc; | ||
522 | int i; | ||
523 | uint16_t pll_ref_freq; | ||
524 | uint32_t vert_space, flicker_removal, tmp; | ||
525 | uint32_t tv_master_cntl, tv_rgb_cntl, tv_dac_cntl; | ||
526 | uint32_t tv_modulator_cntl1, tv_modulator_cntl2; | ||
527 | uint32_t tv_vscaler_cntl1, tv_vscaler_cntl2; | ||
528 | uint32_t tv_pll_cntl, tv_pll_cntl1, tv_ftotal; | ||
529 | uint32_t tv_y_fall_cntl, tv_y_rise_cntl, tv_y_saw_tooth_cntl; | ||
530 | uint32_t m, n, p; | ||
531 | const uint16_t *hor_timing; | ||
532 | const uint16_t *vert_timing; | ||
533 | |||
534 | const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, &pll_ref_freq); | ||
535 | if (!const_ptr) | ||
536 | return; | ||
537 | |||
538 | radeon_crtc = to_radeon_crtc(encoder->crtc); | ||
539 | |||
540 | tv_master_cntl = (RADEON_VIN_ASYNC_RST | | ||
541 | RADEON_CRT_FIFO_CE_EN | | ||
542 | RADEON_TV_FIFO_CE_EN | | ||
543 | RADEON_TV_ON); | ||
544 | |||
545 | if (!ASIC_IS_R300(rdev)) | ||
546 | tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; | ||
547 | |||
548 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
549 | tv_dac->tv_std == TV_STD_NTSC_J) | ||
550 | tv_master_cntl |= RADEON_RESTART_PHASE_FIX; | ||
551 | |||
552 | tv_modulator_cntl1 = (RADEON_SLEW_RATE_LIMIT | | ||
553 | RADEON_SYNC_TIP_LEVEL | | ||
554 | RADEON_YFLT_EN | | ||
555 | RADEON_UVFLT_EN | | ||
556 | (6 << RADEON_CY_FILT_BLEND_SHIFT)); | ||
557 | |||
558 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
559 | tv_dac->tv_std == TV_STD_NTSC_J) { | ||
560 | tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) | | ||
561 | (0x3b << RADEON_BLANK_LEVEL_SHIFT); | ||
562 | tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | | ||
563 | ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); | ||
564 | } else if (tv_dac->tv_std == TV_STD_SCART_PAL) { | ||
565 | tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; | ||
566 | tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | | ||
567 | ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); | ||
568 | } else { | ||
569 | tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN | | ||
570 | (0x3b << RADEON_SET_UP_LEVEL_SHIFT) | | ||
571 | (0x3b << RADEON_BLANK_LEVEL_SHIFT); | ||
572 | tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | | ||
573 | ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); | ||
574 | } | ||
575 | |||
576 | |||
577 | tv_rgb_cntl = (RADEON_RGB_DITHER_EN | ||
578 | | RADEON_TVOUT_SCALE_EN | ||
579 | | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) | ||
580 | | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT) | ||
581 | | RADEON_RGB_ATTEN_SEL(0x3) | ||
582 | | RADEON_RGB_ATTEN_VAL(0xc)); | ||
583 | |||
584 | if (radeon_crtc->crtc_id == 1) | ||
585 | tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; | ||
586 | else { | ||
587 | if (radeon_crtc->rmx_type != RMX_OFF) | ||
588 | tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; | ||
589 | else | ||
590 | tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; | ||
591 | } | ||
592 | |||
593 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
594 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
595 | tv_dac->tv_std == TV_STD_PAL_M || | ||
596 | tv_dac->tv_std == TV_STD_PAL_60) | ||
597 | vert_space = const_ptr->ver_total * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; | ||
598 | else | ||
599 | vert_space = const_ptr->ver_total * 2 * 10000 / PAL_TV_LINES_PER_FRAME; | ||
600 | |||
601 | tmp = RREG32(RADEON_TV_VSCALER_CNTL1); | ||
602 | tmp &= 0xe3ff0000; | ||
603 | tmp |= (vert_space * (1 << FRAC_BITS) / 10000); | ||
604 | tv_vscaler_cntl1 = tmp; | ||
605 | |||
606 | if (pll_ref_freq == 2700) | ||
607 | tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; | ||
608 | |||
609 | if (const_ptr->hor_resolution == 1024) | ||
610 | tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); | ||
611 | else | ||
612 | tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); | ||
613 | |||
614 | /* scale up for int divide */ | ||
615 | tmp = const_ptr->ver_total * 2 * 1000; | ||
616 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
617 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
618 | tv_dac->tv_std == TV_STD_PAL_M || | ||
619 | tv_dac->tv_std == TV_STD_PAL_60) { | ||
620 | tmp /= NTSC_TV_LINES_PER_FRAME; | ||
621 | } else { | ||
622 | tmp /= PAL_TV_LINES_PER_FRAME; | ||
623 | } | ||
624 | flicker_removal = (tmp + 500) / 1000; | ||
625 | |||
626 | if (flicker_removal < 3) | ||
627 | flicker_removal = 3; | ||
628 | for (i = 0; i < 6; ++i) { | ||
629 | if (flicker_removal == SLOPE_limit[i]) | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | tv_y_saw_tooth_cntl = (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + | ||
634 | 5001) / 10000 / 8 | ((SLOPE_value[i] * | ||
635 | (1 << (FRAC_BITS - 1)) / 8) << 16); | ||
636 | tv_y_fall_cntl = | ||
637 | (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | | ||
638 | RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / | ||
639 | 1024; | ||
640 | tv_y_rise_cntl = RADEON_Y_RISE_PING_PONG| | ||
641 | (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; | ||
642 | |||
643 | tv_vscaler_cntl2 = RREG32(RADEON_TV_VSCALER_CNTL2) & 0x00fffff0; | ||
644 | tv_vscaler_cntl2 |= (0x10 << 24) | | ||
645 | RADEON_DITHER_MODE | | ||
646 | RADEON_Y_OUTPUT_DITHER_EN | | ||
647 | RADEON_UV_OUTPUT_DITHER_EN | | ||
648 | RADEON_UV_TO_BUF_DITHER_EN; | ||
649 | |||
650 | tmp = (tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; | ||
651 | tmp = ((16384 * 256 * 10) / tmp + 5) / 10; | ||
652 | tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; | ||
653 | tv_dac->tv.timing_cntl = tmp; | ||
654 | |||
655 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
656 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
657 | tv_dac->tv_std == TV_STD_PAL_M || | ||
658 | tv_dac->tv_std == TV_STD_PAL_60) | ||
659 | tv_dac_cntl = tv_dac->ntsc_tvdac_adj; | ||
660 | else | ||
661 | tv_dac_cntl = tv_dac->pal_tvdac_adj; | ||
662 | |||
663 | tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD; | ||
664 | |||
665 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
666 | tv_dac->tv_std == TV_STD_NTSC_J) | ||
667 | tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; | ||
668 | else | ||
669 | tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; | ||
670 | |||
671 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
672 | tv_dac->tv_std == TV_STD_NTSC_J) { | ||
673 | if (pll_ref_freq == 2700) { | ||
674 | m = NTSC_TV_PLL_M_27; | ||
675 | n = NTSC_TV_PLL_N_27; | ||
676 | p = NTSC_TV_PLL_P_27; | ||
677 | } else { | ||
678 | m = NTSC_TV_PLL_M_14; | ||
679 | n = NTSC_TV_PLL_N_14; | ||
680 | p = NTSC_TV_PLL_P_14; | ||
681 | } | ||
682 | } else { | ||
683 | if (pll_ref_freq == 2700) { | ||
684 | m = PAL_TV_PLL_M_27; | ||
685 | n = PAL_TV_PLL_N_27; | ||
686 | p = PAL_TV_PLL_P_27; | ||
687 | } else { | ||
688 | m = PAL_TV_PLL_M_27; | ||
689 | n = PAL_TV_PLL_N_27; | ||
690 | p = PAL_TV_PLL_P_27; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) | | ||
695 | (((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | | ||
696 | ((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | | ||
697 | (((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | | ||
698 | ((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); | ||
699 | |||
700 | tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK) << RADEON_TVPCP_SHIFT) | | ||
701 | ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) | | ||
702 | ((1 & RADEON_TVPDC_MASK) << RADEON_TVPDC_SHIFT) | | ||
703 | RADEON_TVCLK_SRC_SEL_TVPLL | | ||
704 | RADEON_TVPLL_TEST_DIS); | ||
705 | |||
706 | tv_dac->tv.tv_uv_adr = 0xc8; | ||
707 | |||
708 | if (tv_dac->tv_std == TV_STD_NTSC || | ||
709 | tv_dac->tv_std == TV_STD_NTSC_J || | ||
710 | tv_dac->tv_std == TV_STD_PAL_M || | ||
711 | tv_dac->tv_std == TV_STD_PAL_60) { | ||
712 | tv_ftotal = NTSC_TV_VFTOTAL; | ||
713 | hor_timing = hor_timing_NTSC; | ||
714 | vert_timing = vert_timing_NTSC; | ||
715 | } else { | ||
716 | hor_timing = hor_timing_PAL; | ||
717 | vert_timing = vert_timing_PAL; | ||
718 | tv_ftotal = PAL_TV_VFTOTAL; | ||
719 | } | ||
720 | |||
721 | for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { | ||
722 | if ((tv_dac->tv.h_code_timing[i] = hor_timing[i]) == 0) | ||
723 | break; | ||
724 | } | ||
725 | |||
726 | for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { | ||
727 | if ((tv_dac->tv.v_code_timing[i] = vert_timing[i]) == 0) | ||
728 | break; | ||
729 | } | ||
730 | |||
731 | radeon_legacy_tv_init_restarts(encoder); | ||
732 | |||
733 | /* play with DAC_CNTL */ | ||
734 | /* play with GPIOPAD_A */ | ||
735 | /* DISP_OUTPUT_CNTL */ | ||
736 | /* use reference freq */ | ||
737 | |||
738 | /* program the TV registers */ | ||
739 | WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | | ||
740 | RADEON_CRT_ASYNC_RST | RADEON_TV_FIFO_ASYNC_RST)); | ||
741 | |||
742 | tmp = RREG32(RADEON_TV_DAC_CNTL); | ||
743 | tmp &= ~RADEON_TV_DAC_NBLANK; | ||
744 | tmp |= RADEON_TV_DAC_BGSLEEP | | ||
745 | RADEON_TV_DAC_RDACPD | | ||
746 | RADEON_TV_DAC_GDACPD | | ||
747 | RADEON_TV_DAC_BDACPD; | ||
748 | WREG32(RADEON_TV_DAC_CNTL, tmp); | ||
749 | |||
750 | /* TV PLL */ | ||
751 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); | ||
752 | WREG32_PLL(RADEON_TV_PLL_CNTL, tv_pll_cntl); | ||
753 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); | ||
754 | |||
755 | radeon_wait_pll_lock(encoder, 200, 800, 135); | ||
756 | |||
757 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); | ||
758 | |||
759 | radeon_wait_pll_lock(encoder, 300, 160, 27); | ||
760 | radeon_wait_pll_lock(encoder, 200, 800, 135); | ||
761 | |||
762 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~0xf); | ||
763 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); | ||
764 | |||
765 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); | ||
766 | WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); | ||
767 | |||
768 | /* TV HV */ | ||
769 | WREG32(RADEON_TV_RGB_CNTL, tv_rgb_cntl); | ||
770 | WREG32(RADEON_TV_HTOTAL, const_ptr->hor_total - 1); | ||
771 | WREG32(RADEON_TV_HDISP, const_ptr->hor_resolution - 1); | ||
772 | WREG32(RADEON_TV_HSTART, const_ptr->hor_start); | ||
773 | |||
774 | WREG32(RADEON_TV_VTOTAL, const_ptr->ver_total - 1); | ||
775 | WREG32(RADEON_TV_VDISP, const_ptr->ver_resolution - 1); | ||
776 | WREG32(RADEON_TV_FTOTAL, tv_ftotal); | ||
777 | WREG32(RADEON_TV_VSCALER_CNTL1, tv_vscaler_cntl1); | ||
778 | WREG32(RADEON_TV_VSCALER_CNTL2, tv_vscaler_cntl2); | ||
779 | |||
780 | WREG32(RADEON_TV_Y_FALL_CNTL, tv_y_fall_cntl); | ||
781 | WREG32(RADEON_TV_Y_RISE_CNTL, tv_y_rise_cntl); | ||
782 | WREG32(RADEON_TV_Y_SAW_TOOTH_CNTL, tv_y_saw_tooth_cntl); | ||
783 | |||
784 | WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | | ||
785 | RADEON_CRT_ASYNC_RST)); | ||
786 | |||
787 | /* TV restarts */ | ||
788 | radeon_legacy_write_tv_restarts(radeon_encoder); | ||
789 | |||
790 | /* tv timings */ | ||
791 | radeon_restore_tv_timing_tables(radeon_encoder); | ||
792 | |||
793 | WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST)); | ||
794 | |||
795 | /* tv std */ | ||
796 | WREG32(RADEON_TV_SYNC_CNTL, (RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE)); | ||
797 | WREG32(RADEON_TV_TIMING_CNTL, tv_dac->tv.timing_cntl); | ||
798 | WREG32(RADEON_TV_MODULATOR_CNTL1, tv_modulator_cntl1); | ||
799 | WREG32(RADEON_TV_MODULATOR_CNTL2, tv_modulator_cntl2); | ||
800 | WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, (RADEON_Y_RED_EN | | ||
801 | RADEON_C_GRN_EN | | ||
802 | RADEON_CMP_BLU_EN | | ||
803 | RADEON_DAC_DITHER_EN)); | ||
804 | |||
805 | WREG32(RADEON_TV_CRC_CNTL, 0); | ||
806 | |||
807 | WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); | ||
808 | |||
809 | WREG32(RADEON_TV_GAIN_LIMIT_SETTINGS, ((0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | | ||
810 | (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT))); | ||
811 | WREG32(RADEON_TV_LINEAR_GAIN_SETTINGS, ((0x100 << RADEON_UV_GAIN_SHIFT) | | ||
812 | (0x100 << RADEON_Y_GAIN_SHIFT))); | ||
813 | |||
814 | WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); | ||
815 | |||
816 | } | ||
817 | |||
818 | void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, | ||
819 | uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, | ||
820 | uint32_t *v_total_disp, uint32_t *v_sync_strt_wid) | ||
821 | { | ||
822 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
823 | const struct radeon_tv_mode_constants *const_ptr; | ||
824 | uint32_t tmp; | ||
825 | |||
826 | const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); | ||
827 | if (!const_ptr) | ||
828 | return; | ||
829 | |||
830 | *h_total_disp = (((const_ptr->hor_resolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | | ||
831 | (((const_ptr->hor_total / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); | ||
832 | |||
833 | tmp = *h_sync_strt_wid; | ||
834 | tmp &= ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR); | ||
835 | tmp |= (((const_ptr->hor_syncstart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | | ||
836 | (const_ptr->hor_syncstart & 7); | ||
837 | *h_sync_strt_wid = tmp; | ||
838 | |||
839 | *v_total_disp = ((const_ptr->ver_resolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | | ||
840 | ((const_ptr->ver_total - 1) << RADEON_CRTC_V_TOTAL_SHIFT); | ||
841 | |||
842 | tmp = *v_sync_strt_wid; | ||
843 | tmp &= ~RADEON_CRTC_V_SYNC_STRT; | ||
844 | tmp |= ((const_ptr->ver_syncstart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); | ||
845 | *v_sync_strt_wid = tmp; | ||
846 | } | ||
847 | |||
848 | static inline int get_post_div(int value) | ||
849 | { | ||
850 | int post_div; | ||
851 | switch (value) { | ||
852 | case 1: post_div = 0; break; | ||
853 | case 2: post_div = 1; break; | ||
854 | case 3: post_div = 4; break; | ||
855 | case 4: post_div = 2; break; | ||
856 | case 6: post_div = 6; break; | ||
857 | case 8: post_div = 3; break; | ||
858 | case 12: post_div = 7; break; | ||
859 | case 16: | ||
860 | default: post_div = 5; break; | ||
861 | } | ||
862 | return post_div; | ||
863 | } | ||
864 | |||
865 | void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder, | ||
866 | uint32_t *htotal_cntl, uint32_t *ppll_ref_div, | ||
867 | uint32_t *ppll_div_3, uint32_t *pixclks_cntl) | ||
868 | { | ||
869 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
870 | const struct radeon_tv_mode_constants *const_ptr; | ||
871 | |||
872 | const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); | ||
873 | if (!const_ptr) | ||
874 | return; | ||
875 | |||
876 | *htotal_cntl = (const_ptr->hor_total & 0x7) | RADEON_HTOT_CNTL_VGA_EN; | ||
877 | |||
878 | *ppll_ref_div = const_ptr->crtcPLL_M; | ||
879 | |||
880 | *ppll_div_3 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); | ||
881 | *pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); | ||
882 | *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; | ||
883 | } | ||
884 | |||
885 | void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, | ||
886 | uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div, | ||
887 | uint32_t *p2pll_div_0, uint32_t *pixclks_cntl) | ||
888 | { | ||
889 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
890 | const struct radeon_tv_mode_constants *const_ptr; | ||
891 | |||
892 | const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); | ||
893 | if (!const_ptr) | ||
894 | return; | ||
895 | |||
896 | *htotal2_cntl = (const_ptr->hor_total & 0x7); | ||
897 | |||
898 | *p2pll_ref_div = const_ptr->crtcPLL_M; | ||
899 | |||
900 | *p2pll_div_0 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); | ||
901 | *pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; | ||
902 | *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK | RADEON_PIXCLK_TV_SRC_SEL; | ||
903 | } | ||
904 | |||