? Makefile ? r128.4x.html ? r128._man ? radeon.4x.html ? radeon._man ? radeon_tvout.c ? radeon_tvout.diff ? radeon_tvout.h ? tvout.diff Index: Imakefile =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/Imakefile,v retrieving revision 1.14 diff -u -r1.14 Imakefile --- Imakefile 26 Mar 2005 00:53:01 -0000 1.14 +++ Imakefile 9 Apr 2005 14:45:04 -0000 @@ -190,7 +190,7 @@ SRCS3 = r128_accel.c r128_cursor.c r128_dga.c r128_driver.c \ r128_video.c $(DRISRCS3) $(MODSRCS3) SRCS4 = radeon_accel.c radeon_mergedfb.c radeon_cursor.c radeon_dga.c radeon_driver.c \ - radeon_video.c radeon_bios.c radeon_mm_i2c.c radeon_vip.c \ + radeon_video.c radeon_bios.c radeon_mm_i2c.c radeon_vip.c radeon_tvout.c \ $(DRISRCS4) $(MODSRCS4) SRCS_THEATRE = theatre.c $(MODSRC_THEATRE) @@ -206,7 +206,7 @@ OBJS3 = r128_accel.o r128_cursor.o r128_dga.o r128_driver.o \ r128_video.o $(DRIOBJS3) $(MODOBJS3) OBJS4 = radeon_accel.o radeon_mergedfb.o radeon_cursor.o radeon_dga.o radeon_driver.o \ - radeon_video.o radeon_bios.o radeon_mm_i2c.o radeon_vip.o \ + radeon_video.o radeon_bios.o radeon_mm_i2c.o radeon_vip.o radeon_tvout.o \ $(DRIOBJS4) $(MODOBJS4) OBJS_THEATRE = theatre.o $(MODOBJ_THEATRE) @@ -405,6 +405,8 @@ InstallDriverSDKNonExecFile(radeon_chipset.h,$(DRIVERSDKDIR)/drivers/ati) InstallDriverSDKNonExecFile(radeon_common.h,$(DRIVERSDKDIR)/drivers/ati) InstallDriverSDKNonExecFile(radeon_accelfuncs.c,$(DRIVERSDKDIR)/drivers/ati) +InstallDriverSDKNonExecFile(radeon_tvout.c,$(DRIVERSDKDIR)/drivers/ati) +InstallDriverSDKNonExecFile(radeon_tvout.h,$(DRIVERSDKDIR)/drivers/ati) InstallDriverSDKObjectModule(ati,$(DRIVERSDKMODULEDIR),drivers) InstallDriverSDKObjectModule(atimisc,$(DRIVERSDKMODULEDIR),drivers) Index: radeon.h =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h,v retrieving revision 1.20 diff -u -r1.20 radeon.h --- radeon.h 29 Mar 2005 03:49:04 -0000 1.20 +++ radeon.h 9 Apr 2005 14:45:04 -0000 @@ -164,9 +164,9 @@ /* CRTC2 registers */ CARD32 crtc2_gen_cntl; - CARD32 dac2_cntl; CARD32 disp_output_cntl; + CARD32 disp_tv_out_cntl; CARD32 disp_hw_debug; CARD32 disp2_merge_cntl; CARD32 grph2_buffer_cntl; @@ -177,6 +177,7 @@ CARD32 crtc2_offset; CARD32 crtc2_offset_cntl; CARD32 crtc2_pitch; + /* Flat panel registers */ CARD32 fp_crtc_h_total_disp; CARD32 fp_crtc_v_total_disp; @@ -194,6 +195,40 @@ CARD32 tmds_pll_cntl; CARD32 tmds_transmitter_cntl; + /* TV out registers */ + CARD32 tv_master_cntl; + CARD32 tv_tv_pll_cntl; + CARD32 tv_crt_pll_cntl; + CARD32 tv_htotal; + CARD32 tv_hsize; + CARD32 tv_hdisp; + CARD32 tv_hstart; + CARD32 tv_vtotal; + CARD32 tv_vdisp; + CARD32 tv_timing_cntl; + CARD32 tv_vscaler_cntl; + CARD32 tv_vscaler_cntl2; + CARD32 tv_sync_size; + CARD32 tv_vrestart; + CARD32 tv_hrestart; + CARD32 tv_frestart; + CARD32 tv_ftotal; + CARD32 tv_clock_sel_cntl; + CARD32 tv_clkout_cntl; + CARD32 tv_data_delay_a; + CARD32 tv_data_delay_b; + CARD32 tv_dac_cntl; + CARD32 tv_pll_cntl0; + CARD32 tv_modulator_cntl1; + CARD32 tv_modulator_cntl2; + CARD32 tv_frame_lock_cntl; + CARD32 tv_pre_dac_mux_cntl; + CARD32 tv_rgb_cntl; + CARD32 tv_saw_tooth_cntl; + CARD32 tv_rise_cntl; + CARD32 tv_fall_cntl; + CARD32 tv_uv_adr; + /* Computed values for PLL */ CARD32 dot_clock_freq; CARD32 pll_output_freq; @@ -204,6 +239,7 @@ unsigned ppll_ref_div; unsigned ppll_div_3; CARD32 htotal_cntl; + CARD32 vclk_cntl; /* Computed values for PLL2 */ CARD32 dot_clock_freq_2; @@ -215,14 +251,13 @@ CARD32 p2pll_ref_div; CARD32 p2pll_div_0; CARD32 htotal_cntl2; + CARD32 pixclks_cntl; /* Pallet */ Bool palette_valid; CARD32 palette[256]; CARD32 palette2[256]; - CARD32 tv_dac_cntl; - } RADEONSaveRec, *RADEONSavePtr; typedef struct { @@ -643,6 +678,19 @@ Bool VGAAccess; + /* tv out support */ + int HOverPlusTV; + int HSyncWidthTV; + int HBlankTV; + int VOverPlusTV; + int VSyncWidthTV; + int VBlankTV; + int videoChip; + int vipChannel; + int tvoutType; + int tvFormat; + int tvModeIndex; + } RADEONInfoRec, *RADEONInfoPtr; #define RADEONWaitForFifo(pScrn, entries) \ Index: radeon_driver.c =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v retrieving revision 1.49 diff -u -r1.49 radeon_driver.c --- radeon_driver.c 4 Apr 2005 23:07:08 -0000 1.49 +++ radeon_driver.c 9 Apr 2005 14:45:10 -0000 @@ -69,6 +69,8 @@ #include "radeon_probe.h" #include "radeon_version.h" #include "radeon_mergedfb.h" +#include "radeon_tvout.h" +#include "theatre_reg.h" #ifdef XF86DRI #define _XF86DRI_SERVER_ @@ -179,7 +181,8 @@ OPTION_BIOS_HOTKEYS, OPTION_VGA_ACCESS, OPTION_REVERSE_DDC, - OPTION_LVDS_PROBE_PLL + OPTION_LVDS_PROBE_PLL, + OPTION_TV_FORMAT } RADEONOpts; static const OptionInfoRec RADEONOptions[] = { @@ -237,6 +240,7 @@ { OPTION_VGA_ACCESS, "VGAAccess", OPTV_BOOLEAN, {0}, TRUE }, { OPTION_REVERSE_DDC, "ReverseDDC", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_LVDS_PROBE_PLL, "LVDSProbePLL", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_TV_FORMAT, "TVFormat", OPTV_INTEGER, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -474,6 +478,50 @@ {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R420*/ }; +/* TV out */ + +static unsigned long std_tv_clk[6] = { + 42954540, 53203425, 42907338, 42984675, 53203425, 53203425, +}; + +static TVTimingParam std_tv_timing[6] = { + {2730, 200, 28, 200, 110, 2170, 525, 440, 525, 2}, /* ntsc */ + {3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2}, /* pal */ + {2727, 200, 28, 200, 110, 2170, 525, 440, 525, 2}, /* palm */ + {2751, 202, 28, 202, 110, 2190, 625, 510, 625, 2}, /* palnc */ + {3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2}, /* scart pal ??? */ + {3405, 250, 28, 320, 80, 2627, 525, 440, 525, 2}, /* pal 60 */ +}; + +static TVOutModes tv_modes[] = { + {320, 350, 406, 525, 408, 625, 0, 0, 0, 0, 0, 0}, + {320, 400, 406, 525, 432, 625, 0, 0, 0, 0, 0, 0}, + {320, 480, 400, 600, 408, 625, 0, 0, 0, 0, 0, 0}, + {360, 400, 451, 525, 459, 625, 0, 0, 0, 0, 0, 0}, + {400, 600, 500, 716, 560, 762, 0, 0, 0, 0, 0, 0}, + {512, 384, 672, 525, 660, 625, 671, 472, 661, 487, 0, 0}, + {512, 768, 672, 1000, 660, 625, 0, 0, 0, 0}, + {640, 350, 800, 525, 808, 625, 792, 498, 688, 388, 784, 390}, + {640, 480, 800, 600, 816, 625, 800, 525, 656, 490, 752, 492}, + {720, 350, 900, 525, 909, 625, 0, 0, 0, 0, 0, 0}, + {720, 400, 900, 525, 909, 625, 896, 417, 736, 401, 808, 404}, + {720, 480, 896, 590, 909, 625, 896, 497, 736, 481, 808, 484}, + {720, 576, 896, 716, 912, 730, 0, 0, 0, 0, 0, 0}, + {768, 576, 950, 740, 950, 740, 0, 0, 0, 0, 0, 0}, + {800, 600, 995, 740, 1120, 740, 1056, 628, 840, 601, 968, 605}, + {848, 480, 1088, 590, 1104, 625, 1056, 497, 864, 481, 952, 484}, + {1024, 480, 1280, 960, 1286, 961, 0, 0, 0, 0, 0, 0}, + {1024, 768, 1280, 959, 1286, 961, 1344, 806, 1048, 771, 1184, 777}, + {0, 0, 0, 0, 0, 0}, +}; + +static long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; +static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; +static long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; +static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; + +/* TV out */ + extern int getRADEONEntityIndex(void); struct RADEONInt10Save { @@ -837,6 +885,10 @@ if (!info->IsSecondary) { switch(info->DisplayType) { + case MT_STV: + case MT_CTV: + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, 0, ~RADEON_DAC_TVO_EN); case MT_LCD: case MT_CRT: case MT_DFP: @@ -849,14 +901,21 @@ default: break; } - if (info->MergedFB) + if (info->MergedFB) { OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_DIS, ~(RADEON_CRTC2_DISP_DIS)); + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, 0, ~RADEON_DAC_TVO_EN); + } } else { OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_DIS, ~(RADEON_CRTC2_DISP_DIS)); + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, 0, ~RADEON_DAC_TVO_EN); } } @@ -868,6 +927,10 @@ if (!info->IsSecondary) { switch (info->DisplayType) { + case MT_STV: + case MT_CTV: + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, RADEON_DAC_TVO_EN, ~RADEON_DAC_TVO_EN); case MT_LCD: case MT_CRT: case MT_DFP: @@ -880,12 +943,23 @@ default: break; } - if (info->MergedFB) + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, RADEON_DAC_TVO_EN, ~RADEON_DAC_TVO_EN); + }/* else {*/ OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~(RADEON_CRTC2_DISP_DIS)); + /*}*/ + } } else { switch (info->DisplayType) { + case MT_CTV: + case MT_STV: + if (info->tvoutType != TVOUT_INTERNAL) + OUTREGP (RADEON_DAC_CNTL, RADEON_DAC_TVO_EN, ~RADEON_DAC_TVO_EN); + /*break;*/ case MT_LCD: case MT_DFP: case MT_CRT: @@ -1720,7 +1794,7 @@ { "NONE", "Internal", - "External" + "External" }; const char *DDCTypeName[5] = @@ -1729,7 +1803,7 @@ "MONID", "DVI_DDC", "VGA_DDC", - "CRT2_DDC" + "CRT2_DDC" }; const char *DACTypeName[3] = @@ -1765,7 +1839,7 @@ "Unsupported" }; - max_mt = 5; + max_mt = 7; if(info->IsSecondary) { info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType2; @@ -1957,6 +2031,23 @@ } +#if 0 + if ((pRADEONEnt->PortInfo[1].MonType == MT_CTV) || + (pRADEONEnt->PortInfo[1].MonType == MT_STV) || + (pRADEONEnt->PortInfo[0].MonType == MT_CTV) || + (pRADEONEnt->PortInfo[0].MonType == MT_STV)) { + pRADEONEnt->PortInfo[1].DACType = DAC_PRIMARY; + pRADEONEnt->PortInfo[1].TMDSType = TMDS_UNKNOWN; + pRADEONEnt->PortInfo[1].DDCType = DDC_VGA; + pRADEONEnt->PortInfo[1].ConnectorType = CONNECTOR_CRT; + pRADEONEnt->PortInfo[0].DACType = DAC_TVDAC; + pRADEONEnt->PortInfo[0].TMDSType = TMDS_UNKNOWN; + pRADEONEnt->PortInfo[0].DDCType = DDC_NONE_DETECTED; + pRADEONEnt->PortInfo[0].ConnectorType = pRADEONEnt->PortInfo[0].MonType+1; + pRADEONEnt->PortInfo[0].MonInfo = NULL; + } +#endif + if(((!info->HasCRTC2) || info->IsDellServer)) { if (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN) { if((pRADEONEnt->PortInfo[0].MonType = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->PortInfo[0]))); @@ -2349,6 +2440,8 @@ case PCI_CHIP_RADEON_LZ: info->IsMobility = TRUE; info->ChipFamily = CHIP_FAMILY_RV100; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV100_QY: @@ -2356,6 +2449,8 @@ case PCI_CHIP_RN50_515E: /* RN50 is based on the RV100 but 3D isn't guaranteed to work. YMMV. */ case PCI_CHIP_RN50_5969: info->ChipFamily = CHIP_FAMILY_RV100; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; /* DELL triple-head configuration. */ if ((info->PciInfo->subsysVendor == PCI_VENDOR_DELL) && @@ -2380,6 +2475,8 @@ case PCI_CHIP_RS100_4136: info->ChipFamily = CHIP_FAMILY_RS100; info->IsIGP = TRUE; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RS200_4337: @@ -2387,6 +2484,8 @@ case PCI_CHIP_RS200_4137: info->ChipFamily = CHIP_FAMILY_RS200; info->IsIGP = TRUE; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RS250_4437: @@ -2394,6 +2493,8 @@ case PCI_CHIP_RS250_4237: info->ChipFamily = CHIP_FAMILY_RS200; info->IsIGP = TRUE; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R200_BB: @@ -2402,14 +2503,23 @@ case PCI_CHIP_R200_QL: case PCI_CHIP_R200_QM: info->ChipFamily = CHIP_FAMILY_R200; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_RT1; break; case PCI_CHIP_RADEON_LW: case PCI_CHIP_RADEON_LX: info->IsMobility = TRUE; + info->ChipFamily = CHIP_FAMILY_RV200; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_INTERNAL; + break; + case PCI_CHIP_RV200_QW: /* RV200 desktop */ case PCI_CHIP_RV200_QX: info->ChipFamily = CHIP_FAMILY_RV200; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV250_Ld: @@ -2419,6 +2529,8 @@ case PCI_CHIP_RV250_If: case PCI_CHIP_RV250_Ig: info->ChipFamily = CHIP_FAMILY_RV250; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RS300_5835: @@ -2429,6 +2541,8 @@ info->ChipFamily = CHIP_FAMILY_RS300; info->IsIGP = TRUE; info->HasSingleDAC = TRUE; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV280_5C61: @@ -2440,6 +2554,8 @@ case PCI_CHIP_RV280_5964: case PCI_CHIP_RV280_5965: info->ChipFamily = CHIP_FAMILY_RV280; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R300_AD: @@ -2451,6 +2567,8 @@ case PCI_CHIP_R300_NF: case PCI_CHIP_R300_NG: info->ChipFamily = CHIP_FAMILY_R300; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV350_NP: @@ -2468,6 +2586,8 @@ case PCI_CHIP_RV350_AV: case PCI_CHIP_RV350_4155: info->ChipFamily = CHIP_FAMILY_RV350; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R350_AH: @@ -2479,6 +2599,8 @@ case PCI_CHIP_R350_NK: case PCI_CHIP_R360_NJ: info->ChipFamily = CHIP_FAMILY_R350; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV380_3150: @@ -2487,6 +2609,8 @@ case PCI_CHIP_RV380_3E50: case PCI_CHIP_RV380_3E54: info->ChipFamily = CHIP_FAMILY_RV380; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV370_5460: @@ -2496,6 +2620,8 @@ case PCI_CHIP_RV370_5B64: case PCI_CHIP_RV370_5B65: info->ChipFamily = CHIP_FAMILY_RV380; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RS400_5A42: @@ -2510,6 +2636,8 @@ info->ChipFamily = CHIP_FAMILY_RS300; /*CHIP_FAMILY_RS400*/ info->IsIGP = TRUE; info->HasSingleDAC = TRUE; /*?*/ + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_RV410_564A: @@ -2537,6 +2665,8 @@ case PCI_CHIP_R420_JP: case PCI_CHIP_R420_4A4F: info->ChipFamily = CHIP_FAMILY_R420; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R423_UH: @@ -2549,6 +2679,8 @@ case PCI_CHIP_R423_5D57: case PCI_CHIP_R423_5550: info->ChipFamily = CHIP_FAMILY_R420; + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R430_5D49: @@ -2560,6 +2692,8 @@ case PCI_CHIP_R430_554E: case PCI_CHIP_R430_554C: info->ChipFamily = CHIP_FAMILY_R420; /*CHIP_FAMILY_R430*/ + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; case PCI_CHIP_R480_5D4C: @@ -2573,12 +2707,16 @@ case PCI_CHIP_R481_4B49: case PCI_CHIP_R481_4B4C: info->ChipFamily = CHIP_FAMILY_R420; /*CHIP_FAMILY_R480*/ + info->videoChip = VCHIP_RT2; + info->tvoutType = TVOUT_INTERNAL; break; default: /* Original Radeon/7200 */ info->ChipFamily = CHIP_FAMILY_RADEON; info->HasCRTC2 = FALSE; + info->videoChip = VCHIP_RT1; + info->tvoutType = TVOUT_RT1; } /* Framebuffer */ @@ -2868,6 +3006,32 @@ } } +static Bool +RADEONGetTVInfo (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "TV Chip type: %d\n", info->videoChip); + + if (info->tvoutType != TVOUT_INTERNAL) + if (!RADEONDetectTheatre (pScrn)) + return FALSE; + + /*R300DumpTVInfo (pScrn); */ + + info->tvFormat = NTSC; /* Default to NTSC */ + if (xf86GetOptValInteger (info->Options, + OPTION_TV_FORMAT, &(info->tvFormat))) { + if (info->tvFormat > PAL) + info->tvFormat = NTSC; + } + + /*TODO: Get tvFormat from BIOS or Config file */ + + + return TRUE; +} + /* BIOS may not have right panel size, we search through all supported * DDC modes looking for the maximum panel size. @@ -3501,6 +3665,223 @@ return count; } +/* + * TV support ********************************** + */ +static int +RADEONValidateTVModes (ScrnInfoPtr pScrn) +{ + int i, count = 0, width, height; + RADEONInfoPtr info = RADEONPTR (pScrn); + DisplayModePtr last = NULL, new = NULL, first = NULL; + + /* Free any allocated modes during configuration. We don't need them */ + while (pScrn->modes) { + xf86DeleteMode (&pScrn->modes, pScrn->modes); + } + while (pScrn->modePool) { + xf86DeleteMode (&pScrn->modePool, pScrn->modePool); + } + + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + + /* If no mode specified in config, we use native resolution */ + if (!pScrn->display->modes[0]) { + pScrn->display->modes[0] = xnfalloc (16); + sprintf (pScrn->display->modes[0], "%dx%d", 640, 480); + } + + for (i = 0; pScrn->display->modes[i] != NULL; i++) { + if (sscanf (pScrn->display->modes[i], "%dx%d", &width, &height) == 2) { + int j = 0; + while (tv_modes[j].h_disp) { + if (width != tv_modes[j].h_disp || + height != tv_modes[j].v_disp) { + j++; + continue; + } else + break; + }; + + if (!tv_modes[j].h_disp) { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "Mode %s is not a valid TV mode.\n", + pScrn->display->modes[i]); + continue; + } + + new = xnfcalloc (1, sizeof (DisplayModeRec)); + new->prev = last; + new->name = xnfalloc (strlen (pScrn->display->modes[i]) + 1); + strcpy (new->name, pScrn->display->modes[i]); + new->HDisplay = new->CrtcHDisplay = width; + new->VDisplay = new->CrtcVDisplay = height; + switch (info->tvFormat) { + case NTSC: + new->HTotal = tv_modes[j].h_total_ntsc; + new->VTotal = tv_modes[j].v_total_ntsc; + break; + case PAL: + new->HTotal = tv_modes[j].h_total_pal; + new->VTotal = tv_modes[j].v_total_pal; + break; + default: + new->HTotal = tv_modes[j].h_total_ntsc; + new->VTotal = tv_modes[j].v_total_ntsc; + break; + } + new->CrtcHTotal = tv_modes[j].h_crtc_total; + new->CrtcVTotal = tv_modes[j].v_crtc_total; + new->CrtcHSyncStart = tv_modes[j].h_crtc_sync_start; + new->CrtcVSyncStart = tv_modes[j].v_crtc_sync_start; + new->CrtcHSyncEnd = tv_modes[j].h_crtc_sync_end; + new->CrtcVSyncEnd = tv_modes[j].v_crtc_sync_end; + + if (new->prev) + new->prev->next = new; + last = new; + if (!first) + first = new; + pScrn->display->virtualX = + pScrn->virtualX = MAX (pScrn->virtualX, width); + pScrn->display->virtualY = + pScrn->virtualY = MAX (pScrn->virtualY, height); + count++; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "TV mode: %s OK\n", + pScrn->display->modes[i]); + + } else { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "Mode %s is invalid\n", + pScrn->display->modes[i]); + continue; + } + } + if (last) { + last->next = first; + first->prev = last; + pScrn->modes = first; + RADEONSetPitch(pScrn); + } + return count; +} + +static int +RADEONValidateMergeTVModes (ScrnInfoPtr pScrn1) +{ + int i, count = 0, width, height; + RADEONInfoPtr info = RADEONPTR (pScrn1); + ScrnInfoPtr pScrn = info->CRT2pScrn; + DisplayModePtr last = NULL, new = NULL, first = NULL; + + /* fill in pScrn2 */ + pScrn->videoRam = pScrn1->videoRam; + pScrn->depth = pScrn1->depth; + pScrn->numClocks = pScrn1->numClocks; + pScrn->progClock = pScrn1->progClock; + pScrn->fbFormat = pScrn1->fbFormat; + pScrn->videoRam = pScrn1->videoRam; + pScrn->maxHValue = pScrn1->maxHValue; + pScrn->maxVValue = pScrn1->maxVValue; + pScrn->xInc = pScrn1->xInc; + + if (info->NoVirtual) { + pScrn1->display->virtualX = 0; + pScrn1->display->virtualY = 0; + } + + /* Free any allocated modes during configuration. We don't need them */ + while (pScrn->modes) { + xf86DeleteMode (&pScrn->modes, pScrn->modes); + } + while (pScrn->modePool) { + xf86DeleteMode (&pScrn->modePool, pScrn->modePool); + } + + /* If no mode specified in config, we use native resolution */ + if (!pScrn1->display->modes[0]) { + pScrn1->display->modes[0] = xnfalloc (16); + sprintf (pScrn1->display->modes[0], "%dx%d", 640, 480); + } + + for (i = 0; pScrn1->display->modes[i] != NULL; i++) { + if (sscanf (pScrn1->display->modes[i], "%dx%d", &width, &height) == 2) { + int j = 0; + while (tv_modes[j].h_disp) { + if (width != tv_modes[j].h_disp || + height != tv_modes[j].v_disp) { + j++; + continue; + } else + break; + }; + + if (!tv_modes[j].h_disp) { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "Mode %s is not a valid TV mode.\n", + pScrn1->display->modes[i]); + continue; + } + + new = xnfcalloc (1, sizeof (DisplayModeRec)); + new->prev = last; + new->name = xnfalloc (strlen (pScrn1->display->modes[i]) + 1); + strcpy (new->name, pScrn1->display->modes[i]); + new->HDisplay = new->CrtcHDisplay = width; + new->VDisplay = new->CrtcVDisplay = height; + switch (info->tvFormat) { + case NTSC: + new->HTotal = tv_modes[j].h_total_ntsc; + new->VTotal = tv_modes[j].v_total_ntsc; + break; + case PAL: + new->HTotal = tv_modes[j].h_total_pal; + new->VTotal = tv_modes[j].v_total_pal; + break; + default: + new->HTotal = tv_modes[j].h_total_ntsc; + new->VTotal = tv_modes[j].v_total_ntsc; + break; + } + new->CrtcHTotal = tv_modes[j].h_crtc_total; + new->CrtcVTotal = tv_modes[j].v_crtc_total; + new->CrtcHSyncStart = tv_modes[j].h_crtc_sync_start; + new->CrtcVSyncStart = tv_modes[j].v_crtc_sync_start; + new->CrtcHSyncEnd = tv_modes[j].h_crtc_sync_end; + new->CrtcVSyncEnd = tv_modes[j].v_crtc_sync_end; + + if (new->prev) + new->prev->next = new; + last = new; + if (!first) + first = new; +#if 1 + pScrn->virtualX = MAX (pScrn1->virtualX, width); + pScrn->virtualY = MAX (pScrn1->virtualY, height); +#endif + count++; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "TV mode: %s OK\n", + pScrn->display->modes[i]); + + } else { + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "Mode %s is invalid\n", + pScrn->display->modes[i]); + continue; + } + } + if (last) { + last->next = first; + first->prev = last; + pScrn->modes = first; + RADEONSetPitch(pScrn); + } + return count; +} + /* This is called by RADEONPreInit to initialize gamma correction */ static Bool RADEONPreInitGamma(ScrnInfoPtr pScrn) { @@ -3943,7 +4324,11 @@ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); return FALSE; } - + } else if (info->DisplayType == MT_CTV || info->DisplayType == MT_STV) { + /* TV mode validation routine */ + modesFound = RADEONValidateTVModes (pScrn); + if (modesFound < 1) + return FALSE; } else { /* First, free any allocated modes during configuration, since * we don't need them @@ -4036,8 +4421,10 @@ if (!pRADEONEnt->HasSecondary) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating CRTC2 modes for MergedFB ------------ \n"); - - modesFound = RADEONValidateMergeModes(pScrn); + if (info->MergeType == MT_STV || info->MergeType == MT_CTV) + modesFound = RADEONValidateMergeTVModes(pScrn); + else + modesFound = RADEONValidateMergeModes(pScrn); if (modesFound < 1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid mode found for CRTC2, disabling MergedFB\n"); @@ -4731,6 +5118,11 @@ if (!info->IsSecondary) RADEONGetMergedFBOptions(pScrn); + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + if (!RADEONGetTVInfo (pScrn)) goto fail; + } + + if (!RADEONPreInitGamma(pScrn)) goto fail; if (!RADEONPreInitModes(pScrn, pInt10)) goto fail; @@ -5717,12 +6109,28 @@ OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); - OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); - if ((info->ChipFamily == CHIP_FAMILY_R200) || - IS_R300_VARIANT) { + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl); + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) + OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl); + else + OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); + } else { + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) + OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl); + else + OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); + } } else { OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); + if (info->MergedFB) { + if ((info->MergeType != MT_STV) && (info->MergeType != MT_CTV)) + OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); + } else { + if ((info->DisplayType != MT_STV) && (info->DisplayType != MT_CTV)) + OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); + } } OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); @@ -5812,6 +6220,131 @@ } } +static void +RADEONRestoreTVRegisters (ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->tvoutType == TVOUT_INTERNAL) { + OUTREG (RADEON_TV_MASTER_CNTL, restore->tv_master_cntl + | RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | 0xf0); +/* + OUTREG(RADEON_TV_TVO_DATA_DELAY_A, + restore->tv_data_delay_a); + OUTREG(RADEON_TV_TVO_DATA_DELAY_B, + restore->tv_data_delay_b); + + OUTREG(RADEON_TV_CLKOUT_CNTL, restore->tv_clkout_cntl); + OUTREG(RADEON_TV_PLL_CNTL0, restore->tv_pll_cntl0); + OUTREG(RADEON_TV_CLOCK_SEL_CNTL, + restore->tv_clock_sel_cntl); +*/ + OUTREG (RADEON_TV_HRESTART, restore->tv_hrestart); + OUTREG (RADEON_TV_VRESTART, restore->tv_vrestart); + OUTREG (RADEON_TV_FRESTART, restore->tv_frestart); + OUTREG (RADEON_TV_FTOTAL, restore->tv_ftotal); + + OUTPLLP (pScrn, RADEON_TV_PLL_CNTL, restore->tv_tv_pll_cntl, 0); + OUTPLLP (pScrn, RADEON_TV_PLL_CNTL1, restore->tv_pll_cntl0, 0); + OUTPLLP (pScrn, RADEON_TV_PLL_FINE_CNTL, 0, 0); + + OUTREG (RADEON_TV_HTOTAL, restore->tv_htotal - 1); + /*OUTREG(RADEON_TV_HSIZE, restore->tv_hsize); */ + OUTREG (RADEON_TV_HDISP, restore->tv_hdisp); + OUTREG (RADEON_TV_HSTART, restore->tv_hstart); + OUTREG (RADEON_TV_VTOTAL, restore->tv_vtotal - 1); + OUTREG (RADEON_TV_VDISP, restore->tv_vdisp); + + OUTREG (RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); + + OUTREG (RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl); + OUTREG (RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2); + /*OUTREG(RADEON_TV_SYNC_SIZE, restore->tv_sync_size); */ + OUTREG (RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_saw_tooth_cntl); + OUTREG (RADEON_TV_Y_RISE_CNTL, restore->tv_rise_cntl); + OUTREG (RADEON_TV_Y_FALL_CNTL, restore->tv_fall_cntl); + + OUTREG (RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1); + OUTREG (RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2); + + OUTREG (RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl); + + OUTREG (RADEON_TV_UV_ADR, restore->tv_uv_adr); + + OUTREG (RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl); + /*OUTREG(RADEON_TV_FRAME_LOCK_CNTL, restore->tv_frame_lock_cntl); */ + + usleep (50000); + + OUTREG (RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); + OUTREG (RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); + + } else { + + RT_OUTREG(pScrn, VIP_MASTER_CNTL, + restore->tv_master_cntl | 0xf3); + + RT_OUTREG(pScrn, VIP_TVO_DATA_DELAY_A, + restore->tv_data_delay_a); + RT_OUTREG(pScrn, VIP_TVO_DATA_DELAY_B, + restore->tv_data_delay_b); + + RT_OUTREG(pScrn, VIP_CLKOUT_CNTL, restore->tv_clkout_cntl); + RT_OUTREG(pScrn, VIP_PLL_CNTL0, restore->tv_pll_cntl0); + + RT_OUTREG(pScrn, VIP_DHRESTART, restore->tv_hrestart); + RT_OUTREG(pScrn, VIP_DVRESTART, restore->tv_vrestart); + RT_OUTREG(pScrn, VIP_DFRESTART, restore->tv_frestart); + RT_OUTREG(pScrn, VIP_VFTOTAL, restore->tv_ftotal); + + RT_OUTREG(pScrn, VIP_CLOCK_SEL_CNTL, + restore->tv_clock_sel_cntl); + RT_OUTREG(pScrn, VIP_TV_PLL_CNTL, restore->tv_tv_pll_cntl); + RT_OUTREG(pScrn, VIP_CRT_PLL_CNTL, restore->tv_crt_pll_cntl); + RT_OUTREG(pScrn, VIP_HTOTAL, restore->tv_htotal - 1); + RT_OUTREG(pScrn, VIP_HSIZE, restore->tv_hsize); + RT_OUTREG(pScrn, VIP_HDISP, restore->tv_hdisp); + RT_OUTREG(pScrn, VIP_HSTART, restore->tv_hstart); + RT_OUTREG(pScrn, VIP_VTOTAL, restore->tv_vtotal - 1); + RT_OUTREG(pScrn, VIP_VDISP, restore->tv_vdisp); + + RT_OUTREG(pScrn, VIP_TIMING_CNTL, restore->tv_timing_cntl); + + RT_OUTREG(pScrn, VIP_VSCALER_CNTL1, restore->tv_vscaler_cntl); + RT_OUTREG(pScrn, VIP_VSCALER_CNTL2, restore->tv_vscaler_cntl2); + RT_OUTREG(pScrn, VIP_SYNC_SIZE, restore->tv_sync_size); + RT_OUTREG(pScrn, VIP_Y_SAW_TOOTH_CNTL, + restore->tv_saw_tooth_cntl); + RT_OUTREG(pScrn, VIP_Y_RISE_CNTL, restore->tv_rise_cntl); + RT_OUTREG(pScrn, VIP_Y_FALL_CNTL, restore->tv_fall_cntl); + + RT_OUTREG(pScrn, VIP_MODULATOR_CNTL1, + restore->tv_modulator_cntl1); + RT_OUTREG(pScrn, VIP_MODULATOR_CNTL2, + restore->tv_modulator_cntl2); + + RT_OUTREG(pScrn, VIP_RGB_CNTL, restore->tv_rgb_cntl); + + RT_OUTREG(pScrn, VIP_UV_ADR, restore->tv_uv_adr); + + RT_OUTREG(pScrn, VIP_PRE_DAC_MUX_CNTL, + restore->tv_pre_dac_mux_cntl); + RT_OUTREG(pScrn, VIP_FRAME_LOCK_CNTL, + restore->tv_frame_lock_cntl); + + usleep (50000); + + RT_OUTREG(pScrn, VIP_TV_DAC_CNTL, restore->tv_dac_cntl); + RT_OUTREG(pScrn, VIP_MASTER_CNTL, restore->tv_master_cntl); + + + } + +} + static void RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) { int i = 0; @@ -5954,9 +6487,12 @@ usleep(50000); /* Let the clock to lock */ +#if 0 OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, RADEON_VCLK_SRC_SEL_PPLLCLK, ~(RADEON_VCLK_SRC_SEL_MASK)); +#endif + OUTPLLP (pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_cntl, 0); } @@ -6013,9 +6549,12 @@ usleep(5000); /* Let the clock to lock */ +#if 0 OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, ~(RADEON_PIX2CLK_SRC_SEL_MASK)); +#endif + OUTPLLP (pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl, 0); } void RADEONChangeSurfaces(ScrnInfoPtr pScrn) @@ -6204,6 +6743,19 @@ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); static RADEONSaveRec restore0; + + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + if (info->tvoutType != TVOUT_INTERNAL) + RADEONVIPReset (pScrn); + RADEONRestoreTVRegisters (pScrn, restore); + } else if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + if (info->tvoutType != TVOUT_INTERNAL) + RADEONVIPReset (pScrn); + RADEONRestoreTVRegisters (pScrn, restore); + } + } + /* For Non-dual head card, we don't have private field in the Entity */ if (!info->HasCRTC2) { RADEONRestoreCommonRegisters(pScrn, restore); @@ -6331,6 +6883,7 @@ save->crtc_pitch = INREG(RADEON_CRTC_PITCH); save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL); save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL); + save->disp_tv_out_cntl = INREG(RADEON_DISP_TV_OUT_CNTL); if (info->IsDellServer) { save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); @@ -6367,6 +6920,93 @@ } } +static void +RADEONSaveTVRegisters (ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->tvoutType == TVOUT_RT1) { + save->tv_master_cntl = RT_INREG(pScrn, VIP_MASTER_CNTL); + save->tv_tv_pll_cntl = RT_INREG(pScrn, VIP_TV_PLL_CNTL); + save->tv_crt_pll_cntl = RT_INREG(pScrn, VIP_CRT_PLL_CNTL); + save->tv_htotal = RT_INREG(pScrn, VIP_HTOTAL) + 1; + save->tv_hsize = RT_INREG(pScrn, VIP_HSIZE); + save->tv_hdisp = RT_INREG(pScrn, VIP_HDISP); + save->tv_hstart = RT_INREG(pScrn, VIP_HSTART); + save->tv_vtotal = RT_INREG(pScrn, VIP_VTOTAL) + 1; + save->tv_vdisp = RT_INREG(pScrn, VIP_VDISP); + save->tv_timing_cntl = RT_INREG(pScrn, VIP_TIMING_CNTL); + save->tv_vscaler_cntl = RT_INREG(pScrn, VIP_VSCALER_CNTL1); + save->tv_vscaler_cntl2 = RT_INREG(pScrn, VIP_VSCALER_CNTL2); + save->tv_sync_size = RT_INREG(pScrn, VIP_SYNC_SIZE); + save->tv_clock_sel_cntl = RT_INREG(pScrn, VIP_CLOCK_SEL_CNTL); + save->tv_clkout_cntl = RT_INREG(pScrn, VIP_CLKOUT_CNTL); + save->tv_hrestart = RT_INREG(pScrn, VIP_DHRESTART); + save->tv_vrestart = RT_INREG(pScrn, VIP_DVRESTART); + save->tv_frestart = RT_INREG(pScrn, VIP_DFRESTART); + save->tv_ftotal = RT_INREG(pScrn, VIP_VFTOTAL); + save->tv_data_delay_a = RT_INREG(pScrn, VIP_TVO_DATA_DELAY_A); + save->tv_data_delay_b = RT_INREG(pScrn, VIP_TVO_DATA_DELAY_B); + save->tv_dac_cntl = RT_INREG(pScrn, VIP_TV_DAC_CNTL); + save->tv_pll_cntl0 = RT_INREG(pScrn, VIP_PLL_CNTL0); + save->tv_modulator_cntl1 = + RT_INREG(pScrn, VIP_MODULATOR_CNTL1); + save->tv_modulator_cntl2 = + RT_INREG(pScrn, VIP_MODULATOR_CNTL2); + save->tv_frame_lock_cntl = + RT_INREG(pScrn, VIP_FRAME_LOCK_CNTL); + save->tv_pre_dac_mux_cntl = + RT_INREG(pScrn, VIP_PRE_DAC_MUX_CNTL); + save->tv_rgb_cntl = RT_INREG(pScrn, VIP_RGB_CNTL); + save->tv_saw_tooth_cntl = + RT_INREG(pScrn, VIP_Y_SAW_TOOTH_CNTL); + save->tv_rise_cntl = RT_INREG(pScrn, VIP_Y_RISE_CNTL); + save->tv_fall_cntl = RT_INREG(pScrn, VIP_Y_FALL_CNTL); + save->tv_uv_adr = RT_INREG(pScrn, VIP_UV_ADR); + + save->disp_output_cntl = INREG (RADEON_DISP_OUTPUT_CNTL); + } else if (info->tvoutType == TVOUT_INTERNAL) { + save->tv_master_cntl = INREG (RADEON_TV_MASTER_CNTL); + save->tv_tv_pll_cntl = INPLL (pScrn, RADEON_TV_PLL_CNTL); + save->tv_pll_cntl0 = INPLL (pScrn, RADEON_TV_PLL_CNTL1); + save->tv_htotal = INREG (RADEON_TV_HTOTAL) + 1; + save->tv_hsize = INREG (RADEON_TV_HDISP); + save->tv_hdisp = INREG (RADEON_TV_HDISP); + save->tv_hstart = INREG (RADEON_TV_HSTART); + save->tv_vtotal = INREG (RADEON_TV_VTOTAL) + 1; + save->tv_vdisp = INREG (RADEON_TV_VDISP); + save->tv_timing_cntl = INREG (RADEON_TV_TIMING_CNTL); + save->tv_vscaler_cntl = INREG (RADEON_TV_VSCALER_CNTL1); + save->tv_vscaler_cntl2 = INREG (RADEON_TV_VSCALER_CNTL2); + /*save->tv_sync_size = INREG(RADEON_TV_SYNC_SIZE); + save->tv_clock_sel_cntl = INREG(RADEON_TV_CLOCK_SEL_CNTL); + save->tv_clkout_cntl = INREG(RADEON_TV_CLKOUT_CNTL); */ + save->tv_hrestart = INREG (RADEON_TV_HRESTART); + save->tv_vrestart = INREG (RADEON_TV_VRESTART); + save->tv_frestart = INREG (RADEON_TV_FRESTART); + save->tv_ftotal = INREG (RADEON_TV_FTOTAL); + /*save->tv_data_delay_a = INREG(RADEON_TV_TVO_DATA_DELAY_A); + save->tv_data_delay_b = INREG(RADEON_TV_TVO_DATA_DELAY_B); */ + save->tv_dac_cntl = INREG (RADEON_TV_DAC_CNTL); + /*save->tv_pll_cntl0 = INREG(RADEON_TV__PLL_CNTL0); */ + save->tv_modulator_cntl1 = INREG (RADEON_TV_MODULATOR_CNTL1); + save->tv_modulator_cntl2 = INREG (RADEON_TV_MODULATOR_CNTL2); + /*save->tv_frame_lock_cntl = + INREG(RADEON_TV_FRAME_LOCK_CNTL); */ + save->tv_pre_dac_mux_cntl = INREG (RADEON_TV_PRE_DAC_MUX_CNTL); + save->tv_rgb_cntl = INREG (RADEON_TV_RGB_CNTL); + save->tv_saw_tooth_cntl = INREG (RADEON_TV_Y_SAW_TOOTH_CNTL); + save->tv_rise_cntl = INREG (RADEON_TV_Y_RISE_CNTL); + save->tv_fall_cntl = INREG (RADEON_TV_Y_FALL_CNTL); + save->tv_uv_adr = INREG (RADEON_TV_UV_ADR); + + save->disp_output_cntl = INREG (RADEON_DISP_OUTPUT_CNTL); + + } + +} + /* Read CRTC2 registers */ static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) { @@ -6376,6 +7016,7 @@ save->dac2_cntl = INREG(RADEON_DAC_CNTL2); save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); + save->disp_tv_out_cntl = INREG (RADEON_DISP_TV_OUT_CNTL); save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); save->crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); @@ -6398,6 +7039,7 @@ save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV); save->ppll_div_3 = INPLL(pScrn, RADEON_PPLL_DIV_3); save->htotal_cntl = INPLL(pScrn, RADEON_HTOTAL_CNTL); + save->vclk_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); RADEONTRACE(("Read: 0x%08x 0x%08x 0x%08x\n", save->ppll_ref_div, @@ -6415,6 +7057,7 @@ save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV); save->p2pll_div_0 = INPLL(pScrn, RADEON_P2PLL_DIV_0); save->htotal_cntl2 = INPLL(pScrn, RADEON_HTOTAL2_CNTL); + save->pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); RADEONTRACE(("Read: 0x%08x 0x%08x 0x%08x\n", save->p2pll_ref_div, @@ -7070,6 +7713,16 @@ save->disp_merge_cntl = info->SavedReg.disp_merge_cntl; save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + if ((info->DisplayType == MT_CTV) || (info->DisplayType == MT_STV)) { + save->disp_merge_cntl |= RADEON_DISP_RGB_OFFSET_EN; + mode->CrtcHTotal = save->tv_htotal; + mode->CrtcVTotal = save->tv_vtotal; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlusTV; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidthTV; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlusTV; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidthTV; + } + #if X_BYTE_ORDER == X_BIG_ENDIAN /* Alhought we current onlu use aperture 0, also setting aperture 1 should not harm -ReneR */ switch (pScrn->bitsPerPixel) { @@ -7102,6 +7755,19 @@ save->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); } + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + if (info->tvoutType == TVOUT_INTERNAL) { + save->vclk_cntl = (info->SavedReg.vclk_cntl & + ~RADEON_VCLK_SRC_SEL_MASK) | 0xc3; + } else { + save->vclk_cntl = (info->SavedReg.vclk_cntl & + ~RADEON_VCLK_SRC_SEL_MASK) | 0xc2; + } + } else { + save->vclk_cntl = (info->SavedReg.vclk_cntl & + ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; + } + RADEONTRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", save->crtc_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth)); @@ -7150,21 +7816,52 @@ /* Turn CRT on in case the first head is a DFP */ save->crtc_ext_cntl |= RADEON_CRTC_CRT_ON; save->dac2_cntl = info->SavedReg.dac2_cntl; - /* always let TVDAC drive CRT2, we don't support tvout yet */ - save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; save->disp_output_cntl = info->SavedReg.disp_output_cntl; - if (info->ChipFamily == CHIP_FAMILY_R200 || - IS_R300_VARIANT) { - save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK | + + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + save->dac2_cntl &= ~RADEON_DAC2_DAC2_CLK_SEL; + save->disp_output_cntl = ((info->SavedReg.disp_output_cntl + & ~RADEON_DISP_DAC_SOURCE_MASK) | RADEON_DISP_TV_SOURCE_CRTC); + save->disp_tv_out_cntl = + info->SavedReg.disp_tv_out_cntl | RADEON_DISP_TV_PATH_SRC_CRTC2; + } else { + save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK | RADEON_DISP_DAC2_SOURCE_MASK); - if (pRADEONEnt->MonType1 != MT_CRT) { - save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | + if (pRADEONEnt->MonType1 != MT_CRT) { + save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | RADEON_DISP_DAC2_SOURCE_CRTC2); + } else { + if (pRADEONEnt->ReversedDAC) { + save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2; + } else { + save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + } + } + } } else { - if (pRADEONEnt->ReversedDAC) { - save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2; + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + save->dac2_cntl &= ~RADEON_DAC2_DAC2_CLK_SEL; + save->disp_output_cntl = ((info->SavedReg.disp_output_cntl + & ~RADEON_DISP_DAC_SOURCE_MASK) | RADEON_DISP_TV_SOURCE_CRTC); + save->disp_tv_out_cntl = + info->SavedReg.disp_tv_out_cntl | RADEON_DISP_TV_PATH_SRC_CRTC2; } else { - save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK | + RADEON_DISP_DAC2_SOURCE_MASK); + if (pRADEONEnt->MonType1 != MT_CRT) { + save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | + RADEON_DISP_DAC2_SOURCE_CRTC2); + } else { + if (pRADEONEnt->ReversedDAC) { + save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2; + } else { + save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + } + } } } } else { @@ -7187,6 +7884,71 @@ save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL; } } + if (info->tvoutType == TVOUT_INTERNAL) { + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) + save->dac2_cntl = info->SavedReg.dac2_cntl + & ~(RADEON_DAC2_DAC_CLK_SEL | RADEON_DAC2_DAC2_CLK_SEL); + } else { + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) + save->dac2_cntl = info->SavedReg.dac2_cntl + & ~(RADEON_DAC2_DAC_CLK_SEL | RADEON_DAC2_DAC2_CLK_SEL); + } + } + } + + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + + mode->CrtcHTotal = save->tv_htotal; + mode->CrtcVTotal = save->tv_vtotal; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlusTV; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidthTV; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlusTV; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidthTV; + +#if 0 + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + /*save->dac_cntl = info->SavedReg.dac_cntl | (1<<10); */ + save->disp_output_cntl |= (1 << 16); + save->disp_output_cntl &= ~3; + save->disp_tv_out_cntl = + info->SavedReg.disp_tv_out_cntl | RADEON_DISP_TV_PATH_SRC_CRTC2; + /*****workaround for R200 1024x768 Mode problem, not working yet + if ((mode->HDisplay == 1024) && (mode->VDisplay == 768)) { + save->disp_tv_out_cntl |= 0x555 | (1<<15); + mode->CrtcHTotal *= 2; + } + */ + } +#endif + } + } else { + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + + mode->CrtcHTotal = save->tv_htotal; + mode->CrtcVTotal = save->tv_vtotal; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlusTV; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidthTV; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlusTV; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidthTV; + +#if 0 + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + /*save->dac_cntl = info->SavedReg.dac_cntl | (1<<10); */ + save->disp_output_cntl |= (1 << 16); + save->disp_output_cntl &= ~3; + save->disp_tv_out_cntl = + info->SavedReg.disp_tv_out_cntl | RADEON_DISP_TV_PATH_SRC_CRTC2; + /*****workaround for R200 1024x768 Mode problem, not working yet + if ((mode->HDisplay == 1024) && (mode->VDisplay == 768)) { + save->disp_tv_out_cntl |= 0x555 | (1<<15); + mode->CrtcHTotal *= 2; + } + */ + } +#endif + } } save->crtc2_h_total_disp = @@ -7296,6 +8058,40 @@ } #endif + if (info->MergedFB) { + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + if (info->tvoutType == TVOUT_INTERNAL) { + save->pixclks_cntl = + (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | 0x103; + } else { + save->pixclks_cntl = + (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | 0x102; + } + } else { + save->pixclks_cntl = (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; + } + } else { + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + if (info->tvoutType == TVOUT_INTERNAL) { + save->pixclks_cntl = + (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | 0x103; + } else { + save->pixclks_cntl = + (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | 0x102; + } + } else { + save->pixclks_cntl = (info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; + } + } + RADEONTRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", save->crtc2_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth)); @@ -7546,6 +8342,422 @@ save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; } +static void +RADEONInitTVRegisters (ScrnInfoPtr pScrn, RADEONSavePtr orig, + RADEONSavePtr save, DisplayModePtr mode, RADEONPLLPtr pll, + RADEONInfoPtr info) +{ + SETCLK_INPUT SetClkInput; + SETCLK_OUTPUT SetClkOutput; + SETCRTMN_INPUT SetMnInput; + SETCRTMN_OUTPUT SetMnOutput; + VT_MASTER_INPUT Input; + VT_MASTER_OUTPUT Output; + unsigned long start_line, lines_before_active, vert_space, + flicker_removal; + int retcode, mode888, i; + float h_scale; + + /*mode888 = (mode->HDisplay > 800) ? 0 : 1; */ + mode888 = 1; + SetClkInput.RefClk = pll->reference_freq * 10000; + SetClkInput.ReqdClk = std_tv_clk[info->tvFormat]; + if (info->tvFormat == PAL && SetClkInput.RefClk == 27000000) + SetClkInput.MinPLLInputFreq = 330000; + else + SetClkInput.MinPLLInputFreq = 400000; + SetClkInput.MinPLLOutputFreq = 100000000; + SetClkInput.MaxPLLOutputFreq = 250000000; + SetClkInput.BestPLLOutputFreq = 210000000; + SetClkInput.FBDivMult = 1; + SetClkInput.FixedPostDiv = 0; + SetClkInput.PUpperLimit = 16; + SetClkInput.ErrSign = 0; + SetClkInput.CalculateCRTClkValues = FALSE; + SetClkInput.ulChipType = info->videoChip; + SetClkInput.CalculateCRTClkValues = FALSE; + + SetClk (&SetClkInput, &SetClkOutput); + + /* Lets setup the input paramaters for SetCRTMN() */ + SetMnInput.noCLKBY2 = 0; + SetMnInput.CRTFBDivMult = 1; + + SetMnInput.MinCRTPLLInputFreq = 200000; + if (info->tvoutType == TVOUT_INTERNAL) + SetMnInput.MinCRTPLLOutputFreq = 100000000; + else + SetMnInput.MinCRTPLLOutputFreq = 125000000; + SetMnInput.MaxCRTPLLOutputFreq = 250000000; + + if ((info->ChipFamily == CHIP_FAMILY_RV200) && + (mode->HDisplay == 800) && (mode->VDisplay == 600)) { + SetMnInput.MinCRTPLLInputFreq = 400000; + SetMnInput.MaxCRTPLLOutputFreq = 400000000; + } + + if (info->tvoutType == TVOUT_INTERNAL) + SetMnInput.BestCRTPLLOutputFreq = 175000000; + else + SetMnInput.BestCRTPLLOutputFreq = 210000000; + + SetMnInput.CRT_VTotal = mode->VTotal; + SetMnInput.CRT_HTotal = mode->HTotal; + + /*****workaround for R200 1024x768 Mode problem, not working yet + if (mode->HDisplay == 1024) SetMnInput.CRT_HTotal /= 2; + */ + SetMnInput.MaxVDelta = 2; + SetMnInput.MaxHDelta = 40; + SetMnInput.CRTRefClk = pll->reference_freq * 10000; + SetMnInput.TVRefClk = pll->reference_freq * 10000; + SetMnInput.TVFBDivMult = 1; + SetMnInput.TV_M = SetClkOutput.BestM; + SetMnInput.TV_N = SetClkOutput.BestN; + SetMnInput.TV_P = SetClkOutput.BestP; + SetMnInput.TV_HTotal = std_tv_timing[info->tvFormat].h_total; + SetMnInput.TV_VTotal = std_tv_timing[info->tvFormat].v_total; + + SetMnInput.BytesPerPixel = 2 + mode888; + if (info->tvFormat == PAL) + SetMnInput.FrameSizeAdjust = -6; + else + SetMnInput.FrameSizeAdjust = 0; + SetMnInput.PUpperLimit = 16; + SetMnInput.ErrSign = 0; + + if (info->tvoutType == TVOUT_INTERNAL) + SetMnInput.FrameRateDiffTol = 6; + else + SetMnInput.FrameRateDiffTol = 0; + + SetMnInput.FixedPostDiv = 0; + SetMnInput.ulChipType = info->videoChip; + + SetCrtMN (&SetMnInput, &SetMnOutput); + + Input.RefFreq = pll->reference_freq * 10000; + start_line = std_tv_timing[info->tvFormat].h_sync_len + + std_tv_timing[info->tvFormat].h_setup_del + + std_tv_timing[info->tvFormat].h_active_del - + std_tv_timing[info->tvFormat].h_genclk_del; + lines_before_active = + ((std_tv_timing[info->tvFormat].v_field_total - + std_tv_timing[info->tvFormat].v_active_lines) / 2 - 1) - + VERT_LEAD_IN_LINES + 1; + + Input.TVClksToActive = lines_before_active * + std_tv_timing[info->tvFormat].h_total + start_line; + Input.TVHPeriod = std_tv_timing[info->tvFormat].h_total; + Input.TVHBlank = std_tv_timing[info->tvFormat].h_total - + std_tv_timing[info->tvFormat].h_active_len; + + Input.D_HTOTAL = SetMnOutput.HTotal - 1; + Input.D_VTOTAL = SetMnOutput.VTotal - 1; + + if ((info->tvFormat == NTSC) || + (info->tvFormat == PAL60) || (info->tvFormat == PALM)) { + Input.D_FTOTAL = std_tv_timing[info->tvFormat].v_fields - 1; + } else { + Input.D_FTOTAL = std_tv_timing[info->tvFormat].v_fields * 2 - 1; + } + save->tv_ftotal = Input.D_FTOTAL; + + Input.D_HDISP = mode->HDisplay - 1; + /*****workaround for R200 1024x768 Mode problem, not working yet + if (mode->HDisplay == 1024) Input.D_HDISP = 511; + */ + Input.D_VDISP = mode->VDisplay - 1; + + Input.CRT_M = SetMnOutput.CRT_M; + Input.CRT_N = SetMnOutput.CRT_N; + + Input.CRTCLK_USE_CLKBY2 = SetMnOutput.CRTCLK_USE_CLKBY2; + Input.BYT_CLK_DIV = SetMnOutput.BYT_CLK_DIV; + Input.RGB_565_888 = mode888; + Input.TVFBDivMult = 1; + Input.CRTFBDivMult = 1; + + Input.TV_M = SetClkOutput.BestM; + Input.TV_N = SetClkOutput.BestN; + Input.TV_P = SetClkOutput.BestP; + + Input.TV_Lines = std_tv_timing[info->tvFormat].v_field_total; + Input.TV_Fsc = std_tv_clk[info->tvFormat]; + Input.TV_Samples = std_tv_timing[info->tvFormat].h_total; + + Input.UV_ACCUM_INIT = 0x10; /*????? */ + Input.Y_ACCUM_INIT = 0x0; + + vert_space = SetMnOutput.VTotal * 2 * 10000 / + std_tv_timing[info->tvFormat].v_field_total; + Input.UV_INC = vert_space * (1 << FRAC_BITS) / 10000; + Input.Y_INC = Input.UV_INC; + save->tv_vscaler_cntl = + (orig->tv_vscaler_cntl & 0xe3ff0000) | Input.UV_INC; + if (info->tvoutType == TVOUT_INTERNAL) { + save->tv_vscaler_cntl |= RADEON_RESTART_FIELD; + if (mode->HDisplay == 1024) + save->tv_vscaler_cntl |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); + else + save->tv_vscaler_cntl |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); + } else + save->tv_vscaler_cntl |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); + + flicker_removal = + (float) SetMnOutput.VTotal * 2.0 / + std_tv_timing[info->tvFormat].v_field_total + 0.5; + if (flicker_removal < 3) + flicker_removal = 3; + for (i = 0; i < 6; ++i) { + if (flicker_removal == SLOPE_limit[i]) + break; + } + save->tv_saw_tooth_cntl = + (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + + 5001) / 10000 / 8 | ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / + 8) << 16); + save->tv_fall_cntl = + (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | + RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / + 1024; + save->tv_rise_cntl = + RADEON_Y_RISE_PING_PONG | (flicker_removal * 1024 - + 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - + 1)) / 1024; + + save->tv_vscaler_cntl2 = (orig->tv_vscaler_cntl2 & 0x00ffffff) + | (Input.UV_ACCUM_INIT << 24) + | RADEON_DITHER_MODE + | RADEON_Y_OUTPUT_DITHER_EN + | RADEON_UV_OUTPUT_DITHER_EN + | RADEON_UV_TO_BUF_DITHER_EN; + + retcode = + VTMaster ((LPVT_MASTER_INPUT) & Input, (LPVT_MASTER_OUTPUT) & Output); + if (retcode) { + save->tv_hrestart = Output.D_HRESTART; + save->tv_vrestart = Output.D_VRESTART; + save->tv_frestart = Output.D_FRESTART; + } else { + save->tv_hrestart = orig->tv_hrestart; + save->tv_vrestart = mode->CrtcVDisplay + 25; + save->tv_frestart = orig->tv_frestart; + } + + save->tv_tv_pll_cntl = (SetClkOutput.BestP << 24) | + ((SetClkOutput.BestN & 0x1ff) << 8) | + ((SetClkOutput.BestN >> 9) << 21) | + (SetClkOutput.BestM & 0xff) | + ((SetClkOutput.BestM >> 8) << 18) | RADEON_TV_SLIP_EN | RADEON_TV_DTO_EN; + + save->tv_crt_pll_cntl = + ((SetMnOutput.CRT_N & 0x1ff) << 8) | + ((SetMnOutput.CRT_N >> 9) << 21) | + (SetMnOutput.CRT_M & 0xff) | + ((SetMnOutput.CRT_M >> 8) << 18) | + (SetMnOutput.CRTCLK_USE_CLKBY2 ? 0x02000000 : 0); + + save->tv_clock_sel_cntl = (orig->tv_clock_sel_cntl & ~0x3f) | + 0x33 | ((SetMnOutput.BYT_CLK_DIV - 1) << 2); + save->tv_clkout_cntl = 0x09; + if (info->tvoutType != TVOUT_INTERNAL) { + save->tv_clkout_cntl |= (1 << 5); + } + + save->tv_htotal = SetMnOutput.HTotal; + save->tv_hsize = mode->HDisplay; + save->tv_hdisp = mode->HDisplay - 1; + + if (info->tvoutType == TVOUT_INTERNAL) + save->tv_hstart = mode->HDisplay - mode888 - 12; + else + save->tv_hstart = mode->HDisplay - mode888 + 12; + + save->tv_vtotal = SetMnOutput.VTotal; + save->tv_vdisp = mode->VDisplay - 1; + save->tv_sync_size = mode->HDisplay + 8; + + /*****workaround for R200 1024x768 Mode problem, not working yet + if (mode->HDisplay == 1024) { + save->tv_hsize = 512; + save->tv_hdisp = 511; + save->tv_hstart = 512 + 12 - mode888; + } + */ + + if (info->tvFormat == NTSC) + h_scale = 0.88; + else + h_scale = 0.91; + save->tv_timing_cntl = (orig->tv_timing_cntl & 0xfffff000) + /* | (unsigned long) (mode->HDisplay * 4096 / 1976); */ + | (unsigned long) (mode->HDisplay * 4096 / + (std_tv_timing[info->tvFormat].h_active_len + + std_tv_timing[info->tvFormat].h_active_del) / + h_scale); + if (IS_R300_VARIANT) { + int tmp; + tmp = 0x72 * 640 / mode->HDisplay; + /* 1024x768 mode UV seems to be scaled too high by BIOS (0x80) + we scale it down a bit here. This is a hack, need to find + a proper way of doing this. + */ + save->tv_timing_cntl &= 0x00ffffff; + save->tv_timing_cntl |= (tmp << 24); + } + + if (info->MergedFB) { + if (info->MergeType == MT_STV || info->MergeType == MT_CTV) { + save->feedback_div_2 = SetMnOutput.CRT_N; + if (info->tvoutType == TVOUT_INTERNAL) + save->p2pll_ref_div = + SetMnOutput.CRT_M * (SetMnOutput.BYT_CLK_DIV); + else { + save->p2pll_ref_div = + SetMnOutput.CRT_M * (SetMnOutput.BYT_CLK_DIV); + /*if (mode->HDisplay == 1024) save->p2pll_ref_div /= 2; */ + } + save->post_div_2 = (2 + mode888); + save->p2pll_div_0 = (save->feedback_div_2 | (4 << 16)); + save->htotal_cntl2 = save->tv_htotal & 0x07; + } + } else if (info->IsSecondary) { + save->feedback_div_2 = SetMnOutput.CRT_N; + if (info->tvoutType == TVOUT_INTERNAL) + save->p2pll_ref_div = + SetMnOutput.CRT_M * (SetMnOutput.BYT_CLK_DIV); + else { + save->p2pll_ref_div = + SetMnOutput.CRT_M * (SetMnOutput.BYT_CLK_DIV); + /*if (mode->HDisplay == 1024) save->p2pll_ref_div /= 2; */ + } + save->post_div_2 = (2 + mode888); + save->p2pll_div_0 = (save->feedback_div_2 | (4 << 16)); + save->htotal_cntl2 = save->tv_htotal & 0x07; + } else { + save->feedback_div = SetMnOutput.CRT_N; + save->ppll_ref_div = SetMnOutput.CRT_M * (SetMnOutput.BYT_CLK_DIV); + save->post_div = (2 + mode888); + save->ppll_div_3 = (save->feedback_div | (4 << 16)); + save->htotal_cntl = save->tv_htotal & 0x07; + + } + + { + info->HBlankTV = mode->CrtcHTotal - mode->CrtcHDisplay; + info->HOverPlusTV = mode->CrtcHSyncStart - mode->CrtcHDisplay; + info->HSyncWidthTV = mode->CrtcHSyncEnd - mode->CrtcHSyncStart; + + /*****workaround for R200 1024x768 Mode problem, not working yet */ + if (0 /*mode->HDisplay == 1024 */ ) { + info->HOverPlusTV = info->HOverPlusTV * + (save->tv_htotal * 2 - mode->CrtcHDisplay - + info->HSyncWidthTV) / (info->HBlankTV - info->HSyncWidthTV); + info->HBlankTV = save->tv_htotal * 2 - mode->CrtcHDisplay; + } else { + info->HOverPlusTV = info->HOverPlusTV * + (save->tv_htotal - mode->CrtcHDisplay - info->HSyncWidthTV) / + (info->HBlankTV - info->HSyncWidthTV); + info->HBlankTV = save->tv_htotal - mode->CrtcHDisplay; + } + info->VBlankTV = mode->CrtcVTotal - mode->CrtcVDisplay; + info->VOverPlusTV = mode->CrtcVSyncStart - mode->CrtcVDisplay; + info->VSyncWidthTV = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + + info->VOverPlusTV = info->VOverPlusTV * + (save->tv_vtotal - mode->CrtcVDisplay - info->VSyncWidthTV) / + (info->VBlankTV - info->VSyncWidthTV); + info->VBlankTV = save->tv_vtotal - mode->CrtcVDisplay; + if (info->VOverPlusTV == 0) + info->VOverPlusTV = 1; + + } + + /*save->tv_hstart = mode->HDisplay + info->HOverPlus - 1;*/ + if (info->tvoutType == TVOUT_INTERNAL) { + save->tv_dac_cntl = (orig->tv_dac_cntl | RADEON_TV_DAC_BLANK | RADEON_TV_DAC_HOLD) + & 0xf8ffffb7; + + if (info->ChipFamily == CHIP_FAMILY_RV200) { + save->tv_dac_cntl &= ~(0xf << 20); + save->tv_dac_cntl |= (6 << 20); + } + save->tv_dac_cntl = 0x00680103; + } else { + save->tv_dac_cntl = (orig->tv_dac_cntl + | RADEON_TV_DAC_BLANK + | RADEON_TV_DAC_HOLD + | RADEON_TV_MONITOR_DETECT_EN) + & ~0x3cc; + } + + save->tv_modulator_cntl1 = (orig->tv_modulator_cntl1 & ~0x007f7fc0); + switch (info->tvFormat) { + + case PAL: + save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN + | RADEON_ALT_PHASE_EN + | (0x3b << 16) + | (0x3b << 8); + save->tv_modulator_cntl2 = (0x1b2) | (0x3e << 16); + break; + + case NTSC: + default: + save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; + save->tv_modulator_cntl1 |= RADEON_SYNC_TIP_LEVEL | (0x3b << 16) | (0x46 << 8); + save->tv_modulator_cntl2 = (0x191); + break; + + } + + save->tv_data_delay_a = 0x0b0c0a06; + save->tv_data_delay_b = 0x070a0a0c; + if (info->tvoutType == TVOUT_INTERNAL) + save->tv_frame_lock_cntl = 0x0; + else + save->tv_frame_lock_cntl = 0x0f; + + if (info->tvoutType == TVOUT_INTERNAL) { + save->tv_pll_cntl0 = (4 << 8) | (4 << 11) | (2 << 14) + | RADEON_TVCLK_SRC_SEL_TVPLL | RADEON_TVPLL_TEST_DIS; + if (info->MergedFB) { + if (info->MergeType == MT_STV || info->MergeType == MT_CTV) + save->tv_rgb_cntl = RADEON_RGB_SRC_SEL_CRTC2; + } else if (info->IsSecondary) { + save->tv_rgb_cntl = RADEON_RGB_SRC_SEL_CRTC2; + } else { + save->tv_rgb_cntl = 0x0; + } + save->tv_rgb_cntl |= RADEON_RGB_DITHER_EN | (0x0b << 16) | (0x07 << 20); + save->tv_pre_dac_mux_cntl = RADEON_Y_RED_EN + | RADEON_C_GRN_EN + | RADEON_CMP_BLU_EN + | RADEON_DAC_DITHER_EN + | (0x2c << RADEON_TV_FORCE_DAC_DATA_SHIFT); + } else { + save->tv_pll_cntl0 = RADEON_TVPLL_SLEEP | RADEON_TVPLL_REFCLK_SEL + | (4 << 8) | (1 << 11) | (5 << 13) | (4 << 16) | (1 << 19) | (5 << 21); + save->tv_rgb_cntl = mode888; + save->tv_pre_dac_mux_cntl = RADEON_Y_RED_EN + | RADEON_C_GRN_EN + | RADEON_CMP_BLU_EN + | RADEON_DAC_DITHER_EN + | (0xaf << RADEON_TV_FORCE_DAC_DATA_SHIFT); + } + + save->tv_master_cntl = (orig->tv_master_cntl & 0xe0) + & (RADEON_CRT_FIFO_CE_EN | RADEON_TV_FIFO_CE_EN); + if (info->tvFormat == NTSC) + save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX; + else + save->tv_master_cntl &= ~RADEON_RESTART_PHASE_FIX; + + save->tv_uv_adr = 0xc8; + +} + /* Define PLL registers for requested video mode */ static void RADEONInitPLLRegisters(RADEONInfoPtr info, RADEONSavePtr save, RADEONPLLPtr pll, double dot_clock) @@ -7745,14 +8957,32 @@ if (info->IsSecondary) { if (!RADEONInitCrtc2Registers(pScrn, save, mode, info)) return FALSE; - RADEONInitPLL2Registers(save, &info->pll, dot_clock, info->DisplayType != MT_CRT); + + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + RADEONInitTVRegisters (pScrn, &info->SavedReg, save, mode, + &info->pll, info); + } else { + RADEONInitPLL2Registers(save, &info->pll, dot_clock, info->DisplayType != MT_CRT); + } } else if (info->MergedFB) { RADEONInitCommonRegisters(save, info); + + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + RADEONInitTVRegisters (pScrn, &info->SavedReg, save, + ((RADEONMergedDisplayModePtr)mode->Private)->CRT1, + &info->pll, info); + } + if (!RADEONInitCrtcRegisters(pScrn, save, ((RADEONMergedDisplayModePtr)mode->Private)->CRT1, info)) return FALSE; dot_clock = (((RADEONMergedDisplayModePtr)mode->Private)->CRT1)->Clock / 1000.0; - if (dot_clock) { + if ((info->DisplayType == MT_STV) || + (info->DisplayType == MT_CTV)) { + /* Don't do any thing here, it will be handled in + * InitTV function + */ + } else if (dot_clock) { RADEONInitPLLRegisters(info, save, &info->pll, dot_clock); } else { save->ppll_ref_div = info->SavedReg.ppll_ref_div; @@ -7762,12 +8992,30 @@ RADEONInitCrtc2Registers(pScrn, save, ((RADEONMergedDisplayModePtr)mode->Private)->CRT2, info); dot_clock = (((RADEONMergedDisplayModePtr)mode->Private)->CRT2)->Clock / 1000.0; - RADEONInitPLL2Registers(save, &info->pll, dot_clock, info->MergeType != MT_CRT); + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + RADEONInitTVRegisters (pScrn, &info->SavedReg, save, + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2, + &info->pll, info); + } else { + RADEONInitPLL2Registers(save, &info->pll, + dot_clock, info->MergeType != MT_CRT); + } } else { + + if ((info->DisplayType == MT_STV) || (info->DisplayType == MT_CTV)) { + RADEONInitTVRegisters (pScrn, &info->SavedReg, save, mode, + &info->pll, info); + } + if (!RADEONInitCrtcRegisters(pScrn, save, mode, info)) return FALSE; dot_clock = mode->Clock/1000.0; - if (dot_clock) { + if ((info->DisplayType == MT_STV) || + (info->DisplayType == MT_CTV)) { + /* Don't do any thing here, it will be handled in + * InitTV function + */ + } else if (dot_clock) { RADEONInitPLLRegisters(info, save, &info->pll, dot_clock); } else { save->ppll_ref_div = info->SavedReg.ppll_ref_div; @@ -8555,6 +9803,11 @@ } } + if ((info->MergeType == MT_STV) || (info->MergeType == MT_CTV)) { + if (!RADEONGetTVInfo (pScrn)) + info->MergedFB = FALSE; + } + /* Do some MergedFB mode initialisation */ if(info->MergedFB) { info->CRT2pScrn = xalloc(sizeof(ScrnInfoRec)); Index: radeon_reg.h =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v retrieving revision 1.15 diff -u -r1.15 radeon_reg.h --- radeon_reg.h 26 Jan 2005 18:23:41 -0000 1.15 +++ radeon_reg.h 9 Apr 2005 14:45:12 -0000 @@ -418,6 +418,7 @@ # define RADEON_DAC_CMP_EN (1 << 3) # define RADEON_DAC_CMP_OUTPUT (1 << 7) # define RADEON_DAC_8BIT_EN (1 << 8) +# define RADEON_DAC_TVO_EN (1 << 10) # define RADEON_DAC_VGA_ADR_EN (1 << 13) # define RADEON_DAC_PDWN (1 << 15) # define RADEON_DAC_MASK_ALL (0xff << 24) @@ -436,8 +437,14 @@ # define RADEON_DAC_PDWN_G (1 << 17) # define RADEON_DAC_PDWN_B (1 << 18) #define RADEON_TV_DAC_CNTL 0x088c -# define RADEON_TV_DAC_STD_MASK 0x0300 +# define RADEON_TV_DAC_BLANK (1 << 0) +# define RADEON_TV_DAC_HOLD (1 << 1) +# define RADEON_TV_DAC_PEDESTAL (1 << 2) +# define RADEON_TV_MONITOR_DETECT_EN (1 << 4) +# define RADEON_TV_DAC_CMPOUT (1 << 5) # define RADEON_TV_DAC_BGSLEEP (1 << 6) +# define RADEON_TV_DAC_STD_MASK 0x0300 +# define RADEON_TV_DAC_STD_NTSC (1 << 8) # define RADEON_TV_DAC_RDACPD (1 << 24) # define RADEON_TV_DAC_GDACPD (1 << 25) # define RADEON_TV_DAC_BDACPD (1 << 26) @@ -448,6 +455,12 @@ # define RADEON_DISP_DAC2_SOURCE_MASK 0x0c # define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 # define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 +# define RADEON_DISP_TV_SOURCE_CRTC (1 << 16) /* crtc1 or crtc2 */ +# define RADEON_DISP_TV_SOURCE_LTU (0 << 16) /* linear transform unit */ +#define RADEON_DISP_TV_OUT_CNTL 0x0d6c +# define RADEON_DISP_TV_PATH_SRC_CRTC2 (1 << 16) +# define RADEON_DISP_TV_PATH_SRC_CRTC1 (0 << 16) + #define RADEON_DAC_CRC_SIG 0x02cc #define RADEON_DAC_DATA 0x03c9 /* VGA */ #define RADEON_DAC_MASK 0x03c6 /* VGA */ @@ -1372,6 +1385,9 @@ #define RADEON_VIPH_CH2_ABCNT 0x0c38 #define RADEON_VIPH_CH3_ABCNT 0x0c3c #define RADEON_VIPH_CONTROL 0x0c40 +# define RADEON_VIP_BUSY 0 +# define RADEON_VIP_IDLE 1 +# define RADEON_VIP_RESET 2 #define RADEON_VIPH_DV_LAT 0x0c44 #define RADEON_VIPH_BM_CHUNK 0x0c48 #define RADEON_VIPH_DV_INT 0x0c4c @@ -2897,16 +2913,76 @@ #define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR 51 #define RADEON_SS_SHININESS 60 -#define RADEON_TV_MASTER_CNTL 0x0800 +#define RADEON_TV_MASTER_CNTL 0x0800 +# define RADEON_TV_ASYNC_RST (1 << 0) +# define RADEON_CRT_ASYNC_RST (1 << 1) +# define RADEON_RESTART_PHASE_FIX (1 << 3) +# define RADEON_CRT_FIFO_CE_EN (1 << 9) +# define RADEON_TV_FIFO_CE_EN (1 << 10) # define RADEON_TVCLK_ALWAYS_ONb (1 << 30) -#define RADEON_TV_DAC_CNTL 0x088c -# define RADEON_TV_DAC_CMPOUT (1 << 5) -#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 -# define RADEON_Y_RED_EN (1 << 0) -# define RADEON_C_GRN_EN (1 << 1) -# define RADEON_CMP_BLU_EN (1 << 2) -# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) -# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) +#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 +# define RADEON_Y_RED_EN (1 << 0) +# define RADEON_C_GRN_EN (1 << 1) +# define RADEON_CMP_BLU_EN (1 << 2) +# define RADEON_DAC_DITHER_EN (1 << 3) +# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) +# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) # define RADEON_BLU_MX_FORCE_DAC_DATA (6 << 12) # define RADEON_TV_FORCE_DAC_DATA_SHIFT 16 +#define RADEON_TV_RGB_CNTL 0x0804 +# define RADEON_SWITCH_TO_BLUE (1 << 4) +# define RADEON_RGB_DITHER_EN (1 << 5) +# define RADEON_RGB_SRC_SEL_MASK (3 << 8) +# define RADEON_RGB_SRC_SEL_CRTC1 (0 << 8) +# define RADEON_RGB_SRC_SEL_RMX (1 << 8) +# define RADEON_RGB_SRC_SEL_CRTC2 (2 << 8) +# define RADEON_RGB_CONVERT_BY_PASS (1 << 10) +#define RADEON_TV_SYNC_CNTL 0x0808 +#define RADEON_TV_HTOTAL 0x080c +#define RADEON_TV_HDISP 0x0810 +#define RADEON_TV_HSTART 0x0818 +#define RADEON_TV_HCOUNT 0x081C +#define RADEON_TV_VTOTAL 0x0820 +#define RADEON_TV_VDISP 0x0824 +#define RADEON_TV_VCOUNT 0x0828 +#define RADEON_TV_FTOTAL 0x082c +#define RADEON_TV_FCOUNT 0x0830 +#define RADEON_TV_FRESTART 0x0834 +#define RADEON_TV_HRESTART 0x0838 +#define RADEON_TV_VRESTART 0x083c +#define RADEON_TV_HOST_READ_DATA 0x0840 +#define RADEON_TV_HOST_WRITE_DATA 0x0844 +#define RADEON_TV_HOST_RD_WT_CNTL 0x0848 +#define RADEON_TV_VSCALER_CNTL1 0x084c +# define RADEON_RESTART_FIELD (1 << 29) /* restart on field 0 */ +# define RADEON_Y_DEL_W_SIG_SHIFT 26 +#define RADEON_TV_TIMING_CNTL 0x0850 +#define RADEON_TV_VSCALER_CNTL2 0x0854 +# define RADEON_DITHER_MODE (1 << 0) +# define RADEON_Y_OUTPUT_DITHER_EN (1 << 1) +# define RADEON_UV_OUTPUT_DITHER_EN (1 << 2) +# define RADEON_UV_TO_BUF_DITHER_EN (1 << 3) +#define RADEON_TV_Y_FALL_CNTL 0x0858 +# define RADEON_Y_FALL_PING_PONG (1 << 16) +#define RADEON_TV_Y_RISE_CNTL 0x085c +# define RADEON_Y_RISE_PING_PONG (1 << 16) +#define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860 +#define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864 +#define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868 +#define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c +#define RADEON_TV_MODULATOR_CNTL1 0x0870 +# define RADEON_ALT_PHASE_EN (1 << 6) +# define RADEON_SYNC_TIP_LEVEL (1 << 7) +#define RADEON_TV_MODULATOR_CNTL2 0x0874 +#define RADEON_TV_CRC_CNTL 0x0890 +#define RADEON_TV_UV_ADR 0x08ac +#define RADEON_TV_PLL_FINE_CNTL 0x0020 /* PLL */ +#define RADEON_TV_PLL_CNTL 0x0021 /* PLL */ +# define RADEON_TV_SLIP_EN (1 << 23) +# define RADEON_TV_DTO_EN (1 << 28) +#define RADEON_TV_PLL_CNTL1 0x0022 /* PLL */ +# define RADEON_TVPLL_TEST_DIS (1 << 31) +# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) +# define RADEON_TVPLL_SLEEP (1 << 3) +# define RADEON_TVPLL_REFCLK_SEL (1 << 4) #endif