⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pll.c

📁 ati driver
💻 C
📖 第 1 页 / 共 2 页
字号:
					//	rel_error = abs_crt_error / crt_freq					// now to absolute TV clock error per second:					//	abs_tv_error = rel_error * tv_freq					// and finally to TV clock error per frame:					//	frame_rate_drift = abs_tv_error / frame_rate					//	                 = abs_crt_error / crt_freq * tv_freq / frame_rate					// this can be simplified by using:					//	tv_freq = pix_per_tv_frame * frame_rate					// so we get:					//	frame_rate_drift = abs_crt_error / crt_freq * pix_per_tv_frame * frame_rate / frame_rate					//	                 = abs_crt_error / crt_freq * pix_per_tv_frame					frame_rate_drift = (uint64)abs_crt_error * pix_per_tv_frame / freq;							// if drift is within threshold, we take this setting and stop					// searching (later iteration will increasingly tweak screen size,					// and we don't really want that)					if( frame_rate_drift <= max_frame_rate_drift ) {						SHOW_INFO( 2, "frame_rate_drift=%d, crt_freq=%d, v_total=%d, h_total=%d", 							frame_rate_drift, crt_freq, v_total, h_total );												tweaked_mode->timing.pixel_clock = crt_freq;						tweaked_mode->timing.v_total = v_total;						tweaked_mode->timing.h_total = h_total;						return;					}				}			}		}    }}// table to map divider to register valuestatic pll_divider_map post_divs[] = {	{  1, 0 },	{  2, 1 },	{  4, 2 },	{  8, 3 },	{  3, 4 },//	{ 16, 5 },	// at least for pll2 of M6, this value is reserved	{  6, 6 },	{ 12, 7 },	{  0, 0 }};// normal PLLs have no extra post dividerstatic pll_divider_map extra_post_divs[] = {	{ 1, 1 },	{ 0, 0 }};// extra post-divider provided by Rage Theatrestatic pll_divider_map external_extra_post_divs[] = {	{ 1, 0 },	{ 2, 1 },	{ 0, 0 }};// post-dividers of Rage Theatrestatic pll_divider_map tv_post_divs[] = {	{  1, 1 },	{  2, 2 },	{  3, 3 },	{  4, 4 },	{  5, 5 },	{  6, 6 },	{  7, 7 },	{  8, 8 },	{  9, 9 },	{ 10, 10 },	{ 11, 11 },	{ 12, 12 },	{ 13, 13 },	{ 14, 14 },	{ 15, 15 },	{  0, 0 }};// get PLL parameters of TV PLLvoid Radeon_GetTVPLLConfiguration( const general_pll_info *general_pll, pll_info *pll, 	bool internal_encoder ){	pll->post_divs = tv_post_divs;	pll->extra_post_divs = internal_encoder ? extra_post_divs : external_extra_post_divs;	pll->ref_freq = general_pll->ref_freq;	pll->vco_min = 10000;	pll->vco_max = 25000;	// I'm not sure about the upper limit	pll->min_ref_div = 4;	pll->max_ref_div = 0x3ff;	// in the original code, they set it to 330kHz if PAL is requested and	// quartz is 27 MHz, but I don't see how these circumstances can effect the	// mimimal PLL input frequency	pll->pll_in_min = 20;//40;	// in the original code, they don't define an upper limit	pll->pll_in_max = 100;	pll->extra_feedback_div = 1;	pll->min_feedback_div = 4;	pll->max_feedback_div = 0x7ff;	pll->best_vco = 21000;}// get PLL parameters of CRT PLL used in conjunction with TV-outvoid Radeon_GetTVCRTPLLConfiguration( const general_pll_info *general_pll, pll_info *pll,	bool internal_tv_encoder ){	pll->post_divs = post_divs;	pll->extra_post_divs = extra_post_divs;	pll->ref_freq = general_pll->ref_freq;		// in sample code, these limits are set in a strange way;	// as a first shot, I use the BIOS provided limits	/*pll->vco_min = general_pll->min_pll_freq;	pll->vco_max = general_pll->max_pll_freq;*/		// in sample code, they use a variable post divider during calculation, but	// use a fixed post divider for programming - the variable post divider is	// multiplied to the feedback divider; 	// because of the fixed post divider (3), the VCO always runs far out of 	// its stable frequency range, so we have hack the limits	pll->vco_min = 4000;	pll->vco_max = general_pll->max_pll_freq;	// in sample code, lower limit is 4, but in register spec they say everything but 0/1	pll->min_ref_div = 2;	pll->max_ref_div = 0x3ff;	pll->pll_in_min = 20;	pll->pll_in_max = 100;	pll->extra_feedback_div = 1;	pll->min_feedback_div = 4;	pll->max_feedback_div = 0x7ff;	pll->best_vco = internal_tv_encoder ? 17500 : 21000;}// calc PLL dividers for CRT// mode->timing.pixel_clock must be in Hz because required accuracy in TV-Out modevoid Radeon_CalcCRTPLLDividers( 	const general_pll_info *general_pll, const display_mode *mode, pll_dividers *dividers ){	pll_info pll;			pll.post_divs = post_divs;	pll.extra_post_divs = extra_post_divs;	pll.ref_freq = general_pll->ref_freq;	pll.vco_min = general_pll->min_pll_freq;	pll.vco_max = general_pll->max_pll_freq;	pll.min_ref_div = 2;	pll.max_ref_div = 0x3ff;	pll.pll_in_min = 40;	pll.pll_in_max = 100;	pll.extra_feedback_div = 1;	pll.min_feedback_div = 4;	pll.max_feedback_div = 0x7ff;	pll.best_vco = 0;	SHOW_FLOW( 2, "freq=%ld", mode->timing.pixel_clock );	Radeon_CalcPLLDividers( &pll, mode->timing.pixel_clock, 0, dividers );}// calculate PLL registers // mode->timing.pixel_clock must be in Hz because required accuracy in TV-Out mode// (old: freq is in 10kHz)void Radeon_CalcPLLRegisters( 	const display_mode *mode, const pll_dividers *dividers, pll_regs *values ){	values->dot_clock_freq = dividers->freq;	values->feedback_div   = dividers->feedback;	values->post_div       = dividers->post;	values->pll_output_freq = dividers->freq * dividers->post;		values->ppll_ref_div   = dividers->ref;	values->ppll_div_3     = (dividers->feedback | (dividers->post_code << 16));	// this is mad: the PLL controls the horizontal length in sub-byte precision!	values->htotal_cntl    = mode->timing.h_total & 7;	SHOW_FLOW( 2, "dot_clock_freq=%ld, pll_output_freq=%ld, ref_div=%d, feedback_div=%d, post_div=%d",		values->dot_clock_freq, values->pll_output_freq,		values->ppll_ref_div, values->feedback_div, values->post_div );}// write values into PLL registersvoid Radeon_ProgramPLL( 	accelerator_info *ai, int crtc_idx, pll_regs *values ){	vuint8 *regs = ai->regs;	radeon_type asic = ai->si->asic;		SHOW_FLOW0( 2, "" );		// use some other PLL for pixel clock source to not fiddling with PLL	// while somebody is using it    Radeon_OUTPLLP( regs, asic, crtc_idx == 0 ? RADEON_VCLK_ECP_CNTL : RADEON_PIXCLKS_CNTL,     	RADEON_VCLK_SRC_CPU_CLK, ~RADEON_VCLK_SRC_SEL_MASK );    Radeon_OUTPLLP( regs, asic,		crtc_idx == 0 ? RADEON_PPLL_CNTL : RADEON_P2PLL_CNTL,	    RADEON_PPLL_RESET	    | RADEON_PPLL_ATOMIC_UPDATE_EN	    | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN,	    ~(RADEON_PPLL_RESET		| RADEON_PPLL_ATOMIC_UPDATE_EN		| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN) );			// select divider 3 (well, only required for first PLL)    OUTREGP( regs, RADEON_CLOCK_CNTL_INDEX,	    RADEON_PLL_DIV_SEL_DIV3,	    ~RADEON_PLL_DIV_SEL_MASK );	if( ai->si->new_pll && crtc_idx == 0 ) {		// starting with r300, the reference divider of the first PLL was 		// moved to another bit position; at the old location, you only 		// find the "BIOS suggested divider"; no clue why they did that		Radeon_OUTPLLP( regs, asic,    		RADEON_PPLL_REF_DIV,     		values->ppll_ref_div << RADEON_PPLL_REF_DIV_ACC_SHIFT,     		~RADEON_PPLL_REF_DIV_ACC_MASK );	} else {	    Radeon_OUTPLLP( regs, asic,    		crtc_idx == 0 ? RADEON_PPLL_REF_DIV : RADEON_P2PLL_REF_DIV,     		values->ppll_ref_div,     		~RADEON_PPLL_REF_DIV_MASK );    }        Radeon_OUTPLLP( regs, asic,    	crtc_idx == 0 ? RADEON_PPLL_DIV_3 : RADEON_P2PLL_DIV_0,     	values->ppll_div_3,     	~RADEON_PPLL_FB3_DIV_MASK );    Radeon_OUTPLLP( regs, asic,    	crtc_idx == 0 ? RADEON_PPLL_DIV_3 : RADEON_P2PLL_DIV_0,     	values->ppll_div_3,     	~RADEON_PPLL_POST3_DIV_MASK );    Radeon_PLLWriteUpdate( ai, crtc_idx );    Radeon_PLLWaitForReadUpdateComplete( ai, crtc_idx );        Radeon_OUTPLL( regs, asic,    	crtc_idx == 0 ? RADEON_HTOTAL_CNTL : RADEON_HTOTAL2_CNTL,     	values->htotal_cntl );	Radeon_OUTPLLP( regs, asic, 		crtc_idx == 0 ? RADEON_PPLL_CNTL : RADEON_P2PLL_CNTL, 0, 		~(RADEON_PPLL_RESET		| RADEON_PPLL_SLEEP		| RADEON_PPLL_ATOMIC_UPDATE_EN		| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN) );	// there is no way to check whether PLL has settled, so wait a bit	snooze( 5000 );	// use PLL for pixel clock again    Radeon_OUTPLLP( regs, asic,    	crtc_idx == 0 ? RADEON_VCLK_ECP_CNTL : RADEON_PIXCLKS_CNTL,     	RADEON_VCLK_SRC_PPLL_CLK, ~RADEON_VCLK_SRC_SEL_MASK );}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -