Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3287bab4 authored by Jeevan Shriram's avatar Jeevan Shriram Committed by Narendra Muppalla
Browse files

clk: mdss: add software mux for byte and pixel source clocks



Implement the software mux to byte clock and pixel source clock
with shadow implementation of PLL clock. This is used for
configuring the dynamic refresh pll registers.

Change-Id: I9c84cb76d040c5df7361291b6e1fc0fe69dc214f
Signed-off-by: default avatarJeevan Shriram <jshriram@codeaurora.org>
parent 6dd6b97a
Loading
Loading
Loading
Loading
+337 −52
Original line number Diff line number Diff line
@@ -98,10 +98,118 @@
#define MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER		0x0148
#define MMSS_DSI_PHY_PLL_PLL_VCO_HIGH			0x014C
#define MMSS_DSI_PHY_PLL_RESET_SM			0x0150
#define MMSS_DSI_PHY_PLL_MUXVAL			0x0154
#define MMSS_DSI_PHY_PLL_CORE_RES_CODE_DN		0x0158
#define MMSS_DSI_PHY_PLL_CORE_RES_CODE_UP		0x015C
#define MMSS_DSI_PHY_PLL_CORE_VCO_TUNE			0x0160
#define MMSS_DSI_PHY_PLL_CORE_VCO_TAIL			0x0164
#define MMSS_DSI_PHY_PLL_CORE_KVCO_CODE		0x0168

#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL0		0x014
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL1		0x018
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL2		0x01C
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL3		0x020
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL4		0x024
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL5		0x028
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL6		0x02C
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL7		0x030
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL8		0x034
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL9		0x038
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL10		0x03C
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL11		0x040
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL12		0x044
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL13		0x048
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL14		0x04C
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL15		0x050
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL16		0x054
#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL17		0x058

#define DSI_PLL_POLL_MAX_READS			15
#define DSI_PLL_POLL_TIMEOUT_US			1000

int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel)
{
	return 0;
}

int get_mdss_byte_mux_sel(struct mux_clk *clk)
{
	return 0;
}

int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel)
{
	return 0;
}

int get_mdss_pixel_mux_sel(struct mux_clk *clk)
{
	return 0;
}

void dsi_cache_trim_codes(struct mdss_pll_resources *dsi_pll_res)
{
	int rc;

	if (dsi_pll_res->reg_upd)
		return;

	rc = mdss_pll_resource_enable(dsi_pll_res, true);
	if (rc) {
		pr_err("Failed to enable mdss dsi pll resources\n");
		return;
	}

	dsi_pll_res->cache_pll_trim_codes[0] =
		(MDSS_PLL_REG_R(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_CORE_KVCO_CODE) & ~0xF);
	dsi_pll_res->cache_pll_trim_codes[1] =
		(MDSS_PLL_REG_R(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_CORE_VCO_TAIL) & ~0xF);
	dsi_pll_res->cache_pll_trim_codes[2] =
		(MDSS_PLL_REG_R(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_CORE_VCO_TUNE) & ~0x7F);
	dsi_pll_res->cache_pll_trim_codes[3] =
		(MDSS_PLL_REG_R(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_CORE_RES_CODE_UP) & ~0xF);
	dsi_pll_res->cache_pll_trim_codes[4] =
		(MDSS_PLL_REG_R(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_CORE_RES_CODE_DN) & ~0xF);

	mdss_pll_resource_enable(dsi_pll_res, false);

	dsi_pll_res->reg_upd = true;
}

static void dsi_dfps_override_trim_codes(struct mdss_pll_resources *dsi_pll_res)
{
	int reg_data;

	/*
	 * Override mux config for all cached trim codes from
	 * saved config except for VCO Tune
	 */
	reg_data = dsi_pll_res->cache_pll_trim_codes[0];
	reg_data |= BIT(5);
	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_KVCO_CODE, reg_data);

	reg_data = dsi_pll_res->cache_pll_trim_codes[1] << 2;
	reg_data |= BIT(7);
	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, reg_data);

	reg_data = dsi_pll_res->cache_pll_trim_codes[3];
	reg_data |= BIT(5);
	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_RES_CODE_UP, reg_data);

	reg_data = dsi_pll_res->cache_pll_trim_codes[4];
	reg_data |= BIT(5);
	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
		MMSS_DSI_PHY_PLL_RES_CODE_DN, reg_data);

}

int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel)
{
@@ -121,6 +229,33 @@ int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel)
	return 0;
}

int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel)
{
	struct mdss_pll_resources *dsi_pll_res = clk->priv;
	int reg_data, rem;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}

	reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL);
	reg_data |= BIT(7);

	pr_debug("%d: reg_data = %x\n", __LINE__, reg_data);

	/* Repeat POST DIVIDER 2 times (4 writes)*/
	for (rem = 0; rem < 2; rem++)
		MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
			MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL16 + (4 * rem),
			MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
			MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
			(reg_data | (sel << 5)), (reg_data | (sel << 5)));

	return 0;
}

int get_bypass_lp_div_mux_sel(struct mux_clk *clk)
{
	int mux_mode, rc;
@@ -147,6 +282,8 @@ int ndiv_set_div(struct div_clk *clk, int div)
	int rc, reg_data;
	struct mdss_pll_resources *dsi_pll_res = clk->priv;

	pr_debug("%d div=%i\n", __LINE__, div);

	rc = mdss_pll_resource_enable(dsi_pll_res, true);
	if (rc) {
		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -163,6 +300,26 @@ int ndiv_set_div(struct div_clk *clk, int div)
	return rc;
}

int shadow_ndiv_set_div(struct div_clk *clk, int div)
{
	struct mdss_pll_resources *dsi_pll_res = clk->priv;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}

	pr_debug("%d div=%i\n", __LINE__, div);

	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL14,
		MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
		MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
		0x07, (0xB | div));

	return 0;
}

int ndiv_get_div(struct div_clk *clk)
{
	int div = 0, rc;
@@ -201,6 +358,25 @@ int fixed_hr_oclk2_set_div(struct div_clk *clk, int div)
	return rc;
}

int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div)
{
	struct mdss_pll_resources *dsi_pll_res = clk->priv;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}
	pr_debug("%d div = %d\n", __LINE__, div);

	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL5,
		MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER,
		MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER,
		(div - 1), (div - 1));

	return 0;
}

int fixed_hr_oclk2_get_div(struct div_clk *clk)
{
	int div = 0, rc;
@@ -238,6 +414,26 @@ int hr_oclk3_set_div(struct div_clk *clk, int div)
	return rc;
}

int shadow_hr_oclk3_set_div(struct div_clk *clk, int div)
{
	struct mdss_pll_resources *dsi_pll_res = clk->priv;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}

	pr_debug("%d div = %d\n", __LINE__, div);

	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL6,
		MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER,
		MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER,
		(div - 1), (div - 1));

	return 0;
}

int hr_oclk3_get_div(struct div_clk *clk)
{
	int div = 0, rc;
@@ -478,93 +674,103 @@ static void pll_20nm_phy_config(struct dsi_pll_vco_clk *vco)
	pll_20nm_phy_loop_bw_config(dsi_pll_res);
}

int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
static void pll_20nm_vco_rate_calc(struct dsi_pll_vco_clk *vco,
		struct mdss_pll_vco_calc *vco_calc, s64 vco_clk_rate)
{
	s64 vco_clk_rate = rate;
	s64 multiplier = (1 << 20);
	s64 duration = 128, pll_comp_val;
	s64 dec_start_multiple, dec_start;
	s32 div_frac_start;
	s32 div_frac_start1, div_frac_start2, div_frac_start3;
	s64 dec_start_multiple, dec_start, multiplier = (1 << 20);
	s64 dec_start1, dec_start2;
	s64 duration = 128, pll_comp_val;
	s32 div_frac_start1, div_frac_start2, div_frac_start3;
	s64 pll_plllock_cmp1, pll_plllock_cmp2, pll_plllock_cmp3;

	struct mdss_pll_resources *dsi_pll_res = vco->priv;

	pr_debug("%s: vco set rate: %lld\n", __func__, vco_clk_rate);
	pll_20nm_phy_config(vco);

	memset(vco_calc, 0, sizeof(*vco_calc));
	dec_start_multiple = div_s64(vco_clk_rate * multiplier,
					2 * vco->ref_clk_rate);
	div_s64_rem(dec_start_multiple,
			multiplier, &div_frac_start);

	dec_start = div_s64(dec_start_multiple, multiplier);
	pr_debug("%s: dec_start_multiple = 0x%llx\n",
				__func__, dec_start_multiple);
	pr_debug("%s: dec_start = 0x%llx, div_frac_start = 0x%x\n",
			__func__, dec_start, div_frac_start);

	dec_start1 = (dec_start & 0x7f) | BIT(7);
	dec_start2 = ((dec_start & 0x80) >> 7) | BIT(1);
	pr_debug("%s: dec_start1 = 0x%llx, dec_start2 = 0x%llx\n",
				__func__, dec_start1, dec_start2);

	div_frac_start1 = (div_frac_start & 0x7f) | BIT(7);
	div_frac_start2 = ((div_frac_start >> 7) & 0x7f) | BIT(7);
	div_frac_start3 = ((div_frac_start >> 14) & 0x3f) | BIT(6);
	pr_debug("%s: div_frac_start1 = 0x%x\n",
				__func__, div_frac_start1);
	pr_debug("%s: div_frac_start2 = 0x%x\n",
				__func__, div_frac_start2);
	pr_debug("%s: div_frac_start3 = 0x%x\n",
				__func__, div_frac_start3);
	pll_comp_val = div_s64(dec_start_multiple * 2 * (duration - 1),
				10 * multiplier);
	pll_plllock_cmp1 = pll_comp_val & 0xff;
	pll_plllock_cmp2 = (pll_comp_val >> 8) & 0xff;
	pll_plllock_cmp3 = (pll_comp_val >> 16) & 0xff;

	pr_debug("dec_start_multiple = 0x%llx\n", dec_start_multiple);
	pr_debug("dec_start = 0x%llx, div_frac_start = 0x%x\n",
			dec_start, div_frac_start);
	pr_debug("dec_start1 = 0x%llx, dec_start2 = 0x%llx\n",
			dec_start1, dec_start2);
	pr_debug("div_frac_start1 = 0x%x, div_frac_start2 = 0x%x\n",
			div_frac_start1, div_frac_start2);
	pr_debug("div_frac_start3 = 0x%x\n", div_frac_start3);
	pr_debug("pll_comp_val = 0x%llx\n", pll_comp_val);
	pr_debug("pll_plllock_cmp1 = 0x%llx, pll_plllock_cmp2 =%llx\n",
			pll_plllock_cmp1, pll_plllock_cmp2);
	pr_debug("pll_plllock_cmp3 = 0x%llx\n",	pll_plllock_cmp3);

	/* Assign to vco struct */
	vco_calc->div_frac_start1 = div_frac_start1;
	vco_calc->div_frac_start2 = div_frac_start2;
	vco_calc->div_frac_start3 = div_frac_start3;
	vco_calc->dec_start1 = dec_start1;
	vco_calc->dec_start2 = dec_start2;
	vco_calc->pll_plllock_cmp1 = pll_plllock_cmp1;
	vco_calc->pll_plllock_cmp2 = pll_plllock_cmp2;
	vco_calc->pll_plllock_cmp3 = pll_plllock_cmp3;
}

int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
{
	s64 vco_clk_rate = rate;
	struct mdss_pll_resources *dsi_pll_res = vco->priv;
	struct mdss_pll_vco_calc vco_calc;

	pr_debug("vco set rate: %lld\n", vco_clk_rate);
	pll_20nm_phy_config(vco);

	/* div fraction, start and comp calculations */
	pll_20nm_vco_rate_calc(vco, &vco_calc, vco_clk_rate);

	/* register programming*/
	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DIV_FRAC_START1,
			div_frac_start1);
			vco_calc.div_frac_start1);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DIV_FRAC_START2,
			div_frac_start2);
			vco_calc.div_frac_start2);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DIV_FRAC_START3,
			div_frac_start3);
			vco_calc.div_frac_start3);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DEC_START1,
			dec_start1);
			vco_calc.dec_start1);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DEC_START2,
			dec_start2);

	pll_comp_val = div_s64(dec_start_multiple * 2 * (duration - 1),
				10 * multiplier);

	pr_debug("%s: pll_comp_val = 0x%llx\n", __func__, pll_comp_val);

	pll_plllock_cmp1 = pll_comp_val & 0xff;
	pll_plllock_cmp2 = (pll_comp_val >> 8) & 0xff;
	pll_plllock_cmp3 = (pll_comp_val >> 16) & 0xff;
	pr_debug("%s: pll_plllock_cmp1 = 0x%llx\n",
				__func__, pll_plllock_cmp1);
	pr_debug("%s: pll_plllock_cmp2 = 0x%llx\n",
				__func__, pll_plllock_cmp2);
	pr_debug("%s: pll_plllock_cmp3 = 0x%llx\n",
				__func__, pll_plllock_cmp3);
			vco_calc.dec_start2);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_PLLLOCK_CMP1,
			pll_plllock_cmp1);
			vco_calc.pll_plllock_cmp1);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_PLLLOCK_CMP2,
			pll_plllock_cmp2);
			vco_calc.pll_plllock_cmp2);

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_PLLLOCK_CMP3,
			pll_plllock_cmp3);
			vco_calc.pll_plllock_cmp3);

	/*
	 * Make sure that PLL vco configuration is complete
@@ -576,6 +782,87 @@ int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
	return 0;
}

int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
		unsigned long rate)
{
	struct mdss_pll_resources *dsi_pll_res = vco->priv;
	struct mdss_pll_vco_calc vco_calc;
	s64 vco_clk_rate = rate;
	u32 rem;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}

	pr_debug("req vco set rate: %lld\n", vco_clk_rate);

	dsi_dfps_override_trim_codes(dsi_pll_res);
	/* div fraction, start and comp calculations */
	pll_20nm_vco_rate_calc(vco, &vco_calc, vco_clk_rate);

	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL0,
		MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
		MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN,
		0xB1, 0);
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL1,
		MMSS_DSI_PHY_PLL_PLLLOCK_CMP1,
		MMSS_DSI_PHY_PLL_PLLLOCK_CMP2,
		vco_calc.pll_plllock_cmp1, vco_calc.pll_plllock_cmp2);
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL2,
		MMSS_DSI_PHY_PLL_PLLLOCK_CMP3,
		MMSS_DSI_PHY_PLL_DEC_START1,
		vco_calc.pll_plllock_cmp3, vco_calc.dec_start1);
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL3,
		MMSS_DSI_PHY_PLL_DEC_START2,
		MMSS_DSI_PHY_PLL_DIV_FRAC_START1,
		vco_calc.dec_start2, vco_calc.div_frac_start1);
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL4,
		MMSS_DSI_PHY_PLL_DIV_FRAC_START2,
		MMSS_DSI_PHY_PLL_DIV_FRAC_START3,
		vco_calc.div_frac_start2, vco_calc.div_frac_start3);
	/* Method 2 - Auto PLL calibration */
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL7,
		MMSS_DSI_PHY_PLL_PLL_VCO_TUNE,
		MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN,
		0, 0x0D);
	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL8,
		MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL,
		MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
		0xF0, 0x07);

	/*
	 * RESETSM_CTRL3 has to be set for 12 times (6 reg writes),
	 * Each register setting write 2 times, running in loop for 5
	 * times (5 reg writes) and other two iterations are taken
	 * care (one above and other in shadow_bypass
	 */
	for (rem = 0; rem < 5; rem++) {
		MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
				MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL9 + (4 * rem),
				MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
				MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
				0x07, 0x07);
	}

	MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base,
		MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL15,
		MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
		MMSS_DSI_PHY_PLL_RESETSM_CNTRL3,
		0x03, 0x03);

	/* memory barrier */
	wmb();
	return 0;
}

unsigned long pll_20nm_vco_get_rate(struct clk *c)
{
	u64 vco_rate, multiplier = (1 << 20);
@@ -596,7 +883,7 @@ unsigned long pll_20nm_vco_get_rate(struct clk *c)
			MMSS_DSI_PHY_PLL_DEC_START2) & BIT(0)) << 7;
	dec_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DEC_START1) & 0x7f);
	pr_debug("%s: dec_start = 0x%x\n", __func__, dec_start);
	pr_debug("dec_start = 0x%x\n", dec_start);

	div_frac_start = (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DIV_FRAC_START3) & 0x3f) << 14;
@@ -604,13 +891,11 @@ unsigned long pll_20nm_vco_get_rate(struct clk *c)
			MMSS_DSI_PHY_PLL_DIV_FRAC_START2) & 0x7f) << 7;
	div_frac_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base,
			MMSS_DSI_PHY_PLL_DIV_FRAC_START1) & 0x7f;
	pr_debug("%s: div_frac_start = 0x%x\n",
			__func__, div_frac_start);
	pr_debug("div_frac_start = 0x%x\n", div_frac_start);

	vco_rate = ref_clk * 2 * dec_start;
	vco_rate += ((ref_clk * 2 * div_frac_start) / multiplier);
	pr_debug("%s: returning vco rate = %lu\n",
			__func__, (unsigned long)vco_rate);
	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);

	mdss_pll_resource_enable(dsi_pll_res, false);

+235 −2
Original line number Diff line number Diff line
@@ -31,6 +31,10 @@ static const struct clk_ops pixel_clk_src_ops;
static const struct clk_ops byte_clk_src_ops;
static const struct clk_ops ndiv_clk_ops;

static const struct clk_ops shadow_pixel_clk_src_ops;
static const struct clk_ops shadow_byte_clk_src_ops;
static const struct clk_ops clk_ops_gen_mux_dsi;

static int vco_set_rate_20nm(struct clk *c, unsigned long rate)
{
	int rc;
@@ -49,6 +53,22 @@ static int vco_set_rate_20nm(struct clk *c, unsigned long rate)
	return rc;
}

static int shadow_vco_set_rate_20nm(struct clk *c, unsigned long rate)
{
	int rc;
	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
	struct mdss_pll_resources *dsi_pll_res = vco->priv;

	if (!dsi_pll_res->resource_enable) {
		pr_err("PLL resources disabled. Dynamic fps invalid\n");
		return -EINVAL;
	}

	rc = shadow_pll_20nm_vco_set_rate(vco, rate);

	return rc;
}

static int dsi_pll_enable_seq_8994(struct mdss_pll_resources *dsi_pll_res)
{
	int rc = 0;
@@ -77,13 +97,17 @@ static int dsi_pll_enable_seq_8994(struct mdss_pll_resources *dsi_pll_res)
		rc = -EINVAL;
	} else {
		pr_debug("DSI PLL Lock success\n");
		/*
		 *  Following cached registers are useful when
		 *  dynamic refresh feature is enabled.
		 */
		dsi_cache_trim_codes(dsi_pll_res);
	}

	return rc;
}

/* Op structures */

static const struct clk_ops clk_ops_dsi_vco = {
	.set_rate = vco_set_rate_20nm,
	.round_rate = pll_20nm_vco_round_rate,
@@ -92,7 +116,6 @@ static const struct clk_ops clk_ops_dsi_vco = {
	.unprepare = pll_20nm_vco_unprepare,
};


static struct clk_div_ops fixed_hr_oclk2_div_ops = {
	.set_div = fixed_hr_oclk2_set_div,
	.get_div = fixed_hr_oclk2_get_div,
@@ -113,6 +136,42 @@ static struct clk_mux_ops bypass_lp_div_mux_ops = {
	.get_mux_sel = get_bypass_lp_div_mux_sel,
};

static const struct clk_ops shadow_clk_ops_dsi_vco = {
	.set_rate = shadow_vco_set_rate_20nm,
	.round_rate = pll_20nm_vco_round_rate,
	.handoff = pll_20nm_vco_handoff,
};

static struct clk_div_ops shadow_fixed_hr_oclk2_div_ops = {
	.set_div = shadow_fixed_hr_oclk2_set_div,
	.get_div = fixed_hr_oclk2_get_div,
};

static struct clk_div_ops shadow_ndiv_ops = {
	.set_div = shadow_ndiv_set_div,
	.get_div = ndiv_get_div,
};

static struct clk_div_ops shadow_hr_oclk3_div_ops = {
	.set_div = shadow_hr_oclk3_set_div,
	.get_div = hr_oclk3_get_div,
};

static struct clk_mux_ops shadow_bypass_lp_div_mux_ops = {
	.set_mux_sel = set_shadow_bypass_lp_div_mux_sel,
	.get_mux_sel = get_bypass_lp_div_mux_sel,
};

static struct clk_mux_ops mdss_byte_mux_ops = {
	.set_mux_sel = set_mdss_byte_mux_sel,
	.get_mux_sel = get_mdss_byte_mux_sel,
};

static struct clk_mux_ops mdss_pixel_mux_ops = {
	.set_mux_sel = set_mdss_pixel_mux_sel,
	.get_mux_sel = get_mdss_pixel_mux_sel,
};

static struct dsi_pll_vco_clk dsi_vco_clk_8994 = {
	.ref_clk_rate = 19200000,
	.min_rate = 1000000000,
@@ -126,6 +185,17 @@ static struct dsi_pll_vco_clk dsi_vco_clk_8994 = {
	},
};

static struct dsi_pll_vco_clk shadow_dsi_vco_clk_8994 = {
	.ref_clk_rate = 19200000,
	.min_rate = 1000000000,
	.max_rate = 2000000000,
	.c = {
		.dbg_name = "shadow_dsi_vco_clk_8994",
		.ops = &shadow_clk_ops_dsi_vco,
		CLK_INIT(shadow_dsi_vco_clk_8994.c),
	},
};

static struct div_clk ndiv_clk_8994 = {
	.data = {
		.max_div = 15,
@@ -141,6 +211,21 @@ static struct div_clk ndiv_clk_8994 = {
	},
};

static struct div_clk shadow_ndiv_clk_8994 = {
	.data = {
		.max_div = 15,
		.min_div = 1,
	},
	.ops = &shadow_ndiv_ops,
	.c = {
		.parent = &shadow_dsi_vco_clk_8994.c,
		.dbg_name = "shadow_ndiv_clk_8994",
		.ops = &clk_ops_div,
		.flags = CLKFLAG_NO_RATE_CACHE,
		CLK_INIT(shadow_ndiv_clk_8994.c),
	},
};

static struct div_clk indirect_path_div2_clk_8994 = {
	.data = {
		.div = 2,
@@ -156,6 +241,21 @@ static struct div_clk indirect_path_div2_clk_8994 = {
	},
};

static struct div_clk shadow_indirect_path_div2_clk_8994 = {
	.data = {
		.div = 2,
		.min_div = 2,
		.max_div = 2,
	},
	.c = {
		.parent = &shadow_ndiv_clk_8994.c,
		.dbg_name = "shadow_indirect_path_div2_clk_8994",
		.ops = &clk_ops_div,
		.flags = CLKFLAG_NO_RATE_CACHE,
		CLK_INIT(shadow_indirect_path_div2_clk_8994.c),
	},
};

static struct div_clk hr_oclk3_div_clk_8994 = {
	.data = {
		.max_div = 255,
@@ -171,6 +271,21 @@ static struct div_clk hr_oclk3_div_clk_8994 = {
	},
};

static struct div_clk shadow_hr_oclk3_div_clk_8994 = {
	.data = {
		.max_div = 255,
		.min_div = 1,
	},
	.ops = &shadow_hr_oclk3_div_ops,
	.c = {
		.parent = &shadow_dsi_vco_clk_8994.c,
		.dbg_name = "shadow_hr_oclk3_div_clk_8994",
		.ops = &shadow_pixel_clk_src_ops,
		.flags = CLKFLAG_NO_RATE_CACHE,
		CLK_INIT(shadow_hr_oclk3_div_clk_8994.c),
	},
};

static struct div_clk pixel_clk_src = {
	.data = {
		.div = 2,
@@ -186,6 +301,21 @@ static struct div_clk pixel_clk_src = {
	},
};

static struct div_clk shadow_pixel_clk_src = {
	.data = {
		.div = 2,
		.min_div = 2,
		.max_div = 2,
	},
	.c = {
		.parent = &shadow_hr_oclk3_div_clk_8994.c,
		.dbg_name = "shadow_pixel_clk_src",
		.ops = &clk_ops_div,
		.flags = CLKFLAG_NO_RATE_CACHE,
		CLK_INIT(shadow_pixel_clk_src.c),
	},
};

static struct mux_clk bypass_lp_div_mux_8994 = {
	.num_parents = 2,
	.parents = (struct clk_src[]){
@@ -201,6 +331,21 @@ static struct mux_clk bypass_lp_div_mux_8994 = {
	},
};

static struct mux_clk shadow_bypass_lp_div_mux_8994 = {
	.num_parents = 2,
	.parents = (struct clk_src[]){
		{&shadow_dsi_vco_clk_8994.c, 0},
		{&shadow_indirect_path_div2_clk_8994.c, 1},
	},
	.ops = &shadow_bypass_lp_div_mux_ops,
	.c = {
		.parent = &shadow_dsi_vco_clk_8994.c,
		.dbg_name = "shadow_bypass_lp_div_mux_8994",
		.ops = &clk_ops_gen_mux,
		CLK_INIT(shadow_bypass_lp_div_mux_8994.c),
	},
};

static struct div_clk fixed_hr_oclk2_div_clk_8994 = {
	.ops = &fixed_hr_oclk2_div_ops,
	.data = {
@@ -215,6 +360,20 @@ static struct div_clk fixed_hr_oclk2_div_clk_8994 = {
	},
};

static struct div_clk shadow_fixed_hr_oclk2_div_clk_8994 = {
	.ops = &shadow_fixed_hr_oclk2_div_ops,
	.data = {
		.min_div = 4,
		.max_div = 4,
	},
	.c = {
		.parent = &shadow_bypass_lp_div_mux_8994.c,
		.dbg_name = "shadow_fixed_hr_oclk2_div_clk_8994",
		.ops = &shadow_byte_clk_src_ops,
		CLK_INIT(shadow_fixed_hr_oclk2_div_clk_8994.c),
	},
};

static struct div_clk byte_clk_src = {
	.data = {
		.div = 2,
@@ -229,7 +388,53 @@ static struct div_clk byte_clk_src = {
	},
};

static struct div_clk shadow_byte_clk_src = {
	.data = {
		.div = 2,
		.min_div = 2,
		.max_div = 2,
	},
	.c = {
		.parent = &shadow_fixed_hr_oclk2_div_clk_8994.c,
		.dbg_name = "shadow_byte_clk_src",
		.ops = &clk_ops_div,
		CLK_INIT(shadow_byte_clk_src.c),
	},
};

static struct mux_clk mdss_pixel_clk_mux = {
	.num_parents = 2,
	.parents = (struct clk_src[]) {
		{&pixel_clk_src.c, 0},
		{&shadow_pixel_clk_src.c, 1},
	},
	.ops = &mdss_pixel_mux_ops,
	.c = {
		.parent = &pixel_clk_src.c,
		.dbg_name = "mdss_pixel_clk_mux",
		.ops = &clk_ops_gen_mux,
		CLK_INIT(mdss_pixel_clk_mux.c),
	}
};

static struct mux_clk mdss_byte_clk_mux = {
	.num_parents = 2,
	.parents = (struct clk_src[]) {
		{&byte_clk_src.c, 0},
		{&shadow_byte_clk_src.c, 1},
	},
	.ops = &mdss_byte_mux_ops,
	.c = {
		.parent = &byte_clk_src.c,
		.dbg_name = "mdss_byte_clk_mux",
		.ops = &clk_ops_gen_mux_dsi,
		CLK_INIT(mdss_byte_clk_mux.c),
	}
};

static struct clk_lookup mdss_dsi_pllcc_8994[] = {
	CLK_LIST(mdss_pixel_clk_mux),
	CLK_LIST(mdss_byte_clk_mux),
	CLK_LIST(pixel_clk_src),
	CLK_LIST(byte_clk_src),
	CLK_LIST(fixed_hr_oclk2_div_clk_8994),
@@ -238,6 +443,14 @@ static struct clk_lookup mdss_dsi_pllcc_8994[] = {
	CLK_LIST(indirect_path_div2_clk_8994),
	CLK_LIST(ndiv_clk_8994),
	CLK_LIST(dsi_vco_clk_8994),
	CLK_LIST(shadow_pixel_clk_src),
	CLK_LIST(shadow_byte_clk_src),
	CLK_LIST(shadow_fixed_hr_oclk2_div_clk_8994),
	CLK_LIST(shadow_bypass_lp_div_mux_8994),
	CLK_LIST(shadow_hr_oclk3_div_clk_8994),
	CLK_LIST(shadow_indirect_path_div2_clk_8994),
	CLK_LIST(shadow_ndiv_clk_8994),
	CLK_LIST(shadow_dsi_vco_clk_8994),
};

int dsi_pll_clock_register_20nm(struct platform_device *pdev,
@@ -264,6 +477,16 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev,
	fixed_hr_oclk2_div_clk_8994.priv = pll_res;
	hr_oclk3_div_clk_8994.priv = pll_res;
	dsi_vco_clk_8994.priv = pll_res;

	shadow_byte_clk_src.priv = pll_res;
	shadow_pixel_clk_src.priv = pll_res;
	shadow_bypass_lp_div_mux_8994.priv = pll_res;
	shadow_indirect_path_div2_clk_8994.priv = pll_res;
	shadow_ndiv_clk_8994.priv = pll_res;
	shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res;
	shadow_hr_oclk3_div_clk_8994.priv = pll_res;
	shadow_dsi_vco_clk_8994.priv = pll_res;

	pll_res->vco_delay = VCO_DELAY_USEC;

	/* Set clock source operations */
@@ -279,6 +502,16 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev,
	bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
	bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;

	clk_ops_gen_mux_dsi = clk_ops_gen_mux;
	clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
	clk_ops_gen_mux_dsi.set_rate = parent_set_rate;

	shadow_pixel_clk_src_ops = clk_ops_slave_div;
	shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare;

	shadow_byte_clk_src_ops = clk_ops_div;
	shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;

	if (pll_res->target_id == MDSS_PLL_TARGET_8994) {
		rc = of_msm_clock_register(pdev->dev.of_node,
			mdss_dsi_pllcc_8994, ARRAY_SIZE(mdss_dsi_pllcc_8994));
+12 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ void vco_unprepare(struct clk *c);

/* APIs for 20nm PHY PLL */
int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
				unsigned long rate);
long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
enum handoff pll_20nm_vco_handoff(struct clk *c);
int pll_20nm_vco_prepare(struct clk *c);
@@ -86,12 +88,22 @@ void pll_20nm_vco_unprepare(struct clk *c);
int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);

int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
int fixed_hr_oclk2_get_div(struct div_clk *clk);
int hr_oclk3_set_div(struct div_clk *clk, int div);
int shadow_hr_oclk3_set_div(struct div_clk *clk, int div);
int hr_oclk3_get_div(struct div_clk *clk);
int ndiv_set_div(struct div_clk *clk, int div);
int shadow_ndiv_set_div(struct div_clk *clk, int div);
int ndiv_get_div(struct div_clk *clk);

int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
int get_mdss_pixel_mux_sel(struct mux_clk *clk);
int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel);
int get_mdss_byte_mux_sel(struct mux_clk *clk);
void dsi_cache_trim_codes(struct mdss_pll_resources *dsi_pll_res);

#endif
+29 −1

File changed.

Preview size limit exceeded, changes collapsed.