[DPU PATCH v2 2/2] drm/msm/dsi: implement auto PHY timing calculator for 10nm PHY

abhinavk at codeaurora.org abhinavk at codeaurora.org
Fri Apr 13 20:52:17 UTC 2018


On 2018-04-13 13:29, Sean Paul wrote:
> On Tue, Apr 10, 2018 at 06:54:07PM -0700, Abhinav Kumar wrote:
>> Currently the DSI PHY timings are hard-coded for a specific panel
>> for the 10nm PHY.
>> 
>> Replace this with the auto PHY timing calculator which can calculate
>> the PHY timings for any panel.
> 
> Any chance you could document what you're doing so anyone without 
> documentation
> has a clue what's going on?
> 
> Sean
> 
I am afraid it will hard to document more about this function other than 
whats mentioned here.
Basically, we have an excel sheet which does this math to calculate the 
DSI timings.
This patch implements that excel sheet for SDM845 which uses 10nm PHY.
We will not be able to explain the math in more detail.
>> 
>> Changes in v2:
>> - None
>> 
>> Reviewed-by: Archit Taneja <architt at codeaurora.org>
>> Signed-off-by: Abhinav Kumar <abhinavk at codeaurora.org>
>> ---
>>  drivers/gpu/drm/msm/dsi/phy/dsi_phy.c      | 111 
>> +++++++++++++++++++++++++++++
>>  drivers/gpu/drm/msm/dsi/phy/dsi_phy.h      |   2 +
>>  drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c |  28 --------
>>  3 files changed, 113 insertions(+), 28 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c 
>> b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
>> index 8e9d5c2..5b42885 100644
>> --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
>> +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
>> @@ -265,6 +265,117 @@ int msm_dsi_dphy_timing_calc_v2(struct 
>> msm_dsi_dphy_timing *timing,
>>  	return 0;
>>  }
>> 
>> +int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
>> +				       struct msm_dsi_phy_clk_request *clk_req)
>> +{
>> +	const unsigned long bit_rate = clk_req->bitclk_rate;
>> +	const unsigned long esc_rate = clk_req->escclk_rate;
>> +	s32 ui, ui_x8, lpx;
>> +	s32 tmax, tmin;
>> +	s32 pcnt0 = 50;
>> +	s32 pcnt1 = 50;
>> +	s32 pcnt2 = 10;
>> +	s32 pcnt3 = 30;
>> +	s32 pcnt4 = 10;
>> +	s32 pcnt5 = 2;
>> +	s32 coeff = 1000; /* Precision, should avoid overflow */
>> +	s32 hb_en, hb_en_ckln;
>> +	s32 temp;
>> +
>> +	if (!bit_rate || !esc_rate)
>> +		return -EINVAL;
>> +
>> +	timing->hs_halfbyte_en = 0;
>> +	hb_en = 0;
>> +	timing->hs_halfbyte_en_ckln = 0;
>> +	hb_en_ckln = 0;
>> +
>> +	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
>> +	ui_x8 = ui << 3;
>> +	lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
>> +
>> +	temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
>> +	tmin = max_t(s32, temp, 0);
>> +	temp = (95 * coeff) / ui_x8;
>> +	tmax = max_t(s32, temp, 0);
>> +	timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
>> +
>> +
>> +	temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
>> +	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
>> +	tmax = (tmin > 255) ? 511 : 255;
>> +	timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
>> +
>> +	tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
>> +	temp = 105 * coeff + 12 * ui - 20 * coeff;
>> +	tmax = (temp + 3 * ui) / ui_x8;
>> +	timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
>> +
>> +	temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
>> +	tmin = max_t(s32, temp, 0);
>> +	temp = (85 * coeff + 6 * ui) / ui_x8;
>> +	tmax = max_t(s32, temp, 0);
>> +	timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
>> +
>> +	temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
>> +	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
>> +	tmax = 255;
>> +	timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
>> +
>> +	tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
>> +	temp = 105 * coeff + 12 * ui - 20 * coeff;
>> +	tmax = (temp / ui_x8) - 1;
>> +	timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
>> +
>> +	temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
>> +	timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
>> +
>> +	tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
>> +	tmax = 255;
>> +	timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
>> +
>> +	temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
>> +	timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
>> +
>> +	temp = 60 * coeff + 52 * ui - 43 * ui;
>> +	tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
>> +	tmax = 63;
>> +	timing->shared_timings.clk_post =
>> +				linear_inter(tmax, tmin, pcnt2, 0, false);
>> +
>> +	temp = 8 * ui + (timing->clk_prepare << 3) * ui;
>> +	temp += (((timing->clk_zero + 3) << 3) + 11) * ui;
>> +	temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
>> +				(((timing->hs_rqst_ckln << 3) + 8) * ui);
>> +	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
>> +	tmax = 63;
>> +	if (tmin > tmax) {
>> +		temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
>> +		timing->shared_timings.clk_pre = temp >> 1;
>> +		timing->shared_timings.clk_pre_inc_by_2 = 1;
>> +	} else {
>> +		timing->shared_timings.clk_pre =
>> +				linear_inter(tmax, tmin, pcnt2, 0, false);
>> +		timing->shared_timings.clk_pre_inc_by_2 = 0;
>> +	}
>> +
>> +	timing->ta_go = 3;
>> +	timing->ta_sure = 0;
>> +	timing->ta_get = 4;
>> +
>> +	DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, 
>> %d",
>> +	    timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
>> +	    timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
>> +	    timing->clk_trail, timing->clk_prepare, timing->hs_exit,
>> +	    timing->hs_zero, timing->hs_prepare, timing->hs_trail,
>> +	    timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
>> +	    timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
>> +	    timing->hs_prep_dly_ckln);
>> +
>> +
>> +	return 0;
>> +}
>> +
>>  void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 
>> reg,
>>  				u32 bit_mask)
>>  {
>> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h 
>> b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
>> index c56268c..a24ab80 100644
>> --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
>> +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
>> @@ -101,6 +101,8 @@ int msm_dsi_dphy_timing_calc(struct 
>> msm_dsi_dphy_timing *timing,
>>  			     struct msm_dsi_phy_clk_request *clk_req);
>>  int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing,
>>  				struct msm_dsi_phy_clk_request *clk_req);
>> +int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
>> +				struct msm_dsi_phy_clk_request *clk_req);
>>  void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 
>> reg,
>>  				u32 bit_mask);
>>  int msm_dsi_phy_init_common(struct msm_dsi_phy *phy);
>> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c 
>> b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
>> index 0af951a..b3fffc8 100644
>> --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
>> +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
>> @@ -79,34 +79,6 @@ static void dsi_phy_hw_v3_0_lane_settings(struct 
>> msm_dsi_phy *phy)
>>  	dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04);
>>  }
>> 
>> -static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing 
>> *timing,
>> -				       struct msm_dsi_phy_clk_request *clk_req)
>> -{
>> -	/*
>> -	 * TODO: These params need to be computed, they're currently 
>> hardcoded
>> -	 * for a 1440x2560 at 60Hz panel with a byteclk of 100.618 Mhz, and a
>> -	 * default escape clock of 19.2 Mhz.
>> -	 */
>> -
>> -	timing->hs_halfbyte_en = 0;
>> -	timing->clk_zero = 0x1c;
>> -	timing->clk_prepare = 0x07;
>> -	timing->clk_trail = 0x07;
>> -	timing->hs_exit = 0x23;
>> -	timing->hs_zero = 0x21;
>> -	timing->hs_prepare = 0x07;
>> -	timing->hs_trail = 0x07;
>> -	timing->hs_rqst = 0x05;
>> -	timing->ta_sure = 0x00;
>> -	timing->ta_go = 0x03;
>> -	timing->ta_get = 0x04;
>> -
>> -	timing->shared_timings.clk_pre = 0x2d;
>> -	timing->shared_timings.clk_post = 0x0d;
>> -
>> -	return 0;
>> -}
>> -
>>  static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int 
>> src_pll_id,
>>  			       struct msm_dsi_phy_clk_request *clk_req)
>>  {
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
>> Forum,
>> a Linux Foundation Collaborative Project
>> 


More information about the dri-devel mailing list