clk: qcom: clk-debug: Add support to dump GDSC registers

Add support to dump client's GDSC registers when client
passes a regulator(GDSC) handle to clock dump functions.
While at it, increase the GDSC regmap size to include all
GDSC registers.

And for legacy HW, that only supports single GDSCR per GDSC,
'qcom,no-config-gdscr' flag can be specified in GDSC DT node
to decrease the regmap size and map only single GDSCR.

Change-Id: Ia03c647deae9ffe9df93be60abd901bef25c3503
Signed-off-by: Jagadeesh Kona <jkona@codeaurora.org>
This commit is contained in:
Jagadeesh Kona 2021-02-23 08:22:04 +05:30
commit db9bcd7bd9
4 changed files with 67 additions and 12 deletions

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2016, 2019-2020, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2016, 2019-2021, The Linux Foundation. All rights reserved. */
#include <linux/clk.h>
#include <linux/export.h>
@ -15,6 +15,7 @@
#include "clk-regmap.h"
#include "clk-debug.h"
#include "gdsc-debug.h"
static struct clk_hw *measure;
@ -565,16 +566,22 @@ void clk_common_debug_init(struct clk_hw *hw, struct dentry *dentry)
/**
* qcom_clk_dump - dump the HW specific registers associated with this clock
* and regulator
* @clk: clock source
* @regulator: regulator
* @calltrace: indicates whether calltrace is required
*
* This function attempts to print all the registers associated with the
* clock and it's parents.
* clock, it's parents and regulator.
*/
void qcom_clk_dump(struct clk *clk, bool calltrace)
void qcom_clk_dump(struct clk *clk, struct regulator *regulator,
bool calltrace)
{
struct clk_hw *hw;
if (!IS_ERR_OR_NULL(regulator))
gdsc_debug_print_regs(regulator);
if (IS_ERR_OR_NULL(clk))
return;
@ -589,22 +596,27 @@ EXPORT_SYMBOL(qcom_clk_dump);
/**
* qcom_clk_bulk_dump - dump the HW specific registers associated with clocks
* @clks: the clk_bulk_data table of consumer
* and regulator
* @num_clks: the number of clk_bulk_data
* @clks: the clk_bulk_data table of consumer
* @regulator: regulator source
* @calltrace: indicates whether calltrace is required
*
* This function attempts to print all the registers associated with the
* clock and it's parents for all the clocks in the list.
* clocks in the list and regulator.
*/
void qcom_clk_bulk_dump(int num_clks, struct clk_bulk_data *clks,
bool calltrace)
struct regulator *regulator, bool calltrace)
{
int i;
if (!IS_ERR_OR_NULL(regulator))
gdsc_debug_print_regs(regulator);
if (IS_ERR_OR_NULL(clks))
return;
for (i = 0; i < num_clks; i++)
qcom_clk_dump(clks[i].clk, calltrace);
qcom_clk_dump(clks[i].clk, NULL, calltrace);
}
EXPORT_SYMBOL(qcom_clk_bulk_dump);

View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef __QCOM_GDSC_DEBUG_H__
#define __QCOM_GDSC_DEBUG_H__
void gdsc_debug_print_regs(struct regulator *regulator);
#endif /* __QCOM_GDSC_DEBUG_H__ */

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@ -21,6 +21,7 @@
#include <linux/mfd/syscon.h>
#include "../../regulator/internal.h"
#include "gdsc-debug.h"
/* GDSCR */
#define PWR_ON_MASK BIT(31)
@ -566,13 +567,38 @@ static struct regulator_ops gdsc_ops = {
.get_mode = gdsc_get_mode,
};
static const struct regmap_config gdsc_regmap_config = {
static struct regmap_config gdsc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x8,
.fast_io = true,
};
void gdsc_debug_print_regs(struct regulator *regulator)
{
struct gdsc *sc = rdev_get_drvdata(regulator->rdev);
uint32_t regvals[3] = {0};
int ret;
if (!sc) {
pr_err("Failed to get GDSC Handle\n");
return;
}
ret = regmap_bulk_read(sc->regmap, REG_OFFSET, regvals,
gdsc_regmap_config.max_register ? 3 : 1);
if (ret) {
pr_err("Failed to read %s registers\n", sc->rdesc.name);
return;
}
pr_info("Dumping %s Registers:\n", sc->rdesc.name);
pr_info("GDSCR: 0x%.8x CFG: 0x%.8x CFG2: 0x%.8x\n",
regvals[0], regvals[1], regvals[2]);
}
EXPORT_SYMBOL(gdsc_debug_print_regs);
static int gdsc_parse_dt_data(struct gdsc *sc, struct device *dev,
struct regulator_init_data **init_data)
{
@ -712,6 +738,10 @@ static int gdsc_get_resources(struct gdsc *sc, struct platform_device *pdev)
if (sc->gdscr == NULL)
return -ENOMEM;
if (of_property_read_bool(dev->of_node, "qcom,no-config-gdscr"))
gdsc_regmap_config.max_register = 0;
sc->regmap = devm_regmap_init_mmio(dev, sc->gdscr, &gdsc_regmap_config);
if (!sc->regmap) {
dev_err(dev, "Couldn't get regmap\n");

View file

@ -1,12 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
#ifndef __LINUX_CLK_QCOM_H_
#define __LINUX_CLK_QCOM_H_
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
enum branch_mem_flags {
CLKFLAG_RETAIN_PERIPH,
@ -19,8 +20,9 @@ enum branch_mem_flags {
int qcom_clk_get_voltage(struct clk *clk, unsigned long rate);
int qcom_clk_set_flags(struct clk *clk, unsigned long flags);
void qcom_clk_dump(struct clk *clk, bool calltrace);
void qcom_clk_bulk_dump(int num_clks, struct clk_bulk_data *clks,
void qcom_clk_dump(struct clk *clk, struct regulator *regulator,
bool calltrace);
void qcom_clk_bulk_dump(int num_clks, struct clk_bulk_data *clks,
struct regulator *regulator, bool calltrace);
#endif /* __LINUX_CLK_QCOM_H_ */