diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dpll_mgr.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dpll_mgr.c | 205 | 
1 files changed, 174 insertions, 31 deletions
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 383fbc15113d..b51ad2917dbe 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -163,8 +163,8 @@ void intel_enable_shared_dpll(struct intel_crtc *crtc)  	struct drm_device *dev = crtc->base.dev;  	struct drm_i915_private *dev_priv = to_i915(dev);  	struct intel_shared_dpll *pll = crtc->config->shared_dpll; -	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); -	unsigned old_mask; +	unsigned int crtc_mask = drm_crtc_mask(&crtc->base); +	unsigned int old_mask;  	if (WARN_ON(pll == NULL))  		return; @@ -207,7 +207,7 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc)  {  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);  	struct intel_shared_dpll *pll = crtc->config->shared_dpll; -	unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); +	unsigned int crtc_mask = drm_crtc_mask(&crtc->base);  	/* PCH only available on ILK+ */  	if (INTEL_GEN(dev_priv) < 5) @@ -2525,6 +2525,77 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state,  	return true;  } +int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv, +			       uint32_t pll_id) +{ +	uint32_t cfgcr0, cfgcr1; +	uint32_t pdiv, kdiv, qdiv_mode, qdiv_ratio, dco_integer, dco_fraction; +	const struct skl_wrpll_params *params; +	int index, n_entries, link_clock; + +	/* Read back values from DPLL CFGCR registers */ +	cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(pll_id)); +	cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(pll_id)); + +	dco_integer = cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK; +	dco_fraction = (cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >> +		DPLL_CFGCR0_DCO_FRACTION_SHIFT; +	pdiv = (cfgcr1 & DPLL_CFGCR1_PDIV_MASK) >> DPLL_CFGCR1_PDIV_SHIFT; +	kdiv = (cfgcr1 & DPLL_CFGCR1_KDIV_MASK) >> DPLL_CFGCR1_KDIV_SHIFT; +	qdiv_mode = (cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1)) >> +		DPLL_CFGCR1_QDIV_MODE_SHIFT; +	qdiv_ratio = (cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >> +		DPLL_CFGCR1_QDIV_RATIO_SHIFT; + +	params = dev_priv->cdclk.hw.ref == 24000 ? +		icl_dp_combo_pll_24MHz_values : +		icl_dp_combo_pll_19_2MHz_values; +	n_entries = ARRAY_SIZE(icl_dp_combo_pll_24MHz_values); + +	for (index = 0; index < n_entries; index++) { +		if (dco_integer == params[index].dco_integer && +		    dco_fraction == params[index].dco_fraction && +		    pdiv == params[index].pdiv && +		    kdiv == params[index].kdiv && +		    qdiv_mode == params[index].qdiv_mode && +		    qdiv_ratio == params[index].qdiv_ratio) +			break; +	} + +	/* Map PLL Index to Link Clock */ +	switch (index) { +	default: +		MISSING_CASE(index); +		/* fall through */ +	case 0: +		link_clock = 540000; +		break; +	case 1: +		link_clock = 270000; +		break; +	case 2: +		link_clock = 162000; +		break; +	case 3: +		link_clock = 324000; +		break; +	case 4: +		link_clock = 216000; +		break; +	case 5: +		link_clock = 432000; +		break; +	case 6: +		link_clock = 648000; +		break; +	case 7: +		link_clock = 810000; +		break; +	} + +	return link_clock; +} +  static enum port icl_mg_pll_id_to_port(enum intel_dpll_id id)  {  	return id - DPLL_ID_ICL_MGPLL1 + PORT_C; @@ -2569,6 +2640,7 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,  			switch (div1) {  			default:  				MISSING_CASE(div1); +				/* fall through */  			case 2:  				hsdiv = 0;  				break; @@ -2742,25 +2814,31 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,  				MG_PLL_SSC_FLLEN |  				MG_PLL_SSC_STEPSIZE(ssc_stepsize); -	pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART; - -	if (refclk_khz != 38400) { -		pll_state->mg_pll_tdc_coldst_bias |= -			MG_PLL_TDC_COLDST_IREFINT_EN | -			MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) | -			MG_PLL_TDC_COLDST_COLDSTART | -			MG_PLL_TDC_TDCOVCCORR_EN | -			MG_PLL_TDC_TDCSEL(3); - -		pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) | -					 MG_PLL_BIAS_INIT_DCOAMP(0x3F) | -					 MG_PLL_BIAS_BIAS_BONUS(10) | -					 MG_PLL_BIAS_BIASCAL_EN | -					 MG_PLL_BIAS_CTRIM(12) | -					 MG_PLL_BIAS_VREF_RDAC(4) | -					 MG_PLL_BIAS_IREFTRIM(iref_trim); +	pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART | +					    MG_PLL_TDC_COLDST_IREFINT_EN | +					    MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) | +					    MG_PLL_TDC_TDCOVCCORR_EN | +					    MG_PLL_TDC_TDCSEL(3); + +	pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) | +				 MG_PLL_BIAS_INIT_DCOAMP(0x3F) | +				 MG_PLL_BIAS_BIAS_BONUS(10) | +				 MG_PLL_BIAS_BIASCAL_EN | +				 MG_PLL_BIAS_CTRIM(12) | +				 MG_PLL_BIAS_VREF_RDAC(4) | +				 MG_PLL_BIAS_IREFTRIM(iref_trim); + +	if (refclk_khz == 38400) { +		pll_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; +		pll_state->mg_pll_bias_mask = 0; +	} else { +		pll_state->mg_pll_tdc_coldst_bias_mask = -1U; +		pll_state->mg_pll_bias_mask = -1U;  	} +	pll_state->mg_pll_tdc_coldst_bias &= pll_state->mg_pll_tdc_coldst_bias_mask; +	pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask; +  	return true;  } @@ -2787,10 +2865,17 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,  	case PORT_D:  	case PORT_E:  	case PORT_F: -		min = icl_port_to_mg_pll_id(port); -		max = min; -		ret = icl_calc_mg_pll_state(crtc_state, encoder, clock, -					    &pll_state); +		if (0 /* TODO: TBT PLLs */) { +			min = DPLL_ID_ICL_TBTPLL; +			max = min; +			ret = icl_calc_dpll_state(crtc_state, encoder, clock, +						  &pll_state); +		} else { +			min = icl_port_to_mg_pll_id(port); +			max = min; +			ret = icl_calc_mg_pll_state(crtc_state, encoder, clock, +						    &pll_state); +		}  		break;  	default:  		MISSING_CASE(port); @@ -2820,9 +2905,12 @@ static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id)  	switch (id) {  	default:  		MISSING_CASE(id); +		/* fall through */  	case DPLL_ID_ICL_DPLL0:  	case DPLL_ID_ICL_DPLL1:  		return CNL_DPLL_ENABLE(id); +	case DPLL_ID_ICL_TBTPLL: +		return TBT_PLL_ENABLE;  	case DPLL_ID_ICL_MGPLL1:  	case DPLL_ID_ICL_MGPLL2:  	case DPLL_ID_ICL_MGPLL3: @@ -2850,6 +2938,7 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,  	switch (id) {  	case DPLL_ID_ICL_DPLL0:  	case DPLL_ID_ICL_DPLL1: +	case DPLL_ID_ICL_TBTPLL:  		hw_state->cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(id));  		hw_state->cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(id));  		break; @@ -2859,18 +2948,41 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,  	case DPLL_ID_ICL_MGPLL4:  		port = icl_mg_pll_id_to_port(id);  		hw_state->mg_refclkin_ctl = I915_READ(MG_REFCLKIN_CTL(port)); +		hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; +  		hw_state->mg_clktop2_coreclkctl1 =  			I915_READ(MG_CLKTOP2_CORECLKCTL1(port)); +		hw_state->mg_clktop2_coreclkctl1 &= +			MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; +  		hw_state->mg_clktop2_hsclkctl =  			I915_READ(MG_CLKTOP2_HSCLKCTL(port)); +		hw_state->mg_clktop2_hsclkctl &= +			MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | +			MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | +			MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | +			MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; +  		hw_state->mg_pll_div0 = I915_READ(MG_PLL_DIV0(port));  		hw_state->mg_pll_div1 = I915_READ(MG_PLL_DIV1(port));  		hw_state->mg_pll_lf = I915_READ(MG_PLL_LF(port));  		hw_state->mg_pll_frac_lock = I915_READ(MG_PLL_FRAC_LOCK(port));  		hw_state->mg_pll_ssc = I915_READ(MG_PLL_SSC(port)); +  		hw_state->mg_pll_bias = I915_READ(MG_PLL_BIAS(port));  		hw_state->mg_pll_tdc_coldst_bias =  			I915_READ(MG_PLL_TDC_COLDST_BIAS(port)); + +		if (dev_priv->cdclk.hw.ref == 38400) { +			hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; +			hw_state->mg_pll_bias_mask = 0; +		} else { +			hw_state->mg_pll_tdc_coldst_bias_mask = -1U; +			hw_state->mg_pll_bias_mask = -1U; +		} + +		hw_state->mg_pll_tdc_coldst_bias &= hw_state->mg_pll_tdc_coldst_bias_mask; +		hw_state->mg_pll_bias &= hw_state->mg_pll_bias_mask;  		break;  	default:  		MISSING_CASE(id); @@ -2898,19 +3010,48 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv,  {  	struct intel_dpll_hw_state *hw_state = &pll->state.hw_state;  	enum port port = icl_mg_pll_id_to_port(pll->info->id); +	u32 val; + +	/* +	 * Some of the following registers have reserved fields, so program +	 * these with RMW based on a mask. The mask can be fixed or generated +	 * during the calc/readout phase if the mask depends on some other HW +	 * state like refclk, see icl_calc_mg_pll_state(). +	 */ +	val = I915_READ(MG_REFCLKIN_CTL(port)); +	val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; +	val |= hw_state->mg_refclkin_ctl; +	I915_WRITE(MG_REFCLKIN_CTL(port), val); + +	val = I915_READ(MG_CLKTOP2_CORECLKCTL1(port)); +	val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; +	val |= hw_state->mg_clktop2_coreclkctl1; +	I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), val); + +	val = I915_READ(MG_CLKTOP2_HSCLKCTL(port)); +	val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | +		 MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | +		 MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | +		 MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); +	val |= hw_state->mg_clktop2_hsclkctl; +	I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), val); -	I915_WRITE(MG_REFCLKIN_CTL(port), hw_state->mg_refclkin_ctl); -	I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), -		   hw_state->mg_clktop2_coreclkctl1); -	I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), hw_state->mg_clktop2_hsclkctl);  	I915_WRITE(MG_PLL_DIV0(port), hw_state->mg_pll_div0);  	I915_WRITE(MG_PLL_DIV1(port), hw_state->mg_pll_div1);  	I915_WRITE(MG_PLL_LF(port), hw_state->mg_pll_lf);  	I915_WRITE(MG_PLL_FRAC_LOCK(port), hw_state->mg_pll_frac_lock);  	I915_WRITE(MG_PLL_SSC(port), hw_state->mg_pll_ssc); -	I915_WRITE(MG_PLL_BIAS(port), hw_state->mg_pll_bias); -	I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port), -		   hw_state->mg_pll_tdc_coldst_bias); + +	val = I915_READ(MG_PLL_BIAS(port)); +	val &= ~hw_state->mg_pll_bias_mask; +	val |= hw_state->mg_pll_bias; +	I915_WRITE(MG_PLL_BIAS(port), val); + +	val = I915_READ(MG_PLL_TDC_COLDST_BIAS(port)); +	val &= ~hw_state->mg_pll_tdc_coldst_bias_mask; +	val |= hw_state->mg_pll_tdc_coldst_bias; +	I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port), val); +  	POSTING_READ(MG_PLL_TDC_COLDST_BIAS(port));  } @@ -2936,6 +3077,7 @@ static void icl_pll_enable(struct drm_i915_private *dev_priv,  	switch (id) {  	case DPLL_ID_ICL_DPLL0:  	case DPLL_ID_ICL_DPLL1: +	case DPLL_ID_ICL_TBTPLL:  		icl_dpll_write(dev_priv, pll);  		break;  	case DPLL_ID_ICL_MGPLL1: @@ -3034,6 +3176,7 @@ static const struct intel_shared_dpll_funcs icl_pll_funcs = {  static const struct dpll_info icl_plls[] = {  	{ "DPLL 0",   &icl_pll_funcs, DPLL_ID_ICL_DPLL0,  0 },  	{ "DPLL 1",   &icl_pll_funcs, DPLL_ID_ICL_DPLL1,  0 }, +	{ "TBT PLL",  &icl_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 },  	{ "MG PLL 1", &icl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 },  	{ "MG PLL 2", &icl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 },  	{ "MG PLL 3", &icl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 },  |