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

Commit 8dc79c03 authored by Taniya Das's avatar Taniya Das Committed by Deepak Katragadda
Browse files

clk: qcom: Add support to log clock registers in case of failure



In case of PLL lock errors, RCGR configuration update failures,
and branch clock toggle timeouts, add support to capture the
clock registers as part of kernel logs.

Change-Id: Ifb0cefafc30f8796ba17f2d388fb65ed41aae485
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent d0c80e68
Loading
Loading
Loading
Loading
+2 −11
Original line number Diff line number Diff line
@@ -2632,16 +2632,6 @@ static int clock_debug_enable_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
			clock_debug_enable_set, "%lld\n");

#define clock_debug_output(m, c, fmt, ...)		\
do {							\
	if (m)						\
		seq_printf(m, fmt, ##__VA_ARGS__);	\
	else if (c)					\
		pr_cont(fmt, ##__VA_ARGS__);		\
	else						\
		pr_info(fmt, ##__VA_ARGS__);		\
} while (0)

/*
 * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks
 * during suspend.
@@ -2757,7 +2747,7 @@ static const struct file_operations clk_enabled_list_fops = {
	.release	= seq_release,
};

static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
{
	if (IS_ERR_OR_NULL(clk))
		return;
@@ -2771,6 +2761,7 @@ static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)

	clk->ops->list_registers(f, clk->hw);
}
EXPORT_SYMBOL(clk_debug_print_hw);

static int print_hw_show(struct seq_file *m, void *unused)
{
+16 −0
Original line number Diff line number Diff line
@@ -23,6 +23,22 @@ void __clk_free_clk(struct clk *clk);

/* Debugfs API to print the enabled clocks */
void clock_debug_print_enabled(void);
void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);

#define WARN_CLK(core, name, cond, fmt, ...) do {		\
		clk_debug_print_hw(core, NULL);			\
		WARN(cond, "%s: " fmt, name, ##__VA_ARGS__);	\
} while (0)

#define clock_debug_output(m, c, fmt, ...)		\
do {							\
	if (m)						\
		seq_printf(m, fmt, ##__VA_ARGS__);	\
	else if (c)					\
		pr_cont(fmt, ##__VA_ARGS__);		\
	else						\
		pr_info(fmt, ##__VA_ARGS__);		\
} while (0)

#else
/* All these casts to avoid ifdefs in clkdev... */
+16 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/sched/clock.h>

#include "clk-alpha-pll.h"
#include "common.h"
@@ -110,13 +111,17 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
	u32 val, off;
	int count;
	int ret;
	const char *name = clk_hw_get_name(&pll->clkr.hw);
	u64 time;
	struct clk_hw *hw = &pll->clkr.hw;
	const char *name = clk_hw_get_name(hw);

	off = pll->offset;
	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
	if (ret)
		return ret;

	time = sched_clock();

	for (count = 100; count > 0; count--) {
		ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
		if (ret)
@@ -129,7 +134,12 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
		udelay(1);
	}

	WARN(1, "%s failed to %s!\n", name, action);
	time = sched_clock() - time;

	pr_err("PLL lock bit detection total wait time: %lld ns", time);

	WARN_CLK(hw->core, name, 1, "failed to %s!\n", action);

	return -ETIMEDOUT;
}

@@ -499,7 +509,8 @@ static void print_pll_registers(struct seq_file *f, struct clk_hw *hw,
	for (i = 0; i < size; i++) {
		regmap_read(pll->clkr.regmap, pll->offset + pll_regs[i].offset,
					&val);
		seq_printf(f, "%20s: 0x%.8x\n", pll_regs[i].name, val);
		clock_debug_output(f, false, "%20s: 0x%.8x\n", pll_regs[i].name,
					val);
	}

	regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, &val);
@@ -507,7 +518,8 @@ static void print_pll_registers(struct seq_file *f, struct clk_hw *hw,
	if (val & PLL_FSM_ENA) {
		regmap_read(pll->clkr.regmap, pll->clkr.enable_reg +
					pll_vote_reg->offset, &val);
		seq_printf(f, "%20s: 0x%.8x\n", pll_vote_reg->name, val);
		clock_debug_output(f, false, "%20s: 0x%.8x\n",
					pll_vote_reg->name, val);
	}
}

+12 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#include "clk-branch.h"
#include "clk-regmap.h"
#include "common.h"

static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
{
@@ -78,7 +79,8 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
		bool (check_halt)(const struct clk_branch *, bool))
{
	bool voted = br->halt_check & BRANCH_VOTED;
	const char *name = clk_hw_get_name(&br->clkr.hw);
	const struct clk_hw *hw = &br->clkr.hw;
	const char *name = clk_hw_get_name(hw);

	/* Skip checking halt bit if the clock is in hardware gated mode */
	if (clk_branch_in_hwcg_mode(br))
@@ -96,8 +98,10 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
				return 0;
			udelay(1);
		}
		WARN(1, "%s status stuck at 'o%s'", name,

		WARN_CLK(hw->core, name, 1, "status stuck at 'o%s'",
						enabling ? "ff" : "n");

		return -EBUSY;
	}
	return 0;
@@ -340,7 +344,8 @@ static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
	for (i = 0; i < size; i++) {
		regmap_read(br->clkr.regmap, br->halt_reg + data[i].offset,
					&val);
		seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
		clock_debug_output(f, false, "%20s: 0x%.8x\n",
							data[i].name, val);
	}

	if ((br->halt_check & BRANCH_HALT_VOTED) &&
@@ -350,7 +355,7 @@ static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
			for (i = 0; i < size; i++) {
				regmap_read(br->clkr.regmap, rclk->enable_reg +
						data1[i].offset, &val);
				seq_printf(f, "%20s: 0x%.8x\n",
				clock_debug_output(f, false, "%20s: 0x%.8x\n",
						data1[i].name, val);
			}
		}
@@ -479,7 +484,8 @@ static void clk_gate2_list_registers(struct seq_file *f, struct clk_hw *hw)
	for (i = 0; i < size; i++) {
		regmap_read(gt->clkr.regmap, gt->clkr.enable_reg +
					data[i].offset, &val);
		seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
		clock_debug_output(f, false, "%20s: 0x%.8x\n",
						data[i].name, val);
	}
}

+25 −9
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw)
	return 0;
}

static int update_config(struct clk_rcg2 *rcg)
static int update_config(struct clk_rcg2 *rcg, u32 cfg)
{
	int count, ret;
	u32 cmd;
@@ -131,7 +131,11 @@ static int update_config(struct clk_rcg2 *rcg)
		udelay(1);
	}

	WARN(1, "%s: rcg didn't update its configuration.", name);
	pr_err("CFG_RCGR old frequency configuration 0x%x !\n", cfg);

	WARN_CLK(hw->core, name, count == 0,
			"rcg didn't update its configuration.");

	return 0;
}

@@ -140,6 +144,10 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	int ret;
	u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
	u32 old_cfg;

	/* Read back the old configuration */
	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);

	if (rcg->flags & DFS_ENABLE_RCG)
		return 0;
@@ -149,7 +157,7 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
	if (ret)
		return ret;

	return update_config(rcg);
	return update_config(rcg, old_cfg);
}

static int clk_rcg2_set_force_enable(struct clk_hw *hw)
@@ -368,7 +376,7 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw *hw,

static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
{
	u32 cfg, mask;
	u32 cfg, mask, old_cfg;
	struct clk_hw *hw = &rcg->clkr.hw;
	int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);

@@ -378,6 +386,9 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
	if (index < 0)
		return index;

	/* Read back the old configuration */
	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);

	if (rcg->mnd_width && f->n) {
		mask = BIT(rcg->mnd_width) - 1;
		ret = regmap_update_bits(rcg->clkr.regmap,
@@ -407,7 +418,7 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
	if (ret)
		return ret;

	return update_config(rcg);
	return update_config(rcg, old_cfg);
}

static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw)
@@ -433,14 +444,16 @@ static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw)
		for (i = 0; i < size; i++) {
			regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
					data1[i].offset), &val);
			seq_printf(f, "%20s: 0x%.8x\n",	data1[i].name, val);
			clock_debug_output(f, false, "%20s: 0x%.8x\n",
						data1[i].name, val);
		}
	} else {
		size = ARRAY_SIZE(data);
		for (i = 0; i < size; i++) {
			regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
				data[i].offset), &val);
			seq_printf(f, "%20s: 0x%.8x\n",	data[i].name, val);
			clock_debug_output(f, false, "%20s: 0x%.8x\n",
						data[i].name, val);
		}
	}
}
@@ -1220,16 +1233,19 @@ static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate, u8 index)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	u32 cfg;
	u32 cfg, old_cfg;
	int ret;

	/* Read back the old configuration */
	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);

	/* Just mux it, we don't use the division or m/n hardware */
	cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
	ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
	if (ret)
		return ret;

	return update_config(rcg);
	return update_config(rcg, old_cfg);
}

static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
Loading