radeon_tv.c revision 209ff23f
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" 26209ff23fSmrg 27209ff23fSmrg/********************************************************************** 28209ff23fSmrg * 29209ff23fSmrg * ModeConstants 30209ff23fSmrg * 31209ff23fSmrg * Storage of constants related to a single video mode 32209ff23fSmrg * 33209ff23fSmrg **********************************************************************/ 34209ff23fSmrg 35209ff23fSmrgtypedef struct 36209ff23fSmrg{ 37209ff23fSmrg uint16_t horResolution; 38209ff23fSmrg uint16_t verResolution; 39209ff23fSmrg TVStd standard; 40209ff23fSmrg uint16_t horTotal; 41209ff23fSmrg uint16_t verTotal; 42209ff23fSmrg uint16_t horStart; 43209ff23fSmrg uint16_t horSyncStart; 44209ff23fSmrg uint16_t verSyncStart; 45209ff23fSmrg unsigned defRestart; 46209ff23fSmrg uint16_t crtcPLL_N; 47209ff23fSmrg uint8_t crtcPLL_M; 48209ff23fSmrg uint8_t crtcPLL_postDiv; 49209ff23fSmrg unsigned pixToTV; 50209ff23fSmrg} TVModeConstants; 51209ff23fSmrg 52209ff23fSmrgstatic const uint16_t hor_timing_NTSC[] = 53209ff23fSmrg{ 54209ff23fSmrg 0x0007, 55209ff23fSmrg 0x003f, 56209ff23fSmrg 0x0263, 57209ff23fSmrg 0x0a24, 58209ff23fSmrg 0x2a6b, 59209ff23fSmrg 0x0a36, 60209ff23fSmrg 0x126d, /* H_TABLE_POS1 */ 61209ff23fSmrg 0x1bfe, 62209ff23fSmrg 0x1a8f, /* H_TABLE_POS2 */ 63209ff23fSmrg 0x1ec7, 64209ff23fSmrg 0x3863, 65209ff23fSmrg 0x1bfe, 66209ff23fSmrg 0x1bfe, 67209ff23fSmrg 0x1a2a, 68209ff23fSmrg 0x1e95, 69209ff23fSmrg 0x0e31, 70209ff23fSmrg 0x201b, 71209ff23fSmrg 0 72209ff23fSmrg}; 73209ff23fSmrg 74209ff23fSmrgstatic const uint16_t vert_timing_NTSC[] = 75209ff23fSmrg{ 76209ff23fSmrg 0x2001, 77209ff23fSmrg 0x200d, 78209ff23fSmrg 0x1006, 79209ff23fSmrg 0x0c06, 80209ff23fSmrg 0x1006, 81209ff23fSmrg 0x1818, 82209ff23fSmrg 0x21e3, 83209ff23fSmrg 0x1006, 84209ff23fSmrg 0x0c06, 85209ff23fSmrg 0x1006, 86209ff23fSmrg 0x1817, 87209ff23fSmrg 0x21d4, 88209ff23fSmrg 0x0002, 89209ff23fSmrg 0 90209ff23fSmrg}; 91209ff23fSmrg 92209ff23fSmrgstatic const uint16_t hor_timing_PAL[] = 93209ff23fSmrg{ 94209ff23fSmrg 0x0007, 95209ff23fSmrg 0x0058, 96209ff23fSmrg 0x027c, 97209ff23fSmrg 0x0a31, 98209ff23fSmrg 0x2a77, 99209ff23fSmrg 0x0a95, 100209ff23fSmrg 0x124f, /* H_TABLE_POS1 */ 101209ff23fSmrg 0x1bfe, 102209ff23fSmrg 0x1b22, /* H_TABLE_POS2 */ 103209ff23fSmrg 0x1ef9, 104209ff23fSmrg 0x387c, 105209ff23fSmrg 0x1bfe, 106209ff23fSmrg 0x1bfe, 107209ff23fSmrg 0x1b31, 108209ff23fSmrg 0x1eb5, 109209ff23fSmrg 0x0e43, 110209ff23fSmrg 0x201b, 111209ff23fSmrg 0 112209ff23fSmrg}; 113209ff23fSmrg 114209ff23fSmrgstatic const uint16_t vert_timing_PAL[] = 115209ff23fSmrg{ 116209ff23fSmrg 0x2001, 117209ff23fSmrg 0x200c, 118209ff23fSmrg 0x1005, 119209ff23fSmrg 0x0c05, 120209ff23fSmrg 0x1005, 121209ff23fSmrg 0x1401, 122209ff23fSmrg 0x1821, 123209ff23fSmrg 0x2240, 124209ff23fSmrg 0x1005, 125209ff23fSmrg 0x0c05, 126209ff23fSmrg 0x1005, 127209ff23fSmrg 0x1401, 128209ff23fSmrg 0x1822, 129209ff23fSmrg 0x2230, 130209ff23fSmrg 0x0002, 131209ff23fSmrg 0 132209ff23fSmrg}; 133209ff23fSmrg 134209ff23fSmrg/********************************************************************** 135209ff23fSmrg * 136209ff23fSmrg * availableModes 137209ff23fSmrg * 138209ff23fSmrg * Table of all allowed modes for tv output 139209ff23fSmrg * 140209ff23fSmrg **********************************************************************/ 141209ff23fSmrgstatic const TVModeConstants availableTVModes[] = 142209ff23fSmrg{ 143209ff23fSmrg { 144209ff23fSmrg 800, /* horResolution */ 145209ff23fSmrg 600, /* verResolution */ 146209ff23fSmrg TV_STD_NTSC, /* standard */ 147209ff23fSmrg 990, /* horTotal */ 148209ff23fSmrg 740, /* verTotal */ 149209ff23fSmrg 813, /* horStart */ 150209ff23fSmrg 824, /* horSyncStart */ 151209ff23fSmrg 632, /* verSyncStart */ 152209ff23fSmrg 625592, /* defRestart */ 153209ff23fSmrg 592, /* crtcPLL_N */ 154209ff23fSmrg 91, /* crtcPLL_M */ 155209ff23fSmrg 4, /* crtcPLL_postDiv */ 156209ff23fSmrg 1022, /* pixToTV */ 157209ff23fSmrg }, 158209ff23fSmrg { 159209ff23fSmrg 800, /* horResolution */ 160209ff23fSmrg 600, /* verResolution */ 161209ff23fSmrg TV_STD_PAL, /* standard */ 162209ff23fSmrg 1144, /* horTotal */ 163209ff23fSmrg 706, /* verTotal */ 164209ff23fSmrg 812, /* horStart */ 165209ff23fSmrg 824, /* horSyncStart */ 166209ff23fSmrg 669, /* verSyncStart */ 167209ff23fSmrg 696700, /* defRestart */ 168209ff23fSmrg 1382, /* crtcPLL_N */ 169209ff23fSmrg 231, /* crtcPLL_M */ 170209ff23fSmrg 4, /* crtcPLL_postDiv */ 171209ff23fSmrg 759, /* pixToTV */ 172209ff23fSmrg } 173209ff23fSmrg}; 174209ff23fSmrg 175209ff23fSmrg#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ])) 176209ff23fSmrg 177209ff23fSmrgstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; 178209ff23fSmrgstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; 179209ff23fSmrgstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; 180209ff23fSmrgstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; 181209ff23fSmrg 182209ff23fSmrg 183209ff23fSmrgstatic void 184209ff23fSmrgRADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, 185209ff23fSmrg unsigned nWaitLoops, unsigned cntThreshold) 186209ff23fSmrg{ 187209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 188209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 189209ff23fSmrg uint32_t savePLLTest; 190209ff23fSmrg unsigned i; 191209ff23fSmrg unsigned j; 192209ff23fSmrg 193209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); 194209ff23fSmrg 195209ff23fSmrg savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL); 196209ff23fSmrg 197209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B); 198209ff23fSmrg 199209ff23fSmrg /* XXX: these should probably be OUTPLL to avoid various PLL errata */ 200209ff23fSmrg 201209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); 202209ff23fSmrg 203209ff23fSmrg for (i = 0; i < nTests; i++) { 204209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); 205209ff23fSmrg 206209ff23fSmrg for (j = 0; j < nWaitLoops; j++) 207209ff23fSmrg if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold) 208209ff23fSmrg break; 209209ff23fSmrg } 210209ff23fSmrg 211209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest); 212209ff23fSmrg 213209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); 214209ff23fSmrg} 215209ff23fSmrg 216209ff23fSmrg/* Write to TV FIFO RAM */ 217209ff23fSmrgstatic void 218209ff23fSmrgRADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr, 219209ff23fSmrg uint32_t value) 220209ff23fSmrg{ 221209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 222209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 223209ff23fSmrg uint32_t tmp; 224209ff23fSmrg int i = 0; 225209ff23fSmrg 226209ff23fSmrg OUTREG(RADEON_TV_HOST_WRITE_DATA, value); 227209ff23fSmrg 228209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 229209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); 230209ff23fSmrg 231209ff23fSmrg do { 232209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 233209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) 234209ff23fSmrg break; 235209ff23fSmrg i++; 236209ff23fSmrg } 237209ff23fSmrg while (i < 10000); 238209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ 239209ff23fSmrg 240209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 241209ff23fSmrg} 242209ff23fSmrg 243209ff23fSmrg/* Read from TV FIFO RAM */ 244209ff23fSmrgstatic uint32_t 245209ff23fSmrgRADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr) 246209ff23fSmrg{ 247209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 248209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 249209ff23fSmrg uint32_t tmp; 250209ff23fSmrg int i = 0; 251209ff23fSmrg 252209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 253209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); 254209ff23fSmrg 255209ff23fSmrg do { 256209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 257209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) 258209ff23fSmrg break; 259209ff23fSmrg i++; 260209ff23fSmrg } 261209ff23fSmrg while (i < 10000); 262209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/ 263209ff23fSmrg 264209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 265209ff23fSmrg 266209ff23fSmrg return INREG(RADEON_TV_HOST_READ_DATA); 267209ff23fSmrg} 268209ff23fSmrg 269209ff23fSmrg/* Get FIFO addresses of horizontal & vertical code timing tables from 270209ff23fSmrg * settings of uv_adr register. 271209ff23fSmrg */ 272209ff23fSmrgstatic uint16_t 273209ff23fSmrgRADEONGetHTimingTablesAddr(uint32_t tv_uv_adr) 274209ff23fSmrg{ 275209ff23fSmrg uint16_t hTable; 276209ff23fSmrg 277209ff23fSmrg switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { 278209ff23fSmrg case 0: 279209ff23fSmrg hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; 280209ff23fSmrg break; 281209ff23fSmrg case 1: 282209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; 283209ff23fSmrg break; 284209ff23fSmrg case 2: 285209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; 286209ff23fSmrg break; 287209ff23fSmrg default: 288209ff23fSmrg /* Of course, this should never happen */ 289209ff23fSmrg hTable = 0; 290209ff23fSmrg break; 291209ff23fSmrg } 292209ff23fSmrg return hTable; 293209ff23fSmrg} 294209ff23fSmrg 295209ff23fSmrgstatic uint16_t 296209ff23fSmrgRADEONGetVTimingTablesAddr(uint32_t tv_uv_adr) 297209ff23fSmrg{ 298209ff23fSmrg uint16_t vTable; 299209ff23fSmrg 300209ff23fSmrg switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { 301209ff23fSmrg case 0: 302209ff23fSmrg vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; 303209ff23fSmrg break; 304209ff23fSmrg case 1: 305209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; 306209ff23fSmrg break; 307209ff23fSmrg case 2: 308209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; 309209ff23fSmrg break; 310209ff23fSmrg default: 311209ff23fSmrg /* Of course, this should never happen */ 312209ff23fSmrg vTable = 0; 313209ff23fSmrg break; 314209ff23fSmrg } 315209ff23fSmrg return vTable; 316209ff23fSmrg} 317209ff23fSmrg 318209ff23fSmrg/* Restore horizontal/vertical timing code tables */ 319209ff23fSmrgstatic void 320209ff23fSmrgRADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore) 321209ff23fSmrg{ 322209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 323209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 324209ff23fSmrg uint16_t hTable; 325209ff23fSmrg uint16_t vTable; 326209ff23fSmrg uint32_t tmp; 327209ff23fSmrg unsigned i; 328209ff23fSmrg 329209ff23fSmrg OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr); 330209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr); 331209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr); 332209ff23fSmrg 333209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) { 334209ff23fSmrg tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]); 335209ff23fSmrg RADEONWriteTVFIFO(pScrn, hTable, tmp); 336209ff23fSmrg if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0) 337209ff23fSmrg break; 338209ff23fSmrg } 339209ff23fSmrg 340209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) { 341209ff23fSmrg tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]); 342209ff23fSmrg RADEONWriteTVFIFO(pScrn, vTable, tmp); 343209ff23fSmrg if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0) 344209ff23fSmrg break; 345209ff23fSmrg } 346209ff23fSmrg} 347209ff23fSmrg 348209ff23fSmrg/* restore TV PLLs */ 349209ff23fSmrgstatic void 350209ff23fSmrgRADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 351209ff23fSmrg{ 352209ff23fSmrg 353209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); 354209ff23fSmrg OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl); 355209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); 356209ff23fSmrg 357209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 358209ff23fSmrg 359209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); 360209ff23fSmrg 361209ff23fSmrg RADEONWaitPLLLock(pScrn, 300, 160, 27); 362209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 363209ff23fSmrg 364209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf); 365209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); 366209ff23fSmrg 367209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); 368209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); 369209ff23fSmrg} 370209ff23fSmrg 371209ff23fSmrg/* Restore TV horizontal/vertical settings */ 372209ff23fSmrgstatic void 373209ff23fSmrgRADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 374209ff23fSmrg{ 375209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 376209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 377209ff23fSmrg 378209ff23fSmrg OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl); 379209ff23fSmrg 380209ff23fSmrg OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal); 381209ff23fSmrg OUTREG(RADEON_TV_HDISP, restore->tv_hdisp); 382209ff23fSmrg OUTREG(RADEON_TV_HSTART, restore->tv_hstart); 383209ff23fSmrg 384209ff23fSmrg OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal); 385209ff23fSmrg OUTREG(RADEON_TV_VDISP, restore->tv_vdisp); 386209ff23fSmrg 387209ff23fSmrg OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal); 388209ff23fSmrg 389209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1); 390209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2); 391209ff23fSmrg 392209ff23fSmrg OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl); 393209ff23fSmrg OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl); 394209ff23fSmrg OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl); 395209ff23fSmrg} 396209ff23fSmrg 397209ff23fSmrg/* restore TV RESTART registers */ 398209ff23fSmrgstatic void 399209ff23fSmrgRADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore) 400209ff23fSmrg{ 401209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 402209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 403209ff23fSmrg 404209ff23fSmrg OUTREG(RADEON_TV_FRESTART, restore->tv_frestart); 405209ff23fSmrg OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart); 406209ff23fSmrg OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart); 407209ff23fSmrg} 408209ff23fSmrg 409209ff23fSmrg/* restore tv standard & output muxes */ 410209ff23fSmrgstatic void 411209ff23fSmrgRADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore) 412209ff23fSmrg{ 413209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 414209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 415209ff23fSmrg 416209ff23fSmrg OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl); 417209ff23fSmrg 418209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 419209ff23fSmrg 420209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1); 421209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2); 422209ff23fSmrg 423209ff23fSmrg OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl); 424209ff23fSmrg 425209ff23fSmrg OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl); 426209ff23fSmrg} 427209ff23fSmrg 428209ff23fSmrg/* Restore TV out regs */ 429209ff23fSmrgvoid 430209ff23fSmrgRADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 431209ff23fSmrg{ 432209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 433209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 434209ff23fSmrg 435209ff23fSmrg ErrorF("Entering Restore TV\n"); 436209ff23fSmrg 437209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 438209ff23fSmrg | RADEON_TV_ASYNC_RST 439209ff23fSmrg | RADEON_CRT_ASYNC_RST 440209ff23fSmrg | RADEON_TV_FIFO_ASYNC_RST)); 441209ff23fSmrg 442209ff23fSmrg /* Temporarily turn the TV DAC off */ 443209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK) 444209ff23fSmrg | RADEON_TV_DAC_BGSLEEP 445209ff23fSmrg | RADEON_TV_DAC_RDACPD 446209ff23fSmrg | RADEON_TV_DAC_GDACPD 447209ff23fSmrg | RADEON_TV_DAC_BDACPD)); 448209ff23fSmrg 449209ff23fSmrg ErrorF("Restore TV PLL\n"); 450209ff23fSmrg RADEONRestoreTVPLLRegisters(pScrn, restore); 451209ff23fSmrg 452209ff23fSmrg ErrorF("Restore TVHV\n"); 453209ff23fSmrg RADEONRestoreTVHVRegisters(pScrn, restore); 454209ff23fSmrg 455209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 456209ff23fSmrg | RADEON_TV_ASYNC_RST 457209ff23fSmrg | RADEON_CRT_ASYNC_RST)); 458209ff23fSmrg 459209ff23fSmrg ErrorF("Restore TV Restarts\n"); 460209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 461209ff23fSmrg 462209ff23fSmrg ErrorF("Restore Timing Tables\n"); 463209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 464209ff23fSmrg 465209ff23fSmrg 466209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 467209ff23fSmrg | RADEON_TV_ASYNC_RST)); 468209ff23fSmrg 469209ff23fSmrg ErrorF("Restore TV standard\n"); 470209ff23fSmrg RADEONRestoreTVOutputStd(pScrn, restore); 471209ff23fSmrg 472209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 473209ff23fSmrg 474209ff23fSmrg OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); 475209ff23fSmrg OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); 476209ff23fSmrg 477209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); 478209ff23fSmrg 479209ff23fSmrg ErrorF("Leaving Restore TV\n"); 480209ff23fSmrg} 481209ff23fSmrg 482209ff23fSmrg/* Save horizontal/vertical timing code tables */ 483209ff23fSmrgstatic void 484209ff23fSmrgRADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save) 485209ff23fSmrg{ 486209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 487209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 488209ff23fSmrg uint16_t hTable; 489209ff23fSmrg uint16_t vTable; 490209ff23fSmrg uint32_t tmp; 491209ff23fSmrg unsigned i; 492209ff23fSmrg 493209ff23fSmrg save->tv_uv_adr = INREG(RADEON_TV_UV_ADR); 494209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr); 495209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr); 496209ff23fSmrg 497209ff23fSmrg /* 498209ff23fSmrg * Reset FIFO arbiter in order to be able to access FIFO RAM 499209ff23fSmrg */ 500209ff23fSmrg 501209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST 502209ff23fSmrg | RADEON_CRT_ASYNC_RST 503209ff23fSmrg | RADEON_RESTART_PHASE_FIX 504209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 505209ff23fSmrg | RADEON_TV_FIFO_CE_EN 506209ff23fSmrg | RADEON_TV_ON)); 507209ff23fSmrg 508209ff23fSmrg /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/ 509209ff23fSmrg 510209ff23fSmrg ErrorF("saveTimingTables: reading timing tables\n"); 511209ff23fSmrg 512209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) { 513209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, hTable--); 514209ff23fSmrg save->h_code_timing[ i ] = (uint16_t)((tmp >> 14) & 0x3fff); 515209ff23fSmrg save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff); 516209ff23fSmrg 517209ff23fSmrg if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0) 518209ff23fSmrg break; 519209ff23fSmrg } 520209ff23fSmrg 521209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) { 522209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, vTable++); 523209ff23fSmrg save->v_code_timing[ i ] = (uint16_t)(tmp & 0x3fff); 524209ff23fSmrg save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff); 525209ff23fSmrg 526209ff23fSmrg if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0) 527209ff23fSmrg break; 528209ff23fSmrg } 529209ff23fSmrg} 530209ff23fSmrg 531209ff23fSmrg/* read TV regs */ 532209ff23fSmrgvoid 533209ff23fSmrgRADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) 534209ff23fSmrg{ 535209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 536209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 537209ff23fSmrg 538209ff23fSmrg ErrorF("Entering TV Save\n"); 539209ff23fSmrg 540209ff23fSmrg save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL); 541209ff23fSmrg save->tv_frestart = INREG(RADEON_TV_FRESTART); 542209ff23fSmrg save->tv_hrestart = INREG(RADEON_TV_HRESTART); 543209ff23fSmrg save->tv_vrestart = INREG(RADEON_TV_VRESTART); 544209ff23fSmrg save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS); 545209ff23fSmrg save->tv_hdisp = INREG(RADEON_TV_HDISP); 546209ff23fSmrg save->tv_hstart = INREG(RADEON_TV_HSTART); 547209ff23fSmrg save->tv_htotal = INREG(RADEON_TV_HTOTAL); 548209ff23fSmrg save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS); 549209ff23fSmrg save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL); 550209ff23fSmrg save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL); 551209ff23fSmrg save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1); 552209ff23fSmrg save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2); 553209ff23fSmrg save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); 554209ff23fSmrg save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL); 555209ff23fSmrg save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL); 556209ff23fSmrg save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); 557209ff23fSmrg save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL); 558209ff23fSmrg save->tv_vdisp = INREG(RADEON_TV_VDISP); 559209ff23fSmrg save->tv_ftotal = INREG(RADEON_TV_FTOTAL); 560209ff23fSmrg save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1); 561209ff23fSmrg save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2); 562209ff23fSmrg save->tv_vtotal = INREG(RADEON_TV_VTOTAL); 563209ff23fSmrg save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL); 564209ff23fSmrg save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL); 565209ff23fSmrg save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL); 566209ff23fSmrg 567209ff23fSmrg save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL); 568209ff23fSmrg save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1); 569209ff23fSmrg 570209ff23fSmrg ErrorF("Save TV timing tables\n"); 571209ff23fSmrg 572209ff23fSmrg RADEONSaveTVTimingTables(pScrn, save); 573209ff23fSmrg 574209ff23fSmrg ErrorF("TV Save done\n"); 575209ff23fSmrg} 576209ff23fSmrg 577209ff23fSmrg 578209ff23fSmrg/* Compute F,V,H restarts from default restart position and hPos & vPos 579209ff23fSmrg * Return TRUE when code timing table was changed 580209ff23fSmrg */ 581209ff23fSmrgstatic Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save, 582209ff23fSmrg DisplayModePtr mode) 583209ff23fSmrg{ 584209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 585209ff23fSmrg int restart; 586209ff23fSmrg unsigned hTotal; 587209ff23fSmrg unsigned vTotal; 588209ff23fSmrg unsigned fTotal; 589209ff23fSmrg int vOffset; 590209ff23fSmrg int hOffset; 591209ff23fSmrg uint16_t p1; 592209ff23fSmrg uint16_t p2; 593209ff23fSmrg Bool hChanged; 594209ff23fSmrg uint16_t hInc; 595209ff23fSmrg const TVModeConstants *constPtr; 596209ff23fSmrg 597209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 598209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 599209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 600209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 601209ff23fSmrg constPtr = &availableTVModes[0]; 602209ff23fSmrg else 603209ff23fSmrg constPtr = &availableTVModes[1]; 604209ff23fSmrg 605209ff23fSmrg hTotal = constPtr->horTotal; 606209ff23fSmrg vTotal = constPtr->verTotal; 607209ff23fSmrg 608209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 609209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 610209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 611209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 612209ff23fSmrg fTotal = NTSC_TV_VFTOTAL + 1; 613209ff23fSmrg else 614209ff23fSmrg fTotal = PAL_TV_VFTOTAL + 1; 615209ff23fSmrg 616209ff23fSmrg /* Adjust positions 1&2 in hor. code timing table */ 617209ff23fSmrg hOffset = radeon_output->hPos * H_POS_UNIT; 618209ff23fSmrg 619209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 620209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 621209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) { 622209ff23fSmrg /* improve image centering */ 623209ff23fSmrg hOffset -= 50; 624209ff23fSmrg p1 = hor_timing_NTSC[ H_TABLE_POS1 ]; 625209ff23fSmrg p2 = hor_timing_NTSC[ H_TABLE_POS2 ]; 626209ff23fSmrg } else { 627209ff23fSmrg p1 = hor_timing_PAL[ H_TABLE_POS1 ]; 628209ff23fSmrg p2 = hor_timing_PAL[ H_TABLE_POS2 ]; 629209ff23fSmrg } 630209ff23fSmrg 631209ff23fSmrg 632209ff23fSmrg p1 = (uint16_t)((int)p1 + hOffset); 633209ff23fSmrg p2 = (uint16_t)((int)p2 - hOffset); 634209ff23fSmrg 635209ff23fSmrg hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] || 636209ff23fSmrg p2 != save->h_code_timing[ H_TABLE_POS2 ]); 637209ff23fSmrg 638209ff23fSmrg save->h_code_timing[ H_TABLE_POS1 ] = p1; 639209ff23fSmrg save->h_code_timing[ H_TABLE_POS2 ] = p2; 640209ff23fSmrg 641209ff23fSmrg /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ 642209ff23fSmrg hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000; 643209ff23fSmrg 644209ff23fSmrg /* Adjust restart */ 645209ff23fSmrg restart = constPtr->defRestart; 646209ff23fSmrg 647209ff23fSmrg /* 648209ff23fSmrg * Convert vPos TV lines to n. of CRTC pixels 649209ff23fSmrg * Be verrrrry careful when mixing signed & unsigned values in C.. 650209ff23fSmrg */ 651209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 652209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 653209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 654209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 655209ff23fSmrg vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(NTSC_TV_LINES_PER_FRAME); 656209ff23fSmrg else 657209ff23fSmrg vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(PAL_TV_LINES_PER_FRAME); 658209ff23fSmrg 659209ff23fSmrg restart -= vOffset + hOffset; 660209ff23fSmrg 661209ff23fSmrg ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n", 662209ff23fSmrg constPtr->defRestart , radeon_output->hPos , radeon_output->vPos , p1 , p2 , restart); 663209ff23fSmrg 664209ff23fSmrg save->tv_hrestart = restart % hTotal; 665209ff23fSmrg restart /= hTotal; 666209ff23fSmrg save->tv_vrestart = restart % vTotal; 667209ff23fSmrg restart /= vTotal; 668209ff23fSmrg save->tv_frestart = restart % fTotal; 669209ff23fSmrg 670209ff23fSmrg ErrorF("computeRestarts: F/H/V=%u,%u,%u\n", 671209ff23fSmrg (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart, 672209ff23fSmrg (unsigned)save->tv_hrestart); 673209ff23fSmrg 674209ff23fSmrg /* Compute H_INC from hSize */ 675209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 676209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 677209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 678209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) / 679209ff23fSmrg (radeon_output->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); 680209ff23fSmrg else 681209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) / 682209ff23fSmrg (radeon_output->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); 683209ff23fSmrg 684209ff23fSmrg save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) | 685209ff23fSmrg ((uint32_t)hInc << RADEON_H_INC_SHIFT); 686209ff23fSmrg 687209ff23fSmrg ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , radeon_output->hSize , hInc); 688209ff23fSmrg 689209ff23fSmrg return hChanged; 690209ff23fSmrg} 691209ff23fSmrg 692209ff23fSmrg/* intit TV-out regs */ 693209ff23fSmrgvoid RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, 694209ff23fSmrg DisplayModePtr mode, BOOL IsPrimary) 695209ff23fSmrg{ 696209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 697209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 698209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 699209ff23fSmrg unsigned i; 700209ff23fSmrg unsigned long vert_space, flicker_removal; 701209ff23fSmrg uint32_t tmp; 702209ff23fSmrg const TVModeConstants *constPtr; 703209ff23fSmrg const uint16_t *hor_timing; 704209ff23fSmrg const uint16_t *vert_timing; 705209ff23fSmrg 706209ff23fSmrg 707209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 708209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 709209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 710209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 711209ff23fSmrg constPtr = &availableTVModes[0]; 712209ff23fSmrg else 713209ff23fSmrg constPtr = &availableTVModes[1]; 714209ff23fSmrg 715209ff23fSmrg save->tv_crc_cntl = 0; 716209ff23fSmrg 717209ff23fSmrg save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | 718209ff23fSmrg (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT); 719209ff23fSmrg 720209ff23fSmrg save->tv_hdisp = constPtr->horResolution - 1; 721209ff23fSmrg save->tv_hstart = constPtr->horStart; 722209ff23fSmrg save->tv_htotal = constPtr->horTotal - 1; 723209ff23fSmrg 724209ff23fSmrg save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) | 725209ff23fSmrg (0x100 << RADEON_Y_GAIN_SHIFT); 726209ff23fSmrg 727209ff23fSmrg save->tv_master_cntl = (RADEON_VIN_ASYNC_RST 728209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 729209ff23fSmrg | RADEON_TV_FIFO_CE_EN 730209ff23fSmrg | RADEON_TV_ON); 731209ff23fSmrg 732209ff23fSmrg if (!IS_R300_VARIANT) 733209ff23fSmrg save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; 734209ff23fSmrg 735209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 736209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J) 737209ff23fSmrg save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX; 738209ff23fSmrg 739209ff23fSmrg save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT 740209ff23fSmrg | RADEON_SYNC_TIP_LEVEL 741209ff23fSmrg | RADEON_YFLT_EN 742209ff23fSmrg | RADEON_UVFLT_EN 743209ff23fSmrg | (6 << RADEON_CY_FILT_BLEND_SHIFT); 744209ff23fSmrg 745209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 746209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J) { 747209ff23fSmrg save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) 748209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 749209ff23fSmrg save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | 750209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 751209ff23fSmrg } else if (radeon_output->tvStd == TV_STD_SCART_PAL) { 752209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; 753209ff23fSmrg save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | 754209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 755209ff23fSmrg } else { 756209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN 757209ff23fSmrg | (0x3b << RADEON_SET_UP_LEVEL_SHIFT) 758209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 759209ff23fSmrg save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | 760209ff23fSmrg ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 761209ff23fSmrg } 762209ff23fSmrg 763209ff23fSmrg save->pll_test_cntl = 0; 764209ff23fSmrg 765209ff23fSmrg save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN 766209ff23fSmrg | RADEON_C_GRN_EN 767209ff23fSmrg | RADEON_CMP_BLU_EN 768209ff23fSmrg | RADEON_DAC_DITHER_EN); 769209ff23fSmrg 770209ff23fSmrg save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN 771209ff23fSmrg | RADEON_TVOUT_SCALE_EN 772209ff23fSmrg | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) 773209ff23fSmrg | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT)); 774209ff23fSmrg 775209ff23fSmrg if (IsPrimary) { 776209ff23fSmrg if (radeon_output->Flags & RADEON_USE_RMX) 777209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; 778209ff23fSmrg else 779209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; 780209ff23fSmrg } else { 781209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; 782209ff23fSmrg } 783209ff23fSmrg 784209ff23fSmrg save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE; 785209ff23fSmrg 786209ff23fSmrg save->tv_sync_size = constPtr->horResolution + 8; 787209ff23fSmrg 788209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 789209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 790209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 791209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 792209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; 793209ff23fSmrg else 794209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME; 795209ff23fSmrg 796209ff23fSmrg save->tv_vscaler_cntl1 = RADEON_Y_W_EN; 797209ff23fSmrg save->tv_vscaler_cntl1 = 798209ff23fSmrg (save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000); 799209ff23fSmrg save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; 800209ff23fSmrg if (constPtr->horResolution == 1024) 801209ff23fSmrg save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); 802209ff23fSmrg else 803209ff23fSmrg save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); 804209ff23fSmrg 805209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 806209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 807209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 808209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 809209ff23fSmrg flicker_removal = 810209ff23fSmrg (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5; 811209ff23fSmrg else 812209ff23fSmrg flicker_removal = 813209ff23fSmrg (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5; 814209ff23fSmrg 815209ff23fSmrg if (flicker_removal < 3) 816209ff23fSmrg flicker_removal = 3; 817209ff23fSmrg for (i = 0; i < 6; ++i) { 818209ff23fSmrg if (flicker_removal == SLOPE_limit[i]) 819209ff23fSmrg break; 820209ff23fSmrg } 821209ff23fSmrg save->tv_y_saw_tooth_cntl = 822209ff23fSmrg (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8 823209ff23fSmrg | ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16); 824209ff23fSmrg save->tv_y_fall_cntl = 825209ff23fSmrg (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | 826209ff23fSmrg RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / 827209ff23fSmrg 1024; 828209ff23fSmrg save->tv_y_rise_cntl = 829209ff23fSmrg RADEON_Y_RISE_PING_PONG 830209ff23fSmrg | (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; 831209ff23fSmrg 832209ff23fSmrg save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0) 833209ff23fSmrg | (0x10 << 24) 834209ff23fSmrg | RADEON_DITHER_MODE 835209ff23fSmrg | RADEON_Y_OUTPUT_DITHER_EN 836209ff23fSmrg | RADEON_UV_OUTPUT_DITHER_EN 837209ff23fSmrg | RADEON_UV_TO_BUF_DITHER_EN); 838209ff23fSmrg 839209ff23fSmrg tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; 840209ff23fSmrg tmp = ((16384 * 256 * 10) / tmp + 5) / 10; 841209ff23fSmrg tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; 842209ff23fSmrg save->tv_timing_cntl = tmp; 843209ff23fSmrg 844209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 845209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 846209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 847209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 848209ff23fSmrg save->tv_dac_cntl = radeon_output->ntsc_tvdac_adj; 849209ff23fSmrg else 850209ff23fSmrg save->tv_dac_cntl = radeon_output->pal_tvdac_adj; 851209ff23fSmrg 852209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD); 853209ff23fSmrg 854209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 855209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J) 856209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; 857209ff23fSmrg else 858209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; 859209ff23fSmrg 860209ff23fSmrg#if 0 861209ff23fSmrg /* needs fixes for r4xx */ 862209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD 863209ff23fSmrg | RADEON_TV_DAC_BDACPD); 864209ff23fSmrg 865209ff23fSmrg if (radeon_output->MonType == MT_CTV) { 866209ff23fSmrg save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD; 867209ff23fSmrg } 868209ff23fSmrg 869209ff23fSmrg if (radeon_output->MonType == MT_STV) { 870209ff23fSmrg save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | 871209ff23fSmrg RADEON_TV_DAC_GDACPD); 872209ff23fSmrg } 873209ff23fSmrg#endif 874209ff23fSmrg 875209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 876209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J) 877209ff23fSmrg save->tv_pll_cntl = (NTSC_TV_PLL_M & RADEON_TV_M0LO_MASK) | 878209ff23fSmrg (((NTSC_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | 879209ff23fSmrg ((NTSC_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | 880209ff23fSmrg (((NTSC_TV_PLL_N >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | 881209ff23fSmrg ((NTSC_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); 882209ff23fSmrg else 883209ff23fSmrg save->tv_pll_cntl = (PAL_TV_PLL_M & RADEON_TV_M0LO_MASK) | 884209ff23fSmrg (((PAL_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | 885209ff23fSmrg ((PAL_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | 886209ff23fSmrg (((PAL_TV_PLL_N >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | 887209ff23fSmrg ((PAL_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); 888209ff23fSmrg 889209ff23fSmrg save->tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) | 890209ff23fSmrg ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) | 891209ff23fSmrg ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) | 892209ff23fSmrg RADEON_TVCLK_SRC_SEL_TVPLL | 893209ff23fSmrg RADEON_TVPLL_TEST_DIS); 894209ff23fSmrg 895209ff23fSmrg save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN; 896209ff23fSmrg 897209ff23fSmrg save->tv_uv_adr = 0xc8; 898209ff23fSmrg 899209ff23fSmrg save->tv_vdisp = constPtr->verResolution - 1; 900209ff23fSmrg 901209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 902209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 903209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 904209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) 905209ff23fSmrg save->tv_ftotal = NTSC_TV_VFTOTAL; 906209ff23fSmrg else 907209ff23fSmrg save->tv_ftotal = PAL_TV_VFTOTAL; 908209ff23fSmrg 909209ff23fSmrg save->tv_vtotal = constPtr->verTotal - 1; 910209ff23fSmrg 911209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 912209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 913209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) { 914209ff23fSmrg hor_timing = hor_timing_NTSC; 915209ff23fSmrg } else { 916209ff23fSmrg hor_timing = hor_timing_PAL; 917209ff23fSmrg } 918209ff23fSmrg 919209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 920209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 921209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M || 922209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_60) { 923209ff23fSmrg vert_timing = vert_timing_NTSC; 924209ff23fSmrg } else { 925209ff23fSmrg vert_timing = vert_timing_PAL; 926209ff23fSmrg } 927209ff23fSmrg 928209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { 929209ff23fSmrg if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0) 930209ff23fSmrg break; 931209ff23fSmrg } 932209ff23fSmrg 933209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { 934209ff23fSmrg if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0) 935209ff23fSmrg break; 936209ff23fSmrg } 937209ff23fSmrg 938209ff23fSmrg /* 939209ff23fSmrg * This must be called AFTER loading timing tables as they are modified by this function 940209ff23fSmrg */ 941209ff23fSmrg RADEONInitTVRestarts(output, save, mode); 942209ff23fSmrg 943209ff23fSmrg save->dac_cntl &= ~RADEON_DAC_TVO_EN; 944209ff23fSmrg 945209ff23fSmrg if (IS_R300_VARIANT) 946209ff23fSmrg save->gpiopad_a = info->SavedReg->gpiopad_a & ~1; 947209ff23fSmrg 948209ff23fSmrg if (IsPrimary) { 949209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 950209ff23fSmrg save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC 951209ff23fSmrg | RADEON_DISP_TV_SOURCE_CRTC); 952209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 953209ff23fSmrg save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; 954209ff23fSmrg } else { 955209ff23fSmrg save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 956209ff23fSmrg } 957209ff23fSmrg } else { 958209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK; 959209ff23fSmrg save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; 960209ff23fSmrg 961209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 962209ff23fSmrg save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; 963209ff23fSmrg } else { 964209ff23fSmrg save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; 965209ff23fSmrg } 966209ff23fSmrg } 967209ff23fSmrg} 968209ff23fSmrg 969209ff23fSmrg 970209ff23fSmrg/* Set hw registers for a new h/v position & h size */ 971209ff23fSmrgvoid RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode) 972209ff23fSmrg{ 973209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 974209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 975209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 976209ff23fSmrg Bool reloadTable; 977209ff23fSmrg RADEONSavePtr restore = info->ModeReg; 978209ff23fSmrg 979209ff23fSmrg reloadTable = RADEONInitTVRestarts(output, restore, mode); 980209ff23fSmrg 981209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 982209ff23fSmrg 983209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 984209ff23fSmrg 985209ff23fSmrg if (reloadTable) { 986209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl 987209ff23fSmrg | RADEON_TV_ASYNC_RST 988209ff23fSmrg | RADEON_CRT_ASYNC_RST 989209ff23fSmrg | RADEON_RESTART_PHASE_FIX); 990209ff23fSmrg 991209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 992209ff23fSmrg 993209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 994209ff23fSmrg } 995209ff23fSmrg} 996209ff23fSmrg 997209ff23fSmrgvoid RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 998209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 999209ff23fSmrg{ 1000209ff23fSmrg const TVModeConstants *constPtr; 1001209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1002209ff23fSmrg 1003209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1004209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 1005209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 1006209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 1007209ff23fSmrg constPtr = &availableTVModes[0]; 1008209ff23fSmrg else 1009209ff23fSmrg constPtr = &availableTVModes[1]; 1010209ff23fSmrg 1011209ff23fSmrg save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1012209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1013209ff23fSmrg 1014209ff23fSmrg save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid 1015209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1016209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1017209ff23fSmrg (constPtr->horSyncStart & 7); 1018209ff23fSmrg 1019209ff23fSmrg save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1020209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1021209ff23fSmrg 1022209ff23fSmrg save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1023209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1024209ff23fSmrg 1025209ff23fSmrg} 1026209ff23fSmrg 1027209ff23fSmrgvoid RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1028209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1029209ff23fSmrg{ 1030209ff23fSmrg unsigned postDiv; 1031209ff23fSmrg const TVModeConstants *constPtr; 1032209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1033209ff23fSmrg 1034209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1035209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 1036209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 1037209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 1038209ff23fSmrg constPtr = &availableTVModes[0]; 1039209ff23fSmrg else 1040209ff23fSmrg constPtr = &availableTVModes[1]; 1041209ff23fSmrg 1042209ff23fSmrg save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN; 1043209ff23fSmrg 1044209ff23fSmrg save->ppll_ref_div = constPtr->crtcPLL_M; 1045209ff23fSmrg 1046209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1047209ff23fSmrg case 1: 1048209ff23fSmrg postDiv = 0; 1049209ff23fSmrg break; 1050209ff23fSmrg case 2: 1051209ff23fSmrg postDiv = 1; 1052209ff23fSmrg break; 1053209ff23fSmrg case 3: 1054209ff23fSmrg postDiv = 4; 1055209ff23fSmrg break; 1056209ff23fSmrg case 4: 1057209ff23fSmrg postDiv = 2; 1058209ff23fSmrg break; 1059209ff23fSmrg case 6: 1060209ff23fSmrg postDiv = 6; 1061209ff23fSmrg break; 1062209ff23fSmrg case 8: 1063209ff23fSmrg postDiv = 3; 1064209ff23fSmrg break; 1065209ff23fSmrg case 12: 1066209ff23fSmrg postDiv = 7; 1067209ff23fSmrg break; 1068209ff23fSmrg case 16: 1069209ff23fSmrg default: 1070209ff23fSmrg postDiv = 5; 1071209ff23fSmrg break; 1072209ff23fSmrg } 1073209ff23fSmrg 1074209ff23fSmrg save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1075209ff23fSmrg 1076209ff23fSmrg save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); 1077209ff23fSmrg save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; 1078209ff23fSmrg 1079209ff23fSmrg} 1080209ff23fSmrg 1081209ff23fSmrgvoid RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1082209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1083209ff23fSmrg{ 1084209ff23fSmrg const TVModeConstants *constPtr; 1085209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1086209ff23fSmrg 1087209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1088209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 1089209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 1090209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 1091209ff23fSmrg constPtr = &availableTVModes[0]; 1092209ff23fSmrg else 1093209ff23fSmrg constPtr = &availableTVModes[1]; 1094209ff23fSmrg 1095209ff23fSmrg save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1096209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1097209ff23fSmrg 1098209ff23fSmrg save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid 1099209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1100209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1101209ff23fSmrg (constPtr->horSyncStart & 7); 1102209ff23fSmrg 1103209ff23fSmrg save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1104209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1105209ff23fSmrg 1106209ff23fSmrg save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1107209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1108209ff23fSmrg 1109209ff23fSmrg} 1110209ff23fSmrg 1111209ff23fSmrgvoid RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1112209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1113209ff23fSmrg{ 1114209ff23fSmrg unsigned postDiv; 1115209ff23fSmrg const TVModeConstants *constPtr; 1116209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1117209ff23fSmrg 1118209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1119209ff23fSmrg if (radeon_output->tvStd == TV_STD_NTSC || 1120209ff23fSmrg radeon_output->tvStd == TV_STD_NTSC_J || 1121209ff23fSmrg radeon_output->tvStd == TV_STD_PAL_M) 1122209ff23fSmrg constPtr = &availableTVModes[0]; 1123209ff23fSmrg else 1124209ff23fSmrg constPtr = &availableTVModes[1]; 1125209ff23fSmrg 1126209ff23fSmrg save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */ 1127209ff23fSmrg 1128209ff23fSmrg save->p2pll_ref_div = constPtr->crtcPLL_M; 1129209ff23fSmrg 1130209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1131209ff23fSmrg case 1: 1132209ff23fSmrg postDiv = 0; 1133209ff23fSmrg break; 1134209ff23fSmrg case 2: 1135209ff23fSmrg postDiv = 1; 1136209ff23fSmrg break; 1137209ff23fSmrg case 3: 1138209ff23fSmrg postDiv = 4; 1139209ff23fSmrg break; 1140209ff23fSmrg case 4: 1141209ff23fSmrg postDiv = 2; 1142209ff23fSmrg break; 1143209ff23fSmrg case 6: 1144209ff23fSmrg postDiv = 6; 1145209ff23fSmrg break; 1146209ff23fSmrg case 8: 1147209ff23fSmrg postDiv = 3; 1148209ff23fSmrg break; 1149209ff23fSmrg case 12: 1150209ff23fSmrg postDiv = 7; 1151209ff23fSmrg break; 1152209ff23fSmrg case 16: 1153209ff23fSmrg default: 1154209ff23fSmrg postDiv = 5; 1155209ff23fSmrg break; 1156209ff23fSmrg } 1157209ff23fSmrg 1158209ff23fSmrg save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1159209ff23fSmrg 1160209ff23fSmrg save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; 1161209ff23fSmrg save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 1162209ff23fSmrg | RADEON_PIXCLK_TV_SRC_SEL); 1163209ff23fSmrg 1164209ff23fSmrg} 1165