Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |
Darren Jenkins | fc9a89f | 2010-01-07 01:35:21 -0500 | [diff] [blame] | 80 | static const uint16_t hor_timing_NTSC[MAX_H_CODE_TIMING_LEN] = { |
Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |
Darren Jenkins | fc9a89f | 2010-01-07 01:35:21 -0500 | [diff] [blame] | 101 | static const uint16_t vert_timing_NTSC[MAX_V_CODE_TIMING_LEN] = { |
Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |
Darren Jenkins | fc9a89f | 2010-01-07 01:35:21 -0500 | [diff] [blame] | 118 | static const uint16_t hor_timing_PAL[MAX_H_CODE_TIMING_LEN] = { |
Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |
Darren Jenkins | fc9a89f | 2010-01-07 01:35:21 -0500 | [diff] [blame] | 139 | static const uint16_t vert_timing_PAL[MAX_V_CODE_TIMING_LEN] = { |
Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |
Darren Jenkins | fc9a89f | 2010-01-07 01:35:21 -0500 | [diff] [blame] | 626 | if (flicker_removal < 2) |
| 627 | flicker_removal = 2; |
| 628 | for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) { |
Dave Airlie | 4ce001a | 2009-08-13 16:32:14 +1000 | [diff] [blame] | 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 | |