aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-11-02 11:17:30 -0400
committerArnd Bergmann <arnd@arndb.de>2017-11-02 11:17:30 -0400
commit78af0be67b297c3c4207b034e24c94e14c66b20c (patch)
treea8c98d8c1d7dbea13ea71ada68e1918fafb7b175
parent4e53097313523727bea5b786685f16191ec44b5d (diff)
parent7afebede62bed77ebae34fc64406984949d2a127 (diff)
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
-rw-r--r--Documentation/devicetree/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt32
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/tegra/Kconfig7
-rw-r--r--drivers/thermal/tegra/Makefile3
-rw-r--r--drivers/thermal/tegra/tegra-bpmp-thermal.c263
-rw-r--r--include/dt-bindings/clock/tegra210-car.h1
-rw-r--r--include/dt-bindings/thermal/tegra186-bpmp-thermal.h14
7 files changed, 320 insertions, 2 deletions
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 @@
1NVIDIA Tegra186 BPMP thermal sensor
2
3In Tegra186, the BPMP (Boot and Power Management Processor) implements an
4interface that is used to read system temperatures, including CPU cluster
5and GPU temperatures. This binding describes the thermal sensor that is
6exposed by BPMP.
7
8The BPMP thermal node must be located directly inside the main BPMP node. See
9../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding.
10
11This node represents a thermal sensor. See thermal.txt for details of the
12core thermal binding.
13
14Required properties:
15- compatible:
16 Array of strings.
17 One of:
18 - "nvidia,tegra186-bpmp-thermal".
19- #thermal-sensor-cells: Cell for sensor index.
20 Single-cell integer.
21 Must be <1>.
22
23Example:
24
25bpmp {
26 ...
27
28 bpmp_thermal: thermal {
29 compatible = "nvidia,tegra186-bpmp-thermal";
30 #thermal-sensor-cells = <1>;
31 };
32};
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 8b79bca23536..3a05204e0727 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -54,7 +54,7 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
54obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o 54obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
55obj-$(CONFIG_ST_THERMAL) += st/ 55obj-$(CONFIG_ST_THERMAL) += st/
56obj-$(CONFIG_QCOM_TSENS) += qcom/ 56obj-$(CONFIG_QCOM_TSENS) += qcom/
57obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/ 57obj-y += tegra/
58obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o 58obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
59obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o 59obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
60obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o 60obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig
index cec586ec7e4b..f8740f7852e3 100644
--- a/drivers/thermal/tegra/Kconfig
+++ b/drivers/thermal/tegra/Kconfig
@@ -10,4 +10,11 @@ config TEGRA_SOCTHERM
10 zones to manage temperatures. This option is also required for the 10 zones to manage temperatures. This option is also required for the
11 emergency thermal reset (thermtrip) feature to function. 11 emergency thermal reset (thermtrip) feature to function.
12 12
13config TEGRA_BPMP_THERMAL
14 tristate "Tegra BPMP thermal sensing"
15 depends on TEGRA_BPMP || COMPILE_TEST
16 help
17 Enable this option for support for sensing system temperature of NVIDIA
18 Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
19
13endmenu 20endmenu
diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile
index 1ce1af2cf0f5..ea541ecbbf32 100644
--- a/drivers/thermal/tegra/Makefile
+++ b/drivers/thermal/tegra/Makefile
@@ -1,4 +1,5 @@
1obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o 1obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o
2obj-$(CONFIG_TEGRA_BPMP_THERMAL) += tegra-bpmp-thermal.o
2 3
3tegra-soctherm-y := soctherm.o soctherm-fuse.o 4tegra-soctherm-y := soctherm.o soctherm-fuse.o
4tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o 5tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o
diff --git a/drivers/thermal/tegra/tegra-bpmp-thermal.c b/drivers/thermal/tegra/tegra-bpmp-thermal.c
new file mode 100644
index 000000000000..b0980dbca3b3
--- /dev/null
+++ b/drivers/thermal/tegra/tegra-bpmp-thermal.c
@@ -0,0 +1,263 @@
1/*
2 * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Author:
5 * Mikko Perttunen <mperttunen@nvidia.com>
6 * Aapo Vienamo <avienamo@nvidia.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/err.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/thermal.h>
23#include <linux/workqueue.h>
24
25#include <soc/tegra/bpmp.h>
26#include <soc/tegra/bpmp-abi.h>
27
28struct tegra_bpmp_thermal_zone {
29 struct tegra_bpmp_thermal *tegra;
30 struct thermal_zone_device *tzd;
31 struct work_struct tz_device_update_work;
32 unsigned int idx;
33};
34
35struct tegra_bpmp_thermal {
36 struct device *dev;
37 struct tegra_bpmp *bpmp;
38 unsigned int num_zones;
39 struct tegra_bpmp_thermal_zone **zones;
40};
41
42static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp)
43{
44 struct tegra_bpmp_thermal_zone *zone = data;
45 struct mrq_thermal_host_to_bpmp_request req;
46 union mrq_thermal_bpmp_to_host_response reply;
47 struct tegra_bpmp_message msg;
48 int err;
49
50 memset(&req, 0, sizeof(req));
51 req.type = CMD_THERMAL_GET_TEMP;
52 req.get_temp.zone = zone->idx;
53
54 memset(&msg, 0, sizeof(msg));
55 msg.mrq = MRQ_THERMAL;
56 msg.tx.data = &req;
57 msg.tx.size = sizeof(req);
58 msg.rx.data = &reply;
59 msg.rx.size = sizeof(reply);
60
61 err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
62 if (err)
63 return err;
64
65 *out_temp = reply.get_temp.temp;
66
67 return 0;
68}
69
70static int tegra_bpmp_thermal_set_trips(void *data, int low, int high)
71{
72 struct tegra_bpmp_thermal_zone *zone = data;
73 struct mrq_thermal_host_to_bpmp_request req;
74 struct tegra_bpmp_message msg;
75
76 memset(&req, 0, sizeof(req));
77 req.type = CMD_THERMAL_SET_TRIP;
78 req.set_trip.zone = zone->idx;
79 req.set_trip.enabled = true;
80 req.set_trip.low = low;
81 req.set_trip.high = high;
82
83 memset(&msg, 0, sizeof(msg));
84 msg.mrq = MRQ_THERMAL;
85 msg.tx.data = &req;
86 msg.tx.size = sizeof(req);
87
88 return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
89}
90
91static void tz_device_update_work_fn(struct work_struct *work)
92{
93 struct tegra_bpmp_thermal_zone *zone;
94
95 zone = container_of(work, struct tegra_bpmp_thermal_zone,
96 tz_device_update_work);
97
98 thermal_zone_device_update(zone->tzd, THERMAL_TRIP_VIOLATED);
99}
100
101static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
102 void *data)
103{
104 struct mrq_thermal_bpmp_to_host_request *req;
105 struct tegra_bpmp_thermal *tegra = data;
106 int i;
107
108 req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
109
110 if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
111 dev_err(tegra->dev, "%s: invalid request type: %d\n",
112 __func__, req->type);
113 tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
114 return;
115 }
116
117 for (i = 0; i < tegra->num_zones; ++i) {
118 if (tegra->zones[i]->idx != req->host_trip_reached.zone)
119 continue;
120
121 schedule_work(&tegra->zones[i]->tz_device_update_work);
122 tegra_bpmp_mrq_return(ch, 0, NULL, 0);
123 return;
124 }
125
126 dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
127 req->host_trip_reached.zone);
128 tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
129}
130
131static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
132 int *num_zones)
133{
134 struct mrq_thermal_host_to_bpmp_request req;
135 union mrq_thermal_bpmp_to_host_response reply;
136 struct tegra_bpmp_message msg;
137 int err;
138
139 memset(&req, 0, sizeof(req));
140 req.type = CMD_THERMAL_GET_NUM_ZONES;
141
142 memset(&msg, 0, sizeof(msg));
143 msg.mrq = MRQ_THERMAL;
144 msg.tx.data = &req;
145 msg.tx.size = sizeof(req);
146 msg.rx.data = &reply;
147 msg.rx.size = sizeof(reply);
148
149 err = tegra_bpmp_transfer(bpmp, &msg);
150 if (err)
151 return err;
152
153 *num_zones = reply.get_num_zones.num;
154
155 return 0;
156}
157
158static const struct thermal_zone_of_device_ops tegra_bpmp_of_thermal_ops = {
159 .get_temp = tegra_bpmp_thermal_get_temp,
160 .set_trips = tegra_bpmp_thermal_set_trips,
161};
162
163static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
164{
165 struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
166 struct tegra_bpmp_thermal *tegra;
167 struct thermal_zone_device *tzd;
168 unsigned int i, max_num_zones;
169 int err;
170
171 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
172 if (!tegra)
173 return -ENOMEM;
174
175 tegra->dev = &pdev->dev;
176 tegra->bpmp = bpmp;
177
178 err = tegra_bpmp_thermal_get_num_zones(bpmp, &max_num_zones);
179 if (err) {
180 dev_err(&pdev->dev, "failed to get the number of zones: %d\n",
181 err);
182 return err;
183 }
184
185 tegra->zones = devm_kcalloc(&pdev->dev, max_num_zones,
186 sizeof(*tegra->zones), GFP_KERNEL);
187 if (!tegra->zones)
188 return -ENOMEM;
189
190 for (i = 0; i < max_num_zones; ++i) {
191 struct tegra_bpmp_thermal_zone *zone;
192 int temp;
193
194 zone = devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
195 if (!zone)
196 return -ENOMEM;
197
198 zone->idx = i;
199 zone->tegra = tegra;
200
201 err = tegra_bpmp_thermal_get_temp(zone, &temp);
202 if (err < 0) {
203 devm_kfree(&pdev->dev, zone);
204 continue;
205 }
206
207 tzd = devm_thermal_zone_of_sensor_register(
208 &pdev->dev, i, zone, &tegra_bpmp_of_thermal_ops);
209 if (IS_ERR(tzd)) {
210 if (PTR_ERR(tzd) == -EPROBE_DEFER)
211 return -EPROBE_DEFER;
212 devm_kfree(&pdev->dev, zone);
213 continue;
214 }
215
216 zone->tzd = tzd;
217 INIT_WORK(&zone->tz_device_update_work,
218 tz_device_update_work_fn);
219
220 tegra->zones[tegra->num_zones++] = zone;
221 }
222
223 err = tegra_bpmp_request_mrq(bpmp, MRQ_THERMAL, bpmp_mrq_thermal,
224 tegra);
225 if (err) {
226 dev_err(&pdev->dev, "failed to register mrq handler: %d\n",
227 err);
228 return err;
229 }
230
231 platform_set_drvdata(pdev, tegra);
232
233 return 0;
234}
235
236static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
237{
238 struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
239
240 tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
241
242 return 0;
243}
244
245static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
246 { .compatible = "nvidia,tegra186-bpmp-thermal" },
247 { },
248};
249MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
250
251static struct platform_driver tegra_bpmp_thermal_driver = {
252 .probe = tegra_bpmp_thermal_probe,
253 .remove = tegra_bpmp_thermal_remove,
254 .driver = {
255 .name = "tegra-bpmp-thermal",
256 .of_match_table = tegra_bpmp_thermal_of_match,
257 },
258};
259module_platform_driver(tegra_bpmp_thermal_driver);
260
261MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
262MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
263MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
index 46689cd3750b..43c4a8407333 100644
--- a/include/dt-bindings/clock/tegra210-car.h
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -309,6 +309,7 @@
309#define TEGRA210_CLK_BLINK 280 309#define TEGRA210_CLK_BLINK 280
310/* 281 */ 310/* 281 */
311#define TEGRA210_CLK_SOR1_SRC 282 311#define TEGRA210_CLK_SOR1_SRC 282
312#define TEGRA210_CLK_SOR1_OUT 282
312/* 283 */ 313/* 283 */
313#define TEGRA210_CLK_XUSB_HOST_SRC 284 314#define TEGRA210_CLK_XUSB_HOST_SRC 284
314#define TEGRA210_CLK_XUSB_FALCON_SRC 285 315#define TEGRA210_CLK_XUSB_FALCON_SRC 285
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 @@
1/*
2 * This header provides constants for binding nvidia,tegra186-bpmp-thermal.
3 */
4
5#ifndef _DT_BINDINGS_THERMAL_TEGRA186_BPMP_THERMAL_H
6#define _DT_BINDINGS_THERMAL_TEGRA186_BPMP_THERMAL_H
7
8#define TEGRA186_BPMP_THERMAL_ZONE_CPU 2
9#define TEGRA186_BPMP_THERMAL_ZONE_GPU 3
10#define TEGRA186_BPMP_THERMAL_ZONE_AUX 4
11#define TEGRA186_BPMP_THERMAL_ZONE_PLLX 5
12#define TEGRA186_BPMP_THERMAL_ZONE_AO 6
13
14#endif