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

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

Merge "clk: qcom: clk-debug: Add custom measure operators for mccc_clk"

parents 385ac098 8911e102
Loading
Loading
Loading
Loading
+96 −18
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ static DEFINE_MUTEX(clk_debug_lock);
#define XO_DIV4_CNT_DONE	BIT(25)
#define CNT_EN			BIT(20)
#define MEASURE_CNT		GENMASK(24, 0)
#define CBCR_ENA		BIT(0)

/* Sample clock for 'ticks' reference clock ticks. */
static u32 run_measurement(unsigned int ticks, struct regmap *regmap,
@@ -169,15 +170,6 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
				meas->parent[index].post_div_shift;
		regmap_write(meas->regmap[dbg_cc],
				meas->parent[index].post_div_offset, regval);

		/* Not all recursive muxes have a DEBUG clock. */
		if (meas->parent[index].cbcr_offset != U32_MAX) {
			regmap_read(meas->regmap[dbg_cc],
				meas->parent[index].cbcr_offset, &regval);
			regval |= BIT(0);
			regmap_write(meas->regmap[dbg_cc],
				meas->parent[index].cbcr_offset, regval);
		}
	}

	/* Update the debug sel for GCC */
@@ -194,11 +186,6 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
			meas->post_div_mask) << meas->post_div_shift;
	regmap_write(meas->regmap[GCC], meas->post_div_offset, regval);

	/* Turn on the GCC_DEBUG_CBCR */
	regmap_read(meas->regmap[GCC], meas->cbcr_offset, &regval);
	regval |= BIT(0);
	regmap_write(meas->regmap[GCC], meas->cbcr_offset, regval);

	return 0;
}

@@ -208,6 +195,44 @@ 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)
{
	int dbg_cc = meas->parent[index].dbg_cc;

	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,
					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_debug_mux *meas, u8 index)
{
	int dbg_cc = meas->parent[index].dbg_cc;

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

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

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

static int clk_debug_measure_get(void *data, u64 *val)
{
	struct clk_hw *hw = data, *par;
@@ -222,6 +247,8 @@ static int clk_debug_measure_get(void *data, u64 *val)
	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);
@@ -235,33 +262,79 @@ static int clk_debug_measure_get(void *data, u64 *val)
		/* Accommodate for any pre-set dividers */
		if (meas->parent[index].misc_div_val)
			*val *= meas->parent[index].misc_div_val;
	} else {
		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)
		return -EINVAL;
	if (!par) {
		ret = -EINVAL;
		goto exit1;
	}

	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);
exit:
	mutex_unlock(&clk_debug_lock);

	return ret;
}

DEFINE_DEBUGFS_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
							NULL, "%lld\n");

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;
	int ret = 0;
	u32 regval;

	mutex_lock(&clk_debug_lock);

	ret = clk_set_parent(measure->clk, hw->clk);
	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);
		if (!regval) {
			pr_err("Error reading mccc period register, ret = %d\n",
			       ret);
			mutex_unlock(&clk_debug_lock);
			return 0;
		}
		*val = 1000000000000UL;
		do_div(*val, regval);
	} else {
		pr_err("Failed to set the debug mux's parent.\n");
	}

	mutex_unlock(&clk_debug_lock);
	return ret;
}

DEFINE_SIMPLE_ATTRIBUTE(clk_read_period_fops, clk_debug_read_period,
							NULL, "%lld\n");

void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
{
	int ret;
	int index;
	struct clk_debug_mux *meas;

	if (IS_ERR_OR_NULL(measure)) {
		pr_err_once("Please check if `measure` clk is registered.\n");
		return;
	}

	meas = to_clk_measure(measure);
	ret = clk_set_parent(measure->clk, hw->clk);
	if (ret) {
		pr_debug("Unable to set %s as %s's parent, ret=%d\n",
@@ -269,6 +342,11 @@ void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
		return;
	}

	index = clk_debug_mux_get_parent(measure);
	if (meas->parent[index].dbg_cc == MC_CC)
		debugfs_create_file("clk_measure", 0444, dentry, hw,
					&clk_read_period_fops);
	else
		debugfs_create_file("clk_measure", 0444, dentry, hw,
					&clk_measure_fops);
}
+8 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2016, 2019, The Linux Foundation. All rights reserved. */

#ifndef __QCOM_CLK_DEBUG_H__
#define __QCOM_CLK_DEBUG_H__
@@ -35,6 +35,7 @@ enum debug_cc {
	GPU_CC,
	VIDEO_CC,
	CPU_CC,
	MC_CC,
	MAX_NUM_CC,
};

@@ -88,6 +89,8 @@ struct clk_src {
 * @num_parents:	number of parents
 * @regmap:		regmaps of debug mux
 * @priv:		private measure_clk_data to be used by debug mux
 * @en_mask:		indicates the enable bit mask at global clock
 *			controller debug mux.
 * @debug_offset:	debug mux offset.
 * @post_div_offset:	register with post-divider settings for the debug mux.
 * @cbcr_offset:	branch register to turn on debug mux.
@@ -99,6 +102,8 @@ struct clk_src {
			mux.
 * @post_div_shift:	indicates the shift required for post divider
			selection in primary mux.
 * @period_offset:	offset of the period register used to read to determine
			the mc clock period
 * @hw:			handle between common and hardware-specific interfaces.
 */
struct clk_debug_mux {
@@ -106,6 +111,7 @@ struct clk_debug_mux {
	int num_parents;
	struct regmap **regmap;
	void *priv;
	u32 en_mask;
	u32 debug_offset;
	u32 post_div_offset;
	u32 cbcr_offset;
@@ -113,6 +119,7 @@ struct clk_debug_mux {
	u32 src_sel_shift;
	u32 post_div_mask;
	u32 post_div_shift;
	u32 period_offset;
	struct clk_hw hw;
};