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

Commit fb2a809d authored by Vikram Mulukutla's avatar Vikram Mulukutla
Browse files

msm: clock-local2: Add debug mux measurement support



In the near future, the debug muxes present in MSM clock
controllers will be modelled using the clock-generic
library. Add private data and a get_rate function to
support measurement using that library.

Change-Id: If8b1caac029190976fb98aa1f71267fc5ecfeb13
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
parent 5e06a050
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/clk.h>

#include <mach/clk.h>
#include <mach/clock-generic.h>
#include <mach/clk-provider.h>
#include <mach/clock-generic.h>

@@ -698,6 +699,85 @@ static enum handoff local_vote_clk_handoff(struct clk *c)
	return HANDOFF_ENABLED_CLK;
}

/* Sample clock for 'ticks' reference clock ticks. */
static u32 run_measurement(unsigned ticks, void __iomem *ctl_reg,
				void __iomem *status_reg)
{
	/* Stop counters and set the XO4 counter start value. */
	writel_relaxed(ticks, ctl_reg);

	/* Wait for timer to become ready. */
	while ((readl_relaxed(status_reg) & BIT(25)) != 0)
		cpu_relax();

	/* Run measurement and wait for completion. */
	writel_relaxed(BIT(20)|ticks, ctl_reg);
	while ((readl_relaxed(status_reg) & BIT(25)) == 0)
		cpu_relax();

	/* Return measured ticks. */
	return readl_relaxed(status_reg) & BM(24, 0);
}

/*
 * Perform a hardware rate measurement for a given clock.
 * FOR DEBUG USE ONLY: Measurements take ~15 ms!
 */
unsigned long measure_get_rate(struct clk *c)
{
	unsigned long flags;
	u32 gcc_xo4_reg_backup;
	u64 raw_count_short, raw_count_full;
	unsigned ret;
	u32 sample_ticks = 0x10000;
	u32 multiplier = 0x1;
	struct measure_clk_data *data = to_mux_clk(c)->priv;

	ret = clk_prepare_enable(data->cxo);
	if (ret) {
		pr_warn("CXO clock failed to enable. Can't measure\n");
		return 0;
	}

	spin_lock_irqsave(&local_clock_reg_lock, flags);

	/* Enable CXO/4 and RINGOSC branch. */
	gcc_xo4_reg_backup = readl_relaxed(*data->base + data->xo_div4_cbcr);
	writel_relaxed(0x1, *data->base + data->xo_div4_cbcr);

	/*
	 * 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, *data->base + data->ctl_reg,
					  *data->base + data->status_reg);
	/* Run a full measurement. (~14 ms) */
	raw_count_full = run_measurement(sample_ticks,
					 *data->base + data->ctl_reg,
					 *data->base + data->status_reg);
	writel_relaxed(gcc_xo4_reg_backup, *data->base + data->xo_div4_cbcr);

	/* 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);
	}
	writel_relaxed(data->plltest_val, *data->base + data->plltest_reg);
	spin_unlock_irqrestore(&local_clock_reg_lock, flags);

	clk_disable_unprepare(data->cxo);

	return ret;
}

struct frac_entry {
	int num;
	int den;
+12 −0
Original line number Diff line number Diff line
@@ -165,9 +165,20 @@ struct measure_clk {
	u64 sample_ticks;
	u32 multiplier;
	u32 divider;

	struct clk c;
};

struct measure_clk_data {
	struct clk *cxo;
	u32 plltest_reg;
	u32 plltest_val;
	u32 xo_div4_cbcr;
	u32 ctl_reg;
	u32 status_reg;
	void *const __iomem *base;
};

static inline struct measure_clk *to_measure_clk(struct clk *clk)
{
	return container_of(clk, struct measure_clk, c);
@@ -219,6 +230,7 @@ extern struct clk_mux_ops mux_reg_ops;

enum handoff pixel_rcg_handoff(struct clk *clk);
enum handoff byte_rcg_handoff(struct clk *clk);
unsigned long measure_get_rate(struct clk *c);

/*
 * Clock definition macros