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

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

Merge "clk: qcom: clk-debug: Unflatten mux tree"

parents 314fb0fe 43eef15a
Loading
Loading
Loading
Loading
+138 −122
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/mfd/syscon.h>
#include <linux/msm-bus.h>

#include "clk-regmap.h"
@@ -82,9 +83,9 @@ static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
	spin_lock_irqsave(&clk_reg_lock, flags);

	/* Enable CXO/4 and RINGOSC branch. */
	regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
	regmap_read(meas->regmap, data->xo_div4_cbcr, &gcc_xo4_reg);
	gcc_xo4_reg |= BIT(0);
	regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
	regmap_write(meas->regmap, data->xo_div4_cbcr, gcc_xo4_reg);

	/*
	 * The ring oscillator counter will not reset if the measured clock
@@ -94,15 +95,15 @@ static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
	 */

	/* Run a short measurement. (~1 ms) */
	raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap[GCC],
	raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap,
				data->ctl_reg, data->status_reg);

	/* Run a full measurement. (~14 ms) */
	raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap[GCC],
	raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap,
				data->ctl_reg, data->status_reg);

	gcc_xo4_reg &= ~BIT(0);
	regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
	regmap_write(meas->regmap, data->xo_div4_cbcr, gcc_xo4_reg);

	/* Return 0 if the clock is off. */
	if (raw_count_full == raw_count_short)
@@ -121,73 +122,63 @@ static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
	return ret;
}

static int clk_find_and_set_parent(struct clk_hw *mux, struct clk_hw *clk)
{
	int i;

	if (!clk || !mux || !(mux->init->flags & CLK_IS_MEASURE))
		return -EINVAL;

	if (!clk_set_parent(mux->clk, clk->clk))
		return 0;

	for (i = 0; i < clk_hw_get_num_parents(mux); i++) {
		struct clk_hw *parent = clk_hw_get_parent_by_index(mux, i);

		if (!clk_find_and_set_parent(parent, clk))
			return clk_set_parent(mux->clk, parent->clk);
	}

	return -EINVAL;
}

static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
{
	struct clk_debug_mux *meas = to_clk_measure(hw);
	int i, num_parents = clk_hw_get_num_parents(hw);
	struct clk_hw *hw_clk = clk_hw_get_parent(hw);

	if (!hw_clk)
		return 0;

	for (i = 0; i < num_parents; i++) {
		if (!strcmp(meas->parent[i].parents,
		if (!strcmp(hw->init->parent_names[i],
					clk_hw_get_name(hw_clk))) {
			pr_debug("%s: clock parent - %s, index %d\n", __func__,
					meas->parent[i].parents, i);
					hw->init->parent_names[i], i);
			return i;
		}
	}

	return 0;
}

static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
{
	struct clk_debug_mux *meas = to_clk_measure(hw);
	u32 regval = 0;
	int dbg_cc = 0;

	dbg_cc = meas->parent[index].dbg_cc;

	if (dbg_cc != GCC) {
		/* Update the recursive debug mux */
		regmap_read(meas->regmap[dbg_cc],
				meas->parent[index].mux_offset, &regval);
		regval &= ~(meas->parent[index].mux_sel_mask <<
				meas->parent[index].mux_sel_shift);
		regval |= (meas->parent[index].dbg_cc_mux_sel &
				meas->parent[index].mux_sel_mask) <<
				meas->parent[index].mux_sel_shift;
		regmap_write(meas->regmap[dbg_cc],
				meas->parent[index].mux_offset, regval);

		regmap_read(meas->regmap[dbg_cc],
				meas->parent[index].post_div_offset, &regval);
		regval &= ~(meas->parent[index].post_div_mask <<
				meas->parent[index].post_div_shift);
		regval |= ((meas->parent[index].post_div_val - 1) &
				meas->parent[index].post_div_mask) <<
				meas->parent[index].post_div_shift;
		regmap_write(meas->regmap[dbg_cc],
				meas->parent[index].post_div_offset, regval);
	}
	struct clk_debug_mux *mux = to_clk_measure(hw);
	int ret;

	/* Update the debug sel for GCC */
	regmap_read(meas->regmap[GCC], meas->debug_offset, &regval);
	regval &= ~(meas->src_sel_mask << meas->src_sel_shift);
	regval |= (meas->parent[index].prim_mux_sel & meas->src_sel_mask) <<
			meas->src_sel_shift;
	regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
	if (!mux->mux_sels)
		return 0;

	/* Set the GCC mux's post divider bits */
	regmap_read(meas->regmap[GCC], meas->post_div_offset, &regval);
	regval &= ~(meas->post_div_mask << meas->post_div_shift);
	regval |= ((meas->parent[index].prim_mux_div_val - 1) &
			meas->post_div_mask) << meas->post_div_shift;
	regmap_write(meas->regmap[GCC], meas->post_div_offset, regval);
	/* Update the debug sel for mux */
	ret = regmap_update_bits(mux->regmap, mux->debug_offset,
		mux->src_sel_mask,
		mux->mux_sels[index] << mux->src_sel_shift);
	if (ret)
		return ret;

	return 0;
	/* Set the mux's post divider bits */
	return regmap_update_bits(mux->regmap, mux->post_div_offset,
		mux->post_div_mask,
		(mux->post_div_val - 1) << mux->post_div_shift);
}

const struct clk_ops clk_debug_mux_ops = {
@@ -196,51 +187,69 @@ const struct clk_ops clk_debug_mux_ops = {
};
EXPORT_SYMBOL(clk_debug_mux_ops);

static void enable_debug_clks(struct clk_debug_mux *meas, u8 index)
static void enable_debug_clks(struct clk_hw *mux)
{
	int dbg_cc = meas->parent[index].dbg_cc;
	struct clk_debug_mux *meas = to_clk_measure(mux);
	struct clk_hw *parent;

	if (!mux || !(mux->init->flags & CLK_IS_MEASURE))
		return;

	parent = clk_hw_get_parent(mux);
	enable_debug_clks(parent);

	meas->en_mask = meas->en_mask ? meas->en_mask : CBCR_ENA;

	if (dbg_cc != GCC) {
		/* Not all recursive muxes have a DEBUG clock. */
		if (meas->parent[index].cbcr_offset != U32_MAX)
			regmap_update_bits(meas->regmap[dbg_cc],
					meas->parent[index].cbcr_offset,
	/* Not all muxes have a DEBUG clock. */
	if (meas->cbcr_offset != U32_MAX)
		regmap_update_bits(meas->regmap, meas->cbcr_offset,
				   meas->en_mask, meas->en_mask);
}

	/* Turn on the GCC_DEBUG_CBCR */
	regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset,
					meas->en_mask, meas->en_mask);
static void disable_debug_clks(struct clk_hw *mux)
{
	struct clk_debug_mux *meas = to_clk_measure(mux);
	struct clk_hw *parent;

	if (!mux || !(mux->init->flags & CLK_IS_MEASURE))
		return;

	meas->en_mask = meas->en_mask ? meas->en_mask : CBCR_ENA;

	if (meas->cbcr_offset != U32_MAX)
		regmap_update_bits(meas->regmap, meas->cbcr_offset,
					meas->en_mask, 0);

	parent = clk_hw_get_parent(mux);
	disable_debug_clks(parent);
}

static void disable_debug_clks(struct clk_debug_mux *meas, u8 index)
static u32 get_mux_divs(struct clk_hw *mux)
{
	int dbg_cc = meas->parent[index].dbg_cc;
	struct clk_debug_mux *meas = to_clk_measure(mux);
	struct clk_hw *parent;
	u32 div_val;

	meas->en_mask = meas->en_mask ? meas->en_mask : CBCR_ENA;
	if (!mux || !(mux->init->flags & CLK_IS_MEASURE))
		return 1;

	/* Turn off the GCC_DEBUG_CBCR */
	regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset,
					meas->en_mask, 0);
	WARN_ON(!meas->post_div_val);
	div_val = meas->post_div_val;

	if (dbg_cc != GCC) {
		if (meas->parent[index].cbcr_offset != U32_MAX)
			regmap_update_bits(meas->regmap[dbg_cc],
					meas->parent[index].cbcr_offset,
					meas->en_mask, 0);
	if (meas->pre_div_vals) {
		int i = clk_debug_mux_get_parent(mux);

		div_val *= meas->pre_div_vals[i];
	}
	parent = clk_hw_get_parent(mux);
	return div_val * get_mux_divs(parent);
}

static int clk_debug_measure_get(void *data, u64 *val)
{
	struct clk_hw *hw = data, *par;
	struct clk_hw *hw = data;
	struct clk_debug_mux *meas = to_clk_measure(measure);
	int index;
	int ret = 0;
	unsigned long meas_rate, sw_rate;

	mutex_lock(&clk_debug_lock);

@@ -251,42 +260,18 @@ static int clk_debug_measure_get(void *data, u64 *val)
	if (meas->bus_cl_id)
		msm_bus_scale_client_update_request(meas->bus_cl_id, 1);

	ret = clk_set_parent(measure->clk, hw->clk);
	if (!ret) {
		par = measure;
		index =  clk_debug_mux_get_parent(measure);

		enable_debug_clks(meas, index);
		while (par && par != hw) {
			if (par->init->ops->enable)
				par->init->ops->enable(par);
			par = clk_hw_get_parent(par);
		}
		*val = clk_debug_mux_measure_rate(measure);
		if (meas->parent[index].dbg_cc != GCC)
			*val *= meas->parent[index].post_div_val;
		*val *= meas->parent[index].prim_mux_div_val;

		/* Accommodate for any pre-set dividers */
		if (meas->parent[index].misc_div_val)
			*val *= meas->parent[index].misc_div_val;
	} else {
	ret = clk_find_and_set_parent(measure, hw);
	if (ret) {
		pr_err("Failed to set the debug mux's parent.\n");
		goto exit;
	}

	meas_rate = clk_get_rate(hw->clk);
	par = clk_hw_get_parent(measure);
	if (!par) {
		ret = -EINVAL;
		goto exit1;
	}
	enable_debug_clks(measure);
	*val = clk_debug_mux_measure_rate(measure);

	sw_rate = clk_get_rate(par->clk);
	if (sw_rate && meas_rate >= (sw_rate * 2))
		*val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
exit1:
	disable_debug_clks(meas, index);
	/* recursively calculate actual freq */
	*val *= get_mux_divs(measure);
	disable_debug_clks(measure);
exit:
	if (meas->bus_cl_id)
		msm_bus_scale_client_update_request(meas->bus_cl_id, 0);
@@ -300,20 +285,18 @@ DEFINE_DEBUGFS_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
static int clk_debug_read_period(void *data, u64 *val)
{
	struct clk_hw *hw = data;
	struct clk_debug_mux *meas = to_clk_measure(measure);
	int index;
	int dbg_cc;
	struct clk_hw *parent;
	struct clk_debug_mux *mux;
	int ret = 0;
	u32 regval;

	mutex_lock(&clk_debug_lock);

	ret = clk_set_parent(measure->clk, hw->clk);
	ret = clk_find_and_set_parent(measure, hw);
	if (!ret) {
		index = clk_debug_mux_get_parent(measure);
		dbg_cc = meas->parent[index].dbg_cc;

		regmap_read(meas->regmap[dbg_cc], meas->period_offset, &regval);
		parent = clk_hw_get_parent(measure);
		mux = to_clk_measure(parent);
		regmap_read(mux->regmap, mux->period_offset, &regval);
		if (!regval) {
			pr_err("Error reading mccc period register, ret = %d\n",
			       ret);
@@ -336,8 +319,9 @@ DEFINE_SIMPLE_ATTRIBUTE(clk_read_period_fops, clk_debug_read_period,
void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
{
	int ret;
	int index;
	struct clk_hw *parent;
	struct clk_debug_mux *meas;
	struct clk_debug_mux *meas_parent;

	if (IS_ERR_OR_NULL(measure)) {
		pr_err_once("Please check if `measure` clk is registered.\n");
@@ -347,17 +331,20 @@ void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
	meas = to_clk_measure(measure);
	if (meas->bus_cl_id)
		msm_bus_scale_client_update_request(meas->bus_cl_id, 1);
	ret = clk_set_parent(measure->clk, hw->clk);
	ret = clk_find_and_set_parent(measure, hw);
	if (ret) {
		pr_debug("Unable to set %s as %s's parent, ret=%d\n",
			clk_hw_get_name(hw), clk_hw_get_name(measure), ret);
		goto err;
	}

	index = clk_debug_mux_get_parent(measure);
	if (meas->parent[index].dbg_cc == MC_CC)
	parent = clk_hw_get_parent(measure);
	meas_parent = to_clk_measure(parent);

	if (parent->init->flags & CLK_IS_MEASURE && !meas_parent->mux_sels) {
		debugfs_create_file("clk_measure", 0444, dentry, hw,
				&clk_read_period_fops);
	}
	else
		debugfs_create_file("clk_measure", 0444, dentry, hw,
				&clk_measure_fops);
@@ -387,3 +374,32 @@ void clk_debug_bus_vote(struct clk_hw *hw, bool enable)
		msm_bus_scale_client_update_request(hw->init->bus_cl_id,
								enable);
}

/**
 * map_debug_bases - maps each debug mux based on phandle
 * @pdev: the platform device used to find phandles
 * @base: regmap base name used to look up phandle
 * @mux: debug mux that requires a regmap
 *
 * This function attempts to look up and map a regmap for a debug mux
 * using syscon_regmap_lookup_by_phandle if the base name property exists
 * and assigns an appropriate regmap.
 *
 * Returns 0 on success, -EBADR when it can't find base name, -EERROR otherwise.
 */
int map_debug_bases(struct platform_device *pdev, const char *base,
		    struct clk_debug_mux *mux)
{
	if (!of_get_property(pdev->dev.of_node, base, NULL))
		return -EBADR;

	mux->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
						     base);
	if (IS_ERR(mux->regmap)) {
		pr_err("Failed to map %s (ret=%ld)\n", base,
				PTR_ERR(mux->regmap));
		return PTR_ERR(mux->regmap);
	}
	return 0;
}
EXPORT_SYMBOL(map_debug_bases);
+22 −62
Original line number Diff line number Diff line
@@ -4,8 +4,20 @@
#ifndef __QCOM_CLK_DEBUG_H__
#define __QCOM_CLK_DEBUG_H__

#include <linux/platform_device.h>
#include "../clk.h"

/**
 * struct mux_regmap_names - Structure of mux regmap mapping
 * @mux:		pointer to a clock debug mux
 * @regmap_name:	corresponding regmap name used to match a debug mux to
			its regmap
 */
struct mux_regmap_names {
	struct clk_debug_mux *mux;
	const char *regmap_name;
};

/* Debugfs Measure Clocks */

/**
@@ -24,68 +36,12 @@ struct measure_clk_data {
	u32 xo_div4_cbcr;
};

/**
 * List of Debug clock controllers.
 */
enum debug_cc {
	GCC,
	CAM_CC,
	DISP_CC,
	NPU_CC,
	GPU_CC,
	VIDEO_CC,
	CPU_CC,
	MC_CC,
	MAX_NUM_CC,
};

/**
 * struct clk_src - Structure of clock source for debug mux
 *
 * @parents:		clock name to be used as parent for debug mux.
 * @prim_mux_sel:	debug mux index at global clock controller.
 * @prim_mux_div_val:	PLL post-divider setting for the primary mux.
 * @dbg_cc:		indicates the clock controller for recursive debug
 *			clock controllers.
 * @dbg_cc_mux_sel:	indicates the debug mux index at recursive debug mux.
 * @mux_sel_mask:	indicates the mask for the mux selection.
 * @mux_sel_shift:	indicates the shift required for mux selection.
 * @post_div_mask:	indicates the post div mask to be used at recursive
 *			debug mux.
 * @post_div_shift:	indicates the shift required for post divider
 *			configuration.
 * @post_div_val:	indicates the post div value to be used at recursive
 *			debug mux.
 * @mux_offset:		the debug mux offset.
 * @post_div_offset:	register with post-divider settings for the debug mux.
 * @cbcr_offset:	branch register to turn on debug mux.
 * @misc_div_val:	includes any pre-set dividers in the measurement logic.
 */
struct clk_src {
	const char *parents;
	int prim_mux_sel;
	u32 prim_mux_div_val;
	enum debug_cc dbg_cc;
	int dbg_cc_mux_sel;
	u32 mux_sel_mask;
	u32 mux_sel_shift;
	u32 post_div_mask;
	u32 post_div_shift;
	u32 post_div_val;
	u32 mux_offset;
	u32 post_div_offset;
	u32 cbcr_offset;
	u32 misc_div_val;
};

#define MUX_SRC_LIST(...) \
	.parent = (struct clk_src[]){__VA_ARGS__}, \
	.num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))

/**
 * struct clk_debug_mux - Structure of clock debug mux
 *
 * @parent:		structure of clk_src
 * @mux_sels:		indicates the debug mux index at recursive debug mux.
 * @pre_div_val:	optional divider values for clocks that were pre-divided
			before feeding into the debug muxes
 * @num_parents:	number of parents
 * @regmap:		regmaps of debug mux
 * @priv:		private measure_clk_data to be used by debug mux
@@ -107,18 +63,20 @@ struct clk_src {
 * @hw:			handle between common and hardware-specific interfaces.
 */
struct clk_debug_mux {
	struct clk_src *parent;
	int *mux_sels;
	int *pre_div_vals;
	int num_parents;
	struct regmap **regmap;
	struct regmap *regmap;
	void *priv;
	u32 en_mask;
	u32 debug_offset;
	u32 post_div_offset;
	u32 cbcr_offset;
	u32 src_sel_mask;
	u32 src_sel_shift;
	u32 post_div_offset;
	u32 post_div_mask;
	u32 post_div_shift;
	u32 post_div_val;
	u32 period_offset;
	u32 bus_cl_id;
	struct clk_hw hw;
@@ -131,5 +89,7 @@ extern const struct clk_ops clk_debug_mux_ops;
int clk_debug_measure_register(struct clk_hw *hw);
void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
void clk_debug_bus_vote(struct clk_hw *hw, bool enable);
int map_debug_bases(struct platform_device *pdev, const char *base,
		    struct clk_debug_mux *mux);

#endif
+715 −575

File changed.

Preview size limit exceeded, changes collapsed.

+590 −540

File changed.

Preview size limit exceeded, changes collapsed.

+0 −35
Original line number Diff line number Diff line
@@ -3874,39 +3874,6 @@ static struct clk_branch gcc_video_xo_clk = {
	},
};

/* Measure-only clock for gcc_cfg_noc_ahb_clk. */
static struct clk_dummy measure_only_cnoc_clk = {
	.rrate = 1000,
	.hw.init = &(struct clk_init_data){
		.name = "measure_only_cnoc_clk",
		.ops = &clk_dummy_ops,
	},
};

/* Measure-only clock for gcc_ipa_2x_clk. */
static struct clk_dummy measure_only_ipa_2x_clk = {
	.rrate = 1000,
	.hw.init = &(struct clk_init_data){
		.name = "measure_only_ipa_2x_clk",
		.ops = &clk_dummy_ops,
	},
};

/* Measure-only clock for gcc_sys_noc_axi_clk. */
static struct clk_dummy measure_only_snoc_clk = {
	.rrate = 1000,
	.hw.init = &(struct clk_init_data){
		.name = "measure_only_snoc_clk",
		.ops = &clk_dummy_ops,
	},
};

struct clk_hw *gcc_kona_hws[] = {
	[MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw,
	[MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw,
	[MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw,
};

static struct clk_regmap *gcc_kona_clocks[] = {
	[GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr,
	[GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr,
@@ -4215,8 +4182,6 @@ static const struct qcom_cc_desc gcc_kona_desc = {
	.num_clks = ARRAY_SIZE(gcc_kona_clocks),
	.resets = gcc_kona_resets,
	.num_resets = ARRAY_SIZE(gcc_kona_resets),
	.hwclks = gcc_kona_hws,
	.num_hwclks = ARRAY_SIZE(gcc_kona_hws),
};

static const struct of_device_id gcc_kona_match_table[] = {
Loading