@@ -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+
248299static bool
249300tegra_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,
269320static 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