diff mbox

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

Message ID 1523411647-16840-2-git-send-email-abhinavk@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Abhinav Kumar April 11, 2018, 1:54 a.m. UTC
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.

Changes in v2:
- None

Reviewed-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Abhinav Kumar <abhinavk@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(-)

Comments

Sean Paul April 13, 2018, 8:29 p.m. UTC | #1
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

> 
> Changes in v2:
> - None
> 
> Reviewed-by: Archit Taneja <architt@codeaurora.org>
> Signed-off-by: Abhinav Kumar <abhinavk@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@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
>
Abhinav Kumar April 13, 2018, 8:52 p.m. UTC | #2
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@codeaurora.org>
>> Signed-off-by: Abhinav Kumar <abhinavk@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@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
>>
Sean Paul April 16, 2018, 5:01 p.m. UTC | #3
On Fri, Apr 13, 2018 at 01:52:17PM -0700, abhinavk@codeaurora.org wrote:
> 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.

Ahh, ok :(

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> > > 
> > > Changes in v2:
> > > - None
> > > 
> > > Reviewed-by: Archit Taneja <architt@codeaurora.org>
> > > Signed-off-by: Abhinav Kumar <abhinavk@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@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
> > >
diff mbox

Patch

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@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)
 {