Skip to content

Commit 64b3693

Browse files
committed
WIP: thermal/drivers/tegra30: Support CPU DIV2 frequency throttling
Expose Tegra30 thermal sensor as a cooling device and enable hardware-assisted DIV2 CPU frequency throttling. The DIV2 cooling is activated by hardware while the breach of hot temperature trip is detected by sensor. Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
1 parent 334a711 commit 64b3693

1 file changed

Lines changed: 71 additions & 8 deletions

File tree

drivers/thermal/tegra/tegra30-tsensor.c

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct tegra_tsensor {
8585
struct device *dev;
8686
struct reset_control *rst;
8787
struct tegra_tsensor_channel ch[2];
88+
struct thermal_cooling_device *cdev;
8889
struct tegra_tsensor_calibration_data calib;
8990
};
9091

@@ -245,6 +246,56 @@ static const struct thermal_zone_of_device_ops ops = {
245246
.set_trips = tegra_tsensor_set_trips,
246247
};
247248

249+
static int tegra_tsensor_get_max_state(struct thermal_cooling_device *cdev,
250+
unsigned long *state)
251+
{
252+
*state = 1;
253+
254+
return 0;
255+
}
256+
257+
static bool tegra_tsensor_channel_div2_active(const struct tegra_tsensor *ts,
258+
unsigned int id)
259+
{
260+
u32 val;
261+
262+
val = readl_relaxed(ts->ch[id].regs + TSENSOR_SENSOR0_CONFIG0);
263+
if (!FIELD_GET(TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN, val))
264+
return false;
265+
266+
val = readl_relaxed(ts->ch[id].regs + TSENSOR_SENSOR0_STATUS0);
267+
268+
/* CPU frequency is halved when LEVEL2 is breached */
269+
return FIELD_GET(TSENSOR_SENSOR0_STATUS0_STATE, val) > 2;
270+
}
271+
272+
static int tegra_tsensor_get_cur_state(struct thermal_cooling_device *cdev,
273+
unsigned long *state)
274+
{
275+
const struct tegra_tsensor *ts = cdev->devdata;
276+
unsigned int i, div2_state = 0;
277+
278+
for (i = 0; i < ARRAY_SIZE(ts->ch); i++)
279+
div2_state |= tegra_tsensor_channel_div2_active(ts, i);
280+
281+
*state = div2_state;
282+
283+
return 0;
284+
}
285+
286+
static int tegra_tsensor_set_cur_state(struct thermal_cooling_device *cdev,
287+
unsigned long state)
288+
{
289+
/* state is controlled by hardware and can't be changed by software */
290+
return -EOPNOTSUPP;
291+
}
292+
293+
static const struct thermal_cooling_device_ops tegra_tsensor_cpu_cooling_ops = {
294+
.get_max_state = tegra_tsensor_get_max_state,
295+
.get_cur_state = tegra_tsensor_get_cur_state,
296+
.set_cur_state = tegra_tsensor_set_cur_state,
297+
};
298+
248299
static bool
249300
tegra_tsensor_handle_channel_interrupt(const struct tegra_tsensor *ts,
250301
unsigned int id)
@@ -269,11 +320,16 @@ tegra_tsensor_handle_channel_interrupt(const struct tegra_tsensor *ts,
269320
static irqreturn_t tegra_tsensor_isr(int irq, void *data)
270321
{
271322
const struct tegra_tsensor *ts = data;
323+
bool div2_state = false;
272324
bool handled = false;
273325
unsigned int i;
274326

275-
for (i = 0; i < ARRAY_SIZE(ts->ch); i++)
276-
handled |= tegra_tsensor_handle_channel_interrupt(ts, i);
327+
for (i = 0; i < ARRAY_SIZE(ts->ch); i++) {
328+
div2_state |= tegra_tsensor_channel_div2_active(ts, i);
329+
handled |= tegra_tsensor_handle_channel_interrupt(ts, i);
330+
}
331+
332+
thermal_cooling_device_stats_update(ts->cdev, div2_state);
277333

278334
return handled ? IRQ_HANDLED : IRQ_NONE;
279335
}
@@ -364,6 +420,9 @@ static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
364420
/* prevent potential racing with tegra_tsensor_set_trips() */
365421
mutex_lock(&tzd->lock);
366422

423+
dev_info_once(ts->dev, "ch%u: CPU freq div2 throttle trip set to %dC\n",
424+
id, DIV_ROUND_CLOSEST(hot_trip, 1000));
425+
367426
dev_info_once(ts->dev, "ch%u: PMC emergency shutdown trip set to %dC\n",
368427
id, DIV_ROUND_CLOSEST(crit_trip, 1000));
369428

@@ -383,11 +442,8 @@ static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
383442
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG2);
384443

385444
/*
386-
* Enable sensor, emergency shutdown, interrupts for level 1/2/3
387-
* breaches and counter overflow condition.
388-
*
389-
* Disable DIV2 throttle for now since we need to figure out how
390-
* to integrate it properly with the thermal framework.
445+
* Enable sensor, DIV2 throttle, emergency shutdown, interrupts
446+
* for level 1/2/3 breaches and counter overflow condition.
391447
*
392448
* Thermal levels supported by hardware:
393449
*
@@ -399,7 +455,7 @@ static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
399455
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0);
400456
val &= ~TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP;
401457
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_DVFS_EN, 1);
402-
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN, 0);
458+
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN, 1);
403459
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_THERMAL_RST_EN, 1);
404460
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_OVERFLOW_EN, 1);
405461
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_HW_FREQ_DIV_EN, 1);
@@ -587,6 +643,13 @@ static int tegra_tsensor_probe(struct platform_device *pdev)
587643
return err;
588644
}
589645

646+
ts->cdev = devm_thermal_of_cooling_device_register(&pdev->dev,
647+
pdev->dev.of_node, "tegra-cpu-div2-throttle",
648+
ts, &tegra_tsensor_cpu_cooling_ops);
649+
if (IS_ERR(ts->cdev))
650+
return dev_err_probe(&pdev->dev, PTR_ERR(ts->cdev),
651+
"failed to register cooling device\n");
652+
590653
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
591654
tegra_tsensor_isr, IRQF_ONESHOT,
592655
"tegra_tsensor", ts);

0 commit comments

Comments
 (0)