diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 4f1ba98a2b2c..e8e48015d3af 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2649,7 +2649,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; @@ -2663,6 +2663,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) { diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index c95a327a9301..25bf4bc85f5c 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -25,6 +25,7 @@ void __clk_free_clk(struct clk *clk); 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 /* All these casts to avoid ifdefs in clkdev... */ diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 375f1420f3bb..e6054444599c 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -16,8 +16,10 @@ #include #include #include +#include #include "clk-alpha-pll.h" +#include "common.h" #define PLL_MODE 0x00 #define PLL_OUTCTRL BIT(0) @@ -74,13 +76,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) @@ -93,7 +99,13 @@ 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; } @@ -589,7 +601,11 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw) {"PLL_ALPHA_VAL", 0x8}, {"PLL_ALPHA_VAL_U", 0xC}, {"PLL_USER_CTL", 0x10}, + {"PLL_USER_CTL_U", 0x14}, {"PLL_CONFIG_CTL", 0x18}, + {"PLL_TEST_CTL", 0x1c}, + {"PLL_TEST_CTL_U", 0x20}, + {"PLL_STATUS", 0x24}, }; static struct clk_register_data data1[] = { @@ -601,7 +617,8 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw) for (i = 0; i < size; i++) { regmap_read(pll->clkr.regmap, pll->offset + 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); } regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val); @@ -609,7 +626,8 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw) if (val & PLL_FSM_ENA) { regmap_read(pll->clkr.regmap, pll->clkr.enable_reg + data1[0].offset, &val); - seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val); + clock_debug_output(f, false, "%20s: 0x%.8x\n", + data1[0].name, val); } } diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index bfaf4482d668..ca6010db8d78 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -22,6 +22,7 @@ #include "clk-branch.h" #include "clk-regmap.h" +#include "common.h" static bool clk_branch_in_hwcg_mode(const struct clk_branch *br) { @@ -77,7 +78,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)) @@ -104,8 +106,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, - enabling ? "ff" : "n"); + + WARN_CLK(hw->core, name, 1, "status stuck at 'o%s'", + enabling ? "ff" : "n"); + return -EBUSY; } return 0; @@ -212,7 +216,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) && @@ -222,7 +227,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); } } @@ -360,7 +365,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); } } diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 6e6adbff4676..a07deb902577 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -122,7 +122,7 @@ err: 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; @@ -144,7 +144,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; } @@ -153,13 +157,17 @@ 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); ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, CFG_SRC_SEL_MASK, cfg); if (ret) return ret; - return update_config(rcg); + return update_config(rcg, old_cfg); } static void clk_rcg_clear_force_enable(struct clk_hw *hw) @@ -297,13 +305,16 @@ static int clk_rcg2_determine_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); 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, @@ -333,7 +344,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) @@ -359,14 +370,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); } } } @@ -1186,16 +1199,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, @@ -1271,9 +1287,12 @@ static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw, { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f; - 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); + cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; f = qcom_find_freq(rcg->freq_tbl, rate); @@ -1287,7 +1306,7 @@ static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw, if (ret) return ret; - return update_config(rcg); + return update_config(rcg, old_cfg); } const struct clk_ops clk_gfx3d_src_ops = { diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 06ec0bb0bc29..95408a47fef0 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -13,6 +13,8 @@ #ifndef __QCOM_CLK_COMMON_H__ #define __QCOM_CLK_COMMON_H__ +#include "../clk.h" + struct platform_device; struct regmap_config; struct clk_regmap; @@ -153,4 +155,19 @@ struct clk_debug_mux { 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__); \ +} 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) + #endif