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

Commit 365ba81c authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: qcom: Add additional clock debugfs support"

parents 72f168d2 ea8a2984
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -23,6 +23,15 @@ config COMMON_CLK
menu "Common Clock Framework"
	depends on COMMON_CLK

config COMMON_CLK_QCOM_DEBUG
	bool "QCOM clock debug features"
	depends on DEBUG_FS && QGKI
	help
	  Support for QCOM debug features. These features include
	  modifications to existing debugfs nodes to make them writable (e.g.
	  clk_enable_count, clk_rate), as well as new debugfs nodes (e.g.
	  clk_enabled_list, debug_suspend, trace_clocks).

config COMMON_CLK_WM831X
	tristate "Clock driver for WM831x/2x PMICs"
	depends on MFD_WM831X
+231 −2
Original line number Diff line number Diff line
@@ -3127,6 +3127,76 @@ static int clk_max_rate_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(clk_max_rate);

static int clock_debug_rate_set(void *data, u64 val)
{
	struct clk_core *core = data;
	int ret;

	ret = clk_set_rate(core->hw->clk, val);
	if (ret)
		pr_err("clk_set_rate(%lu) failed (%d)\n",
				(unsigned long)val, ret);

	return ret;
}

static int clock_debug_rate_get(void *data, u64 *val)
{
	struct clk_core *core = data;

	*val = clk_get_rate(core->hw->clk);

	return 0;
}

DEFINE_DEBUGFS_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
			clock_debug_rate_set, "%llu\n");

static ssize_t clock_parent_read(struct file *filp, char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	char name[256] = {0};
	struct clk_core *core = filp->private_data;
	struct clk_core *p = core->hw->core->parent;

	snprintf(name, sizeof(name), "%s\n", p ? p->name : "None\n");

	return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name));
}

static const struct file_operations clock_parent_fops = {
	.open		= simple_open,
	.read		= clock_parent_read,
};

static int clock_debug_enable_set(void *data, u64 val)
{
	struct clk_core *core = data;
	int rc = 0;

	if (val)
		rc = clk_prepare_enable(core->hw->clk);
	else
		clk_disable_unprepare(core->hw->clk);

	return rc;
}

static int clock_debug_enable_get(void *data, u64 *val)
{
	struct clk_core *core = data;
	int enabled = 0;

	enabled = core->enable_count;

	*val = enabled;

	return 0;
}

DEFINE_DEBUGFS_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
			clock_debug_enable_set, "%lld\n");

static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
{
	struct dentry *root;
@@ -3137,14 +3207,15 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
	root = debugfs_create_dir(core->name, pdentry);
	core->dentry = root;

	debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
	debugfs_create_file("clk_rate", 0444, root, core, &clock_rate_fops);
	debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
	debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
	debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
	debugfs_create_u32("clk_phase", 0444, root, &core->phase);
	debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops);
	debugfs_create_u32("clk_prepare_count", 0444, root, &core->prepare_count);
	debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
	debugfs_create_file("clk_enable_count", 0444, root, core,
			    &clock_enable_fops);
	debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
	debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
	debugfs_create_file("clk_duty_cycle", 0444, root, core,
@@ -3196,6 +3267,156 @@ static void clk_debug_unregister(struct clk_core *core)
	mutex_unlock(&clk_debug_lock);
}

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

static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s)
{
	char *start = "\t";
	struct clk *clk;

	if (!c || !c->prepare_count)
		return 0;

	clk = c->hw->clk;

	do {
		c = clk->core;
		if (c->ops->list_rate_vdd_level)
			clock_debug_output(s, "%s%s:%u:%u [%ld, %d]", start,
				c->name,
				c->prepare_count,
				c->enable_count,
				c->rate,
				c->ops->list_rate_vdd_level(c->hw, c->rate));
		else
			clock_debug_output(s, "%s%s:%u:%u [%ld]", start,
				c->name,
				c->prepare_count,
				c->enable_count,
				c->rate);
		start = " -> ";
	} while (s && (clk = clk_get_parent(clk)));

	if (s)
		clock_debug_output(s, "\n");

	return 1;
}

/*
 * clock_debug_print_enabled_clocks() - Print names of enabled clocks
 */
static void clock_debug_print_enabled_clocks(struct seq_file *s)
{
	struct clk_core *core;
	int cnt = 0;

	clock_debug_output(s, "Enabled clocks:\n");

	hlist_for_each_entry(core, &clk_debug_list, debug_node)
		cnt += clock_debug_print_clock(core, s);

	if (cnt)
		clock_debug_output(s, "Enabled clock count: %d\n", cnt);
	else
		clock_debug_output(s, "No clocks enabled.\n");
}

static int enabled_clocks_show(struct seq_file *s, void *unused)
{
	mutex_lock(&clk_debug_lock);
	clock_debug_print_enabled_clocks(s);
	mutex_unlock(&clk_debug_lock);

	return 0;
}

static int enabled_clocks_open(struct inode *inode, struct file *file)
{
	return single_open(file, enabled_clocks_show, inode->i_private);
}

static const struct file_operations clk_enabled_list_fops = {
	.open		= enabled_clocks_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static u32 debug_suspend;

/*
 * Print the names of all enabled clocks and their parents if
 * debug_suspend is set from debugfs.
 */
void clock_debug_print_enabled(void)
{
	if (likely(!debug_suspend))
		return;

	if (!mutex_trylock(&clk_debug_lock))
		return;

	clock_debug_print_enabled_clocks(NULL);
	mutex_unlock(&clk_debug_lock);
}
EXPORT_SYMBOL(clock_debug_print_enabled);

static void clk_state_subtree(struct clk_core *c)
{
	int vdd_level = 0;
	struct clk_core *child;

	if (!c)
		return;

	if (c->ops->list_rate_vdd_level)
		vdd_level = c->ops->list_rate_vdd_level(c->hw, c->rate);

	trace_clk_state(c->name, c->prepare_count, c->enable_count,
						c->rate, vdd_level);

	hlist_for_each_entry(child, &c->children, child_node)
		clk_state_subtree(child);
}

static int clk_state_show(struct seq_file *s, void *data)
{
	struct clk_core *c;
	struct hlist_head **lists = (struct hlist_head **)s->private;

	clk_prepare_lock();

	for (; *lists; lists++)
		hlist_for_each_entry(c, *lists, child_node)
			clk_state_subtree(c);

	clk_prepare_unlock();

	return 0;
}


static int clk_state_open(struct inode *inode, struct file *file)
{
	return single_open(file, clk_state_show, inode->i_private);
}

static const struct file_operations clk_state_fops = {
	.open		= clk_state_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
#endif

/**
 * clk_debug_init - lazily populate the debugfs clk directory
 *
@@ -3220,6 +3441,14 @@ static int __init clk_debug_init(void)
	debugfs_create_file("clk_orphan_dump", 0444, rootdir, &orphan_list,
			    &clk_dump_fops);

#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	debugfs_create_file("clk_enabled_list", 0444, rootdir,
			    &clk_debug_list, &clk_enabled_list_fops);
	debugfs_create_u32("debug_suspend", 0644, rootdir, &debug_suspend);
	debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists,
			    &clk_state_fops);
#endif

	mutex_lock(&clk_debug_lock);
	hlist_for_each_entry(core, &clk_debug_list, debug_node)
		clk_debug_create_one(core, rootdir);
+4 −0
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@ struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id);
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
			      const char *dev_id, const char *con_id);
void __clk_put(struct clk *clk);

/* Debugfs API to print the enabled clocks */
void clock_debug_print_enabled(void);

#else
/* All these casts to avoid ifdefs in clkdev... */
static inline struct clk *
+86 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/delay.h>

#include "clk-alpha-pll.h"
#include "clk-debug.h"
#include "common.h"

#define PLL_MODE(p)		((p)->offset + 0x0)
@@ -1331,6 +1332,53 @@ static void clk_zonda_5lpe_pll_disable(struct clk_hw *hw)
		return;
}

static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
{
	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
	int size, i, val;

	static struct clk_register_data data[] = {
		{"PLL_MODE", 0x0},
		{"PLL_L_VAL", 0x4},
		{"PLL_ALPHA_VAL", 0x8},
		{"PLL_ALPHA_VAL_U", 0xC},
		{"PLL_USER_CTL", 0x10},
		{"PLL_CONFIG_CTL", 0x18},
	};

	static struct clk_register_data data1[] = {
		{"APSS_PLL_VOTE", 0x0},
	};

	size = ARRAY_SIZE(data);

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

	regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val);

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

static struct clk_regmap_ops clk_alpha_pll_regmap_ops = {
	.list_registers = clk_alpha_pll_list_registers,
};

static void clk_alpha_pll_init(struct clk_hw *hw)
{
	struct clk_regmap *rclk = to_clk_regmap(hw);

	if (!rclk->ops)
		rclk->ops = &clk_alpha_pll_regmap_ops;
}

const struct clk_ops clk_alpha_pll_ops = {
	.prepare = clk_prepare_regmap,
	.unprepare = clk_unprepare_regmap,
@@ -1342,6 +1390,11 @@ const struct clk_ops clk_alpha_pll_ops = {
	.recalc_rate = clk_alpha_pll_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = clk_alpha_pll_set_rate,
	.init = clk_alpha_pll_init,
	.debug_init = clk_common_debug_init,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);

@@ -1356,6 +1409,9 @@ const struct clk_ops clk_alpha_pll_huayra_ops = {
	.recalc_rate = alpha_pll_huayra_recalc_rate,
	.round_rate = alpha_pll_huayra_round_rate,
	.set_rate = alpha_pll_huayra_set_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_huayra_ops);

@@ -1370,6 +1426,10 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = {
	.recalc_rate = clk_alpha_pll_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = clk_alpha_pll_hwfsm_set_rate,
	.debug_init = clk_common_debug_init,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);

@@ -1383,6 +1443,9 @@ const struct clk_ops clk_trion_fixed_pll_ops = {
	.is_enabled = clk_trion_pll_is_enabled,
	.recalc_rate = clk_trion_pll_recalc_rate,
	.round_rate = clk_trion_pll_round_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_trion_fixed_pll_ops);

@@ -1397,6 +1460,9 @@ const struct clk_ops clk_alpha_pll_zonda_ops = {
	.recalc_rate = clk_zonda_pll_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = clk_zonda_pll_set_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_zonda_ops);

@@ -1681,6 +1747,9 @@ const struct clk_ops clk_alpha_pll_fabia_ops = {
	.set_rate = alpha_pll_fabia_set_rate,
	.recalc_rate = alpha_pll_fabia_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_fabia_ops);

@@ -1694,6 +1763,9 @@ const struct clk_ops clk_alpha_pll_fixed_fabia_ops = {
	.is_enabled = clk_alpha_pll_is_enabled,
	.recalc_rate = alpha_pll_fabia_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_fixed_fabia_ops);

@@ -2476,6 +2548,9 @@ const struct clk_ops clk_alpha_pll_lucid_ops = {
	.recalc_rate = alpha_pll_lucid_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = alpha_pll_lucid_set_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_lucid_ops);

@@ -2490,6 +2565,10 @@ const struct clk_ops clk_alpha_pll_lucid_5lpe_ops = {
	.recalc_rate = alpha_pll_lucid_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.set_rate = alpha_pll_lucid_5lpe_set_rate,
	.debug_init = clk_common_debug_init,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_lucid_5lpe_ops);

@@ -2503,6 +2582,9 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_ops = {
	.is_enabled = alpha_pll_lucid_is_enabled,
	.recalc_rate = alpha_pll_lucid_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_ops);

@@ -2523,6 +2605,10 @@ const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops = {
	.is_enabled = alpha_pll_lucid_is_enabled,
	.recalc_rate = alpha_pll_lucid_recalc_rate,
	.round_rate = clk_alpha_pll_round_rate,
	.debug_init = clk_common_debug_init,
#ifdef CONFIG_COMMON_CLK_QCOM_DEBUG
	.list_rate_vdd_level = clk_list_rate_vdd_level,
#endif
};
EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_5lpe_ops);

+62 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013, 2016-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/kernel.h>
@@ -14,6 +14,7 @@

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

static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
{
@@ -124,10 +125,17 @@ static void clk_branch_disable(struct clk_hw *hw)
	clk_branch_toggle(hw, false, clk_branch_check_halt);
}

static void clk_branch_debug_init(struct clk_hw *hw, struct dentry *dentry)
{
	clk_common_debug_init(hw, dentry);
	clk_debug_measure_add(hw, dentry);
}

const struct clk_ops clk_branch_ops = {
	.enable = clk_branch_enable,
	.disable = clk_branch_disable,
	.is_enabled = clk_is_enabled_regmap,
	.debug_init = clk_branch_debug_init,
};
EXPORT_SYMBOL_GPL(clk_branch_ops);

@@ -141,17 +149,69 @@ static void clk_branch2_disable(struct clk_hw *hw)
	clk_branch_toggle(hw, false, clk_branch2_check_halt);
}

static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
{
	struct clk_branch *br = to_clk_branch(hw);
	struct clk_regmap *rclk = to_clk_regmap(hw);
	int size, i, val;

	static struct clk_register_data data[] = {
		{"CBCR", 0x0},
	};

	static struct clk_register_data data1[] = {
		{"APSS_VOTE", 0x0},
		{"APSS_SLEEP_VOTE", 0x4},
	};

	size = ARRAY_SIZE(data);

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

	if ((br->halt_check & BRANCH_HALT_VOTED) &&
			!(br->halt_check & BRANCH_VOTED)) {
		if (rclk->enable_reg) {
			size = ARRAY_SIZE(data1);
			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",
						data1[i].name, val);
			}
		}
	}
}

static struct clk_regmap_ops clk_branch2_regmap_ops = {
	.list_registers = clk_branch2_list_registers,
};

static void clk_branch2_init(struct clk_hw *hw)
{
	struct clk_regmap *rclk = to_clk_regmap(hw);

	if (!rclk->ops)
		rclk->ops = &clk_branch2_regmap_ops;
}

const struct clk_ops clk_branch2_ops = {
	.enable = clk_branch2_enable,
	.disable = clk_branch2_disable,
	.is_enabled = clk_is_enabled_regmap,
	.debug_init = clk_debug_measure_add,
	.init = clk_branch2_init,
	.debug_init = clk_branch_debug_init,
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);

const struct clk_ops clk_branch2_aon_ops = {
	.enable = clk_branch2_enable,
	.is_enabled = clk_is_enabled_regmap,
	.init = clk_branch2_init,
	.debug_init = clk_branch_debug_init,
};
EXPORT_SYMBOL_GPL(clk_branch2_aon_ops);

Loading