Commit 3568df3d authored by Mikko Perttunen's avatar Mikko Perttunen Committed by Thierry Reding

soc: tegra: Add thermal reset (thermtrip) support to PMC

This adds a device tree controlled option to enable PMC-based
thermal reset in overheating situations. Thermtrip is supported on
Tegra30, Tegra114 and Tegra124. The thermal reset only works when
the thermal sensors are calibrated, so a soctherm driver is also
required.

The thermtrip event is triggered by the soctherm block, and all
soctherm sensors default to showing a temperature of zero Celsius
before they are initialized. Because of this, it is safe to initialize
thermtrip and soctherm in any order.
Signed-off-by: default avatarMikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 9c963301
...@@ -70,6 +70,10 @@ ...@@ -70,6 +70,10 @@
#define PMC_SCRATCH41 0x140 #define PMC_SCRATCH41 0x140
#define PMC_SENSOR_CTRL 0x1b0
#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
#define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30) #define IO_DPD_REQ_CODE_OFF (1 << 30)
...@@ -81,6 +85,18 @@ ...@@ -81,6 +85,18 @@
#define IO_DPD2_STATUS 0x1c4 #define IO_DPD2_STATUS 0x1c4
#define SEL_DPD_TIM 0x1c8 #define SEL_DPD_TIM 0x1c8
#define PMC_SCRATCH54 0x258
#define PMC_SCRATCH54_DATA_SHIFT 8
#define PMC_SCRATCH54_ADDR_SHIFT 0
#define PMC_SCRATCH55 0x25c
#define PMC_SCRATCH55_RESET_TEGRA (1 << 31)
#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
#define PMC_SCRATCH55_PINMUX_SHIFT 24
#define PMC_SCRATCH55_16BITOP (1 << 15)
#define PMC_SCRATCH55_CHECKSUM_SHIFT 16
#define PMC_SCRATCH55_I2CSLV1_SHIFT 0
#define GPU_RG_CNTRL 0x2d4 #define GPU_RG_CNTRL 0x2d4
struct tegra_pmc_soc { struct tegra_pmc_soc {
...@@ -89,6 +105,7 @@ struct tegra_pmc_soc { ...@@ -89,6 +105,7 @@ struct tegra_pmc_soc {
unsigned int num_cpu_powergates; unsigned int num_cpu_powergates;
const u8 *cpu_powergates; const u8 *cpu_powergates;
bool has_tsense_reset;
bool has_gpu_clamps; bool has_gpu_clamps;
}; };
...@@ -112,6 +129,7 @@ struct tegra_pmc_soc { ...@@ -112,6 +129,7 @@ struct tegra_pmc_soc {
* @powergates_lock: mutex for power gate register access * @powergates_lock: mutex for power gate register access
*/ */
struct tegra_pmc { struct tegra_pmc {
struct device *dev;
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
...@@ -705,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) ...@@ -705,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
tegra_pmc_writel(value, PMC_CNTRL); tegra_pmc_writel(value, PMC_CNTRL);
} }
void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
{
static const char disabled[] = "emergency thermal reset disabled";
u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
struct device *dev = pmc->dev;
struct device_node *np;
u32 value, checksum;
if (!pmc->soc->has_tsense_reset)
goto out;
np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
if (!np) {
dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) {
dev_err(dev, "I2C controller ID missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) {
dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,reg-addr", &reg_addr)) {
dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,reg-data", &reg_data)) {
dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux))
pinmux = 0;
value = tegra_pmc_readl(PMC_SENSOR_CTRL);
value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
tegra_pmc_writel(value, PMC_SENSOR_CTRL);
value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
(reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
tegra_pmc_writel(value, PMC_SCRATCH54);
value = PMC_SCRATCH55_RESET_TEGRA;
value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT;
/*
* Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will
* contain the checksum and are currently zero, so they are not added.
*/
checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff)
+ ((value >> 24) & 0xff);
checksum &= 0xff;
checksum = 0x100 - checksum;
value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT;
tegra_pmc_writel(value, PMC_SCRATCH55);
value = tegra_pmc_readl(PMC_SENSOR_CTRL);
value |= PMC_SENSOR_CTRL_ENABLE_RST;
tegra_pmc_writel(value, PMC_SENSOR_CTRL);
dev_info(pmc->dev, "emergency thermal reset enabled\n");
out:
of_node_put(np);
return;
}
static int tegra_pmc_probe(struct platform_device *pdev) static int tegra_pmc_probe(struct platform_device *pdev)
{ {
void __iomem *base = pmc->base; void __iomem *base = pmc->base;
...@@ -730,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -730,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err; return err;
} }
pmc->dev = &pdev->dev;
tegra_pmc_init(pmc); tegra_pmc_init(pmc);
tegra_pmc_init_tsense_reset(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)
...@@ -775,6 +874,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { ...@@ -775,6 +874,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.powergates = tegra20_powergates, .powergates = tegra20_powergates,
.num_cpu_powergates = 0, .num_cpu_powergates = 0,
.cpu_powergates = NULL, .cpu_powergates = NULL,
.has_tsense_reset = false,
.has_gpu_clamps = false, .has_gpu_clamps = false,
}; };
...@@ -807,6 +907,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { ...@@ -807,6 +907,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.powergates = tegra30_powergates, .powergates = tegra30_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
.cpu_powergates = tegra30_cpu_powergates, .cpu_powergates = tegra30_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false, .has_gpu_clamps = false,
}; };
...@@ -843,6 +944,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { ...@@ -843,6 +944,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.powergates = tegra114_powergates, .powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
.cpu_powergates = tegra114_cpu_powergates, .cpu_powergates = tegra114_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false, .has_gpu_clamps = false,
}; };
...@@ -885,6 +987,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { ...@@ -885,6 +987,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.powergates = tegra124_powergates, .powergates = tegra124_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
.cpu_powergates = tegra124_cpu_powergates, .cpu_powergates = tegra124_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = true, .has_gpu_clamps = true,
}; };
......
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