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

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

Merge "clk: msm : Add clock-gcc-8952 driver snapshot"

parents cd27a252 c9ccd352
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -11,23 +11,16 @@ obj-$(CONFIG_MSM_CLK_CONTROLLER_V2) += msm-clock-controller.o

obj-$(CONFIG_DEBUG_FS)		+= clock-debug.o

# MSM8916
obj-$(CONFIG_ARCH_MSM8916)	+= clock-rpm-8916.o
obj-$(CONFIG_ARCH_MSM8916)	+= clock-gcc-8916.o

# MSM 8996
obj-$(CONFIG_ARCH_MSM8996)	+= clock-gcc-8996.o
obj-$(CONFIG_ARCH_MSM8996)	+= clock-mmss-8996.o
obj-$(CONFIG_ARCH_MSM8996)	+= clock-cpu-8996.o

# MSM8936
obj-$(CONFIG_ARCH_MSM8916)	+= clock-rpm-8936.o
obj-$(CONFIG_ARCH_MSM8916)	+= clock-gcc-8936.o

# ACPU clock
obj-$(CONFIG_ARCH_MSM8916)	+= clock-a7.o
obj-$(CONFIG_ARCH_MSM8916)	+= clock-cpu-8939.o
obj-$(CONFIG_ARCH_MSM8916)	+= clock-cpu-8936.o
obj-$(CONFIG_ARCH_MSM8916)	+= clock-gcc-8952.o


obj-y				+= gdsc.o
obj-y				+= mdss/
+38 −23
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <linux/of_platform.h>
#include <linux/pm_opp.h>
#include <soc/qcom/clock-local2.h>
#include <dt-bindings/clock/msm-clocks-a7.h>

#include "clock.h"

@@ -54,18 +55,15 @@ static struct mux_div_clk a7ssmux = {
};

static struct clk_lookup clock_tbl_a7[] = {
	CLK_LOOKUP("cpu0_clk",	a7ssmux.c, "0.qcom,msm-cpufreq"),
	CLK_LOOKUP("cpu1_clk",	a7ssmux.c, "0.qcom,msm-cpufreq"),
	CLK_LOOKUP("cpu2_clk",	a7ssmux.c, "0.qcom,msm-cpufreq"),
	CLK_LOOKUP("cpu3_clk",	a7ssmux.c, "0.qcom,msm-cpufreq"),
	CLK_LOOKUP("cpu0_clk",	a7ssmux.c, "fe805664.qcom,pm"),
	CLK_LOOKUP("cpu1_clk",	a7ssmux.c, "fe805664.qcom,pm"),
	CLK_LOOKUP("cpu2_clk",	a7ssmux.c, "fe805664.qcom,pm"),
	CLK_LOOKUP("cpu3_clk",	a7ssmux.c, "fe805664.qcom,pm"),
	CLK_LOOKUP("cpu0_clk",   a7ssmux.c, "8600664.qcom,pm"),
	CLK_LOOKUP("cpu1_clk",   a7ssmux.c, "8600664.qcom,pm"),
	CLK_LOOKUP("cpu2_clk",   a7ssmux.c, "8600664.qcom,pm"),
	CLK_LOOKUP("cpu3_clk",   a7ssmux.c, "8600664.qcom,pm"),
	CLK_LIST(a7ssmux),
	CLK_LOOKUP_OF("cpu0_clk",	a7ssmux, "fe805664.qcom,pm"),
	CLK_LOOKUP_OF("cpu1_clk",	a7ssmux, "fe805664.qcom,pm"),
	CLK_LOOKUP_OF("cpu2_clk",	a7ssmux, "fe805664.qcom,pm"),
	CLK_LOOKUP_OF("cpu3_clk",	a7ssmux, "fe805664.qcom,pm"),
	CLK_LOOKUP_OF("cpu0_clk",   a7ssmux, "8600664.qcom,pm"),
	CLK_LOOKUP_OF("cpu1_clk",   a7ssmux, "8600664.qcom,pm"),
	CLK_LOOKUP_OF("cpu2_clk",   a7ssmux, "8600664.qcom,pm"),
	CLK_LOOKUP_OF("cpu3_clk",   a7ssmux, "8600664.qcom,pm"),
};

static void print_opp_table(int a7_cpu)
@@ -282,19 +280,35 @@ static void get_speed_bin_b(struct platform_device *pdev, int *bin,
	*bin = 0;
	*version = 0;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
	if (res) {
		base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
		if (base) {
			pte_efuse = readl_relaxed(base);
			devm_iounmap(&pdev->dev, base);

			*version = (pte_efuse >> 18) & 0x3;
			if (!(*version)) {
				if (*bin) {
					*bin = (pte_efuse >> 23) & 0x3;
					dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n",
						*bin, *version);
					return;
				}
			}
		} else {
			dev_warn(&pdev->dev,
				"Unable to read efuse1 data. Defaulting to 0!\n");
			return;
		}
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
	if (!res) {
		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
								"efuse1");
	if (!res) {
		dev_info(&pdev->dev,
				"No speed/PVS binning available. Defaulting to 0!\n");
		return;
	}
		shift = 23;
		mask  = 0x3;
	}

	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (!base) {
		dev_warn(&pdev->dev,
@@ -412,7 +426,8 @@ static int clock_a7_probe(struct platform_device *pdev)
		dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
	}

	rc = msm_clock_register(clock_tbl_a7, ARRAY_SIZE(clock_tbl_a7));
	rc = of_msm_clock_register(pdev->dev.of_node,
			clock_tbl_a7, ARRAY_SIZE(clock_tbl_a7));
	if (rc) {
		dev_err(&pdev->dev, "msm_clock_register failed\n");
		return rc;
+242 −13
Original line number Diff line number Diff line
@@ -37,11 +37,13 @@
#define OUTPUT_REG(pll) (*pll->base + pll->offset + 0x10)
#define VOTE_REG(pll) (*pll->base + pll->fsm_reg_offset)
#define USER_CTL_LO_REG(pll) (*pll->base + pll->offset + 0x10)
#define USER_CTL_HI_REG(pll) (*pll->base + pll->offset + 0x14)
#define CONFIG_CTL_REG(pll) (*pll->base + pll->offset + 0x18)

#define PLL_BYPASSNL 0x2
#define PLL_RESET_N  0x4
#define PLL_OUTCTRL  0x1
#define PLL_LATCH_INTERFACE	BIT(11)

/*
 * Even though 40 bits are present, use only 32 for ease of calculation.
@@ -124,7 +126,7 @@ static int __alpha_pll_vote_enable(struct alpha_pll_clk *pll)
	return wait_for_update(pll);
}

static int __alpha_pll_enable(struct alpha_pll_clk *pll)
static int __alpha_pll_enable(struct alpha_pll_clk *pll, int enable_output)
{
	int rc;
	u32 mode;
@@ -148,14 +150,39 @@ static int __alpha_pll_enable(struct alpha_pll_clk *pll)
		return rc;

	/* Enable PLL output. */
	if (enable_output) {
		mode |= PLL_OUTCTRL;
		writel_relaxed(mode, MODE_REG(pll));
	}

	/* Ensure that the write above goes through before returning. */
	mb();
	return 0;
}

static void setup_alpha_pll_values(u64 a_val, u32 l_val, u32 vco_val,
				struct alpha_pll_clk *pll)
{
	struct alpha_pll_masks *masks = pll->masks;
	u32 regval;

	a_val = a_val << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);

	writel_relaxed(l_val, L_REG(pll));
	__iowrite32_copy(A_REG(pll), &a_val, 2);

	if (vco_val != UINT_MAX) {
		regval = readl_relaxed(VCO_REG(pll));
		regval &= ~(masks->vco_mask << masks->vco_shift);
		regval |= vco_val << masks->vco_shift;
		writel_relaxed(regval, VCO_REG(pll));
	}

	regval = readl_relaxed(ALPHA_EN_REG(pll));
	regval |= masks->alpha_en_mask;
	writel_relaxed(regval, ALPHA_EN_REG(pll));
}

static int alpha_pll_enable(struct clk *c)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
@@ -169,7 +196,31 @@ static int alpha_pll_enable(struct clk *c)
	if (pll->fsm_en_mask)
		rc = __alpha_pll_vote_enable(pll);
	else
		rc = __alpha_pll_enable(pll);
		rc = __alpha_pll_enable(pll, true);
	spin_unlock_irqrestore(&alpha_pll_reg_lock, flags);

	return rc;
}

static int __calibrate_alpha_pll(struct alpha_pll_clk *pll);
static int dyna_alpha_pll_enable(struct clk *c)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
	unsigned long flags;
	int rc;

	if (unlikely(!pll->inited))
		__init_alpha_pll(c);

	spin_lock_irqsave(&alpha_pll_reg_lock, flags);

	if (pll->slew)
		__calibrate_alpha_pll(pll);

	if (pll->fsm_en_mask)
		rc = __alpha_pll_vote_enable(pll);
	else
		rc = __alpha_pll_enable(pll, true);
	spin_unlock_irqrestore(&alpha_pll_reg_lock, flags);

	return rc;
@@ -258,6 +309,20 @@ static void alpha_pll_disable(struct clk *c)
	spin_unlock_irqrestore(&alpha_pll_reg_lock, flags);
}

static void dyna_alpha_pll_disable(struct clk *c)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
	unsigned long flags;

	spin_lock_irqsave(&alpha_pll_reg_lock, flags);
	if (pll->fsm_en_mask)
		__alpha_pll_vote_disable(pll);
	else
		__alpha_pll_disable(pll);

	spin_unlock_irqrestore(&alpha_pll_reg_lock, flags);
}

static u32 find_vco(struct alpha_pll_clk *pll, unsigned long rate)
{
	unsigned long i;
@@ -313,6 +378,156 @@ static unsigned long round_rate_up(struct alpha_pll_clk *pll,
	return __calc_values(pll, rate, l_val, a_val, true);
}

static bool dynamic_update_finish(struct alpha_pll_clk *pll)
{
	u32 reg = readl_relaxed(UPDATE_REG(pll));
	u32 mask = pll->masks->update_mask;

	return (reg & mask) == 0;
}

static int wait_for_dynamic_update(struct alpha_pll_clk *pll)
{
	int count;

	for (count = WAIT_MAX_LOOPS; count > 0; count--) {
		if (dynamic_update_finish(pll))
			break;
		udelay(1);
	}

	if (!count) {
		pr_err("%s didn't latch after updating it!\n", pll->c.dbg_name);
		return -EINVAL;
	}

	return 0;
}

static int dyna_alpha_pll_dynamic_update(struct alpha_pll_clk *pll)
{
	struct alpha_pll_masks *masks = pll->masks;
	u32 regval;
	int rc;

	regval = readl_relaxed(UPDATE_REG(pll));
	regval |= masks->update_mask;
	writel_relaxed(regval, UPDATE_REG(pll));

	rc = wait_for_dynamic_update(pll);
	if (rc < 0)
		return rc;

	/*
	 * HPG mandates a wait of at least 570ns before polling the LOCK
	 * detect bit. Have a delay of 1us just to be safe.
	 */
	mb();
	udelay(1);

	rc = wait_for_update(pll);
	if (rc < 0)
		return rc;

	return 0;
}

static int alpha_pll_set_rate(struct clk *c, unsigned long rate);
static int dyna_alpha_pll_set_rate(struct clk *c, unsigned long rate)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
	unsigned long freq_hz, flags;
	u32 l_val, vco_val;
	u64 a_val;
	int ret;

	freq_hz = round_rate_up(pll, rate, &l_val, &a_val);
	if (freq_hz != rate) {
		pr_err("alpha_pll: Call clk_set_rate with rounded rates!\n");
		return -EINVAL;
	}

	vco_val = find_vco(pll, freq_hz);

	/*
	 * Dynamic pll update will not support switching frequencies across
	 * vco ranges. In those cases fall back to normal alpha set rate.
	 */
	if (pll->current_vco_val != vco_val) {
		ret = alpha_pll_set_rate(c, rate);
		if (!ret)
			pll->current_vco_val = vco_val;
		else
			return ret;
		return 0;
	}

	spin_lock_irqsave(&c->lock, flags);

	a_val = a_val << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);

	writel_relaxed(l_val, L_REG(pll));
	__iowrite32_copy(A_REG(pll), &a_val, 2);

	/* Ensure that the write above goes through before proceeding. */
	mb();

	if (c->count)
		dyna_alpha_pll_dynamic_update(pll);

	spin_unlock_irqrestore(&c->lock, flags);
	return 0;
}

/*
 * Slewing plls should be bought up at frequency which is in the middle of the
 * desired VCO range. So after bringing up the pll at calibration freq, set it
 * back to desired frequency(that was set by previous clk_set_rate).
 */
static int __calibrate_alpha_pll(struct alpha_pll_clk *pll)
{
	unsigned long calibration_freq, freq_hz;
	struct alpha_pll_vco_tbl *vco_tbl = pll->vco_tbl;
	u64 a_val;
	u32 l_val, vco_val;
	int rc;

	vco_val = find_vco(pll, pll->c.rate);
	if (IS_ERR_VALUE(vco_val)) {
		pr_err("alpha pll: not in a valid vco range\n");
		return -EINVAL;
	}
	calibration_freq = (vco_tbl[vco_val].min_freq +
			    vco_tbl[vco_val].max_freq)/2;

	freq_hz = round_rate_up(pll, calibration_freq, &l_val, &a_val);
	if (freq_hz != calibration_freq) {
		pr_err("alpha_pll: call clk_set_rate with rounded rates!\n");
		return -EINVAL;
	}

	setup_alpha_pll_values(a_val, l_val, vco_tbl->vco_val, pll);

	/* Bringup the pll at calibration frequency */
	rc = __alpha_pll_enable(pll, false);
	if (rc) {
		pr_err("alpha pll calibration failed\n");
		return rc;
	}

	/*
	 * PLL is already running at calibration frequency.
	 * So slew pll to the previously set frequency.
	 */
	pr_debug("pll %s: setting back to required rate %lu\n", pll->c.dbg_name,
					pll->c.rate);
	freq_hz = round_rate_up(pll, pll->c.rate, &l_val, &a_val);
	setup_alpha_pll_values(a_val, l_val, UINT_MAX, pll);
	dyna_alpha_pll_dynamic_update(pll);

	return 0;
}

static int alpha_pll_set_rate(struct clk *c, unsigned long rate)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
@@ -450,23 +665,29 @@ void __init_alpha_pll(struct clk *c)
{
	struct alpha_pll_clk *pll = to_alpha_pll_clk(c);
	struct alpha_pll_masks *masks = pll->masks;
	u32 output_en, userval;
	u32 regval;

	if (pll->config_ctl_val)
		writel_relaxed(pll->config_ctl_val, CONFIG_CTL_REG(pll));

	if (masks->output_mask && pll->enable_config) {
		output_en = readl_relaxed(OUTPUT_REG(pll));
		output_en &= ~masks->output_mask;
		output_en |= pll->enable_config;
		writel_relaxed(output_en, OUTPUT_REG(pll));
		regval = readl_relaxed(OUTPUT_REG(pll));
		regval &= ~masks->output_mask;
		regval |= pll->enable_config;
		writel_relaxed(regval, OUTPUT_REG(pll));
	}

	if (masks->post_div_mask) {
		userval = readl_relaxed(USER_CTL_LO_REG(pll));
		userval &= ~masks->post_div_mask;
		userval |= pll->post_div_config;
		writel_relaxed(userval, USER_CTL_LO_REG(pll));
		regval = readl_relaxed(USER_CTL_LO_REG(pll));
		regval &= ~masks->post_div_mask;
		regval |= pll->post_div_config;
		writel_relaxed(regval, USER_CTL_LO_REG(pll));
	}

	if (pll->slew) {
		regval = readl_relaxed(USER_CTL_HI_REG(pll));
		regval &= ~PLL_LATCH_INTERFACE;
		writel_relaxed(regval, USER_CTL_HI_REG(pll));
	}

	if (pll->fsm_en_mask)
@@ -539,6 +760,14 @@ struct clk_ops clk_ops_fixed_alpha_pll = {
	.handoff = alpha_pll_handoff,
};

struct clk_ops clk_ops_dyna_alpha_pll = {
	.enable = dyna_alpha_pll_enable,
	.disable = dyna_alpha_pll_disable,
	.round_rate = alpha_pll_round_rate,
	.set_rate = dyna_alpha_pll_set_rate,
	.handoff = alpha_pll_handoff,
};

static struct alpha_pll_masks masks_20nm_p = {
	.lock_mask = BIT(31),
	.active_mask = BIT(30),
+40 −3
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -171,8 +171,8 @@ static void get_speed_bin(struct platform_device *pdev, int *bin,
								int *version)
{
	struct resource *res;
	void __iomem *base;
	u32 pte_efuse;
	void __iomem *base, *base1, *base2;
	u32 pte_efuse, pte_efuse1, pte_efuse2;

	*bin = 0;
	*version = 0;
@@ -196,6 +196,43 @@ static void get_speed_bin(struct platform_device *pdev, int *bin,

	*bin = (pte_efuse >> 2) & 0x7;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
	if (!res) {
		dev_info(&pdev->dev,
			 "No PVS version available. Defaulting to 0!\n");
		goto out;
	}

	base1 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (!base1) {
		dev_warn(&pdev->dev,
			 "Unable to read efuse1 data. Defaulting to 0!\n");
		goto out;
	}

	pte_efuse1 = readl_relaxed(base1);
	devm_iounmap(&pdev->dev, base1);

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse2");
	if (!res) {
		dev_info(&pdev->dev,
			 "No PVS version available. Defaulting to 0!\n");
		goto out;
	}

	base2 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (!base2) {
		dev_warn(&pdev->dev,
			 "Unable to read efuse2 data. Defaulting to 0!\n");
		goto out;
	}

	pte_efuse2 = readl_relaxed(base2);
	devm_iounmap(&pdev->dev, base2);

	*version = ((pte_efuse1 >> 29 & 0x1) | ((pte_efuse2 >> 18 & 0x3) << 1));

out:
	dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
								*version);
}
+3703 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading