[RFC PATCH 22/34] msm: clock-8x60: Support measurement of CPU and L2 clocks

From: David Brown
Date: Wed Nov 02 2011 - 14:39:05 EST


From: Matt Wagantall <mattw@xxxxxxxxxxxxxx>

Users of these debug facilities should keep in mind that these
clocks can gate automatically when the CPU or L2 is idle,
resulting in a lower-than-expected or 0 Hz measurement in those
cases.

Also, because the test points used to measure these clocks are
after a hard-wired divide-by-two, the rates of these clocks
are multiplied again by two in software to get the actual CPU
and L2 rates. When observing these clocks on an oscilloscope,
however, the half-rate clocks are what is seen.

CRs-Fixed: 273908
Signed-off-by: Matt Wagantall <mattw@xxxxxxxxxxxxxx>
Signed-off-by: David Brown <davidb@xxxxxxxxxxxxxx>
---
arch/arm/mach-msm/clock-8x60.c | 51 ++++++++++++++++++++++++++++++--------
arch/arm/mach-msm/clock-local.c | 4 +++
arch/arm/mach-msm/clock-local.h | 29 ++++++++++++++++++++++
3 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 7dac975..71e014d 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -219,6 +219,7 @@
#define TEST_TYPE_MM_LS 3
#define TEST_TYPE_MM_HS 4
#define TEST_TYPE_LPA 5
+#define TEST_TYPE_SC 6
#define TEST_TYPE_SHIFT 24
#define TEST_CLK_SEL_MASK BM(23, 0)
#define TEST_VECTOR(s, t) (((t) << TEST_TYPE_SHIFT) | BVAL(23, 0, (s)))
@@ -227,6 +228,7 @@
#define TEST_MM_LS(s) TEST_VECTOR((s), TEST_TYPE_MM_LS)
#define TEST_MM_HS(s) TEST_VECTOR((s), TEST_TYPE_MM_HS)
#define TEST_LPA(s) TEST_VECTOR((s), TEST_TYPE_LPA)
+#define TEST_SC(s) TEST_VECTOR((s), TEST_TYPE_SC)

struct pll_rate {
const uint32_t l_val;
@@ -3126,6 +3128,10 @@ static struct rcg_clk pcm_clk = {
},
};

+static DEFINE_CLK_MEASURE(sc0_m_clk);
+static DEFINE_CLK_MEASURE(sc1_m_clk);
+static DEFINE_CLK_MEASURE(l2_m_clk);
+
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
u32 test_vector;
@@ -3271,6 +3277,10 @@ static struct measure_sel measure_mux[] = {
{ TEST_LPA(0x12), &spare_i2s_spkr_osr_clk.c },
{ TEST_LPA(0x13), &spare_i2s_spkr_bit_clk.c },
{ TEST_LPA(0x14), &pcm_clk.c },
+
+ { TEST_SC(0x40), &sc0_m_clk },
+ { TEST_SC(0x41), &sc1_m_clk },
+ { TEST_SC(0x42), &l2_m_clk },
};

static struct measure_sel *find_measure_sel(struct clk *clk)
@@ -3283,11 +3293,12 @@ static struct measure_sel *find_measure_sel(struct clk *clk)
return NULL;
}

-static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
{
int ret = 0;
u32 clk_sel;
struct measure_sel *p;
+ struct measure_clk *clk = to_measure_clk(c);
unsigned long flags;

if (!parent)
@@ -3299,8 +3310,13 @@ static int measure_clk_set_parent(struct clk *clk, struct clk *parent)

spin_lock_irqsave(&local_clock_reg_lock, flags);

- /* Program the test vector. */
+ /*
+ * Program the test vector, measurement period (sample_ticks)
+ * and scaling factor (multiplier).
+ */
clk_sel = p->test_vector & TEST_CLK_SEL_MASK;
+ clk->sample_ticks = 0x10000;
+ clk->multiplier = 1;
switch (p->test_vector >> TEST_TYPE_SHIFT) {
case TEST_TYPE_PER_LS:
writel_relaxed(0x4030D00|BVAL(7, 0, clk_sel), CLK_TEST_REG);
@@ -3321,6 +3337,11 @@ static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0),
LCC_CLK_LS_DEBUG_CFG_REG);
break;
+ case TEST_TYPE_SC:
+ writel_relaxed(0x5020000|BVAL(16, 10, clk_sel), CLK_TEST_REG);
+ clk->sample_ticks = 0x4000;
+ clk->multiplier = 2;
+ break;
default:
ret = -EPERM;
}
@@ -3357,11 +3378,12 @@ static u32 run_measurement(unsigned ticks)

/* Perform a hardware rate measurement for a given clock.
FOR DEBUG USE ONLY: Measurements take ~15 ms! */
-static unsigned measure_clk_get_rate(struct clk *clk)
+static unsigned measure_clk_get_rate(struct clk *c)
{
unsigned long flags;
u32 pdm_reg_backup, ringosc_reg_backup;
u64 raw_count_short, raw_count_full;
+ struct measure_clk *clk = to_measure_clk(c);
unsigned ret;

spin_lock_irqsave(&local_clock_reg_lock, flags);
@@ -3382,7 +3404,7 @@ static unsigned measure_clk_get_rate(struct clk *clk)
/* Run a short measurement. (~1 ms) */
raw_count_short = run_measurement(0x1000);
/* Run a full measurement. (~14 ms) */
- raw_count_full = run_measurement(0x10000);
+ raw_count_full = run_measurement(clk->sample_ticks);

writel_relaxed(ringosc_reg_backup, RINGOSC_NS_REG);
writel_relaxed(pdm_reg_backup, PDM_CLK_NS_REG);
@@ -3393,8 +3415,8 @@ static unsigned measure_clk_get_rate(struct clk *clk)
else {
/* Compute rate in Hz. */
raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
- do_div(raw_count_full, ((0x10000 * 10) + 35));
- ret = raw_count_full;
+ do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+ ret = (raw_count_full * clk->multiplier);
}

/* Route dbg_hs_clk to PLLTEST. 300mV single-ended amplitude. */
@@ -3421,17 +3443,20 @@ static struct clk_ops measure_clk_ops = {
.is_local = local_clk_is_local,
};

-static struct clk measure_clk = {
- .dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
- CLK_INIT(measure_clk),
+static struct measure_clk measure_clk = {
+ .c = {
+ .dbg_name = "measure_clk",
+ .ops = &measure_clk_ops,
+ CLK_INIT(measure_clk.c),
+ },
+ .multiplier = 1,
};

struct clk_lookup msm_clocks_8x60[] = {
CLK_LOOKUP("cxo", cxo_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("pll4", pll4_clk.c, "peripheral-reset"),
- CLK_LOOKUP("measure", measure_clk, "debug"),
+ CLK_LOOKUP("measure", measure_clk.c, "debug"),

CLK_LOOKUP("gsbi_uart_clk", gsbi1_uart_clk.c, NULL),
CLK_LOOKUP("gsbi_uart_clk", gsbi2_uart_clk.c, NULL),
@@ -3592,6 +3617,10 @@ struct clk_lookup msm_clocks_8x60[] = {
CLK_LOOKUP("iommu_clk", gfx3d_clk.c, "msm_iommu.9"),
CLK_LOOKUP("iommu_clk", gfx2d0_clk.c, "msm_iommu.10"),
CLK_LOOKUP("iommu_clk", gfx2d1_clk.c, "msm_iommu.11"),
+
+ CLK_LOOKUP("sc0_mclk", sc0_m_clk, NULL),
+ CLK_LOOKUP("sc1_mclk", sc1_m_clk, NULL),
+ CLK_LOOKUP("l2_mclk", l2_m_clk, NULL),
};
unsigned msm_num_clocks_8x60 = ARRAY_SIZE(msm_clocks_8x60);

diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index c79895c..e2dab7a 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -861,6 +861,10 @@ struct fixed_clk gnd_clk = {
},
};

+struct clk_ops clk_ops_measure = {
+ .is_local = local_clk_is_local,
+};
+
int branch_clk_enable(struct clk *clk)
{
int rc;
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index e004490..6d48e61 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -33,6 +33,16 @@
#define DELAY 5 /* No bit to check, just delay */

/*
+ * Clock Definition Macros
+ */
+#define DEFINE_CLK_MEASURE(name) \
+ struct clk name = { \
+ .ops = &clk_ops_measure, \
+ .dbg_name = #name, \
+ CLK_INIT(name), \
+ }; \
+
+/*
* Generic frequency-definition structs and macros
*/
struct clk_freq_tbl {
@@ -255,6 +265,25 @@ unsigned branch_clk_is_enabled(struct clk *clk);
void branch_clk_auto_off(struct clk *clk);
int branch_clk_reset(struct clk *c, enum clk_reset_action action);

+/**
+ * struct measure_clk - for rate measurement debug use
+ * @sample_ticks: sample period in reference clock ticks
+ * @multiplier: measurement scale-up factor
+ * @c: clk
+*/
+struct measure_clk {
+ u64 sample_ticks;
+ u32 multiplier;
+ struct clk c;
+};
+
+extern struct clk_ops clk_ops_measure;
+
+static inline struct measure_clk *to_measure_clk(struct clk *clk)
+{
+ return container_of(clk, struct measure_clk, c);
+}
+
/*
* Variables from clock-local driver
*/
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/