blob: 7d2db23d71a32deab7c524cb0c9ad8466886018a [file] [log] [blame]
Wei Ni65b6d572016-03-29 18:29:14 +08001/*
2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Author:
5 * Mikko Perttunen <mperttunen@nvidia.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
Wei Nid753b222016-03-29 18:29:16 +080018#include <linux/debugfs.h>
Wei Ni65b6d572016-03-29 18:29:14 +080019#include <linux/bitops.h>
20#include <linux/clk.h>
21#include <linux/delay.h>
22#include <linux/err.h>
23#include <linux/interrupt.h>
24#include <linux/io.h>
25#include <linux/module.h>
26#include <linux/of.h>
27#include <linux/platform_device.h>
28#include <linux/reset.h>
29#include <linux/thermal.h>
30
31#include <dt-bindings/thermal/tegra124-soctherm.h>
32
Wei Nice0dbf02016-05-11 18:20:17 +080033#include "../thermal_core.h"
Wei Ni65b6d572016-03-29 18:29:14 +080034#include "soctherm.h"
35
36#define SENSOR_CONFIG0 0
37#define SENSOR_CONFIG0_STOP BIT(0)
Wei Ni65b6d572016-03-29 18:29:14 +080038#define SENSOR_CONFIG0_CPTR_OVER BIT(2)
Wei Nid753b222016-03-29 18:29:16 +080039#define SENSOR_CONFIG0_OVER BIT(3)
40#define SENSOR_CONFIG0_TCALC_OVER BIT(4)
41#define SENSOR_CONFIG0_TALL_MASK (0xfffff << 8)
42#define SENSOR_CONFIG0_TALL_SHIFT 8
Wei Ni65b6d572016-03-29 18:29:14 +080043
44#define SENSOR_CONFIG1 4
Wei Nid753b222016-03-29 18:29:16 +080045#define SENSOR_CONFIG1_TSAMPLE_MASK 0x3ff
Wei Ni65b6d572016-03-29 18:29:14 +080046#define SENSOR_CONFIG1_TSAMPLE_SHIFT 0
Wei Nid753b222016-03-29 18:29:16 +080047#define SENSOR_CONFIG1_TIDDQ_EN_MASK (0x3f << 15)
Wei Ni65b6d572016-03-29 18:29:14 +080048#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15
Wei Nid753b222016-03-29 18:29:16 +080049#define SENSOR_CONFIG1_TEN_COUNT_MASK (0x3f << 24)
Wei Ni65b6d572016-03-29 18:29:14 +080050#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
51#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
52
53/*
54 * SENSOR_CONFIG2 is defined in soctherm.h
55 * because, it will be used by tegra_soctherm_fuse.c
56 */
57
Wei Nid753b222016-03-29 18:29:16 +080058#define SENSOR_STATUS0 0xc
59#define SENSOR_STATUS0_VALID_MASK BIT(31)
60#define SENSOR_STATUS0_CAPTURE_MASK 0xffff
61
62#define SENSOR_STATUS1 0x10
63#define SENSOR_STATUS1_TEMP_VALID_MASK BIT(31)
64#define SENSOR_STATUS1_TEMP_MASK 0xffff
65
Wei Ni65b6d572016-03-29 18:29:14 +080066#define READBACK_VALUE_MASK 0xff00
67#define READBACK_VALUE_SHIFT 8
68#define READBACK_ADD_HALF BIT(7)
69#define READBACK_NEGATE BIT(0)
70
Wei Nice0dbf02016-05-11 18:20:17 +080071/*
72 * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h
73 * because it will be used by tegraxxx_soctherm.c
74 */
75#define THERMCTL_LVL0_CPU0_EN_MASK BIT(8)
76#define THERMCTL_LVL0_CPU0_CPU_THROT_MASK (0x3 << 5)
77#define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT 0x1
78#define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY 0x2
79#define THERMCTL_LVL0_CPU0_GPU_THROT_MASK (0x3 << 3)
80#define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT 0x1
81#define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY 0x2
82#define THERMCTL_LVL0_CPU0_MEM_THROT_MASK BIT(2)
83#define THERMCTL_LVL0_CPU0_STATUS_MASK 0x3
84
85#define THERMCTL_LVL0_UP_STATS 0x10
86#define THERMCTL_LVL0_DN_STATS 0x14
87
88#define THERMCTL_STATS_CTL 0x94
89#define STATS_CTL_CLR_DN 0x8
90#define STATS_CTL_EN_DN 0x4
91#define STATS_CTL_CLR_UP 0x2
92#define STATS_CTL_EN_UP 0x1
93
94#define THROT_GLOBAL_CFG 0x400
95#define THROT_GLOBAL_ENB_MASK BIT(0)
96
97#define CPU_PSKIP_STATUS 0x418
98#define XPU_PSKIP_STATUS_M_MASK (0xff << 12)
99#define XPU_PSKIP_STATUS_N_MASK (0xff << 4)
100#define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK BIT(1)
101#define XPU_PSKIP_STATUS_ENABLED_MASK BIT(0)
102
103#define THROT_PRIORITY_LOCK 0x424
104#define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff
105
106#define THROT_STATUS 0x428
107#define THROT_STATUS_BREACH_MASK BIT(12)
108#define THROT_STATUS_STATE_MASK (0xff << 4)
109#define THROT_STATUS_ENABLED_MASK BIT(0)
110
111#define THROT_PSKIP_CTRL_LITE_CPU 0x430
112#define THROT_PSKIP_CTRL_ENABLE_MASK BIT(31)
113#define THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)
114#define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff
115#define THROT_PSKIP_CTRL_VECT_GPU_MASK (0x7 << 16)
116#define THROT_PSKIP_CTRL_VECT_CPU_MASK (0x7 << 8)
117#define THROT_PSKIP_CTRL_VECT2_CPU_MASK 0x7
118
119#define THROT_VECT_NONE 0x0 /* 3'b000 */
120#define THROT_VECT_LOW 0x1 /* 3'b001 */
121#define THROT_VECT_MED 0x3 /* 3'b011 */
122#define THROT_VECT_HIGH 0x7 /* 3'b111 */
123
124#define THROT_PSKIP_RAMP_LITE_CPU 0x434
125#define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)
126#define THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)
127#define THROT_PSKIP_RAMP_STEP_MASK 0xff
128
129#define THROT_PRIORITY_LITE 0x444
130#define THROT_PRIORITY_LITE_PRIO_MASK 0xff
131
132#define THROT_DELAY_LITE 0x448
133#define THROT_DELAY_LITE_DELAY_MASK 0xff
134
135/* car register offsets needed for enabling HW throttling */
136#define CAR_SUPER_CCLKG_DIVIDER 0x36c
137#define CDIVG_USE_THERM_CONTROLS_MASK BIT(30)
138
Wei Ni6c7c3242016-05-11 18:20:18 +0800139/* ccroc register offsets needed for enabling HW throttling for Tegra132 */
140#define CCROC_SUPER_CCLKG_DIVIDER 0x024
141
142#define CCROC_GLOBAL_CFG 0x148
143
144#define CCROC_THROT_PSKIP_RAMP_CPU 0x150
145#define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)
146#define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)
147#define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff
148
149#define CCROC_THROT_PSKIP_CTRL_CPU 0x154
150#define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31)
151#define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)
152#define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff
153
Wei Ni65b6d572016-03-29 18:29:14 +0800154/* get val from register(r) mask bits(m) */
155#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))
156/* set val(v) to mask bits(m) of register(r) */
157#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \
158 (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))
159
Wei Nice0dbf02016-05-11 18:20:17 +0800160/* get dividend from the depth */
161#define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1)
162
163/* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */
164#define THROT_OFFSET 0x30
165#define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \
166 (THROT_OFFSET * throt) + (8 * dev))
167#define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \
168 (THROT_OFFSET * throt) + (8 * dev))
169
170/* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */
171#define THROT_PRIORITY_CTRL(throt) (THROT_PRIORITY_LITE + \
172 (THROT_OFFSET * throt))
173#define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \
174 (THROT_OFFSET * throt))
175
Wei Ni6c7c3242016-05-11 18:20:18 +0800176/* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/
177#define CCROC_THROT_OFFSET 0x0c
178#define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \
179 (CCROC_THROT_OFFSET * vect))
180#define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \
181 (CCROC_THROT_OFFSET * vect))
182
Wei Nice0dbf02016-05-11 18:20:17 +0800183/* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */
184#define THERMCTL_LVL_REGS_SIZE 0x20
185#define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
186
Wei Ni2a895872016-03-29 18:29:19 +0800187static const int min_low_temp = -127000;
188static const int max_high_temp = 127000;
189
Wei Nice0dbf02016-05-11 18:20:17 +0800190enum soctherm_throttle_id {
191 THROTTLE_LIGHT = 0,
192 THROTTLE_HEAVY,
193 THROTTLE_SIZE,
194};
195
196enum soctherm_throttle_dev_id {
197 THROTTLE_DEV_CPU = 0,
198 THROTTLE_DEV_GPU,
199 THROTTLE_DEV_SIZE,
200};
201
202static const char *const throt_names[] = {
203 [THROTTLE_LIGHT] = "light",
204 [THROTTLE_HEAVY] = "heavy",
205};
206
207struct tegra_soctherm;
Wei Ni65b6d572016-03-29 18:29:14 +0800208struct tegra_thermctl_zone {
209 void __iomem *reg;
Wei Ni2a895872016-03-29 18:29:19 +0800210 struct device *dev;
Wei Nice0dbf02016-05-11 18:20:17 +0800211 struct tegra_soctherm *ts;
Wei Ni2a895872016-03-29 18:29:19 +0800212 struct thermal_zone_device *tz;
213 const struct tegra_tsensor_group *sg;
Wei Ni65b6d572016-03-29 18:29:14 +0800214};
215
Wei Nice0dbf02016-05-11 18:20:17 +0800216struct soctherm_throt_cfg {
217 const char *name;
218 unsigned int id;
219 u8 priority;
Wei Ni6c7c3242016-05-11 18:20:18 +0800220 u8 cpu_throt_level;
Wei Nice0dbf02016-05-11 18:20:17 +0800221 u32 cpu_throt_depth;
222 struct thermal_cooling_device *cdev;
223 bool init;
224};
225
Wei Ni65b6d572016-03-29 18:29:14 +0800226struct tegra_soctherm {
227 struct reset_control *reset;
228 struct clk *clock_tsensor;
229 struct clk *clock_soctherm;
230 void __iomem *regs;
Wei Nice0dbf02016-05-11 18:20:17 +0800231 void __iomem *clk_regs;
Wei Ni6c7c3242016-05-11 18:20:18 +0800232 void __iomem *ccroc_regs;
Wei Ni65b6d572016-03-29 18:29:14 +0800233
234 u32 *calib;
Wei Nice0dbf02016-05-11 18:20:17 +0800235 struct thermal_zone_device **thermctl_tzs;
Wei Ni65b6d572016-03-29 18:29:14 +0800236 struct tegra_soctherm_soc *soc;
Wei Nid753b222016-03-29 18:29:16 +0800237
Wei Nice0dbf02016-05-11 18:20:17 +0800238 struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE];
239
Wei Nid753b222016-03-29 18:29:16 +0800240 struct dentry *debugfs_dir;
Wei Ni65b6d572016-03-29 18:29:14 +0800241};
242
Wei Nice0dbf02016-05-11 18:20:17 +0800243/**
244 * clk_writel() - writes a value to a CAR register
245 * @ts: pointer to a struct tegra_soctherm
246 * @v: the value to write
247 * @reg: the register offset
248 *
249 * Writes @v to @reg. No return value.
250 */
251static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg)
252{
253 writel(value, (ts->clk_regs + reg));
254}
255
256/**
257 * clk_readl() - reads specified register from CAR IP block
258 * @ts: pointer to a struct tegra_soctherm
259 * @reg: register address to be read
260 *
261 * Return: the value of the register
262 */
263static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg)
264{
265 return readl(ts->clk_regs + reg);
266}
267
Wei Ni6c7c3242016-05-11 18:20:18 +0800268/**
269 * ccroc_writel() - writes a value to a CCROC register
270 * @ts: pointer to a struct tegra_soctherm
271 * @v: the value to write
272 * @reg: the register offset
273 *
274 * Writes @v to @reg. No return value.
275 */
276static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg)
277{
278 writel(value, (ts->ccroc_regs + reg));
279}
280
281/**
282 * ccroc_readl() - reads specified register from CCROC IP block
283 * @ts: pointer to a struct tegra_soctherm
284 * @reg: register address to be read
285 *
286 * Return: the value of the register
287 */
288static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg)
289{
290 return readl(ts->ccroc_regs + reg);
291}
292
Wei Ni1ed895c2016-03-29 18:29:21 +0800293static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i)
Wei Ni65b6d572016-03-29 18:29:14 +0800294{
295 const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i];
296 void __iomem *base = tegra->regs + sensor->base;
Wei Ni65b6d572016-03-29 18:29:14 +0800297 unsigned int val;
Wei Ni65b6d572016-03-29 18:29:14 +0800298
299 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
300 writel(val, base + SENSOR_CONFIG0);
301
302 val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
303 val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
304 val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
305 val |= SENSOR_CONFIG1_TEMP_ENABLE;
306 writel(val, base + SENSOR_CONFIG1);
307
Wei Ni1ed895c2016-03-29 18:29:21 +0800308 writel(tegra->calib[i], base + SENSOR_CONFIG2);
Wei Ni65b6d572016-03-29 18:29:14 +0800309}
310
311/*
312 * Translate from soctherm readback format to millicelsius.
313 * The soctherm readback format in bits is as follows:
314 * TTTTTTTT H______N
315 * where T's contain the temperature in Celsius,
316 * H denotes an addition of 0.5 Celsius and N denotes negation
317 * of the final value.
318 */
319static int translate_temp(u16 val)
320{
321 int t;
322
323 t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
324 if (val & READBACK_ADD_HALF)
325 t += 500;
326 if (val & READBACK_NEGATE)
327 t *= -1;
328
329 return t;
330}
331
332static int tegra_thermctl_get_temp(void *data, int *out_temp)
333{
334 struct tegra_thermctl_zone *zone = data;
335 u32 val;
336
337 val = readl(zone->reg);
Wei Ni2a895872016-03-29 18:29:19 +0800338 val = REG_GET_MASK(val, zone->sg->sensor_temp_mask);
Wei Ni65b6d572016-03-29 18:29:14 +0800339 *out_temp = translate_temp(val);
340
341 return 0;
342}
343
Wei Ni2a895872016-03-29 18:29:19 +0800344static int
345thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
346 int trip_temp);
Wei Nice0dbf02016-05-11 18:20:17 +0800347static int
348throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg,
349 struct soctherm_throt_cfg *stc, int trip_temp);
350static struct soctherm_throt_cfg *
351find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name);
Wei Ni2a895872016-03-29 18:29:19 +0800352
353static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
354{
355 struct tegra_thermctl_zone *zone = data;
356 struct thermal_zone_device *tz = zone->tz;
Wei Nice0dbf02016-05-11 18:20:17 +0800357 struct tegra_soctherm *ts = zone->ts;
Wei Ni2a895872016-03-29 18:29:19 +0800358 const struct tegra_tsensor_group *sg = zone->sg;
359 struct device *dev = zone->dev;
360 enum thermal_trip_type type;
361 int ret;
362
363 if (!tz)
364 return -EINVAL;
365
366 ret = tz->ops->get_trip_type(tz, trip, &type);
367 if (ret)
368 return ret;
369
Wei Nice0dbf02016-05-11 18:20:17 +0800370 if (type == THERMAL_TRIP_CRITICAL) {
371 return thermtrip_program(dev, sg, temp);
372 } else if (type == THERMAL_TRIP_HOT) {
373 int i;
Wei Ni2a895872016-03-29 18:29:19 +0800374
Wei Nice0dbf02016-05-11 18:20:17 +0800375 for (i = 0; i < THROTTLE_SIZE; i++) {
376 struct thermal_cooling_device *cdev;
377 struct soctherm_throt_cfg *stc;
378
379 if (!ts->throt_cfgs[i].init)
380 continue;
381
382 cdev = ts->throt_cfgs[i].cdev;
383 if (get_thermal_instance(tz, cdev, trip))
384 stc = find_throttle_cfg_by_name(ts, cdev->type);
385 else
386 continue;
387
388 return throttrip_program(dev, sg, stc, temp);
389 }
390 }
391
392 return 0;
Wei Ni2a895872016-03-29 18:29:19 +0800393}
394
Wei Ni65b6d572016-03-29 18:29:14 +0800395static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
396 .get_temp = tegra_thermctl_get_temp,
Wei Ni2a895872016-03-29 18:29:19 +0800397 .set_trip_temp = tegra_thermctl_set_trip_temp,
Wei Ni65b6d572016-03-29 18:29:14 +0800398};
399
Wei Ni2a895872016-03-29 18:29:19 +0800400/**
401 * enforce_temp_range() - check and enforce temperature range [min, max]
402 * @trip_temp: the trip temperature to check
403 *
404 * Checks and enforces the permitted temperature range that SOC_THERM
405 * HW can support This is
406 * done while taking care of precision.
407 *
408 * Return: The precision adjusted capped temperature in millicelsius.
409 */
410static int enforce_temp_range(struct device *dev, int trip_temp)
411{
412 int temp;
413
414 temp = clamp_val(trip_temp, min_low_temp, max_high_temp);
415 if (temp != trip_temp)
416 dev_info(dev, "soctherm: trip temperature %d forced to %d\n",
417 trip_temp, temp);
418 return temp;
419}
420
421/**
422 * thermtrip_program() - Configures the hardware to shut down the
423 * system if a given sensor group reaches a given temperature
424 * @dev: ptr to the struct device for the SOC_THERM IP block
425 * @sg: pointer to the sensor group to set the thermtrip temperature for
426 * @trip_temp: the temperature in millicelsius to trigger the thermal trip at
427 *
428 * Sets the thermal trip threshold of the given sensor group to be the
429 * @trip_temp. If this threshold is crossed, the hardware will shut
430 * down.
431 *
432 * Note that, although @trip_temp is specified in millicelsius, the
433 * hardware is programmed in degrees Celsius.
434 *
435 * Return: 0 upon success, or %-EINVAL upon failure.
436 */
437static int thermtrip_program(struct device *dev,
438 const struct tegra_tsensor_group *sg,
439 int trip_temp)
440{
441 struct tegra_soctherm *ts = dev_get_drvdata(dev);
442 int temp;
443 u32 r;
444
Wei Nif3500982016-04-06 17:48:04 +0800445 if (!sg || !sg->thermtrip_threshold_mask)
Wei Ni2a895872016-03-29 18:29:19 +0800446 return -EINVAL;
447
448 temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;
449
450 r = readl(ts->regs + THERMCTL_THERMTRIP_CTL);
451 r = REG_SET_MASK(r, sg->thermtrip_threshold_mask, temp);
452 r = REG_SET_MASK(r, sg->thermtrip_enable_mask, 1);
453 r = REG_SET_MASK(r, sg->thermtrip_any_en_mask, 0);
454 writel(r, ts->regs + THERMCTL_THERMTRIP_CTL);
455
456 return 0;
457}
458
459/**
Wei Nice0dbf02016-05-11 18:20:17 +0800460 * throttrip_program() - Configures the hardware to throttle the
461 * pulse if a given sensor group reaches a given temperature
462 * @dev: ptr to the struct device for the SOC_THERM IP block
463 * @sg: pointer to the sensor group to set the thermtrip temperature for
464 * @stc: pointer to the throttle need to be triggered
465 * @trip_temp: the temperature in millicelsius to trigger the thermal trip at
466 *
467 * Sets the thermal trip threshold and throttle event of the given sensor
468 * group. If this threshold is crossed, the hardware will trigger the
469 * throttle.
470 *
471 * Note that, although @trip_temp is specified in millicelsius, the
472 * hardware is programmed in degrees Celsius.
473 *
474 * Return: 0 upon success, or %-EINVAL upon failure.
475 */
476static int throttrip_program(struct device *dev,
477 const struct tegra_tsensor_group *sg,
478 struct soctherm_throt_cfg *stc,
479 int trip_temp)
480{
481 struct tegra_soctherm *ts = dev_get_drvdata(dev);
482 int temp, cpu_throt, gpu_throt;
483 unsigned int throt;
484 u32 r, reg_off;
485
486 if (!dev || !sg || !stc || !stc->init)
487 return -EINVAL;
488
489 temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;
490
491 /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */
492 throt = stc->id;
493 reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1);
494
495 if (throt == THROTTLE_LIGHT) {
496 cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT;
497 gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT;
498 } else {
499 cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY;
500 gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY;
501 if (throt != THROTTLE_HEAVY)
502 dev_warn(dev,
503 "invalid throt id %d - assuming HEAVY",
504 throt);
505 }
506
507 r = readl(ts->regs + reg_off);
508 r = REG_SET_MASK(r, sg->thermctl_lvl0_up_thresh_mask, temp);
509 r = REG_SET_MASK(r, sg->thermctl_lvl0_dn_thresh_mask, temp);
510 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_CPU_THROT_MASK, cpu_throt);
511 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_GPU_THROT_MASK, gpu_throt);
512 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);
513 writel(r, ts->regs + reg_off);
514
515 return 0;
516}
517
518static struct soctherm_throt_cfg *
519find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name)
520{
521 unsigned int i;
522
523 for (i = 0; ts->throt_cfgs[i].name; i++)
524 if (!strcmp(ts->throt_cfgs[i].name, name))
525 return &ts->throt_cfgs[i];
526
527 return NULL;
528}
529
530static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
531{
532 int ntrips, i, ret;
533 enum thermal_trip_type type;
534
535 ntrips = of_thermal_get_ntrips(tz);
536 if (ntrips <= 0)
537 return -EINVAL;
538
539 for (i = 0; i < ntrips; i++) {
540 ret = tz->ops->get_trip_type(tz, i, &type);
541 if (ret)
542 return -EINVAL;
543 if (type == THERMAL_TRIP_HOT) {
544 ret = tz->ops->get_trip_temp(tz, i, temp);
545 if (!ret)
546 *trip = i;
547
548 return ret;
549 }
550 }
551
552 return -EINVAL;
553}
554
555/**
Wei Ni2a895872016-03-29 18:29:19 +0800556 * tegra_soctherm_set_hwtrips() - set HW trip point from DT data
557 * @dev: struct device * of the SOC_THERM instance
558 *
559 * Configure the SOC_THERM HW trip points, setting "THERMTRIP"
Wei Nice0dbf02016-05-11 18:20:17 +0800560 * "THROTTLE" trip points , using "critical" or "hot" type trip_temp
561 * from thermal zone.
562 * After they have been configured, THERMTRIP or THROTTLE will take
563 * action when the configured SoC thermal sensor group reaches a
Wei Ni2a895872016-03-29 18:29:19 +0800564 * certain temperature.
565 *
566 * Return: 0 upon success, or a negative error code on failure.
567 * "Success" does not mean that trips was enabled; it could also
568 * mean that no node was found in DT.
569 * THERMTRIP has been enabled successfully when a message similar to
570 * this one appears on the serial console:
571 * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC"
Wei Nice0dbf02016-05-11 18:20:17 +0800572 * THROTTLE has been enabled successfully when a message similar to
573 * this one appears on the serial console:
574 * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC"
Wei Ni2a895872016-03-29 18:29:19 +0800575 */
576static int tegra_soctherm_set_hwtrips(struct device *dev,
577 const struct tegra_tsensor_group *sg,
578 struct thermal_zone_device *tz)
579{
Wei Nice0dbf02016-05-11 18:20:17 +0800580 struct tegra_soctherm *ts = dev_get_drvdata(dev);
581 struct soctherm_throt_cfg *stc;
582 int i, trip, temperature;
Wei Ni2a895872016-03-29 18:29:19 +0800583 int ret;
584
585 ret = tz->ops->get_crit_temp(tz, &temperature);
586 if (ret) {
587 dev_warn(dev, "thermtrip: %s: missing critical temperature\n",
588 sg->name);
Wei Nice0dbf02016-05-11 18:20:17 +0800589 goto set_throttle;
Wei Ni2a895872016-03-29 18:29:19 +0800590 }
591
592 ret = thermtrip_program(dev, sg, temperature);
593 if (ret) {
594 dev_err(dev, "thermtrip: %s: error during enable\n",
595 sg->name);
596 return ret;
597 }
598
599 dev_info(dev,
600 "thermtrip: will shut down when %s reaches %d mC\n",
601 sg->name, temperature);
602
Wei Nice0dbf02016-05-11 18:20:17 +0800603set_throttle:
Wei Nice0dbf02016-05-11 18:20:17 +0800604 ret = get_hot_temp(tz, &trip, &temperature);
605 if (ret) {
606 dev_warn(dev, "throttrip: %s: missing hot temperature\n",
607 sg->name);
608 return 0;
609 }
610
611 for (i = 0; i < THROTTLE_SIZE; i++) {
612 struct thermal_cooling_device *cdev;
613
614 if (!ts->throt_cfgs[i].init)
615 continue;
616
617 cdev = ts->throt_cfgs[i].cdev;
618 if (get_thermal_instance(tz, cdev, trip))
619 stc = find_throttle_cfg_by_name(ts, cdev->type);
620 else
621 continue;
622
623 ret = throttrip_program(dev, sg, stc, temperature);
624 if (ret) {
625 dev_err(dev, "throttrip: %s: error during enable\n",
626 sg->name);
627 return ret;
628 }
629
630 dev_info(dev,
631 "throttrip: will throttle when %s reaches %d mC\n",
632 sg->name, temperature);
633 break;
634 }
635
636 if (i == THROTTLE_SIZE)
637 dev_warn(dev, "throttrip: %s: missing throttle cdev\n",
638 sg->name);
639
Wei Ni2a895872016-03-29 18:29:19 +0800640 return 0;
641}
642
Wei Nid753b222016-03-29 18:29:16 +0800643#ifdef CONFIG_DEBUG_FS
644static int regs_show(struct seq_file *s, void *data)
645{
646 struct platform_device *pdev = s->private;
647 struct tegra_soctherm *ts = platform_get_drvdata(pdev);
648 const struct tegra_tsensor *tsensors = ts->soc->tsensors;
Wei Ni2a895872016-03-29 18:29:19 +0800649 const struct tegra_tsensor_group **ttgs = ts->soc->ttgs;
Wei Nid753b222016-03-29 18:29:16 +0800650 u32 r, state;
Wei Nice0dbf02016-05-11 18:20:17 +0800651 int i, level;
Wei Nid753b222016-03-29 18:29:16 +0800652
653 seq_puts(s, "-----TSENSE (convert HW)-----\n");
654
655 for (i = 0; i < ts->soc->num_tsensors; i++) {
656 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG1);
657 state = REG_GET_MASK(r, SENSOR_CONFIG1_TEMP_ENABLE);
658
659 seq_printf(s, "%s: ", tsensors[i].name);
660 seq_printf(s, "En(%d) ", state);
661
662 if (!state) {
663 seq_puts(s, "\n");
664 continue;
665 }
666
667 state = REG_GET_MASK(r, SENSOR_CONFIG1_TIDDQ_EN_MASK);
668 seq_printf(s, "tiddq(%d) ", state);
669 state = REG_GET_MASK(r, SENSOR_CONFIG1_TEN_COUNT_MASK);
670 seq_printf(s, "ten_count(%d) ", state);
671 state = REG_GET_MASK(r, SENSOR_CONFIG1_TSAMPLE_MASK);
672 seq_printf(s, "tsample(%d) ", state + 1);
673
674 r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS1);
675 state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_VALID_MASK);
676 seq_printf(s, "Temp(%d/", state);
677 state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_MASK);
678 seq_printf(s, "%d) ", translate_temp(state));
679
680 r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS0);
681 state = REG_GET_MASK(r, SENSOR_STATUS0_VALID_MASK);
682 seq_printf(s, "Capture(%d/", state);
683 state = REG_GET_MASK(r, SENSOR_STATUS0_CAPTURE_MASK);
684 seq_printf(s, "%d) ", state);
685
686 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG0);
687 state = REG_GET_MASK(r, SENSOR_CONFIG0_STOP);
688 seq_printf(s, "Stop(%d) ", state);
689 state = REG_GET_MASK(r, SENSOR_CONFIG0_TALL_MASK);
690 seq_printf(s, "Tall(%d) ", state);
691 state = REG_GET_MASK(r, SENSOR_CONFIG0_TCALC_OVER);
692 seq_printf(s, "Over(%d/", state);
693 state = REG_GET_MASK(r, SENSOR_CONFIG0_OVER);
694 seq_printf(s, "%d/", state);
695 state = REG_GET_MASK(r, SENSOR_CONFIG0_CPTR_OVER);
696 seq_printf(s, "%d) ", state);
697
698 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG2);
699 state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMA_MASK);
700 seq_printf(s, "Therm_A/B(%d/", state);
701 state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMB_MASK);
702 seq_printf(s, "%d)\n", (s16)state);
703 }
704
705 r = readl(ts->regs + SENSOR_PDIV);
706 seq_printf(s, "PDIV: 0x%x\n", r);
707
708 r = readl(ts->regs + SENSOR_HOTSPOT_OFF);
709 seq_printf(s, "HOTSPOT: 0x%x\n", r);
710
711 seq_puts(s, "\n");
712 seq_puts(s, "-----SOC_THERM-----\n");
713
714 r = readl(ts->regs + SENSOR_TEMP1);
715 state = REG_GET_MASK(r, SENSOR_TEMP1_CPU_TEMP_MASK);
716 seq_printf(s, "Temperatures: CPU(%d) ", translate_temp(state));
717 state = REG_GET_MASK(r, SENSOR_TEMP1_GPU_TEMP_MASK);
718 seq_printf(s, " GPU(%d) ", translate_temp(state));
719 r = readl(ts->regs + SENSOR_TEMP2);
720 state = REG_GET_MASK(r, SENSOR_TEMP2_PLLX_TEMP_MASK);
721 seq_printf(s, " PLLX(%d) ", translate_temp(state));
722 state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK);
723 seq_printf(s, " MEM(%d)\n", translate_temp(state));
724
Wei Nice0dbf02016-05-11 18:20:17 +0800725 for (i = 0; i < ts->soc->num_ttgs; i++) {
726 seq_printf(s, "%s:\n", ttgs[i]->name);
727 for (level = 0; level < 4; level++) {
728 s32 v;
729 u32 mask;
730 u16 off = ttgs[i]->thermctl_lvl0_offset;
731
732 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
733
734 mask = ttgs[i]->thermctl_lvl0_up_thresh_mask;
735 state = REG_GET_MASK(r, mask);
736 v = sign_extend32(state, ts->soc->bptt - 1);
737 v *= ts->soc->thresh_grain;
738 seq_printf(s, " %d: Up/Dn(%d /", level, v);
739
740 mask = ttgs[i]->thermctl_lvl0_dn_thresh_mask;
741 state = REG_GET_MASK(r, mask);
742 v = sign_extend32(state, ts->soc->bptt - 1);
743 v *= ts->soc->thresh_grain;
744 seq_printf(s, "%d ) ", v);
745
746 mask = THERMCTL_LVL0_CPU0_EN_MASK;
747 state = REG_GET_MASK(r, mask);
748 seq_printf(s, "En(%d) ", state);
749
750 mask = THERMCTL_LVL0_CPU0_CPU_THROT_MASK;
751 state = REG_GET_MASK(r, mask);
752 seq_puts(s, "CPU Throt");
753 if (!state)
754 seq_printf(s, "(%s) ", "none");
755 else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT)
756 seq_printf(s, "(%s) ", "L");
757 else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY)
758 seq_printf(s, "(%s) ", "H");
759 else
760 seq_printf(s, "(%s) ", "H+L");
761
762 mask = THERMCTL_LVL0_CPU0_GPU_THROT_MASK;
763 state = REG_GET_MASK(r, mask);
764 seq_puts(s, "GPU Throt");
765 if (!state)
766 seq_printf(s, "(%s) ", "none");
767 else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT)
768 seq_printf(s, "(%s) ", "L");
769 else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY)
770 seq_printf(s, "(%s) ", "H");
771 else
772 seq_printf(s, "(%s) ", "H+L");
773
774 mask = THERMCTL_LVL0_CPU0_STATUS_MASK;
775 state = REG_GET_MASK(r, mask);
776 seq_printf(s, "Status(%s)\n",
777 state == 0 ? "LO" :
778 state == 1 ? "In" :
779 state == 2 ? "Res" : "HI");
780 }
781 }
782
783 r = readl(ts->regs + THERMCTL_STATS_CTL);
784 seq_printf(s, "STATS: Up(%s) Dn(%s)\n",
785 r & STATS_CTL_EN_UP ? "En" : "--",
786 r & STATS_CTL_EN_DN ? "En" : "--");
787
788 for (level = 0; level < 4; level++) {
789 u16 off;
790
791 off = THERMCTL_LVL0_UP_STATS;
792 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
793 seq_printf(s, " Level_%d Up(%d) ", level, r);
794
795 off = THERMCTL_LVL0_DN_STATS;
796 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));
797 seq_printf(s, "Dn(%d)\n", r);
798 }
799
Wei Ni2a895872016-03-29 18:29:19 +0800800 r = readl(ts->regs + THERMCTL_THERMTRIP_CTL);
801 state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask);
802 seq_printf(s, "Thermtrip Any En(%d)\n", state);
803 for (i = 0; i < ts->soc->num_ttgs; i++) {
804 state = REG_GET_MASK(r, ttgs[i]->thermtrip_enable_mask);
805 seq_printf(s, " %s En(%d) ", ttgs[i]->name, state);
806 state = REG_GET_MASK(r, ttgs[i]->thermtrip_threshold_mask);
807 state *= ts->soc->thresh_grain;
808 seq_printf(s, "Thresh(%d)\n", state);
809 }
810
Wei Nice0dbf02016-05-11 18:20:17 +0800811 r = readl(ts->regs + THROT_GLOBAL_CFG);
812 seq_puts(s, "\n");
813 seq_printf(s, "GLOBAL THROTTLE CONFIG: 0x%08x\n", r);
814
815 seq_puts(s, "---------------------------------------------------\n");
816 r = readl(ts->regs + THROT_STATUS);
817 state = REG_GET_MASK(r, THROT_STATUS_BREACH_MASK);
818 seq_printf(s, "THROT STATUS: breach(%d) ", state);
819 state = REG_GET_MASK(r, THROT_STATUS_STATE_MASK);
820 seq_printf(s, "state(%d) ", state);
821 state = REG_GET_MASK(r, THROT_STATUS_ENABLED_MASK);
822 seq_printf(s, "enabled(%d)\n", state);
823
824 r = readl(ts->regs + CPU_PSKIP_STATUS);
Wei Ni6c7c3242016-05-11 18:20:18 +0800825 if (ts->soc->use_ccroc) {
826 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
827 seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state);
828 } else {
829 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK);
830 seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state);
831 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK);
832 seq_printf(s, "N(%d) ", state);
833 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);
834 seq_printf(s, "enabled(%d)\n", state);
835 }
Wei Nice0dbf02016-05-11 18:20:17 +0800836
Wei Nid753b222016-03-29 18:29:16 +0800837 return 0;
838}
839
840static int regs_open(struct inode *inode, struct file *file)
841{
842 return single_open(file, regs_show, inode->i_private);
843}
844
845static const struct file_operations regs_fops = {
846 .open = regs_open,
847 .read = seq_read,
848 .llseek = seq_lseek,
849 .release = single_release,
850};
851
852static void soctherm_debug_init(struct platform_device *pdev)
853{
854 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
855 struct dentry *root, *file;
856
857 root = debugfs_create_dir("soctherm", NULL);
858 if (!root) {
859 dev_err(&pdev->dev, "failed to create debugfs directory\n");
860 return;
861 }
862
863 tegra->debugfs_dir = root;
864
865 file = debugfs_create_file("reg_contents", 0644, root,
866 pdev, &regs_fops);
867 if (!file) {
868 dev_err(&pdev->dev, "failed to create debugfs file\n");
869 debugfs_remove_recursive(tegra->debugfs_dir);
870 tegra->debugfs_dir = NULL;
871 }
872}
873#else
874static inline void soctherm_debug_init(struct platform_device *pdev) {}
875#endif
876
Wei Ni8de2ab02016-03-29 18:29:20 +0800877static int soctherm_clk_enable(struct platform_device *pdev, bool enable)
878{
879 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
880 int err;
881
882 if (!tegra->clock_soctherm || !tegra->clock_tsensor)
883 return -EINVAL;
884
885 reset_control_assert(tegra->reset);
886
887 if (enable) {
888 err = clk_prepare_enable(tegra->clock_soctherm);
889 if (err) {
890 reset_control_deassert(tegra->reset);
891 return err;
892 }
893
894 err = clk_prepare_enable(tegra->clock_tsensor);
895 if (err) {
896 clk_disable_unprepare(tegra->clock_soctherm);
897 reset_control_deassert(tegra->reset);
898 return err;
899 }
900 } else {
901 clk_disable_unprepare(tegra->clock_tsensor);
902 clk_disable_unprepare(tegra->clock_soctherm);
903 }
904
905 reset_control_deassert(tegra->reset);
906
907 return 0;
908}
909
Wei Nice0dbf02016-05-11 18:20:17 +0800910static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev,
911 unsigned long *max_state)
912{
913 *max_state = 1;
914 return 0;
915}
916
917static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev,
918 unsigned long *cur_state)
919{
920 struct tegra_soctherm *ts = cdev->devdata;
921 u32 r;
922
923 r = readl(ts->regs + THROT_STATUS);
924 if (REG_GET_MASK(r, THROT_STATUS_STATE_MASK))
925 *cur_state = 1;
926 else
927 *cur_state = 0;
928
929 return 0;
930}
931
932static int throt_set_cdev_state(struct thermal_cooling_device *cdev,
933 unsigned long cur_state)
934{
935 return 0;
936}
937
938static struct thermal_cooling_device_ops throt_cooling_ops = {
939 .get_max_state = throt_get_cdev_max_state,
940 .get_cur_state = throt_get_cdev_cur_state,
941 .set_cur_state = throt_set_cdev_state,
942};
943
944/**
945 * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
946 * and register them as cooling devices.
947 */
948static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
949{
950 struct device *dev = &pdev->dev;
951 struct tegra_soctherm *ts = dev_get_drvdata(dev);
952 struct device_node *np_stc, *np_stcc;
953 const char *name;
954 u32 val;
955 int i, r;
956
957 for (i = 0; i < THROTTLE_SIZE; i++) {
958 ts->throt_cfgs[i].name = throt_names[i];
959 ts->throt_cfgs[i].id = i;
960 ts->throt_cfgs[i].init = false;
961 }
962
963 np_stc = of_get_child_by_name(dev->of_node, "throttle-cfgs");
964 if (!np_stc) {
965 dev_info(dev,
966 "throttle-cfg: no throttle-cfgs - not enabling\n");
967 return;
968 }
969
970 for_each_child_of_node(np_stc, np_stcc) {
971 struct soctherm_throt_cfg *stc;
972 struct thermal_cooling_device *tcd;
973
974 name = np_stcc->name;
975 stc = find_throttle_cfg_by_name(ts, name);
976 if (!stc) {
977 dev_err(dev,
978 "throttle-cfg: could not find %s\n", name);
979 continue;
980 }
981
982 r = of_property_read_u32(np_stcc, "nvidia,priority", &val);
983 if (r) {
984 dev_info(dev,
985 "throttle-cfg: %s: missing priority\n", name);
986 continue;
987 }
988 stc->priority = val;
989
Wei Ni6c7c3242016-05-11 18:20:18 +0800990 if (ts->soc->use_ccroc) {
991 r = of_property_read_u32(np_stcc,
992 "nvidia,cpu-throt-level",
993 &val);
994 if (r) {
995 dev_info(dev,
996 "throttle-cfg: %s: missing cpu-throt-level\n",
997 name);
998 continue;
999 }
1000 stc->cpu_throt_level = val;
1001 } else {
1002 r = of_property_read_u32(np_stcc,
1003 "nvidia,cpu-throt-percent",
1004 &val);
1005 if (r) {
1006 dev_info(dev,
1007 "throttle-cfg: %s: missing cpu-throt-percent\n",
1008 name);
1009 continue;
1010 }
1011 stc->cpu_throt_depth = val;
Wei Nice0dbf02016-05-11 18:20:17 +08001012 }
Wei Nice0dbf02016-05-11 18:20:17 +08001013
1014 tcd = thermal_of_cooling_device_register(np_stcc,
1015 (char *)name, ts,
1016 &throt_cooling_ops);
1017 of_node_put(np_stcc);
1018 if (IS_ERR_OR_NULL(tcd)) {
1019 dev_err(dev,
1020 "throttle-cfg: %s: failed to register cooling device\n",
1021 name);
1022 continue;
1023 }
1024
1025 stc->cdev = tcd;
1026 stc->init = true;
1027 }
1028
1029 of_node_put(np_stc);
1030}
1031
1032/**
Wei Ni6c7c3242016-05-11 18:20:18 +08001033 * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config
1034 * @level: describing the level LOW/MED/HIGH of throttling
1035 *
1036 * It's necessary to set up the CPU-local CCROC NV_THERM instance with
1037 * the M/N values desired for each level. This function does this.
1038 *
1039 * This function pre-programs the CCROC NV_THERM levels in terms of
1040 * pre-configured "Low", "Medium" or "Heavy" throttle levels which are
1041 * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY.
1042 */
1043static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level)
1044{
1045 u8 depth, dividend;
1046 u32 r;
1047
1048 switch (level) {
1049 case TEGRA_SOCTHERM_THROT_LEVEL_LOW:
1050 depth = 50;
1051 break;
1052 case TEGRA_SOCTHERM_THROT_LEVEL_MED:
1053 depth = 75;
1054 break;
1055 case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:
1056 depth = 80;
1057 break;
1058 case TEGRA_SOCTHERM_THROT_LEVEL_NONE:
1059 return;
1060 default:
1061 return;
1062 }
1063
1064 dividend = THROT_DEPTH_DIVIDEND(depth);
1065
1066 /* setup PSKIP in ccroc nv_therm registers */
1067 r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));
1068 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff);
1069 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf);
1070 ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));
1071
1072 r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));
1073 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1);
1074 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);
1075 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);
1076 ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));
1077}
1078
1079/**
1080 * throttlectl_cpu_level_select() - program CPU pulse skipper config
1081 * @throt: the LIGHT/HEAVY of throttle event id
1082 *
1083 * Pulse skippers are used to throttle clock frequencies. This
1084 * function programs the pulse skippers based on @throt and platform
1085 * data. This function is used on SoCs which have CPU-local pulse
1086 * skipper control, such as T13x. It programs soctherm's interface to
1087 * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling
1088 * vectors. PSKIP_BYPASS mode is set as required per HW spec.
1089 */
1090static void throttlectl_cpu_level_select(struct tegra_soctherm *ts,
1091 enum soctherm_throttle_id throt)
1092{
1093 u32 r, throt_vect;
1094
1095 /* Denver:CCROC NV_THERM interface N:3 Mapping */
1096 switch (ts->throt_cfgs[throt].cpu_throt_level) {
1097 case TEGRA_SOCTHERM_THROT_LEVEL_LOW:
1098 throt_vect = THROT_VECT_LOW;
1099 break;
1100 case TEGRA_SOCTHERM_THROT_LEVEL_MED:
1101 throt_vect = THROT_VECT_MED;
1102 break;
1103 case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:
1104 throt_vect = THROT_VECT_HIGH;
1105 break;
1106 default:
1107 throt_vect = THROT_VECT_NONE;
1108 break;
1109 }
1110
1111 r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
1112 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
1113 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect);
1114 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect);
1115 writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
1116
1117 /* bypass sequencer in soc_therm as it is programmed in ccroc */
1118 r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1);
1119 writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
1120}
1121
1122/**
Wei Nice0dbf02016-05-11 18:20:17 +08001123 * throttlectl_cpu_mn() - program CPU pulse skipper configuration
1124 * @throt: the LIGHT/HEAVY of throttle event id
1125 *
1126 * Pulse skippers are used to throttle clock frequencies. This
1127 * function programs the pulse skippers based on @throt and platform
1128 * data. This function is used for CPUs that have "remote" pulse
1129 * skipper control, e.g., the CPU pulse skipper is controlled by the
1130 * SOC_THERM IP block. (SOC_THERM is located outside the CPU
1131 * complex.)
1132 */
1133static void throttlectl_cpu_mn(struct tegra_soctherm *ts,
1134 enum soctherm_throttle_id throt)
1135{
1136 u32 r;
1137 int depth;
1138 u8 dividend;
1139
1140 depth = ts->throt_cfgs[throt].cpu_throt_depth;
1141 dividend = THROT_DEPTH_DIVIDEND(depth);
1142
1143 r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
1144 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
1145 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);
1146 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);
1147 writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));
1148
1149 r = readl(ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
1150 r = REG_SET_MASK(r, THROT_PSKIP_RAMP_DURATION_MASK, 0xff);
1151 r = REG_SET_MASK(r, THROT_PSKIP_RAMP_STEP_MASK, 0xf);
1152 writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));
1153}
1154
1155/**
1156 * soctherm_throttle_program() - programs pulse skippers' configuration
1157 * @throt: the LIGHT/HEAVY of the throttle event id.
1158 *
1159 * Pulse skippers are used to throttle clock frequencies.
1160 * This function programs the pulse skippers.
1161 */
1162static void soctherm_throttle_program(struct tegra_soctherm *ts,
1163 enum soctherm_throttle_id throt)
1164{
1165 u32 r;
1166 struct soctherm_throt_cfg stc = ts->throt_cfgs[throt];
1167
1168 if (!stc.init)
1169 return;
1170
1171 /* Setup PSKIP parameters */
Wei Ni6c7c3242016-05-11 18:20:18 +08001172 if (ts->soc->use_ccroc)
1173 throttlectl_cpu_level_select(ts, throt);
1174 else
1175 throttlectl_cpu_mn(ts, throt);
Wei Nice0dbf02016-05-11 18:20:17 +08001176
1177 r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
1178 writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));
1179
1180 r = REG_SET_MASK(0, THROT_DELAY_LITE_DELAY_MASK, 0);
1181 writel(r, ts->regs + THROT_DELAY_CTRL(throt));
1182
1183 r = readl(ts->regs + THROT_PRIORITY_LOCK);
1184 r = REG_GET_MASK(r, THROT_PRIORITY_LOCK_PRIORITY_MASK);
1185 if (r >= stc.priority)
1186 return;
1187 r = REG_SET_MASK(0, THROT_PRIORITY_LOCK_PRIORITY_MASK,
1188 stc.priority);
1189 writel(r, ts->regs + THROT_PRIORITY_LOCK);
1190}
1191
1192static void tegra_soctherm_throttle(struct device *dev)
1193{
1194 struct tegra_soctherm *ts = dev_get_drvdata(dev);
1195 u32 v;
1196 int i;
1197
Wei Ni6c7c3242016-05-11 18:20:18 +08001198 /* configure LOW, MED and HIGH levels for CCROC NV_THERM */
1199 if (ts->soc->use_ccroc) {
1200 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW);
1201 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED);
1202 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH);
1203 }
1204
Wei Nice0dbf02016-05-11 18:20:17 +08001205 /* Thermal HW throttle programming */
1206 for (i = 0; i < THROTTLE_SIZE; i++)
1207 soctherm_throttle_program(ts, i);
1208
1209 v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1);
Wei Ni6c7c3242016-05-11 18:20:18 +08001210 if (ts->soc->use_ccroc) {
1211 ccroc_writel(ts, v, CCROC_GLOBAL_CFG);
Wei Nice0dbf02016-05-11 18:20:17 +08001212
Wei Ni6c7c3242016-05-11 18:20:18 +08001213 v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER);
1214 v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);
1215 ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER);
1216 } else {
1217 writel(v, ts->regs + THROT_GLOBAL_CFG);
1218
1219 v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER);
1220 v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);
1221 clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER);
1222 }
Wei Nice0dbf02016-05-11 18:20:17 +08001223
1224 /* initialize stats collection */
1225 v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN |
1226 STATS_CTL_CLR_UP | STATS_CTL_EN_UP;
1227 writel(v, ts->regs + THERMCTL_STATS_CTL);
1228}
1229
Wei Ni1ed895c2016-03-29 18:29:21 +08001230static void soctherm_init(struct platform_device *pdev)
1231{
1232 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
1233 const struct tegra_tsensor_group **ttgs = tegra->soc->ttgs;
1234 int i;
1235 u32 pdiv, hotspot;
1236
1237 /* Initialize raw sensors */
1238 for (i = 0; i < tegra->soc->num_tsensors; ++i)
1239 enable_tsensor(tegra, i);
1240
1241 /* program pdiv and hotspot offsets per THERM */
1242 pdiv = readl(tegra->regs + SENSOR_PDIV);
1243 hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF);
1244 for (i = 0; i < tegra->soc->num_ttgs; ++i) {
1245 pdiv = REG_SET_MASK(pdiv, ttgs[i]->pdiv_mask,
1246 ttgs[i]->pdiv);
1247 /* hotspot offset from PLLX, doesn't need to configure PLLX */
1248 if (ttgs[i]->id == TEGRA124_SOCTHERM_SENSOR_PLLX)
1249 continue;
1250 hotspot = REG_SET_MASK(hotspot,
1251 ttgs[i]->pllx_hotspot_mask,
1252 ttgs[i]->pllx_hotspot_diff);
1253 }
1254 writel(pdiv, tegra->regs + SENSOR_PDIV);
1255 writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);
Wei Nice0dbf02016-05-11 18:20:17 +08001256
Wei Nice0dbf02016-05-11 18:20:17 +08001257 /* Configure hw throttle */
1258 tegra_soctherm_throttle(&pdev->dev);
Wei Ni1ed895c2016-03-29 18:29:21 +08001259}
1260
Wei Ni65b6d572016-03-29 18:29:14 +08001261static const struct of_device_id tegra_soctherm_of_match[] = {
1262#ifdef CONFIG_ARCH_TEGRA_124_SOC
1263 {
1264 .compatible = "nvidia,tegra124-soctherm",
1265 .data = &tegra124_soctherm,
1266 },
1267#endif
Wei Ni44cb6a72016-04-27 11:25:46 +08001268#ifdef CONFIG_ARCH_TEGRA_132_SOC
1269 {
1270 .compatible = "nvidia,tegra132-soctherm",
1271 .data = &tegra132_soctherm,
1272 },
1273#endif
Wei Ni82041042016-03-29 18:29:15 +08001274#ifdef CONFIG_ARCH_TEGRA_210_SOC
1275 {
1276 .compatible = "nvidia,tegra210-soctherm",
1277 .data = &tegra210_soctherm,
1278 },
1279#endif
Wei Ni65b6d572016-03-29 18:29:14 +08001280 { },
1281};
1282MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
1283
1284static int tegra_soctherm_probe(struct platform_device *pdev)
1285{
1286 const struct of_device_id *match;
1287 struct tegra_soctherm *tegra;
1288 struct thermal_zone_device *z;
1289 struct tsensor_shared_calib shared_calib;
1290 struct resource *res;
1291 struct tegra_soctherm_soc *soc;
1292 unsigned int i;
1293 int err;
Wei Ni65b6d572016-03-29 18:29:14 +08001294
1295 match = of_match_node(tegra_soctherm_of_match, pdev->dev.of_node);
1296 if (!match)
1297 return -ENODEV;
1298
1299 soc = (struct tegra_soctherm_soc *)match->data;
1300 if (soc->num_ttgs > TEGRA124_SOCTHERM_SENSOR_NUM)
1301 return -EINVAL;
1302
1303 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
1304 if (!tegra)
1305 return -ENOMEM;
1306
1307 dev_set_drvdata(&pdev->dev, tegra);
1308
1309 tegra->soc = soc;
1310
Wei Nice0dbf02016-05-11 18:20:17 +08001311 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1312 "soctherm-reg");
Wei Ni65b6d572016-03-29 18:29:14 +08001313 tegra->regs = devm_ioremap_resource(&pdev->dev, res);
Wei Nice0dbf02016-05-11 18:20:17 +08001314 if (IS_ERR(tegra->regs)) {
1315 dev_err(&pdev->dev, "can't get soctherm registers");
Wei Ni65b6d572016-03-29 18:29:14 +08001316 return PTR_ERR(tegra->regs);
Wei Nice0dbf02016-05-11 18:20:17 +08001317 }
1318
1319 if (!tegra->soc->use_ccroc) {
1320 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1321 "car-reg");
1322 tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res);
1323 if (IS_ERR(tegra->clk_regs)) {
1324 dev_err(&pdev->dev, "can't get car clk registers");
1325 return PTR_ERR(tegra->clk_regs);
1326 }
Wei Ni6c7c3242016-05-11 18:20:18 +08001327 } else {
1328 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1329 "ccroc-reg");
1330 tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res);
1331 if (IS_ERR(tegra->ccroc_regs)) {
1332 dev_err(&pdev->dev, "can't get ccroc registers");
1333 return PTR_ERR(tegra->ccroc_regs);
1334 }
Wei Nice0dbf02016-05-11 18:20:17 +08001335 }
Wei Ni65b6d572016-03-29 18:29:14 +08001336
1337 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
1338 if (IS_ERR(tegra->reset)) {
1339 dev_err(&pdev->dev, "can't get soctherm reset\n");
1340 return PTR_ERR(tegra->reset);
1341 }
1342
1343 tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
1344 if (IS_ERR(tegra->clock_tsensor)) {
1345 dev_err(&pdev->dev, "can't get tsensor clock\n");
1346 return PTR_ERR(tegra->clock_tsensor);
1347 }
1348
1349 tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
1350 if (IS_ERR(tegra->clock_soctherm)) {
1351 dev_err(&pdev->dev, "can't get soctherm clock\n");
1352 return PTR_ERR(tegra->clock_soctherm);
1353 }
1354
Wei Ni1ed895c2016-03-29 18:29:21 +08001355 tegra->calib = devm_kzalloc(&pdev->dev,
1356 sizeof(u32) * soc->num_tsensors,
1357 GFP_KERNEL);
1358 if (!tegra->calib)
1359 return -ENOMEM;
1360
1361 /* calculate shared calibration data */
1362 err = tegra_calc_shared_calib(soc->tfuse, &shared_calib);
1363 if (err)
1364 return err;
1365
1366 /* calculate tsensor calibaration data */
1367 for (i = 0; i < soc->num_tsensors; ++i) {
1368 err = tegra_calc_tsensor_calib(&soc->tsensors[i],
1369 &shared_calib,
1370 &tegra->calib[i]);
1371 if (err)
1372 return err;
1373 }
1374
Wei Nif09d6982016-03-29 18:29:22 +08001375 tegra->thermctl_tzs = devm_kzalloc(&pdev->dev,
1376 sizeof(*z) * soc->num_ttgs,
1377 GFP_KERNEL);
1378 if (!tegra->thermctl_tzs)
1379 return -ENOMEM;
1380
Wei Ni8de2ab02016-03-29 18:29:20 +08001381 err = soctherm_clk_enable(pdev, true);
Wei Ni65b6d572016-03-29 18:29:14 +08001382 if (err)
1383 return err;
1384
Wei Ni6c7c3242016-05-11 18:20:18 +08001385 soctherm_init_hw_throt_cdev(pdev);
Wei Nice0dbf02016-05-11 18:20:17 +08001386
Wei Ni1ed895c2016-03-29 18:29:21 +08001387 soctherm_init(pdev);
Wei Ni65b6d572016-03-29 18:29:14 +08001388
Wei Ni65b6d572016-03-29 18:29:14 +08001389 for (i = 0; i < soc->num_ttgs; ++i) {
1390 struct tegra_thermctl_zone *zone =
1391 devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
1392 if (!zone) {
1393 err = -ENOMEM;
1394 goto disable_clocks;
1395 }
1396
1397 zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;
Wei Ni2a895872016-03-29 18:29:19 +08001398 zone->dev = &pdev->dev;
1399 zone->sg = soc->ttgs[i];
Wei Nice0dbf02016-05-11 18:20:17 +08001400 zone->ts = tegra;
Wei Ni65b6d572016-03-29 18:29:14 +08001401
1402 z = devm_thermal_zone_of_sensor_register(&pdev->dev,
1403 soc->ttgs[i]->id, zone,
1404 &tegra_of_thermal_ops);
1405 if (IS_ERR(z)) {
1406 err = PTR_ERR(z);
1407 dev_err(&pdev->dev, "failed to register sensor: %d\n",
1408 err);
1409 goto disable_clocks;
1410 }
Wei Ni2a895872016-03-29 18:29:19 +08001411
1412 zone->tz = z;
Wei Nif09d6982016-03-29 18:29:22 +08001413 tegra->thermctl_tzs[soc->ttgs[i]->id] = z;
Wei Ni2a895872016-03-29 18:29:19 +08001414
1415 /* Configure hw trip points */
Wei Nice0dbf02016-05-11 18:20:17 +08001416 err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);
1417 if (err)
1418 goto disable_clocks;
Wei Ni65b6d572016-03-29 18:29:14 +08001419 }
1420
Wei Nid753b222016-03-29 18:29:16 +08001421 soctherm_debug_init(pdev);
1422
Wei Ni65b6d572016-03-29 18:29:14 +08001423 return 0;
1424
1425disable_clocks:
Wei Ni8de2ab02016-03-29 18:29:20 +08001426 soctherm_clk_enable(pdev, false);
Wei Ni65b6d572016-03-29 18:29:14 +08001427
1428 return err;
1429}
1430
1431static int tegra_soctherm_remove(struct platform_device *pdev)
1432{
1433 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
1434
Wei Nid753b222016-03-29 18:29:16 +08001435 debugfs_remove_recursive(tegra->debugfs_dir);
1436
Wei Ni8de2ab02016-03-29 18:29:20 +08001437 soctherm_clk_enable(pdev, false);
Wei Ni65b6d572016-03-29 18:29:14 +08001438
1439 return 0;
1440}
1441
Arnd Bergmanna977c412016-04-16 22:19:33 +02001442static int __maybe_unused soctherm_suspend(struct device *dev)
Wei Nif09d6982016-03-29 18:29:22 +08001443{
1444 struct platform_device *pdev = to_platform_device(dev);
1445
1446 soctherm_clk_enable(pdev, false);
1447
1448 return 0;
1449}
1450
Arnd Bergmanna977c412016-04-16 22:19:33 +02001451static int __maybe_unused soctherm_resume(struct device *dev)
Wei Nif09d6982016-03-29 18:29:22 +08001452{
1453 struct platform_device *pdev = to_platform_device(dev);
1454 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
1455 struct tegra_soctherm_soc *soc = tegra->soc;
1456 int err, i;
1457
1458 err = soctherm_clk_enable(pdev, true);
1459 if (err) {
1460 dev_err(&pdev->dev,
1461 "Resume failed: enable clocks failed\n");
1462 return err;
1463 }
1464
1465 soctherm_init(pdev);
1466
1467 for (i = 0; i < soc->num_ttgs; ++i) {
1468 struct thermal_zone_device *tz;
1469
1470 tz = tegra->thermctl_tzs[soc->ttgs[i]->id];
Wei Nice0dbf02016-05-11 18:20:17 +08001471 err = tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz);
1472 if (err) {
1473 dev_err(&pdev->dev,
1474 "Resume failed: set hwtrips failed\n");
1475 return err;
1476 }
Wei Nif09d6982016-03-29 18:29:22 +08001477 }
1478
1479 return 0;
1480}
1481
1482static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume);
1483
Wei Ni65b6d572016-03-29 18:29:14 +08001484static struct platform_driver tegra_soctherm_driver = {
1485 .probe = tegra_soctherm_probe,
1486 .remove = tegra_soctherm_remove,
1487 .driver = {
1488 .name = "tegra_soctherm",
Wei Nif09d6982016-03-29 18:29:22 +08001489 .pm = &tegra_soctherm_pm,
Wei Ni65b6d572016-03-29 18:29:14 +08001490 .of_match_table = tegra_soctherm_of_match,
1491 },
1492};
1493module_platform_driver(tegra_soctherm_driver);
1494
1495MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
1496MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
1497MODULE_LICENSE("GPL v2");