Commit 5f84bb1a authored by Sandipan Patra's avatar Sandipan Patra Committed by Thierry Reding
Browse files

soc/tegra: pmc: Add sysfs entries for reset info



Implement read-only reset_reason and reset_level sysfs attributes that
can be used to query the reset reason and level at runtime.

Signed-off-by: default avatarSandipan Patra <spatra@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 3bb2f843
Loading
Loading
Loading
Loading
+128 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
 * drivers/soc/tegra/pmc.c
 *
 * Copyright (c) 2010 Google, Inc
 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
 *
 * Author:
 *	Colin Cross <ccross@google.com>
@@ -92,7 +93,6 @@
#define  PMC_SENSOR_CTRL_SCRATCH_WRITE	BIT(2)
#define  PMC_SENSOR_CTRL_ENABLE_RST	BIT(1)

#define PMC_RST_STATUS			0x1b4
#define  PMC_RST_STATUS_POR		0
#define  PMC_RST_STATUS_WATCHDOG	1
#define  PMC_RST_STATUS_SENSOR		2
@@ -151,6 +151,11 @@ struct tegra_pmc_regs {
	unsigned int dpd_status;
	unsigned int dpd2_req;
	unsigned int dpd2_status;
	unsigned int rst_status;
	unsigned int rst_source_shift;
	unsigned int rst_source_mask;
	unsigned int rst_level_shift;
	unsigned int rst_level_mask;
};

struct tegra_pmc_soc {
@@ -175,6 +180,42 @@ struct tegra_pmc_soc {
	void (*setup_irq_polarity)(struct tegra_pmc *pmc,
				   struct device_node *np,
				   bool invert);

	const char * const *reset_sources;
	unsigned int num_reset_sources;
	const char * const *reset_levels;
	unsigned int num_reset_levels;
};

static const char * const tegra186_reset_sources[] = {
	"SYS_RESET",
	"AOWDT",
	"MCCPLEXWDT",
	"BPMPWDT",
	"SCEWDT",
	"SPEWDT",
	"APEWDT",
	"BCCPLEXWDT",
	"SENSOR",
	"AOTAG",
	"VFSENSOR",
	"SWREST",
	"SC7",
	"HSM",
	"CORESIGHT"
};

static const char * const tegra186_reset_levels[] = {
	"L0", "L1", "L2", "WARM"
};

static const char * const tegra30_reset_sources[] = {
	"POWER_ON_RESET",
	"WATCHDOG",
	"SENSOR",
	"SW_MAIN",
	"LP0",
	"AOTAG"
};

/**
@@ -1527,6 +1568,56 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
	return err;
}

static ssize_t reset_reason_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	u32 value, rst_src;

	value = tegra_pmc_readl(pmc->soc->regs->rst_status);
	rst_src = (value & pmc->soc->regs->rst_source_mask) >>
			pmc->soc->regs->rst_source_shift;

	return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]);
}

static DEVICE_ATTR_RO(reset_reason);

static ssize_t reset_level_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	u32 value, rst_lvl;

	value = tegra_pmc_readl(pmc->soc->regs->rst_status);
	rst_lvl = (value & pmc->soc->regs->rst_level_mask) >>
			pmc->soc->regs->rst_level_shift;

	return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]);
}

static DEVICE_ATTR_RO(reset_level);

static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc)
{
	struct device *dev = pmc->dev;
	int err = 0;

	if (pmc->soc->reset_sources) {
		err = device_create_file(dev, &dev_attr_reset_reason);
		if (err < 0)
			dev_warn(dev,
				"failed to create attr \"reset_reason\": %d\n",
				err);
	}

	if (pmc->soc->reset_levels) {
		err = device_create_file(dev, &dev_attr_reset_level);
		if (err < 0)
			dev_warn(dev,
				"failed to create attr \"reset_level\": %d\n",
				err);
	}
}

static int tegra_pmc_probe(struct platform_device *pdev)
{
	void __iomem *base;
@@ -1596,6 +1687,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)

	tegra_pmc_init_tsense_reset(pmc);

	tegra_pmc_reset_sysfs_init(pmc);

	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
		err = tegra_powergate_debugfs_init();
		if (err < 0)
@@ -1662,6 +1755,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
	.dpd_status = 0x1bc,
	.dpd2_req = 0x1c0,
	.dpd2_status = 0x1c4,
	.rst_status = 0x1b4,
	.rst_source_shift = 0x0,
	.rst_source_mask = 0x7,
	.rst_level_shift = 0x0,
	.rst_level_mask = 0x0,
};

static void tegra20_pmc_init(struct tegra_pmc *pmc)
@@ -1719,6 +1817,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.reset_sources = NULL,
	.num_reset_sources = 0,
	.reset_levels = NULL,
	.num_reset_levels = 0,
};

static const char * const tegra30_powergates[] = {
@@ -1760,6 +1862,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = 5,
	.reset_levels = NULL,
	.num_reset_levels = 0,
};

static const char * const tegra114_powergates[] = {
@@ -1805,6 +1911,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = 5,
	.reset_levels = NULL,
	.num_reset_levels = 0,
};

static const char * const tegra124_powergates[] = {
@@ -1910,6 +2020,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = 5,
	.reset_levels = NULL,
	.num_reset_levels = 0,
};

static const char * const tegra210_powergates[] = {
@@ -2011,6 +2125,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
	.regs = &tegra20_pmc_regs,
	.init = tegra20_pmc_init,
	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
	.reset_sources = tegra30_reset_sources,
	.num_reset_sources = 5,
	.reset_levels = NULL,
	.num_reset_levels = 0,
};

#define TEGRA186_IO_PAD_TABLE(_pad)					     \
@@ -2068,6 +2186,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
	.dpd_status = 0x78,
	.dpd2_req = 0x7c,
	.dpd2_status = 0x80,
	.rst_status = 0x70,
	.rst_source_shift = 0x2,
	.rst_source_mask = 0x3C,
	.rst_level_shift = 0x0,
	.rst_level_mask = 0x3,
};

static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
@@ -2120,6 +2243,10 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
	.regs = &tegra186_pmc_regs,
	.init = NULL,
	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
	.reset_sources = tegra186_reset_sources,
	.num_reset_sources = 14,
	.reset_levels = tegra186_reset_levels,
	.num_reset_levels = 3,
};

static const struct of_device_id tegra_pmc_match[] = {