thermal: tegra: Changes for v4.15-rc1

This contains the Tegra186 BPMP thermal driver. It is used to monitor
 and access several thermal sensors found in the SoC.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAlnp4eMTHHRyZWRpbmdA
 bnZpZGlhLmNvbQAKCRDdI6zXfz6zodrZEACEhH5rCNN/848plxE43sG3nr67MBgd
 j012dMLQJghvTv60nJerWOapfiNIQIubaGxMe4cW0QM6tiQ4fmIrl4ewTA20R6lI
 Udsy/vgzzpfGZeClVGlL9DDmnxu7yNDL+LL70Hps00d74k3rWpnf6xRcIqxsdpxJ
 1bEZzZRCu4Q+0RpjgfmfrHrDo22qUrj1f0HjVQ4iFwDx6fbzNLPEkKszFoevgNPE
 ce7pnzmYywR+694t7CQ2REWDBIYzTZrgWqxkMtXmPgQISYzUXmqD5dzBFA2IZQO4
 kWyxzlMLyV2eK4ElvKnycZFYhuEzaOG/EVlpvHtFxy8NOlAIJWNh1CXT0mwdKx/o
 ZQvOU64vyqBSXURFoHLkGn8KfqrNpkc1nC4KU65Vuef4XMTTeLabki2rkxKo+7nb
 ljnwuMBTMfsaN9iLDHCdbXxxLQN1qXiUIcdOpt95NVZS4wsL7gQvpLj9UvUCFqJj
 o1OilXyArZd0KzxDQDAfoq1TC+AzYrQ2/29QZHqi6gi9/Qg4ipWKOiLezeqiwSyG
 6I85+fNV8Oc1nor9HqOC4cxNrO5woJA/gFw/J+JP3zg7aHOwldD4feKCeAV6QUKg
 /XS+S6iVqQQ7CVMV1Dw6ruiq1vaZ+DiapoaTnhC7n1g+wTfWdiQ9CsQ8UnAjVT76
 mfjD/Qjn8m5NoQ==
 =Y8Vc
 -----END PGP SIGNATURE-----

Merge tag 'tegra-for-4.15-thermal' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers

Pull "thermal: tegra: Changes for v4.15-rc1" from Thierry Reding:

This contains the Tegra186 BPMP thermal driver. It is used to monitor
and access several thermal sensors found in the SoC.

* tag 'tegra-for-4.15-thermal' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  thermal: Add Tegra BPMP thermal sensor driver
  dt-bindings: Add bindings for nvidia,tegra186-bpmp-thermal
  dt-bindings: clock: tegra: Add sor1_out clock
This commit is contained in:
Arnd Bergmann 2017-11-02 16:17:30 +01:00
commit 78af0be67b
7 changed files with 320 additions and 2 deletions

View File

@ -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>;
};
};

View File

@ -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_INTEL_PCH_THERMAL) += intel_pch_thermal.o
obj-$(CONFIG_ST_THERMAL) += st/ obj-$(CONFIG_ST_THERMAL) += st/
obj-$(CONFIG_QCOM_TSENS) += qcom/ obj-$(CONFIG_QCOM_TSENS) += qcom/
obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/ obj-y += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o

View File

@ -10,4 +10,11 @@ config TEGRA_SOCTHERM
zones to manage temperatures. This option is also required for the zones to manage temperatures. This option is also required for the
emergency thermal reset (thermtrip) feature to function. emergency thermal reset (thermtrip) feature to function.
config TEGRA_BPMP_THERMAL
tristate "Tegra BPMP thermal sensing"
depends on TEGRA_BPMP || COMPILE_TEST
help
Enable this option for support for sensing system temperature of NVIDIA
Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
endmenu endmenu

View File

@ -1,4 +1,5 @@
obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
obj-$(CONFIG_TEGRA_BPMP_THERMAL) += tegra-bpmp-thermal.o
tegra-soctherm-y := soctherm.o soctherm-fuse.o tegra-soctherm-y := soctherm.o soctherm-fuse.o
tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Mikko Perttunen <mperttunen@nvidia.com>
* Aapo Vienamo <avienamo@nvidia.com>
*
* 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 i;
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;
}
for (i = 0; i < tegra->num_zones; ++i) {
if (tegra->zones[i]->idx != req->host_trip_reached.zone)
continue;
schedule_work(&tegra->zones[i]->tz_device_update_work);
tegra_bpmp_mrq_return(ch, 0, NULL, 0);
return;
}
dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
req->host_trip_reached.zone);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
}
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, max_num_zones;
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, &max_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, max_num_zones,
sizeof(*tegra->zones), GFP_KERNEL);
if (!tegra->zones)
return -ENOMEM;
for (i = 0; i < max_num_zones; ++i) {
struct tegra_bpmp_thermal_zone *zone;
int temp;
zone = devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
if (!zone)
return -ENOMEM;
zone->idx = i;
zone->tegra = tegra;
err = tegra_bpmp_thermal_get_temp(zone, &temp);
if (err < 0) {
devm_kfree(&pdev->dev, zone);
continue;
}
tzd = devm_thermal_zone_of_sensor_register(
&pdev->dev, i, zone, &tegra_bpmp_of_thermal_ops);
if (IS_ERR(tzd)) {
if (PTR_ERR(tzd) == -EPROBE_DEFER)
return -EPROBE_DEFER;
devm_kfree(&pdev->dev, zone);
continue;
}
zone->tzd = tzd;
INIT_WORK(&zone->tz_device_update_work,
tz_device_update_work_fn);
tegra->zones[tegra->num_zones++] = zone;
}
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 <mperttunen@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
MODULE_LICENSE("GPL v2");

View File

@ -309,6 +309,7 @@
#define TEGRA210_CLK_BLINK 280 #define TEGRA210_CLK_BLINK 280
/* 281 */ /* 281 */
#define TEGRA210_CLK_SOR1_SRC 282 #define TEGRA210_CLK_SOR1_SRC 282
#define TEGRA210_CLK_SOR1_OUT 282
/* 283 */ /* 283 */
#define TEGRA210_CLK_XUSB_HOST_SRC 284 #define TEGRA210_CLK_XUSB_HOST_SRC 284
#define TEGRA210_CLK_XUSB_FALCON_SRC 285 #define TEGRA210_CLK_XUSB_FALCON_SRC 285

View File

@ -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