* [PATCH V1 02/10] thermal: tegra: combine sensor group-related data
2016-01-13 7:58 [PATCH V1 00/10] Add T210 support in tegra_soctherm Wei Ni
2016-01-13 7:58 ` [PATCH V1 01/10] thermal: tegra: move tegra thermal files into tegra directory Wei Ni
@ 2016-01-13 7:58 ` Wei Ni
2016-01-13 14:31 ` Thierry Reding
2016-01-13 7:58 ` [PATCH V1 03/10] thermal: tegra: split tegra_soctherm driver Wei Ni
2016-01-13 7:58 ` [PATCH V1 04/10] thermal: tegra: add T210-specific SOC_THERM driver Wei Ni
3 siblings, 1 reply; 13+ messages in thread
From: Wei Ni @ 2016-01-13 7:58 UTC (permalink / raw)
To: rui.zhang, mikko.perttunen, swarren; +Cc: linux-tegra, linux-kernel, Wei Ni
Combine sensor group-related data structures into struct
tegra_tsensor_group. This provides a single location for
sensor group data storage.
More sensor group data will be added in subsequent patches.
Get rid of T124-specific PDIV/HOTSPOT hack.
tegra-soctherm.c contained a hack to set the SENSOR_PDIV and
SENSOR_HOTSPOT_OFFSET registers - it just did two writes of
T124-specific opaque values. Convert these into a form that can be
substituted on a per-chip basis, and into structure fields that have
at least some independent meaning.
Signed-off-by: Wei Ni <wni@nvidia.com>
---
drivers/thermal/tegra/tegra_soctherm.c | 165 +++++++++++++++++++-----
include/dt-bindings/thermal/tegra124-soctherm.h | 1 +
2 files changed, 135 insertions(+), 31 deletions(-)
diff --git a/drivers/thermal/tegra/tegra_soctherm.c b/drivers/thermal/tegra/tegra_soctherm.c
index 74ea5765938b..80d97151739e 100644
--- a/drivers/thermal/tegra/tegra_soctherm.c
+++ b/drivers/thermal/tegra/tegra_soctherm.c
@@ -28,6 +28,7 @@
#include <linux/thermal.h>
#include <soc/tegra/fuse.h>
+#include <dt-bindings/thermal/tegra124-soctherm.h>
#define SENSOR_CONFIG0 0
#define SENSOR_CONFIG0_STOP BIT(0)
@@ -47,13 +48,23 @@
#define SENSOR_CONFIG2_THERMB_SHIFT 0
#define SENSOR_PDIV 0x1c0
-#define SENSOR_PDIV_T124 0x8888
+#define SENSOR_PDIV_CPU_MASK (0xf << 12)
+#define SENSOR_PDIV_GPU_MASK (0xf << 8)
+#define SENSOR_PDIV_MEM_MASK (0xf << 4)
+#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
+
#define SENSOR_HOTSPOT_OFF 0x1c4
-#define SENSOR_HOTSPOT_OFF_T124 0x00060600
+#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
+#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
+#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
+
#define SENSOR_TEMP1 0x1c8
+#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16)
+#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
#define SENSOR_TEMP2 0x1cc
+#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16)
+#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
-#define SENSOR_TEMP_MASK 0xffff
#define READBACK_VALUE_MASK 0xff00
#define READBACK_VALUE_SHIFT 8
#define READBACK_ADD_HALF BIT(7)
@@ -77,8 +88,36 @@
#define NOMINAL_CALIB_FT_T124 105
#define NOMINAL_CALIB_CP_T124 25
+/* get val from register(r) mask bits(m) */
+#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
+/* set val(v) to mask bits(m) of register(r) */
+#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
+ (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
+
+/**
+ * struct tegra_tsensor_group - SOC_THERM sensor group data
+ * @name: short name of the temperature sensor group
+ * @id: numeric ID of the temperature sensor group
+ * @sensor_temp_offset: offset of the SENSOR_TEMP* register
+ * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register
+ * @pdiv: the sensor count post-divider to use during runtime
+ * @pdiv_ate: the sensor count post-divider used during automated test
+ * @pdiv_mask: register bitfield mask for the PDIV field for this sensor
+ * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for
+ PLLX sensor group
+ * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field
+ */
+struct tegra_tsensor_group {
+ const char *name;
+ u8 id;
+ u16 sensor_temp_offset;
+ u32 sensor_temp_mask;
+ u32 pdiv, pdiv_ate, pdiv_mask;
+ u32 pllx_hotspot_diff, pllx_hotspot_mask;
+};
+
struct tegra_tsensor_configuration {
- u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate;
+ u32 tall, tiddq_en, ten_count, tsample, tsample_ate;
};
struct tegra_tsensor {
@@ -86,21 +125,74 @@ struct tegra_tsensor {
u32 base, calib_fuse_offset;
/* Correction values used to modify values read from calibration fuses */
s32 fuse_corr_alpha, fuse_corr_beta;
+ const struct tegra_tsensor_group *group;
};
struct tegra_thermctl_zone {
void __iomem *reg;
- unsigned int shift;
+ u32 mask;
};
static const struct tegra_tsensor_configuration t124_tsensor_config = {
.tall = 16300,
- .tsample = 120,
.tiddq_en = 1,
.ten_count = 1,
- .pdiv = 8,
+ .tsample = 120,
.tsample_ate = 480,
- .pdiv_ate = 8
+};
+
+static struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_CPU,
+ .name = "cpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_CPU_MASK,
+ .pllx_hotspot_diff = 10,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
+};
+
+static struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_GPU,
+ .name = "gpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_GPU_MASK,
+ .pllx_hotspot_diff = 5,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
+};
+
+static struct tegra_tsensor_group tegra124_tsensor_group_pll = {
+ .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
+ .name = "pll",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
+ .pllx_hotspot_diff = 0,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
+};
+
+static struct tegra_tsensor_group tegra124_tsensor_group_mem = {
+ .id = TEGRA124_SOCTHERM_SENSOR_MEM,
+ .name = "mem",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_MEM_MASK,
+};
+
+static struct tegra_tsensor_group *
+tegra124_tsensor_groups[TEGRA124_SOCTHERM_SENSOR_NUM] = {
+ &tegra124_tsensor_group_cpu,
+ &tegra124_tsensor_group_gpu,
+ &tegra124_tsensor_group_pll,
+ &tegra124_tsensor_group_mem,
};
static const struct tegra_tsensor t124_tsensors[] = {
@@ -110,6 +202,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x098,
.fuse_corr_alpha = 1135400,
.fuse_corr_beta = -6266900,
+ .group = &tegra124_tsensor_group_cpu,
},
{
.config = &t124_tsensor_config,
@@ -117,6 +210,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x084,
.fuse_corr_alpha = 1122220,
.fuse_corr_beta = -5700700,
+ .group = &tegra124_tsensor_group_cpu,
},
{
.config = &t124_tsensor_config,
@@ -124,6 +218,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x088,
.fuse_corr_alpha = 1127000,
.fuse_corr_beta = -6768200,
+ .group = &tegra124_tsensor_group_cpu,
},
{
.config = &t124_tsensor_config,
@@ -131,6 +226,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x12c,
.fuse_corr_alpha = 1110900,
.fuse_corr_beta = -6232000,
+ .group = &tegra124_tsensor_group_cpu,
},
{
.config = &t124_tsensor_config,
@@ -138,6 +234,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x158,
.fuse_corr_alpha = 1122300,
.fuse_corr_beta = -5936400,
+ .group = &tegra124_tsensor_group_mem,
},
{
.config = &t124_tsensor_config,
@@ -145,6 +242,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x15c,
.fuse_corr_alpha = 1145700,
.fuse_corr_beta = -7124600,
+ .group = &tegra124_tsensor_group_mem,
},
{
.config = &t124_tsensor_config,
@@ -152,6 +250,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x154,
.fuse_corr_alpha = 1120100,
.fuse_corr_beta = -6000500,
+ .group = &tegra124_tsensor_group_gpu,
},
{
.config = &t124_tsensor_config,
@@ -159,6 +258,7 @@ static const struct tegra_tsensor t124_tsensors[] = {
.calib_fuse_offset = 0x160,
.fuse_corr_alpha = 1106500,
.fuse_corr_beta = -6729300,
+ .group = &tegra124_tsensor_group_pll,
},
};
@@ -168,7 +268,7 @@ struct tegra_soctherm {
struct clk *clock_soctherm;
void __iomem *regs;
- struct thermal_zone_device *thermctl_tzs[4];
+ struct thermal_zone_device *thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_NUM];
};
struct tsensor_shared_calibration {
@@ -237,8 +337,8 @@ calculate_tsensor_calibration(const struct tegra_tsensor *sensor,
delta_sens = actual_tsensor_ft - actual_tsensor_cp;
delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
- mult = sensor->config->pdiv * sensor->config->tsample_ate;
- div = sensor->config->tsample * sensor->config->pdiv_ate;
+ mult = sensor->group->pdiv * sensor->config->tsample_ate;
+ div = sensor->config->tsample * sensor->group->pdiv_ate;
therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult,
(s64) delta_sens * div);
@@ -311,7 +411,8 @@ static int tegra_thermctl_get_temp(void *data, int *out_temp)
struct tegra_thermctl_zone *zone = data;
u32 val;
- val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK;
+ val = readl(zone->reg);
+ val = REG_GET_MASK(val, zone->mask);
*out_temp = translate_temp(val);
return 0;
@@ -327,18 +428,6 @@ static const struct of_device_id tegra_soctherm_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
-struct thermctl_zone_desc {
- unsigned int offset;
- unsigned int shift;
-};
-
-static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = {
- { SENSOR_TEMP1, 16 },
- { SENSOR_TEMP2, 16 },
- { SENSOR_TEMP1, 0 },
- { SENSOR_TEMP2, 0 }
-};
-
static int tegra_soctherm_probe(struct platform_device *pdev)
{
struct tegra_soctherm *tegra;
@@ -347,8 +436,10 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
struct resource *res;
unsigned int i;
int err;
+ u32 pdiv, hotspot;
const struct tegra_tsensor *tsensors = t124_tsensors;
+ struct tegra_tsensor_group **ttgs = tegra124_tsensor_groups;
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
if (!tegra)
@@ -403,12 +494,23 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
goto disable_clocks;
}
- writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV);
- writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF);
+ /* program pdiv and hotspot offsets per THERM */
+ pdiv = readl(tegra->regs + SENSOR_PDIV);
+ hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF);
+ for (i = 0; i < TEGRA124_SOCTHERM_SENSOR_NUM; ++i) {
+ pdiv = REG_SET_MASK(pdiv, ttgs[i]->pdiv_mask,
+ ttgs[i]->pdiv);
+ if (ttgs[i]->id != TEGRA124_SOCTHERM_SENSOR_PLLX)
+ hotspot = REG_SET_MASK(hotspot,
+ ttgs[i]->pllx_hotspot_mask,
+ ttgs[i]->pllx_hotspot_diff);
+ }
+ writel(pdiv, tegra->regs + SENSOR_PDIV);
+ writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
/* Initialize thermctl sensors */
- for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) {
+ for (i = 0; i < TEGRA124_SOCTHERM_SENSOR_NUM; ++i) {
struct tegra_thermctl_zone *zone =
devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
if (!zone) {
@@ -416,10 +518,11 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
goto unregister_tzs;
}
- zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset;
- zone->shift = t124_thermctl_temp_zones[i].shift;
+ zone->reg = tegra->regs + ttgs[i]->sensor_temp_offset;
+ zone->mask = ttgs[i]->sensor_temp_mask;
- tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone,
+ tz = thermal_zone_of_sensor_register(&pdev->dev,
+ ttgs[i]->id, zone,
&tegra_of_thermal_ops);
if (IS_ERR(tz)) {
err = PTR_ERR(tz);
@@ -428,7 +531,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
goto unregister_tzs;
}
- tegra->thermctl_tzs[i] = tz;
+ tegra->thermctl_tzs[ttgs[i]->id] = tz;
}
return 0;
diff --git a/include/dt-bindings/thermal/tegra124-soctherm.h b/include/dt-bindings/thermal/tegra124-soctherm.h
index 85aaf66690f9..729ab9fc325e 100644
--- a/include/dt-bindings/thermal/tegra124-soctherm.h
+++ b/include/dt-bindings/thermal/tegra124-soctherm.h
@@ -9,5 +9,6 @@
#define TEGRA124_SOCTHERM_SENSOR_MEM 1
#define TEGRA124_SOCTHERM_SENSOR_GPU 2
#define TEGRA124_SOCTHERM_SENSOR_PLLX 3
+#define TEGRA124_SOCTHERM_SENSOR_NUM 4
#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH V1 03/10] thermal: tegra: split tegra_soctherm driver
2016-01-13 7:58 [PATCH V1 00/10] Add T210 support in tegra_soctherm Wei Ni
2016-01-13 7:58 ` [PATCH V1 01/10] thermal: tegra: move tegra thermal files into tegra directory Wei Ni
2016-01-13 7:58 ` [PATCH V1 02/10] thermal: tegra: combine sensor group-related data Wei Ni
@ 2016-01-13 7:58 ` Wei Ni
[not found] ` <1452671929-32740-4-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2016-01-13 7:58 ` [PATCH V1 04/10] thermal: tegra: add T210-specific SOC_THERM driver Wei Ni
3 siblings, 1 reply; 13+ messages in thread
From: Wei Ni @ 2016-01-13 7:58 UTC (permalink / raw)
To: rui.zhang, mikko.perttunen, swarren; +Cc: linux-tegra, linux-kernel, Wei Ni
Split most of the T124 data and code into a T124-specific driver.
Split most of the fuse-related code into a fuse-related source file.
Now drivers/thermal/tegra_soctherm.c contains common SOC_THERM library
code. This is in preparation for adding a T210-specific driver in a
future patch.
Beyond the maintainability improvements, this is intended to separate
chip-specific ATE and characterization-related hacks into chip-specific
drivers, in the hopes that they won't pollute code for other chips.
Signed-off-by: Wei Ni <wni@nvidia.com>
---
drivers/thermal/tegra/Kconfig | 8 +-
drivers/thermal/tegra/Makefile | 3 +-
drivers/thermal/tegra/tegra124_soctherm.c | 201 +++++++++++++++++
drivers/thermal/tegra/tegra_soctherm.c | 333 ++--------------------------
drivers/thermal/tegra/tegra_soctherm.h | 106 +++++++++
drivers/thermal/tegra/tegra_soctherm_fuse.c | 143 ++++++++++++
6 files changed, 474 insertions(+), 320 deletions(-)
create mode 100644 drivers/thermal/tegra/tegra124_soctherm.c
create mode 100644 drivers/thermal/tegra/tegra_soctherm.h
create mode 100644 drivers/thermal/tegra/tegra_soctherm_fuse.c
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
index a6e6cd4528dc..ae7e5e93dab9 100644
--- a/drivers/thermal/tegra/Kconfig
+++ b/drivers/thermal/tegra/Kconfig
@@ -1,6 +1,10 @@
config TEGRA_SOCTHERM
- tristate "Tegra SOCTHERM thermal management"
- depends on ARCH_TEGRA
+ bool
+
+config TEGRA124_SOCTHERM
+ bool "Tegra124 SOCTHERM thermal management"
+ depends on ARCH_TEGRA_124_SOC
+ select TEGRA_SOCTHERM
help
Enable this option for integrated thermal management support on NVIDIA
Tegra124 systems-on-chip. The driver supports four thermal zones
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index 8c51076e4b1e..7a864ec07a25 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -3,4 +3,5 @@
#
# Tegra soc thermal drivers
-obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o
+obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o tegra_soctherm_fuse.o
+obj-$(CONFIG_TEGRA124_SOCTHERM) += tegra124_soctherm.o
diff --git a/drivers/thermal/tegra/tegra124_soctherm.c b/drivers/thermal/tegra/tegra124_soctherm.c
new file mode 100644
index 000000000000..56bf26d58a04
--- /dev/null
+++ b/drivers/thermal/tegra/tegra124_soctherm.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/thermal/tegra124-soctherm.h>
+
+#include "tegra_soctherm.h"
+
+static const struct tegra_tsensor_configuration t124_tsensor_config = {
+ .tall = 16300,
+ .tiddq_en = 1,
+ .ten_count = 1,
+ .tsample = 120,
+ .tsample_ate = 480,
+};
+
+static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_CPU,
+ .name = "cpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_CPU_MASK,
+ .pllx_hotspot_diff = 10,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
+};
+
+static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_GPU,
+ .name = "gpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_GPU_MASK,
+ .pllx_hotspot_diff = 5,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
+};
+
+static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
+ .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
+ .name = "pll",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
+};
+
+static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
+ .id = TEGRA124_SOCTHERM_SENSOR_MEM,
+ .name = "mem",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_MEM_MASK,
+ .pllx_hotspot_diff = 0,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
+};
+
+static const struct tegra_tsensor_group *
+tegra124_tsensor_groups[TEGRA124_SOCTHERM_SENSOR_NUM] = {
+ &tegra124_tsensor_group_cpu,
+ &tegra124_tsensor_group_gpu,
+ &tegra124_tsensor_group_pll,
+ &tegra124_tsensor_group_mem,
+};
+
+static struct tegra_tsensor tegra124_tsensors[] = {
+ {
+ .name = "cpu0",
+ .base = 0xc0,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x098,
+ .fuse_corr_alpha = 1135400,
+ .fuse_corr_beta = -6266900,
+ .group = &tegra124_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu1",
+ .base = 0xe0,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x084,
+ .fuse_corr_alpha = 1122220,
+ .fuse_corr_beta = -5700700,
+ .group = &tegra124_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu2",
+ .base = 0x100,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x088,
+ .fuse_corr_alpha = 1127000,
+ .fuse_corr_beta = -6768200,
+ .group = &tegra124_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu3",
+ .base = 0x120,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x12c,
+ .fuse_corr_alpha = 1110900,
+ .fuse_corr_beta = -6232000,
+ .group = &tegra124_tsensor_group_cpu,
+ },
+ {
+ .name = "mem0",
+ .base = 0x140,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x158,
+ .fuse_corr_alpha = 1122300,
+ .fuse_corr_beta = -5936400,
+ .group = &tegra124_tsensor_group_mem,
+ },
+ {
+ .name = "mem1",
+ .base = 0x160,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x15c,
+ .fuse_corr_alpha = 1145700,
+ .fuse_corr_beta = -7124600,
+ .group = &tegra124_tsensor_group_mem,
+ },
+ {
+ .name = "gpu",
+ .base = 0x180,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x154,
+ .fuse_corr_alpha = 1120100,
+ .fuse_corr_beta = -6000500,
+ .group = &tegra124_tsensor_group_gpu,
+ },
+ {
+ .name = "pllx",
+ .base = 0x1a0,
+ .config = &t124_tsensor_config,
+ .calib_fuse_offset = 0x160,
+ .fuse_corr_alpha = 1106500,
+ .fuse_corr_beta = -6729300,
+ .group = &tegra124_tsensor_group_pll,
+ },
+ { .name = NULL },
+};
+
+/*
+ * Mask/shift bits in FUSE_TSENSOR_COMMON and
+ * FUSE_TSENSOR_COMMON, which are described in
+ * tegra_soctherm_fuse.c
+ */
+static const struct tegra_soctherm_fuse tegra124_soctherm_fuse = {
+ .fuse_base_cp_mask = 0x3ff,
+ .fuse_base_cp_shift = 0,
+ .fuse_base_ft_mask = 0x7ff << 10,
+ .fuse_base_ft_shift = 10,
+ .fuse_shift_ft_mask = 0x1f << 21,
+ .fuse_shift_ft_shift = 21,
+ .fuse_spare_realignment = 0x1fc,
+};
+
+static const struct of_device_id tegra124_soctherm_of_match[] = {
+ { .compatible = "nvidia,tegra124-soctherm" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
+
+static int tegra124_soctherm_probe(struct platform_device *pdev)
+{
+ return tegra_soctherm_probe(pdev,
+ tegra124_tsensors,
+ tegra124_tsensor_groups,
+ &tegra124_soctherm_fuse);
+}
+
+static struct platform_driver tegra124_soctherm_driver = {
+ .probe = tegra124_soctherm_probe,
+ .remove = tegra_soctherm_remove,
+ .driver = {
+ .name = "tegra124_soctherm",
+ .of_match_table = tegra124_soctherm_of_match,
+ },
+};
+module_platform_driver(tegra124_soctherm_driver);
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("Tegra124 SOCTHERM thermal management driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/tegra_soctherm.c b/drivers/thermal/tegra/tegra_soctherm.c
index 80d97151739e..cc5a3e14948f 100644
--- a/drivers/thermal/tegra/tegra_soctherm.c
+++ b/drivers/thermal/tegra/tegra_soctherm.c
@@ -27,9 +27,10 @@
#include <linux/reset.h>
#include <linux/thermal.h>
-#include <soc/tegra/fuse.h>
#include <dt-bindings/thermal/tegra124-soctherm.h>
+#include "tegra_soctherm.h"
+
#define SENSOR_CONFIG0 0
#define SENSOR_CONFIG0_STOP BIT(0)
#define SENSOR_CONFIG0_TALL_SHIFT 8
@@ -43,225 +44,27 @@
#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
-#define SENSOR_CONFIG2 8
-#define SENSOR_CONFIG2_THERMA_SHIFT 16
-#define SENSOR_CONFIG2_THERMB_SHIFT 0
-
-#define SENSOR_PDIV 0x1c0
-#define SENSOR_PDIV_CPU_MASK (0xf << 12)
-#define SENSOR_PDIV_GPU_MASK (0xf << 8)
-#define SENSOR_PDIV_MEM_MASK (0xf << 4)
-#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
-
-#define SENSOR_HOTSPOT_OFF 0x1c4
-#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
-#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
-#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
-
-#define SENSOR_TEMP1 0x1c8
-#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16)
-#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
-#define SENSOR_TEMP2 0x1cc
-#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16)
-#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
+/*
+ * SENSOR_CONFIG2 is defined in tegra_soctherm.h
+ * because, it will be used by tegra_soctherm_fuse.c
+ */
#define READBACK_VALUE_MASK 0xff00
#define READBACK_VALUE_SHIFT 8
#define READBACK_ADD_HALF BIT(7)
#define READBACK_NEGATE BIT(1)
-#define FUSE_TSENSOR8_CALIB 0x180
-#define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc
-
-#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
-#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
-#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
-
-#define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff
-#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10)
-#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10
-
-#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f
-#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21)
-#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
-
-#define NOMINAL_CALIB_FT_T124 105
-#define NOMINAL_CALIB_CP_T124 25
-
/* get val from register(r) mask bits(m) */
#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
/* set val(v) to mask bits(m) of register(r) */
#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
(((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
-/**
- * struct tegra_tsensor_group - SOC_THERM sensor group data
- * @name: short name of the temperature sensor group
- * @id: numeric ID of the temperature sensor group
- * @sensor_temp_offset: offset of the SENSOR_TEMP* register
- * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register
- * @pdiv: the sensor count post-divider to use during runtime
- * @pdiv_ate: the sensor count post-divider used during automated test
- * @pdiv_mask: register bitfield mask for the PDIV field for this sensor
- * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for
- PLLX sensor group
- * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field
- */
-struct tegra_tsensor_group {
- const char *name;
- u8 id;
- u16 sensor_temp_offset;
- u32 sensor_temp_mask;
- u32 pdiv, pdiv_ate, pdiv_mask;
- u32 pllx_hotspot_diff, pllx_hotspot_mask;
-};
-
-struct tegra_tsensor_configuration {
- u32 tall, tiddq_en, ten_count, tsample, tsample_ate;
-};
-
-struct tegra_tsensor {
- const struct tegra_tsensor_configuration *config;
- u32 base, calib_fuse_offset;
- /* Correction values used to modify values read from calibration fuses */
- s32 fuse_corr_alpha, fuse_corr_beta;
- const struct tegra_tsensor_group *group;
-};
-
struct tegra_thermctl_zone {
void __iomem *reg;
u32 mask;
};
-static const struct tegra_tsensor_configuration t124_tsensor_config = {
- .tall = 16300,
- .tiddq_en = 1,
- .ten_count = 1,
- .tsample = 120,
- .tsample_ate = 480,
-};
-
-static struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
- .id = TEGRA124_SOCTHERM_SENSOR_CPU,
- .name = "cpu",
- .sensor_temp_offset = SENSOR_TEMP1,
- .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
- .pdiv = 8,
- .pdiv_ate = 8,
- .pdiv_mask = SENSOR_PDIV_CPU_MASK,
- .pllx_hotspot_diff = 10,
- .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
-};
-
-static struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
- .id = TEGRA124_SOCTHERM_SENSOR_GPU,
- .name = "gpu",
- .sensor_temp_offset = SENSOR_TEMP1,
- .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
- .pdiv = 8,
- .pdiv_ate = 8,
- .pdiv_mask = SENSOR_PDIV_GPU_MASK,
- .pllx_hotspot_diff = 5,
- .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
-};
-
-static struct tegra_tsensor_group tegra124_tsensor_group_pll = {
- .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
- .name = "pll",
- .sensor_temp_offset = SENSOR_TEMP2,
- .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
- .pdiv = 8,
- .pdiv_ate = 8,
- .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
- .pllx_hotspot_diff = 0,
- .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
-};
-
-static struct tegra_tsensor_group tegra124_tsensor_group_mem = {
- .id = TEGRA124_SOCTHERM_SENSOR_MEM,
- .name = "mem",
- .sensor_temp_offset = SENSOR_TEMP2,
- .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
- .pdiv = 8,
- .pdiv_ate = 8,
- .pdiv_mask = SENSOR_PDIV_MEM_MASK,
-};
-
-static struct tegra_tsensor_group *
-tegra124_tsensor_groups[TEGRA124_SOCTHERM_SENSOR_NUM] = {
- &tegra124_tsensor_group_cpu,
- &tegra124_tsensor_group_gpu,
- &tegra124_tsensor_group_pll,
- &tegra124_tsensor_group_mem,
-};
-
-static const struct tegra_tsensor t124_tsensors[] = {
- {
- .config = &t124_tsensor_config,
- .base = 0xc0,
- .calib_fuse_offset = 0x098,
- .fuse_corr_alpha = 1135400,
- .fuse_corr_beta = -6266900,
- .group = &tegra124_tsensor_group_cpu,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0xe0,
- .calib_fuse_offset = 0x084,
- .fuse_corr_alpha = 1122220,
- .fuse_corr_beta = -5700700,
- .group = &tegra124_tsensor_group_cpu,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x100,
- .calib_fuse_offset = 0x088,
- .fuse_corr_alpha = 1127000,
- .fuse_corr_beta = -6768200,
- .group = &tegra124_tsensor_group_cpu,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x120,
- .calib_fuse_offset = 0x12c,
- .fuse_corr_alpha = 1110900,
- .fuse_corr_beta = -6232000,
- .group = &tegra124_tsensor_group_cpu,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x140,
- .calib_fuse_offset = 0x158,
- .fuse_corr_alpha = 1122300,
- .fuse_corr_beta = -5936400,
- .group = &tegra124_tsensor_group_mem,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x160,
- .calib_fuse_offset = 0x15c,
- .fuse_corr_alpha = 1145700,
- .fuse_corr_beta = -7124600,
- .group = &tegra124_tsensor_group_mem,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x180,
- .calib_fuse_offset = 0x154,
- .fuse_corr_alpha = 1120100,
- .fuse_corr_beta = -6000500,
- .group = &tegra124_tsensor_group_gpu,
- },
- {
- .config = &t124_tsensor_config,
- .base = 0x1a0,
- .calib_fuse_offset = 0x160,
- .fuse_corr_alpha = 1106500,
- .fuse_corr_beta = -6729300,
- .group = &tegra124_tsensor_group_pll,
- },
-};
-
struct tegra_soctherm {
struct reset_control *reset;
struct clk *clock_tsensor;
@@ -271,103 +74,15 @@ struct tegra_soctherm {
struct thermal_zone_device *thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_NUM];
};
-struct tsensor_shared_calibration {
- u32 base_cp, base_ft;
- u32 actual_temp_cp, actual_temp_ft;
-};
-
-static int calculate_shared_calibration(struct tsensor_shared_calibration *r)
-{
- u32 val, shifted_cp, shifted_ft;
- int err;
-
- err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val);
- if (err)
- return err;
- r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK;
- r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK)
- >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT;
- val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK)
- >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT);
- shifted_ft = sign_extend32(val, 4);
-
- err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val);
- if (err)
- return err;
- shifted_cp = sign_extend32(val, 5);
-
- r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp;
- r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft;
-
- return 0;
-}
-
-static s64 div64_s64_precise(s64 a, s64 b)
-{
- s64 r, al;
-
- /* Scale up for increased precision division */
- al = a << 16;
-
- r = div64_s64(al * 2 + 1, 2 * b);
- return r >> 16;
-}
-
-static int
-calculate_tsensor_calibration(const struct tegra_tsensor *sensor,
- const struct tsensor_shared_calibration *shared,
- u32 *calib)
-{
- u32 val;
- s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp,
- mult, div;
- s16 therma, thermb;
- s64 tmp;
- int err;
-
- err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
- if (err)
- return err;
-
- actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
- val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK)
- >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
- actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
-
- delta_sens = actual_tsensor_ft - actual_tsensor_cp;
- delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
-
- mult = sensor->group->pdiv * sensor->config->tsample_ate;
- div = sensor->config->tsample * sensor->group->pdiv_ate;
-
- therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult,
- (s64) delta_sens * div);
-
- tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp -
- (s64)actual_tsensor_cp * shared->actual_temp_ft;
- thermb = div64_s64_precise(tmp, (s64)delta_sens);
-
- therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha,
- (s64)1000000LL);
- thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha +
- sensor->fuse_corr_beta, (s64)1000000LL);
-
- *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
- ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
-
- return 0;
-}
-
static int enable_tsensor(struct tegra_soctherm *tegra,
- const struct tegra_tsensor *sensor,
+ struct tegra_tsensor *sensor,
const struct tsensor_shared_calibration *shared)
{
void __iomem *base = tegra->regs + sensor->base;
unsigned int val;
- u32 calib;
int err;
- err = calculate_tsensor_calibration(sensor, shared, &calib);
+ err = tegra_soctherm_calculate_tsensor_calibration(sensor, shared);
if (err)
return err;
@@ -380,7 +95,7 @@ static int enable_tsensor(struct tegra_soctherm *tegra,
val |= SENSOR_CONFIG1_TEMP_ENABLE;
writel(val, base + SENSOR_CONFIG1);
- writel(calib, base + SENSOR_CONFIG2);
+ writel(sensor->calib, base + SENSOR_CONFIG2);
return 0;
}
@@ -422,13 +137,10 @@ static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
.get_temp = tegra_thermctl_get_temp,
};
-static const struct of_device_id tegra_soctherm_of_match[] = {
- { .compatible = "nvidia,tegra124-soctherm" },
- { },
-};
-MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
-
-static int tegra_soctherm_probe(struct platform_device *pdev)
+int tegra_soctherm_probe(struct platform_device *pdev,
+ struct tegra_tsensor *tsensors,
+ const struct tegra_tsensor_group **ttgs,
+ const struct tegra_soctherm_fuse *tfuse)
{
struct tegra_soctherm *tegra;
struct thermal_zone_device *tz;
@@ -438,9 +150,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
int err;
u32 pdiv, hotspot;
- const struct tegra_tsensor *tsensors = t124_tsensors;
- struct tegra_tsensor_group **ttgs = tegra124_tsensor_groups;
-
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
if (!tegra)
return -ENOMEM;
@@ -484,11 +193,11 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
/* Initialize raw sensors */
- err = calculate_shared_calibration(&shared_calib);
+ err = tegra_soctherm_calculate_shared_calibration(tfuse, &shared_calib);
if (err)
goto disable_clocks;
- for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) {
+ for (i = 0; tsensors[i].name; ++i) {
err = enable_tsensor(tegra, tsensors + i, &shared_calib);
if (err)
goto disable_clocks;
@@ -548,7 +257,7 @@ disable_clocks:
return err;
}
-static int tegra_soctherm_remove(struct platform_device *pdev)
+int tegra_soctherm_remove(struct platform_device *pdev)
{
struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
unsigned int i;
@@ -564,16 +273,6 @@ static int tegra_soctherm_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver tegra_soctherm_driver = {
- .probe = tegra_soctherm_probe,
- .remove = tegra_soctherm_remove,
- .driver = {
- .name = "tegra-soctherm",
- .of_match_table = tegra_soctherm_of_match,
- },
-};
-module_platform_driver(tegra_soctherm_driver);
-
MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/tegra_soctherm.h b/drivers/thermal/tegra/tegra_soctherm.h
new file mode 100644
index 000000000000..8d06f4f75ff9
--- /dev/null
+++ b/drivers/thermal/tegra/tegra_soctherm.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
+#define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H
+
+#define SENSOR_CONFIG2 8
+#define SENSOR_CONFIG2_THERMA_SHIFT 16
+#define SENSOR_CONFIG2_THERMB_SHIFT 0
+
+#define SENSOR_PDIV 0x1c0
+#define SENSOR_PDIV_CPU_MASK (0xf << 12)
+#define SENSOR_PDIV_GPU_MASK (0xf << 8)
+#define SENSOR_PDIV_MEM_MASK (0xf << 4)
+#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
+
+#define SENSOR_HOTSPOT_OFF 0x1c4
+#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
+#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
+#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
+
+#define SENSOR_TEMP1 0x1c8
+#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffff << 16)
+#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
+#define SENSOR_TEMP2 0x1cc
+#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16)
+#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
+
+/**
+ * struct tegra_tsensor_group - SOC_THERM sensor group data
+ * @name: short name of the temperature sensor group
+ * @id: numeric ID of the temperature sensor group
+ * @sensor_temp_offset: offset of the SENSOR_TEMP* register
+ * @sensor_temp_mask: bit mask for this sensor group in SENSOR_TEMP* register
+ * @pdiv: the sensor count post-divider to use during runtime
+ * @pdiv_ate: the sensor count post-divider used during automated test
+ * @pdiv_mask: register bitfield mask for the PDIV field for this sensor
+ * @pllx_hotspot_diff: hotspot offset from the PLLX sensor, must be 0 for
+ PLLX sensor group
+ * @pllx_hotspot_mask: register bitfield mask for the HOTSPOT field
+ */
+struct tegra_tsensor_group {
+ const char *name;
+ u8 id;
+ u16 sensor_temp_offset;
+ u32 sensor_temp_mask;
+ u32 pdiv, pdiv_ate, pdiv_mask;
+ u32 pllx_hotspot_diff, pllx_hotspot_mask;
+};
+
+struct tegra_tsensor_configuration {
+ u32 tall, tiddq_en, ten_count, pdiv, pdiv_ate, tsample, tsample_ate;
+};
+
+struct tegra_tsensor {
+ const char *name;
+ u32 base;
+ const struct tegra_tsensor_configuration *config;
+ u32 calib_fuse_offset;
+ /*
+ * Correction values used to modify values read from
+ * calibration fuses
+ */
+ s32 fuse_corr_alpha, fuse_corr_beta;
+ u32 calib;
+ const struct tegra_tsensor_group *group;
+};
+
+struct tegra_soctherm_fuse {
+ u32 fuse_base_cp_mask, fuse_base_cp_shift;
+ u32 fuse_base_ft_mask, fuse_base_ft_shift;
+ u32 fuse_shift_ft_mask, fuse_shift_ft_shift;
+ u32 fuse_spare_realignment;
+};
+
+struct tsensor_shared_calibration {
+ u32 base_cp, base_ft;
+ u32 actual_temp_cp, actual_temp_ft;
+};
+
+int tegra_soctherm_calculate_shared_calibration(
+ const struct tegra_soctherm_fuse *tfuse,
+ struct tsensor_shared_calibration *shared);
+int tegra_soctherm_calculate_tsensor_calibration(
+ struct tegra_tsensor *sensor,
+ const struct tsensor_shared_calibration *shared);
+
+int tegra_soctherm_probe(struct platform_device *pdev,
+ struct tegra_tsensor *tsensors,
+ const struct tegra_tsensor_group **ttgs,
+ const struct tegra_soctherm_fuse *tfuse);
+int tegra_soctherm_remove(struct platform_device *pdev);
+
+#endif
+
diff --git a/drivers/thermal/tegra/tegra_soctherm_fuse.c b/drivers/thermal/tegra/tegra_soctherm_fuse.c
new file mode 100644
index 000000000000..7c608698f1ae
--- /dev/null
+++ b/drivers/thermal/tegra/tegra_soctherm_fuse.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <soc/tegra/fuse.h>
+
+#include "tegra_soctherm.h"
+
+#define NOMINAL_CALIB_FT 105
+#define NOMINAL_CALIB_CP 25
+
+#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
+#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
+#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
+
+#define FUSE_TSENSOR_COMMON 0x180
+
+/*
+ * T12x, etc: FUSE_TSENSOR_COMMON:
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |-----------| SHFT_FT | BASE_FT | BASE_CP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * FUSE_SPARE_REALIGNMENT_REG:
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |---------------------------------------------------| SHIFT_CP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static s64 div64_s64_precise(s64 a, s64 b)
+{
+ s64 r, al;
+
+ /* Scale up for increased precision division */
+ al = a << 16;
+
+ r = div64_s64(al * 2 + 1, 2 * b);
+ return r >> 16;
+}
+
+int tegra_soctherm_calculate_shared_calibration(
+ const struct tegra_soctherm_fuse *tfuse,
+ struct tsensor_shared_calibration *r)
+{
+ u32 val;
+ s32 shifted_cp, shifted_ft;
+ int err;
+
+ err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val);
+ if (err)
+ return err;
+
+ r->base_cp = (val & tfuse->fuse_base_cp_mask)
+ >> tfuse->fuse_base_cp_shift;
+ r->base_ft = (val & tfuse->fuse_base_ft_mask)
+ >> tfuse->fuse_base_ft_shift;
+
+ shifted_ft = (val & tfuse->fuse_shift_ft_mask)
+ >> tfuse->fuse_shift_ft_shift;
+ shifted_ft = sign_extend32(shifted_ft, 4);
+
+ if (tfuse->fuse_spare_realignment) {
+ err = tegra_fuse_readl(tfuse->fuse_spare_realignment, &val);
+ if (err)
+ return err;
+ }
+
+ shifted_cp = sign_extend32(val, 5);
+
+ r->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp;
+ r->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft;
+
+ return 0;
+}
+
+int tegra_soctherm_calculate_tsensor_calibration(
+ struct tegra_tsensor *sensor,
+ const struct tsensor_shared_calibration *shared)
+{
+ const struct tegra_tsensor_group *sensor_group;
+ u32 val, calib;
+ s32 actual_tsensor_ft, actual_tsensor_cp;
+ s32 delta_sens, delta_temp;
+ s32 mult, div;
+ s16 therma, thermb;
+ int err;
+
+ sensor_group = sensor->group;
+
+ err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
+ if (err)
+ return err;
+
+ actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
+ val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK)
+ >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
+ actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
+
+ delta_sens = actual_tsensor_ft - actual_tsensor_cp;
+ delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
+
+ mult = sensor_group->pdiv * sensor->config->tsample_ate;
+ div = sensor->config->tsample * sensor_group->pdiv_ate;
+
+ therma = div64_s64_precise((s64)delta_temp * (1LL << 13) * mult,
+ (s64)delta_sens * div);
+ thermb = div64_s64_precise(
+ ((s64)actual_tsensor_ft * shared->actual_temp_cp) -
+ ((s64)actual_tsensor_cp * shared->actual_temp_ft),
+ (s64)delta_sens);
+
+ therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha,
+ (s64)1000000LL);
+ thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha +
+ sensor->fuse_corr_beta,
+ (s64)1000000LL);
+ calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
+ ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
+
+ sensor->calib = calib;
+
+ return 0;
+}
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("Tegra SOCTHERM fuse management");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH V1 04/10] thermal: tegra: add T210-specific SOC_THERM driver
2016-01-13 7:58 [PATCH V1 00/10] Add T210 support in tegra_soctherm Wei Ni
` (2 preceding siblings ...)
2016-01-13 7:58 ` [PATCH V1 03/10] thermal: tegra: split tegra_soctherm driver Wei Ni
@ 2016-01-13 7:58 ` Wei Ni
[not found] ` <1452671929-32740-5-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
3 siblings, 1 reply; 13+ messages in thread
From: Wei Ni @ 2016-01-13 7:58 UTC (permalink / raw)
To: rui.zhang, mikko.perttunen, swarren; +Cc: linux-tegra, linux-kernel, Wei Ni
Add Tegra210 specific SOC_THERM driver.
Signed-off-by: Wei Ni <wni@nvidia.com>
---
drivers/thermal/tegra/Kconfig | 11 ++
drivers/thermal/tegra/Makefile | 1 +
drivers/thermal/tegra/tegra210_soctherm.c | 210 ++++++++++++++++++++++++++++
drivers/thermal/tegra/tegra_soctherm_fuse.c | 11 ++
4 files changed, 233 insertions(+)
create mode 100644 drivers/thermal/tegra/tegra210_soctherm.c
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
index ae7e5e93dab9..902ef8bdbc91 100644
--- a/drivers/thermal/tegra/Kconfig
+++ b/drivers/thermal/tegra/Kconfig
@@ -11,3 +11,14 @@ config TEGRA124_SOCTHERM
(CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal
zones to manage temperatures. This option is also required for the
emergency thermal reset (thermtrip) feature to function.
+
+config TEGRA210_SOCTHERM
+ bool "Tegra210 SOCTHERM thermal management"
+ depends on ARCH_TEGRA_210_SOC
+ select TEGRA_SOCTHERM
+ help
+ Enable this option for integrated thermal management support on NVIDIA
+ Tegra210 systems-on-chip. The driver supports four thermal zones
+ (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal
+ zones to manage temperatures. This option is also required for the
+ emergency thermal reset (thermtrip) feature to function.
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index 7a864ec07a25..272dd84c7995 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -5,3 +5,4 @@
# Tegra soc thermal drivers
obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o tegra_soctherm_fuse.o
obj-$(CONFIG_TEGRA124_SOCTHERM) += tegra124_soctherm.o
+obj-$(CONFIG_TEGRA210_SOCTHERM) += tegra210_soctherm.o
diff --git a/drivers/thermal/tegra/tegra210_soctherm.c b/drivers/thermal/tegra/tegra210_soctherm.c
new file mode 100644
index 000000000000..70c748c6bed6
--- /dev/null
+++ b/drivers/thermal/tegra/tegra210_soctherm.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <soc/tegra/fuse.h>
+
+#include <dt-bindings/thermal/tegra124-soctherm.h>
+
+#include "tegra_soctherm.h"
+
+static const struct tegra_tsensor_configuration tegra210_tsensor_config = {
+ .tall = 16300,
+ .tiddq_en = 1,
+ .ten_count = 1,
+ .tsample = 120,
+ .tsample_ate = 480,
+};
+
+static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_CPU,
+ .name = "cpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_CPU_MASK,
+ .pllx_hotspot_diff = 10,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
+};
+
+static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
+ .id = TEGRA124_SOCTHERM_SENSOR_GPU,
+ .name = "gpu",
+ .sensor_temp_offset = SENSOR_TEMP1,
+ .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_GPU_MASK,
+ .pllx_hotspot_diff = 5,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
+};
+
+static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
+ .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
+ .name = "pll",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_PLLX_MASK,
+};
+
+static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
+ .id = TEGRA124_SOCTHERM_SENSOR_MEM,
+ .name = "mem",
+ .sensor_temp_offset = SENSOR_TEMP2,
+ .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
+ .pdiv = 8,
+ .pdiv_ate = 8,
+ .pdiv_mask = SENSOR_PDIV_MEM_MASK,
+ .pllx_hotspot_diff = 0,
+ .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
+};
+
+static const struct tegra_tsensor_group *
+tegra210_tsensor_groups[TEGRA124_SOCTHERM_SENSOR_NUM] = {
+ &tegra210_tsensor_group_cpu,
+ &tegra210_tsensor_group_gpu,
+ &tegra210_tsensor_group_pll,
+ &tegra210_tsensor_group_mem,
+};
+
+static struct tegra_tsensor tegra210_tsensors[] = {
+ {
+ .name = "cpu0",
+ .base = 0xc0,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x098,
+ .fuse_corr_alpha = 1085000,
+ .fuse_corr_beta = 3244200,
+ .group = &tegra210_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu1",
+ .base = 0xe0,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x084,
+ .fuse_corr_alpha = 1126200,
+ .fuse_corr_beta = -67500,
+ .group = &tegra210_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu2",
+ .base = 0x100,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x088,
+ .fuse_corr_alpha = 1098400,
+ .fuse_corr_beta = 2251100,
+ .group = &tegra210_tsensor_group_cpu,
+ },
+ {
+ .name = "cpu3",
+ .base = 0x120,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x12c,
+ .fuse_corr_alpha = 1108000,
+ .fuse_corr_beta = 602700,
+ .group = &tegra210_tsensor_group_cpu,
+ },
+ {
+ .name = "mem0",
+ .base = 0x140,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x158,
+ .fuse_corr_alpha = 1069200,
+ .fuse_corr_beta = 3549900,
+ .group = &tegra210_tsensor_group_mem,
+ },
+ {
+ .name = "mem1",
+ .base = 0x160,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x15c,
+ .fuse_corr_alpha = 1173700,
+ .fuse_corr_beta = -6263600,
+ .group = &tegra210_tsensor_group_mem,
+ },
+ {
+ .name = "gpu",
+ .base = 0x180,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x154,
+ .fuse_corr_alpha = 1074300,
+ .fuse_corr_beta = 2734900,
+ .group = &tegra210_tsensor_group_gpu,
+ },
+ {
+ .name = "pllx",
+ .base = 0x1a0,
+ .config = &tegra210_tsensor_config,
+ .calib_fuse_offset = 0x160,
+ .fuse_corr_alpha = 1039700,
+ .fuse_corr_beta = 6829100,
+ .group = &tegra210_tsensor_group_pll,
+ },
+ { .name = NULL },
+};
+
+/*
+ * Mask/shift bits in FUSE_TSENSOR_COMMON and
+ * FUSE_TSENSOR_COMMON, which are described in
+ * tegra_soctherm_fuse.c
+ */
+static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = {
+ .fuse_base_cp_mask = 0x3ff << 11,
+ .fuse_base_cp_shift = 11,
+ .fuse_base_ft_mask = 0x7ff << 21,
+ .fuse_base_ft_shift = 21,
+ .fuse_shift_ft_mask = 0x1f << 6,
+ .fuse_shift_ft_shift = 6,
+ .fuse_spare_realignment = 0,
+};
+
+static const struct of_device_id tegra210_soctherm_of_match[] = {
+ { .compatible = "nvidia,tegra210-soctherm" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
+
+#define TEGRA210_FUSE_CP_REV 0x90
+
+static int tegra210_soctherm_probe(struct platform_device *pdev)
+{
+ u32 rev;
+
+ tegra_fuse_readl(TEGRA210_FUSE_CP_REV, &rev);
+ pr_debug("tsosc: CP rev %d.%d\n", (rev & 0x1f), ((rev >> 5) & 0x3f));
+
+ return tegra_soctherm_probe(pdev,
+ tegra210_tsensors,
+ tegra210_tsensor_groups,
+ &tegra210_soctherm_fuse);
+}
+
+static struct platform_driver tegra210_soctherm_driver = {
+ .probe = tegra210_soctherm_probe,
+ .remove = tegra_soctherm_remove,
+ .driver = {
+ .name = "tegra210_soctherm",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra210_soctherm_of_match,
+ },
+};
+module_platform_driver(tegra210_soctherm_driver);
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("Tegra210 SOCTHERM thermal management driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/tegra/tegra_soctherm_fuse.c b/drivers/thermal/tegra/tegra_soctherm_fuse.c
index 7c608698f1ae..22f402240672 100644
--- a/drivers/thermal/tegra/tegra_soctherm_fuse.c
+++ b/drivers/thermal/tegra/tegra_soctherm_fuse.c
@@ -28,6 +28,17 @@
#define FUSE_TSENSOR_COMMON 0x180
/*
+ * T210: Layout of bits in FUSE_TSENSOR_COMMON:
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | BASE_FT | BASE_CP | SHFT_FT | SHIFT_CP |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * In chips prior to T210, this fuse was incorrectly sized as 26 bits,
+ * and didn't hold SHIFT_CP in [31:26]. Therefore these missing six bits
+ * were obtained via the FUSE_SPARE_REALIGNMENT_REG register [5:0].
+ *
* T12x, etc: FUSE_TSENSOR_COMMON:
* 3 2 1 0
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
--
1.9.1
^ permalink raw reply related [flat|nested] 13+ messages in thread