From e827cb26858869ed7d77ad781f3b1466ee817bda Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Fri, 5 Jan 2018 15:30:24 -0800 Subject: [PATCH 1/2] clk: qcom: clk-debug: Disable the DEBUG clocks when not being used The multimedia debug clocks if left enabled will block the MMCX rail from going into power collapse. Toggle them on a need-by basis. Change-Id: Ia7e946d30f52b2128f40fa9b965bd7eb97e28f73 Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/clk-debug.c | 64 ++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index dd50887d80d8..c67bb2bf2c69 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -26,6 +26,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, @@ -170,15 +171,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, ®val); - regval |= BIT(0); - regmap_write(meas->regmap[dbg_cc], - meas->parent[index].cbcr_offset, regval); - } } /* Update the debug sel for GCC */ @@ -195,11 +187,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, ®val); - regval |= BIT(0); - regmap_write(meas->regmap[GCC], meas->cbcr_offset, regval); - return 0; } @@ -209,6 +196,40 @@ 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; + + 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, + CBCR_ENA, CBCR_ENA); + } + + /* Turn on the GCC_DEBUG_CBCR */ + regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset, + CBCR_ENA, CBCR_ENA); + +} + +static void disable_debug_clks(struct clk_debug_mux *meas, u8 index) +{ + int dbg_cc = meas->parent[index].dbg_cc; + + /* Turn off the GCC_DEBUG_CBCR */ + regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset, + CBCR_ENA, 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, + CBCR_ENA, 0); + } +} + static int clk_debug_measure_get(void *data, u64 *val) { struct clk_hw *hw = data, *par; @@ -223,6 +244,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); @@ -236,18 +259,25 @@ 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; } From e08df66270dc7bece1daeed30bd589b96015f08a Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Mon, 16 Apr 2018 14:06:57 +0530 Subject: [PATCH 2/2] clk: qcom: clk-debug: Add support for enable mask for debug clk The enable bit position could vary across targets. Add the en_mask where the enable bit position could be supplied for debug clock branch. Change-Id: I9e910f53e4a13f701a3a37b640c4f72da164f6af Signed-off-by: Shefali Jain --- drivers/clk/qcom/clk-debug.c | 12 ++++++++---- drivers/clk/qcom/clk-debug.h | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index c67bb2bf2c69..2bcad2d0173a 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -200,17 +200,19 @@ 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, - CBCR_ENA, CBCR_ENA); + meas->en_mask, meas->en_mask); } /* Turn on the GCC_DEBUG_CBCR */ regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset, - CBCR_ENA, CBCR_ENA); + meas->en_mask, meas->en_mask); } @@ -218,15 +220,17 @@ 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, - CBCR_ENA, 0); + 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, - CBCR_ENA, 0); + meas->en_mask, 0); } } diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h index eb40b32b66bf..6e23487751f3 100644 --- a/drivers/clk/qcom/clk-debug.h +++ b/drivers/clk/qcom/clk-debug.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* 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__ @@ -88,6 +88,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. @@ -106,6 +108,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;