radeon_tv.c revision c503f109
1209ff23fSmrg/* 2209ff23fSmrg * Integrated TV out support based on the GATOS code by 3209ff23fSmrg * Federico Ulivi <fulivi@lycos.com> 4209ff23fSmrg */ 5209ff23fSmrg 6209ff23fSmrg#ifdef HAVE_CONFIG_H 7209ff23fSmrg#include "config.h" 8209ff23fSmrg#endif 9209ff23fSmrg 10209ff23fSmrg#include <string.h> 11209ff23fSmrg#include <stdio.h> 12209ff23fSmrg 13209ff23fSmrg/* X and server generic header files */ 14209ff23fSmrg#include "xf86.h" 15209ff23fSmrg#include "xf86_OSproc.h" 16209ff23fSmrg#include "vgaHW.h" 17209ff23fSmrg#include "xf86Modes.h" 18209ff23fSmrg 19209ff23fSmrg/* Driver data structures */ 20209ff23fSmrg#include "radeon.h" 21209ff23fSmrg#include "radeon_reg.h" 22209ff23fSmrg#include "radeon_macros.h" 23209ff23fSmrg#include "radeon_probe.h" 24209ff23fSmrg#include "radeon_version.h" 25209ff23fSmrg#include "radeon_tv.h" 26b7e1c893Smrg#include "radeon_atombios.h" 27209ff23fSmrg 28209ff23fSmrg/********************************************************************** 29209ff23fSmrg * 30209ff23fSmrg * ModeConstants 31209ff23fSmrg * 32209ff23fSmrg * Storage of constants related to a single video mode 33209ff23fSmrg * 34209ff23fSmrg **********************************************************************/ 35209ff23fSmrg 36209ff23fSmrgtypedef struct 37209ff23fSmrg{ 38209ff23fSmrg uint16_t horResolution; 39209ff23fSmrg uint16_t verResolution; 40209ff23fSmrg TVStd standard; 41209ff23fSmrg uint16_t horTotal; 42209ff23fSmrg uint16_t verTotal; 43209ff23fSmrg uint16_t horStart; 44209ff23fSmrg uint16_t horSyncStart; 45209ff23fSmrg uint16_t verSyncStart; 46209ff23fSmrg unsigned defRestart; 47209ff23fSmrg uint16_t crtcPLL_N; 48209ff23fSmrg uint8_t crtcPLL_M; 49209ff23fSmrg uint8_t crtcPLL_postDiv; 50209ff23fSmrg unsigned pixToTV; 51209ff23fSmrg} TVModeConstants; 52209ff23fSmrg 53209ff23fSmrgstatic const uint16_t hor_timing_NTSC[] = 54209ff23fSmrg{ 55209ff23fSmrg 0x0007, 56209ff23fSmrg 0x003f, 57209ff23fSmrg 0x0263, 58209ff23fSmrg 0x0a24, 59209ff23fSmrg 0x2a6b, 60209ff23fSmrg 0x0a36, 61209ff23fSmrg 0x126d, /* H_TABLE_POS1 */ 62209ff23fSmrg 0x1bfe, 63209ff23fSmrg 0x1a8f, /* H_TABLE_POS2 */ 64209ff23fSmrg 0x1ec7, 65209ff23fSmrg 0x3863, 66209ff23fSmrg 0x1bfe, 67209ff23fSmrg 0x1bfe, 68209ff23fSmrg 0x1a2a, 69209ff23fSmrg 0x1e95, 70209ff23fSmrg 0x0e31, 71209ff23fSmrg 0x201b, 72209ff23fSmrg 0 73209ff23fSmrg}; 74209ff23fSmrg 75209ff23fSmrgstatic const uint16_t vert_timing_NTSC[] = 76209ff23fSmrg{ 77209ff23fSmrg 0x2001, 78209ff23fSmrg 0x200d, 79209ff23fSmrg 0x1006, 80209ff23fSmrg 0x0c06, 81209ff23fSmrg 0x1006, 82209ff23fSmrg 0x1818, 83209ff23fSmrg 0x21e3, 84209ff23fSmrg 0x1006, 85209ff23fSmrg 0x0c06, 86209ff23fSmrg 0x1006, 87209ff23fSmrg 0x1817, 88209ff23fSmrg 0x21d4, 89209ff23fSmrg 0x0002, 90209ff23fSmrg 0 91209ff23fSmrg}; 92209ff23fSmrg 93209ff23fSmrgstatic const uint16_t hor_timing_PAL[] = 94209ff23fSmrg{ 95209ff23fSmrg 0x0007, 96209ff23fSmrg 0x0058, 97209ff23fSmrg 0x027c, 98209ff23fSmrg 0x0a31, 99209ff23fSmrg 0x2a77, 100209ff23fSmrg 0x0a95, 101209ff23fSmrg 0x124f, /* H_TABLE_POS1 */ 102209ff23fSmrg 0x1bfe, 103209ff23fSmrg 0x1b22, /* H_TABLE_POS2 */ 104209ff23fSmrg 0x1ef9, 105209ff23fSmrg 0x387c, 106209ff23fSmrg 0x1bfe, 107209ff23fSmrg 0x1bfe, 108209ff23fSmrg 0x1b31, 109209ff23fSmrg 0x1eb5, 110209ff23fSmrg 0x0e43, 111209ff23fSmrg 0x201b, 112209ff23fSmrg 0 113209ff23fSmrg}; 114209ff23fSmrg 115209ff23fSmrgstatic const uint16_t vert_timing_PAL[] = 116209ff23fSmrg{ 117209ff23fSmrg 0x2001, 118209ff23fSmrg 0x200c, 119209ff23fSmrg 0x1005, 120209ff23fSmrg 0x0c05, 121209ff23fSmrg 0x1005, 122209ff23fSmrg 0x1401, 123209ff23fSmrg 0x1821, 124209ff23fSmrg 0x2240, 125209ff23fSmrg 0x1005, 126209ff23fSmrg 0x0c05, 127209ff23fSmrg 0x1005, 128209ff23fSmrg 0x1401, 129209ff23fSmrg 0x1822, 130209ff23fSmrg 0x2230, 131209ff23fSmrg 0x0002, 132209ff23fSmrg 0 133209ff23fSmrg}; 134209ff23fSmrg 135209ff23fSmrg/********************************************************************** 136209ff23fSmrg * 137209ff23fSmrg * availableModes 138209ff23fSmrg * 139209ff23fSmrg * Table of all allowed modes for tv output 140209ff23fSmrg * 141209ff23fSmrg **********************************************************************/ 142209ff23fSmrgstatic const TVModeConstants availableTVModes[] = 143209ff23fSmrg{ 144b7e1c893Smrg { /* NTSC timing for 27 Mhz ref clk */ 145209ff23fSmrg 800, /* horResolution */ 146209ff23fSmrg 600, /* verResolution */ 147209ff23fSmrg TV_STD_NTSC, /* standard */ 148209ff23fSmrg 990, /* horTotal */ 149209ff23fSmrg 740, /* verTotal */ 150209ff23fSmrg 813, /* horStart */ 151209ff23fSmrg 824, /* horSyncStart */ 152209ff23fSmrg 632, /* verSyncStart */ 153209ff23fSmrg 625592, /* defRestart */ 154209ff23fSmrg 592, /* crtcPLL_N */ 155209ff23fSmrg 91, /* crtcPLL_M */ 156209ff23fSmrg 4, /* crtcPLL_postDiv */ 157209ff23fSmrg 1022, /* pixToTV */ 158209ff23fSmrg }, 159b7e1c893Smrg { /* PAL timing for 27 Mhz ref clk */ 160209ff23fSmrg 800, /* horResolution */ 161209ff23fSmrg 600, /* verResolution */ 162209ff23fSmrg TV_STD_PAL, /* standard */ 163209ff23fSmrg 1144, /* horTotal */ 164209ff23fSmrg 706, /* verTotal */ 165209ff23fSmrg 812, /* horStart */ 166209ff23fSmrg 824, /* horSyncStart */ 167209ff23fSmrg 669, /* verSyncStart */ 168209ff23fSmrg 696700, /* defRestart */ 169209ff23fSmrg 1382, /* crtcPLL_N */ 170209ff23fSmrg 231, /* crtcPLL_M */ 171209ff23fSmrg 4, /* crtcPLL_postDiv */ 172209ff23fSmrg 759, /* pixToTV */ 173b7e1c893Smrg }, 174b7e1c893Smrg { /* NTSC timing for 14 Mhz ref clk */ 175b7e1c893Smrg 800, /* horResolution */ 176b7e1c893Smrg 600, /* verResolution */ 177b7e1c893Smrg TV_STD_NTSC, /* standard */ 178b7e1c893Smrg 1018, /* horTotal */ 179b7e1c893Smrg 727, /* verTotal */ 180b7e1c893Smrg 813, /* horStart */ 181b7e1c893Smrg 840, /* horSyncStart */ 182b7e1c893Smrg 633, /* verSyncStart */ 183b7e1c893Smrg 630627, /* defRestart */ 184b7e1c893Smrg 347, /* crtcPLL_N */ 185b7e1c893Smrg 14, /* crtcPLL_M */ 186b7e1c893Smrg 8, /* crtcPLL_postDiv */ 187b7e1c893Smrg 1022, /* pixToTV */ 188b7e1c893Smrg }, 189209ff23fSmrg}; 190209ff23fSmrg 191209ff23fSmrg#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ])) 192209ff23fSmrg 193209ff23fSmrgstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; 194209ff23fSmrgstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; 195209ff23fSmrgstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; 196209ff23fSmrgstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; 197209ff23fSmrg 198209ff23fSmrg 199209ff23fSmrgstatic void 200209ff23fSmrgRADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, 201209ff23fSmrg unsigned nWaitLoops, unsigned cntThreshold) 202209ff23fSmrg{ 203209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 204209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 205209ff23fSmrg uint32_t savePLLTest; 206209ff23fSmrg unsigned i; 207209ff23fSmrg unsigned j; 208209ff23fSmrg 209209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); 210209ff23fSmrg 211209ff23fSmrg savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL); 212209ff23fSmrg 213209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B); 214209ff23fSmrg 215209ff23fSmrg /* XXX: these should probably be OUTPLL to avoid various PLL errata */ 216209ff23fSmrg 217209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); 218209ff23fSmrg 219209ff23fSmrg for (i = 0; i < nTests; i++) { 220209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); 221209ff23fSmrg 222209ff23fSmrg for (j = 0; j < nWaitLoops; j++) 223209ff23fSmrg if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold) 224209ff23fSmrg break; 225209ff23fSmrg } 226209ff23fSmrg 227209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest); 228209ff23fSmrg 229209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); 230209ff23fSmrg} 231209ff23fSmrg 232209ff23fSmrg/* Write to TV FIFO RAM */ 233209ff23fSmrgstatic void 234209ff23fSmrgRADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr, 235209ff23fSmrg uint32_t value) 236209ff23fSmrg{ 237209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 238209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 239209ff23fSmrg uint32_t tmp; 240209ff23fSmrg int i = 0; 241209ff23fSmrg 242209ff23fSmrg OUTREG(RADEON_TV_HOST_WRITE_DATA, value); 243209ff23fSmrg 244209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 245209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); 246209ff23fSmrg 247209ff23fSmrg do { 248209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 249209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) 250209ff23fSmrg break; 251209ff23fSmrg i++; 252209ff23fSmrg } 253209ff23fSmrg while (i < 10000); 254209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ 255209ff23fSmrg 256209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 257209ff23fSmrg} 258209ff23fSmrg 259209ff23fSmrg/* Read from TV FIFO RAM */ 260209ff23fSmrgstatic uint32_t 261209ff23fSmrgRADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr) 262209ff23fSmrg{ 263209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 264209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 265209ff23fSmrg uint32_t tmp; 266209ff23fSmrg int i = 0; 267209ff23fSmrg 268209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 269209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); 270209ff23fSmrg 271209ff23fSmrg do { 272209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 273209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) 274209ff23fSmrg break; 275209ff23fSmrg i++; 276209ff23fSmrg } 277209ff23fSmrg while (i < 10000); 278209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/ 279209ff23fSmrg 280209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 281209ff23fSmrg 282209ff23fSmrg return INREG(RADEON_TV_HOST_READ_DATA); 283209ff23fSmrg} 284209ff23fSmrg 285209ff23fSmrg/* Get FIFO addresses of horizontal & vertical code timing tables from 286209ff23fSmrg * settings of uv_adr register. 287209ff23fSmrg */ 288209ff23fSmrgstatic uint16_t 289209ff23fSmrgRADEONGetHTimingTablesAddr(uint32_t tv_uv_adr) 290209ff23fSmrg{ 291209ff23fSmrg uint16_t hTable; 292209ff23fSmrg 293209ff23fSmrg switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { 294209ff23fSmrg case 0: 295209ff23fSmrg hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; 296209ff23fSmrg break; 297209ff23fSmrg case 1: 298209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; 299209ff23fSmrg break; 300209ff23fSmrg case 2: 301209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; 302209ff23fSmrg break; 303209ff23fSmrg default: 304209ff23fSmrg /* Of course, this should never happen */ 305209ff23fSmrg hTable = 0; 306209ff23fSmrg break; 307209ff23fSmrg } 308209ff23fSmrg return hTable; 309209ff23fSmrg} 310209ff23fSmrg 311209ff23fSmrgstatic uint16_t 312209ff23fSmrgRADEONGetVTimingTablesAddr(uint32_t tv_uv_adr) 313209ff23fSmrg{ 314209ff23fSmrg uint16_t vTable; 315209ff23fSmrg 316209ff23fSmrg switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { 317209ff23fSmrg case 0: 318209ff23fSmrg vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; 319209ff23fSmrg break; 320209ff23fSmrg case 1: 321209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; 322209ff23fSmrg break; 323209ff23fSmrg case 2: 324209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; 325209ff23fSmrg break; 326209ff23fSmrg default: 327209ff23fSmrg /* Of course, this should never happen */ 328209ff23fSmrg vTable = 0; 329209ff23fSmrg break; 330209ff23fSmrg } 331209ff23fSmrg return vTable; 332209ff23fSmrg} 333209ff23fSmrg 334209ff23fSmrg/* Restore horizontal/vertical timing code tables */ 335209ff23fSmrgstatic void 336209ff23fSmrgRADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore) 337209ff23fSmrg{ 338209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 339209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 340209ff23fSmrg uint16_t hTable; 341209ff23fSmrg uint16_t vTable; 342209ff23fSmrg uint32_t tmp; 343209ff23fSmrg unsigned i; 344209ff23fSmrg 345209ff23fSmrg OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr); 346209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr); 347209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr); 348209ff23fSmrg 349209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) { 350209ff23fSmrg tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]); 351209ff23fSmrg RADEONWriteTVFIFO(pScrn, hTable, tmp); 352209ff23fSmrg if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0) 353209ff23fSmrg break; 354209ff23fSmrg } 355209ff23fSmrg 356209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) { 357209ff23fSmrg tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]); 358209ff23fSmrg RADEONWriteTVFIFO(pScrn, vTable, tmp); 359209ff23fSmrg if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0) 360209ff23fSmrg break; 361209ff23fSmrg } 362209ff23fSmrg} 363209ff23fSmrg 364209ff23fSmrg/* restore TV PLLs */ 365209ff23fSmrgstatic void 366209ff23fSmrgRADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 367209ff23fSmrg{ 368209ff23fSmrg 369209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); 370209ff23fSmrg OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl); 371209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); 372209ff23fSmrg 373209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 374209ff23fSmrg 375209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); 376209ff23fSmrg 377209ff23fSmrg RADEONWaitPLLLock(pScrn, 300, 160, 27); 378209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 379209ff23fSmrg 380209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf); 381209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); 382209ff23fSmrg 383209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); 384209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); 385209ff23fSmrg} 386209ff23fSmrg 387209ff23fSmrg/* Restore TV horizontal/vertical settings */ 388209ff23fSmrgstatic void 389209ff23fSmrgRADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 390209ff23fSmrg{ 391209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 392209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 393209ff23fSmrg 394209ff23fSmrg OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl); 395209ff23fSmrg 396209ff23fSmrg OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal); 397209ff23fSmrg OUTREG(RADEON_TV_HDISP, restore->tv_hdisp); 398209ff23fSmrg OUTREG(RADEON_TV_HSTART, restore->tv_hstart); 399209ff23fSmrg 400209ff23fSmrg OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal); 401209ff23fSmrg OUTREG(RADEON_TV_VDISP, restore->tv_vdisp); 402209ff23fSmrg 403209ff23fSmrg OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal); 404209ff23fSmrg 405209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1); 406209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2); 407209ff23fSmrg 408209ff23fSmrg OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl); 409209ff23fSmrg OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl); 410209ff23fSmrg OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl); 411209ff23fSmrg} 412209ff23fSmrg 413209ff23fSmrg/* restore TV RESTART registers */ 414209ff23fSmrgstatic void 415209ff23fSmrgRADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore) 416209ff23fSmrg{ 417209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 418209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 419209ff23fSmrg 420209ff23fSmrg OUTREG(RADEON_TV_FRESTART, restore->tv_frestart); 421209ff23fSmrg OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart); 422209ff23fSmrg OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart); 423209ff23fSmrg} 424209ff23fSmrg 425209ff23fSmrg/* restore tv standard & output muxes */ 426209ff23fSmrgstatic void 427209ff23fSmrgRADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore) 428209ff23fSmrg{ 429209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 430209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 431209ff23fSmrg 432209ff23fSmrg OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl); 433209ff23fSmrg 434209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 435209ff23fSmrg 436209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1); 437209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2); 438209ff23fSmrg 439209ff23fSmrg OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl); 440209ff23fSmrg 441209ff23fSmrg OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl); 442209ff23fSmrg} 443209ff23fSmrg 444209ff23fSmrg/* Restore TV out regs */ 445209ff23fSmrgvoid 446209ff23fSmrgRADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 447209ff23fSmrg{ 448209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 449209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 450209ff23fSmrg 451209ff23fSmrg ErrorF("Entering Restore TV\n"); 452209ff23fSmrg 453209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 454209ff23fSmrg | RADEON_TV_ASYNC_RST 455209ff23fSmrg | RADEON_CRT_ASYNC_RST 456209ff23fSmrg | RADEON_TV_FIFO_ASYNC_RST)); 457209ff23fSmrg 458209ff23fSmrg /* Temporarily turn the TV DAC off */ 459209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK) 460209ff23fSmrg | RADEON_TV_DAC_BGSLEEP 461209ff23fSmrg | RADEON_TV_DAC_RDACPD 462209ff23fSmrg | RADEON_TV_DAC_GDACPD 463209ff23fSmrg | RADEON_TV_DAC_BDACPD)); 464209ff23fSmrg 465209ff23fSmrg ErrorF("Restore TV PLL\n"); 466209ff23fSmrg RADEONRestoreTVPLLRegisters(pScrn, restore); 467209ff23fSmrg 468209ff23fSmrg ErrorF("Restore TVHV\n"); 469209ff23fSmrg RADEONRestoreTVHVRegisters(pScrn, restore); 470209ff23fSmrg 471209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 472209ff23fSmrg | RADEON_TV_ASYNC_RST 473209ff23fSmrg | RADEON_CRT_ASYNC_RST)); 474209ff23fSmrg 475209ff23fSmrg ErrorF("Restore TV Restarts\n"); 476209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 477209ff23fSmrg 478209ff23fSmrg ErrorF("Restore Timing Tables\n"); 479209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 480209ff23fSmrg 481209ff23fSmrg 482209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 483209ff23fSmrg | RADEON_TV_ASYNC_RST)); 484209ff23fSmrg 485209ff23fSmrg ErrorF("Restore TV standard\n"); 486209ff23fSmrg RADEONRestoreTVOutputStd(pScrn, restore); 487209ff23fSmrg 488209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 489209ff23fSmrg 490209ff23fSmrg OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); 491209ff23fSmrg OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); 492209ff23fSmrg 493209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); 494209ff23fSmrg 495209ff23fSmrg ErrorF("Leaving Restore TV\n"); 496209ff23fSmrg} 497209ff23fSmrg 498209ff23fSmrg/* Save horizontal/vertical timing code tables */ 499209ff23fSmrgstatic void 500209ff23fSmrgRADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save) 501209ff23fSmrg{ 502209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 503209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 504209ff23fSmrg uint16_t hTable; 505209ff23fSmrg uint16_t vTable; 506209ff23fSmrg uint32_t tmp; 507209ff23fSmrg unsigned i; 508209ff23fSmrg 509209ff23fSmrg save->tv_uv_adr = INREG(RADEON_TV_UV_ADR); 510209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr); 511209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr); 512209ff23fSmrg 513209ff23fSmrg /* 514209ff23fSmrg * Reset FIFO arbiter in order to be able to access FIFO RAM 515209ff23fSmrg */ 516209ff23fSmrg 517209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST 518209ff23fSmrg | RADEON_CRT_ASYNC_RST 519209ff23fSmrg | RADEON_RESTART_PHASE_FIX 520209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 521209ff23fSmrg | RADEON_TV_FIFO_CE_EN 522209ff23fSmrg | RADEON_TV_ON)); 523209ff23fSmrg 524209ff23fSmrg /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/ 525209ff23fSmrg 526209ff23fSmrg ErrorF("saveTimingTables: reading timing tables\n"); 527209ff23fSmrg 528209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) { 529209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, hTable--); 530209ff23fSmrg save->h_code_timing[ i ] = (uint16_t)((tmp >> 14) & 0x3fff); 531209ff23fSmrg save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff); 532209ff23fSmrg 533209ff23fSmrg if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0) 534209ff23fSmrg break; 535209ff23fSmrg } 536209ff23fSmrg 537209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) { 538209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, vTable++); 539209ff23fSmrg save->v_code_timing[ i ] = (uint16_t)(tmp & 0x3fff); 540209ff23fSmrg save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff); 541209ff23fSmrg 542209ff23fSmrg if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0) 543209ff23fSmrg break; 544209ff23fSmrg } 545209ff23fSmrg} 546209ff23fSmrg 547209ff23fSmrg/* read TV regs */ 548209ff23fSmrgvoid 549209ff23fSmrgRADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) 550209ff23fSmrg{ 551209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 552209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 553209ff23fSmrg 554209ff23fSmrg ErrorF("Entering TV Save\n"); 555209ff23fSmrg 556209ff23fSmrg save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL); 557209ff23fSmrg save->tv_frestart = INREG(RADEON_TV_FRESTART); 558209ff23fSmrg save->tv_hrestart = INREG(RADEON_TV_HRESTART); 559209ff23fSmrg save->tv_vrestart = INREG(RADEON_TV_VRESTART); 560209ff23fSmrg save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS); 561209ff23fSmrg save->tv_hdisp = INREG(RADEON_TV_HDISP); 562209ff23fSmrg save->tv_hstart = INREG(RADEON_TV_HSTART); 563209ff23fSmrg save->tv_htotal = INREG(RADEON_TV_HTOTAL); 564209ff23fSmrg save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS); 565209ff23fSmrg save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL); 566209ff23fSmrg save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL); 567209ff23fSmrg save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1); 568209ff23fSmrg save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2); 569209ff23fSmrg save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); 570209ff23fSmrg save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL); 571209ff23fSmrg save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL); 572209ff23fSmrg save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); 573209ff23fSmrg save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL); 574209ff23fSmrg save->tv_vdisp = INREG(RADEON_TV_VDISP); 575209ff23fSmrg save->tv_ftotal = INREG(RADEON_TV_FTOTAL); 576209ff23fSmrg save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1); 577209ff23fSmrg save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2); 578209ff23fSmrg save->tv_vtotal = INREG(RADEON_TV_VTOTAL); 579209ff23fSmrg save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL); 580209ff23fSmrg save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL); 581209ff23fSmrg save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL); 582209ff23fSmrg 583209ff23fSmrg save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL); 584209ff23fSmrg save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1); 585209ff23fSmrg 586209ff23fSmrg ErrorF("Save TV timing tables\n"); 587209ff23fSmrg 588209ff23fSmrg RADEONSaveTVTimingTables(pScrn, save); 589209ff23fSmrg 590209ff23fSmrg ErrorF("TV Save done\n"); 591209ff23fSmrg} 592209ff23fSmrg 593209ff23fSmrg 594209ff23fSmrg/* Compute F,V,H restarts from default restart position and hPos & vPos 595209ff23fSmrg * Return TRUE when code timing table was changed 596209ff23fSmrg */ 597209ff23fSmrgstatic Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save, 598209ff23fSmrg DisplayModePtr mode) 599209ff23fSmrg{ 600209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 601b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 602b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(output->scrn); 603b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 604209ff23fSmrg int restart; 605209ff23fSmrg unsigned hTotal; 606209ff23fSmrg unsigned vTotal; 607209ff23fSmrg unsigned fTotal; 608209ff23fSmrg int vOffset; 609209ff23fSmrg int hOffset; 610209ff23fSmrg uint16_t p1; 611209ff23fSmrg uint16_t p2; 612209ff23fSmrg Bool hChanged; 613209ff23fSmrg uint16_t hInc; 614209ff23fSmrg const TVModeConstants *constPtr; 615209ff23fSmrg 616209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 617b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 618b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 619b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 620b7e1c893Smrg if (pll->reference_freq == 2700) 621b7e1c893Smrg constPtr = &availableTVModes[0]; 622b7e1c893Smrg else 623b7e1c893Smrg constPtr = &availableTVModes[2]; 624b7e1c893Smrg } else { 625b7e1c893Smrg if (pll->reference_freq == 2700) 626b7e1c893Smrg constPtr = &availableTVModes[1]; 627b7e1c893Smrg else 628b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 629b7e1c893Smrg } 630209ff23fSmrg 631209ff23fSmrg hTotal = constPtr->horTotal; 632209ff23fSmrg vTotal = constPtr->verTotal; 633b7e1c893Smrg 634b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 635b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 636b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 637b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 638209ff23fSmrg fTotal = NTSC_TV_VFTOTAL + 1; 639209ff23fSmrg else 640209ff23fSmrg fTotal = PAL_TV_VFTOTAL + 1; 641209ff23fSmrg 642209ff23fSmrg /* Adjust positions 1&2 in hor. code timing table */ 643b7e1c893Smrg hOffset = tvout->hPos * H_POS_UNIT; 644209ff23fSmrg 645b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 646b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 647b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 648209ff23fSmrg /* improve image centering */ 649209ff23fSmrg hOffset -= 50; 650209ff23fSmrg p1 = hor_timing_NTSC[ H_TABLE_POS1 ]; 651209ff23fSmrg p2 = hor_timing_NTSC[ H_TABLE_POS2 ]; 652209ff23fSmrg } else { 653209ff23fSmrg p1 = hor_timing_PAL[ H_TABLE_POS1 ]; 654209ff23fSmrg p2 = hor_timing_PAL[ H_TABLE_POS2 ]; 655209ff23fSmrg } 656209ff23fSmrg 657209ff23fSmrg 658209ff23fSmrg p1 = (uint16_t)((int)p1 + hOffset); 659209ff23fSmrg p2 = (uint16_t)((int)p2 - hOffset); 660209ff23fSmrg 661209ff23fSmrg hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] || 662209ff23fSmrg p2 != save->h_code_timing[ H_TABLE_POS2 ]); 663209ff23fSmrg 664209ff23fSmrg save->h_code_timing[ H_TABLE_POS1 ] = p1; 665209ff23fSmrg save->h_code_timing[ H_TABLE_POS2 ] = p2; 666209ff23fSmrg 667209ff23fSmrg /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ 668209ff23fSmrg hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000; 669209ff23fSmrg 670209ff23fSmrg /* Adjust restart */ 671209ff23fSmrg restart = constPtr->defRestart; 672209ff23fSmrg 673209ff23fSmrg /* 674209ff23fSmrg * Convert vPos TV lines to n. of CRTC pixels 675209ff23fSmrg * Be verrrrry careful when mixing signed & unsigned values in C.. 676209ff23fSmrg */ 677b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 678b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 679b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 680b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 681b7e1c893Smrg vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(NTSC_TV_LINES_PER_FRAME); 682209ff23fSmrg else 683b7e1c893Smrg vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(PAL_TV_LINES_PER_FRAME); 684209ff23fSmrg 685209ff23fSmrg restart -= vOffset + hOffset; 686209ff23fSmrg 687209ff23fSmrg ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n", 688b7e1c893Smrg constPtr->defRestart , tvout->hPos , tvout->vPos , p1 , p2 , restart); 689209ff23fSmrg 690209ff23fSmrg save->tv_hrestart = restart % hTotal; 691209ff23fSmrg restart /= hTotal; 692209ff23fSmrg save->tv_vrestart = restart % vTotal; 693209ff23fSmrg restart /= vTotal; 694209ff23fSmrg save->tv_frestart = restart % fTotal; 695209ff23fSmrg 696209ff23fSmrg ErrorF("computeRestarts: F/H/V=%u,%u,%u\n", 697209ff23fSmrg (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart, 698209ff23fSmrg (unsigned)save->tv_hrestart); 699209ff23fSmrg 700209ff23fSmrg /* Compute H_INC from hSize */ 701b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 702b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 703b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) 704209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) / 705b7e1c893Smrg (tvout->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); 706209ff23fSmrg else 707209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) / 708b7e1c893Smrg (tvout->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); 709209ff23fSmrg 710209ff23fSmrg save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) | 711209ff23fSmrg ((uint32_t)hInc << RADEON_H_INC_SHIFT); 712209ff23fSmrg 713b7e1c893Smrg ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , tvout->hSize , hInc); 714209ff23fSmrg 715209ff23fSmrg return hChanged; 716209ff23fSmrg} 717209ff23fSmrg 718209ff23fSmrg/* intit TV-out regs */ 719209ff23fSmrgvoid RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, 720209ff23fSmrg DisplayModePtr mode, BOOL IsPrimary) 721209ff23fSmrg{ 722209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 723209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 724b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 725209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 726b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 727b7e1c893Smrg unsigned m, n, p; 728209ff23fSmrg unsigned i; 729209ff23fSmrg unsigned long vert_space, flicker_removal; 730209ff23fSmrg uint32_t tmp; 731209ff23fSmrg const TVModeConstants *constPtr; 732209ff23fSmrg const uint16_t *hor_timing; 733209ff23fSmrg const uint16_t *vert_timing; 734b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 735b7e1c893Smrg radeon_tvdac_ptr tvdac = NULL; 736b7e1c893Smrg 737b7e1c893Smrg if (radeon_encoder == NULL) 738b7e1c893Smrg return; 739b7e1c893Smrg 740b7e1c893Smrg tvdac = (radeon_tvdac_ptr)radeon_encoder->dev_priv; 741209ff23fSmrg 742b7e1c893Smrg if (tvdac == NULL) 743b7e1c893Smrg return; 744209ff23fSmrg 745209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 746b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 747b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 748b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 749b7e1c893Smrg if (pll->reference_freq == 2700) 750b7e1c893Smrg constPtr = &availableTVModes[0]; 751b7e1c893Smrg else 752b7e1c893Smrg constPtr = &availableTVModes[2]; 753b7e1c893Smrg } else { 754b7e1c893Smrg if (pll->reference_freq == 2700) 755b7e1c893Smrg constPtr = &availableTVModes[1]; 756b7e1c893Smrg else 757b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 758b7e1c893Smrg } 759209ff23fSmrg 760209ff23fSmrg save->tv_crc_cntl = 0; 761209ff23fSmrg 762209ff23fSmrg save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | 763209ff23fSmrg (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT); 764209ff23fSmrg 765209ff23fSmrg save->tv_hdisp = constPtr->horResolution - 1; 766209ff23fSmrg save->tv_hstart = constPtr->horStart; 767209ff23fSmrg save->tv_htotal = constPtr->horTotal - 1; 768209ff23fSmrg 769209ff23fSmrg save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) | 770209ff23fSmrg (0x100 << RADEON_Y_GAIN_SHIFT); 771209ff23fSmrg 772209ff23fSmrg save->tv_master_cntl = (RADEON_VIN_ASYNC_RST 773209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 774209ff23fSmrg | RADEON_TV_FIFO_CE_EN 775209ff23fSmrg | RADEON_TV_ON); 776209ff23fSmrg 777209ff23fSmrg if (!IS_R300_VARIANT) 778209ff23fSmrg save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; 779209ff23fSmrg 780b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 781b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) 782209ff23fSmrg save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX; 783209ff23fSmrg 784209ff23fSmrg save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT 785209ff23fSmrg | RADEON_SYNC_TIP_LEVEL 786209ff23fSmrg | RADEON_YFLT_EN 787209ff23fSmrg | RADEON_UVFLT_EN 788209ff23fSmrg | (6 << RADEON_CY_FILT_BLEND_SHIFT); 789209ff23fSmrg 790b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 791b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) { 792209ff23fSmrg save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) 793209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 794209ff23fSmrg save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | 795209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 796b7e1c893Smrg } else if (tvout->tvStd == TV_STD_SCART_PAL) { 797209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; 798209ff23fSmrg save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | 799209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 800209ff23fSmrg } else { 801209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN 802209ff23fSmrg | (0x3b << RADEON_SET_UP_LEVEL_SHIFT) 803209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 804209ff23fSmrg save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | 805209ff23fSmrg ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 806209ff23fSmrg } 807209ff23fSmrg 808209ff23fSmrg save->pll_test_cntl = 0; 809209ff23fSmrg 810209ff23fSmrg save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN 811209ff23fSmrg | RADEON_C_GRN_EN 812209ff23fSmrg | RADEON_CMP_BLU_EN 813209ff23fSmrg | RADEON_DAC_DITHER_EN); 814209ff23fSmrg 815209ff23fSmrg save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN 816209ff23fSmrg | RADEON_TVOUT_SCALE_EN 817209ff23fSmrg | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) 818b7e1c893Smrg | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT) 819b7e1c893Smrg | RADEON_RGB_ATTEN_SEL(0x3) 820b7e1c893Smrg | RADEON_RGB_ATTEN_VAL(0xc)); 821209ff23fSmrg 822209ff23fSmrg if (IsPrimary) { 823209ff23fSmrg if (radeon_output->Flags & RADEON_USE_RMX) 824209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; 825209ff23fSmrg else 826209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; 827209ff23fSmrg } else { 828209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; 829209ff23fSmrg } 830209ff23fSmrg 831209ff23fSmrg save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE; 832209ff23fSmrg 833209ff23fSmrg save->tv_sync_size = constPtr->horResolution + 8; 834209ff23fSmrg 835b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 836b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 837b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 838b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 839209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; 840209ff23fSmrg else 841209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME; 842209ff23fSmrg 843209ff23fSmrg save->tv_vscaler_cntl1 = RADEON_Y_W_EN; 844209ff23fSmrg save->tv_vscaler_cntl1 = 845209ff23fSmrg (save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000); 846b7e1c893Smrg 847b7e1c893Smrg if (pll->reference_freq == 2700) 848b7e1c893Smrg save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; 849b7e1c893Smrg 850209ff23fSmrg if (constPtr->horResolution == 1024) 851209ff23fSmrg save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); 852209ff23fSmrg else 853209ff23fSmrg save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); 854209ff23fSmrg 855b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 856b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 857b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 858b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 859209ff23fSmrg flicker_removal = 860209ff23fSmrg (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5; 861209ff23fSmrg else 862209ff23fSmrg flicker_removal = 863209ff23fSmrg (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5; 864209ff23fSmrg 865209ff23fSmrg if (flicker_removal < 3) 866209ff23fSmrg flicker_removal = 3; 867209ff23fSmrg for (i = 0; i < 6; ++i) { 868209ff23fSmrg if (flicker_removal == SLOPE_limit[i]) 869209ff23fSmrg break; 870209ff23fSmrg } 871209ff23fSmrg save->tv_y_saw_tooth_cntl = 872209ff23fSmrg (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8 873209ff23fSmrg | ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16); 874209ff23fSmrg save->tv_y_fall_cntl = 875209ff23fSmrg (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | 876209ff23fSmrg RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / 877209ff23fSmrg 1024; 878209ff23fSmrg save->tv_y_rise_cntl = 879209ff23fSmrg RADEON_Y_RISE_PING_PONG 880209ff23fSmrg | (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; 881209ff23fSmrg 882209ff23fSmrg save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0) 883209ff23fSmrg | (0x10 << 24) 884209ff23fSmrg | RADEON_DITHER_MODE 885209ff23fSmrg | RADEON_Y_OUTPUT_DITHER_EN 886209ff23fSmrg | RADEON_UV_OUTPUT_DITHER_EN 887209ff23fSmrg | RADEON_UV_TO_BUF_DITHER_EN); 888209ff23fSmrg 889209ff23fSmrg tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; 890209ff23fSmrg tmp = ((16384 * 256 * 10) / tmp + 5) / 10; 891209ff23fSmrg tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; 892209ff23fSmrg save->tv_timing_cntl = tmp; 893209ff23fSmrg 894b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 895b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 896b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 897b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 898b7e1c893Smrg save->tv_dac_cntl = tvdac->ntsc_tvdac_adj; 899209ff23fSmrg else 900b7e1c893Smrg save->tv_dac_cntl = tvdac->pal_tvdac_adj; 901209ff23fSmrg 902209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD); 903209ff23fSmrg 904b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 905b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) 906209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; 907209ff23fSmrg else 908209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; 909209ff23fSmrg 910209ff23fSmrg#if 0 911209ff23fSmrg /* needs fixes for r4xx */ 912209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD 913209ff23fSmrg | RADEON_TV_DAC_BDACPD); 914209ff23fSmrg 915209ff23fSmrg if (radeon_output->MonType == MT_CTV) { 916209ff23fSmrg save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD; 917209ff23fSmrg } 918209ff23fSmrg 919209ff23fSmrg if (radeon_output->MonType == MT_STV) { 920209ff23fSmrg save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | 921209ff23fSmrg RADEON_TV_DAC_GDACPD); 922209ff23fSmrg } 923209ff23fSmrg#endif 924209ff23fSmrg 925b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 926b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) { 927b7e1c893Smrg if (pll->reference_freq == 2700) { 928b7e1c893Smrg m = NTSC_TV_PLL_M_27; 929b7e1c893Smrg n = NTSC_TV_PLL_N_27; 930b7e1c893Smrg p = NTSC_TV_PLL_P_27; 931b7e1c893Smrg } else { 932b7e1c893Smrg m = NTSC_TV_PLL_M_14; 933b7e1c893Smrg n = NTSC_TV_PLL_N_14; 934b7e1c893Smrg p = NTSC_TV_PLL_P_14; 935b7e1c893Smrg } 936b7e1c893Smrg } else { 937b7e1c893Smrg if (pll->reference_freq == 2700) { 938b7e1c893Smrg m = PAL_TV_PLL_M_27; 939b7e1c893Smrg n = PAL_TV_PLL_N_27; 940b7e1c893Smrg p = PAL_TV_PLL_P_27; 941b7e1c893Smrg } else { 942b7e1c893Smrg /* FIXME */ 943b7e1c893Smrg m = PAL_TV_PLL_M_27; 944b7e1c893Smrg n = PAL_TV_PLL_N_27; 945b7e1c893Smrg p = PAL_TV_PLL_P_27; 946b7e1c893Smrg } 947b7e1c893Smrg } 948b7e1c893Smrg save->tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) | 949b7e1c893Smrg (((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | 950b7e1c893Smrg ((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | 951b7e1c893Smrg (((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | 952b7e1c893Smrg ((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); 953209ff23fSmrg 954209ff23fSmrg save->tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) | 955209ff23fSmrg ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) | 956209ff23fSmrg ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) | 957209ff23fSmrg RADEON_TVCLK_SRC_SEL_TVPLL | 958209ff23fSmrg RADEON_TVPLL_TEST_DIS); 959209ff23fSmrg 960209ff23fSmrg save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN; 961209ff23fSmrg 962209ff23fSmrg save->tv_uv_adr = 0xc8; 963209ff23fSmrg 964209ff23fSmrg save->tv_vdisp = constPtr->verResolution - 1; 965209ff23fSmrg 966b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 967b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 968b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 969b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 970209ff23fSmrg save->tv_ftotal = NTSC_TV_VFTOTAL; 971209ff23fSmrg else 972209ff23fSmrg save->tv_ftotal = PAL_TV_VFTOTAL; 973209ff23fSmrg 974209ff23fSmrg save->tv_vtotal = constPtr->verTotal - 1; 975209ff23fSmrg 976b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 977b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 978b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 979209ff23fSmrg hor_timing = hor_timing_NTSC; 980209ff23fSmrg } else { 981209ff23fSmrg hor_timing = hor_timing_PAL; 982209ff23fSmrg } 983209ff23fSmrg 984b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 985b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 986b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 987b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) { 988209ff23fSmrg vert_timing = vert_timing_NTSC; 989209ff23fSmrg } else { 990209ff23fSmrg vert_timing = vert_timing_PAL; 991209ff23fSmrg } 992209ff23fSmrg 993209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { 994209ff23fSmrg if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0) 995209ff23fSmrg break; 996209ff23fSmrg } 997209ff23fSmrg 998209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { 999209ff23fSmrg if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0) 1000209ff23fSmrg break; 1001209ff23fSmrg } 1002209ff23fSmrg 1003209ff23fSmrg /* 1004209ff23fSmrg * This must be called AFTER loading timing tables as they are modified by this function 1005209ff23fSmrg */ 1006209ff23fSmrg RADEONInitTVRestarts(output, save, mode); 1007209ff23fSmrg 1008209ff23fSmrg save->dac_cntl &= ~RADEON_DAC_TVO_EN; 1009209ff23fSmrg 1010209ff23fSmrg if (IS_R300_VARIANT) 1011209ff23fSmrg save->gpiopad_a = info->SavedReg->gpiopad_a & ~1; 1012209ff23fSmrg 1013209ff23fSmrg if (IsPrimary) { 1014209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 1015209ff23fSmrg save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC 1016209ff23fSmrg | RADEON_DISP_TV_SOURCE_CRTC); 1017209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 1018209ff23fSmrg save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; 1019209ff23fSmrg } else { 1020209ff23fSmrg save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 1021209ff23fSmrg } 1022209ff23fSmrg } else { 1023209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK; 1024209ff23fSmrg save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; 1025209ff23fSmrg 1026209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 1027209ff23fSmrg save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; 1028209ff23fSmrg } else { 1029209ff23fSmrg save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; 1030209ff23fSmrg } 1031209ff23fSmrg } 1032209ff23fSmrg} 1033209ff23fSmrg 1034209ff23fSmrg 1035209ff23fSmrg/* Set hw registers for a new h/v position & h size */ 1036209ff23fSmrgvoid RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode) 1037209ff23fSmrg{ 1038209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1039209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1040209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1041209ff23fSmrg Bool reloadTable; 1042209ff23fSmrg RADEONSavePtr restore = info->ModeReg; 1043209ff23fSmrg 1044209ff23fSmrg reloadTable = RADEONInitTVRestarts(output, restore, mode); 1045209ff23fSmrg 1046209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 1047209ff23fSmrg 1048209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 1049209ff23fSmrg 1050209ff23fSmrg if (reloadTable) { 1051209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl 1052209ff23fSmrg | RADEON_TV_ASYNC_RST 1053209ff23fSmrg | RADEON_CRT_ASYNC_RST 1054209ff23fSmrg | RADEON_RESTART_PHASE_FIX); 1055209ff23fSmrg 1056209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 1057209ff23fSmrg 1058209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 1059209ff23fSmrg } 1060209ff23fSmrg} 1061209ff23fSmrg 1062209ff23fSmrgvoid RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1063209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1064209ff23fSmrg{ 1065209ff23fSmrg const TVModeConstants *constPtr; 1066209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1067b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1068b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1069b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1070209ff23fSmrg 1071209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1072b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1073b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1074b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1075b7e1c893Smrg if (pll->reference_freq == 2700) 1076b7e1c893Smrg constPtr = &availableTVModes[0]; 1077b7e1c893Smrg else 1078b7e1c893Smrg constPtr = &availableTVModes[2]; 1079b7e1c893Smrg } else { 1080b7e1c893Smrg if (pll->reference_freq == 2700) 1081b7e1c893Smrg constPtr = &availableTVModes[1]; 1082b7e1c893Smrg else 1083b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 1084b7e1c893Smrg } 1085209ff23fSmrg 1086209ff23fSmrg save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1087209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1088209ff23fSmrg 1089209ff23fSmrg save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid 1090209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1091209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1092209ff23fSmrg (constPtr->horSyncStart & 7); 1093209ff23fSmrg 1094209ff23fSmrg save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1095209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1096209ff23fSmrg 1097209ff23fSmrg save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1098209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1099209ff23fSmrg 1100209ff23fSmrg} 1101209ff23fSmrg 1102209ff23fSmrgvoid RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1103209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1104209ff23fSmrg{ 1105209ff23fSmrg unsigned postDiv; 1106209ff23fSmrg const TVModeConstants *constPtr; 1107209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1108b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1109b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1110b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1111209ff23fSmrg 1112209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1113b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1114b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1115b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1116b7e1c893Smrg if (pll->reference_freq == 2700) 1117b7e1c893Smrg constPtr = &availableTVModes[0]; 1118b7e1c893Smrg else 1119b7e1c893Smrg constPtr = &availableTVModes[2]; 1120b7e1c893Smrg } else { 1121b7e1c893Smrg if (pll->reference_freq == 2700) 1122b7e1c893Smrg constPtr = &availableTVModes[1]; 1123b7e1c893Smrg else 1124b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 1125b7e1c893Smrg } 1126209ff23fSmrg 1127209ff23fSmrg save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN; 1128209ff23fSmrg 1129209ff23fSmrg save->ppll_ref_div = constPtr->crtcPLL_M; 1130209ff23fSmrg 1131209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1132209ff23fSmrg case 1: 1133209ff23fSmrg postDiv = 0; 1134209ff23fSmrg break; 1135209ff23fSmrg case 2: 1136209ff23fSmrg postDiv = 1; 1137209ff23fSmrg break; 1138209ff23fSmrg case 3: 1139209ff23fSmrg postDiv = 4; 1140209ff23fSmrg break; 1141209ff23fSmrg case 4: 1142209ff23fSmrg postDiv = 2; 1143209ff23fSmrg break; 1144209ff23fSmrg case 6: 1145209ff23fSmrg postDiv = 6; 1146209ff23fSmrg break; 1147209ff23fSmrg case 8: 1148209ff23fSmrg postDiv = 3; 1149209ff23fSmrg break; 1150209ff23fSmrg case 12: 1151209ff23fSmrg postDiv = 7; 1152209ff23fSmrg break; 1153209ff23fSmrg case 16: 1154209ff23fSmrg default: 1155209ff23fSmrg postDiv = 5; 1156209ff23fSmrg break; 1157209ff23fSmrg } 1158209ff23fSmrg 1159209ff23fSmrg save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1160209ff23fSmrg 1161209ff23fSmrg save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); 1162209ff23fSmrg save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; 1163209ff23fSmrg 1164209ff23fSmrg} 1165209ff23fSmrg 1166209ff23fSmrgvoid RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1167209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1168209ff23fSmrg{ 1169209ff23fSmrg const TVModeConstants *constPtr; 1170209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1171b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1172b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1173b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1174209ff23fSmrg 1175209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1176b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1177b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1178b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1179b7e1c893Smrg if (pll->reference_freq == 2700) 1180b7e1c893Smrg constPtr = &availableTVModes[0]; 1181b7e1c893Smrg else 1182b7e1c893Smrg constPtr = &availableTVModes[2]; 1183b7e1c893Smrg } else { 1184b7e1c893Smrg if (pll->reference_freq == 2700) 1185b7e1c893Smrg constPtr = &availableTVModes[1]; 1186b7e1c893Smrg else 1187b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 1188b7e1c893Smrg } 1189209ff23fSmrg 1190209ff23fSmrg save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1191209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1192209ff23fSmrg 1193209ff23fSmrg save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid 1194209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1195209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1196209ff23fSmrg (constPtr->horSyncStart & 7); 1197209ff23fSmrg 1198209ff23fSmrg save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1199209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1200209ff23fSmrg 1201c503f109Smrg save->crtc2_v_sync_strt_wid = (save->crtc2_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1202209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1203209ff23fSmrg 1204209ff23fSmrg} 1205209ff23fSmrg 1206209ff23fSmrgvoid RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1207209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1208209ff23fSmrg{ 1209209ff23fSmrg unsigned postDiv; 1210209ff23fSmrg const TVModeConstants *constPtr; 1211209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1212b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1213b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1214b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1215209ff23fSmrg 1216209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1217b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1218b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1219b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1220b7e1c893Smrg if (pll->reference_freq == 2700) 1221b7e1c893Smrg constPtr = &availableTVModes[0]; 1222b7e1c893Smrg else 1223b7e1c893Smrg constPtr = &availableTVModes[2]; 1224b7e1c893Smrg } else { 1225b7e1c893Smrg if (pll->reference_freq == 2700) 1226b7e1c893Smrg constPtr = &availableTVModes[1]; 1227b7e1c893Smrg else 1228b7e1c893Smrg constPtr = &availableTVModes[1]; /* FIXME */ 1229b7e1c893Smrg } 1230209ff23fSmrg 1231209ff23fSmrg save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */ 1232209ff23fSmrg 1233209ff23fSmrg save->p2pll_ref_div = constPtr->crtcPLL_M; 1234209ff23fSmrg 1235209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1236209ff23fSmrg case 1: 1237209ff23fSmrg postDiv = 0; 1238209ff23fSmrg break; 1239209ff23fSmrg case 2: 1240209ff23fSmrg postDiv = 1; 1241209ff23fSmrg break; 1242209ff23fSmrg case 3: 1243209ff23fSmrg postDiv = 4; 1244209ff23fSmrg break; 1245209ff23fSmrg case 4: 1246209ff23fSmrg postDiv = 2; 1247209ff23fSmrg break; 1248209ff23fSmrg case 6: 1249209ff23fSmrg postDiv = 6; 1250209ff23fSmrg break; 1251209ff23fSmrg case 8: 1252209ff23fSmrg postDiv = 3; 1253209ff23fSmrg break; 1254209ff23fSmrg case 12: 1255209ff23fSmrg postDiv = 7; 1256209ff23fSmrg break; 1257209ff23fSmrg case 16: 1258209ff23fSmrg default: 1259209ff23fSmrg postDiv = 5; 1260209ff23fSmrg break; 1261209ff23fSmrg } 1262209ff23fSmrg 1263209ff23fSmrg save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1264209ff23fSmrg 1265209ff23fSmrg save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; 1266209ff23fSmrg save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 1267209ff23fSmrg | RADEON_PIXCLK_TV_SRC_SEL); 1268209ff23fSmrg 1269209ff23fSmrg} 1270