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

Commit e26434bc authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: clock-mdss-8974: Dynamic HDMI PHY-PLL configuration"

parents 07af3c2c 93bcf7fc
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -5188,25 +5188,18 @@ static struct branch_clk mdss_pclk1_clk = {
};

static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
	F_MM( 25200000, hdmipll, 1, 0, 0),
	F_MM( 27000000, hdmipll, 1, 0, 0),
	F_MM( 27030000, hdmipll, 1, 0, 0),
	F_MM( 65000000, hdmipll, 1, 0, 0),
	F_MM( 74250000, hdmipll, 1, 0, 0),
	F_MM(108000000, hdmipll, 1, 0, 0),
	F_MM(148500000, hdmipll, 1, 0, 0),
	F_MM(268500000, hdmipll, 1, 0, 0),
	F_MM(297000000, hdmipll, 1, 0, 0),
	F_END
};

static struct rcg_clk extpclk_clk_src = {
	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
	.freq_tbl = ftbl_mdss_extpclk_clk,
	.current_freq = &rcg_dummy_freq,
	.current_freq = ftbl_mdss_extpclk_clk,
	.base = &virt_bases[MMSS_BASE],
	.c = {
		.dbg_name = "extpclk_clk_src",
		.parent = &hdmipll_clk_src.c,
		.ops = &clk_ops_rcg_hdmi,
		VDD_DIG_FMAX_MAP2(LOW, 150000000, NOMINAL, 297000000),
		CLK_INIT(extpclk_clk_src.c),
+3 −21
Original line number Diff line number Diff line
@@ -580,17 +580,6 @@ static void __iomem *virt_bases[N_BASES];
			| BVAL(10, 8, s##_mm_source_val), \
	}

#define F_HDMI(f, s, div, m, n) \
	{ \
		.freq_hz = (f), \
		.src_clk = &s##_clk_src.c, \
		.m_val = (m), \
		.n_val = ~((n)-(m)) * !!(n), \
		.d_val = ~(n),\
		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
			| BVAL(10, 8, s##_mm_source_val), \
	}

#define F_EDP(f, s, div, m, n) \
	{ \
		.freq_hz = (f), \
@@ -3271,25 +3260,18 @@ static struct rcg_clk esc1_clk_src = {
};

static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
	F_HDMI( 25200000, hdmipll, 1, 0, 0),
	F_HDMI( 27000000, hdmipll, 1, 0, 0),
	F_HDMI( 27030000, hdmipll, 1, 0, 0),
	F_HDMI( 65000000, hdmipll, 1, 0, 0),
	F_HDMI( 74250000, hdmipll, 1, 0, 0),
	F_HDMI(108000000, hdmipll, 1, 0, 0),
	F_HDMI(148500000, hdmipll, 1, 0, 0),
	F_HDMI(268500000, hdmipll, 1, 0, 0),
	F_HDMI(297000000, hdmipll, 1, 0, 0),
	F_MM(148500000, hdmipll, 1, 0, 0),
	F_END
};

static struct rcg_clk extpclk_clk_src = {
	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
	.freq_tbl = ftbl_mdss_extpclk_clk,
	.current_freq = &rcg_dummy_freq,
	.current_freq = ftbl_mdss_extpclk_clk,
	.base = &virt_bases[MMSS_BASE],
	.c = {
		.dbg_name = "extpclk_clk_src",
		.parent = &hdmipll_clk_src.c,
		.ops = &clk_ops_rcg_hdmi,
		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
		CLK_INIT(extpclk_clk_src.c),
+34 −2
Original line number Diff line number Diff line
@@ -1034,6 +1034,38 @@ static int set_rate_pixel(struct clk *clk, unsigned long rate)
 * re-programming. It is also routed through an HID divider.
 */
static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
{
	struct rcg_clk *rcg = to_rcg_clk(c);
	struct clk_freq_tbl *nf = rcg->freq_tbl;
	int rc;

	rc = clk_set_rate(nf->src_clk, rate);
	if (rc < 0)
		goto out;
	set_rate_hid(rcg, nf);

	rcg->current_freq = nf;
out:
	return rc;
}

static struct clk *rcg_hdmi_clk_get_parent(struct clk *c)
{
	struct rcg_clk *rcg = to_rcg_clk(c);
	struct clk_freq_tbl *freq = rcg->freq_tbl;
	u32 cmd_rcgr_regval;

	/* Is there a pending configuration? */
	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
	if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
		return NULL;

	rcg->current_freq->freq_hz = clk_get_rate(c->parent);

	return freq->src_clk;
}

static int rcg_clk_set_rate_edp(struct clk *c, unsigned long rate)
{
	struct clk_freq_tbl *nf;
	struct rcg_clk *rcg = to_rcg_clk(c);
@@ -1272,13 +1304,13 @@ struct clk_ops clk_ops_rcg_hdmi = {
	.list_rate = rcg_clk_list_rate,
	.round_rate = rcg_clk_round_rate,
	.handoff = rcg_clk_handoff,
	.get_parent = rcg_clk_get_parent,
	.get_parent = rcg_hdmi_clk_get_parent,
	.list_registers = rcg_hid_clk_list_registers,
};

struct clk_ops clk_ops_rcg_edp = {
	.enable = rcg_clk_prepare,
	.set_rate = rcg_clk_set_rate_hdmi,
	.set_rate = rcg_clk_set_rate_edp,
	.list_rate = rcg_clk_list_rate,
	.round_rate = rcg_clk_round_rate,
	.handoff = rcg_clk_handoff,
+190 −25
Original line number Diff line number Diff line
@@ -291,6 +291,140 @@ static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk)
	return container_of(clk, struct hdmi_pll_vco_clk, c);
}

static void hdmi_phy_pll_calculator(u32 vco_freq)
{
	u32 ref_clk             = 19200000;
	u32 sdm_mode            = 1;
	u32 ref_clk_multiplier  = sdm_mode == 1 ? 2 : 1;
	u32 int_ref_clk_freq    = ref_clk * ref_clk_multiplier;
	u32 fbclk_pre_div       = 1;
	u32 ssc_mode            = 0;
	u32 kvco                = 270;
	u32 vdd                 = 95;
	u32 ten_power_six       = 1000000;
	u32 ssc_ds_ppm          = ssc_mode ? 5000 : 0;
	u32 sdm_res             = 16;
	u32 ssc_tri_step        = 32;
	u32 ssc_freq            = 2;
	u64 ssc_ds              = vco_freq * ssc_ds_ppm;
	u32 div_in_freq         = vco_freq / fbclk_pre_div;
	u64 dc_offset           = (div_in_freq / int_ref_clk_freq - 1) *
					ten_power_six * 10;
	u32 ssc_kdiv            = (int_ref_clk_freq / ssc_freq) -
					ten_power_six;
	u64 sdm_freq_seed;
	u32 ssc_tri_inc;
	u64 fb_div_n;

	u32 val;

	pr_debug("%s: vco_freq = %u\n", __func__, vco_freq);

	do_div(ssc_ds, (u64)ten_power_six);

	fb_div_n = (u64)div_in_freq * (u64)ten_power_six * 10;
	do_div(fb_div_n, int_ref_clk_freq);

	sdm_freq_seed = ((fb_div_n - dc_offset - ten_power_six * 10) *
				(1 << sdm_res)  * 10) + 5;
	do_div(sdm_freq_seed, ((u64)ten_power_six * 100));

	ssc_tri_inc = (u32)ssc_ds;
	ssc_tri_inc = (ssc_tri_inc / int_ref_clk_freq) * (1 << 16) /
			ssc_tri_step;

	val = (ref_clk_multiplier == 2 ? 1 : 0) +
		((fbclk_pre_div == 2 ? 1 : 0) * 16);
	pr_debug("%s: HDMI_UNI_PLL_REFCLK_CFG = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);

	REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CHFPUMP_CFG);
	REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
	REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_PWRGEN_CFG);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
	REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
	REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
	REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);

	do_div(dc_offset, (u64)ten_power_six * 10);
	val = sdm_mode == 0 ? 64 + dc_offset : 0;
	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG0 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);

	val = 64 + dc_offset;
	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG1 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);

	val = sdm_freq_seed & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG2 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);

	val = (sdm_freq_seed >> 8) & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG3 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);

	val = (sdm_freq_seed >> 16) & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG4 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);

	val = (ssc_mode == 0 ? 128 : 0) + (ssc_kdiv / ten_power_six);
	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG0 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG0);

	val = ssc_tri_inc & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG1 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG1);

	val = (ssc_tri_inc >> 8) & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG2 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG2);

	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG3 = 0x%x\n", __func__, ssc_tri_step);
	REG_W(ssc_tri_step, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG3);

	REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
	REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
	REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
	REG_W(0x0A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG0);
	REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG1);
	REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG3);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG4);
	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG5);

	val = (kvco * vdd * 10000) / 6;
	val += 500000;
	val /= ten_power_six;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG6 = 0x%x\n", __func__, val);
	REG_W(val & 0xFF, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG6);

	val = (kvco * vdd * 10000) / 6;
	val -= ten_power_six;
	val /= ten_power_six;
	val = (val >> 8) & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG7 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG7);

	val = (ref_clk * 5) / ten_power_six;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG8 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);

	val = ((ref_clk * 5) / ten_power_six) >> 8;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG9 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);

	vco_freq /= ten_power_six;
	val = vco_freq & 0xFF;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG10 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);

	val = vco_freq >> 8;
	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG11 = 0x%x\n", __func__, val);
	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
} /* hdmi_phy_pll_calculator */

static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
{
	unsigned int set_power_dwn = 0;
@@ -313,6 +447,9 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
	pr_debug("%s: rate=%ld\n", __func__, rate);

	switch (rate) {
	case 0:
		break;

	case 756000000:
		/* 640x480p60 */
		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
@@ -663,7 +800,52 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
	break;

	default:
		pr_err("%s: not supported rate=%ld\n", __func__, rate);
		pr_debug("%s: Use pll settings calculator for rate=%ld\n",
			__func__, rate);

		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
		hdmi_phy_pll_calculator(rate);
		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
		udelay(50);

		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);

		if (rate < 825000000) {
			REG_W(0x01, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
			REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
		} else if (rate >= 825000000 && rate < 1342500000) {
			REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
			REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
		} else {
			REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
			REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
		}

		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);

		if (rate < 825000000)
			REG_W(0x01, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
		else
			REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);

		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
		REG_W(0x62, hdmi_phy_base + HDMI_PHY_BIST_PATN0);
		REG_W(0x03, hdmi_phy_base + HDMI_PHY_BIST_PATN1);
		REG_W(0x69, hdmi_phy_base + HDMI_PHY_BIST_PATN2);
		REG_W(0x02, hdmi_phy_base + HDMI_PHY_BIST_PATN3);

		udelay(200);

		REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG1);
		REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG0);
	}

	/* Make sure writes complete before disabling iface clock */
@@ -2404,17 +2586,13 @@ static unsigned long hdmi_vco_get_rate(struct clk *c)

static long hdmi_vco_round_rate(struct clk *c, unsigned long rate)
{
	unsigned long rrate = rate;
	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
	unsigned long rrate = 0;
	unsigned long *lp = vco->rate_list;

	while (*lp) {
		rrate = *lp;

		if (rate <= rrate)
			break;
		lp++;
	}
	if (rate < vco->min_rate)
		rrate = vco->min_rate;
	if (rate > vco->max_rate)
		rrate = vco->max_rate;

	pr_debug("%s: rrate=%ld\n", __func__, rrate);

@@ -2486,20 +2664,6 @@ static enum handoff hdmi_vco_handoff(struct clk *c)
	return ret;
}

/* Should be in increasing order */
static unsigned long hdmi_vco_rate_list[] = {
	 650000000,
	 742500000,
	 756000000,
	 810000000,
	 810900000,
	1080000000,
	1342500000,
	1485000000,
		 0
};


static struct clk_ops hdmi_vco_clk_ops = {
	.enable = hdmi_vco_enable,
	.set_rate = hdmi_vco_set_rate,
@@ -2512,7 +2676,8 @@ static struct clk_ops hdmi_vco_clk_ops = {
};

static struct hdmi_pll_vco_clk hdmi_vco_clk = {
	.rate_list = hdmi_vco_rate_list,
	.min_rate = 600000000,
	.max_rate = 1800000000,
	.c = {
		.dbg_name = "hdmi_vco_clk",
		.ops = &hdmi_vco_clk_ops,
+3 −2
Original line number Diff line number Diff line
@@ -32,8 +32,9 @@ struct edp_pll_vco_clk {
};

struct hdmi_pll_vco_clk {
	unsigned long rate;	/* vco rate */
	unsigned long *rate_list;
	unsigned long rate;	/* current vco rate */
	unsigned long min_rate;	/* min vco rate */
	unsigned long max_rate;	/* max vco rate */
	bool rate_set;

	struct clk c;