2017-06-16 11:29:39

by Mikko Perttunen

[permalink] [raw]
Subject: [PATCH 1/4] arm64: tegra: Add BPMP thermal sensor to Tegra186

This adds the thermal sensor device provided by the BPMP, and the
relevant thermal sensors to the Tegra186 device tree.

Signed-off-by: Mikko Perttunen <[email protected]>
---
arch/arm64/boot/dts/nvidia/tegra186.dtsi | 48 ++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 5e62e68ac053..5c19ea74da24 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -4,6 +4,7 @@
#include <dt-bindings/mailbox/tegra186-hsp.h>
#include <dt-bindings/power/tegra186-powergate.h>
#include <dt-bindings/reset/tegra186-reset.h>
+#include <dt-bindings/thermal/tegra186-bpmp-thermal.h>

/ {
compatible = "nvidia,tegra186";
@@ -444,6 +445,53 @@
#size-cells = <0>;
status = "disabled";
};
+
+ bpmp_thermal: thermal {
+ compatible = "nvidia,tegra186-bpmp-thermal";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ thermal-zones {
+ a57 {
+ polling-delay = <0>;
+ polling-delay-passive = <1000>;
+
+ thermal-sensors =
+ <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_CPU>;
+ };
+
+ denver {
+ polling-delay = <0>;
+ polling-delay-passive = <1000>;
+
+ thermal-sensors =
+ <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AUX>;
+ };
+
+ gpu {
+ polling-delay = <0>;
+ polling-delay-passive = <1000>;
+
+ thermal-sensors =
+ <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_GPU>;
+ };
+
+ pll {
+ polling-delay = <0>;
+ polling-delay-passive = <1000>;
+
+ thermal-sensors =
+ <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_PLLX>;
+ };
+
+ always_on {
+ polling-delay = <0>;
+ polling-delay-passive = <1000>;
+
+ thermal-sensors =
+ <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AO>;
+ };
};

timer {
--
2.13.1


2017-06-16 11:29:41

by Mikko Perttunen

[permalink] [raw]
Subject: [PATCH 3/4] firmware: tegra: Expose tegra_bpmp_mrq_return

Expose and export the tegra_bpmp_mrq_return function for use of drivers
outside the core BPMP driver. This function is used to reply to
messages originating from the BPMP, which is required in the thermal
driver.

Signed-off-by: Mikko Perttunen <[email protected]>
---
drivers/firmware/tegra/bpmp.c | 5 +++--
include/soc/tegra/bpmp.h | 2 ++
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 84e4c9a58a0c..72ffccd891f4 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -379,8 +379,8 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
return NULL;
}

-static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel,
- int code, const void *data, size_t size)
+void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
+ const void *data, size_t size)
{
unsigned long flags = channel->ib->flags;
struct tegra_bpmp *bpmp = channel->bpmp;
@@ -418,6 +418,7 @@ static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel,
mbox_client_txdone(bpmp->mbox.channel, 0);
}
}
+EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_return);

static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp,
unsigned int mrq,
diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h
index 13dcd44e91bb..179a3a0f4963 100644
--- a/include/soc/tegra/bpmp.h
+++ b/include/soc/tegra/bpmp.h
@@ -114,6 +114,8 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg);
int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg);
+void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
+ const void *data, size_t size);

int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq,
tegra_bpmp_mrq_handler_t handler, void *data);
--
2.13.1

2017-06-16 11:29:38

by Mikko Perttunen

[permalink] [raw]
Subject: [PATCH 2/4] dt-bindings: Add bindings for nvidia,tegra186-bpmp-thermal

In Tegra186, the BPMP (Boot and Power Management Processor) implements
an interface that is used to read system temperatures, including CPU
cluster and GPU temperatures. This binding describes the thermal sensor
that is exposed by BPMP.

Signed-off-by: Mikko Perttunen <[email protected]>
---
.../thermal/nvidia,tegra186-bpmp-thermal.txt | 32 ++++++++++++++++++++++
.../dt-bindings/thermal/tegra186-bpmp-thermal.h | 14 ++++++++++
2 files changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt
create mode 100644 include/dt-bindings/thermal/tegra186-bpmp-thermal.h

diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt
new file mode 100644
index 000000000000..276387dd6815
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt
@@ -0,0 +1,32 @@
+NVIDIA Tegra186 BPMP thermal sensor
+
+In Tegra186, the BPMP (Boot and Power Management Processor) implements an
+interface that is used to read system temperatures, including CPU cluster
+and GPU temperatures. This binding describes the thermal sensor that is
+exposed by BPMP.
+
+The BPMP thermal node must be located directly inside the main BPMP node. See
+../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding.
+
+This node represents a thermal sensor. See thermal.txt for details of the
+core thermal binding.
+
+Required properties:
+- compatible:
+ Array of strings.
+ One of:
+ - "nvidia,tegra186-bpmp-thermal".
+- #thermal-sensor-cells: Cell for sensor index.
+ Single-cell integer.
+ Must be <1>.
+
+Example:
+
+bpmp {
+ ...
+
+ bpmp_thermal: thermal {
+ compatible = "nvidia,tegra186-bpmp-thermal";
+ #thermal-sensor-cells = <1>;
+ };
+};
diff --git a/include/dt-bindings/thermal/tegra186-bpmp-thermal.h b/include/dt-bindings/thermal/tegra186-bpmp-thermal.h
new file mode 100644
index 000000000000..a96b8fa31aab
--- /dev/null
+++ b/include/dt-bindings/thermal/tegra186-bpmp-thermal.h
@@ -0,0 +1,14 @@
+/*
+ * This header provides constants for binding nvidia,tegra186-bpmp-thermal.
+ */
+
+#ifndef _DT_BINDINGS_THERMAL_TEGRA186_BPMP_THERMAL_H
+#define _DT_BINDINGS_THERMAL_TEGRA186_BPMP_THERMAL_H
+
+#define TEGRA186_BPMP_THERMAL_ZONE_CPU 2
+#define TEGRA186_BPMP_THERMAL_ZONE_GPU 3
+#define TEGRA186_BPMP_THERMAL_ZONE_AUX 4
+#define TEGRA186_BPMP_THERMAL_ZONE_PLLX 5
+#define TEGRA186_BPMP_THERMAL_ZONE_AO 6
+
+#endif
--
2.13.1

2017-06-16 11:30:27

by Mikko Perttunen

[permalink] [raw]
Subject: [PATCH 4/4] thermal: Add Tegra BPMP thermal sensor driver

On Tegra186, the BPMP (Boot and Power Management Processor) exposes an
interface to thermal sensors on the system-on-chip. This driver
implements access to the interface. It supports reading the
temperature, setting trip points and receiving notification of a
tripped trip point.

Signed-off-by: Mikko Perttunen <[email protected]>
---
drivers/thermal/Makefile | 2 +-
drivers/thermal/tegra/Kconfig | 7 +
drivers/thermal/tegra/Makefile | 3 +-
drivers/thermal/tegra/bpmp-thermal.c | 253 +++++++++++++++++++++++++++++++++++
4 files changed, 263 insertions(+), 2 deletions(-)
create mode 100644 drivers/thermal/tegra/bpmp-thermal.c

diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 094d7039981c..c03dccdba7b8 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -54,7 +54,7 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
obj-$(CONFIG_ST_THERMAL) += st/
obj-$(CONFIG_QCOM_TSENS) += qcom/
-obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
+obj-y += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
index cec586ec7e4b..36e4b03bb98b 100644
--- a/drivers/thermal/tegra/Kconfig
+++ b/drivers/thermal/tegra/Kconfig
@@ -10,4 +10,11 @@ config TEGRA_SOCTHERM
zones to manage temperatures. This option is also required for the
emergency thermal reset (thermtrip) feature to function.

+config TEGRA_BPMP_THERMAL
+ tristate "Tegra BPMP thermal sensing"
+ depends on TEGRA_BPMP
+ help
+ Enable this option for support for sensing system temperature of NVIDIA
+ Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
+
endmenu
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index 1ce1af2cf0f5..757abcd1feaf 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -1,4 +1,5 @@
-obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
+obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
+obj-$(CONFIG_TEGRA_BPMP_THERMAL) += bpmp-thermal.o

tegra-soctherm-y := soctherm.o soctherm-fuse.o
tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
diff --git a/drivers/thermal/tegra/bpmp-thermal.c b/drivers/thermal/tegra/bpmp-thermal.c
new file mode 100644
index 000000000000..3465a201d1ac
--- /dev/null
+++ b/drivers/thermal/tegra/bpmp-thermal.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author:
+ * Mikko Perttunen <[email protected]>
+ * Aapo Vienamo <[email protected]>
+ *
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/workqueue.h>
+
+#include <soc/tegra/bpmp.h>
+#include <soc/tegra/bpmp-abi.h>
+
+struct tegra_bpmp_thermal_zone {
+ struct tegra_bpmp_thermal *tegra;
+ struct thermal_zone_device *tzd;
+ struct work_struct tz_device_update_work;
+ unsigned int idx;
+};
+
+struct tegra_bpmp_thermal {
+ struct device *dev;
+ struct tegra_bpmp *bpmp;
+ unsigned int num_zones;
+ struct tegra_bpmp_thermal_zone *zones;
+};
+
+static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp)
+{
+ struct tegra_bpmp_thermal_zone *zone = data;
+ struct mrq_thermal_host_to_bpmp_request req;
+ union mrq_thermal_bpmp_to_host_response reply;
+ struct tegra_bpmp_message msg;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+ req.type = CMD_THERMAL_GET_TEMP;
+ req.get_temp.zone = zone->idx;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_THERMAL;
+ msg.tx.data = &req;
+ msg.tx.size = sizeof(req);
+ msg.rx.data = &reply;
+ msg.rx.size = sizeof(reply);
+
+ err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
+ if (err)
+ return err;
+
+ *out_temp = reply.get_temp.temp;
+
+ return 0;
+}
+
+static int tegra_bpmp_thermal_set_trips(void *data, int low, int high)
+{
+ struct tegra_bpmp_thermal_zone *zone = data;
+ struct mrq_thermal_host_to_bpmp_request req;
+ struct tegra_bpmp_message msg;
+
+ memset(&req, 0, sizeof(req));
+ req.type = CMD_THERMAL_SET_TRIP;
+ req.set_trip.zone = zone->idx;
+ req.set_trip.enabled = true;
+ req.set_trip.low = low;
+ req.set_trip.high = high;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_THERMAL;
+ msg.tx.data = &req;
+ msg.tx.size = sizeof(req);
+
+ return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
+}
+
+static void tz_device_update_work_fn(struct work_struct *work)
+{
+ struct tegra_bpmp_thermal_zone *zone;
+
+ zone = container_of(work, struct tegra_bpmp_thermal_zone,
+ tz_device_update_work);
+
+ thermal_zone_device_update(zone->tzd, THERMAL_TRIP_VIOLATED);
+}
+
+static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
+ void *data)
+{
+ struct mrq_thermal_bpmp_to_host_request *req;
+ struct tegra_bpmp_thermal *tegra = data;
+ int zone_idx;
+
+ req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
+
+ if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
+ dev_err(tegra->dev, "%s: invalid request type: %d\n",
+ __func__, req->type);
+ tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
+ return;
+ }
+
+ zone_idx = req->host_trip_reached.zone;
+ if (zone_idx >= tegra->num_zones) {
+ dev_err(tegra->dev, "%s: invalid thermal zone: %d\n",
+ __func__, zone_idx);
+ tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
+ return;
+ }
+
+ tegra_bpmp_mrq_return(ch, 0, NULL, 0);
+
+ schedule_work(&tegra->zones[zone_idx].tz_device_update_work);
+}
+
+static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
+ int *num_zones)
+{
+ struct mrq_thermal_host_to_bpmp_request req;
+ union mrq_thermal_bpmp_to_host_response reply;
+ struct tegra_bpmp_message msg;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+ req.type = CMD_THERMAL_GET_NUM_ZONES;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_THERMAL;
+ msg.tx.data = &req;
+ msg.tx.size = sizeof(req);
+ msg.rx.data = &reply;
+ msg.rx.size = sizeof(reply);
+
+ err = tegra_bpmp_transfer(bpmp, &msg);
+ if (err)
+ return err;
+
+ *num_zones = reply.get_num_zones.num;
+
+ return 0;
+}
+
+static const struct thermal_zone_of_device_ops tegra_bpmp_of_thermal_ops = {
+ .get_temp = tegra_bpmp_thermal_get_temp,
+ .set_trips = tegra_bpmp_thermal_set_trips,
+};
+
+static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
+{
+ struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
+ struct tegra_bpmp_thermal *tegra;
+ struct thermal_zone_device *tzd;
+ unsigned int i;
+ int err;
+
+ tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+ if (!tegra)
+ return -ENOMEM;
+
+ tegra->dev = &pdev->dev;
+ tegra->bpmp = bpmp;
+
+ err = tegra_bpmp_thermal_get_num_zones(bpmp, &tegra->num_zones);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get the number of zones: %d\n",
+ err);
+ return err;
+ }
+
+ tegra->zones = devm_kcalloc(&pdev->dev, tegra->num_zones,
+ sizeof(*tegra->zones), GFP_KERNEL);
+ if (!tegra->zones)
+ return -ENOMEM;
+
+ for (i = 0; i < tegra->num_zones; ++i) {
+ int temp;
+
+ tegra->zones[i].idx = i;
+ tegra->zones[i].tegra = tegra;
+
+ err = tegra_bpmp_thermal_get_temp(&tegra->zones[i], &temp);
+ if (err < 0)
+ continue;
+
+ tzd = devm_thermal_zone_of_sensor_register(
+ &pdev->dev, i, &tegra->zones[i],
+ &tegra_bpmp_of_thermal_ops);
+ if (IS_ERR(tzd)) {
+ if (PTR_ERR(tzd) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ continue;
+ }
+
+ tegra->zones[i].tzd = tzd;
+ INIT_WORK(&tegra->zones[i].tz_device_update_work,
+ tz_device_update_work_fn);
+ }
+
+ err = tegra_bpmp_request_mrq(bpmp, MRQ_THERMAL, bpmp_mrq_thermal,
+ tegra);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register mrq handler: %d\n",
+ err);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, tegra);
+
+ return 0;
+}
+
+static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
+{
+ struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
+
+ tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
+ { .compatible = "nvidia,tegra186-bpmp-thermal" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
+
+static struct platform_driver tegra_bpmp_thermal_driver = {
+ .probe = tegra_bpmp_thermal_probe,
+ .remove = tegra_bpmp_thermal_remove,
+ .driver = {
+ .name = "tegra-bpmp-thermal",
+ .of_match_table = tegra_bpmp_thermal_of_match,
+ },
+};
+module_platform_driver(tegra_bpmp_thermal_driver);
+
+MODULE_AUTHOR("Mikko Perttunen <[email protected]>");
+MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
+MODULE_LICENSE("GPL v2");
--
2.13.1

2017-06-23 18:48:47

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 2/4] dt-bindings: Add bindings for nvidia,tegra186-bpmp-thermal

On Fri, Jun 16, 2017 at 02:28:23PM +0300, Mikko Perttunen wrote:
> In Tegra186, the BPMP (Boot and Power Management Processor) implements
> an interface that is used to read system temperatures, including CPU
> cluster and GPU temperatures. This binding describes the thermal sensor
> that is exposed by BPMP.
>
> Signed-off-by: Mikko Perttunen <[email protected]>
> ---
> .../thermal/nvidia,tegra186-bpmp-thermal.txt | 32 ++++++++++++++++++++++
> .../dt-bindings/thermal/tegra186-bpmp-thermal.h | 14 ++++++++++
> 2 files changed, 46 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt
> create mode 100644 include/dt-bindings/thermal/tegra186-bpmp-thermal.h

Acked-by: Rob Herring <[email protected]>

2017-06-30 23:56:12

by Eduardo Valentin

[permalink] [raw]
Subject: Re: [PATCH 1/4] arm64: tegra: Add BPMP thermal sensor to Tegra186

On Fri, Jun 16, 2017 at 02:28:22PM +0300, Mikko Perttunen wrote:
> This adds the thermal sensor device provided by the BPMP, and the
> relevant thermal sensors to the Tegra186 device tree.
>
> Signed-off-by: Mikko Perttunen <[email protected]>
> ---
> arch/arm64/boot/dts/nvidia/tegra186.dtsi | 48 ++++++++++++++++++++++++++++++++
> 1 file changed, 48 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
> index 5e62e68ac053..5c19ea74da24 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
> @@ -4,6 +4,7 @@
> #include <dt-bindings/mailbox/tegra186-hsp.h>
> #include <dt-bindings/power/tegra186-powergate.h>
> #include <dt-bindings/reset/tegra186-reset.h>
> +#include <dt-bindings/thermal/tegra186-bpmp-thermal.h>
>
> / {
> compatible = "nvidia,tegra186";
> @@ -444,6 +445,53 @@
> #size-cells = <0>;
> status = "disabled";
> };
> +
> + bpmp_thermal: thermal {
> + compatible = "nvidia,tegra186-bpmp-thermal";
> + #thermal-sensor-cells = <1>;
> + };
> + };
> +
> + thermal-zones {
> + a57 {
> + polling-delay = <0>;
> + polling-delay-passive = <1000>;
> +
> + thermal-sensors =
> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_CPU>;
> + };
> +
> + denver {
> + polling-delay = <0>;
> + polling-delay-passive = <1000>;
> +
> + thermal-sensors =
> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AUX>;
> + };
> +
> + gpu {
> + polling-delay = <0>;
> + polling-delay-passive = <1000>;
> +
> + thermal-sensors =
> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_GPU>;
> + };
> +
> + pll {
> + polling-delay = <0>;
> + polling-delay-passive = <1000>;
> +
> + thermal-sensors =
> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_PLLX>;
> + };
> +
> + always_on {
> + polling-delay = <0>;
> + polling-delay-passive = <1000>;
> +
> + thermal-sensors =
> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AO>;
> + };

All the above zones are lacking mandatory fields. Please refer to the
thermal binding documentation.

> };
>
> timer {
> --
> 2.13.1
>

2017-07-01 02:53:34

by Eduardo Valentin

[permalink] [raw]
Subject: Re: [PATCH 4/4] thermal: Add Tegra BPMP thermal sensor driver

Hey Mikko,

Sorry for the late answer,

On Fri, Jun 16, 2017 at 02:28:25PM +0300, Mikko Perttunen wrote:
> On Tegra186, the BPMP (Boot and Power Management Processor) exposes an
> interface to thermal sensors on the system-on-chip. This driver
> implements access to the interface. It supports reading the
> temperature, setting trip points and receiving notification of a
> tripped trip point.
>
> Signed-off-by: Mikko Perttunen <[email protected]>
> ---
> drivers/thermal/Makefile | 2 +-
> drivers/thermal/tegra/Kconfig | 7 +
> drivers/thermal/tegra/Makefile | 3 +-
> drivers/thermal/tegra/bpmp-thermal.c | 253 +++++++++++++++++++++++++++++++++++
> 4 files changed, 263 insertions(+), 2 deletions(-)
> create mode 100644 drivers/thermal/tegra/bpmp-thermal.c
>
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 094d7039981c..c03dccdba7b8 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -54,7 +54,7 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
> obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
> obj-$(CONFIG_ST_THERMAL) += st/
> obj-$(CONFIG_QCOM_TSENS) += qcom/
> -obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
> +obj-y += tegra/
> obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
> obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
> obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
> diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
> index cec586ec7e4b..36e4b03bb98b 100644
> --- a/drivers/thermal/tegra/Kconfig
> +++ b/drivers/thermal/tegra/Kconfig
> @@ -10,4 +10,11 @@ config TEGRA_SOCTHERM
> zones to manage temperatures. This option is also required for the
> emergency thermal reset (thermtrip) feature to function.
>
> +config TEGRA_BPMP_THERMAL
> + tristate "Tegra BPMP thermal sensing"
> + depends on TEGRA_BPMP

Can you add COMPILE_TEST support here?

> + help
> + Enable this option for support for sensing system temperature of NVIDIA
> + Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
> +
> endmenu
> diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
> index 1ce1af2cf0f5..757abcd1feaf 100644
> --- a/drivers/thermal/tegra/Makefile
> +++ b/drivers/thermal/tegra/Makefile
> @@ -1,4 +1,5 @@
> -obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
> +obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
> +obj-$(CONFIG_TEGRA_BPMP_THERMAL) += bpmp-thermal.o
>
> tegra-soctherm-y := soctherm.o soctherm-fuse.o
> tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
> diff --git a/drivers/thermal/tegra/bpmp-thermal.c b/drivers/thermal/tegra/bpmp-thermal.c
> new file mode 100644
> index 000000000000..3465a201d1ac
> --- /dev/null
> +++ b/drivers/thermal/tegra/bpmp-thermal.c
> @@ -0,0 +1,253 @@
> +/*
> + * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
> + *
> + * Author:
> + * Mikko Perttunen <[email protected]>
> + * Aapo Vienamo <[email protected]>
> + *
> + * 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/err.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/thermal.h>
> +#include <linux/workqueue.h>
> +
> +#include <soc/tegra/bpmp.h>
> +#include <soc/tegra/bpmp-abi.h>
> +
> +struct tegra_bpmp_thermal_zone {
> + struct tegra_bpmp_thermal *tegra;
> + struct thermal_zone_device *tzd;
> + struct work_struct tz_device_update_work;
> + unsigned int idx;
> +};
> +
> +struct tegra_bpmp_thermal {
> + struct device *dev;
> + struct tegra_bpmp *bpmp;
> + unsigned int num_zones;
> + struct tegra_bpmp_thermal_zone *zones;
> +};
> +
> +static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp)
> +{
> + struct tegra_bpmp_thermal_zone *zone = data;
> + struct mrq_thermal_host_to_bpmp_request req;
> + union mrq_thermal_bpmp_to_host_response reply;
> + struct tegra_bpmp_message msg;
> + int err;
> +
> + memset(&req, 0, sizeof(req));
> + req.type = CMD_THERMAL_GET_TEMP;
> + req.get_temp.zone = zone->idx;
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.mrq = MRQ_THERMAL;
> + msg.tx.data = &req;
> + msg.tx.size = sizeof(req);
> + msg.rx.data = &reply;
> + msg.rx.size = sizeof(reply);
> +
> + err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
> + if (err)
> + return err;
> +
> + *out_temp = reply.get_temp.temp;
> +
> + return 0;
> +}
> +
> +static int tegra_bpmp_thermal_set_trips(void *data, int low, int high)
> +{
> + struct tegra_bpmp_thermal_zone *zone = data;
> + struct mrq_thermal_host_to_bpmp_request req;
> + struct tegra_bpmp_message msg;
> +
> + memset(&req, 0, sizeof(req));
> + req.type = CMD_THERMAL_SET_TRIP;
> + req.set_trip.zone = zone->idx;
> + req.set_trip.enabled = true;
> + req.set_trip.low = low;
> + req.set_trip.high = high;
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.mrq = MRQ_THERMAL;
> + msg.tx.data = &req;
> + msg.tx.size = sizeof(req);
> +
> + return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
> +}
> +
> +static void tz_device_update_work_fn(struct work_struct *work)
> +{
> + struct tegra_bpmp_thermal_zone *zone;
> +
> + zone = container_of(work, struct tegra_bpmp_thermal_zone,
> + tz_device_update_work);
> +
> + thermal_zone_device_update(zone->tzd, THERMAL_TRIP_VIOLATED);
> +}
> +
> +static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
> + void *data)
> +{
> + struct mrq_thermal_bpmp_to_host_request *req;
> + struct tegra_bpmp_thermal *tegra = data;
> + int zone_idx;
> +
> + req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
> +
> + if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
> + dev_err(tegra->dev, "%s: invalid request type: %d\n",
> + __func__, req->type);
> + tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
> + return;
> + }
> +
> + zone_idx = req->host_trip_reached.zone;
> + if (zone_idx >= tegra->num_zones) {
> + dev_err(tegra->dev, "%s: invalid thermal zone: %d\n",
> + __func__, zone_idx);
> + tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
> + return;
> + }
> +
> + tegra_bpmp_mrq_return(ch, 0, NULL, 0);
> +
> + schedule_work(&tegra->zones[zone_idx].tz_device_update_work);

Why not a thermal update right here?

> +}
> +
> +static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
> + int *num_zones)
> +{
> + struct mrq_thermal_host_to_bpmp_request req;
> + union mrq_thermal_bpmp_to_host_response reply;
> + struct tegra_bpmp_message msg;
> + int err;
> +
> + memset(&req, 0, sizeof(req));
> + req.type = CMD_THERMAL_GET_NUM_ZONES;
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.mrq = MRQ_THERMAL;
> + msg.tx.data = &req;
> + msg.tx.size = sizeof(req);
> + msg.rx.data = &reply;
> + msg.rx.size = sizeof(reply);
> +
> + err = tegra_bpmp_transfer(bpmp, &msg);
> + if (err)
> + return err;
> +
> + *num_zones = reply.get_num_zones.num;
> +
> + return 0;
> +}
> +
> +static const struct thermal_zone_of_device_ops tegra_bpmp_of_thermal_ops = {
> + .get_temp = tegra_bpmp_thermal_get_temp,
> + .set_trips = tegra_bpmp_thermal_set_trips,
> +};
> +
> +static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
> +{
> + struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
> + struct tegra_bpmp_thermal *tegra;
> + struct thermal_zone_device *tzd;
> + unsigned int i;
> + int err;
> +
> + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
> + if (!tegra)
> + return -ENOMEM;
> +
> + tegra->dev = &pdev->dev;
> + tegra->bpmp = bpmp;
> +
> + err = tegra_bpmp_thermal_get_num_zones(bpmp, &tegra->num_zones);
> + if (err) {
> + dev_err(&pdev->dev, "failed to get the number of zones: %d\n",
> + err);
> + return err;
> + }
> +
> + tegra->zones = devm_kcalloc(&pdev->dev, tegra->num_zones,
> + sizeof(*tegra->zones), GFP_KERNEL);
> + if (!tegra->zones)
> + return -ENOMEM;
> +
> + for (i = 0; i < tegra->num_zones; ++i) {
> + int temp;
> +
> + tegra->zones[i].idx = i;
> + tegra->zones[i].tegra = tegra;
> +
> + err = tegra_bpmp_thermal_get_temp(&tegra->zones[i], &temp);
> + if (err < 0)
> + continue;

Should we release the memory allocated for zones that fail to retrieve
temperature here, given that you are not going to use it elsewhere.

> +
> + tzd = devm_thermal_zone_of_sensor_register(
> + &pdev->dev, i, &tegra->zones[i],
> + &tegra_bpmp_of_thermal_ops);
> + if (IS_ERR(tzd)) {
> + if (PTR_ERR(tzd) == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> + continue;

same here?

> + }
> +
> + tegra->zones[i].tzd = tzd;
> + INIT_WORK(&tegra->zones[i].tz_device_update_work,
> + tz_device_update_work_fn);
> + }
> +
> + err = tegra_bpmp_request_mrq(bpmp, MRQ_THERMAL, bpmp_mrq_thermal,
> + tegra);
> + if (err) {
> + dev_err(&pdev->dev, "failed to register mrq handler: %d\n",
> + err);
> + return err;
> + }
> +
> + platform_set_drvdata(pdev, tegra);
> +
> + return 0;
> +}
> +
> +static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
> +{
> + struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
> +
> + tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
> + { .compatible = "nvidia,tegra186-bpmp-thermal" },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
> +
> +static struct platform_driver tegra_bpmp_thermal_driver = {
> + .probe = tegra_bpmp_thermal_probe,
> + .remove = tegra_bpmp_thermal_remove,
> + .driver = {
> + .name = "tegra-bpmp-thermal",
> + .of_match_table = tegra_bpmp_thermal_of_match,
> + },
> +};
> +module_platform_driver(tegra_bpmp_thermal_driver);
> +
> +MODULE_AUTHOR("Mikko Perttunen <[email protected]>");
> +MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.13.1
>

2017-07-10 08:50:30

by Mikko Perttunen

[permalink] [raw]
Subject: Re: [PATCH 4/4] thermal: Add Tegra BPMP thermal sensor driver

On 01.07.2017 05:53, Eduardo Valentin wrote:
> Hey Mikko,
>
> Sorry for the late answer,

Likewise,

>
> On Fri, Jun 16, 2017 at 02:28:25PM +0300, Mikko Perttunen wrote:
>> On Tegra186, the BPMP (Boot and Power Management Processor) exposes an
>> interface to thermal sensors on the system-on-chip. This driver
>> implements access to the interface. It supports reading the
>> temperature, setting trip points and receiving notification of a
>> tripped trip point.
>>
>> Signed-off-by: Mikko Perttunen <[email protected]>
>> ---
>> drivers/thermal/Makefile | 2 +-
>> drivers/thermal/tegra/Kconfig | 7 +
>> drivers/thermal/tegra/Makefile | 3 +-
>> drivers/thermal/tegra/bpmp-thermal.c | 253 +++++++++++++++++++++++++++++++++++
>> 4 files changed, 263 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/thermal/tegra/bpmp-thermal.c
>>
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index 094d7039981c..c03dccdba7b8 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -54,7 +54,7 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
>> obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
>> obj-$(CONFIG_ST_THERMAL) += st/
>> obj-$(CONFIG_QCOM_TSENS) += qcom/
>> -obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
>> +obj-y += tegra/
>> obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
>> obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
>> obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
>> diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
>> index cec586ec7e4b..36e4b03bb98b 100644
>> --- a/drivers/thermal/tegra/Kconfig
>> +++ b/drivers/thermal/tegra/Kconfig
>> @@ -10,4 +10,11 @@ config TEGRA_SOCTHERM
>> zones to manage temperatures. This option is also required for the
>> emergency thermal reset (thermtrip) feature to function.
>>
>> +config TEGRA_BPMP_THERMAL
>> + tristate "Tegra BPMP thermal sensing"
>> + depends on TEGRA_BPMP
>
> Can you add COMPILE_TEST support here?

Sure.

>
>> + help
>> + Enable this option for support for sensing system temperature of NVIDIA
>> + Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
>> +
>> endmenu
>> diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
>> index 1ce1af2cf0f5..757abcd1feaf 100644
>> --- a/drivers/thermal/tegra/Makefile
>> +++ b/drivers/thermal/tegra/Makefile
>> @@ -1,4 +1,5 @@
>> -obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
>> +obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
>> +obj-$(CONFIG_TEGRA_BPMP_THERMAL) += bpmp-thermal.o
>>
>> tegra-soctherm-y := soctherm.o soctherm-fuse.o
>> tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
>> diff --git a/drivers/thermal/tegra/bpmp-thermal.c b/drivers/thermal/tegra/bpmp-thermal.c
>> new file mode 100644
>> index 000000000000..3465a201d1ac
>> --- /dev/null
>> +++ b/drivers/thermal/tegra/bpmp-thermal.c
>> @@ -0,0 +1,253 @@
>> +/*
>> + * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
>> + *
>> + * Author:
>> + * Mikko Perttunen <[email protected]>
>> + * Aapo Vienamo <[email protected]>
>> + *
>> + * 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/err.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/thermal.h>
>> +#include <linux/workqueue.h>
>> +
>> +#include <soc/tegra/bpmp.h>
>> +#include <soc/tegra/bpmp-abi.h>
>> +
>> +struct tegra_bpmp_thermal_zone {
>> + struct tegra_bpmp_thermal *tegra;
>> + struct thermal_zone_device *tzd;
>> + struct work_struct tz_device_update_work;
>> + unsigned int idx;
>> +};
>> +
>> +struct tegra_bpmp_thermal {
>> + struct device *dev;
>> + struct tegra_bpmp *bpmp;
>> + unsigned int num_zones;
>> + struct tegra_bpmp_thermal_zone *zones;
>> +};
>> +
>> +static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp)
>> +{
>> + struct tegra_bpmp_thermal_zone *zone = data;
>> + struct mrq_thermal_host_to_bpmp_request req;
>> + union mrq_thermal_bpmp_to_host_response reply;
>> + struct tegra_bpmp_message msg;
>> + int err;
>> +
>> + memset(&req, 0, sizeof(req));
>> + req.type = CMD_THERMAL_GET_TEMP;
>> + req.get_temp.zone = zone->idx;
>> +
>> + memset(&msg, 0, sizeof(msg));
>> + msg.mrq = MRQ_THERMAL;
>> + msg.tx.data = &req;
>> + msg.tx.size = sizeof(req);
>> + msg.rx.data = &reply;
>> + msg.rx.size = sizeof(reply);
>> +
>> + err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
>> + if (err)
>> + return err;
>> +
>> + *out_temp = reply.get_temp.temp;
>> +
>> + return 0;
>> +}
>> +
>> +static int tegra_bpmp_thermal_set_trips(void *data, int low, int high)
>> +{
>> + struct tegra_bpmp_thermal_zone *zone = data;
>> + struct mrq_thermal_host_to_bpmp_request req;
>> + struct tegra_bpmp_message msg;
>> +
>> + memset(&req, 0, sizeof(req));
>> + req.type = CMD_THERMAL_SET_TRIP;
>> + req.set_trip.zone = zone->idx;
>> + req.set_trip.enabled = true;
>> + req.set_trip.low = low;
>> + req.set_trip.high = high;
>> +
>> + memset(&msg, 0, sizeof(msg));
>> + msg.mrq = MRQ_THERMAL;
>> + msg.tx.data = &req;
>> + msg.tx.size = sizeof(req);
>> +
>> + return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
>> +}
>> +
>> +static void tz_device_update_work_fn(struct work_struct *work)
>> +{
>> + struct tegra_bpmp_thermal_zone *zone;
>> +
>> + zone = container_of(work, struct tegra_bpmp_thermal_zone,
>> + tz_device_update_work);
>> +
>> + thermal_zone_device_update(zone->tzd, THERMAL_TRIP_VIOLATED);
>> +}
>> +
>> +static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
>> + void *data)
>> +{
>> + struct mrq_thermal_bpmp_to_host_request *req;
>> + struct tegra_bpmp_thermal *tegra = data;
>> + int zone_idx;
>> +
>> + req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
>> +
>> + if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
>> + dev_err(tegra->dev, "%s: invalid request type: %d\n",
>> + __func__, req->type);
>> + tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
>> + return;
>> + }
>> +
>> + zone_idx = req->host_trip_reached.zone;
>> + if (zone_idx >= tegra->num_zones) {
>> + dev_err(tegra->dev, "%s: invalid thermal zone: %d\n",
>> + __func__, zone_idx);
>> + tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
>> + return;
>> + }
>> +
>> + tegra_bpmp_mrq_return(ch, 0, NULL, 0);
>> +
>> + schedule_work(&tegra->zones[zone_idx].tz_device_update_work);
>
> Why not a thermal update right here?

The device update will call back to the .get_temp callback, which will
call tegra_bpmp_transfer - but this function may not be called from
atomic context. (bpmp_mrq_thermal is called from atomic context)

>
>> +}
>> +
>> +static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
>> + int *num_zones)
>> +{
>> + struct mrq_thermal_host_to_bpmp_request req;
>> + union mrq_thermal_bpmp_to_host_response reply;
>> + struct tegra_bpmp_message msg;
>> + int err;
>> +
>> + memset(&req, 0, sizeof(req));
>> + req.type = CMD_THERMAL_GET_NUM_ZONES;
>> +
>> + memset(&msg, 0, sizeof(msg));
>> + msg.mrq = MRQ_THERMAL;
>> + msg.tx.data = &req;
>> + msg.tx.size = sizeof(req);
>> + msg.rx.data = &reply;
>> + msg.rx.size = sizeof(reply);
>> +
>> + err = tegra_bpmp_transfer(bpmp, &msg);
>> + if (err)
>> + return err;
>> +
>> + *num_zones = reply.get_num_zones.num;
>> +
>> + return 0;
>> +}
>> +
>> +static const struct thermal_zone_of_device_ops tegra_bpmp_of_thermal_ops = {
>> + .get_temp = tegra_bpmp_thermal_get_temp,
>> + .set_trips = tegra_bpmp_thermal_set_trips,
>> +};
>> +
>> +static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
>> +{
>> + struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
>> + struct tegra_bpmp_thermal *tegra;
>> + struct thermal_zone_device *tzd;
>> + unsigned int i;
>> + int err;
>> +
>> + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
>> + if (!tegra)
>> + return -ENOMEM;
>> +
>> + tegra->dev = &pdev->dev;
>> + tegra->bpmp = bpmp;
>> +
>> + err = tegra_bpmp_thermal_get_num_zones(bpmp, &tegra->num_zones);
>> + if (err) {
>> + dev_err(&pdev->dev, "failed to get the number of zones: %d\n",
>> + err);
>> + return err;
>> + }
>> +
>> + tegra->zones = devm_kcalloc(&pdev->dev, tegra->num_zones,
>> + sizeof(*tegra->zones), GFP_KERNEL);
>> + if (!tegra->zones)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < tegra->num_zones; ++i) {
>> + int temp;
>> +
>> + tegra->zones[i].idx = i;
>> + tegra->zones[i].tegra = tegra;
>> +
>> + err = tegra_bpmp_thermal_get_temp(&tegra->zones[i], &temp);
>> + if (err < 0)
>> + continue;
>
> Should we release the memory allocated for zones that fail to retrieve
> temperature here, given that you are not going to use it elsewhere.

That's possible, though then we will need a separate allocation for each
zone struct. I'll make the change.

>
>> +
>> + tzd = devm_thermal_zone_of_sensor_register(
>> + &pdev->dev, i, &tegra->zones[i],
>> + &tegra_bpmp_of_thermal_ops);
>> + if (IS_ERR(tzd)) {
>> + if (PTR_ERR(tzd) == -EPROBE_DEFER)
>> + return -EPROBE_DEFER;
>> + continue;
>
> same here?
>
>> + }
>> +
>> + tegra->zones[i].tzd = tzd;
>> + INIT_WORK(&tegra->zones[i].tz_device_update_work,
>> + tz_device_update_work_fn);
>> + }
>> +
>> + err = tegra_bpmp_request_mrq(bpmp, MRQ_THERMAL, bpmp_mrq_thermal,
>> + tegra);
>> + if (err) {
>> + dev_err(&pdev->dev, "failed to register mrq handler: %d\n",
>> + err);
>> + return err;
>> + }
>> +
>> + platform_set_drvdata(pdev, tegra);
>> +
>> + return 0;
>> +}
>> +
>> +static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
>> +{
>> + struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
>> +
>> + tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
>> + { .compatible = "nvidia,tegra186-bpmp-thermal" },
>> + { },
>> +};
>> +MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
>> +
>> +static struct platform_driver tegra_bpmp_thermal_driver = {
>> + .probe = tegra_bpmp_thermal_probe,
>> + .remove = tegra_bpmp_thermal_remove,
>> + .driver = {
>> + .name = "tegra-bpmp-thermal",
>> + .of_match_table = tegra_bpmp_thermal_of_match,
>> + },
>> +};
>> +module_platform_driver(tegra_bpmp_thermal_driver);
>> +
>> +MODULE_AUTHOR("Mikko Perttunen <[email protected]>");
>> +MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.13.1
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Thanks,
Mikko

2017-07-10 09:14:29

by Mikko Perttunen

[permalink] [raw]
Subject: Re: [PATCH 1/4] arm64: tegra: Add BPMP thermal sensor to Tegra186

On 01.07.2017 02:56, Eduardo Valentin wrote:
> On Fri, Jun 16, 2017 at 02:28:22PM +0300, Mikko Perttunen wrote:
>> This adds the thermal sensor device provided by the BPMP, and the
>> relevant thermal sensors to the Tegra186 device tree.
>>
>> Signed-off-by: Mikko Perttunen <[email protected]>
>> ---
>> arch/arm64/boot/dts/nvidia/tegra186.dtsi | 48 ++++++++++++++++++++++++++++++++
>> 1 file changed, 48 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
>> index 5e62e68ac053..5c19ea74da24 100644
>> --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
>> +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
>> @@ -4,6 +4,7 @@
>> #include <dt-bindings/mailbox/tegra186-hsp.h>
>> #include <dt-bindings/power/tegra186-powergate.h>
>> #include <dt-bindings/reset/tegra186-reset.h>
>> +#include <dt-bindings/thermal/tegra186-bpmp-thermal.h>
>>
>> / {
>> compatible = "nvidia,tegra186";
>> @@ -444,6 +445,53 @@
>> #size-cells = <0>;
>> status = "disabled";
>> };
>> +
>> + bpmp_thermal: thermal {
>> + compatible = "nvidia,tegra186-bpmp-thermal";
>> + #thermal-sensor-cells = <1>;
>> + };
>> + };
>> +
>> + thermal-zones {
>> + a57 {
>> + polling-delay = <0>;
>> + polling-delay-passive = <1000>;
>> +
>> + thermal-sensors =
>> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_CPU>;
>> + };
>> +
>> + denver {
>> + polling-delay = <0>;
>> + polling-delay-passive = <1000>;
>> +
>> + thermal-sensors =
>> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AUX>;
>> + };
>> +
>> + gpu {
>> + polling-delay = <0>;
>> + polling-delay-passive = <1000>;
>> +
>> + thermal-sensors =
>> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_GPU>;
>> + };
>> +
>> + pll {
>> + polling-delay = <0>;
>> + polling-delay-passive = <1000>;
>> +
>> + thermal-sensors =
>> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_PLLX>;
>> + };
>> +
>> + always_on {
>> + polling-delay = <0>;
>> + polling-delay-passive = <1000>;
>> +
>> + thermal-sensors =
>> + <&bpmp_thermal TEGRA186_BPMP_THERMAL_ZONE_AO>;
>> + };
>
> All the above zones are lacking mandatory fields. Please refer to the
> thermal binding documentation.

Will fix.

>
>> };
>>
>> timer {
>> --
>> 2.13.1
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>