1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-3-08 GuEe-GUI the first version
9 */
10
11 #include <drivers/platform.h>
12
13 #define DBG_TAG "rtdm.thermal"
14 #define DBG_LVL DBG_INFO
15 #include <rtdbg.h>
16
17 #include "thermal_dm.h"
18
19 #ifndef INT_MAX
20 #define INT_MAX (RT_UINT32_MAX >> 1)
21 #endif
22
23 #define device_list(dev) (dev)->parent.parent.list
24 #define device_foreach(dev, nodes) rt_list_for_each_entry(dev, nodes, parent.parent.list)
25
26 static RT_DEFINE_SPINLOCK(nodes_lock);
27 static rt_list_t thermal_zone_device_nodes = RT_LIST_OBJECT_INIT(thermal_zone_device_nodes);
28 static rt_list_t thermal_cooling_device_nodes = RT_LIST_OBJECT_INIT(thermal_cooling_device_nodes);
29 static rt_list_t thermal_cooling_governor_nodes = RT_LIST_OBJECT_INIT(thermal_cooling_governor_nodes);
30
31 #ifdef RT_USING_OFW
thermal_ofw_params_parse(struct rt_ofw_node * np,struct rt_thermal_zone_params * tz_params)32 static void thermal_ofw_params_parse(struct rt_ofw_node *np,
33 struct rt_thermal_zone_params *tz_params)
34 {
35 rt_uint32_t coef[2], prop;
36
37 if (!np)
38 {
39 return;
40 }
41
42 if (!rt_ofw_prop_read_u32(np, "sustainable-power", &prop))
43 {
44 tz_params->sustainable_power = prop;
45 }
46
47 /*
48 * For now, the thermal framework supports only one sensor per thermal zone.
49 * Thus, we are considering only the first two values as slope and offset.
50 */
51 if (rt_ofw_prop_read_u32_array_index(np, "coefficients", 0, 2, coef) < 0)
52 {
53 coef[0] = 1;
54 coef[1] = 0;
55 }
56
57 tz_params->slope = coef[0];
58 tz_params->offset = coef[1];
59 }
60
thermal_ofw_setup(struct rt_ofw_node * np,struct rt_thermal_zone_device * zdev)61 static void thermal_ofw_setup(struct rt_ofw_node *np, struct rt_thermal_zone_device *zdev)
62 {
63 int i = 0;
64 rt_uint32_t delay, pdelay;
65 struct rt_ofw_cell_args args;
66 struct rt_ofw_node *tmp_np, *tz_np, *trip_np, *cm_np, *cdev_np;
67
68 if (!np || !zdev)
69 {
70 return;
71 }
72
73 tmp_np = rt_ofw_find_node_by_path("/thermal-zones");
74
75 if (!tmp_np)
76 {
77 return;
78 }
79
80 rt_ofw_foreach_child_node(tmp_np, tz_np)
81 {
82 if (!rt_ofw_parse_phandle_cells(tz_np, "thermal-sensors", "#thermal-sensor-cells", 0, &args))
83 {
84 if (args.data == np && (!args.args_count || args.args[0] == zdev->zone_id))
85 {
86 rt_ofw_node_put(args.data);
87
88 goto _found;
89 }
90 rt_ofw_node_put(args.data);
91 }
92 }
93
94 return;
95
96 _found:
97 rt_ofw_prop_read_u32(tz_np, "polling-delay-passive", &pdelay);
98 rt_ofw_prop_read_u32(tz_np, "polling-delay", &delay);
99
100 zdev->passive_delay = rt_tick_from_millisecond(pdelay);
101 zdev->polling_delay = rt_tick_from_millisecond(delay);
102
103 thermal_ofw_params_parse(tz_np, &zdev->params);
104
105 if (zdev->trips_nr)
106 {
107 goto _scan_cooling;
108 }
109
110 tmp_np = rt_ofw_get_child_by_tag(tz_np, "trips");
111 if (!tmp_np)
112 {
113 goto _scan_cooling;
114 }
115
116 zdev->trips_nr = rt_ofw_get_child_count(tmp_np);
117 if (!zdev->trips_nr)
118 {
119 goto _scan_cooling;
120 }
121 zdev->trips = rt_calloc(zdev->trips_nr, sizeof(*zdev->trips));
122 zdev->trips_free = RT_TRUE;
123
124 if (!zdev->trips)
125 {
126 LOG_E("%s: No memory to create %s", rt_ofw_node_full_name(np), "trips");
127 RT_ASSERT(0);
128 }
129
130 rt_ofw_foreach_child_node(tmp_np, trip_np)
131 {
132 const char *type;
133
134 rt_ofw_prop_read_u32(trip_np, "temperature", (rt_uint32_t *)&zdev->trips[i].temperature);
135 rt_ofw_prop_read_u32(trip_np, "hysteresis", (rt_uint32_t *)&zdev->trips[i].hysteresis);
136 rt_ofw_prop_read_string(trip_np, "type", &type);
137 zdev->trips[i].type = thermal_type(type);
138
139 rt_ofw_data(trip_np) = &zdev->trips[i];
140
141 ++i;
142 }
143
144 _scan_cooling:
145 i = 0;
146 tmp_np = rt_ofw_get_child_by_tag(tz_np, "cooling-maps");
147 if (!tmp_np)
148 {
149 goto _end;
150 }
151
152 zdev->cooling_maps_nr = rt_ofw_get_child_count(tmp_np);
153 if (!zdev->cooling_maps_nr)
154 {
155 goto _end;
156 }
157 zdev->cooling_maps = rt_calloc(zdev->cooling_maps_nr, sizeof(*zdev->cooling_maps));
158
159 if (!zdev->cooling_maps)
160 {
161 LOG_E("%s: No memory to create %s", rt_ofw_node_full_name(np), "cooling_maps");
162 RT_ASSERT(0);
163 }
164
165 rt_ofw_foreach_child_node(tmp_np, cm_np)
166 {
167 struct rt_thermal_cooling_device *cdev;
168 struct rt_thermal_cooling_map *map = &zdev->cooling_maps[i++];
169
170 map->cells_nr = rt_ofw_count_phandle_cells(cm_np, "cooling-device", "#cooling-cells");
171 map->cells = rt_calloc(sizeof(*map->cells), map->cells_nr);
172
173 if (!map->cells)
174 {
175 LOG_E("%s: No memory to create %s", rt_ofw_node_full_name(np), "cells");
176 RT_ASSERT(0);
177 }
178
179 trip_np = rt_ofw_parse_phandle(cm_np, "trip", 0);
180 map->trips = rt_ofw_data(trip_np);
181 rt_ofw_node_put(trip_np);
182
183 if (!map->trips)
184 {
185 LOG_E("%s: trips(%s) not found", rt_ofw_node_full_name(np),
186 rt_ofw_node_full_name(trip_np));
187 RT_ASSERT(0);
188 }
189
190 rt_ofw_prop_read_u32(cm_np, "contribution", &map->contribution);
191
192 for (int c = 0; c < map->cells_nr; ++c)
193 {
194 struct rt_thermal_cooling_cell *cell = &map->cells[c];
195
196 if (rt_ofw_parse_phandle_cells(cm_np, "cooling-device", "#cooling-cells", c, &args))
197 {
198 continue;
199 }
200
201 cdev_np = args.data;
202
203 rt_spin_lock(&nodes_lock);
204 device_foreach(cdev, &thermal_cooling_device_nodes)
205 {
206 if (cdev->parent.ofw_node == cdev_np)
207 {
208 cell->cooling_devices = cdev;
209 break;
210 }
211 }
212 rt_spin_unlock(&nodes_lock);
213
214 cell->level_range[0] = args.args[0];
215 cell->level_range[1] = args.args[1];
216
217 if (cell->cooling_devices)
218 {
219 thermal_bind(cell->cooling_devices, zdev);
220 }
221
222 rt_ofw_node_put(cdev_np);
223 }
224 }
225 _end:
226 }
227 #else
thermal_ofw_setup(struct rt_ofw_node * np,struct rt_thermal_zone_device * zdev)228 rt_inline void thermal_ofw_setup(struct rt_ofw_node *np, struct rt_thermal_zone_device *zdev)
229 {
230 }
231 #endif /* RT_USING_OFW */
232
thermal_zone_poll(struct rt_work * work,void * work_data)233 static void thermal_zone_poll(struct rt_work *work, void *work_data)
234 {
235 struct rt_thermal_zone_device *zdev = work_data;
236
237 rt_thermal_zone_device_update(zdev, RT_THERMAL_MSG_EVENT_UNSPECIFIED);
238 }
239
rt_thermal_zone_device_register(struct rt_thermal_zone_device * zdev)240 rt_err_t rt_thermal_zone_device_register(struct rt_thermal_zone_device *zdev)
241 {
242 if (!zdev || !zdev->ops || !zdev->ops->get_temp)
243 {
244 return -RT_EINVAL;
245 }
246
247 zdev->ops->get_temp(zdev, &zdev->temperature);
248 zdev->last_temperature = zdev->temperature;
249
250 if (!zdev->trips)
251 {
252 zdev->trips_nr = 0;
253 }
254
255 rt_spin_lock_init(&zdev->nodes_lock);
256 rt_list_init(&zdev->notifier_nodes);
257 rt_list_init(&device_list(zdev));
258 rt_mutex_init(&zdev->mutex, rt_dm_dev_get_name(&zdev->parent), RT_IPC_FLAG_PRIO);
259
260 zdev->temperature = RT_THERMAL_TEMP_INVALID;
261 zdev->prev_low_trip = -INT_MAX;
262 zdev->prev_high_trip = INT_MAX;
263
264 rt_spin_lock(&nodes_lock);
265 rt_list_insert_before(&thermal_zone_device_nodes, &device_list(zdev));
266 rt_spin_unlock(&nodes_lock);
267
268 thermal_ofw_setup(zdev->parent.ofw_node, zdev);
269
270 rt_work_init(&zdev->poller, thermal_zone_poll, zdev);
271 zdev->enabled = RT_TRUE;
272
273 /* Start to poll */
274 rt_work_submit(&zdev->poller, zdev->polling_delay);
275
276 return RT_EOK;
277 }
278
rt_thermal_zone_device_unregister(struct rt_thermal_zone_device * zdev)279 rt_err_t rt_thermal_zone_device_unregister(struct rt_thermal_zone_device *zdev)
280 {
281 if (!zdev)
282 {
283 return -RT_EINVAL;
284 }
285
286 rt_spin_lock(&zdev->nodes_lock);
287 if (rt_list_isempty(&zdev->notifier_nodes))
288 {
289 LOG_E("%s: there is %u user", rt_dm_dev_get_name(&zdev->parent),
290 rt_list_len(&zdev->notifier_nodes));
291
292 rt_spin_unlock(&zdev->nodes_lock);
293
294 return -RT_EBUSY;
295 }
296 rt_spin_unlock(&zdev->nodes_lock);
297
298 rt_work_cancel(&zdev->poller);
299
300 rt_spin_lock(&nodes_lock);
301 rt_list_remove(&device_list(zdev));
302 rt_spin_unlock(&nodes_lock);
303
304 if (zdev->trips_free && zdev->trips)
305 {
306 rt_free(zdev->trips);
307 }
308
309 if (zdev->cooling_maps_nr && zdev->cooling_maps_nr)
310 {
311 for (int i = 0; i < zdev->cooling_maps_nr; ++i)
312 {
313 struct rt_thermal_cooling_device *cdev;
314 struct rt_thermal_cooling_map *map = &zdev->cooling_maps[i];
315
316 for (int c = 0; c < map->cells_nr; ++c)
317 {
318 cdev = map->cells[i].cooling_devices;
319
320 if (cdev)
321 {
322 thermal_unbind(cdev, zdev);
323 }
324 }
325
326 rt_free(map->cells);
327 }
328
329 rt_free(zdev->cooling_maps);
330 }
331
332 rt_mutex_detach(&zdev->mutex);
333
334 return RT_EOK;
335 }
336
rt_thermal_cooling_device_register(struct rt_thermal_cooling_device * cdev)337 rt_err_t rt_thermal_cooling_device_register(struct rt_thermal_cooling_device *cdev)
338 {
339 rt_err_t err;
340
341 if (!cdev || !cdev->ops ||
342 !cdev->ops->get_max_level || !cdev->ops->get_cur_level || !cdev->ops->set_cur_level)
343 {
344 return -RT_EINVAL;
345 }
346
347 if ((err = cdev->ops->get_max_level(cdev, &cdev->max_level)))
348 {
349 return err;
350 }
351
352 rt_list_init(&device_list(cdev));
353 rt_list_init(&cdev->governor_node);
354
355 rt_spin_lock(&nodes_lock);
356 rt_list_insert_before(&thermal_cooling_device_nodes, &device_list(cdev));
357 rt_spin_unlock(&nodes_lock);
358
359 err = rt_thermal_cooling_device_change_governor(cdev, RT_NULL);
360
361 return err;
362 }
363
rt_thermal_cooling_device_unregister(struct rt_thermal_cooling_device * cdev)364 rt_err_t rt_thermal_cooling_device_unregister(struct rt_thermal_cooling_device *cdev)
365 {
366 if (!cdev)
367 {
368 return -RT_EINVAL;
369 }
370
371 if (cdev->parent.ref_count)
372 {
373 LOG_E("%s: there is %u user",
374 rt_dm_dev_get_name(&cdev->parent), cdev->parent.ref_count);
375 return -RT_EINVAL;
376 }
377
378 rt_spin_lock(&nodes_lock);
379 rt_list_remove(&device_list(cdev));
380 rt_spin_unlock(&nodes_lock);
381
382 return RT_EOK;
383 }
384
dumb_governor_tuning(struct rt_thermal_zone_device * zdev,int map_idx,int cell_idx,rt_ubase_t * level)385 static void dumb_governor_tuning(struct rt_thermal_zone_device *zdev,
386 int map_idx, int cell_idx, rt_ubase_t *level)
387 {
388 struct rt_thermal_cooling_map *map = &zdev->cooling_maps[map_idx];
389
390 if (zdev->cooling && zdev->temperature > map->trips->temperature)
391 {
392 if (zdev->temperature - zdev->last_temperature > map->trips->hysteresis)
393 {
394 ++*level;
395 }
396 else if (zdev->last_temperature - zdev->temperature > map->trips->hysteresis)
397 {
398 --*level;
399 }
400 }
401 else
402 {
403 *level = 0;
404 }
405 }
406
407 static struct rt_thermal_cooling_governor dumb_governor =
408 {
409 .name = "dumb",
410 .tuning = dumb_governor_tuning,
411 };
412
system_thermal_cooling_governor_init(void)413 static int system_thermal_cooling_governor_init(void)
414 {
415 rt_thermal_cooling_governor_register(&dumb_governor);
416
417 return 0;
418 }
419 INIT_CORE_EXPORT(system_thermal_cooling_governor_init);
420
rt_thermal_cooling_governor_register(struct rt_thermal_cooling_governor * gov)421 rt_err_t rt_thermal_cooling_governor_register(struct rt_thermal_cooling_governor *gov)
422 {
423 rt_err_t err = RT_EOK;
424 struct rt_thermal_cooling_governor *gov_tmp;
425
426 if (!gov || !gov->name || !gov->tuning)
427 {
428 return -RT_EINVAL;
429 }
430
431 rt_list_init(&gov->list);
432 rt_list_init(&gov->cdev_nodes);
433
434 rt_spin_lock(&nodes_lock);
435
436 rt_list_for_each_entry(gov_tmp, &thermal_cooling_governor_nodes, list)
437 {
438 if (!rt_strcmp(gov_tmp->name, gov->name))
439 {
440 err = -RT_ERROR;
441 goto _out_unlock;
442 }
443 }
444
445 rt_list_insert_before(&thermal_cooling_governor_nodes, &gov->list);
446
447 _out_unlock:
448 rt_spin_unlock(&nodes_lock);
449
450 return err;
451 }
452
rt_thermal_cooling_governor_unregister(struct rt_thermal_cooling_governor * gov)453 rt_err_t rt_thermal_cooling_governor_unregister(struct rt_thermal_cooling_governor *gov)
454 {
455 if (!gov)
456 {
457 return -RT_EINVAL;
458 }
459
460 if (gov == &dumb_governor)
461 {
462 return -RT_EINVAL;
463 }
464
465 rt_spin_lock(&nodes_lock);
466
467 if (!rt_list_isempty(&gov->cdev_nodes))
468 {
469 goto _out_unlock;
470 }
471
472 rt_list_remove(&gov->list);
473
474 _out_unlock:
475 rt_spin_unlock(&nodes_lock);
476
477 return RT_EOK;
478 }
479
rt_thermal_cooling_device_change_governor(struct rt_thermal_cooling_device * cdev,const char * name)480 rt_err_t rt_thermal_cooling_device_change_governor(struct rt_thermal_cooling_device *cdev,
481 const char *name)
482 {
483 rt_err_t err;
484 struct rt_thermal_cooling_governor *gov;
485
486 if (!cdev)
487 {
488 return -RT_EINVAL;
489 }
490
491 name = name ? : dumb_governor.name;
492 err = -RT_ENOSYS;
493
494 rt_spin_lock(&nodes_lock);
495
496 rt_list_for_each_entry(gov, &thermal_cooling_governor_nodes, list)
497 {
498 if (!rt_strcmp(gov->name, name))
499 {
500 if (cdev->gov)
501 {
502 rt_list_remove(&cdev->governor_node);
503 }
504
505 cdev->gov = gov;
506 rt_list_insert_before(&cdev->governor_node, &gov->cdev_nodes);
507
508 err = RT_EOK;
509 break;
510 }
511 }
512
513 rt_spin_unlock(&nodes_lock);
514
515 return err;
516 }
517
rt_thermal_zone_notifier_register(struct rt_thermal_zone_device * zdev,struct rt_thermal_notifier * notifier)518 rt_err_t rt_thermal_zone_notifier_register(struct rt_thermal_zone_device *zdev,
519 struct rt_thermal_notifier *notifier)
520 {
521 if (!zdev || !notifier)
522 {
523 return -RT_EINVAL;
524 }
525
526 notifier->zdev = zdev;
527 rt_list_init(¬ifier->list);
528
529 rt_spin_lock(&zdev->nodes_lock);
530 rt_list_insert_after(&zdev->notifier_nodes, ¬ifier->list);
531 rt_spin_unlock(&zdev->nodes_lock);
532
533 return RT_EOK;
534 }
535
rt_thermal_zone_notifier_unregister(struct rt_thermal_zone_device * zdev,struct rt_thermal_notifier * notifier)536 rt_err_t rt_thermal_zone_notifier_unregister(struct rt_thermal_zone_device *zdev,
537 struct rt_thermal_notifier *notifier)
538 {
539 if (!zdev || !notifier)
540 {
541 return -RT_EINVAL;
542 }
543
544 rt_spin_lock(&zdev->nodes_lock);
545 rt_list_remove(¬ifier->list);
546 rt_spin_unlock(&zdev->nodes_lock);
547
548 return RT_EOK;
549 }
550
rt_thermal_zone_device_update(struct rt_thermal_zone_device * zdev,rt_ubase_t msg)551 void rt_thermal_zone_device_update(struct rt_thermal_zone_device *zdev, rt_ubase_t msg)
552 {
553 rt_err_t err;
554 rt_bool_t passive = RT_FALSE, need_cool = RT_FALSE;
555 struct rt_thermal_notifier *notifier, *next_notifier;
556
557 RT_ASSERT(zdev != RT_NULL);
558
559 if (!rt_interrupt_get_nest())
560 {
561 rt_mutex_take(&zdev->mutex, RT_WAITING_FOREVER);
562 }
563
564 /* Check thermal zone status */
565 if (msg == RT_THERMAL_MSG_DEVICE_DOWN)
566 {
567 zdev->enabled = RT_FALSE;
568 }
569 else if (msg == RT_THERMAL_MSG_DEVICE_UP)
570 {
571 zdev->enabled = RT_TRUE;
572 }
573
574 /* Read temperature */
575 zdev->last_temperature = zdev->temperature;
576 zdev->ops->get_temp(zdev, &zdev->temperature);
577
578 for (int i = 0; i < zdev->trips_nr; ++i)
579 {
580 struct rt_thermal_trip *tmp_trip = &zdev->trips[i];
581
582 if (zdev->temperature <= tmp_trip->temperature)
583 {
584 continue;
585 }
586
587 switch (tmp_trip->type)
588 {
589 case RT_THERMAL_TRIP_PASSIVE:
590 passive = RT_TRUE;
591 goto cooling;
592
593 case RT_THERMAL_TRIP_CRITICAL:
594 if (zdev->ops->critical)
595 {
596 zdev->ops->critical(zdev);
597 }
598 else if (zdev->last_temperature > tmp_trip->temperature)
599 {
600 /* Tried to cool already, but failed */
601 rt_hw_cpu_reset();
602 }
603 else
604 {
605 goto cooling;
606 }
607 break;
608
609 case RT_THERMAL_TRIP_HOT:
610 if (zdev->ops->hot)
611 {
612 zdev->ops->hot(zdev);
613 break;
614 }
615
616 default:
617 cooling:
618 zdev->cooling = need_cool = RT_TRUE;
619 rt_thermal_cooling_device_kick(zdev);
620 break;
621 }
622 }
623
624 if (!need_cool && zdev->cooling)
625 {
626 rt_thermal_cooling_device_kick(zdev);
627 }
628
629 /* Set the new trips */
630 if (zdev->ops->set_trips)
631 {
632 rt_bool_t same_trip = RT_FALSE;
633 int low = -INT_MAX, high = INT_MAX;
634 struct rt_thermal_trip trip;
635
636 for (int i = 0; i < zdev->trips_nr; ++i)
637 {
638 int trip_low;
639 rt_bool_t low_set = RT_FALSE;
640
641 rt_memcpy(&trip, &zdev->trips[i], sizeof(trip));
642
643 trip_low = trip.temperature - trip.hysteresis;
644
645 if (trip_low < zdev->temperature && trip_low > low)
646 {
647 low = trip_low;
648 low_set = RT_TRUE;
649 same_trip = RT_FALSE;
650 }
651
652 if (trip.temperature > zdev->temperature && trip.temperature < high)
653 {
654 high = trip.temperature;
655 same_trip = low_set;
656 }
657 }
658
659 /* No need to change trip points */
660 if (zdev->prev_low_trip == low && zdev->prev_high_trip == high)
661 {
662 goto _call_notifier;
663 }
664
665 if (same_trip &&
666 (zdev->prev_low_trip != -INT_MAX || zdev->prev_high_trip != INT_MAX))
667 {
668 goto _call_notifier;
669 }
670
671 zdev->prev_low_trip = low;
672 zdev->prev_high_trip = high;
673
674 if ((err = zdev->ops->set_trips(zdev, low, high)))
675 {
676 LOG_E("%s: Set trips error = %s", rt_dm_dev_get_name(&zdev->parent),
677 rt_strerror(err));
678 }
679 }
680
681 /* Call all notifier, maybe have governor */
682 _call_notifier:
683 rt_spin_lock(&zdev->nodes_lock);
684
685 rt_list_for_each_entry_safe(notifier, next_notifier, &zdev->notifier_nodes, list)
686 {
687 rt_spin_unlock(&zdev->nodes_lock);
688
689 notifier->callback(notifier, msg);
690
691 rt_spin_lock(&zdev->nodes_lock);
692 }
693
694 rt_spin_unlock(&zdev->nodes_lock);
695
696 /* Prepare for the next report */
697 if (!zdev->enabled)
698 {
699 rt_work_cancel(&zdev->poller);
700 }
701 else if (passive && zdev->passive_delay)
702 {
703 rt_work_submit(&zdev->poller, zdev->passive_delay);
704 }
705 else if (zdev->polling_delay)
706 {
707 rt_work_submit(&zdev->poller, zdev->polling_delay);
708 }
709
710 if (!rt_interrupt_get_nest())
711 {
712 rt_mutex_release(&zdev->mutex);
713 }
714 }
715
rt_thermal_cooling_device_kick(struct rt_thermal_zone_device * zdev)716 void rt_thermal_cooling_device_kick(struct rt_thermal_zone_device *zdev)
717 {
718 RT_ASSERT(zdev != RT_NULL);
719
720 for (int i = 0; i < zdev->cooling_maps_nr; ++i)
721 {
722 rt_ubase_t level;
723 struct rt_thermal_cooling_device *cdev;
724 struct rt_thermal_cooling_cell *cell;
725 struct rt_thermal_cooling_map *map = &zdev->cooling_maps[i];
726
727 for (int c = 0; c < map->cells_nr; ++c)
728 {
729 cell = &map->cells[c];
730 cdev = cell->cooling_devices;
731
732 if (!cdev)
733 {
734 continue;
735 }
736
737 /* Update status */
738 if (cdev->ops->get_max_level(cdev, &cdev->max_level))
739 {
740 continue;
741 }
742
743 if (cdev->ops->get_cur_level(cdev, &level) || level > cdev->max_level)
744 {
745 continue;
746 }
747
748 /* Check if cooling is required */
749 if (level >= cell->level_range[0] && level <= cell->level_range[1])
750 {
751 /* Is cooling, not call */
752 continue;
753 }
754
755 cdev->gov->tuning(zdev, i, c, &level);
756 level = rt_min_t(rt_ubase_t, level, cdev->max_level);
757
758 cdev->ops->set_cur_level(cdev, level);
759 }
760 }
761 }
762
rt_thermal_zone_set_trip(struct rt_thermal_zone_device * zdev,int trip_id,const struct rt_thermal_trip * trip)763 rt_err_t rt_thermal_zone_set_trip(struct rt_thermal_zone_device *zdev, int trip_id,
764 const struct rt_thermal_trip *trip)
765 {
766 rt_err_t err;
767 struct rt_thermal_trip tmp_trip;
768
769 if (!zdev || !trip)
770 {
771 return -RT_EINVAL;
772 }
773
774 rt_mutex_take(&zdev->mutex, RT_WAITING_FOREVER);
775
776 if (!zdev->ops->set_trip_temp && !zdev->ops->set_trip_hyst && !zdev->trips)
777 {
778 err = -RT_EINVAL;
779 goto _out_unlock;
780 }
781
782 if (trip_id >= zdev->trips_nr)
783 {
784 err = -RT_EINVAL;
785 goto _out_unlock;
786 }
787
788 rt_memcpy(&tmp_trip, &zdev->trips[trip_id], sizeof(tmp_trip));
789
790 if (tmp_trip.type != trip->type)
791 {
792 err = -RT_EINVAL;
793 goto _out_unlock;
794 }
795
796 if (tmp_trip.temperature != trip->temperature && zdev->ops->set_trip_temp)
797 {
798 if ((err = zdev->ops->set_trip_temp(zdev, trip_id, trip->temperature)))
799 {
800 goto _out_unlock;
801 }
802 }
803
804 if (tmp_trip.hysteresis != trip->hysteresis && zdev->ops->set_trip_hyst)
805 {
806 if ((err = zdev->ops->set_trip_hyst(zdev, trip_id, trip->hysteresis)))
807 {
808 goto _out_unlock;
809 }
810 }
811
812 if (zdev->trips &&
813 (tmp_trip.temperature != trip->temperature || tmp_trip.hysteresis != trip->hysteresis))
814 {
815 zdev->trips[trip_id] = *trip;
816 }
817
818 _out_unlock:
819 rt_mutex_release(&zdev->mutex);
820
821 if (!err)
822 {
823 rt_thermal_zone_device_update(zdev, RT_THERMAL_MSG_TRIP_CHANGED);
824 }
825
826 return err;
827 }
828
rt_thermal_zone_get_trip(struct rt_thermal_zone_device * zdev,int trip_id,struct rt_thermal_trip * out_trip)829 rt_err_t rt_thermal_zone_get_trip(struct rt_thermal_zone_device *zdev, int trip_id,
830 struct rt_thermal_trip *out_trip)
831 {
832 rt_err_t err = RT_EOK;
833
834 if (!zdev || !out_trip)
835 {
836 return -RT_EINVAL;
837 }
838
839 rt_mutex_take(&zdev->mutex, RT_WAITING_FOREVER);
840
841 if (!zdev->trips_nr)
842 {
843 err = -RT_ENOSYS;
844 goto _out_unlock;
845 }
846
847 if (trip_id >= zdev->trips_nr)
848 {
849 err = -RT_EINVAL;
850 goto _out_unlock;
851 }
852
853 *out_trip = zdev->trips[trip_id];
854
855 _out_unlock:
856 rt_mutex_release(&zdev->mutex);
857
858 return err;
859 }
860
861 #if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
list_thermal(int argc,char ** argv)862 static int list_thermal(int argc, char**argv)
863 {
864 struct rt_thermal_zone_device *zdev;
865
866 /* Thermal is an important subsystem, please do not output too much. */
867 rt_spin_lock(&nodes_lock);
868 device_foreach(zdev, &thermal_zone_device_nodes)
869 {
870 int temperature = zdev->temperature;
871
872 rt_kprintf("%s-%d\n", rt_dm_dev_get_name(&zdev->parent), zdev->zone_id);
873 rt_kprintf("temperature:\t%+d.%u C\n", temperature / 1000, rt_abs(temperature) % 1000);
874
875 for (int i = 0, id = 0; i < zdev->cooling_maps_nr; ++i)
876 {
877 rt_ubase_t level;
878 struct rt_thermal_trip *trips;
879 struct rt_thermal_cooling_device *cdev;
880 struct rt_thermal_cooling_cell *cell;
881 struct rt_thermal_cooling_map *map = &zdev->cooling_maps[i];
882
883 for (int c = 0; c < map->cells_nr; ++c, ++id)
884 {
885 trips = map->trips;
886 cell = &map->cells[c];
887 cdev = cell->cooling_devices;
888
889 if (cdev)
890 {
891 cdev->ops->get_cur_level(cdev, &level);
892
893 rt_kprintf("cooling%u:\t%s[%+d.%u C] %d\n", id,
894 rt_dm_dev_get_name(&cdev->parent),
895 trips->temperature / 1000, rt_abs(trips->temperature) % 1000,
896 level);
897 }
898 else
899 {
900 rt_kprintf("cooling%u:\t%s[%+d.%u C] %d\n", id,
901 "(not supported)",
902 trips->temperature / 1000, rt_abs(trips->temperature) % 1000,
903 0);
904 }
905 }
906 }
907 }
908 rt_spin_unlock(&nodes_lock);
909
910 return 0;
911 }
912 MSH_CMD_EXPORT(list_thermal, dump all of thermal information);
913 #endif /* RT_USING_CONSOLE && RT_USING_MSH */
914