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 }, 189ad43ddacSmrg { /* PAL timing for 14 Mhz ref clk */ 190ad43ddacSmrg 800, /* horResolution */ 191ad43ddacSmrg 600, /* verResolution */ 192ad43ddacSmrg TV_STD_PAL, /* standard */ 193ad43ddacSmrg 1131, /* horTotal */ 194ad43ddacSmrg 742, /* verTotal */ 195ad43ddacSmrg 813, /* horStart */ 196ad43ddacSmrg 840, /* horSyncStart */ 197ad43ddacSmrg 633, /* verSyncStart */ 198ad43ddacSmrg 708369, /* defRestart */ 199ad43ddacSmrg 211, /* crtcPLL_N */ 200ad43ddacSmrg 9, /* crtcPLL_M */ 201ad43ddacSmrg 8, /* crtcPLL_postDiv */ 202ad43ddacSmrg 759, /* pixToTV */ 203ad43ddacSmrg }, 204209ff23fSmrg}; 205209ff23fSmrg 206209ff23fSmrg#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ])) 207209ff23fSmrg 208209ff23fSmrgstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; 209209ff23fSmrgstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; 210209ff23fSmrgstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; 211209ff23fSmrgstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; 212209ff23fSmrg 213209ff23fSmrg 214209ff23fSmrgstatic void 215209ff23fSmrgRADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, 216209ff23fSmrg unsigned nWaitLoops, unsigned cntThreshold) 217209ff23fSmrg{ 218209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 219209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 220209ff23fSmrg uint32_t savePLLTest; 221209ff23fSmrg unsigned i; 222209ff23fSmrg unsigned j; 223209ff23fSmrg 224209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); 225209ff23fSmrg 226209ff23fSmrg savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL); 227209ff23fSmrg 228209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B); 229209ff23fSmrg 230209ff23fSmrg /* XXX: these should probably be OUTPLL to avoid various PLL errata */ 231209ff23fSmrg 232209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); 233209ff23fSmrg 234209ff23fSmrg for (i = 0; i < nTests; i++) { 235209ff23fSmrg OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); 236209ff23fSmrg 237209ff23fSmrg for (j = 0; j < nWaitLoops; j++) 238209ff23fSmrg if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold) 239209ff23fSmrg break; 240209ff23fSmrg } 241209ff23fSmrg 242209ff23fSmrg OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest); 243209ff23fSmrg 244209ff23fSmrg OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); 245209ff23fSmrg} 246209ff23fSmrg 247209ff23fSmrg/* Write to TV FIFO RAM */ 248209ff23fSmrgstatic void 249209ff23fSmrgRADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr, 250209ff23fSmrg uint32_t value) 251209ff23fSmrg{ 252209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 253209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 254209ff23fSmrg uint32_t tmp; 255209ff23fSmrg int i = 0; 256209ff23fSmrg 257209ff23fSmrg OUTREG(RADEON_TV_HOST_WRITE_DATA, value); 258209ff23fSmrg 259209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 260209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); 261209ff23fSmrg 262209ff23fSmrg do { 263209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 264209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) 265209ff23fSmrg break; 266209ff23fSmrg i++; 267209ff23fSmrg } 268209ff23fSmrg while (i < 10000); 269209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ 270209ff23fSmrg 271209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 272209ff23fSmrg} 273209ff23fSmrg 274209ff23fSmrg/* Read from TV FIFO RAM */ 275209ff23fSmrgstatic uint32_t 276209ff23fSmrgRADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr) 277209ff23fSmrg{ 278209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 279209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 280209ff23fSmrg uint32_t tmp; 281209ff23fSmrg int i = 0; 282209ff23fSmrg 283209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); 284209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); 285209ff23fSmrg 286209ff23fSmrg do { 287209ff23fSmrg tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); 288209ff23fSmrg if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) 289209ff23fSmrg break; 290209ff23fSmrg i++; 291209ff23fSmrg } 292209ff23fSmrg while (i < 10000); 293209ff23fSmrg /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/ 294209ff23fSmrg 295209ff23fSmrg OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); 296209ff23fSmrg 297209ff23fSmrg return INREG(RADEON_TV_HOST_READ_DATA); 298209ff23fSmrg} 299209ff23fSmrg 300209ff23fSmrg/* Get FIFO addresses of horizontal & vertical code timing tables from 301209ff23fSmrg * settings of uv_adr register. 302209ff23fSmrg */ 303209ff23fSmrgstatic uint16_t 304209ff23fSmrgRADEONGetHTimingTablesAddr(uint32_t tv_uv_adr) 305209ff23fSmrg{ 306209ff23fSmrg uint16_t hTable; 307209ff23fSmrg 308209ff23fSmrg switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { 309209ff23fSmrg case 0: 310209ff23fSmrg hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; 311209ff23fSmrg break; 312209ff23fSmrg case 1: 313209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; 314209ff23fSmrg break; 315209ff23fSmrg case 2: 316209ff23fSmrg hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; 317209ff23fSmrg break; 318209ff23fSmrg default: 319209ff23fSmrg /* Of course, this should never happen */ 320209ff23fSmrg hTable = 0; 321209ff23fSmrg break; 322209ff23fSmrg } 323209ff23fSmrg return hTable; 324209ff23fSmrg} 325209ff23fSmrg 326209ff23fSmrgstatic uint16_t 327209ff23fSmrgRADEONGetVTimingTablesAddr(uint32_t tv_uv_adr) 328209ff23fSmrg{ 329209ff23fSmrg uint16_t vTable; 330209ff23fSmrg 331209ff23fSmrg switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { 332209ff23fSmrg case 0: 333209ff23fSmrg vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; 334209ff23fSmrg break; 335209ff23fSmrg case 1: 336209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; 337209ff23fSmrg break; 338209ff23fSmrg case 2: 339209ff23fSmrg vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; 340209ff23fSmrg break; 341209ff23fSmrg default: 342209ff23fSmrg /* Of course, this should never happen */ 343209ff23fSmrg vTable = 0; 344209ff23fSmrg break; 345209ff23fSmrg } 346209ff23fSmrg return vTable; 347209ff23fSmrg} 348209ff23fSmrg 349209ff23fSmrg/* Restore horizontal/vertical timing code tables */ 350209ff23fSmrgstatic void 351209ff23fSmrgRADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore) 352209ff23fSmrg{ 353209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 354209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 355209ff23fSmrg uint16_t hTable; 356209ff23fSmrg uint16_t vTable; 357209ff23fSmrg uint32_t tmp; 358209ff23fSmrg unsigned i; 359209ff23fSmrg 360209ff23fSmrg OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr); 361209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr); 362209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr); 363209ff23fSmrg 364209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) { 365209ff23fSmrg tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]); 366209ff23fSmrg RADEONWriteTVFIFO(pScrn, hTable, tmp); 367209ff23fSmrg if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0) 368209ff23fSmrg break; 369209ff23fSmrg } 370209ff23fSmrg 371209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) { 372209ff23fSmrg tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]); 373209ff23fSmrg RADEONWriteTVFIFO(pScrn, vTable, tmp); 374209ff23fSmrg if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0) 375209ff23fSmrg break; 376209ff23fSmrg } 377209ff23fSmrg} 378209ff23fSmrg 379209ff23fSmrg/* restore TV PLLs */ 380209ff23fSmrgstatic void 381209ff23fSmrgRADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 382209ff23fSmrg{ 383209ff23fSmrg 384209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); 385209ff23fSmrg OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl); 386209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); 387209ff23fSmrg 388209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 389209ff23fSmrg 390209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); 391209ff23fSmrg 392209ff23fSmrg RADEONWaitPLLLock(pScrn, 300, 160, 27); 393209ff23fSmrg RADEONWaitPLLLock(pScrn, 200, 800, 135); 394209ff23fSmrg 395209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf); 396209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); 397209ff23fSmrg 398209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); 399209ff23fSmrg OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); 400209ff23fSmrg} 401209ff23fSmrg 402209ff23fSmrg/* Restore TV horizontal/vertical settings */ 403209ff23fSmrgstatic void 404209ff23fSmrgRADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 405209ff23fSmrg{ 406209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 407209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 408209ff23fSmrg 409209ff23fSmrg OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl); 410209ff23fSmrg 411209ff23fSmrg OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal); 412209ff23fSmrg OUTREG(RADEON_TV_HDISP, restore->tv_hdisp); 413209ff23fSmrg OUTREG(RADEON_TV_HSTART, restore->tv_hstart); 414209ff23fSmrg 415209ff23fSmrg OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal); 416209ff23fSmrg OUTREG(RADEON_TV_VDISP, restore->tv_vdisp); 417209ff23fSmrg 418209ff23fSmrg OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal); 419209ff23fSmrg 420209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1); 421209ff23fSmrg OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2); 422209ff23fSmrg 423209ff23fSmrg OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl); 424209ff23fSmrg OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl); 425209ff23fSmrg OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl); 426209ff23fSmrg} 427209ff23fSmrg 428209ff23fSmrg/* restore TV RESTART registers */ 429209ff23fSmrgstatic void 430209ff23fSmrgRADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore) 431209ff23fSmrg{ 432209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 433209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 434209ff23fSmrg 435209ff23fSmrg OUTREG(RADEON_TV_FRESTART, restore->tv_frestart); 436209ff23fSmrg OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart); 437209ff23fSmrg OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart); 438209ff23fSmrg} 439209ff23fSmrg 440209ff23fSmrg/* restore tv standard & output muxes */ 441209ff23fSmrgstatic void 442209ff23fSmrgRADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore) 443209ff23fSmrg{ 444209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 445209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 446209ff23fSmrg 447209ff23fSmrg OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl); 448209ff23fSmrg 449209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 450209ff23fSmrg 451209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1); 452209ff23fSmrg OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2); 453209ff23fSmrg 454209ff23fSmrg OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl); 455209ff23fSmrg 456209ff23fSmrg OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl); 457209ff23fSmrg} 458209ff23fSmrg 459209ff23fSmrg/* Restore TV out regs */ 460209ff23fSmrgvoid 461209ff23fSmrgRADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) 462209ff23fSmrg{ 463209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 464209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 465209ff23fSmrg 466209ff23fSmrg ErrorF("Entering Restore TV\n"); 467209ff23fSmrg 468209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 469209ff23fSmrg | RADEON_TV_ASYNC_RST 470209ff23fSmrg | RADEON_CRT_ASYNC_RST 471209ff23fSmrg | RADEON_TV_FIFO_ASYNC_RST)); 472209ff23fSmrg 473209ff23fSmrg /* Temporarily turn the TV DAC off */ 474209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK) 475209ff23fSmrg | RADEON_TV_DAC_BGSLEEP 476209ff23fSmrg | RADEON_TV_DAC_RDACPD 477209ff23fSmrg | RADEON_TV_DAC_GDACPD 478209ff23fSmrg | RADEON_TV_DAC_BDACPD)); 479209ff23fSmrg 480209ff23fSmrg ErrorF("Restore TV PLL\n"); 481209ff23fSmrg RADEONRestoreTVPLLRegisters(pScrn, restore); 482209ff23fSmrg 483209ff23fSmrg ErrorF("Restore TVHV\n"); 484209ff23fSmrg RADEONRestoreTVHVRegisters(pScrn, restore); 485209ff23fSmrg 486209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 487209ff23fSmrg | RADEON_TV_ASYNC_RST 488209ff23fSmrg | RADEON_CRT_ASYNC_RST)); 489209ff23fSmrg 490209ff23fSmrg ErrorF("Restore TV Restarts\n"); 491209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 492209ff23fSmrg 493209ff23fSmrg ErrorF("Restore Timing Tables\n"); 494209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 495209ff23fSmrg 496209ff23fSmrg 497209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl 498209ff23fSmrg | RADEON_TV_ASYNC_RST)); 499209ff23fSmrg 500209ff23fSmrg ErrorF("Restore TV standard\n"); 501209ff23fSmrg RADEONRestoreTVOutputStd(pScrn, restore); 502209ff23fSmrg 503209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 504209ff23fSmrg 505209ff23fSmrg OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); 506209ff23fSmrg OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); 507209ff23fSmrg 508209ff23fSmrg OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); 509209ff23fSmrg 510209ff23fSmrg ErrorF("Leaving Restore TV\n"); 511209ff23fSmrg} 512209ff23fSmrg 513209ff23fSmrg/* Save horizontal/vertical timing code tables */ 514209ff23fSmrgstatic void 515209ff23fSmrgRADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save) 516209ff23fSmrg{ 517209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 518209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 519209ff23fSmrg uint16_t hTable; 520209ff23fSmrg uint16_t vTable; 521209ff23fSmrg uint32_t tmp; 522209ff23fSmrg unsigned i; 523209ff23fSmrg 524209ff23fSmrg save->tv_uv_adr = INREG(RADEON_TV_UV_ADR); 525209ff23fSmrg hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr); 526209ff23fSmrg vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr); 527209ff23fSmrg 528209ff23fSmrg /* 529209ff23fSmrg * Reset FIFO arbiter in order to be able to access FIFO RAM 530209ff23fSmrg */ 531209ff23fSmrg 532209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST 533209ff23fSmrg | RADEON_CRT_ASYNC_RST 534209ff23fSmrg | RADEON_RESTART_PHASE_FIX 535209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 536209ff23fSmrg | RADEON_TV_FIFO_CE_EN 537209ff23fSmrg | RADEON_TV_ON)); 538209ff23fSmrg 539209ff23fSmrg /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/ 540209ff23fSmrg 541209ff23fSmrg ErrorF("saveTimingTables: reading timing tables\n"); 542209ff23fSmrg 543209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) { 544209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, hTable--); 545209ff23fSmrg save->h_code_timing[ i ] = (uint16_t)((tmp >> 14) & 0x3fff); 546209ff23fSmrg save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff); 547209ff23fSmrg 548209ff23fSmrg if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0) 549209ff23fSmrg break; 550209ff23fSmrg } 551209ff23fSmrg 552209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) { 553209ff23fSmrg tmp = RADEONReadTVFIFO(pScrn, vTable++); 554209ff23fSmrg save->v_code_timing[ i ] = (uint16_t)(tmp & 0x3fff); 555209ff23fSmrg save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff); 556209ff23fSmrg 557209ff23fSmrg if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0) 558209ff23fSmrg break; 559209ff23fSmrg } 560209ff23fSmrg} 561209ff23fSmrg 562209ff23fSmrg/* read TV regs */ 563209ff23fSmrgvoid 564209ff23fSmrgRADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) 565209ff23fSmrg{ 566209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 567209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 568209ff23fSmrg 569209ff23fSmrg ErrorF("Entering TV Save\n"); 570209ff23fSmrg 571209ff23fSmrg save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL); 572209ff23fSmrg save->tv_frestart = INREG(RADEON_TV_FRESTART); 573209ff23fSmrg save->tv_hrestart = INREG(RADEON_TV_HRESTART); 574209ff23fSmrg save->tv_vrestart = INREG(RADEON_TV_VRESTART); 575209ff23fSmrg save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS); 576209ff23fSmrg save->tv_hdisp = INREG(RADEON_TV_HDISP); 577209ff23fSmrg save->tv_hstart = INREG(RADEON_TV_HSTART); 578209ff23fSmrg save->tv_htotal = INREG(RADEON_TV_HTOTAL); 579209ff23fSmrg save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS); 580209ff23fSmrg save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL); 581209ff23fSmrg save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL); 582209ff23fSmrg save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1); 583209ff23fSmrg save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2); 584209ff23fSmrg save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); 585209ff23fSmrg save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL); 586209ff23fSmrg save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL); 587209ff23fSmrg save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); 588209ff23fSmrg save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL); 589209ff23fSmrg save->tv_vdisp = INREG(RADEON_TV_VDISP); 590209ff23fSmrg save->tv_ftotal = INREG(RADEON_TV_FTOTAL); 591209ff23fSmrg save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1); 592209ff23fSmrg save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2); 593209ff23fSmrg save->tv_vtotal = INREG(RADEON_TV_VTOTAL); 594209ff23fSmrg save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL); 595209ff23fSmrg save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL); 596209ff23fSmrg save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL); 597209ff23fSmrg 598209ff23fSmrg save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL); 599209ff23fSmrg save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1); 600209ff23fSmrg 601209ff23fSmrg ErrorF("Save TV timing tables\n"); 602209ff23fSmrg 603209ff23fSmrg RADEONSaveTVTimingTables(pScrn, save); 604209ff23fSmrg 605209ff23fSmrg ErrorF("TV Save done\n"); 606209ff23fSmrg} 607209ff23fSmrg 608209ff23fSmrg 609209ff23fSmrg/* Compute F,V,H restarts from default restart position and hPos & vPos 610209ff23fSmrg * Return TRUE when code timing table was changed 611209ff23fSmrg */ 612209ff23fSmrgstatic Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save, 613209ff23fSmrg DisplayModePtr mode) 614209ff23fSmrg{ 615209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 616b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 617b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(output->scrn); 618b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 619209ff23fSmrg int restart; 620209ff23fSmrg unsigned hTotal; 621209ff23fSmrg unsigned vTotal; 622209ff23fSmrg unsigned fTotal; 623209ff23fSmrg int vOffset; 624209ff23fSmrg int hOffset; 625209ff23fSmrg uint16_t p1; 626209ff23fSmrg uint16_t p2; 627209ff23fSmrg Bool hChanged; 628209ff23fSmrg uint16_t hInc; 629209ff23fSmrg const TVModeConstants *constPtr; 630209ff23fSmrg 631209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 632b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 633b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 634b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 635b7e1c893Smrg if (pll->reference_freq == 2700) 636b7e1c893Smrg constPtr = &availableTVModes[0]; 637b7e1c893Smrg else 638b7e1c893Smrg constPtr = &availableTVModes[2]; 639b7e1c893Smrg } else { 640b7e1c893Smrg if (pll->reference_freq == 2700) 641b7e1c893Smrg constPtr = &availableTVModes[1]; 642b7e1c893Smrg else 643ad43ddacSmrg constPtr = &availableTVModes[3]; 644b7e1c893Smrg } 645209ff23fSmrg 646209ff23fSmrg hTotal = constPtr->horTotal; 647209ff23fSmrg vTotal = constPtr->verTotal; 648b7e1c893Smrg 649b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 650b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 651b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 652b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 653209ff23fSmrg fTotal = NTSC_TV_VFTOTAL + 1; 654209ff23fSmrg else 655209ff23fSmrg fTotal = PAL_TV_VFTOTAL + 1; 656209ff23fSmrg 657209ff23fSmrg /* Adjust positions 1&2 in hor. code timing table */ 658b7e1c893Smrg hOffset = tvout->hPos * H_POS_UNIT; 659209ff23fSmrg 660b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 661b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 662b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 663209ff23fSmrg /* improve image centering */ 664209ff23fSmrg hOffset -= 50; 665209ff23fSmrg p1 = hor_timing_NTSC[ H_TABLE_POS1 ]; 666209ff23fSmrg p2 = hor_timing_NTSC[ H_TABLE_POS2 ]; 667209ff23fSmrg } else { 668209ff23fSmrg p1 = hor_timing_PAL[ H_TABLE_POS1 ]; 669209ff23fSmrg p2 = hor_timing_PAL[ H_TABLE_POS2 ]; 670209ff23fSmrg } 671209ff23fSmrg 672209ff23fSmrg 673209ff23fSmrg p1 = (uint16_t)((int)p1 + hOffset); 674209ff23fSmrg p2 = (uint16_t)((int)p2 - hOffset); 675209ff23fSmrg 676209ff23fSmrg hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] || 677209ff23fSmrg p2 != save->h_code_timing[ H_TABLE_POS2 ]); 678209ff23fSmrg 679209ff23fSmrg save->h_code_timing[ H_TABLE_POS1 ] = p1; 680209ff23fSmrg save->h_code_timing[ H_TABLE_POS2 ] = p2; 681209ff23fSmrg 682209ff23fSmrg /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ 683209ff23fSmrg hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000; 684209ff23fSmrg 685209ff23fSmrg /* Adjust restart */ 686209ff23fSmrg restart = constPtr->defRestart; 687209ff23fSmrg 688209ff23fSmrg /* 689209ff23fSmrg * Convert vPos TV lines to n. of CRTC pixels 690209ff23fSmrg * Be verrrrry careful when mixing signed & unsigned values in C.. 691209ff23fSmrg */ 692b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 693b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 694b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 695b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 696b7e1c893Smrg vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(NTSC_TV_LINES_PER_FRAME); 697209ff23fSmrg else 698b7e1c893Smrg vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(PAL_TV_LINES_PER_FRAME); 699209ff23fSmrg 700209ff23fSmrg restart -= vOffset + hOffset; 701209ff23fSmrg 702209ff23fSmrg ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n", 703b7e1c893Smrg constPtr->defRestart , tvout->hPos , tvout->vPos , p1 , p2 , restart); 704209ff23fSmrg 705209ff23fSmrg save->tv_hrestart = restart % hTotal; 706209ff23fSmrg restart /= hTotal; 707209ff23fSmrg save->tv_vrestart = restart % vTotal; 708209ff23fSmrg restart /= vTotal; 709209ff23fSmrg save->tv_frestart = restart % fTotal; 710209ff23fSmrg 711209ff23fSmrg ErrorF("computeRestarts: F/H/V=%u,%u,%u\n", 712209ff23fSmrg (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart, 713209ff23fSmrg (unsigned)save->tv_hrestart); 714209ff23fSmrg 715209ff23fSmrg /* Compute H_INC from hSize */ 716b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 717b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 718b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) 719209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) / 720b7e1c893Smrg (tvout->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); 721209ff23fSmrg else 722209ff23fSmrg hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) / 723b7e1c893Smrg (tvout->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); 724209ff23fSmrg 725209ff23fSmrg save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) | 726209ff23fSmrg ((uint32_t)hInc << RADEON_H_INC_SHIFT); 727209ff23fSmrg 728b7e1c893Smrg ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , tvout->hSize , hInc); 729209ff23fSmrg 730209ff23fSmrg return hChanged; 731209ff23fSmrg} 732209ff23fSmrg 733209ff23fSmrg/* intit TV-out regs */ 734209ff23fSmrgvoid RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, 735209ff23fSmrg DisplayModePtr mode, BOOL IsPrimary) 736209ff23fSmrg{ 737209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 738209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 739b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 740209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 741b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 742b7e1c893Smrg unsigned m, n, p; 743209ff23fSmrg unsigned i; 744209ff23fSmrg unsigned long vert_space, flicker_removal; 745209ff23fSmrg uint32_t tmp; 746209ff23fSmrg const TVModeConstants *constPtr; 747209ff23fSmrg const uint16_t *hor_timing; 748209ff23fSmrg const uint16_t *vert_timing; 749b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 750b7e1c893Smrg radeon_tvdac_ptr tvdac = NULL; 751b7e1c893Smrg 752b7e1c893Smrg if (radeon_encoder == NULL) 753b7e1c893Smrg return; 754b7e1c893Smrg 755b7e1c893Smrg tvdac = (radeon_tvdac_ptr)radeon_encoder->dev_priv; 756209ff23fSmrg 757b7e1c893Smrg if (tvdac == NULL) 758b7e1c893Smrg return; 759209ff23fSmrg 760209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 761b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 762b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 763b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 764b7e1c893Smrg if (pll->reference_freq == 2700) 765b7e1c893Smrg constPtr = &availableTVModes[0]; 766b7e1c893Smrg else 767b7e1c893Smrg constPtr = &availableTVModes[2]; 768b7e1c893Smrg } else { 769b7e1c893Smrg if (pll->reference_freq == 2700) 770b7e1c893Smrg constPtr = &availableTVModes[1]; 771b7e1c893Smrg else 772ad43ddacSmrg constPtr = &availableTVModes[3]; 773b7e1c893Smrg } 774209ff23fSmrg 775209ff23fSmrg save->tv_crc_cntl = 0; 776209ff23fSmrg 777209ff23fSmrg save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | 778209ff23fSmrg (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT); 779209ff23fSmrg 780209ff23fSmrg save->tv_hdisp = constPtr->horResolution - 1; 781209ff23fSmrg save->tv_hstart = constPtr->horStart; 782209ff23fSmrg save->tv_htotal = constPtr->horTotal - 1; 783209ff23fSmrg 784209ff23fSmrg save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) | 785209ff23fSmrg (0x100 << RADEON_Y_GAIN_SHIFT); 786209ff23fSmrg 787209ff23fSmrg save->tv_master_cntl = (RADEON_VIN_ASYNC_RST 788209ff23fSmrg | RADEON_CRT_FIFO_CE_EN 789209ff23fSmrg | RADEON_TV_FIFO_CE_EN 790209ff23fSmrg | RADEON_TV_ON); 791209ff23fSmrg 792209ff23fSmrg if (!IS_R300_VARIANT) 793209ff23fSmrg save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb; 794209ff23fSmrg 795b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 796b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) 797209ff23fSmrg save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX; 798209ff23fSmrg 799209ff23fSmrg save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT 800209ff23fSmrg | RADEON_SYNC_TIP_LEVEL 801209ff23fSmrg | RADEON_YFLT_EN 802209ff23fSmrg | RADEON_UVFLT_EN 803209ff23fSmrg | (6 << RADEON_CY_FILT_BLEND_SHIFT); 804209ff23fSmrg 805b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 806b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) { 807209ff23fSmrg save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) 808209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 809209ff23fSmrg save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) | 810209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 811b7e1c893Smrg } else if (tvout->tvStd == TV_STD_SCART_PAL) { 812209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN; 813209ff23fSmrg save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) | 814209ff23fSmrg ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 815209ff23fSmrg } else { 816209ff23fSmrg save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN 817209ff23fSmrg | (0x3b << RADEON_SET_UP_LEVEL_SHIFT) 818209ff23fSmrg | (0x3b << RADEON_BLANK_LEVEL_SHIFT); 819209ff23fSmrg save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) | 820209ff23fSmrg ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT); 821209ff23fSmrg } 822209ff23fSmrg 823209ff23fSmrg save->pll_test_cntl = 0; 824209ff23fSmrg 825209ff23fSmrg save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN 826209ff23fSmrg | RADEON_C_GRN_EN 827209ff23fSmrg | RADEON_CMP_BLU_EN 828209ff23fSmrg | RADEON_DAC_DITHER_EN); 829209ff23fSmrg 830209ff23fSmrg save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN 831209ff23fSmrg | RADEON_TVOUT_SCALE_EN 832209ff23fSmrg | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT) 833b7e1c893Smrg | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT) 834b7e1c893Smrg | RADEON_RGB_ATTEN_SEL(0x3) 835b7e1c893Smrg | RADEON_RGB_ATTEN_VAL(0xc)); 836209ff23fSmrg 837209ff23fSmrg if (IsPrimary) { 838209ff23fSmrg if (radeon_output->Flags & RADEON_USE_RMX) 839209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; 840209ff23fSmrg else 841209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; 842209ff23fSmrg } else { 843209ff23fSmrg save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; 844209ff23fSmrg } 845209ff23fSmrg 846209ff23fSmrg save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE; 847209ff23fSmrg 848209ff23fSmrg save->tv_sync_size = constPtr->horResolution + 8; 849209ff23fSmrg 850b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 851b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 852b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 853b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 854209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; 855209ff23fSmrg else 856209ff23fSmrg vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME; 857209ff23fSmrg 858209ff23fSmrg save->tv_vscaler_cntl1 = RADEON_Y_W_EN; 859209ff23fSmrg save->tv_vscaler_cntl1 = 860209ff23fSmrg (save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000); 861b7e1c893Smrg 862b7e1c893Smrg if (pll->reference_freq == 2700) 863b7e1c893Smrg save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; 864b7e1c893Smrg 865209ff23fSmrg if (constPtr->horResolution == 1024) 866209ff23fSmrg save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); 867209ff23fSmrg else 868209ff23fSmrg save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); 869209ff23fSmrg 870b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 871b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 872b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 873b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 874209ff23fSmrg flicker_removal = 875209ff23fSmrg (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5; 876209ff23fSmrg else 877209ff23fSmrg flicker_removal = 878209ff23fSmrg (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5; 879209ff23fSmrg 880209ff23fSmrg if (flicker_removal < 3) 881209ff23fSmrg flicker_removal = 3; 882209ff23fSmrg for (i = 0; i < 6; ++i) { 883209ff23fSmrg if (flicker_removal == SLOPE_limit[i]) 884209ff23fSmrg break; 885209ff23fSmrg } 886209ff23fSmrg save->tv_y_saw_tooth_cntl = 887209ff23fSmrg (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8 888209ff23fSmrg | ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16); 889209ff23fSmrg save->tv_y_fall_cntl = 890209ff23fSmrg (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | 891209ff23fSmrg RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / 892209ff23fSmrg 1024; 893209ff23fSmrg save->tv_y_rise_cntl = 894209ff23fSmrg RADEON_Y_RISE_PING_PONG 895209ff23fSmrg | (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; 896209ff23fSmrg 897209ff23fSmrg save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0) 898209ff23fSmrg | (0x10 << 24) 899209ff23fSmrg | RADEON_DITHER_MODE 900209ff23fSmrg | RADEON_Y_OUTPUT_DITHER_EN 901209ff23fSmrg | RADEON_UV_OUTPUT_DITHER_EN 902209ff23fSmrg | RADEON_UV_TO_BUF_DITHER_EN); 903209ff23fSmrg 904209ff23fSmrg tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; 905209ff23fSmrg tmp = ((16384 * 256 * 10) / tmp + 5) / 10; 906209ff23fSmrg tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; 907209ff23fSmrg save->tv_timing_cntl = tmp; 908209ff23fSmrg 909b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 910b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 911b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 912b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 913b7e1c893Smrg save->tv_dac_cntl = tvdac->ntsc_tvdac_adj; 914209ff23fSmrg else 915b7e1c893Smrg save->tv_dac_cntl = tvdac->pal_tvdac_adj; 916209ff23fSmrg 917209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD); 918209ff23fSmrg 919b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 920b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) 921209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; 922209ff23fSmrg else 923209ff23fSmrg save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; 924209ff23fSmrg 925209ff23fSmrg#if 0 926209ff23fSmrg /* needs fixes for r4xx */ 927209ff23fSmrg save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD 928209ff23fSmrg | RADEON_TV_DAC_BDACPD); 929209ff23fSmrg 930209ff23fSmrg if (radeon_output->MonType == MT_CTV) { 931209ff23fSmrg save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD; 932209ff23fSmrg } 933209ff23fSmrg 934209ff23fSmrg if (radeon_output->MonType == MT_STV) { 935209ff23fSmrg save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | 936209ff23fSmrg RADEON_TV_DAC_GDACPD); 937209ff23fSmrg } 938209ff23fSmrg#endif 939209ff23fSmrg 940b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 941b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J) { 942b7e1c893Smrg if (pll->reference_freq == 2700) { 943b7e1c893Smrg m = NTSC_TV_PLL_M_27; 944b7e1c893Smrg n = NTSC_TV_PLL_N_27; 945b7e1c893Smrg p = NTSC_TV_PLL_P_27; 946b7e1c893Smrg } else { 947b7e1c893Smrg m = NTSC_TV_PLL_M_14; 948b7e1c893Smrg n = NTSC_TV_PLL_N_14; 949b7e1c893Smrg p = NTSC_TV_PLL_P_14; 950b7e1c893Smrg } 951b7e1c893Smrg } else { 952b7e1c893Smrg if (pll->reference_freq == 2700) { 953b7e1c893Smrg m = PAL_TV_PLL_M_27; 954b7e1c893Smrg n = PAL_TV_PLL_N_27; 955b7e1c893Smrg p = PAL_TV_PLL_P_27; 956b7e1c893Smrg } else { 957ad43ddacSmrg m = PAL_TV_PLL_M_14; 958ad43ddacSmrg n = PAL_TV_PLL_N_14; 959ad43ddacSmrg p = PAL_TV_PLL_P_14; 960b7e1c893Smrg } 961b7e1c893Smrg } 962b7e1c893Smrg save->tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) | 963b7e1c893Smrg (((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | 964b7e1c893Smrg ((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | 965b7e1c893Smrg (((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | 966b7e1c893Smrg ((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); 967209ff23fSmrg 968209ff23fSmrg save->tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) | 969209ff23fSmrg ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) | 970209ff23fSmrg ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) | 971209ff23fSmrg RADEON_TVCLK_SRC_SEL_TVPLL | 972209ff23fSmrg RADEON_TVPLL_TEST_DIS); 973209ff23fSmrg 974209ff23fSmrg save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN; 975209ff23fSmrg 976209ff23fSmrg save->tv_uv_adr = 0xc8; 977209ff23fSmrg 978209ff23fSmrg save->tv_vdisp = constPtr->verResolution - 1; 979209ff23fSmrg 980b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 981b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 982b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 983b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) 984209ff23fSmrg save->tv_ftotal = NTSC_TV_VFTOTAL; 985209ff23fSmrg else 986209ff23fSmrg save->tv_ftotal = PAL_TV_VFTOTAL; 987209ff23fSmrg 988209ff23fSmrg save->tv_vtotal = constPtr->verTotal - 1; 989209ff23fSmrg 990b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 991b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 992b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 993209ff23fSmrg hor_timing = hor_timing_NTSC; 994209ff23fSmrg } else { 995209ff23fSmrg hor_timing = hor_timing_PAL; 996209ff23fSmrg } 997209ff23fSmrg 998b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 999b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1000b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M || 1001b7e1c893Smrg tvout->tvStd == TV_STD_PAL_60) { 1002209ff23fSmrg vert_timing = vert_timing_NTSC; 1003209ff23fSmrg } else { 1004209ff23fSmrg vert_timing = vert_timing_PAL; 1005209ff23fSmrg } 1006209ff23fSmrg 1007209ff23fSmrg for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { 1008209ff23fSmrg if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0) 1009209ff23fSmrg break; 1010209ff23fSmrg } 1011209ff23fSmrg 1012209ff23fSmrg for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { 1013209ff23fSmrg if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0) 1014209ff23fSmrg break; 1015209ff23fSmrg } 1016209ff23fSmrg 1017209ff23fSmrg /* 1018209ff23fSmrg * This must be called AFTER loading timing tables as they are modified by this function 1019209ff23fSmrg */ 1020209ff23fSmrg RADEONInitTVRestarts(output, save, mode); 1021209ff23fSmrg 1022209ff23fSmrg save->dac_cntl &= ~RADEON_DAC_TVO_EN; 1023209ff23fSmrg 1024209ff23fSmrg if (IS_R300_VARIANT) 1025209ff23fSmrg save->gpiopad_a = info->SavedReg->gpiopad_a & ~1; 1026209ff23fSmrg 1027209ff23fSmrg if (IsPrimary) { 1028209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; 1029209ff23fSmrg save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC 1030209ff23fSmrg | RADEON_DISP_TV_SOURCE_CRTC); 1031209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 1032209ff23fSmrg save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; 1033209ff23fSmrg } else { 1034209ff23fSmrg save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; 1035209ff23fSmrg } 1036209ff23fSmrg } else { 1037209ff23fSmrg save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK; 1038209ff23fSmrg save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; 1039209ff23fSmrg 1040209ff23fSmrg if (info->ChipFamily >= CHIP_FAMILY_R200) { 1041209ff23fSmrg save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; 1042209ff23fSmrg } else { 1043209ff23fSmrg save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; 1044209ff23fSmrg } 1045209ff23fSmrg } 1046209ff23fSmrg} 1047209ff23fSmrg 1048209ff23fSmrg 1049209ff23fSmrg/* Set hw registers for a new h/v position & h size */ 1050209ff23fSmrgvoid RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode) 1051209ff23fSmrg{ 1052209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 1053209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 1054209ff23fSmrg unsigned char *RADEONMMIO = info->MMIO; 1055209ff23fSmrg Bool reloadTable; 1056209ff23fSmrg RADEONSavePtr restore = info->ModeReg; 1057209ff23fSmrg 1058209ff23fSmrg reloadTable = RADEONInitTVRestarts(output, restore, mode); 1059209ff23fSmrg 1060209ff23fSmrg RADEONRestoreTVRestarts(pScrn, restore); 1061209ff23fSmrg 1062209ff23fSmrg OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); 1063209ff23fSmrg 1064209ff23fSmrg if (reloadTable) { 1065209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl 1066209ff23fSmrg | RADEON_TV_ASYNC_RST 1067209ff23fSmrg | RADEON_CRT_ASYNC_RST 1068209ff23fSmrg | RADEON_RESTART_PHASE_FIX); 1069209ff23fSmrg 1070209ff23fSmrg RADEONRestoreTVTimingTables(pScrn, restore); 1071209ff23fSmrg 1072209ff23fSmrg OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); 1073209ff23fSmrg } 1074209ff23fSmrg} 1075209ff23fSmrg 1076209ff23fSmrgvoid RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1077209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1078209ff23fSmrg{ 1079209ff23fSmrg const TVModeConstants *constPtr; 1080209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1081b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1082b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1083b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1084209ff23fSmrg 1085209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1086b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1087b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1088b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1089b7e1c893Smrg if (pll->reference_freq == 2700) 1090b7e1c893Smrg constPtr = &availableTVModes[0]; 1091b7e1c893Smrg else 1092b7e1c893Smrg constPtr = &availableTVModes[2]; 1093b7e1c893Smrg } else { 1094b7e1c893Smrg if (pll->reference_freq == 2700) 1095b7e1c893Smrg constPtr = &availableTVModes[1]; 1096b7e1c893Smrg else 1097ad43ddacSmrg constPtr = &availableTVModes[3]; 1098b7e1c893Smrg } 1099209ff23fSmrg 1100209ff23fSmrg save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1101209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1102209ff23fSmrg 1103209ff23fSmrg save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid 1104209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1105209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1106209ff23fSmrg (constPtr->horSyncStart & 7); 1107209ff23fSmrg 1108209ff23fSmrg save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1109209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1110209ff23fSmrg 1111209ff23fSmrg save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1112209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1113209ff23fSmrg 1114209ff23fSmrg} 1115209ff23fSmrg 1116209ff23fSmrgvoid RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1117209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1118209ff23fSmrg{ 1119209ff23fSmrg unsigned postDiv; 1120209ff23fSmrg const TVModeConstants *constPtr; 1121209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1122b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1123b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1124b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1125209ff23fSmrg 1126209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1127b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1128b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1129b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1130b7e1c893Smrg if (pll->reference_freq == 2700) 1131b7e1c893Smrg constPtr = &availableTVModes[0]; 1132b7e1c893Smrg else 1133b7e1c893Smrg constPtr = &availableTVModes[2]; 1134b7e1c893Smrg } else { 1135b7e1c893Smrg if (pll->reference_freq == 2700) 1136b7e1c893Smrg constPtr = &availableTVModes[1]; 1137b7e1c893Smrg else 1138ad43ddacSmrg constPtr = &availableTVModes[3]; 1139b7e1c893Smrg } 1140209ff23fSmrg 1141209ff23fSmrg save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN; 1142209ff23fSmrg 1143209ff23fSmrg save->ppll_ref_div = constPtr->crtcPLL_M; 1144209ff23fSmrg 1145209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1146209ff23fSmrg case 1: 1147209ff23fSmrg postDiv = 0; 1148209ff23fSmrg break; 1149209ff23fSmrg case 2: 1150209ff23fSmrg postDiv = 1; 1151209ff23fSmrg break; 1152209ff23fSmrg case 3: 1153209ff23fSmrg postDiv = 4; 1154209ff23fSmrg break; 1155209ff23fSmrg case 4: 1156209ff23fSmrg postDiv = 2; 1157209ff23fSmrg break; 1158209ff23fSmrg case 6: 1159209ff23fSmrg postDiv = 6; 1160209ff23fSmrg break; 1161209ff23fSmrg case 8: 1162209ff23fSmrg postDiv = 3; 1163209ff23fSmrg break; 1164209ff23fSmrg case 12: 1165209ff23fSmrg postDiv = 7; 1166209ff23fSmrg break; 1167209ff23fSmrg case 16: 1168209ff23fSmrg default: 1169209ff23fSmrg postDiv = 5; 1170209ff23fSmrg break; 1171209ff23fSmrg } 1172209ff23fSmrg 1173209ff23fSmrg save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1174209ff23fSmrg 1175209ff23fSmrg save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); 1176209ff23fSmrg save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; 1177209ff23fSmrg 1178209ff23fSmrg} 1179209ff23fSmrg 1180209ff23fSmrgvoid RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1181209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1182209ff23fSmrg{ 1183209ff23fSmrg const TVModeConstants *constPtr; 1184209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1185b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1186b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1187b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1188209ff23fSmrg 1189209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1190b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1191b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1192b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1193b7e1c893Smrg if (pll->reference_freq == 2700) 1194b7e1c893Smrg constPtr = &availableTVModes[0]; 1195b7e1c893Smrg else 1196b7e1c893Smrg constPtr = &availableTVModes[2]; 1197b7e1c893Smrg } else { 1198b7e1c893Smrg if (pll->reference_freq == 2700) 1199b7e1c893Smrg constPtr = &availableTVModes[1]; 1200b7e1c893Smrg else 1201ad43ddacSmrg constPtr = &availableTVModes[3]; 1202b7e1c893Smrg } 1203209ff23fSmrg 1204209ff23fSmrg save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | 1205209ff23fSmrg (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); 1206209ff23fSmrg 1207209ff23fSmrg save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid 1208209ff23fSmrg & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | 1209209ff23fSmrg (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | 1210209ff23fSmrg (constPtr->horSyncStart & 7); 1211209ff23fSmrg 1212209ff23fSmrg save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | 1213209ff23fSmrg ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); 1214209ff23fSmrg 1215c503f109Smrg save->crtc2_v_sync_strt_wid = (save->crtc2_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | 1216209ff23fSmrg ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); 1217209ff23fSmrg 1218209ff23fSmrg} 1219209ff23fSmrg 1220209ff23fSmrgvoid RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, 1221209ff23fSmrg DisplayModePtr mode, xf86OutputPtr output) 1222209ff23fSmrg{ 1223209ff23fSmrg unsigned postDiv; 1224209ff23fSmrg const TVModeConstants *constPtr; 1225209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 1226b7e1c893Smrg radeon_tvout_ptr tvout = &radeon_output->tvout; 1227b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1228b7e1c893Smrg RADEONPLLPtr pll = &info->pll; 1229209ff23fSmrg 1230209ff23fSmrg /* FIXME: need to revisit this when we add more modes */ 1231b7e1c893Smrg if (tvout->tvStd == TV_STD_NTSC || 1232b7e1c893Smrg tvout->tvStd == TV_STD_NTSC_J || 1233b7e1c893Smrg tvout->tvStd == TV_STD_PAL_M) { 1234b7e1c893Smrg if (pll->reference_freq == 2700) 1235b7e1c893Smrg constPtr = &availableTVModes[0]; 1236b7e1c893Smrg else 1237b7e1c893Smrg constPtr = &availableTVModes[2]; 1238b7e1c893Smrg } else { 1239b7e1c893Smrg if (pll->reference_freq == 2700) 1240b7e1c893Smrg constPtr = &availableTVModes[1]; 1241b7e1c893Smrg else 1242ad43ddacSmrg constPtr = &availableTVModes[3]; 1243b7e1c893Smrg } 1244209ff23fSmrg 1245209ff23fSmrg save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */ 1246209ff23fSmrg 1247209ff23fSmrg save->p2pll_ref_div = constPtr->crtcPLL_M; 1248209ff23fSmrg 1249209ff23fSmrg switch (constPtr->crtcPLL_postDiv) { 1250209ff23fSmrg case 1: 1251209ff23fSmrg postDiv = 0; 1252209ff23fSmrg break; 1253209ff23fSmrg case 2: 1254209ff23fSmrg postDiv = 1; 1255209ff23fSmrg break; 1256209ff23fSmrg case 3: 1257209ff23fSmrg postDiv = 4; 1258209ff23fSmrg break; 1259209ff23fSmrg case 4: 1260209ff23fSmrg postDiv = 2; 1261209ff23fSmrg break; 1262209ff23fSmrg case 6: 1263209ff23fSmrg postDiv = 6; 1264209ff23fSmrg break; 1265209ff23fSmrg case 8: 1266209ff23fSmrg postDiv = 3; 1267209ff23fSmrg break; 1268209ff23fSmrg case 12: 1269209ff23fSmrg postDiv = 7; 1270209ff23fSmrg break; 1271209ff23fSmrg case 16: 1272209ff23fSmrg default: 1273209ff23fSmrg postDiv = 5; 1274209ff23fSmrg break; 1275209ff23fSmrg } 1276209ff23fSmrg 1277209ff23fSmrg save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); 1278209ff23fSmrg 1279209ff23fSmrg save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; 1280209ff23fSmrg save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 1281209ff23fSmrg | RADEON_PIXCLK_TV_SRC_SEL); 1282209ff23fSmrg 1283209ff23fSmrg} 1284