diff options
Diffstat (limited to 'drivers/gpu/drm/meson/meson_vclk.c')
| -rw-r--r-- | drivers/gpu/drm/meson/meson_vclk.c | 93 | 
1 files changed, 71 insertions, 22 deletions
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index f690793ae2d5..fdf26dac9fa8 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -354,12 +354,17 @@ enum {  /* 2970 /1 /1 /1 /5 /2  => /1 /1 */  	MESON_VCLK_HDMI_297000,  /* 5940 /1 /1 /2 /5 /1  => /1 /1 */ -	MESON_VCLK_HDMI_594000 +	MESON_VCLK_HDMI_594000, +/* 2970 /1 /1 /1 /5 /1  => /1 /2 */ +	MESON_VCLK_HDMI_594000_YUV420,  };  struct meson_vclk_params { +	unsigned int pll_freq; +	unsigned int phy_freq; +	unsigned int vclk_freq; +	unsigned int venc_freq;  	unsigned int pixel_freq; -	unsigned int pll_base_freq;  	unsigned int pll_od1;  	unsigned int pll_od2;  	unsigned int pll_od3; @@ -367,8 +372,11 @@ struct meson_vclk_params {  	unsigned int vclk_div;  } params[] = {  	[MESON_VCLK_HDMI_ENCI_54000] = { +		.pll_freq = 4320000, +		.phy_freq = 270000, +		.vclk_freq = 54000, +		.venc_freq = 54000,  		.pixel_freq = 54000, -		.pll_base_freq = 4320000,  		.pll_od1 = 4,  		.pll_od2 = 4,  		.pll_od3 = 1, @@ -376,8 +384,11 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_DDR_54000] = { -		.pixel_freq = 54000, -		.pll_base_freq = 4320000, +		.pll_freq = 4320000, +		.phy_freq = 270000, +		.vclk_freq = 54000, +		.venc_freq = 54000, +		.pixel_freq = 27000,  		.pll_od1 = 4,  		.pll_od2 = 4,  		.pll_od3 = 1, @@ -385,8 +396,11 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_DDR_148500] = { -		.pixel_freq = 148500, -		.pll_base_freq = 2970000, +		.pll_freq = 2970000, +		.phy_freq = 742500, +		.vclk_freq = 148500, +		.venc_freq = 148500, +		.pixel_freq = 74250,  		.pll_od1 = 4,  		.pll_od2 = 1,  		.pll_od3 = 1, @@ -394,8 +408,11 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_74250] = { +		.pll_freq = 2970000, +		.phy_freq = 742500, +		.vclk_freq = 74250, +		.venc_freq = 74250,  		.pixel_freq = 74250, -		.pll_base_freq = 2970000,  		.pll_od1 = 2,  		.pll_od2 = 2,  		.pll_od3 = 2, @@ -403,8 +420,11 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_148500] = { +		.pll_freq = 2970000, +		.phy_freq = 1485000, +		.vclk_freq = 148500, +		.venc_freq = 148500,  		.pixel_freq = 148500, -		.pll_base_freq = 2970000,  		.pll_od1 = 1,  		.pll_od2 = 2,  		.pll_od3 = 2, @@ -412,8 +432,11 @@ struct meson_vclk_params {  		.vclk_div = 1,  	},  	[MESON_VCLK_HDMI_297000] = { +		.pll_freq = 5940000, +		.phy_freq = 2970000, +		.venc_freq = 297000, +		.vclk_freq = 297000,  		.pixel_freq = 297000, -		.pll_base_freq = 5940000,  		.pll_od1 = 2,  		.pll_od2 = 1,  		.pll_od3 = 1, @@ -421,14 +444,29 @@ struct meson_vclk_params {  		.vclk_div = 2,  	},  	[MESON_VCLK_HDMI_594000] = { +		.pll_freq = 5940000, +		.phy_freq = 5940000, +		.venc_freq = 594000, +		.vclk_freq = 594000,  		.pixel_freq = 594000, -		.pll_base_freq = 5940000,  		.pll_od1 = 1,  		.pll_od2 = 1,  		.pll_od3 = 2,  		.vid_pll_div = VID_PLL_DIV_5,  		.vclk_div = 1,  	}, +	[MESON_VCLK_HDMI_594000_YUV420] = { +		.pll_freq = 5940000, +		.phy_freq = 2970000, +		.venc_freq = 594000, +		.vclk_freq = 594000, +		.pixel_freq = 297000, +		.pll_od1 = 2, +		.pll_od2 = 1, +		.pll_od3 = 1, +		.vid_pll_div = VID_PLL_DIV_5, +		.vclk_div = 1, +	},  	{ /* sentinel */ },  }; @@ -701,6 +739,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,  	unsigned int od, m, frac, od1, od2, od3;  	if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { +		/* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */  		od3 = 1;  		if (od < 4) {  			od1 = 2; @@ -723,21 +762,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,  }  enum drm_mode_status -meson_vclk_vic_supported_freq(unsigned int freq) +meson_vclk_vic_supported_freq(unsigned int phy_freq, +			      unsigned int vclk_freq)  {  	int i; -	DRM_DEBUG_DRIVER("freq = %d\n", freq); +	DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", +			 phy_freq, vclk_freq);  	for (i = 0 ; params[i].pixel_freq ; ++i) {  		DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",  				 i, params[i].pixel_freq,  				 FREQ_1000_1001(params[i].pixel_freq)); +		DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", +				 i, params[i].phy_freq, +				 FREQ_1000_1001(params[i].phy_freq/10)*10);  		/* Match strict frequency */ -		if (freq == params[i].pixel_freq) +		if (phy_freq == params[i].phy_freq && +		    vclk_freq == params[i].vclk_freq)  			return MODE_OK;  		/* Match 1000/1001 variant */ -		if (freq == FREQ_1000_1001(params[i].pixel_freq)) +		if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && +		    vclk_freq == FREQ_1000_1001(params[i].vclk_freq))  			return MODE_OK;  	} @@ -965,8 +1011,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,  }  void meson_vclk_setup(struct meson_drm *priv, unsigned int target, -		      unsigned int vclk_freq, unsigned int venc_freq, -		      unsigned int dac_freq, bool hdmi_use_enci) +		      unsigned int phy_freq, unsigned int vclk_freq, +		      unsigned int venc_freq, unsigned int dac_freq, +		      bool hdmi_use_enci)  {  	bool vic_alternate_clock = false;  	unsigned int freq; @@ -986,7 +1033,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		 * - venc_div = 1  		 * - encp encoder  		 */ -		meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, +		meson_vclk_set(priv, phy_freq, 0, 0, 0,  			       VID_PLL_DIV_5, 2, 1, 1, false, false);  		return;  	} @@ -1008,9 +1055,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  	}  	for (freq = 0 ; params[freq].pixel_freq ; ++freq) { -		if (vclk_freq == params[freq].pixel_freq || -		    vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) { -			if (vclk_freq != params[freq].pixel_freq) +		if ((phy_freq == params[freq].phy_freq || +		     phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && +		    (vclk_freq == params[freq].vclk_freq || +		     vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { +			if (vclk_freq != params[freq].vclk_freq)  				vic_alternate_clock = true;  			else  				vic_alternate_clock = false; @@ -1039,7 +1088,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,  		return;  	} -	meson_vclk_set(priv, params[freq].pll_base_freq, +	meson_vclk_set(priv, params[freq].pll_freq,  		       params[freq].pll_od1, params[freq].pll_od2,  		       params[freq].pll_od3, params[freq].vid_pll_div,  		       params[freq].vclk_div, hdmi_tx_div, venc_div,  |