summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
authorArun KS <arunks@codeaurora.org>2017-04-06 15:45:04 +0530
committerArun KS <arunks@codeaurora.org>2017-04-06 15:45:04 +0530
commite8a49b120cbc3a0472aebcd0f8b06cf95f775a54 (patch)
tree7b58ec70803bbfda534ed2a8b50d321a1ecb22ba /drivers/clk
parent9a0d24cf9f0e1d4cad7cf92f7e50939fb605e075 (diff)
parenta3851309dbf7e919b27e2ec927ba3f6350347dff (diff)
Merge remote-tracking branch 'remotes/origin/msm-4.4' into dev/msm-4.4-8996au
Conflicts: arch/arm/boot/dts/qcom/msm8996pro.dtsi arch/arm64/kernel/Makefile drivers/leds/leds-qpnp-flash.c sound/soc/msm/apq8096-auto.c Change-Id: Idea5d05fec354b8f38ea70643decb03f7b80ddb7 Signed-off-by: Arun KS <arunks@codeaurora.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/bcm/clk-bcm2835.c4
-rw-r--r--drivers/clk/clk-divider.c2
-rw-r--r--drivers/clk/clk-qoriq.c19
-rw-r--r--drivers/clk/clk-wm831x.c2
-rw-r--r--drivers/clk/clk-xgene.c4
-rw-r--r--drivers/clk/clk.c6
-rw-r--r--drivers/clk/clk.h2
-rw-r--r--drivers/clk/imx/clk-imx31.c4
-rw-r--r--drivers/clk/imx/clk-imx35.c2
-rw-r--r--drivers/clk/imx/clk-imx6q.c18
-rw-r--r--drivers/clk/mmp/clk-of-mmp2.c2
-rw-r--r--drivers/clk/mmp/clk-of-pxa168.c2
-rw-r--r--drivers/clk/mmp/clk-of-pxa910.c4
-rw-r--r--drivers/clk/msm/clock-gcc-8998.c14
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clk-branch.c3
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c2
-rw-r--r--drivers/clk/qcom/clk-debug.c277
-rw-r--r--drivers/clk/qcom/clk-debug.h120
-rw-r--r--drivers/clk/qcom/clk-dummy.c5
-rw-r--r--drivers/clk/qcom/clk-rcg.h3
-rw-r--r--drivers/clk/qcom/clk-rcg2.c78
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c11
-rw-r--r--drivers/clk/qcom/common.c239
-rw-r--r--drivers/clk/qcom/common.h100
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c7
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.c7
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.h1
-rw-r--r--drivers/clk/qcom/mmcc-sdm660.c8
-rw-r--r--drivers/clk/ti/clk-3xxx.c20
-rw-r--r--drivers/clk/ti/clock.h9
-rw-r--r--drivers/clk/ti/dpll.c19
-rw-r--r--drivers/clk/ti/dpll3xxx.c67
33 files changed, 676 insertions, 387 deletions
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 6029313aa995..35ab89fe9d7b 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1082,7 +1082,9 @@ static void bcm2835_pll_divider_off(struct clk_hw *hw)
cprman_write(cprman, data->cm_reg,
(cprman_read(cprman, data->cm_reg) &
~data->load_mask) | data->hold_mask);
- cprman_write(cprman, data->a2w_reg, A2W_PLL_CHANNEL_DISABLE);
+ cprman_write(cprman, data->a2w_reg,
+ cprman_read(cprman, data->a2w_reg) |
+ A2W_PLL_CHANNEL_DISABLE);
spin_unlock(&cprman->regs_lock);
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 0c83ffc22dd2..f45d923ed3cd 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -354,7 +354,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
/* if read only, just return current value */
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
- bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv = clk_readl(divider->reg) >> divider->shift;
bestdiv &= div_mask(divider->width);
bestdiv = _get_div(divider->table, bestdiv, divider->flags,
divider->width);
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 7bc1c4527ae4..a5070f9cb0d4 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -700,6 +700,7 @@ static struct clk * __init create_mux_common(struct clockgen *cg,
struct mux_hwclock *hwc,
const struct clk_ops *ops,
unsigned long min_rate,
+ unsigned long max_rate,
unsigned long pct80_rate,
const char *fmt, int idx)
{
@@ -728,6 +729,8 @@ static struct clk * __init create_mux_common(struct clockgen *cg,
continue;
if (rate < min_rate)
continue;
+ if (rate > max_rate)
+ continue;
parent_names[j] = div->name;
hwc->parent_to_clksel[j] = i;
@@ -759,14 +762,18 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
struct mux_hwclock *hwc;
const struct clockgen_pll_div *div;
unsigned long plat_rate, min_rate;
- u64 pct80_rate;
+ u64 max_rate, pct80_rate;
u32 clksel;
hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
if (!hwc)
return NULL;
- hwc->reg = cg->regs + 0x20 * idx;
+ if (cg->info.flags & CG_VER3)
+ hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
+ else
+ hwc->reg = cg->regs + 0x20 * idx;
+
hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];
/*
@@ -783,8 +790,8 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
return NULL;
}
- pct80_rate = clk_get_rate(div->clk);
- pct80_rate *= 8;
+ max_rate = clk_get_rate(div->clk);
+ pct80_rate = max_rate * 8;
do_div(pct80_rate, 10);
plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk);
@@ -794,7 +801,7 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
else
min_rate = plat_rate / 2;
- return create_mux_common(cg, hwc, &cmux_ops, min_rate,
+ return create_mux_common(cg, hwc, &cmux_ops, min_rate, max_rate,
pct80_rate, "cg-cmux%d", idx);
}
@@ -809,7 +816,7 @@ static struct clk * __init create_one_hwaccel(struct clockgen *cg, int idx)
hwc->reg = cg->regs + 0x20 * idx + 0x10;
hwc->info = cg->info.hwaccel[idx];
- return create_mux_common(cg, hwc, &hwaccel_ops, 0, 0,
+ return create_mux_common(cg, hwc, &hwaccel_ops, 0, ULONG_MAX, 0,
"cg-hwaccel%d", idx);
}
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index 43f9d15255f4..763aed2de893 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -247,7 +247,7 @@ static int wm831x_clkout_is_prepared(struct clk_hw *hw)
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
ret);
- return true;
+ return false;
}
return (ret & WM831X_CLKOUT_ENA) != 0;
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index 10224b01b97c..b134a8b15e2c 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -351,8 +351,8 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
/* Set new divider */
data = xgene_clk_read(pclk->param.divider_reg +
pclk->param.reg_divider_offset);
- data &= ~((1 << pclk->param.reg_divider_width) - 1)
- << pclk->param.reg_divider_shift;
+ data &= ~(((1 << pclk->param.reg_divider_width) - 1)
+ << pclk->param.reg_divider_shift);
data |= divider;
xgene_clk_write(data, pclk->param.divider_reg +
pclk->param.reg_divider_offset);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index e8e48015d3af..4a9e034f939f 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2874,8 +2874,6 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
goto err_out;
}
- clk_debug_measure_add(core->hw, core->dentry);
-
ret = 0;
goto out;
@@ -3005,10 +3003,8 @@ static int __init clk_debug_init(void)
return -ENOMEM;
mutex_lock(&clk_debug_lock);
- hlist_for_each_entry(core, &clk_debug_list, debug_node) {
- clk_register_debug(core->hw, core->dentry);
+ hlist_for_each_entry(core, &clk_debug_list, debug_node)
clk_debug_create_one(core, rootdir);
- }
inited = 1;
mutex_unlock(&clk_debug_lock);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index 25bf4bc85f5c..87af7af7aac2 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -23,8 +23,6 @@ void __clk_free_clk(struct clk *clk);
/* Debugfs API to print the enabled clocks */
void clock_debug_print_enabled(void);
-int clk_register_debug(struct clk_hw *hw, struct dentry *dentry);
-void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);
#else
diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
index 6a964144a5b5..6a49ba2b9671 100644
--- a/drivers/clk/imx/clk-imx31.c
+++ b/drivers/clk/imx/clk-imx31.c
@@ -157,10 +157,8 @@ static void __init _mx31_clocks_init(unsigned long fref)
}
}
-int __init mx31_clocks_init(void)
+int __init mx31_clocks_init(unsigned long fref)
{
- u32 fref = 26000000; /* default */
-
_mx31_clocks_init(fref);
clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index b0978d3b83e2..d302ed3b8225 100644
--- a/drivers/clk/imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -115,7 +115,7 @@ static void __init _mx35_clocks_init(void)
}
clk[ckih] = imx_clk_fixed("ckih", 24000000);
- clk[ckil] = imx_clk_fixed("ckih", 32768);
+ clk[ckil] = imx_clk_fixed("ckil", 32768);
clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index c1935081d34a..aab64205d866 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -550,6 +550,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
if (IS_ENABLED(CONFIG_PCI_IMX6))
clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
+ /*
+ * Initialize the GPU clock muxes, so that the maximum specified clock
+ * rates for the respective SoC are not exceeded.
+ */
+ if (clk_on_imx6dl()) {
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+ clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+ clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ } else if (clk_on_imx6q()) {
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+ clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
+ clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+ clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+ }
+
imx_register_uart_clocks(uart_clks);
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c
index 251533d87c65..f261b1d292c7 100644
--- a/drivers/clk/mmp/clk-of-mmp2.c
+++ b/drivers/clk/mmp/clk-of-mmp2.c
@@ -313,7 +313,7 @@ static void __init mmp2_clk_init(struct device_node *np)
}
pxa_unit->apmu_base = of_iomap(np, 1);
- if (!pxa_unit->mpmu_base) {
+ if (!pxa_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c
index 64eaf4141c69..427f4bb08665 100644
--- a/drivers/clk/mmp/clk-of-pxa168.c
+++ b/drivers/clk/mmp/clk-of-pxa168.c
@@ -262,7 +262,7 @@ static void __init pxa168_clk_init(struct device_node *np)
}
pxa_unit->apmu_base = of_iomap(np, 1);
- if (!pxa_unit->mpmu_base) {
+ if (!pxa_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c
index 13d6173326a4..cdf5ba566d3b 100644
--- a/drivers/clk/mmp/clk-of-pxa910.c
+++ b/drivers/clk/mmp/clk-of-pxa910.c
@@ -282,7 +282,7 @@ static void __init pxa910_clk_init(struct device_node *np)
}
pxa_unit->apmu_base = of_iomap(np, 1);
- if (!pxa_unit->mpmu_base) {
+ if (!pxa_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
return;
}
@@ -294,7 +294,7 @@ static void __init pxa910_clk_init(struct device_node *np)
}
pxa_unit->apbcp_base = of_iomap(np, 3);
- if (!pxa_unit->mpmu_base) {
+ if (!pxa_unit->apbcp_base) {
pr_err("failed to map apbcp registers\n");
return;
}
diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c
index f9d713a22c76..b1c8cc43769f 100644
--- a/drivers/clk/msm/clock-gcc-8998.c
+++ b/drivers/clk/msm/clock-gcc-8998.c
@@ -42,6 +42,7 @@ static void __iomem *virt_dbgbase;
#define gpll0_out_main_source_val 1
#define gpll0_ao_source_val 1
#define gpll4_out_main_source_val 5
+#define gpll0_early_div_source_val 6
#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
@@ -164,6 +165,7 @@ static struct pll_vote_clk gpll0_ao = {
};
DEFINE_EXT_CLK(gpll0_out_main, &gpll0.c);
+DEFINE_EXT_CLK(gpll0_early_div, &gpll0.c);
static struct local_vote_clk gcc_mmss_gpll0_clk = {
.cbcr_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE_1,
@@ -328,7 +330,7 @@ static struct clk_freq_tbl ftbl_blsp_qup_spi_apps_clk_src[] = {
F( 960000, cxo_clk_src, 10, 1, 2),
F( 4800000, cxo_clk_src, 4, 0, 0),
F( 9600000, cxo_clk_src, 2, 0, 0),
- F( 15000000, gpll0_out_main, 10, 1, 4),
+ F( 15000000, gpll0_early_div, 5, 1, 4),
F( 19200000, cxo_clk_src, 1, 0, 0),
F( 25000000, gpll0_out_main, 12, 1, 2),
F( 50000000, gpll0_out_main, 12, 0, 0),
@@ -496,10 +498,10 @@ static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
};
static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
- F( 3686400, gpll0_out_main, 1, 96, 15625),
- F( 7372800, gpll0_out_main, 1, 192, 15625),
- F( 14745600, gpll0_out_main, 1, 384, 15625),
- F( 16000000, gpll0_out_main, 5, 2, 15),
+ F( 3686400, gpll0_early_div, 1, 192, 15625),
+ F( 7372800, gpll0_early_div, 1, 384, 15625),
+ F( 14745600, gpll0_early_div, 1, 768, 15625),
+ F( 16000000, gpll0_early_div, 1, 4, 75),
F( 19200000, cxo_clk_src, 1, 0, 0),
F( 24000000, gpll0_out_main, 5, 1, 5),
F( 32000000, gpll0_out_main, 1, 4, 75),
@@ -2732,6 +2734,8 @@ static int msm_gcc_8998_probe(struct platform_device *pdev)
if (ret)
return ret;
+ gpll0_early_div.c.rate = 300000000;
+
ret = enable_rpm_scaling();
if (ret < 0)
return ret;
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 317091a8003d..4c18181c047c 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -12,7 +12,7 @@ clk-qcom-y += clk-regmap-mux.o
clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o clk-voter.o
-clk-qcom-y += clk-dummy.o
+clk-qcom-y += clk-dummy.o clk-debug.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index ca6010db8d78..3e9cd9909b86 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -21,6 +21,7 @@
#include <linux/regmap.h>
#include "clk-branch.h"
+#include "clk-debug.h"
#include "clk-regmap.h"
#include "common.h"
@@ -250,6 +251,7 @@ const struct clk_ops clk_branch2_ops = {
.is_enabled = clk_is_enabled_regmap,
.set_flags = clk_branch_set_flags,
.list_registers = clk_branch2_list_registers,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);
@@ -384,6 +386,7 @@ const struct clk_ops clk_gate2_ops = {
.is_enabled = clk_is_enabled_regmap,
.list_registers = clk_gate2_list_registers,
.set_flags = clk_gate2_set_flags,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_gate2_ops);
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 6b00bee337a1..f82ddc3b008b 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -39,6 +39,7 @@
#include "common.h"
#include "clk-regmap.h"
#include "clk-rcg.h"
+#include "clk-debug.h"
enum {
LMH_LITE_CLK_SRC,
@@ -757,6 +758,7 @@ static struct clk_ops clk_ops_cpu_osm = {
.round_rate = clk_osm_round_rate,
.list_rate = clk_osm_list_rate,
.recalc_rate = clk_osm_recalc_rate,
+ .debug_init = clk_debug_measure_add,
};
static const struct parent_map gcc_parent_map_1[] = {
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
new file mode 100644
index 000000000000..50d0d01188ed
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2013-2014, 2016-2017,
+ *
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+
+#include "clk-regmap.h"
+#include "clk-debug.h"
+#include "common.h"
+
+static struct clk_hw *measure;
+
+static DEFINE_SPINLOCK(clk_reg_lock);
+static DEFINE_MUTEX(clk_debug_lock);
+
+#define TCXO_DIV_4_HZ 4800000
+#define SAMPLE_TICKS_1_MS 0x1000
+#define SAMPLE_TICKS_14_MS 0x10000
+
+#define XO_DIV4_CNT_DONE BIT(25)
+#define CNT_EN BIT(20)
+#define MEASURE_CNT BM(24, 0)
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks, struct regmap *regmap,
+ u32 ctl_reg, u32 status_reg)
+{
+ u32 regval;
+
+ /* Stop counters and set the XO4 counter start value. */
+ regmap_write(regmap, ctl_reg, ticks);
+
+ regmap_read(regmap, status_reg, &regval);
+
+ /* Wait for timer to become ready. */
+ while ((regval & XO_DIV4_CNT_DONE) != 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Run measurement and wait for completion. */
+ regmap_write(regmap, ctl_reg, (CNT_EN|ticks));
+
+ regmap_read(regmap, status_reg, &regval);
+
+ while ((regval & XO_DIV4_CNT_DONE) == 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, &regval);
+ }
+
+ /* Return measured ticks. */
+ regmap_read(regmap, status_reg, &regval);
+ regval &= MEASURE_CNT;
+
+ return regval;
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
+{
+ unsigned long flags, ret = 0;
+ u32 gcc_xo4_reg, multiplier;
+ u64 raw_count_short, raw_count_full;
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ struct measure_clk_data *data = meas->priv;
+
+ clk_prepare_enable(data->cxo);
+
+ spin_lock_irqsave(&clk_reg_lock, flags);
+
+ multiplier = meas->multiplier + 1;
+
+ /* Enable CXO/4 and RINGOSC branch. */
+ regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
+ gcc_xo4_reg |= BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /*
+ * The ring oscillator counter will not reset if the measured clock
+ * is not running. To detect this, run a short measurement before
+ * the full measurement. If the raw results of the two are the same
+ * then the clock must be off.
+ */
+
+ /* Run a short measurement. (~1 ms) */
+ raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ /* Run a full measurement. (~14 ms) */
+ raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ gcc_xo4_reg &= ~BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /* Return 0 if the clock is off. */
+ if (raw_count_full == raw_count_short)
+ ret = 0;
+ else {
+ /* Compute rate in Hz. */
+ raw_count_full = ((raw_count_full * 10) + 15) * TCXO_DIV_4_HZ;
+ do_div(raw_count_full, ((SAMPLE_TICKS_14_MS * 10) + 35));
+ ret = (raw_count_full * multiplier);
+ }
+
+ spin_unlock_irqrestore(&clk_reg_lock, flags);
+
+ clk_disable_unprepare(data->cxo);
+
+ return ret;
+}
+
+static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ int i, num_parents = clk_hw_get_num_parents(hw);
+
+ for (i = 0; i < num_parents; i++) {
+ if (!strcmp(meas->parent[i].parents,
+ hw->init->parent_names[i])) {
+ pr_debug("%s: Clock name %s index %d\n", __func__,
+ hw->init->name, i);
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ unsigned long lsb = 0;
+ u32 regval = 0;
+ int dbg_cc = 0;
+
+ dbg_cc = meas->parent[index].dbg_cc;
+
+ if (dbg_cc != GCC) {
+ regmap_read(meas->regmap[dbg_cc], 0x0, &regval);
+
+ /* Clear & Set post divider bits */
+ if (meas->parent[index].post_div_mask) {
+ regval &= ~meas->parent[index].post_div_mask;
+ lsb = find_first_bit((unsigned long *)
+ &meas->parent[index].post_div_mask, 32);
+ regval |= (meas->parent[index].post_div_val << lsb) &
+ meas->parent[index].post_div_mask;
+ meas->multiplier = meas->parent[index].post_div_val;
+ }
+
+ if (meas->parent[index].mask)
+ regval &= ~meas->parent[index].mask <<
+ meas->parent[index].shift;
+ else
+ regval &= ~meas->mask;
+
+ regval |= (meas->parent[index].next_sel & meas->mask);
+
+ if (meas->parent[index].en_mask == 0xFF)
+ /* Skip en_mask */
+ regval = regval;
+ else if (meas->parent[index].en_mask)
+ regval |= meas->parent[index].en_mask;
+ else
+ regval |= meas->en_mask;
+
+ regmap_write(meas->regmap[dbg_cc], 0x0, regval);
+ }
+
+ /* update the debug sel for GCC */
+ regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
+
+ /* clear post divider bits */
+ regval &= ~BM(15, 12);
+ lsb = find_first_bit((unsigned long *)
+ &meas->parent[index].post_div_mask, 32);
+ regval |= (meas->parent[index].post_div_val << lsb) &
+ meas->parent[index].post_div_mask;
+ meas->multiplier = meas->parent[index].post_div_val;
+ regval &= ~meas->mask;
+ regval |= (meas->parent[index].sel & meas->mask);
+ regval |= meas->en_mask;
+
+ regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
+
+ return 0;
+}
+
+const struct clk_ops clk_debug_mux_ops = {
+ .get_parent = clk_debug_mux_get_parent,
+ .set_parent = clk_debug_mux_set_parent,
+};
+EXPORT_SYMBOL(clk_debug_mux_ops);
+
+static int clk_debug_measure_get(void *data, u64 *val)
+{
+ struct clk_hw *hw = data, *par;
+ int ret = 0;
+ unsigned long meas_rate, sw_rate;
+
+ mutex_lock(&clk_debug_lock);
+
+ ret = clk_set_parent(measure->clk, hw->clk);
+ if (!ret) {
+ par = measure;
+ while (par && par != hw) {
+ if (par->init->ops->enable)
+ par->init->ops->enable(par);
+ par = clk_hw_get_parent(par);
+ }
+ *val = clk_debug_mux_measure_rate(measure);
+ }
+
+ meas_rate = clk_get_rate(hw->clk);
+ sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk);
+ if (sw_rate && meas_rate >= (sw_rate * 2))
+ *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
+
+ mutex_unlock(&clk_debug_lock);
+
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
+ NULL, "%lld\n");
+
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
+{
+ if (IS_ERR_OR_NULL(measure)) {
+ pr_err_once("Please check if `measure` clk is registered!!!\n");
+ return 0;
+ }
+
+ if (clk_set_parent(measure->clk, hw->clk))
+ return 0;
+
+ debugfs_create_file("clk_measure", S_IRUGO, dentry, hw,
+ &clk_measure_fops);
+ return 0;
+}
+EXPORT_SYMBOL(clk_debug_measure_add);
+
+int clk_register_debug(struct clk_hw *hw)
+{
+ if (IS_ERR_OR_NULL(measure)) {
+ if (hw->init->flags & CLK_IS_MEASURE) {
+ measure = hw;
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_register_debug);
+
diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h
new file mode 100644
index 000000000000..40e8730a9466
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, 2016-2017, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_DEBUG_H__
+#define __QCOM_CLK_DEBUG_H__
+
+#include "../clk.h"
+
+/* Debugfs Measure Clocks */
+
+/**
+ * struct measure_clk_data - Structure of clk measure
+ *
+ * @cxo: XO clock.
+ * @xo_div4_cbcr: offset of debug XO/4 div register.
+ * @ctl_reg: offset of debug control register.
+ * @status_reg: offset of debug status register.
+ *
+ */
+struct measure_clk_data {
+ struct clk *cxo;
+ u32 xo_div4_cbcr;
+ u32 ctl_reg;
+ u32 status_reg;
+};
+
+/**
+ * List of Debug clock controllers.
+ */
+enum debug_cc {
+ GCC,
+ MMCC,
+ GPU,
+ CPU,
+};
+
+/**
+ * struct clk_src - Struture of clock source for debug mux
+ *
+ * @parents: clock name to be used as parent for debug mux.
+ * @sel: debug mux index at global clock controller.
+ * @dbg_cc: indicates the clock controller for recursive debug clock
+ * controllers.
+ * @next_sel: indicates the debug mux index at recursive debug mux.
+ * @mask: indicates the mask required at recursive debug mux.
+ * @shift: indicates the shift required at recursive debug mux.
+ * @en_mask: indicates the enable bit mask at recursive debug mux.
+ * Incase the recursive debug mux does not have a enable bit,
+ * 0xFF should be used to indicate the same, otherwise global
+ * enable bit would be used.
+ * @post_div_mask: indicates the post div mask to be used at debug/recursive
+ * debug mux.
+ * @post_div_val: indicates the post div value to be used at debug/recursive
+ * debug mux.
+ */
+struct clk_src {
+ const char *parents;
+ int sel;
+ enum debug_cc dbg_cc;
+ int next_sel;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ u32 post_div_mask;
+ u32 post_div_val;
+};
+
+#define MUX_SRC_LIST(...) \
+ .parent = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+/**
+ * struct clk_debug_mux - Struture of clock debug mux
+ *
+ * @parent: structure of clk_src
+ * @num_parents: number of parents
+ * @regmap: regmaps of debug mux
+ * @num_parent_regmap: number of regmap of debug mux
+ * @priv: private measure_clk_data to be used by debug mux
+ * @en_mask: indicates the enable bit mask at global clock
+ * controller debug mux.
+ * @mask: indicates the mask to be used at global clock
+ * controller debug mux.
+ * @debug_offset: debug mux offset.
+ * @hw: handle between common and hardware-specific interfaces.
+ * @multiplier: internally used by debug mux as post div multiplier.
+ */
+struct clk_debug_mux {
+ struct clk_src *parent;
+ int num_parents;
+ struct regmap **regmap;
+ int num_parent_regmap;
+ void *priv;
+ u32 en_mask;
+ u32 mask;
+ u32 debug_offset;
+ struct clk_hw hw;
+
+ /* internal */
+ u32 multiplier;
+};
+
+#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
+
+extern const struct clk_ops clk_debug_mux_ops;
+
+int clk_register_debug(struct clk_hw *hw);
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
+
+#endif
diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c
index e06a829e508c..c08136563e31 100644
--- a/drivers/clk/qcom/clk-dummy.c
+++ b/drivers/clk/qcom/clk-dummy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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
@@ -17,6 +17,8 @@
#include <linux/slab.h>
#include <linux/reset-controller.h>
+#include "clk-debug.h"
+
struct clk_dummy {
struct clk_hw hw;
struct reset_controller_dev reset;
@@ -65,6 +67,7 @@ struct clk_ops clk_dummy_ops = {
.round_rate = dummy_clk_round_rate,
.recalc_rate = dummy_clk_recalc_rate,
.set_flags = dummy_clk_set_flags,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_dummy_ops);
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 58fbd07e6f15..0bcada9aac5d 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -192,5 +192,6 @@ extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_gfx3d_src_ops;
extern const struct clk_ops clk_dp_ops;
+extern const struct clk_ops clk_esc_ops;
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 9e5c0b6f7a0e..ff0c8327fabe 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -513,7 +513,7 @@ static int clk_rcg2_enable(struct clk_hw *hw)
* is always on while APPS is online. Therefore, the RCG can safely be
* switched.
*/
- rate = clk_get_rate(hw->clk);
+ rate = rcg->current_freq;
f = qcom_find_freq(rcg->freq_tbl, rate);
if (!f)
return -EINVAL;
@@ -580,6 +580,9 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
rcg->curr_index = 0;
else {
f = qcom_find_freq(rcg->freq_tbl, rcg->current_freq);
+ if (!f)
+ return -EINVAL;
+
rcg->curr_index = qcom_find_src_index(hw,
rcg->parent_map, f->src);
@@ -627,6 +630,9 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
rcg->new_index, false);
}
+ /* Update current frequency with the frequency requested. */
+ rcg->current_freq = rate;
+
return ret;
}
@@ -1343,3 +1349,73 @@ const struct clk_ops clk_gfx3d_src_ops = {
.list_registers = clk_rcg2_list_registers,
};
EXPORT_SYMBOL_GPL(clk_gfx3d_src_ops);
+
+static int clk_esc_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ unsigned long parent_rate, div;
+ u32 mask = BIT(rcg->hid_width) - 1;
+ struct clk_hw *p;
+ unsigned long rate = req->rate;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ p = req->best_parent_hw;
+ req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);
+
+ div = ((2 * parent_rate) / rate) - 1;
+ div = min_t(u32, div, mask);
+
+ req->rate = calc_rate(parent_rate, 0, 0, 0, div);
+
+ return 0;
+}
+
+static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct freq_tbl f = { 0 };
+ unsigned long div;
+ int i, num_parents = clk_hw_get_num_parents(hw);
+ u32 mask = BIT(rcg->hid_width) - 1;
+ u32 cfg;
+
+ div = ((2 * parent_rate) / rate) - 1;
+ div = min_t(u32, div, mask);
+
+ f.pre_div = div;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+ cfg &= CFG_SRC_SEL_MASK;
+ cfg >>= CFG_SRC_SEL_SHIFT;
+
+ for (i = 0; i < num_parents; i++) {
+ if (cfg == rcg->parent_map[i].cfg) {
+ f.src = rcg->parent_map[i].src;
+ return clk_rcg2_configure(rcg, &f);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int clk_esc_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate, u8 index)
+{
+ return clk_esc_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_esc_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .determine_rate = clk_esc_determine_rate,
+ .set_rate = clk_esc_set_rate,
+ .set_rate_and_parent = clk_esc_set_rate_and_parent,
+ .list_registers = clk_rcg2_list_registers,
+};
+EXPORT_SYMBOL(clk_esc_ops);
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index 0d76b6b28985..8dcdf2929ca6 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -30,6 +30,7 @@
#include <dt-bindings/mfd/qcom-rpm.h>
#include "clk-voter.h"
+#include "clk-debug.h"
#define QCOM_RPM_KEY_SOFTWARE_ENABLE 0x6e657773
#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370
@@ -463,6 +464,7 @@ static const struct clk_ops clk_smd_rpm_ops = {
.round_rate = clk_smd_rpm_round_rate,
.recalc_rate = clk_smd_rpm_recalc_rate,
.is_enabled = clk_smd_rpm_is_enabled,
+ .debug_init = clk_debug_measure_add,
};
static const struct clk_ops clk_smd_rpm_branch_ops = {
@@ -471,6 +473,7 @@ static const struct clk_ops clk_smd_rpm_branch_ops = {
.round_rate = clk_smd_rpm_round_rate,
.recalc_rate = clk_smd_rpm_recalc_rate,
.is_enabled = clk_smd_rpm_is_enabled,
+ .debug_init = clk_debug_measure_add,
};
/* msm8916 */
@@ -570,6 +573,10 @@ static DEFINE_CLK_VOTER(pnoc_msmbus_clk, pnoc_clk, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, pnoc_a_clk, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_pm_clk, pnoc_clk, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sps_clk, pnoc_clk, 0);
+static DEFINE_CLK_VOTER(aggre2_noc_msmbus_clk, aggre2_noc_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(aggre2_noc_msmbus_a_clk, aggre2_noc_a_clk, LONG_MAX);
+static DEFINE_CLK_VOTER(aggre2_noc_usb_clk, aggre2_noc_clk, 19200000);
+static DEFINE_CLK_VOTER(aggre2_noc_smmu_clk, aggre2_noc_clk, 1000);
/* Voter Branch clocks */
static DEFINE_CLK_BRANCH_VOTER(cxo_dwc3_clk, cxo);
@@ -738,6 +745,10 @@ static struct clk_hw *sdm660_clks[] = {
[CXO_PIL_LPASS_CLK] = &cxo_pil_lpass_clk.hw,
[CXO_PIL_CDSP_CLK] = &cxo_pil_cdsp_clk.hw,
[CNOC_PERIPH_KEEPALIVE_A_CLK] = &cnoc_periph_keepalive_a_clk.hw,
+ [AGGR2_NOC_MSMBUS_CLK] = &aggre2_noc_msmbus_clk.hw,
+ [AGGR2_NOC_MSMBUS_A_CLK] = &aggre2_noc_msmbus_a_clk.hw,
+ [AGGR2_NOC_SMMU_CLK] = &aggre2_noc_smmu_clk.hw,
+ [AGGR2_NOC_USB_CLK] = &aggre2_noc_usb_clk.hw,
};
static const struct rpm_smd_clk_desc rpm_clk_sdm660 = {
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f6ce3106ab6f..8ecb207a97e5 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,7 @@
/*
- * Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2017,
+ *
+ * The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -287,239 +289,4 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
}
EXPORT_SYMBOL_GPL(qcom_cc_probe);
-/* Debugfs Support */
-static struct clk_hw *measure;
-
-DEFINE_SPINLOCK(clk_reg_lock);
-
-/* Sample clock for 'ticks' reference clock ticks. */
-static u32 run_measurement(unsigned ticks, struct regmap *regmap,
- u32 ctl_reg, u32 status_reg)
-{
- u32 regval;
-
- /* Stop counters and set the XO4 counter start value. */
- regmap_write(regmap, ctl_reg, ticks);
-
- regmap_read(regmap, status_reg, &regval);
-
- /* Wait for timer to become ready. */
- while ((regval & BIT(25)) != 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Run measurement and wait for completion. */
- regmap_write(regmap, ctl_reg, (BIT(20)|ticks));
- regmap_read(regmap, ctl_reg, &regval);
-
- regmap_read(regmap, status_reg, &regval);
-
- while ((regval & BIT(25)) == 0) {
- cpu_relax();
- regmap_read(regmap, status_reg, &regval);
- }
-
- /* Return measured ticks. */
- regmap_read(regmap, status_reg, &regval);
- regval &= BM(24, 0);
-
- return regval;
-}
-
-/*
- * Perform a hardware rate measurement for a given clock.
- * FOR DEBUG USE ONLY: Measurements take ~15 ms!
- */
-static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
-{
- unsigned long flags, ret = 0;
- u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier;
- u64 raw_count_short, raw_count_full;
- struct clk_debug_mux *meas = to_clk_measure(hw);
- struct measure_clk_data *data = meas->priv;
-
- clk_prepare_enable(data->cxo);
-
- spin_lock_irqsave(&clk_reg_lock, flags);
-
- multiplier = meas->multiplier + 1;
-
- /* Enable CXO/4 and RINGOSC branch. */
- regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
- gcc_xo4_reg |= BIT(0);
- regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
-
- /*
- * The ring oscillator counter will not reset if the measured clock
- * is not running. To detect this, run a short measurement before
- * the full measurement. If the raw results of the two are the same
- * then the clock must be off.
- */
-
- /* Run a short measurement. (~1 ms) */
- raw_count_short = run_measurement(0x1000, meas->regmap[GCC],
- data->ctl_reg, data->status_reg);
-
- /* Run a full measurement. (~14 ms) */
- raw_count_full = run_measurement(sample_ticks, meas->regmap[GCC],
- data->ctl_reg, data->status_reg);
-
- gcc_xo4_reg &= ~BIT(0);
- regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
-
- /* Return 0 if the clock is off. */
- if (raw_count_full == raw_count_short)
- ret = 0;
- else {
- /* Compute rate in Hz. */
- raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
- do_div(raw_count_full, ((sample_ticks * 10) + 35));
- ret = (raw_count_full * multiplier);
- }
-
- spin_unlock_irqrestore(&clk_reg_lock, flags);
-
- clk_disable_unprepare(data->cxo);
-
- return ret;
-}
-
-static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
-{
- struct clk_debug_mux *meas = to_clk_measure(hw);
- int i, num_parents = clk_hw_get_num_parents(hw);
-
- for (i = 0; i < num_parents; i++) {
- if (!strcmp(meas->parent[i].parents,
- hw->init->parent_names[i])) {
- pr_debug("%s :Clock name %s index %d\n", __func__,
- hw->init->name, i);
- return i;
- }
- }
-
- return 0;
-}
-
-static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_debug_mux *meas = to_clk_measure(hw);
- unsigned long lsb = 0;
- u32 regval = 0;
- int dbg_cc = 0;
-
- dbg_cc = meas->parent[index].dbg_cc;
-
- if (dbg_cc != GCC) {
- regmap_read(meas->regmap[dbg_cc], 0x0, &regval);
-
- /* Clear & Set post divider bits */
- if (meas->parent[index].post_div_mask) {
- regval &= ~meas->parent[index].post_div_mask;
- lsb = find_first_bit((unsigned long *)
- &meas->parent[index].post_div_mask, 32);
- regval |= (meas->parent[index].post_div_val << lsb) &
- meas->parent[index].post_div_mask;
- meas->multiplier = meas->parent[index].post_div_val;
- }
-
- if (meas->parent[index].mask)
- regval &= ~meas->parent[index].mask <<
- meas->parent[index].shift;
- else
- regval &= ~meas->mask;
-
- regval |= (meas->parent[index].next_sel & meas->mask);
-
- if (meas->parent[index].en_mask == 0xFF)
- /* Skip en_mask */
- regval = regval;
- else if (meas->parent[index].en_mask)
- regval |= meas->parent[index].en_mask;
- else
- regval |= meas->en_mask;
-
- regmap_write(meas->regmap[dbg_cc], 0x0, regval);
- }
-
- /* update the debug sel for GCC */
- regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
-
- /* clear post divider bits */
- regval &= ~BM(15, 12);
- lsb = find_first_bit((unsigned long *)
- &meas->parent[index].post_div_mask, 32);
- regval |= (meas->parent[index].post_div_val << lsb) &
- meas->parent[index].post_div_mask;
- meas->multiplier = meas->parent[index].post_div_val;
- regval &= ~meas->mask;
- regval |= (meas->parent[index].sel & meas->mask);
- regval |= meas->en_mask;
-
- regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
-
- return 0;
-}
-
-const struct clk_ops clk_debug_mux_ops = {
- .get_parent = clk_debug_mux_get_parent,
- .set_parent = clk_debug_mux_set_parent,
-};
-EXPORT_SYMBOL_GPL(clk_debug_mux_ops);
-
-static int clk_debug_measure_get(void *data, u64 *val)
-{
- struct clk_hw *hw = data, *par;
- int ret = 0;
- unsigned long meas_rate, sw_rate;
-
- ret = clk_set_parent(measure->clk, hw->clk);
- if (!ret) {
- par = measure;
- while (par && par != hw) {
- if (par->init->ops->enable)
- par->init->ops->enable(par);
- par = clk_hw_get_parent(par);
- }
- *val = clk_debug_mux_measure_rate(measure);
- }
-
- meas_rate = clk_get_rate(hw->clk);
- sw_rate = clk_get_rate(clk_hw_get_parent(measure)->clk);
- if (sw_rate && meas_rate >= (sw_rate * 2))
- *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
-
- return ret;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
- NULL, "%lld\n");
-
-void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
-{
- if (IS_ERR_OR_NULL(measure))
- return;
-
- if (clk_set_parent(measure->clk, hw->clk))
- return;
-
- debugfs_create_file("measure", S_IRUGO, dentry, hw,
- &clk_measure_fops);
-}
-EXPORT_SYMBOL_GPL(clk_debug_measure_add);
-
-int clk_register_debug(struct clk_hw *hw, struct dentry *dentry)
-{
- if (IS_ERR_OR_NULL(measure)) {
- if (hw->init->flags & CLK_IS_MEASURE)
- measure = hw;
- if (!IS_ERR_OR_NULL(measure))
- clk_debug_measure_add(hw, dentry);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(clk_register_debug);
-
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 95408a47fef0..c532444a0d40 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -13,7 +13,7 @@
#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__
-#include "../clk.h"
+#include "clk-debug.h"
struct platform_device;
struct regmap_config;
@@ -54,107 +54,9 @@ extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
extern struct clk_ops clk_dummy_ops;
-/* Debugfs Measure Clocks */
-
-/**
- * struct measure_clk_data - Structure of clk measure
- *
- * @cxo: XO clock.
- * @xo_div4_cbcr: offset of debug XO/4 div register.
- * @ctl_reg: offset of debug control register.
- * @status_reg: offset of debug status register.
- *
- */
-struct measure_clk_data {
- struct clk *cxo;
- u32 xo_div4_cbcr;
- u32 ctl_reg;
- u32 status_reg;
-};
-
-/**
- * List of Debug clock controllers.
- */
-enum debug_cc {
- GCC,
- MMCC,
- GPU,
- CPU,
-};
-
-/**
- * struct clk_src - Struture of clock source for debug mux
- *
- * @parents: clock name to be used as parent for debug mux.
- * @sel: debug mux index at global clock controller.
- * @dbg_cc: indicates the clock controller for recursive debug clock
- * controllers.
- * @next_sel: indicates the debug mux index at recursive debug mux.
- * @mask: indicates the mask required at recursive debug mux.
- * @shift: indicates the shift required at recursive debug mux.
- * @en_mask: indicates the enable bit mask at recursive debug mux.
- * Incase the recursive debug mux does not have a enable bit,
- * 0xFF should be used to indicate the same, otherwise global
- * enable bit would be used.
- * @post_div_mask: indicates the post div mask to be used at debug/recursive
- * debug mux.
- * @post_div_val: indicates the post div value to be used at debug/recursive
- * debug mux.
- */
-struct clk_src {
- const char *parents;
- int sel;
- enum debug_cc dbg_cc;
- int next_sel;
- u32 mask;
- u32 shift;
- u32 en_mask;
- u32 post_div_mask;
- u32 post_div_val;
-};
-
-#define MUX_SRC_LIST(...) \
- .parent = (struct clk_src[]){__VA_ARGS__}, \
- .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
-
-/**
- * struct clk_debug_mux - Struture of clock debug mux
- *
- * @parent: structure of clk_src
- * @num_parents: number of parents
- * @regmap: regmaps of debug mux
- * @num_parent_regmap: number of regmap of debug mux
- * @priv: private measure_clk_data to be used by debug mux
- * @en_mask: indicates the enable bit mask at global clock
- * controller debug mux.
- * @mask: indicates the mask to be used at global clock
- * controller debug mux.
- * @debug_offset: Start of debug mux offset.
- * @hw: handle between common and hardware-specific interfaces.
- * @multiplier: internally used by debug mux as post div multiplier.
- */
-struct clk_debug_mux {
- struct clk_src *parent;
- int num_parents;
- struct regmap **regmap;
- int num_parent_regmap;
- void *priv;
- u32 en_mask;
- u32 mask;
- u32 debug_offset;
- struct clk_hw hw;
-
- /* internal */
- u32 multiplier;
-};
-
#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
-#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
-
-extern const struct clk_ops clk_debug_mux_ops;
-
#define WARN_CLK(core, name, cond, fmt, ...) do { \
clk_debug_print_hw(core, NULL); \
WARN(cond, "%s: " fmt, name, ##__VA_ARGS__); \
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index c282253da584..b55310e091af 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -27,6 +27,7 @@
#include "clk-alpha-pll.h"
#include "clk-branch.h"
+#include "clk-debug.h"
#include "common.h"
#include "clk-pll.h"
#include "clk-regmap.h"
@@ -3328,7 +3329,11 @@ static int clk_debug_660_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
- dev_info(&pdev->dev, "Registered debug mux successfully\n");
+ ret = clk_register_debug(&gcc_debug_mux.hw);
+ if (ret)
+ dev_err(&pdev->dev, "Could not register Measure clock\n");
+ else
+ dev_info(&pdev->dev, "Registered debug mux successfully\n");
return ret;
}
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 833bb4a17b6a..9b7f014e1cec 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -149,6 +149,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
} else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_sdm660")) {
pll_res->target_id = MDSS_PLL_TARGET_SDM660;
pll_res->pll_interface_type = MDSS_DP_PLL_SDM660;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_sdm630")) {
+ pll_res->target_id = MDSS_PLL_TARGET_SDM630;
+ pll_res->pll_interface_type = MDSS_DP_PLL_SDM630;
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) {
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996;
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) {
@@ -189,6 +192,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
case MDSS_DP_PLL_SDM660:
rc = dp_pll_clock_register_14nm(pdev, pll_res);
break;
+ case MDSS_DP_PLL_SDM630:
+ rc = dp_pll_clock_register_14nm(pdev, pll_res);
+ break;
case MDSS_UNKNOWN_PLL:
default:
rc = -EINVAL;
@@ -396,6 +402,7 @@ static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_dsi_pll_sdm660"},
{.compatible = "qcom,mdss_dp_pll_sdm660"},
{.compatible = "qcom,mdss_dsi_pll_sdm630"},
+ {.compatible = "qcom,mdss_dp_pll_sdm630"},
{}
};
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index cb6918127041..369c36407ff7 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -42,6 +42,7 @@ enum {
MDSS_DSI_PLL_8998,
MDSS_DP_PLL_8998,
MDSS_DP_PLL_SDM660,
+ MDSS_DP_PLL_SDM630,
MDSS_HDMI_PLL_8996,
MDSS_HDMI_PLL_8996_V2,
MDSS_HDMI_PLL_8996_V3,
diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c
index 87e6f8c6be0a..910c36c65b6a 100644
--- a/drivers/clk/qcom/mmcc-sdm660.c
+++ b/drivers/clk/qcom/mmcc-sdm660.c
@@ -978,12 +978,11 @@ static struct clk_rcg2 esc0_clk_src = {
.mnd_width = 0,
.hid_width = 5,
.parent_map = mmcc_parent_map_1,
- .freq_tbl = ftbl_dp_aux_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc0_clk_src",
.parent_names = mmcc_parent_names_1,
.num_parents = 4,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_esc_ops,
VDD_DIG_FMAX_MAP1(
LOWER, 19200000),
},
@@ -994,12 +993,11 @@ static struct clk_rcg2 esc1_clk_src = {
.mnd_width = 0,
.hid_width = 5,
.parent_map = mmcc_parent_map_1,
- .freq_tbl = ftbl_dp_aux_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc1_clk_src",
.parent_names = mmcc_parent_names_1,
.num_parents = 4,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_esc_ops,
VDD_DIG_FMAX_MAP1(
LOWER, 19200000),
},
@@ -1041,7 +1039,7 @@ static const struct freq_tbl ftbl_mclk0_clk_src[] = {
F(9600000, P_CXO, 2, 0, 0),
F(16666667, P_GPLL0_OUT_MAIN_DIV, 2, 1, 9),
F(19200000, P_CXO, 1, 0, 0),
- F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25),
+ F(24000000, P_MMPLL10_PLL_OUT_MAIN, 1, 1, 24),
F(33333333, P_GPLL0_OUT_MAIN_DIV, 1, 1, 9),
F(48000000, P_GPLL0_OUT_MAIN, 1, 2, 25),
F(66666667, P_GPLL0_OUT_MAIN, 1, 1, 9),
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
index 8831e1a05367..11d8aa3ec186 100644
--- a/drivers/clk/ti/clk-3xxx.c
+++ b/drivers/clk/ti/clk-3xxx.c
@@ -22,13 +22,6 @@
#include "clock.h"
-/*
- * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
- * that are sourced by DPLL5, and both of these require this clock
- * to be at 120 MHz for proper operation.
- */
-#define DPLL5_FREQ_FOR_USBHOST 120000000
-
#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1
#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5
#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8
@@ -546,14 +539,21 @@ void __init omap3_clk_lock_dpll5(void)
struct clk *dpll5_clk;
struct clk *dpll5_m2_clk;
+ /*
+ * Errata sprz319f advisory 2.1 documents a USB host clock drift issue
+ * that can be worked around using specially crafted dpll5 settings
+ * with a dpll5_m2 divider set to 8. Set the dpll5 rate to 8x the USB
+ * host clock rate, its .set_rate handler() will detect that frequency
+ * and use the errata settings.
+ */
dpll5_clk = clk_get(NULL, "dpll5_ck");
- clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+ clk_set_rate(dpll5_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST * 8);
clk_prepare_enable(dpll5_clk);
- /* Program dpll5_m2_clk divider for no division */
+ /* Program dpll5_m2_clk divider */
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
clk_prepare_enable(dpll5_m2_clk);
- clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+ clk_set_rate(dpll5_m2_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST);
clk_disable_unprepare(dpll5_m2_clk);
clk_disable_unprepare(dpll5_clk);
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
index 90f3f472ae1c..13c37f48d9d6 100644
--- a/drivers/clk/ti/clock.h
+++ b/drivers/clk/ti/clock.h
@@ -257,11 +257,20 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long parent_rate);
+/*
+ * OMAP3_DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
+ * that are sourced by DPLL5, and both of these require this clock
+ * to be at 120 MHz for proper operation.
+ */
+#define OMAP3_DPLL5_FREQ_FOR_USBHOST 120000000
+
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
unsigned long parent_rate);
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index);
+int omap3_dpll5_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
void omap3_clk_lock_dpll5(void);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 5519b386edc0..f9a5089ddc79 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -114,6 +114,18 @@ static const struct clk_ops omap3_dpll_ck_ops = {
.round_rate = &omap2_dpll_round_rate,
};
+static const struct clk_ops omap3_dpll5_ck_ops = {
+ .enable = &omap3_noncore_dpll_enable,
+ .disable = &omap3_noncore_dpll_disable,
+ .get_parent = &omap2_init_dpll_parent,
+ .recalc_rate = &omap3_dpll_recalc,
+ .set_rate = &omap3_dpll5_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
+ .round_rate = &omap2_dpll_round_rate,
+};
+
static const struct clk_ops omap3_dpll_per_ck_ops = {
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
@@ -461,7 +473,12 @@ static void __init of_ti_omap3_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd);
+ if ((of_machine_is_compatible("ti,omap3630") ||
+ of_machine_is_compatible("ti,omap36xx")) &&
+ !strcmp(node->name, "dpll5_ck"))
+ of_ti_dpll_setup(node, &omap3_dpll5_ck_ops, &dd);
+ else
+ of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
of_ti_omap3_dpll_setup);
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index f4dec00fb684..0e9119fae760 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -815,3 +815,70 @@ int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
index);
}
+
+/* Apply DM3730 errata sprz319 advisory 2.1. */
+static bool omap3_dpll5_apply_errata(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct omap3_dpll5_settings {
+ unsigned int rate, m, n;
+ };
+
+ static const struct omap3_dpll5_settings precomputed[] = {
+ /*
+ * From DM3730 errata advisory 2.1, table 35 and 36.
+ * The N value is increased by 1 compared to the tables as the
+ * errata lists register values while last_rounded_field is the
+ * real divider value.
+ */
+ { 12000000, 80, 0 + 1 },
+ { 13000000, 443, 5 + 1 },
+ { 19200000, 50, 0 + 1 },
+ { 26000000, 443, 11 + 1 },
+ { 38400000, 25, 0 + 1 }
+ };
+
+ const struct omap3_dpll5_settings *d;
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(precomputed); ++i) {
+ if (parent_rate == precomputed[i].rate)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(precomputed))
+ return false;
+
+ d = &precomputed[i];
+
+ /* Update the M, N and rounded rate values and program the DPLL. */
+ dd = clk->dpll_data;
+ dd->last_rounded_m = d->m;
+ dd->last_rounded_n = d->n;
+ dd->last_rounded_rate = div_u64((u64)parent_rate * d->m, d->n);
+ omap3_noncore_dpll_program(clk, 0);
+
+ return true;
+}
+
+/**
+ * omap3_dpll5_set_rate - set rate for omap3 dpll5
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Set rate for the DPLL5 clock. Apply the sprz319 advisory 2.1 on OMAP36xx if
+ * the DPLL is used for USB host (detected through the requested rate).
+ */
+int omap3_dpll5_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ if (rate == OMAP3_DPLL5_FREQ_FOR_USBHOST * 8) {
+ if (omap3_dpll5_apply_errata(hw, parent_rate))
+ return 0;
+ }
+
+ return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
+}