drm/radeon/kms: add new pll algo for avivo asics
Based on the vbios code. This should hopefully fix the pll problems on a number of avivo asics once it's enabled. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Cc: stable@kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
		
							parent
							
								
									51d4bf840a
								
							
						
					
					
						commit
						f523f74eac
					
				| @ -951,8 +951,8 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | ||||
| 	/* adjust pixel clock as needed */ | ||||
| 	adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); | ||||
| 
 | ||||
| 	radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||||
| 			   &ref_div, &post_div); | ||||
| 	radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||||
| 				  &ref_div, &post_div); | ||||
| 
 | ||||
| 	atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); | ||||
| 
 | ||||
|  | ||||
| @ -780,6 +780,115 @@ static int radeon_ddc_dump(struct drm_connector *connector) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* avivo */ | ||||
| static void avivo_get_fb_div(struct radeon_pll *pll, | ||||
| 			     u32 target_clock, | ||||
| 			     u32 post_div, | ||||
| 			     u32 ref_div, | ||||
| 			     u32 *fb_div, | ||||
| 			     u32 *frac_fb_div) | ||||
| { | ||||
| 	u32 tmp = post_div * ref_div; | ||||
| 
 | ||||
| 	tmp *= target_clock; | ||||
| 	*fb_div = tmp / pll->reference_freq; | ||||
| 	*frac_fb_div = tmp % pll->reference_freq; | ||||
| } | ||||
| 
 | ||||
| static u32 avivo_get_post_div(struct radeon_pll *pll, | ||||
| 			      u32 target_clock) | ||||
| { | ||||
| 	u32 vco, post_div, tmp; | ||||
| 
 | ||||
| 	if (pll->flags & RADEON_PLL_USE_POST_DIV) | ||||
| 		return pll->post_div; | ||||
| 
 | ||||
| 	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { | ||||
| 		if (pll->flags & RADEON_PLL_IS_LCD) | ||||
| 			vco = pll->lcd_pll_out_min; | ||||
| 		else | ||||
| 			vco = pll->pll_out_min; | ||||
| 	} else { | ||||
| 		if (pll->flags & RADEON_PLL_IS_LCD) | ||||
| 			vco = pll->lcd_pll_out_max; | ||||
| 		else | ||||
| 			vco = pll->pll_out_max; | ||||
| 	} | ||||
| 
 | ||||
| 	post_div = vco / target_clock; | ||||
| 	tmp = vco % target_clock; | ||||
| 
 | ||||
| 	if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { | ||||
| 		if (tmp) | ||||
| 			post_div++; | ||||
| 	} else { | ||||
| 		if (!tmp) | ||||
| 			post_div--; | ||||
| 	} | ||||
| 
 | ||||
| 	return post_div; | ||||
| } | ||||
| 
 | ||||
| #define MAX_TOLERANCE 10 | ||||
| 
 | ||||
| void radeon_compute_pll_avivo(struct radeon_pll *pll, | ||||
| 			      u32 freq, | ||||
| 			      u32 *dot_clock_p, | ||||
| 			      u32 *fb_div_p, | ||||
| 			      u32 *frac_fb_div_p, | ||||
| 			      u32 *ref_div_p, | ||||
| 			      u32 *post_div_p) | ||||
| { | ||||
| 	u32 target_clock = freq / 10; | ||||
| 	u32 post_div = avivo_get_post_div(pll, target_clock); | ||||
| 	u32 ref_div = pll->min_ref_div; | ||||
| 	u32 fb_div = 0, frac_fb_div = 0, tmp; | ||||
| 
 | ||||
| 	if (pll->flags & RADEON_PLL_USE_REF_DIV) | ||||
| 		ref_div = pll->reference_div; | ||||
| 
 | ||||
| 	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { | ||||
| 		avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); | ||||
| 		frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; | ||||
| 		if (frac_fb_div >= 5) { | ||||
| 			frac_fb_div -= 5; | ||||
| 			frac_fb_div = frac_fb_div / 10; | ||||
| 			frac_fb_div++; | ||||
| 		} | ||||
| 		if (frac_fb_div >= 10) { | ||||
| 			fb_div++; | ||||
| 			frac_fb_div = 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		while (ref_div <= pll->max_ref_div) { | ||||
| 			avivo_get_fb_div(pll, target_clock, post_div, ref_div, | ||||
| 					 &fb_div, &frac_fb_div); | ||||
| 			if (frac_fb_div >= (pll->reference_freq / 2)) | ||||
| 				fb_div++; | ||||
| 			frac_fb_div = 0; | ||||
| 			tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); | ||||
| 			tmp = (tmp * 10000) / target_clock; | ||||
| 
 | ||||
| 			if (tmp > (10000 + MAX_TOLERANCE)) | ||||
| 				ref_div++; | ||||
| 			else if (tmp >= (10000 - MAX_TOLERANCE)) | ||||
| 				break; | ||||
| 			else | ||||
| 				ref_div++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	*dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / | ||||
| 		(ref_div * post_div * 10); | ||||
| 	*fb_div_p = fb_div; | ||||
| 	*frac_fb_div_p = frac_fb_div; | ||||
| 	*ref_div_p = ref_div; | ||||
| 	*post_div_p = post_div; | ||||
| 	DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n", | ||||
| 		      *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div); | ||||
| } | ||||
| 
 | ||||
| /* pre-avivo */ | ||||
| static inline uint32_t radeon_div(uint64_t n, uint32_t d) | ||||
| { | ||||
| 	uint64_t mod; | ||||
| @ -790,13 +899,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d) | ||||
| 	return n; | ||||
| } | ||||
| 
 | ||||
| void radeon_compute_pll(struct radeon_pll *pll, | ||||
| 			uint64_t freq, | ||||
| 			uint32_t *dot_clock_p, | ||||
| 			uint32_t *fb_div_p, | ||||
| 			uint32_t *frac_fb_div_p, | ||||
| 			uint32_t *ref_div_p, | ||||
| 			uint32_t *post_div_p) | ||||
| void radeon_compute_pll_legacy(struct radeon_pll *pll, | ||||
| 			       uint64_t freq, | ||||
| 			       uint32_t *dot_clock_p, | ||||
| 			       uint32_t *fb_div_p, | ||||
| 			       uint32_t *frac_fb_div_p, | ||||
| 			       uint32_t *ref_div_p, | ||||
| 			       uint32_t *post_div_p) | ||||
| { | ||||
| 	uint32_t min_ref_div = pll->min_ref_div; | ||||
| 	uint32_t max_ref_div = pll->max_ref_div; | ||||
|  | ||||
| @ -778,9 +778,9 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | ||||
| 	DRM_DEBUG_KMS("\n"); | ||||
| 
 | ||||
| 	if (!use_bios_divs) { | ||||
| 		radeon_compute_pll(pll, mode->clock, | ||||
| 				   &freq, &feedback_div, &frac_fb_div, | ||||
| 				   &reference_div, &post_divider); | ||||
| 		radeon_compute_pll_legacy(pll, mode->clock, | ||||
| 					  &freq, &feedback_div, &frac_fb_div, | ||||
| 					  &reference_div, &post_divider); | ||||
| 
 | ||||
| 		for (post_div = &post_divs[0]; post_div->divider; ++post_div) { | ||||
| 			if (post_div->divider == post_divider) | ||||
|  | ||||
| @ -149,6 +149,7 @@ struct radeon_tmds_pll { | ||||
| #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) | ||||
| #define RADEON_PLL_USE_POST_DIV         (1 << 12) | ||||
| #define RADEON_PLL_IS_LCD               (1 << 13) | ||||
| #define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14) | ||||
| 
 | ||||
| struct radeon_pll { | ||||
| 	/* reference frequency */ | ||||
| @ -510,13 +511,21 @@ extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, | ||||
| 					     struct radeon_atom_ss *ss, | ||||
| 					     int id, u32 clock); | ||||
| 
 | ||||
| extern void radeon_compute_pll(struct radeon_pll *pll, | ||||
| 			       uint64_t freq, | ||||
| 			       uint32_t *dot_clock_p, | ||||
| 			       uint32_t *fb_div_p, | ||||
| 			       uint32_t *frac_fb_div_p, | ||||
| 			       uint32_t *ref_div_p, | ||||
| 			       uint32_t *post_div_p); | ||||
| extern void radeon_compute_pll_legacy(struct radeon_pll *pll, | ||||
| 				      uint64_t freq, | ||||
| 				      uint32_t *dot_clock_p, | ||||
| 				      uint32_t *fb_div_p, | ||||
| 				      uint32_t *frac_fb_div_p, | ||||
| 				      uint32_t *ref_div_p, | ||||
| 				      uint32_t *post_div_p); | ||||
| 
 | ||||
| extern void radeon_compute_pll_avivo(struct radeon_pll *pll, | ||||
| 				     u32 freq, | ||||
| 				     u32 *dot_clock_p, | ||||
| 				     u32 *fb_div_p, | ||||
| 				     u32 *frac_fb_div_p, | ||||
| 				     u32 *ref_div_p, | ||||
| 				     u32 *post_div_p); | ||||
| 
 | ||||
| extern void radeon_setup_encoder_clones(struct drm_device *dev); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user