Hi,
this series adds support for hardware-triggered thermal reset to the PMC
driver. Namely, it adds device tree properties for specifying the I2C
command to be sent when thermtrip is triggered.
The soctherm driver has now been acked and will be taken into 3.19, so we
can move forward with this. Note that there are no compile time dependencies
between the two series; it's just that this series is no-op without the
soctherm driver being present.
The series is also available at
git://github.com/cyndis/linux pmc-thermtrip-v5
Changes in v5:
- Dropped id property for I2C controllers
- Use integer field instead of phandle for thermtrip i2c controller id
- Rearrange pmc.c using a forward declaration to prevent huge patch
Mikko Perttunen (3):
of: Add descriptions of thermtrip properties to Tegra PMC bindings
ARM: tegra: Add PMC thermtrip programming to Jetson TK1 device tree
ARM: tegra: Add thermal reset (thermtrip) support to PMC
.../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 26 +++++
arch/arm/boot/dts/tegra124-jetson-tk1.dts | 7 ++
drivers/soc/tegra/pmc.c | 107 +++++++++++++++++++++
3 files changed, 140 insertions(+)
--
2.1.3
From: Mikko Perttunen <[email protected]>
Hardware-triggered thermal reset requires configuring the I2C
reset procedure. This configuration is read from the device tree,
so document the relevant properties in the binding documentation.
Signed-off-by: Mikko Perttunen <[email protected]>
---
.../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
index 68ac65f..2fd5051 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -47,6 +47,23 @@ Required properties when nvidia,suspend-mode=<0>:
sleep mode, the warm boot code will restore some PLLs, clocks and then
bring up CPU0 for resuming the system.
+Hardware-triggered thermal reset:
+On Tegra30, Tegra114 and Tegra124, if the 'i2c-thermtrip' subnode exists,
+hardware-triggered thermal reset will be enabled.
+
+Required properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
+- nvidia,i2c-controller-id : ID of I2C controller to send poweroff command to. Valid values are
+ described in section 9.2.148 "APBDEV_PMC_SCRATCH53_0" of the
+ Tegra K1 Technical Reference Manual.
+- nvidia,bus-addr : Bus address of the PMU on the I2C bus
+- nvidia,reg-addr : I2C register address to write poweroff command to
+- nvidia,reg-data : Poweroff command to write to PMU
+
+Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
+- nvidia,pinmux-id : Pinmux used by the hardware when issuing poweroff command.
+ Defaults to 0. Valid values are described in section 12.5.2
+ "Pinmux Support" of the Tegra4 Technical Reference Manual.
+
Example:
/ SoC dts including file
@@ -69,6 +86,15 @@ pmc@7000f400 {
/ Tegra board dts file
{
...
+ pmc@7000f400 {
+ i2c-thermtrip {
+ nvidia,i2c-controller-id = <4>;
+ nvidia,bus-addr = <0x40>;
+ nvidia,reg-addr = <0x36>;
+ nvidia,reg-data = <0x2>;
+ };
+ };
+ ...
clocks {
compatible = "simple-bus";
#address-cells = <1>;
--
2.1.3
From: Mikko Perttunen <[email protected]>
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: Mikko Perttunen <[email protected]>
---
drivers/soc/tegra/pmc.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a2c0ceb..9ed8be5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -83,11 +83,28 @@
#define GPU_RG_CNTRL 0x2d4
+#define PMC_SENSOR_CTRL 0x1b0
+#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
+#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
+
+#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
+
struct tegra_pmc_soc {
unsigned int num_powergates;
const char *const *powergates;
unsigned int num_cpu_powergates;
const u8 *cpu_powergates;
+ bool has_tsense_reset;
};
/**
@@ -703,6 +720,90 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
tegra_pmc_writel(value, PMC_CNTRL);
}
+static const struct of_device_id tegra_pmc_match[];
+
+void tegra_pmc_init_tsense_reset(struct device *dev)
+{
+ u32 pmu_i2c_addr, i2c_ctrl_id, reg_addr, reg_data, pinmux;
+ u32 value, checksum;
+ struct device_node *np = dev->of_node;
+ struct device_node *tt_np;
+ const struct of_device_id *match = of_match_node(tegra_pmc_match, np);
+ const struct tegra_pmc_soc *data = match->data;
+
+ if (!data->has_tsense_reset)
+ return;
+
+ tt_np = of_find_node_by_name(np, "i2c-thermtrip");
+ if (!tt_np) {
+ dev_warn(dev, "no i2c-thermtrip node found, disabling emergency thermal reset\n");
+ return;
+ }
+
+ if (of_property_read_u32(tt_np, "nvidia,i2c-controller-id", &i2c_ctrl_id)) {
+ dev_err(dev, "I2C bus controller id missing, disabling emergency thermal reset\n");
+ goto put_tt;
+ }
+
+ if (of_property_read_u32(tt_np, "nvidia,bus-addr", &pmu_i2c_addr)) {
+ dev_err(dev, "nvidia,bus-addr missing, disabling emergency thermal reset\n");
+ goto put_tt;
+ }
+
+ if (of_property_read_u32(tt_np, "nvidia,reg-addr", ®_addr)) {
+ dev_err(dev, "nvidia,reg-addr missing, disabling emergency thermal reset\n");
+ goto put_tt;
+ }
+
+ if (of_property_read_u32(tt_np, "nvidia,reg-data", ®_data)) {
+ dev_err(dev, "nvidia,reg-data missing, disabling emergency thermal reset\n");
+ goto put_tt;
+ }
+
+ if (of_property_read_u32(tt_np, "nvidia,pinmux-id", &pinmux))
+ pinmux = 0;
+
+ of_node_put(tt_np);
+
+ 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 = 0;
+ value |= PMC_SCRATCH55_RESET_TEGRA;
+ value |= i2c_ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
+ value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
+ value |= pmu_i2c_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(dev, "PMC emergency thermal reset enabled\n");
+
+ return;
+
+put_tt:
+ of_node_put(tt_np);
+}
+
static int tegra_pmc_probe(struct platform_device *pdev)
{
void __iomem *base = pmc->base;
@@ -730,6 +831,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
tegra_pmc_init(pmc);
+ tegra_pmc_init_tsense_reset(&pdev->dev);
+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_powergate_debugfs_init();
if (err < 0)
@@ -772,6 +875,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.powergates = tegra20_powergates,
.num_cpu_powergates = 0,
.cpu_powergates = NULL,
+ .has_tsense_reset = false,
};
static const char * const tegra30_powergates[] = {
@@ -803,6 +907,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.powergates = tegra30_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
.cpu_powergates = tegra30_cpu_powergates,
+ .has_tsense_reset = true,
};
static const char * const tegra114_powergates[] = {
@@ -838,6 +943,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
.cpu_powergates = tegra114_cpu_powergates,
+ .has_tsense_reset = true,
};
static const char * const tegra124_powergates[] = {
@@ -879,6 +985,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.powergates = tegra124_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
.cpu_powergates = tegra124_cpu_powergates,
+ .has_tsense_reset = true,
};
static const struct of_device_id tegra_pmc_match[] = {
--
2.1.3
From: Mikko Perttunen <[email protected]>
This adds the required information to reset the board during an overheating
situation to the Jetson TK1 device tree. The thermal reset is handled by the
PMC by sending an I2C message to the PMIC. The entries specify the I2C
message to be sent.
Signed-off-by: Mikko Perttunen <[email protected]>
---
arch/arm/boot/dts/tegra124-jetson-tk1.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index f46a789..be36bb4 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1672,6 +1672,13 @@
nvidia,core-pwr-off-time = <61036>;
nvidia,core-power-req-active-high;
nvidia,sys-clock-req-active-high;
+
+ i2c-thermtrip {
+ nvidia,i2c-controller-id = <4>;
+ nvidia,bus-addr = <0x40>;
+ nvidia,reg-addr = <0x36>;
+ nvidia,reg-data = <0x2>;
+ };
};
/* Serial ATA */
--
2.1.3