mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	drm/i915: Move SKL/KLB pll selection logic to intel_dpll_mgr.c
Move the code for selecting plls for SKL/KLB into the shared dpll code, so that the platform specific details are hidden behind that interface. Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1457451987-17466-11-git-send-email-ander.conselvan.de.oliveira@intel.com
This commit is contained in:
		
							parent
							
								
									daedf20a4f
								
							
						
					
					
						commit
						304b65cbdc
					
				| @ -1005,311 +1005,15 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct skl_wrpll_context { | ||||
| 	uint64_t min_deviation;		/* current minimal deviation */ | ||||
| 	uint64_t central_freq;		/* chosen central freq */ | ||||
| 	uint64_t dco_freq;		/* chosen dco freq */ | ||||
| 	unsigned int p;			/* chosen divider */ | ||||
| }; | ||||
| 
 | ||||
| static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) | ||||
| { | ||||
| 	memset(ctx, 0, sizeof(*ctx)); | ||||
| 
 | ||||
| 	ctx->min_deviation = U64_MAX; | ||||
| } | ||||
| 
 | ||||
| /* DCO freq must be within +1%/-6%  of the DCO central freq */ | ||||
| #define SKL_DCO_MAX_PDEVIATION	100 | ||||
| #define SKL_DCO_MAX_NDEVIATION	600 | ||||
| 
 | ||||
| static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, | ||||
| 				  uint64_t central_freq, | ||||
| 				  uint64_t dco_freq, | ||||
| 				  unsigned int divider) | ||||
| { | ||||
| 	uint64_t deviation; | ||||
| 
 | ||||
| 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq), | ||||
| 			      central_freq); | ||||
| 
 | ||||
| 	/* positive deviation */ | ||||
| 	if (dco_freq >= central_freq) { | ||||
| 		if (deviation < SKL_DCO_MAX_PDEVIATION && | ||||
| 		    deviation < ctx->min_deviation) { | ||||
| 			ctx->min_deviation = deviation; | ||||
| 			ctx->central_freq = central_freq; | ||||
| 			ctx->dco_freq = dco_freq; | ||||
| 			ctx->p = divider; | ||||
| 		} | ||||
| 	/* negative deviation */ | ||||
| 	} else if (deviation < SKL_DCO_MAX_NDEVIATION && | ||||
| 		   deviation < ctx->min_deviation) { | ||||
| 		ctx->min_deviation = deviation; | ||||
| 		ctx->central_freq = central_freq; | ||||
| 		ctx->dco_freq = dco_freq; | ||||
| 		ctx->p = divider; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void skl_wrpll_get_multipliers(unsigned int p, | ||||
| 				      unsigned int *p0 /* out */, | ||||
| 				      unsigned int *p1 /* out */, | ||||
| 				      unsigned int *p2 /* out */) | ||||
| { | ||||
| 	/* even dividers */ | ||||
| 	if (p % 2 == 0) { | ||||
| 		unsigned int half = p / 2; | ||||
| 
 | ||||
| 		if (half == 1 || half == 2 || half == 3 || half == 5) { | ||||
| 			*p0 = 2; | ||||
| 			*p1 = 1; | ||||
| 			*p2 = half; | ||||
| 		} else if (half % 2 == 0) { | ||||
| 			*p0 = 2; | ||||
| 			*p1 = half / 2; | ||||
| 			*p2 = 2; | ||||
| 		} else if (half % 3 == 0) { | ||||
| 			*p0 = 3; | ||||
| 			*p1 = half / 3; | ||||
| 			*p2 = 2; | ||||
| 		} else if (half % 7 == 0) { | ||||
| 			*p0 = 7; | ||||
| 			*p1 = half / 7; | ||||
| 			*p2 = 2; | ||||
| 		} | ||||
| 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */ | ||||
| 		*p0 = 3; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = p / 3; | ||||
| 	} else if (p == 5 || p == 7) { | ||||
| 		*p0 = p; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 1; | ||||
| 	} else if (p == 15) { | ||||
| 		*p0 = 3; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 5; | ||||
| 	} else if (p == 21) { | ||||
| 		*p0 = 7; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 3; | ||||
| 	} else if (p == 35) { | ||||
| 		*p0 = 7; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 5; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct skl_wrpll_params { | ||||
| 	uint32_t        dco_fraction; | ||||
| 	uint32_t        dco_integer; | ||||
| 	uint32_t        qdiv_ratio; | ||||
| 	uint32_t        qdiv_mode; | ||||
| 	uint32_t        kdiv; | ||||
| 	uint32_t        pdiv; | ||||
| 	uint32_t        central_freq; | ||||
| }; | ||||
| 
 | ||||
| static void skl_wrpll_params_populate(struct skl_wrpll_params *params, | ||||
| 				      uint64_t afe_clock, | ||||
| 				      uint64_t central_freq, | ||||
| 				      uint32_t p0, uint32_t p1, uint32_t p2) | ||||
| { | ||||
| 	uint64_t dco_freq; | ||||
| 
 | ||||
| 	switch (central_freq) { | ||||
| 	case 9600000000ULL: | ||||
| 		params->central_freq = 0; | ||||
| 		break; | ||||
| 	case 9000000000ULL: | ||||
| 		params->central_freq = 1; | ||||
| 		break; | ||||
| 	case 8400000000ULL: | ||||
| 		params->central_freq = 3; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (p0) { | ||||
| 	case 1: | ||||
| 		params->pdiv = 0; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		params->pdiv = 1; | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		params->pdiv = 2; | ||||
| 		break; | ||||
| 	case 7: | ||||
| 		params->pdiv = 4; | ||||
| 		break; | ||||
| 	default: | ||||
| 		WARN(1, "Incorrect PDiv\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	switch (p2) { | ||||
| 	case 5: | ||||
| 		params->kdiv = 0; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		params->kdiv = 1; | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		params->kdiv = 2; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		params->kdiv = 3; | ||||
| 		break; | ||||
| 	default: | ||||
| 		WARN(1, "Incorrect KDiv\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	params->qdiv_ratio = p1; | ||||
| 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1; | ||||
| 
 | ||||
| 	dco_freq = p0 * p1 * p2 * afe_clock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Intermediate values are in Hz. | ||||
| 	 * Divide by MHz to match bsepc | ||||
| 	 */ | ||||
| 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1)); | ||||
| 	params->dco_fraction = | ||||
| 		div_u64((div_u64(dco_freq, 24) - | ||||
| 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1)); | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| skl_ddi_calculate_wrpll(int clock /* in Hz */, | ||||
| 			struct skl_wrpll_params *wrpll_params) | ||||
| { | ||||
| 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ | ||||
| 	uint64_t dco_central_freq[3] = {8400000000ULL, | ||||
| 					9000000000ULL, | ||||
| 					9600000000ULL}; | ||||
| 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20, | ||||
| 					     24, 28, 30, 32, 36, 40, 42, 44, | ||||
| 					     48, 52, 54, 56, 60, 64, 66, 68, | ||||
| 					     70, 72, 76, 78, 80, 84, 88, 90, | ||||
| 					     92, 96, 98 }; | ||||
| 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; | ||||
| 	static const struct { | ||||
| 		const int *list; | ||||
| 		int n_dividers; | ||||
| 	} dividers[] = { | ||||
| 		{ even_dividers, ARRAY_SIZE(even_dividers) }, | ||||
| 		{ odd_dividers, ARRAY_SIZE(odd_dividers) }, | ||||
| 	}; | ||||
| 	struct skl_wrpll_context ctx; | ||||
| 	unsigned int dco, d, i; | ||||
| 	unsigned int p0, p1, p2; | ||||
| 
 | ||||
| 	skl_wrpll_context_init(&ctx); | ||||
| 
 | ||||
| 	for (d = 0; d < ARRAY_SIZE(dividers); d++) { | ||||
| 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { | ||||
| 			for (i = 0; i < dividers[d].n_dividers; i++) { | ||||
| 				unsigned int p = dividers[d].list[i]; | ||||
| 				uint64_t dco_freq = p * afe_clock; | ||||
| 
 | ||||
| 				skl_wrpll_try_divider(&ctx, | ||||
| 						      dco_central_freq[dco], | ||||
| 						      dco_freq, | ||||
| 						      p); | ||||
| 				/*
 | ||||
| 				 * Skip the remaining dividers if we're sure to | ||||
| 				 * have found the definitive divider, we can't | ||||
| 				 * improve a 0 deviation. | ||||
| 				 */ | ||||
| 				if (ctx.min_deviation == 0) | ||||
| 					goto skip_remaining_dividers; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| skip_remaining_dividers: | ||||
| 		/*
 | ||||
| 		 * If a solution is found with an even divider, prefer | ||||
| 		 * this one. | ||||
| 		 */ | ||||
| 		if (d == 0 && ctx.p) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ctx.p) { | ||||
| 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * gcc incorrectly analyses that these can be used without being | ||||
| 	 * initialized. To be fair, it's hard to guess. | ||||
| 	 */ | ||||
| 	p0 = p1 = p2 = 0; | ||||
| 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2); | ||||
| 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq, | ||||
| 				  p0, p1, p2); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| skl_ddi_pll_select(struct intel_crtc *intel_crtc, | ||||
| 		   struct intel_crtc_state *crtc_state, | ||||
| 		   struct intel_encoder *intel_encoder) | ||||
| { | ||||
| 	struct intel_shared_dpll *pll; | ||||
| 	uint32_t ctrl1, cfgcr1, cfgcr2; | ||||
| 	int clock = crtc_state->port_clock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * See comment in intel_dpll_hw_state to understand why we always use 0 | ||||
| 	 * as the DPLL id in this function. | ||||
| 	 */ | ||||
| 
 | ||||
| 	ctrl1 = DPLL_CTRL1_OVERRIDE(0); | ||||
| 
 | ||||
| 	if (intel_encoder->type == INTEL_OUTPUT_HDMI) { | ||||
| 		struct skl_wrpll_params wrpll_params = { 0, }; | ||||
| 
 | ||||
| 		ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); | ||||
| 
 | ||||
| 		if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) | ||||
| 			return false; | ||||
| 
 | ||||
| 		cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | | ||||
| 			 DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | | ||||
| 			 wrpll_params.dco_integer; | ||||
| 
 | ||||
| 		cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) | | ||||
| 			 DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) | | ||||
| 			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | | ||||
| 			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | | ||||
| 			 wrpll_params.central_freq; | ||||
| 	} else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || | ||||
| 		   intel_encoder->type == INTEL_OUTPUT_DP_MST) { | ||||
| 		switch (crtc_state->port_clock / 2) { | ||||
| 		case 81000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); | ||||
| 			break; | ||||
| 		case 135000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); | ||||
| 			break; | ||||
| 		case 270000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		cfgcr1 = cfgcr2 = 0; | ||||
| 	} else if (intel_encoder->type == INTEL_OUTPUT_EDP) { | ||||
| 	if (intel_encoder->type == INTEL_OUTPUT_EDP) | ||||
| 		return true; | ||||
| 	} else | ||||
| 		return false; | ||||
| 
 | ||||
| 	memset(&crtc_state->dpll_hw_state, 0, | ||||
| 	       sizeof(crtc_state->dpll_hw_state)); | ||||
| 
 | ||||
| 	crtc_state->dpll_hw_state.ctrl1 = ctrl1; | ||||
| 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; | ||||
| 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; | ||||
| 
 | ||||
| 	pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder); | ||||
| 	if (pll == NULL) { | ||||
| @ -1318,9 +1022,6 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* shared DPLL id 0 is DPLL 1 */ | ||||
| 	crtc_state->ddi_pll_sel = pll->id + 1; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -837,15 +837,318 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| struct skl_wrpll_context { | ||||
| 	uint64_t min_deviation;		/* current minimal deviation */ | ||||
| 	uint64_t central_freq;		/* chosen central freq */ | ||||
| 	uint64_t dco_freq;		/* chosen dco freq */ | ||||
| 	unsigned int p;			/* chosen divider */ | ||||
| }; | ||||
| 
 | ||||
| static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) | ||||
| { | ||||
| 	memset(ctx, 0, sizeof(*ctx)); | ||||
| 
 | ||||
| 	ctx->min_deviation = U64_MAX; | ||||
| } | ||||
| 
 | ||||
| /* DCO freq must be within +1%/-6%  of the DCO central freq */ | ||||
| #define SKL_DCO_MAX_PDEVIATION	100 | ||||
| #define SKL_DCO_MAX_NDEVIATION	600 | ||||
| 
 | ||||
| static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, | ||||
| 				  uint64_t central_freq, | ||||
| 				  uint64_t dco_freq, | ||||
| 				  unsigned int divider) | ||||
| { | ||||
| 	uint64_t deviation; | ||||
| 
 | ||||
| 	deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq), | ||||
| 			      central_freq); | ||||
| 
 | ||||
| 	/* positive deviation */ | ||||
| 	if (dco_freq >= central_freq) { | ||||
| 		if (deviation < SKL_DCO_MAX_PDEVIATION && | ||||
| 		    deviation < ctx->min_deviation) { | ||||
| 			ctx->min_deviation = deviation; | ||||
| 			ctx->central_freq = central_freq; | ||||
| 			ctx->dco_freq = dco_freq; | ||||
| 			ctx->p = divider; | ||||
| 		} | ||||
| 	/* negative deviation */ | ||||
| 	} else if (deviation < SKL_DCO_MAX_NDEVIATION && | ||||
| 		   deviation < ctx->min_deviation) { | ||||
| 		ctx->min_deviation = deviation; | ||||
| 		ctx->central_freq = central_freq; | ||||
| 		ctx->dco_freq = dco_freq; | ||||
| 		ctx->p = divider; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void skl_wrpll_get_multipliers(unsigned int p, | ||||
| 				      unsigned int *p0 /* out */, | ||||
| 				      unsigned int *p1 /* out */, | ||||
| 				      unsigned int *p2 /* out */) | ||||
| { | ||||
| 	/* even dividers */ | ||||
| 	if (p % 2 == 0) { | ||||
| 		unsigned int half = p / 2; | ||||
| 
 | ||||
| 		if (half == 1 || half == 2 || half == 3 || half == 5) { | ||||
| 			*p0 = 2; | ||||
| 			*p1 = 1; | ||||
| 			*p2 = half; | ||||
| 		} else if (half % 2 == 0) { | ||||
| 			*p0 = 2; | ||||
| 			*p1 = half / 2; | ||||
| 			*p2 = 2; | ||||
| 		} else if (half % 3 == 0) { | ||||
| 			*p0 = 3; | ||||
| 			*p1 = half / 3; | ||||
| 			*p2 = 2; | ||||
| 		} else if (half % 7 == 0) { | ||||
| 			*p0 = 7; | ||||
| 			*p1 = half / 7; | ||||
| 			*p2 = 2; | ||||
| 		} | ||||
| 	} else if (p == 3 || p == 9) {  /* 3, 5, 7, 9, 15, 21, 35 */ | ||||
| 		*p0 = 3; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = p / 3; | ||||
| 	} else if (p == 5 || p == 7) { | ||||
| 		*p0 = p; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 1; | ||||
| 	} else if (p == 15) { | ||||
| 		*p0 = 3; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 5; | ||||
| 	} else if (p == 21) { | ||||
| 		*p0 = 7; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 3; | ||||
| 	} else if (p == 35) { | ||||
| 		*p0 = 7; | ||||
| 		*p1 = 1; | ||||
| 		*p2 = 5; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct skl_wrpll_params { | ||||
| 	uint32_t        dco_fraction; | ||||
| 	uint32_t        dco_integer; | ||||
| 	uint32_t        qdiv_ratio; | ||||
| 	uint32_t        qdiv_mode; | ||||
| 	uint32_t        kdiv; | ||||
| 	uint32_t        pdiv; | ||||
| 	uint32_t        central_freq; | ||||
| }; | ||||
| 
 | ||||
| static void skl_wrpll_params_populate(struct skl_wrpll_params *params, | ||||
| 				      uint64_t afe_clock, | ||||
| 				      uint64_t central_freq, | ||||
| 				      uint32_t p0, uint32_t p1, uint32_t p2) | ||||
| { | ||||
| 	uint64_t dco_freq; | ||||
| 
 | ||||
| 	switch (central_freq) { | ||||
| 	case 9600000000ULL: | ||||
| 		params->central_freq = 0; | ||||
| 		break; | ||||
| 	case 9000000000ULL: | ||||
| 		params->central_freq = 1; | ||||
| 		break; | ||||
| 	case 8400000000ULL: | ||||
| 		params->central_freq = 3; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (p0) { | ||||
| 	case 1: | ||||
| 		params->pdiv = 0; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		params->pdiv = 1; | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		params->pdiv = 2; | ||||
| 		break; | ||||
| 	case 7: | ||||
| 		params->pdiv = 4; | ||||
| 		break; | ||||
| 	default: | ||||
| 		WARN(1, "Incorrect PDiv\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	switch (p2) { | ||||
| 	case 5: | ||||
| 		params->kdiv = 0; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		params->kdiv = 1; | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		params->kdiv = 2; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		params->kdiv = 3; | ||||
| 		break; | ||||
| 	default: | ||||
| 		WARN(1, "Incorrect KDiv\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	params->qdiv_ratio = p1; | ||||
| 	params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1; | ||||
| 
 | ||||
| 	dco_freq = p0 * p1 * p2 * afe_clock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Intermediate values are in Hz. | ||||
| 	 * Divide by MHz to match bsepc | ||||
| 	 */ | ||||
| 	params->dco_integer = div_u64(dco_freq, 24 * MHz(1)); | ||||
| 	params->dco_fraction = | ||||
| 		div_u64((div_u64(dco_freq, 24) - | ||||
| 			 params->dco_integer * MHz(1)) * 0x8000, MHz(1)); | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| skl_ddi_calculate_wrpll(int clock /* in Hz */, | ||||
| 			struct skl_wrpll_params *wrpll_params) | ||||
| { | ||||
| 	uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ | ||||
| 	uint64_t dco_central_freq[3] = {8400000000ULL, | ||||
| 					9000000000ULL, | ||||
| 					9600000000ULL}; | ||||
| 	static const int even_dividers[] = {  4,  6,  8, 10, 12, 14, 16, 18, 20, | ||||
| 					     24, 28, 30, 32, 36, 40, 42, 44, | ||||
| 					     48, 52, 54, 56, 60, 64, 66, 68, | ||||
| 					     70, 72, 76, 78, 80, 84, 88, 90, | ||||
| 					     92, 96, 98 }; | ||||
| 	static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; | ||||
| 	static const struct { | ||||
| 		const int *list; | ||||
| 		int n_dividers; | ||||
| 	} dividers[] = { | ||||
| 		{ even_dividers, ARRAY_SIZE(even_dividers) }, | ||||
| 		{ odd_dividers, ARRAY_SIZE(odd_dividers) }, | ||||
| 	}; | ||||
| 	struct skl_wrpll_context ctx; | ||||
| 	unsigned int dco, d, i; | ||||
| 	unsigned int p0, p1, p2; | ||||
| 
 | ||||
| 	skl_wrpll_context_init(&ctx); | ||||
| 
 | ||||
| 	for (d = 0; d < ARRAY_SIZE(dividers); d++) { | ||||
| 		for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { | ||||
| 			for (i = 0; i < dividers[d].n_dividers; i++) { | ||||
| 				unsigned int p = dividers[d].list[i]; | ||||
| 				uint64_t dco_freq = p * afe_clock; | ||||
| 
 | ||||
| 				skl_wrpll_try_divider(&ctx, | ||||
| 						      dco_central_freq[dco], | ||||
| 						      dco_freq, | ||||
| 						      p); | ||||
| 				/*
 | ||||
| 				 * Skip the remaining dividers if we're sure to | ||||
| 				 * have found the definitive divider, we can't | ||||
| 				 * improve a 0 deviation. | ||||
| 				 */ | ||||
| 				if (ctx.min_deviation == 0) | ||||
| 					goto skip_remaining_dividers; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| skip_remaining_dividers: | ||||
| 		/*
 | ||||
| 		 * If a solution is found with an even divider, prefer | ||||
| 		 * this one. | ||||
| 		 */ | ||||
| 		if (d == 0 && ctx.p) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ctx.p) { | ||||
| 		DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * gcc incorrectly analyses that these can be used without being | ||||
| 	 * initialized. To be fair, it's hard to guess. | ||||
| 	 */ | ||||
| 	p0 = p1 = p2 = 0; | ||||
| 	skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2); | ||||
| 	skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq, | ||||
| 				  p0, p1, p2); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static struct intel_shared_dpll * | ||||
| skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, | ||||
| 	     struct intel_encoder *encoder) | ||||
| { | ||||
| 	struct intel_shared_dpll *pll; | ||||
| 	uint32_t ctrl1, cfgcr1, cfgcr2; | ||||
| 	int clock = crtc_state->port_clock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * See comment in intel_dpll_hw_state to understand why we always use 0 | ||||
| 	 * as the DPLL id in this function. | ||||
| 	 */ | ||||
| 
 | ||||
| 	ctrl1 = DPLL_CTRL1_OVERRIDE(0); | ||||
| 
 | ||||
| 	if (encoder->type == INTEL_OUTPUT_HDMI) { | ||||
| 		struct skl_wrpll_params wrpll_params = { 0, }; | ||||
| 
 | ||||
| 		ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); | ||||
| 
 | ||||
| 		if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) | ||||
| 			return false; | ||||
| 
 | ||||
| 		cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | | ||||
| 			 DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | | ||||
| 			 wrpll_params.dco_integer; | ||||
| 
 | ||||
| 		cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) | | ||||
| 			 DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) | | ||||
| 			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | | ||||
| 			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | | ||||
| 			 wrpll_params.central_freq; | ||||
| 	} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT || | ||||
| 		   encoder->type == INTEL_OUTPUT_DP_MST) { | ||||
| 		switch (crtc_state->port_clock / 2) { | ||||
| 		case 81000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); | ||||
| 			break; | ||||
| 		case 135000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); | ||||
| 			break; | ||||
| 		case 270000: | ||||
| 			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		cfgcr1 = cfgcr2 = 0; | ||||
| 	} else { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&crtc_state->dpll_hw_state, 0, | ||||
| 	       sizeof(crtc_state->dpll_hw_state)); | ||||
| 
 | ||||
| 	crtc_state->dpll_hw_state.ctrl1 = ctrl1; | ||||
| 	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; | ||||
| 	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; | ||||
| 
 | ||||
| 	pll = intel_find_shared_dpll(crtc, crtc_state, | ||||
| 				     DPLL_ID_SKL_DPLL1, DPLL_ID_SKL_DPLL3); | ||||
| 	if (pll) | ||||
| 	if (!pll) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	/* shared DPLL id 0 is DPLL 1 */ | ||||
| 	crtc_state->ddi_pll_sel = pll->id + 1; | ||||
| 
 | ||||
| 	intel_reference_shared_dpll(pll, crtc_state); | ||||
| 
 | ||||
| 	return pll; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Ander Conselvan de Oliveira
						Ander Conselvan de Oliveira