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

Commit db9bcd7b authored by Jagadeesh Kona's avatar Jagadeesh Kona
Browse files

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: default avatarJagadeesh Kona <jkona@codeaurora.org>
parent 98ed1806
Loading
Loading
Loading
Loading
+19 −7
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// 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/clk.h>
#include <linux/export.h>
#include <linux/export.h>
@@ -15,6 +15,7 @@


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


static struct clk_hw *measure;
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
 * qcom_clk_dump - dump the HW specific registers associated with this clock
 * and regulator
 * @clk: clock source
 * @clk: clock source
 * @regulator: regulator
 * @calltrace: indicates whether calltrace is required
 * @calltrace: indicates whether calltrace is required
 *
 *
 * This function attempts to print all the registers associated with the
 * 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;
	struct clk_hw *hw;


	if (!IS_ERR_OR_NULL(regulator))
		gdsc_debug_print_regs(regulator);

	if (IS_ERR_OR_NULL(clk))
	if (IS_ERR_OR_NULL(clk))
		return;
		return;


@@ -589,22 +596,27 @@ EXPORT_SYMBOL(qcom_clk_dump);


/**
/**
 * qcom_clk_bulk_dump - dump the HW specific registers associated with clocks
 * 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
 * @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
 * @calltrace: indicates whether calltrace is required
 *
 *
 * This function attempts to print all the registers associated with the
 * 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,
void qcom_clk_bulk_dump(int num_clks, struct clk_bulk_data *clks,
			bool calltrace)
			struct regulator *regulator, bool calltrace)
{
{
	int i;
	int i;


	if (!IS_ERR_OR_NULL(regulator))
		gdsc_debug_print_regs(regulator);

	if (IS_ERR_OR_NULL(clks))
	if (IS_ERR_OR_NULL(clks))
		return;
		return;


	for (i = 0; i < num_clks; i++)
	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);
EXPORT_SYMBOL(qcom_clk_bulk_dump);
+11 −0
Original line number Original line Diff line number Diff line
/* 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__ */
+32 −2
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// 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>
#include <linux/kernel.h>
@@ -21,6 +21,7 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon.h>


#include "../../regulator/internal.h"
#include "../../regulator/internal.h"
#include "gdsc-debug.h"


/* GDSCR */
/* GDSCR */
#define PWR_ON_MASK		BIT(31)
#define PWR_ON_MASK		BIT(31)
@@ -566,13 +567,38 @@ static struct regulator_ops gdsc_ops = {
	.get_mode = gdsc_get_mode,
	.get_mode = gdsc_get_mode,
};
};


static const struct regmap_config gdsc_regmap_config = {
static struct regmap_config gdsc_regmap_config = {
	.reg_bits   = 32,
	.reg_bits   = 32,
	.reg_stride = 4,
	.reg_stride = 4,
	.val_bits   = 32,
	.val_bits   = 32,
	.max_register = 0x8,
	.fast_io    = true,
	.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,
static int gdsc_parse_dt_data(struct gdsc *sc, struct device *dev,
				struct regulator_init_data **init_data)
				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)
	if (sc->gdscr == NULL)
		return -ENOMEM;
		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);
	sc->regmap = devm_regmap_init_mmio(dev, sc->gdscr, &gdsc_regmap_config);
	if (!sc->regmap) {
	if (!sc->regmap) {
		dev_err(dev, "Couldn't get regmap\n");
		dev_err(dev, "Couldn't get regmap\n");
+5 −3
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* 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_
#ifndef __LINUX_CLK_QCOM_H_
#define __LINUX_CLK_QCOM_H_
#define __LINUX_CLK_QCOM_H_


#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>


enum branch_mem_flags {
enum branch_mem_flags {
	CLKFLAG_RETAIN_PERIPH,
	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_get_voltage(struct clk *clk, unsigned long rate);
int qcom_clk_set_flags(struct clk *clk, unsigned long flags);
int qcom_clk_set_flags(struct clk *clk, unsigned long flags);
void qcom_clk_dump(struct clk *clk, bool calltrace);
void qcom_clk_dump(struct clk *clk, struct regulator *regulator,
void qcom_clk_bulk_dump(int num_clks, struct clk_bulk_data *clks,
			bool calltrace);
			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_ */
#endif  /* __LINUX_CLK_QCOM_H_ */