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

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
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* drivers/soc/tegra/pmc.c * drivers/soc/tegra/pmc.c
* *
* Copyright (c) 2010 Google, Inc * Copyright (c) 2010 Google, Inc
* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
* *
* Author: * Author:
* Colin Cross <ccross@google.com> * Colin Cross <ccross@google.com>
...@@ -92,7 +93,6 @@ ...@@ -92,7 +93,6 @@
#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
#define PMC_RST_STATUS 0x1b4
#define PMC_RST_STATUS_POR 0 #define PMC_RST_STATUS_POR 0
#define PMC_RST_STATUS_WATCHDOG 1 #define PMC_RST_STATUS_WATCHDOG 1
#define PMC_RST_STATUS_SENSOR 2 #define PMC_RST_STATUS_SENSOR 2
...@@ -151,6 +151,11 @@ struct tegra_pmc_regs { ...@@ -151,6 +151,11 @@ struct tegra_pmc_regs {
unsigned int dpd_status; unsigned int dpd_status;
unsigned int dpd2_req; unsigned int dpd2_req;
unsigned int dpd2_status; 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 { struct tegra_pmc_soc {
...@@ -175,6 +180,42 @@ struct tegra_pmc_soc { ...@@ -175,6 +180,42 @@ struct tegra_pmc_soc {
void (*setup_irq_polarity)(struct tegra_pmc *pmc, void (*setup_irq_polarity)(struct tegra_pmc *pmc,
struct device_node *np, struct device_node *np,
bool invert); 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) ...@@ -1527,6 +1568,56 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
return err; 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) static int tegra_pmc_probe(struct platform_device *pdev)
{ {
void __iomem *base; void __iomem *base;
...@@ -1596,6 +1687,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -1596,6 +1687,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
tegra_pmc_init_tsense_reset(pmc); tegra_pmc_init_tsense_reset(pmc);
tegra_pmc_reset_sysfs_init(pmc);
if (IS_ENABLED(CONFIG_DEBUG_FS)) { if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_powergate_debugfs_init(); err = tegra_powergate_debugfs_init();
if (err < 0) if (err < 0)
...@@ -1662,6 +1755,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = { ...@@ -1662,6 +1755,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
.dpd_status = 0x1bc, .dpd_status = 0x1bc,
.dpd2_req = 0x1c0, .dpd2_req = 0x1c0,
.dpd2_status = 0x1c4, .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) static void tegra20_pmc_init(struct tegra_pmc *pmc)
...@@ -1719,6 +1817,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { ...@@ -1719,6 +1817,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.regs = &tegra20_pmc_regs, .regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init, .init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .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[] = { static const char * const tegra30_powergates[] = {
...@@ -1760,6 +1862,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { ...@@ -1760,6 +1862,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.regs = &tegra20_pmc_regs, .regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init, .init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .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[] = { static const char * const tegra114_powergates[] = {
...@@ -1805,6 +1911,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { ...@@ -1805,6 +1911,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.regs = &tegra20_pmc_regs, .regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init, .init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .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[] = { static const char * const tegra124_powergates[] = {
...@@ -1910,6 +2020,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { ...@@ -1910,6 +2020,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.regs = &tegra20_pmc_regs, .regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init, .init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .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[] = { static const char * const tegra210_powergates[] = {
...@@ -2011,6 +2125,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { ...@@ -2011,6 +2125,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.regs = &tegra20_pmc_regs, .regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init, .init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .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) \ #define TEGRA186_IO_PAD_TABLE(_pad) \
...@@ -2068,6 +2186,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = { ...@@ -2068,6 +2186,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
.dpd_status = 0x78, .dpd_status = 0x78,
.dpd2_req = 0x7c, .dpd2_req = 0x7c,
.dpd2_status = 0x80, .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, static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
...@@ -2120,6 +2243,10 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { ...@@ -2120,6 +2243,10 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.regs = &tegra186_pmc_regs, .regs = &tegra186_pmc_regs,
.init = NULL, .init = NULL,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity, .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[] = { static const struct of_device_id tegra_pmc_match[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment