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

Sean Paul seanpaul at chromium.org
Mon Apr 16 17:01:34 UTC 2018


On Fri, Apr 13, 2018 at 01:52:17PM -0700, abhinavk at 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 at chromium.org>

> > > 
> > > 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
> > > 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


More information about the Freedreno mailing list