Merge "clk: qcom: Add support to log PLL/RCGR values in case of failure"

This commit is contained in:
Linux Build Service Account 2017-02-15 17:00:58 -08:00 committed by Gerrit - the friendly Code Review server
commit d76b403a39
6 changed files with 84 additions and 22 deletions

View file

@ -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)
{

View file

@ -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... */

View file

@ -16,8 +16,10 @@
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/sched.h>
#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);
}
}

View file

@ -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);
}
}

View file

@ -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 = {

View file

@ -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