thermal.c 22 KB

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