162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <drm/drm_device.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "radeon.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * Integrated TV out support based on the GATOS code by 962306a36Sopenharmony_ci * Federico Ulivi <fulivi@lycos.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Limits of h/v positions (hPos & vPos) 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */ 1762306a36Sopenharmony_ci#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Unit for hPos (in TV clock periods) 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci#define H_POS_UNIT 10 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Indexes in h. code timing table for horizontal line position adjustment 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#define H_TABLE_POS1 6 2862306a36Sopenharmony_ci#define H_TABLE_POS2 8 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Limits of hor. size (hSize) 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* tv standard constants */ 3662306a36Sopenharmony_ci#define NTSC_TV_CLOCK_T 233 3762306a36Sopenharmony_ci#define NTSC_TV_VFTOTAL 1 3862306a36Sopenharmony_ci#define NTSC_TV_LINES_PER_FRAME 525 3962306a36Sopenharmony_ci#define NTSC_TV_ZERO_H_SIZE 479166 4062306a36Sopenharmony_ci#define NTSC_TV_H_SIZE_UNIT 9478 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define PAL_TV_CLOCK_T 188 4362306a36Sopenharmony_ci#define PAL_TV_VFTOTAL 3 4462306a36Sopenharmony_ci#define PAL_TV_LINES_PER_FRAME 625 4562306a36Sopenharmony_ci#define PAL_TV_ZERO_H_SIZE 473200 4662306a36Sopenharmony_ci#define PAL_TV_H_SIZE_UNIT 9360 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* tv pll setting for 27 mhz ref clk */ 4962306a36Sopenharmony_ci#define NTSC_TV_PLL_M_27 22 5062306a36Sopenharmony_ci#define NTSC_TV_PLL_N_27 175 5162306a36Sopenharmony_ci#define NTSC_TV_PLL_P_27 5 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define PAL_TV_PLL_M_27 113 5462306a36Sopenharmony_ci#define PAL_TV_PLL_N_27 668 5562306a36Sopenharmony_ci#define PAL_TV_PLL_P_27 3 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* tv pll setting for 14 mhz ref clk */ 5862306a36Sopenharmony_ci#define NTSC_TV_PLL_M_14 33 5962306a36Sopenharmony_ci#define NTSC_TV_PLL_N_14 693 6062306a36Sopenharmony_ci#define NTSC_TV_PLL_P_14 7 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define PAL_TV_PLL_M_14 19 6362306a36Sopenharmony_ci#define PAL_TV_PLL_N_14 353 6462306a36Sopenharmony_ci#define PAL_TV_PLL_P_14 5 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define VERT_LEAD_IN_LINES 2 6762306a36Sopenharmony_ci#define FRAC_BITS 0xe 6862306a36Sopenharmony_ci#define FRAC_MASK 0x3fff 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct radeon_tv_mode_constants { 7162306a36Sopenharmony_ci uint16_t hor_resolution; 7262306a36Sopenharmony_ci uint16_t ver_resolution; 7362306a36Sopenharmony_ci enum radeon_tv_std standard; 7462306a36Sopenharmony_ci uint16_t hor_total; 7562306a36Sopenharmony_ci uint16_t ver_total; 7662306a36Sopenharmony_ci uint16_t hor_start; 7762306a36Sopenharmony_ci uint16_t hor_syncstart; 7862306a36Sopenharmony_ci uint16_t ver_syncstart; 7962306a36Sopenharmony_ci unsigned def_restart; 8062306a36Sopenharmony_ci uint16_t crtcPLL_N; 8162306a36Sopenharmony_ci uint8_t crtcPLL_M; 8262306a36Sopenharmony_ci uint8_t crtcPLL_post_div; 8362306a36Sopenharmony_ci unsigned pix_to_tv; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const uint16_t hor_timing_NTSC[MAX_H_CODE_TIMING_LEN] = { 8762306a36Sopenharmony_ci 0x0007, 8862306a36Sopenharmony_ci 0x003f, 8962306a36Sopenharmony_ci 0x0263, 9062306a36Sopenharmony_ci 0x0a24, 9162306a36Sopenharmony_ci 0x2a6b, 9262306a36Sopenharmony_ci 0x0a36, 9362306a36Sopenharmony_ci 0x126d, /* H_TABLE_POS1 */ 9462306a36Sopenharmony_ci 0x1bfe, 9562306a36Sopenharmony_ci 0x1a8f, /* H_TABLE_POS2 */ 9662306a36Sopenharmony_ci 0x1ec7, 9762306a36Sopenharmony_ci 0x3863, 9862306a36Sopenharmony_ci 0x1bfe, 9962306a36Sopenharmony_ci 0x1bfe, 10062306a36Sopenharmony_ci 0x1a2a, 10162306a36Sopenharmony_ci 0x1e95, 10262306a36Sopenharmony_ci 0x0e31, 10362306a36Sopenharmony_ci 0x201b, 10462306a36Sopenharmony_ci 0 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const uint16_t vert_timing_NTSC[MAX_V_CODE_TIMING_LEN] = { 10862306a36Sopenharmony_ci 0x2001, 10962306a36Sopenharmony_ci 0x200d, 11062306a36Sopenharmony_ci 0x1006, 11162306a36Sopenharmony_ci 0x0c06, 11262306a36Sopenharmony_ci 0x1006, 11362306a36Sopenharmony_ci 0x1818, 11462306a36Sopenharmony_ci 0x21e3, 11562306a36Sopenharmony_ci 0x1006, 11662306a36Sopenharmony_ci 0x0c06, 11762306a36Sopenharmony_ci 0x1006, 11862306a36Sopenharmony_ci 0x1817, 11962306a36Sopenharmony_ci 0x21d4, 12062306a36Sopenharmony_ci 0x0002, 12162306a36Sopenharmony_ci 0 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic const uint16_t hor_timing_PAL[MAX_H_CODE_TIMING_LEN] = { 12562306a36Sopenharmony_ci 0x0007, 12662306a36Sopenharmony_ci 0x0058, 12762306a36Sopenharmony_ci 0x027c, 12862306a36Sopenharmony_ci 0x0a31, 12962306a36Sopenharmony_ci 0x2a77, 13062306a36Sopenharmony_ci 0x0a95, 13162306a36Sopenharmony_ci 0x124f, /* H_TABLE_POS1 */ 13262306a36Sopenharmony_ci 0x1bfe, 13362306a36Sopenharmony_ci 0x1b22, /* H_TABLE_POS2 */ 13462306a36Sopenharmony_ci 0x1ef9, 13562306a36Sopenharmony_ci 0x387c, 13662306a36Sopenharmony_ci 0x1bfe, 13762306a36Sopenharmony_ci 0x1bfe, 13862306a36Sopenharmony_ci 0x1b31, 13962306a36Sopenharmony_ci 0x1eb5, 14062306a36Sopenharmony_ci 0x0e43, 14162306a36Sopenharmony_ci 0x201b, 14262306a36Sopenharmony_ci 0 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const uint16_t vert_timing_PAL[MAX_V_CODE_TIMING_LEN] = { 14662306a36Sopenharmony_ci 0x2001, 14762306a36Sopenharmony_ci 0x200c, 14862306a36Sopenharmony_ci 0x1005, 14962306a36Sopenharmony_ci 0x0c05, 15062306a36Sopenharmony_ci 0x1005, 15162306a36Sopenharmony_ci 0x1401, 15262306a36Sopenharmony_ci 0x1821, 15362306a36Sopenharmony_ci 0x2240, 15462306a36Sopenharmony_ci 0x1005, 15562306a36Sopenharmony_ci 0x0c05, 15662306a36Sopenharmony_ci 0x1005, 15762306a36Sopenharmony_ci 0x1401, 15862306a36Sopenharmony_ci 0x1822, 15962306a36Sopenharmony_ci 0x2230, 16062306a36Sopenharmony_ci 0x0002, 16162306a36Sopenharmony_ci 0 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/********************************************************************** 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * availableModes 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Table of all allowed modes for tv output 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci **********************************************************************/ 17162306a36Sopenharmony_cistatic const struct radeon_tv_mode_constants available_tv_modes[] = { 17262306a36Sopenharmony_ci { /* NTSC timing for 27 Mhz ref clk */ 17362306a36Sopenharmony_ci 800, /* horResolution */ 17462306a36Sopenharmony_ci 600, /* verResolution */ 17562306a36Sopenharmony_ci TV_STD_NTSC, /* standard */ 17662306a36Sopenharmony_ci 990, /* horTotal */ 17762306a36Sopenharmony_ci 740, /* verTotal */ 17862306a36Sopenharmony_ci 813, /* horStart */ 17962306a36Sopenharmony_ci 824, /* horSyncStart */ 18062306a36Sopenharmony_ci 632, /* verSyncStart */ 18162306a36Sopenharmony_ci 625592, /* defRestart */ 18262306a36Sopenharmony_ci 592, /* crtcPLL_N */ 18362306a36Sopenharmony_ci 91, /* crtcPLL_M */ 18462306a36Sopenharmony_ci 4, /* crtcPLL_postDiv */ 18562306a36Sopenharmony_ci 1022, /* pixToTV */ 18662306a36Sopenharmony_ci }, 18762306a36Sopenharmony_ci { /* PAL timing for 27 Mhz ref clk */ 18862306a36Sopenharmony_ci 800, /* horResolution */ 18962306a36Sopenharmony_ci 600, /* verResolution */ 19062306a36Sopenharmony_ci TV_STD_PAL, /* standard */ 19162306a36Sopenharmony_ci 1144, /* horTotal */ 19262306a36Sopenharmony_ci 706, /* verTotal */ 19362306a36Sopenharmony_ci 812, /* horStart */ 19462306a36Sopenharmony_ci 824, /* horSyncStart */ 19562306a36Sopenharmony_ci 669, /* verSyncStart */ 19662306a36Sopenharmony_ci 696700, /* defRestart */ 19762306a36Sopenharmony_ci 1382, /* crtcPLL_N */ 19862306a36Sopenharmony_ci 231, /* crtcPLL_M */ 19962306a36Sopenharmony_ci 4, /* crtcPLL_postDiv */ 20062306a36Sopenharmony_ci 759, /* pixToTV */ 20162306a36Sopenharmony_ci }, 20262306a36Sopenharmony_ci { /* NTSC timing for 14 Mhz ref clk */ 20362306a36Sopenharmony_ci 800, /* horResolution */ 20462306a36Sopenharmony_ci 600, /* verResolution */ 20562306a36Sopenharmony_ci TV_STD_NTSC, /* standard */ 20662306a36Sopenharmony_ci 1018, /* horTotal */ 20762306a36Sopenharmony_ci 727, /* verTotal */ 20862306a36Sopenharmony_ci 813, /* horStart */ 20962306a36Sopenharmony_ci 840, /* horSyncStart */ 21062306a36Sopenharmony_ci 633, /* verSyncStart */ 21162306a36Sopenharmony_ci 630627, /* defRestart */ 21262306a36Sopenharmony_ci 347, /* crtcPLL_N */ 21362306a36Sopenharmony_ci 14, /* crtcPLL_M */ 21462306a36Sopenharmony_ci 8, /* crtcPLL_postDiv */ 21562306a36Sopenharmony_ci 1022, /* pixToTV */ 21662306a36Sopenharmony_ci }, 21762306a36Sopenharmony_ci { /* PAL timing for 14 Mhz ref clk */ 21862306a36Sopenharmony_ci 800, /* horResolution */ 21962306a36Sopenharmony_ci 600, /* verResolution */ 22062306a36Sopenharmony_ci TV_STD_PAL, /* standard */ 22162306a36Sopenharmony_ci 1131, /* horTotal */ 22262306a36Sopenharmony_ci 742, /* verTotal */ 22362306a36Sopenharmony_ci 813, /* horStart */ 22462306a36Sopenharmony_ci 840, /* horSyncStart */ 22562306a36Sopenharmony_ci 633, /* verSyncStart */ 22662306a36Sopenharmony_ci 708369, /* defRestart */ 22762306a36Sopenharmony_ci 211, /* crtcPLL_N */ 22862306a36Sopenharmony_ci 9, /* crtcPLL_M */ 22962306a36Sopenharmony_ci 8, /* crtcPLL_postDiv */ 23062306a36Sopenharmony_ci 759, /* pixToTV */ 23162306a36Sopenharmony_ci }, 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes) 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder, 23762306a36Sopenharmony_ci uint16_t *pll_ref_freq) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 24062306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 24162306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc; 24262306a36Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 24362306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 24462306a36Sopenharmony_ci struct radeon_pll *pll; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc); 24762306a36Sopenharmony_ci if (radeon_crtc->crtc_id == 1) 24862306a36Sopenharmony_ci pll = &rdev->clock.p2pll; 24962306a36Sopenharmony_ci else 25062306a36Sopenharmony_ci pll = &rdev->clock.p1pll; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (pll_ref_freq) 25362306a36Sopenharmony_ci *pll_ref_freq = pll->reference_freq; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 25662306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 25762306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M) { 25862306a36Sopenharmony_ci if (pll->reference_freq == 2700) 25962306a36Sopenharmony_ci const_ptr = &available_tv_modes[0]; 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci const_ptr = &available_tv_modes[2]; 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci if (pll->reference_freq == 2700) 26462306a36Sopenharmony_ci const_ptr = &available_tv_modes[1]; 26562306a36Sopenharmony_ci else 26662306a36Sopenharmony_ci const_ptr = &available_tv_modes[3]; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci return const_ptr; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; 27262306a36Sopenharmony_cistatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; 27362306a36Sopenharmony_cistatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; 27462306a36Sopenharmony_cistatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic void radeon_wait_pll_lock(struct drm_encoder *encoder, unsigned n_tests, 27762306a36Sopenharmony_ci unsigned n_wait_loops, unsigned cnt_threshold) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 28062306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 28162306a36Sopenharmony_ci uint32_t save_pll_test; 28262306a36Sopenharmony_ci unsigned int i, j; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci WREG32(RADEON_TEST_DEBUG_MUX, (RREG32(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); 28562306a36Sopenharmony_ci save_pll_test = RREG32_PLL(RADEON_PLL_TEST_CNTL); 28662306a36Sopenharmony_ci WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test & ~RADEON_PLL_MASK_READ_B); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); 28962306a36Sopenharmony_ci for (i = 0; i < n_tests; i++) { 29062306a36Sopenharmony_ci WREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); 29162306a36Sopenharmony_ci for (j = 0; j < n_wait_loops; j++) 29262306a36Sopenharmony_ci if (RREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cnt_threshold) 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test); 29662306a36Sopenharmony_ci WREG32(RADEON_TEST_DEBUG_MUX, RREG32(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void radeon_legacy_tv_write_fifo(struct radeon_encoder *radeon_encoder, 30162306a36Sopenharmony_ci uint16_t addr, uint32_t value) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 30462306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 30562306a36Sopenharmony_ci uint32_t tmp; 30662306a36Sopenharmony_ci int i = 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_WRITE_DATA, value); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); 31162306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci do { 31462306a36Sopenharmony_ci tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); 31562306a36Sopenharmony_ci if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci i++; 31862306a36Sopenharmony_ci } while (i < 10000); 31962306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci#if 0 /* included for completeness */ 32362306a36Sopenharmony_cistatic uint32_t radeon_legacy_tv_read_fifo(struct radeon_encoder *radeon_encoder, uint16_t addr) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 32662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 32762306a36Sopenharmony_ci uint32_t tmp; 32862306a36Sopenharmony_ci int i = 0; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr); 33162306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci do { 33462306a36Sopenharmony_ci tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL); 33562306a36Sopenharmony_ci if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci i++; 33862306a36Sopenharmony_ci } while (i < 10000); 33962306a36Sopenharmony_ci WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0); 34062306a36Sopenharmony_ci return RREG32(RADEON_TV_HOST_READ_DATA); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci#endif 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic uint16_t radeon_get_htiming_tables_addr(uint32_t tv_uv_adr) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci uint16_t h_table; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { 34962306a36Sopenharmony_ci case 0: 35062306a36Sopenharmony_ci h_table = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case 1: 35362306a36Sopenharmony_ci h_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case 2: 35662306a36Sopenharmony_ci h_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci default: 35962306a36Sopenharmony_ci h_table = 0; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci return h_table; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic uint16_t radeon_get_vtiming_tables_addr(uint32_t tv_uv_adr) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci uint16_t v_table; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { 37062306a36Sopenharmony_ci case 0: 37162306a36Sopenharmony_ci v_table = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case 1: 37462306a36Sopenharmony_ci v_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case 2: 37762306a36Sopenharmony_ci v_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci default: 38062306a36Sopenharmony_ci v_table = 0; 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci return v_table; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void radeon_restore_tv_timing_tables(struct radeon_encoder *radeon_encoder) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 38962306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 39062306a36Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 39162306a36Sopenharmony_ci uint16_t h_table, v_table; 39262306a36Sopenharmony_ci uint32_t tmp; 39362306a36Sopenharmony_ci int i; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci WREG32(RADEON_TV_UV_ADR, tv_dac->tv.tv_uv_adr); 39662306a36Sopenharmony_ci h_table = radeon_get_htiming_tables_addr(tv_dac->tv.tv_uv_adr); 39762306a36Sopenharmony_ci v_table = radeon_get_vtiming_tables_addr(tv_dac->tv.tv_uv_adr); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, h_table--) { 40062306a36Sopenharmony_ci tmp = ((uint32_t)tv_dac->tv.h_code_timing[i] << 14) | ((uint32_t)tv_dac->tv.h_code_timing[i+1]); 40162306a36Sopenharmony_ci radeon_legacy_tv_write_fifo(radeon_encoder, h_table, tmp); 40262306a36Sopenharmony_ci if (tv_dac->tv.h_code_timing[i] == 0 || tv_dac->tv.h_code_timing[i + 1] == 0) 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, v_table++) { 40662306a36Sopenharmony_ci tmp = ((uint32_t)tv_dac->tv.v_code_timing[i+1] << 14) | ((uint32_t)tv_dac->tv.v_code_timing[i]); 40762306a36Sopenharmony_ci radeon_legacy_tv_write_fifo(radeon_encoder, v_table, tmp); 40862306a36Sopenharmony_ci if (tv_dac->tv.v_code_timing[i] == 0 || tv_dac->tv.v_code_timing[i + 1] == 0) 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encoder) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct drm_device *dev = radeon_encoder->base.dev; 41662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 41762306a36Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 41862306a36Sopenharmony_ci WREG32(RADEON_TV_FRESTART, tv_dac->tv.frestart); 41962306a36Sopenharmony_ci WREG32(RADEON_TV_HRESTART, tv_dac->tv.hrestart); 42062306a36Sopenharmony_ci WREG32(RADEON_TV_VRESTART, tv_dac->tv.vrestart); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 42662306a36Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 42762306a36Sopenharmony_ci int restart; 42862306a36Sopenharmony_ci unsigned int h_total, v_total, f_total; 42962306a36Sopenharmony_ci int v_offset, h_offset; 43062306a36Sopenharmony_ci u16 p1, p2, h_inc; 43162306a36Sopenharmony_ci bool h_changed; 43262306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); 43562306a36Sopenharmony_ci if (!const_ptr) 43662306a36Sopenharmony_ci return false; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci h_total = const_ptr->hor_total; 43962306a36Sopenharmony_ci v_total = const_ptr->ver_total; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 44262306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 44362306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 44462306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) 44562306a36Sopenharmony_ci f_total = NTSC_TV_VFTOTAL + 1; 44662306a36Sopenharmony_ci else 44762306a36Sopenharmony_ci f_total = PAL_TV_VFTOTAL + 1; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* adjust positions 1&2 in hor. cod timing table */ 45062306a36Sopenharmony_ci h_offset = tv_dac->h_pos * H_POS_UNIT; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 45362306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 45462306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M) { 45562306a36Sopenharmony_ci h_offset -= 50; 45662306a36Sopenharmony_ci p1 = hor_timing_NTSC[H_TABLE_POS1]; 45762306a36Sopenharmony_ci p2 = hor_timing_NTSC[H_TABLE_POS2]; 45862306a36Sopenharmony_ci } else { 45962306a36Sopenharmony_ci p1 = hor_timing_PAL[H_TABLE_POS1]; 46062306a36Sopenharmony_ci p2 = hor_timing_PAL[H_TABLE_POS2]; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci p1 = (u16)((int)p1 + h_offset); 46462306a36Sopenharmony_ci p2 = (u16)((int)p2 - h_offset); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci h_changed = (p1 != tv_dac->tv.h_code_timing[H_TABLE_POS1] || 46762306a36Sopenharmony_ci p2 != tv_dac->tv.h_code_timing[H_TABLE_POS2]); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci tv_dac->tv.h_code_timing[H_TABLE_POS1] = p1; 47062306a36Sopenharmony_ci tv_dac->tv.h_code_timing[H_TABLE_POS2] = p2; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ 47362306a36Sopenharmony_ci h_offset = (h_offset * (int)(const_ptr->pix_to_tv)) / 1000; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* adjust restart */ 47662306a36Sopenharmony_ci restart = const_ptr->def_restart; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * convert v_pos TV lines to n. of CRTC pixels 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 48262306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 48362306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 48462306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) 48562306a36Sopenharmony_ci v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(NTSC_TV_LINES_PER_FRAME); 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(PAL_TV_LINES_PER_FRAME); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci restart -= v_offset + h_offset; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci DRM_DEBUG_KMS("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n", 49262306a36Sopenharmony_ci const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci tv_dac->tv.hrestart = restart % h_total; 49562306a36Sopenharmony_ci restart /= h_total; 49662306a36Sopenharmony_ci tv_dac->tv.vrestart = restart % v_total; 49762306a36Sopenharmony_ci restart /= v_total; 49862306a36Sopenharmony_ci tv_dac->tv.frestart = restart % f_total; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci DRM_DEBUG_KMS("compute_restart: F/H/V=%u,%u,%u\n", 50162306a36Sopenharmony_ci (unsigned)tv_dac->tv.frestart, 50262306a36Sopenharmony_ci (unsigned)tv_dac->tv.vrestart, 50362306a36Sopenharmony_ci (unsigned)tv_dac->tv.hrestart); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* compute h_inc from hsize */ 50662306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 50762306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 50862306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M) 50962306a36Sopenharmony_ci h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * NTSC_TV_CLOCK_T) / 51062306a36Sopenharmony_ci (tv_dac->h_size * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); 51162306a36Sopenharmony_ci else 51262306a36Sopenharmony_ci h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * PAL_TV_CLOCK_T) / 51362306a36Sopenharmony_ci (tv_dac->h_size * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) | 51662306a36Sopenharmony_ci ((u32)h_inc << RADEON_H_INC_SHIFT); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci DRM_DEBUG_KMS("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return h_changed; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_civoid radeon_legacy_tv_mode_set(struct drm_encoder *encoder, 52462306a36Sopenharmony_ci struct drm_display_mode *mode, 52562306a36Sopenharmony_ci struct drm_display_mode *adjusted_mode) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct drm_device *dev = encoder->dev; 52862306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 52962306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 53062306a36Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; 53162306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 53262306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc; 53362306a36Sopenharmony_ci int i; 53462306a36Sopenharmony_ci uint16_t pll_ref_freq; 53562306a36Sopenharmony_ci uint32_t vert_space, flicker_removal, tmp; 53662306a36Sopenharmony_ci uint32_t tv_master_cntl, tv_rgb_cntl, tv_dac_cntl; 53762306a36Sopenharmony_ci uint32_t tv_modulator_cntl1, tv_modulator_cntl2; 53862306a36Sopenharmony_ci uint32_t tv_vscaler_cntl1, tv_vscaler_cntl2; 53962306a36Sopenharmony_ci uint32_t tv_pll_cntl, tv_ftotal; 54062306a36Sopenharmony_ci uint32_t tv_y_fall_cntl, tv_y_rise_cntl, tv_y_saw_tooth_cntl; 54162306a36Sopenharmony_ci uint32_t m, n, p; 54262306a36Sopenharmony_ci const uint16_t *hor_timing; 54362306a36Sopenharmony_ci const uint16_t *vert_timing; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, &pll_ref_freq); 54662306a36Sopenharmony_ci if (!const_ptr) 54762306a36Sopenharmony_ci return; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci radeon_crtc = to_radeon_crtc(encoder->crtc); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci tv_master_cntl = (RADEON_VIN_ASYNC_RST | 55262306a36Sopenharmony_ci RADEON_CRT_FIFO_CE_EN | 55362306a36Sopenharmony_ci RADEON_TV_FIFO_CE_EN | 55462306a36Sopenharmony_ci RADEON_TV_ON); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!ASIC_IS_R300(rdev)) 55762306a36Sopenharmony_ci tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 56062306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J) 56162306a36Sopenharmony_ci tv_master_cntl |= RADEON_RESTART_PHASE_FIX; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci tv_modulator_cntl1 = (RADEON_SLEW_RATE_LIMIT | 56462306a36Sopenharmony_ci RADEON_SYNC_TIP_LEVEL | 56562306a36Sopenharmony_ci RADEON_YFLT_EN | 56662306a36Sopenharmony_ci RADEON_UVFLT_EN | 56762306a36Sopenharmony_ci (6 << RADEON_CY_FILT_BLEND_SHIFT)); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 57062306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J) { 57162306a36Sopenharmony_ci tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) | 57262306a36Sopenharmony_ci (0x3b << RADEON_BLANK_LEVEL_SHIFT); 57362306a36Sopenharmony_ci tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | 57462306a36Sopenharmony_ci ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 57562306a36Sopenharmony_ci } else if (tv_dac->tv_std == TV_STD_SCART_PAL) { 57662306a36Sopenharmony_ci tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; 57762306a36Sopenharmony_ci tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | 57862306a36Sopenharmony_ci ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 57962306a36Sopenharmony_ci } else { 58062306a36Sopenharmony_ci tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN | 58162306a36Sopenharmony_ci (0x3b << RADEON_SET_UP_LEVEL_SHIFT) | 58262306a36Sopenharmony_ci (0x3b << RADEON_BLANK_LEVEL_SHIFT); 58362306a36Sopenharmony_ci tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | 58462306a36Sopenharmony_ci ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci tv_rgb_cntl = (RADEON_RGB_DITHER_EN 58962306a36Sopenharmony_ci | RADEON_TVOUT_SCALE_EN 59062306a36Sopenharmony_ci | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) 59162306a36Sopenharmony_ci | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT) 59262306a36Sopenharmony_ci | RADEON_RGB_ATTEN_SEL(0x3) 59362306a36Sopenharmony_ci | RADEON_RGB_ATTEN_VAL(0xc)); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (radeon_crtc->crtc_id == 1) 59662306a36Sopenharmony_ci tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; 59762306a36Sopenharmony_ci else { 59862306a36Sopenharmony_ci if (radeon_crtc->rmx_type != RMX_OFF) 59962306a36Sopenharmony_ci tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; 60062306a36Sopenharmony_ci else 60162306a36Sopenharmony_ci tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 60562306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 60662306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 60762306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) 60862306a36Sopenharmony_ci vert_space = const_ptr->ver_total * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; 60962306a36Sopenharmony_ci else 61062306a36Sopenharmony_ci vert_space = const_ptr->ver_total * 2 * 10000 / PAL_TV_LINES_PER_FRAME; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci tmp = RREG32(RADEON_TV_VSCALER_CNTL1); 61362306a36Sopenharmony_ci tmp &= 0xe3ff0000; 61462306a36Sopenharmony_ci tmp |= (vert_space * (1 << FRAC_BITS) / 10000); 61562306a36Sopenharmony_ci tv_vscaler_cntl1 = tmp; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (pll_ref_freq == 2700) 61862306a36Sopenharmony_ci tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (const_ptr->hor_resolution == 1024) 62162306a36Sopenharmony_ci tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); 62262306a36Sopenharmony_ci else 62362306a36Sopenharmony_ci tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* scale up for int divide */ 62662306a36Sopenharmony_ci tmp = const_ptr->ver_total * 2 * 1000; 62762306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 62862306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 62962306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 63062306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) { 63162306a36Sopenharmony_ci tmp /= NTSC_TV_LINES_PER_FRAME; 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci tmp /= PAL_TV_LINES_PER_FRAME; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci flicker_removal = (tmp + 500) / 1000; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (flicker_removal < 3) 63862306a36Sopenharmony_ci flicker_removal = 3; 63962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) { 64062306a36Sopenharmony_ci if (flicker_removal == SLOPE_limit[i]) 64162306a36Sopenharmony_ci break; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci tv_y_saw_tooth_cntl = (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 64562306a36Sopenharmony_ci 5001) / 10000 / 8 | ((SLOPE_value[i] * 64662306a36Sopenharmony_ci (1 << (FRAC_BITS - 1)) / 8) << 16); 64762306a36Sopenharmony_ci tv_y_fall_cntl = 64862306a36Sopenharmony_ci (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | 64962306a36Sopenharmony_ci RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / 65062306a36Sopenharmony_ci 1024; 65162306a36Sopenharmony_ci tv_y_rise_cntl = RADEON_Y_RISE_PING_PONG| 65262306a36Sopenharmony_ci (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci tv_vscaler_cntl2 = RREG32(RADEON_TV_VSCALER_CNTL2) & 0x00fffff0; 65562306a36Sopenharmony_ci tv_vscaler_cntl2 |= (0x10 << 24) | 65662306a36Sopenharmony_ci RADEON_DITHER_MODE | 65762306a36Sopenharmony_ci RADEON_Y_OUTPUT_DITHER_EN | 65862306a36Sopenharmony_ci RADEON_UV_OUTPUT_DITHER_EN | 65962306a36Sopenharmony_ci RADEON_UV_TO_BUF_DITHER_EN; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci tmp = (tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; 66262306a36Sopenharmony_ci tmp = ((16384 * 256 * 10) / tmp + 5) / 10; 66362306a36Sopenharmony_ci tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; 66462306a36Sopenharmony_ci tv_dac->tv.timing_cntl = tmp; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 66762306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 66862306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 66962306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) 67062306a36Sopenharmony_ci tv_dac_cntl = tv_dac->ntsc_tvdac_adj; 67162306a36Sopenharmony_ci else 67262306a36Sopenharmony_ci tv_dac_cntl = tv_dac->pal_tvdac_adj; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 67762306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J) 67862306a36Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; 67962306a36Sopenharmony_ci else 68062306a36Sopenharmony_ci tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 68362306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J) { 68462306a36Sopenharmony_ci if (pll_ref_freq == 2700) { 68562306a36Sopenharmony_ci m = NTSC_TV_PLL_M_27; 68662306a36Sopenharmony_ci n = NTSC_TV_PLL_N_27; 68762306a36Sopenharmony_ci p = NTSC_TV_PLL_P_27; 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci m = NTSC_TV_PLL_M_14; 69062306a36Sopenharmony_ci n = NTSC_TV_PLL_N_14; 69162306a36Sopenharmony_ci p = NTSC_TV_PLL_P_14; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci } else { 69462306a36Sopenharmony_ci if (pll_ref_freq == 2700) { 69562306a36Sopenharmony_ci m = PAL_TV_PLL_M_27; 69662306a36Sopenharmony_ci n = PAL_TV_PLL_N_27; 69762306a36Sopenharmony_ci p = PAL_TV_PLL_P_27; 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci m = PAL_TV_PLL_M_14; 70062306a36Sopenharmony_ci n = PAL_TV_PLL_N_14; 70162306a36Sopenharmony_ci p = PAL_TV_PLL_P_14; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) | 70662306a36Sopenharmony_ci (((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | 70762306a36Sopenharmony_ci ((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | 70862306a36Sopenharmony_ci (((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | 70962306a36Sopenharmony_ci ((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci tv_dac->tv.tv_uv_adr = 0xc8; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (tv_dac->tv_std == TV_STD_NTSC || 71462306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_NTSC_J || 71562306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_M || 71662306a36Sopenharmony_ci tv_dac->tv_std == TV_STD_PAL_60) { 71762306a36Sopenharmony_ci tv_ftotal = NTSC_TV_VFTOTAL; 71862306a36Sopenharmony_ci hor_timing = hor_timing_NTSC; 71962306a36Sopenharmony_ci vert_timing = vert_timing_NTSC; 72062306a36Sopenharmony_ci } else { 72162306a36Sopenharmony_ci hor_timing = hor_timing_PAL; 72262306a36Sopenharmony_ci vert_timing = vert_timing_PAL; 72362306a36Sopenharmony_ci tv_ftotal = PAL_TV_VFTOTAL; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { 72762306a36Sopenharmony_ci tv_dac->tv.h_code_timing[i] = hor_timing[i]; 72862306a36Sopenharmony_ci if (tv_dac->tv.h_code_timing[i] == 0) 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { 73362306a36Sopenharmony_ci tv_dac->tv.v_code_timing[i] = vert_timing[i]; 73462306a36Sopenharmony_ci if (tv_dac->tv.v_code_timing[i] == 0) 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci radeon_legacy_tv_init_restarts(encoder); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* play with DAC_CNTL */ 74162306a36Sopenharmony_ci /* play with GPIOPAD_A */ 74262306a36Sopenharmony_ci /* DISP_OUTPUT_CNTL */ 74362306a36Sopenharmony_ci /* use reference freq */ 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* program the TV registers */ 74662306a36Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | 74762306a36Sopenharmony_ci RADEON_CRT_ASYNC_RST | RADEON_TV_FIFO_ASYNC_RST)); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci tmp = RREG32(RADEON_TV_DAC_CNTL); 75062306a36Sopenharmony_ci tmp &= ~RADEON_TV_DAC_NBLANK; 75162306a36Sopenharmony_ci tmp |= RADEON_TV_DAC_BGSLEEP | 75262306a36Sopenharmony_ci RADEON_TV_DAC_RDACPD | 75362306a36Sopenharmony_ci RADEON_TV_DAC_GDACPD | 75462306a36Sopenharmony_ci RADEON_TV_DAC_BDACPD; 75562306a36Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tmp); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* TV PLL */ 75862306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); 75962306a36Sopenharmony_ci WREG32_PLL(RADEON_TV_PLL_CNTL, tv_pll_cntl); 76062306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci radeon_wait_pll_lock(encoder, 200, 800, 135); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci radeon_wait_pll_lock(encoder, 300, 160, 27); 76762306a36Sopenharmony_ci radeon_wait_pll_lock(encoder, 200, 800, 135); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~0xf); 77062306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); 77362306a36Sopenharmony_ci WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* TV HV */ 77662306a36Sopenharmony_ci WREG32(RADEON_TV_RGB_CNTL, tv_rgb_cntl); 77762306a36Sopenharmony_ci WREG32(RADEON_TV_HTOTAL, const_ptr->hor_total - 1); 77862306a36Sopenharmony_ci WREG32(RADEON_TV_HDISP, const_ptr->hor_resolution - 1); 77962306a36Sopenharmony_ci WREG32(RADEON_TV_HSTART, const_ptr->hor_start); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci WREG32(RADEON_TV_VTOTAL, const_ptr->ver_total - 1); 78262306a36Sopenharmony_ci WREG32(RADEON_TV_VDISP, const_ptr->ver_resolution - 1); 78362306a36Sopenharmony_ci WREG32(RADEON_TV_FTOTAL, tv_ftotal); 78462306a36Sopenharmony_ci WREG32(RADEON_TV_VSCALER_CNTL1, tv_vscaler_cntl1); 78562306a36Sopenharmony_ci WREG32(RADEON_TV_VSCALER_CNTL2, tv_vscaler_cntl2); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci WREG32(RADEON_TV_Y_FALL_CNTL, tv_y_fall_cntl); 78862306a36Sopenharmony_ci WREG32(RADEON_TV_Y_RISE_CNTL, tv_y_rise_cntl); 78962306a36Sopenharmony_ci WREG32(RADEON_TV_Y_SAW_TOOTH_CNTL, tv_y_saw_tooth_cntl); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST | 79262306a36Sopenharmony_ci RADEON_CRT_ASYNC_RST)); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* TV restarts */ 79562306a36Sopenharmony_ci radeon_legacy_write_tv_restarts(radeon_encoder); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* tv timings */ 79862306a36Sopenharmony_ci radeon_restore_tv_timing_tables(radeon_encoder); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST)); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* tv std */ 80362306a36Sopenharmony_ci WREG32(RADEON_TV_SYNC_CNTL, (RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE)); 80462306a36Sopenharmony_ci WREG32(RADEON_TV_TIMING_CNTL, tv_dac->tv.timing_cntl); 80562306a36Sopenharmony_ci WREG32(RADEON_TV_MODULATOR_CNTL1, tv_modulator_cntl1); 80662306a36Sopenharmony_ci WREG32(RADEON_TV_MODULATOR_CNTL2, tv_modulator_cntl2); 80762306a36Sopenharmony_ci WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, (RADEON_Y_RED_EN | 80862306a36Sopenharmony_ci RADEON_C_GRN_EN | 80962306a36Sopenharmony_ci RADEON_CMP_BLU_EN | 81062306a36Sopenharmony_ci RADEON_DAC_DITHER_EN)); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci WREG32(RADEON_TV_CRC_CNTL, 0); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci WREG32(RADEON_TV_GAIN_LIMIT_SETTINGS, ((0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | 81762306a36Sopenharmony_ci (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT))); 81862306a36Sopenharmony_ci WREG32(RADEON_TV_LINEAR_GAIN_SETTINGS, ((0x100 << RADEON_UV_GAIN_SHIFT) | 81962306a36Sopenharmony_ci (0x100 << RADEON_Y_GAIN_SHIFT))); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_civoid radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder, 82662306a36Sopenharmony_ci uint32_t *h_total_disp, uint32_t *h_sync_strt_wid, 82762306a36Sopenharmony_ci uint32_t *v_total_disp, uint32_t *v_sync_strt_wid) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 83062306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 83162306a36Sopenharmony_ci uint32_t tmp; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); 83462306a36Sopenharmony_ci if (!const_ptr) 83562306a36Sopenharmony_ci return; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci *h_total_disp = (((const_ptr->hor_resolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 83862306a36Sopenharmony_ci (((const_ptr->hor_total / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci tmp = *h_sync_strt_wid; 84162306a36Sopenharmony_ci tmp &= ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR); 84262306a36Sopenharmony_ci tmp |= (((const_ptr->hor_syncstart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 84362306a36Sopenharmony_ci (const_ptr->hor_syncstart & 7); 84462306a36Sopenharmony_ci *h_sync_strt_wid = tmp; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci *v_total_disp = ((const_ptr->ver_resolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 84762306a36Sopenharmony_ci ((const_ptr->ver_total - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci tmp = *v_sync_strt_wid; 85062306a36Sopenharmony_ci tmp &= ~RADEON_CRTC_V_SYNC_STRT; 85162306a36Sopenharmony_ci tmp |= ((const_ptr->ver_syncstart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 85262306a36Sopenharmony_ci *v_sync_strt_wid = tmp; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int get_post_div(int value) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci int post_div; 85862306a36Sopenharmony_ci switch (value) { 85962306a36Sopenharmony_ci case 1: post_div = 0; break; 86062306a36Sopenharmony_ci case 2: post_div = 1; break; 86162306a36Sopenharmony_ci case 3: post_div = 4; break; 86262306a36Sopenharmony_ci case 4: post_div = 2; break; 86362306a36Sopenharmony_ci case 6: post_div = 6; break; 86462306a36Sopenharmony_ci case 8: post_div = 3; break; 86562306a36Sopenharmony_ci case 12: post_div = 7; break; 86662306a36Sopenharmony_ci case 16: 86762306a36Sopenharmony_ci default: post_div = 5; break; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci return post_div; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_civoid radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder, 87362306a36Sopenharmony_ci uint32_t *htotal_cntl, uint32_t *ppll_ref_div, 87462306a36Sopenharmony_ci uint32_t *ppll_div_3, uint32_t *pixclks_cntl) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 87762306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); 88062306a36Sopenharmony_ci if (!const_ptr) 88162306a36Sopenharmony_ci return; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci *htotal_cntl = (const_ptr->hor_total & 0x7) | RADEON_HTOT_CNTL_VGA_EN; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci *ppll_ref_div = const_ptr->crtcPLL_M; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci *ppll_div_3 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); 88862306a36Sopenharmony_ci *pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); 88962306a36Sopenharmony_ci *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_civoid radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, 89362306a36Sopenharmony_ci uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div, 89462306a36Sopenharmony_ci uint32_t *p2pll_div_0, uint32_t *pixclks_cntl) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 89762306a36Sopenharmony_ci const struct radeon_tv_mode_constants *const_ptr; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL); 90062306a36Sopenharmony_ci if (!const_ptr) 90162306a36Sopenharmony_ci return; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci *htotal2_cntl = (const_ptr->hor_total & 0x7); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci *p2pll_ref_div = const_ptr->crtcPLL_M; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci *p2pll_div_0 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16); 90862306a36Sopenharmony_ci *pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; 90962306a36Sopenharmony_ci *pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK | RADEON_PIXCLK_TV_SRC_SEL; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 912