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