Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c31c24b8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull thermal management update from Zhang Rui:
 "Specifics:

   - fix a bug in Exynos thermal driver, which overwrites the hardware
     trip point threshold when updating software trigger levels and
     results in emergency shutdown.  From: Tushar Behera.

   - add thermal sensor support for Armada 375 and 38x SoCs.  From
     Ezequiel Garcia.

   - add TMU (Thermal Management Unit) support for Exynos5260 and
     Exynos5420 SoCs.  From Naveen Krishna Chatradhi.

   - add support for the additional digital temperature sensors in the
     Intel SoCs like Bay Trail.  From: Srinivas Pandruvada.

   - a couple of cleanups and small fixes from Jingoo Han, Bartlomiej
     Zolnierkiewicz, Geert Uytterhoeven, Jacob Pan, Paul Walmsley and
     Lan,Tianyu"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (21 commits)
  thermal: spear: remove unnecessary OOM messages
  thermal: exynos: remove unnecessary OOM messages
  thermal: rcar: remove unnecessary OOM messages
  thermal: armada: Support Armada 380 SoC
  thermal: armada: Support Armada 375 SoC
  thermal: armada: Allow to specify an 'inverted readout' sensor
  thermal: armada: Pass the platform_device to init_sensor()
  thermal: armada: Add generic infrastructure to handle the sensor
  thermal: armada: Add infrastructure to support generic formulas
  thermal: armada: Rename armada_thermal_ops struct
  thermal/intel_powerclamp: add newer cpu ids
  thermal: rcar: Use pm_runtime_put() i.s.o. pm_runtime_put_sync()
  thermal: samsung: Only update available threshold limits
  Thermal/int3403: Fix thermal hysteresis unit conversion
  thermal: Intel SoC DTS thermal
  thermal: samsung: Add TMU support for Exynos5260 SoCs
  thermal: samsung: Add TMU support for Exynos5420 SoCs
  thermal: samsung: change base_common to more meaningful base_second
  thermal: samsung: replace inten_ bit fields with intclr_
  thermal: offer Samsung thermal support only when ARCH_EXYNOS is defined
  ...
parents 7f33e724 63745aa7
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
* Marvell Armada 370/XP thermal management
* Marvell Armada 370/375/380/XP thermal management

Required properties:

- compatible:	Should be set to one of the following:
		marvell,armada370-thermal
		marvell,armada375-thermal
		marvell,armada375-z1-thermal
		marvell,armada380-thermal
		marvell,armadaxp-thermal

		Note: As the name suggests, "marvell,armada375-z1-thermal"
		applies for the SoC Z1 stepping only. On such stepping
		some quirks need to be done and the register offset differs
		from the one in the A0 stepping.
		The operating system may auto-detect the SoC stepping and
		update the compatible and register offsets at runtime.

- reg:		Device's register space.
		Two entries are expected, see the examples below.
		The first one is required for the sensor register;
+47 −3
Original line number Diff line number Diff line
@@ -6,16 +6,35 @@
	       "samsung,exynos4412-tmu"
	       "samsung,exynos4210-tmu"
	       "samsung,exynos5250-tmu"
	       "samsung,exynos5260-tmu"
	       "samsung,exynos5420-tmu" for TMU channel 0, 1 on Exynos5420
	       "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
			Exynos5420 (Must pass triminfo base and triminfo clock)
	       "samsung,exynos5440-tmu"
- interrupt-parent : The phandle for the interrupt controller
- reg : Address range of the thermal registers. For soc's which has multiple
	instances of TMU and some registers are shared across all TMU's like
	interrupt related then 2 set of register has to supplied. First set
	belongs	to each instance of TMU and second set belongs to common TMU
	registers.
	belongs	to register set of TMU instance and second set belongs to
	registers shared with the TMU instance.

  NOTE: On Exynos5420, the TRIMINFO register is misplaced for TMU
	channels 2, 3 and 4
	Use "samsung,exynos5420-tmu-ext-triminfo" in cases, there is a misplaced
	register, also provide clock to access that base.

	TRIMINFO at 0x1006c000 contains data for TMU channel 3
	TRIMINFO at 0x100a0000 contains data for TMU channel 4
	TRIMINFO at 0x10068000 contains data for TMU channel 2

- interrupts : Should contain interrupt for thermal system
- clocks : The main clock for TMU device
- clocks : The main clocks for TMU device
	-- 1. operational clock for TMU channel
	-- 2. optional clock to access the shared registers of TMU channel
- clock-names : Thermal system clock name
	-- "tmu_apbif" operational clock for current TMU channel
	-- "tmu_triminfo_apbif" clock to access the shared triminfo register
		for current TMU channel
- vtmu-supply: This entry is optional and provides the regulator node supplying
		voltage to TMU. If needed this entry can be placed inside
		board/platform specific dts file.
@@ -43,6 +62,31 @@ Example 2):
		clock-names = "tmu_apbif";
	};

Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register")
	tmu_cpu2: tmu@10068000 {
		compatible = "samsung,exynos5420-tmu-ext-triminfo";
		reg = <0x10068000 0x100>, <0x1006c000 0x4>;
		interrupts = <0 184 0>;
		clocks = <&clock 318>, <&clock 318>;
		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
	};

	tmu_cpu3: tmu@1006c000 {
		compatible = "samsung,exynos5420-tmu-ext-triminfo";
		reg = <0x1006c000 0x100>, <0x100a0000 0x4>;
		interrupts = <0 185 0>;
		clocks = <&clock 318>, <&clock 319>;
		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
	};

	tmu_gpu: tmu@100a0000 {
		compatible = "samsung,exynos5420-tmu-ext-triminfo";
		reg = <0x100a0000 0x100>, <0x10068000 0x4>;
		interrupts = <0 215 0>;
		clocks = <&clock 319>, <&clock 318>;
		clock-names = "tmu_apbif", "tmu_triminfo_apbif";
	};

Note: For multi-instance tmu each instance should have an alias correctly
numbered in "aliases" node.

+13 −1
Original line number Diff line number Diff line
@@ -222,12 +222,24 @@ config ACPI_INT3403_THERMAL
	  the Intel Thermal Daemon can use this information to allow the user
	  to select his laptop to run without turning on the fans.

config INTEL_SOC_DTS_THERMAL
	tristate "Intel SoCs DTS thermal driver"
	depends on X86 && IOSF_MBI
	help
	  Enable this to register Intel SoCs (e.g. Bay Trail) platform digital
	  temperature sensor (DTS). These SoCs have two additional DTSs in
	  addition to DTSs on CPU cores. Each DTS will be registered as a
	  thermal zone. There are two trip points. One of the trip point can
	  be set by user mode programs to get notifications via Linux thermal
	  notification methods.The other trip is a critical trip point, which
	  was set by the driver based on the TJ MAX temperature.

menu "Texas Instruments thermal drivers"
source "drivers/thermal/ti-soc-thermal/Kconfig"
endmenu

menu "Samsung thermal drivers"
depends on PLAT_SAMSUNG
depends on ARCH_EXYNOS
source "drivers/thermal/samsung/Kconfig"
endmenu

+1 −0
Original line number Diff line number Diff line
@@ -29,5 +29,6 @@ obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+= db8500_cpufreq_cooling.o
obj-$(CONFIG_INTEL_POWERCLAMP)	+= intel_powerclamp.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL)	+= x86_pkg_temp_thermal.o
obj-$(CONFIG_INTEL_SOC_DTS_THERMAL)	+= intel_soc_dts_thermal.o
obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
obj-$(CONFIG_ACPI_INT3403_THERMAL)	+= int3403_thermal.o
+139 −19
Original line number Diff line number Diff line
@@ -24,10 +24,7 @@
#include <linux/of_device.h>
#include <linux/thermal.h>

#define THERMAL_VALID_OFFSET		9
#define THERMAL_VALID_MASK		0x1
#define THERMAL_TEMP_OFFSET		10
#define THERMAL_TEMP_MASK		0x1ff

/* Thermal Manager Control and Status Register */
#define PMU_TDC0_SW_RST_MASK		(0x1 << 1)
@@ -38,24 +35,47 @@
#define PMU_TDC0_OTF_CAL_MASK		(0x1 << 30)
#define PMU_TDC0_START_CAL_MASK		(0x1 << 25)

struct armada_thermal_ops;
#define A375_Z1_CAL_RESET_LSB		0x8011e214
#define A375_Z1_CAL_RESET_MSB		0x30a88019
#define A375_Z1_WORKAROUND_BIT		BIT(9)

#define A375_UNIT_CONTROL_SHIFT		27
#define A375_UNIT_CONTROL_MASK		0x7
#define A375_READOUT_INVERT		BIT(15)
#define A375_HW_RESETn			BIT(8)
#define A380_HW_RESET			BIT(8)

struct armada_thermal_data;

/* Marvell EBU Thermal Sensor Dev Structure */
struct armada_thermal_priv {
	void __iomem *sensor;
	void __iomem *control;
	struct armada_thermal_ops *ops;
	struct armada_thermal_data *data;
};

struct armada_thermal_ops {
struct armada_thermal_data {
	/* Initialize the sensor */
	void (*init_sensor)(struct armada_thermal_priv *);
	void (*init_sensor)(struct platform_device *pdev,
			    struct armada_thermal_priv *);

	/* Test for a valid sensor value (optional) */
	bool (*is_valid)(struct armada_thermal_priv *);

	/* Formula coeficients: temp = (b + m * reg) / div */
	unsigned long coef_b;
	unsigned long coef_m;
	unsigned long coef_div;
	bool inverted;

	/* Register shift and mask to access the sensor temperature */
	unsigned int temp_shift;
	unsigned int temp_mask;
	unsigned int is_valid_shift;
};

static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
static void armadaxp_init_sensor(struct platform_device *pdev,
				 struct armada_thermal_priv *priv)
{
	unsigned long reg;

@@ -80,7 +100,8 @@ static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
	writel(reg, priv->sensor);
}

static void armada370_init_sensor(struct armada_thermal_priv *priv)
static void armada370_init_sensor(struct platform_device *pdev,
				  struct armada_thermal_priv *priv)
{
	unsigned long reg;

@@ -99,11 +120,54 @@ static void armada370_init_sensor(struct armada_thermal_priv *priv)
	mdelay(10);
}

static void armada375_init_sensor(struct platform_device *pdev,
				  struct armada_thermal_priv *priv)
{
	unsigned long reg;
	bool quirk_needed =
		!!of_device_is_compatible(pdev->dev.of_node,
					  "marvell,armada375-z1-thermal");

	if (quirk_needed) {
		/* Ensure these registers have the default (reset) values */
		writel(A375_Z1_CAL_RESET_LSB, priv->control);
		writel(A375_Z1_CAL_RESET_MSB, priv->control + 0x4);
	}

	reg = readl(priv->control + 4);
	reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT);
	reg &= ~A375_READOUT_INVERT;
	reg &= ~A375_HW_RESETn;

	if (quirk_needed)
		reg |= A375_Z1_WORKAROUND_BIT;

	writel(reg, priv->control + 4);
	mdelay(20);

	reg |= A375_HW_RESETn;
	writel(reg, priv->control + 4);
	mdelay(50);
}

static void armada380_init_sensor(struct platform_device *pdev,
				  struct armada_thermal_priv *priv)
{
	unsigned long reg = readl_relaxed(priv->control);

	/* Reset hardware once */
	if (!(reg & A380_HW_RESET)) {
		reg |= A380_HW_RESET;
		writel(reg, priv->control);
		mdelay(10);
	}
}

static bool armada_is_valid(struct armada_thermal_priv *priv)
{
	unsigned long reg = readl_relaxed(priv->sensor);

	return (reg >> THERMAL_VALID_OFFSET) & THERMAL_VALID_MASK;
	return (reg >> priv->data->is_valid_shift) & THERMAL_VALID_MASK;
}

static int armada_get_temp(struct thermal_zone_device *thermal,
@@ -111,17 +175,27 @@ static int armada_get_temp(struct thermal_zone_device *thermal,
{
	struct armada_thermal_priv *priv = thermal->devdata;
	unsigned long reg;
	unsigned long m, b, div;

	/* Valid check */
	if (priv->ops->is_valid && !priv->ops->is_valid(priv)) {
	if (priv->data->is_valid && !priv->data->is_valid(priv)) {
		dev_err(&thermal->device,
			"Temperature sensor reading not valid\n");
		return -EIO;
	}

	reg = readl_relaxed(priv->sensor);
	reg = (reg >> THERMAL_TEMP_OFFSET) & THERMAL_TEMP_MASK;
	*temp = (3153000000UL - (10000000UL*reg)) / 13825;
	reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask;

	/* Get formula coeficients */
	b = priv->data->coef_b;
	m = priv->data->coef_m;
	div = priv->data->coef_div;

	if (priv->data->inverted)
		*temp = ((m * reg) - b) / div;
	else
		*temp = (b - (m * reg)) / div;
	return 0;
}

@@ -129,23 +203,69 @@ static struct thermal_zone_device_ops ops = {
	.get_temp = armada_get_temp,
};

static const struct armada_thermal_ops armadaxp_ops = {
static const struct armada_thermal_data armadaxp_data = {
	.init_sensor = armadaxp_init_sensor,
	.temp_shift = 10,
	.temp_mask = 0x1ff,
	.coef_b = 3153000000UL,
	.coef_m = 10000000UL,
	.coef_div = 13825,
};

static const struct armada_thermal_ops armada370_ops = {
static const struct armada_thermal_data armada370_data = {
	.is_valid = armada_is_valid,
	.init_sensor = armada370_init_sensor,
	.is_valid_shift = 9,
	.temp_shift = 10,
	.temp_mask = 0x1ff,
	.coef_b = 3153000000UL,
	.coef_m = 10000000UL,
	.coef_div = 13825,
};

static const struct armada_thermal_data armada375_data = {
	.is_valid = armada_is_valid,
	.init_sensor = armada375_init_sensor,
	.is_valid_shift = 10,
	.temp_shift = 0,
	.temp_mask = 0x1ff,
	.coef_b = 3171900000UL,
	.coef_m = 10000000UL,
	.coef_div = 13616,
};

static const struct armada_thermal_data armada380_data = {
	.is_valid = armada_is_valid,
	.init_sensor = armada380_init_sensor,
	.is_valid_shift = 10,
	.temp_shift = 0,
	.temp_mask = 0x3ff,
	.coef_b = 1169498786UL,
	.coef_m = 2000000UL,
	.coef_div = 4289,
	.inverted = true,
};

static const struct of_device_id armada_thermal_id_table[] = {
	{
		.compatible = "marvell,armadaxp-thermal",
		.data       = &armadaxp_ops,
		.data       = &armadaxp_data,
	},
	{
		.compatible = "marvell,armada370-thermal",
		.data       = &armada370_ops,
		.data       = &armada370_data,
	},
	{
		.compatible = "marvell,armada375-thermal",
		.data       = &armada375_data,
	},
	{
		.compatible = "marvell,armada375-z1-thermal",
		.data       = &armada375_data,
	},
	{
		.compatible = "marvell,armada380-thermal",
		.data       = &armada380_data,
	},
	{
		/* sentinel */
@@ -178,8 +298,8 @@ static int armada_thermal_probe(struct platform_device *pdev)
	if (IS_ERR(priv->control))
		return PTR_ERR(priv->control);

	priv->ops = (struct armada_thermal_ops *)match->data;
	priv->ops->init_sensor(priv);
	priv->data = (struct armada_thermal_data *)match->data;
	priv->data->init_sensor(pdev, priv);

	thermal = thermal_zone_device_register("armada_thermal", 0, 0,
					       priv, &ops, NULL, 0, 0);
Loading