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

Commit 0abe33a2 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: mdss: shutdown 20nm PHY pll properly to fix power issue" into msm-4.8

parents bd996817 a91de84b
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -481,6 +481,19 @@ int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res)
	return pll_locked;
}

void __dsi_pll_disable(void __iomem *pll_base)
{
	if (!pll_base) {
		pr_err("Invalid pll base\n");
		return;
	}
	pr_debug("Disabling PHY PLL for PLL_BASE=%p\n", pll_base);

	MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x042);
	MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x02);
	MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02);
}

static int dsi_pll_enable(struct clk *c)
{
	int i, rc;
@@ -501,6 +514,9 @@ static int dsi_pll_enable(struct clk *c)
		if (!rc)
			break;
	}
	/* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */
	if (dsi_pll_res->pll_1_base)
		__dsi_pll_disable(dsi_pll_res->pll_1_base);

	if (rc) {
		mdss_pll_resource_enable(dsi_pll_res, false);
@@ -524,8 +540,11 @@ static void dsi_pll_disable(struct clk *c)

	dsi_pll_res->handoff_resources = false;

	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
				MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x02);
	__dsi_pll_disable(dsi_pll_res->pll_base);

	/* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */
	if (dsi_pll_res->pll_1_base)
		__dsi_pll_disable(dsi_pll_res->pll_1_base);

	mdss_pll_resource_enable(dsi_pll_res, false);
	dsi_pll_res->pll_on = false;
@@ -779,6 +798,8 @@ int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
	udelay(1000);
	/* memory barrier */
	wmb();
	if (dsi_pll_res->pll_1_base)
		__dsi_pll_disable(dsi_pll_res->pll_1_base);
	return 0;
}

+62 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/clk/msm-clk-provider.h>
#include <linux/clk/msm-clk.h>
#include <linux/workqueue.h>
#include <linux/clk/msm-clock-generic.h>
#include <dt-bindings/clock/msm-clocks-8994.h>

@@ -47,6 +48,8 @@ static int vco_set_rate_20nm(struct clk *c, unsigned long rate)
		return rc;
	}

	pr_debug("Cancel pending pll off work\n");
	cancel_work_sync(&dsi_pll_res->pll_off);
	rc = pll_20nm_vco_set_rate(vco, rate);

	mdss_pll_resource_enable(dsi_pll_res, false);
@@ -453,10 +456,58 @@ static struct clk_lookup mdss_dsi_pllcc_8994[] = {
	CLK_LIST(shadow_dsi_vco_clk_8994),
};

static void dsi_pll_off_work(struct work_struct *work)
{
	struct mdss_pll_resources *pll_res;

	if (!work) {
		pr_err("pll_resource is invalid\n");
		return;
	}

	pr_debug("Starting PLL off Worker%s\n", __func__);

	pll_res = container_of(work, struct
			mdss_pll_resources, pll_off);

	mdss_pll_resource_enable(pll_res, true);
	__dsi_pll_disable(pll_res->pll_base);
	if (pll_res->pll_1_base)
		__dsi_pll_disable(pll_res->pll_1_base);
	mdss_pll_resource_enable(pll_res, false);
}

static int dsi_pll_regulator_notifier_call(struct notifier_block *self,
		unsigned long event, void *data)
{

	struct mdss_pll_resources *pll_res;

	if (!self) {
		pr_err("pll_resource is invalid\n");
		goto error;
	}

	pll_res = container_of(self, struct
			mdss_pll_resources, gdsc_cb);

	if (event & REGULATOR_EVENT_ENABLE) {
		pr_debug("Regulator ON event. Scheduling pll off worker\n");
		schedule_work(&pll_res->pll_off);
	}

	if (event & REGULATOR_EVENT_DISABLE)
		pr_debug("Regulator OFF event.\n");

error:
	return NOTIFY_OK;
}

int dsi_pll_clock_register_20nm(struct platform_device *pdev,
				struct mdss_pll_resources *pll_res)
{
	int rc;
	struct dss_vreg *pll_reg;

	if (!pdev || !pdev->dev.of_node) {
		pr_err("Invalid input parameters\n");
@@ -513,12 +564,23 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev,
	shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;

	if (pll_res->target_id == MDSS_PLL_TARGET_8994) {
		pll_res->gdsc_cb.notifier_call =
			dsi_pll_regulator_notifier_call;
		INIT_WORK(&pll_res->pll_off, dsi_pll_off_work);

		rc = of_msm_clock_register(pdev->dev.of_node,
			mdss_dsi_pllcc_8994, ARRAY_SIZE(mdss_dsi_pllcc_8994));
		if (rc) {
			pr_err("Clock register failed\n");
			rc = -EPROBE_DEFER;
		}
		pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc");
		if (pll_reg) {
			pr_debug("Registering for gdsc regulator events\n");
			if (regulator_register_notifier(pll_reg->vreg,
						&(pll_res->gdsc_cb)))
				pr_err("Regulator notification registration failed!\n");
		}
	} else {
		pr_err("Invalid target ID\n");
		rc = -EINVAL;
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ 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);
void __dsi_pll_disable(void __iomem *pll_base);

int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
int get_mdss_pixel_mux_sel(struct mux_clk *clk);
+34 −0
Original line number Diff line number Diff line
@@ -47,6 +47,40 @@ int mdss_pll_util_resource_init(struct platform_device *pdev,
	return rc;
}

/**
 * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name
 *@pll_res: Pointer to the PLL resource
 *@name: Regulator name as specified in the pll dtsi
 *
 * This is a helper function to retrieve the regulator information
 * for each pll resource.
 */
struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
		, char *name)
{

	struct dss_vreg *regulator = NULL;
	int i;

	if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) {
		pr_err("%s Invalid PLL resource\n", __func__);
		goto error;
	}

	regulator = pll_res->mp.vreg_config;

	for (i = 0; i < pll_res->mp.num_vreg; i++) {
		if (!strcmp(name, regulator->vreg_name)) {
			pr_debug("Found regulator match for %s\n", name);
			break;
		}
		regulator++;
	}

error:
	return regulator;
}

void mdss_pll_util_resource_deinit(struct platform_device *pdev,
					 struct mdss_pll_resources *pll_res)
{
+22 −0
Original line number Diff line number Diff line
@@ -249,6 +249,26 @@ static int mdss_pll_probe(struct platform_device *pdev)
		goto res_parse_error;
	}

	/*
	 * DSI PLL 1 is leaking current whenever MDSS GDSC is toggled. Need to
	 * map PLL1 registers along with the PLl0 so that we can manually turn
	 * off PLL1.
	 */
	if (pll_res->pll_interface_type == MDSS_DSI_PLL_20NM) {
		struct resource *pll_1_base_reg;

		pll_1_base_reg = platform_get_resource_byname(pdev,
				IORESOURCE_MEM, "pll_1_base");
		if (pll_1_base_reg) {
			pll_res->pll_1_base = ioremap(pll_1_base_reg->start,
					resource_size(pll_1_base_reg));
			if (!pll_res->pll_1_base)
				pr_err("Unable to remap pll 1 base resources\n");
		} else {
			pr_err("Unable to get the pll 1 base resource\n");
		}
	}

	phy_base_reg = platform_get_resource_byname(pdev,
						IORESOURCE_MEM, "phy_base");
	if (!phy_base_reg) {
@@ -303,6 +323,8 @@ static int mdss_pll_probe(struct platform_device *pdev)
	if (pll_res->phy_base)
		iounmap(pll_res->phy_base);
phy_io_error:
	if (pll_res->pll_1_base)
		iounmap(pll_res->pll_1_base);
	mdss_pll_resource_release(pdev, pll_res);
res_parse_error:
	iounmap(pll_res->pll_base);
Loading