msm_mmrm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/of_platform.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/slab.h>
  9. #include <linux/soc/qcom/msm_mmrm.h>
  10. #include <linux/fs.h>
  11. #include "mmrm_internal.h"
  12. #include "mmrm_debug.h"
  13. #include "mmrm_clk_rsrc_mgr.h"
  14. #define VERIFY_PDEV(pdev) \
  15. { \
  16. if (!pdev) { \
  17. d_mpr_e("%s: null platform dev\n", __func__);\
  18. rc = -EINVAL; \
  19. goto err_exit; \
  20. } \
  21. }
  22. #define RESET_DRV_DATA(drv_data) \
  23. { \
  24. kfree(drv_data); \
  25. drv_data = (void *) -EPROBE_DEFER; \
  26. }
  27. #define CHECK_SKIP_MMRM_CLK_RSRC(drv_data) \
  28. { \
  29. if (!drv_data->is_clk_scaling_supported) { \
  30. d_mpr_h("%s: mmrm clk rsrc not supported\n", __func__);\
  31. goto skip_mmrm; \
  32. } \
  33. }
  34. #define MMRM_SYSFS_ENTRY_MAX_LEN PAGE_SIZE
  35. extern int msm_mmrm_debug;
  36. extern u8 msm_mmrm_enable_throttle_feature;
  37. extern u8 msm_mmrm_allow_multiple_register;
  38. struct mmrm_driver_data *drv_data = (void *) -EPROBE_DEFER;
  39. bool mmrm_client_check_scaling_supported(enum mmrm_client_type client_type, u32 client_domain)
  40. {
  41. if (drv_data == (void *)-EPROBE_DEFER) {
  42. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  43. goto err_exit;
  44. }
  45. if (client_type == MMRM_CLIENT_CLOCK) {
  46. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  47. /* TODO: Check for individual domain */
  48. }
  49. return true;
  50. err_exit:
  51. d_mpr_e("%s: error exit\n", __func__);
  52. skip_mmrm:
  53. return false;
  54. }
  55. EXPORT_SYMBOL(mmrm_client_check_scaling_supported);
  56. struct mmrm_client *mmrm_client_register(struct mmrm_client_desc *client_desc)
  57. {
  58. struct mmrm_client *client = NULL;
  59. /* check for null input */
  60. if (!client_desc) {
  61. d_mpr_e("%s: null input descriptor\n", __func__);
  62. goto err_exit;
  63. }
  64. if (drv_data == (void *) -EPROBE_DEFER) {
  65. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  66. goto err_exit;
  67. }
  68. /* check for client type, then register */
  69. if (client_desc->client_type == MMRM_CLIENT_CLOCK) {
  70. /* check for skip mmrm */
  71. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  72. client = mmrm_clk_client_register(
  73. drv_data->clk_mgr, client_desc);
  74. if (!client) {
  75. d_mpr_e("%s: failed to register client\n", __func__);
  76. goto err_exit;
  77. }
  78. } else {
  79. d_mpr_e("%s: unknown client_type %d\n",
  80. __func__, client_desc->client_type);
  81. goto err_exit;
  82. }
  83. skip_mmrm:
  84. return client;
  85. err_exit:
  86. d_mpr_e("%s: error exit\n", __func__);
  87. return client;
  88. }
  89. EXPORT_SYMBOL(mmrm_client_register);
  90. int mmrm_client_deregister(struct mmrm_client *client)
  91. {
  92. int rc = 0;
  93. /* check for null input */
  94. if (!client) {
  95. d_mpr_e("%s: invalid input client\n", __func__);
  96. rc = -EINVAL;
  97. goto err_exit;
  98. }
  99. if (drv_data == (void *) -EPROBE_DEFER) {
  100. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  101. goto err_exit;
  102. }
  103. /* check for client type, then deregister */
  104. if (client->client_type == MMRM_CLIENT_CLOCK) {
  105. /* check for skip mmrm */
  106. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  107. rc = mmrm_clk_client_deregister(drv_data->clk_mgr, client);
  108. if (rc != 0) {
  109. d_mpr_e("%s: failed to deregister client\n", __func__);
  110. goto err_exit;
  111. }
  112. } else {
  113. d_mpr_e("%s: unknown client_type %d\n",
  114. __func__, client->client_type);
  115. }
  116. skip_mmrm:
  117. return rc;
  118. err_exit:
  119. d_mpr_e("%s: error = %d\n", __func__, rc);
  120. return rc;
  121. }
  122. EXPORT_SYMBOL(mmrm_client_deregister);
  123. int mmrm_client_set_value(struct mmrm_client *client,
  124. struct mmrm_client_data *client_data, unsigned long val)
  125. {
  126. int rc = 0;
  127. /* check for null input */
  128. if (!client || !client_data) {
  129. d_mpr_e("%s: invalid input client(%pK) client_data(%pK)\n",
  130. __func__, client, client_data);
  131. rc = -EINVAL;
  132. goto err_exit;
  133. }
  134. if (drv_data == (void *) -EPROBE_DEFER) {
  135. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  136. goto err_exit;
  137. }
  138. /* check for client type, then set value */
  139. if (client->client_type == MMRM_CLIENT_CLOCK) {
  140. /* check for skip mmrm */
  141. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  142. rc = mmrm_clk_client_setval(drv_data->clk_mgr, client,
  143. client_data, val);
  144. if (rc != 0) {
  145. d_mpr_e("%s: failed to set value for client\n", __func__);
  146. goto err_exit;
  147. }
  148. } else {
  149. d_mpr_e("%s: unknown client_type %d\n",
  150. __func__, client->client_type);
  151. }
  152. skip_mmrm:
  153. return rc;
  154. err_exit:
  155. d_mpr_e("%s: error = %d\n", __func__, rc);
  156. return rc;
  157. }
  158. EXPORT_SYMBOL(mmrm_client_set_value);
  159. int mmrm_client_set_value_in_range(struct mmrm_client *client,
  160. struct mmrm_client_data *client_data,
  161. struct mmrm_client_res_value *val)
  162. {
  163. int rc = 0;
  164. /* check for null input */
  165. if (!client || !client_data || !val) {
  166. d_mpr_e(
  167. "%s: invalid input client(%pK) client_data(%pK) val(%pK)\n",
  168. __func__, client, client_data, val);
  169. rc = -EINVAL;
  170. goto err_exit;
  171. }
  172. if (drv_data == (void *) -EPROBE_DEFER) {
  173. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  174. goto err_exit;
  175. }
  176. /* check for client type, then set value */
  177. if (client->client_type == MMRM_CLIENT_CLOCK) {
  178. /* check for skip mmrm */
  179. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  180. rc = mmrm_clk_client_setval_inrange(drv_data->clk_mgr,
  181. client, client_data, val);
  182. if (rc != 0) {
  183. d_mpr_e("%s: failed to set value for client\n", __func__);
  184. goto err_exit;
  185. }
  186. } else {
  187. d_mpr_e("%s: unknown client_type %d\n",
  188. __func__, client->client_type);
  189. }
  190. skip_mmrm:
  191. return rc;
  192. err_exit:
  193. d_mpr_e("%s: error = %d\n", __func__, rc);
  194. return rc;
  195. }
  196. EXPORT_SYMBOL(mmrm_client_set_value_in_range);
  197. int mmrm_client_get_value(struct mmrm_client *client,
  198. struct mmrm_client_res_value *val)
  199. {
  200. int rc = 0;
  201. /* check for null input */
  202. if (!client || !val) {
  203. d_mpr_e("%s: invalid input client(%pK) val(%pK)\n",
  204. __func__, client, val);
  205. rc = -EINVAL;
  206. goto err_exit;
  207. }
  208. if (drv_data == (void *) -EPROBE_DEFER) {
  209. d_mpr_e("%s: mmrm probe_init not done\n", __func__);
  210. goto err_exit;
  211. }
  212. /* check for client type, then get value */
  213. if (client->client_type == MMRM_CLIENT_CLOCK) {
  214. /* check for skip mmrm */
  215. CHECK_SKIP_MMRM_CLK_RSRC(drv_data);
  216. rc = mmrm_clk_client_getval(drv_data->clk_mgr,
  217. client, val);
  218. if (rc != 0) {
  219. d_mpr_e("%s: failed to get value for client\n", __func__);
  220. goto err_exit;
  221. }
  222. } else {
  223. d_mpr_e("%s: unknown client_type %d\n",
  224. __func__, client->client_type);
  225. }
  226. skip_mmrm:
  227. return rc;
  228. err_exit:
  229. d_mpr_e("%s: error = %d\n", __func__, rc);
  230. return rc;
  231. }
  232. EXPORT_SYMBOL(mmrm_client_get_value);
  233. int mmrm_client_get_clk_count(void)
  234. {
  235. struct mmrm_sw_clk_mgr_info *sinfo;
  236. if (drv_data == (void *) -EPROBE_DEFER)
  237. return 0;
  238. sinfo = &(drv_data->clk_mgr->data.sw_info);
  239. return sinfo->tot_clk_clients;
  240. }
  241. EXPORT_SYMBOL(mmrm_client_get_clk_count);
  242. static int sysfs_get_param(const char *buf, u32 *param)
  243. {
  244. int base;
  245. if (buf) {
  246. if ((buf[1] == 'x') || (buf[1] == 'X'))
  247. base = 16;
  248. else
  249. base = 10;
  250. if (kstrtou32(buf, base, param) != 0)
  251. return -EINVAL;
  252. }
  253. return 0;
  254. }
  255. static ssize_t mmrm_sysfs_debug_get(struct device *dev,
  256. struct device_attribute *attr, char *buf)
  257. {
  258. int ret;
  259. ret = scnprintf(buf, MMRM_SYSFS_ENTRY_MAX_LEN, "0x%x\n", msm_mmrm_debug);
  260. pr_info("%s: 0x%04X\n", __func__, msm_mmrm_debug);
  261. return ret;
  262. }
  263. static ssize_t mmrm_sysfs_debug_set(struct device *dev,
  264. struct device_attribute *attr, const char *buf, size_t count)
  265. {
  266. int ret;
  267. u32 reg_addr;
  268. ret = sysfs_get_param(buf, &reg_addr);
  269. if (ret == 0)
  270. msm_mmrm_debug = reg_addr;
  271. return count;
  272. }
  273. static ssize_t mmrm_sysfs_enable_throttle_get(struct device *dev,
  274. struct device_attribute *attr, char *buf)
  275. {
  276. int ret;
  277. ret = scnprintf(buf, MMRM_SYSFS_ENTRY_MAX_LEN, "0x%x\n", msm_mmrm_enable_throttle_feature);
  278. pr_info("%s: 0x%04X\n", __func__, msm_mmrm_enable_throttle_feature);
  279. return ret;
  280. }
  281. static ssize_t mmrm_sysfs_enable_throttle_set(struct device *dev,
  282. struct device_attribute *attr, const char *buf, size_t count)
  283. {
  284. u32 reg_addr;
  285. int ret;
  286. ret = sysfs_get_param(buf, &reg_addr);
  287. if (ret == 0)
  288. msm_mmrm_enable_throttle_feature = (u8)reg_addr;
  289. return count;
  290. }
  291. static ssize_t mmrm_sysfs_allow_multiple_get(struct device *dev,
  292. struct device_attribute *attr, char *buf)
  293. {
  294. int ret;
  295. ret = scnprintf(buf, MMRM_SYSFS_ENTRY_MAX_LEN, "0x%x\n", msm_mmrm_allow_multiple_register);
  296. pr_info("%s: 0x%04X\n", __func__, msm_mmrm_allow_multiple_register);
  297. return ret;
  298. }
  299. static ssize_t mmrm_sysfs_allow_multiple_set(struct device *dev,
  300. struct device_attribute *attr, const char *buf, size_t count)
  301. {
  302. u32 reg_addr;
  303. int ret;
  304. ret = sysfs_get_param(buf, &reg_addr);
  305. if (ret == 0)
  306. msm_mmrm_allow_multiple_register = (u8)reg_addr;
  307. return count;
  308. }
  309. static ssize_t dump_enabled_client_info_show(struct device *dev,
  310. struct device_attribute *attr, char *buf)
  311. {
  312. int rc;
  313. rc = mmrm_clk_print_enabled_client_info(drv_data->clk_mgr, buf, MMRM_SYSFS_ENTRY_MAX_LEN);
  314. if (rc == 0)
  315. d_mpr_e("%s: failed to dump client info\n", __func__);
  316. return rc;
  317. }
  318. static ssize_t dump_clk_res_info_show(struct device *dev,
  319. struct device_attribute *attr, char *buf)
  320. {
  321. int i, len;
  322. struct mmrm_clk_platform_resources *cres = &drv_data->clk_res;
  323. struct nom_clk_src_set *clk_set = &cres->nom_clk_set;
  324. struct nom_clk_src_info *pclk;
  325. int left_spaces = MMRM_SYSFS_ENTRY_MAX_LEN;
  326. for (i=0, pclk=clk_set->clk_src_tbl; i < clk_set->count && left_spaces > 1; i++, pclk++) {
  327. len = scnprintf(buf, left_spaces, "%d %d %d %d %d\n",
  328. pclk->domain,
  329. pclk->clk_src_id,
  330. pclk->nom_dyn_pwr,
  331. pclk->nom_leak_pwr,
  332. pclk->num_hw_block);
  333. left_spaces -= len;
  334. buf += len;
  335. }
  336. return MMRM_SYSFS_ENTRY_MAX_LEN - left_spaces;
  337. }
  338. static DEVICE_ATTR(debug, 0644,
  339. mmrm_sysfs_debug_get,
  340. mmrm_sysfs_debug_set);
  341. static DEVICE_ATTR(enable_throttle_feature, 0644,
  342. mmrm_sysfs_enable_throttle_get,
  343. mmrm_sysfs_enable_throttle_set);
  344. static DEVICE_ATTR(allow_multiple_register, 0644,
  345. mmrm_sysfs_allow_multiple_get,
  346. mmrm_sysfs_allow_multiple_set);
  347. static DEVICE_ATTR_RO(dump_enabled_client_info);
  348. static DEVICE_ATTR_RO(dump_clk_res_info);
  349. static struct attribute *mmrm_fs_attrs[] = {
  350. &dev_attr_debug.attr,
  351. &dev_attr_enable_throttle_feature.attr,
  352. &dev_attr_allow_multiple_register.attr,
  353. &dev_attr_dump_enabled_client_info.attr,
  354. &dev_attr_dump_clk_res_info.attr,
  355. NULL,
  356. };
  357. static struct attribute_group mmrm_fs_attrs_group = {
  358. .attrs = mmrm_fs_attrs,
  359. };
  360. static int msm_mmrm_probe_init(struct platform_device *pdev)
  361. {
  362. int rc = 0;
  363. u32 clk_clients = 0;
  364. drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
  365. if (!drv_data) {
  366. d_mpr_e("%s: unable to allocate memory for mmrm driver\n",
  367. __func__);
  368. rc = -ENOMEM;
  369. goto err_no_mem;
  370. }
  371. /* check for clk clients needing admission control */
  372. clk_clients = mmrm_count_clk_clients_frm_dt(pdev);
  373. if (clk_clients) {
  374. d_mpr_h("%s: %d clk clients managed for admission control\n",
  375. __func__, clk_clients);
  376. drv_data->is_clk_scaling_supported = true;
  377. } else {
  378. d_mpr_h("%s: no clk clients managed for admission control\n",
  379. __func__);
  380. drv_data->is_clk_scaling_supported = false;
  381. goto skip_mmrm;
  382. }
  383. drv_data->platform_data = mmrm_get_platform_data(&pdev->dev);
  384. if (!drv_data->platform_data) {
  385. d_mpr_e("%s: unable to get platform data\n",
  386. __func__);
  387. rc = -EINVAL;
  388. goto err_get_drv_data;
  389. }
  390. drv_data->debugfs_root = msm_mmrm_debugfs_init();
  391. if (!drv_data->debugfs_root)
  392. d_mpr_e("%s: failed to create debugfs for mmrm\n", __func__);
  393. dev_set_drvdata(&pdev->dev, drv_data);
  394. rc = mmrm_read_platform_resources(pdev, drv_data);
  395. if (rc) {
  396. d_mpr_e("%s: unable to read platform resources for mmrm\n",
  397. __func__);
  398. goto err_read_pltfrm_rsc;
  399. }
  400. rc = mmrm_init(drv_data);
  401. if (rc) {
  402. d_mpr_e("%s: failed to init mmrm\n",
  403. __func__);
  404. goto err_mmrm_init;
  405. }
  406. if (sysfs_create_group(&pdev->dev.kobj, &mmrm_fs_attrs_group)) {
  407. d_mpr_e("%s: failed to create sysfs\n",
  408. __func__);
  409. }
  410. skip_mmrm:
  411. return rc;
  412. err_mmrm_init:
  413. msm_mmrm_debugfs_deinit(drv_data->debugfs_root);
  414. err_read_pltfrm_rsc:
  415. mmrm_free_platform_resources(drv_data);
  416. err_get_drv_data:
  417. RESET_DRV_DATA(drv_data);
  418. err_no_mem:
  419. d_mpr_e("%s: error = %d\n", __func__, rc);
  420. return rc;
  421. }
  422. static int msm_mmrm_probe(struct platform_device *pdev)
  423. {
  424. int rc = -EINVAL;
  425. d_mpr_h("%s\n", __func__);
  426. VERIFY_PDEV(pdev)
  427. if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-mmrm"))
  428. return msm_mmrm_probe_init(pdev);
  429. d_mpr_e("%s: no compatible device node\n", __func__);
  430. return rc;
  431. err_exit:
  432. d_mpr_e("%s: error = %d\n", __func__, rc);
  433. return rc;
  434. }
  435. static int msm_mmrm_remove(struct platform_device *pdev)
  436. {
  437. int rc = 0;
  438. VERIFY_PDEV(pdev);
  439. drv_data = dev_get_drvdata(&pdev->dev);
  440. if (!drv_data) {
  441. d_mpr_e("%s: null driver data\n", __func__);
  442. return -EINVAL;
  443. }
  444. if (drv_data->is_clk_scaling_supported) {
  445. sysfs_remove_group(&pdev->dev.kobj, &mmrm_fs_attrs_group);
  446. msm_mmrm_debugfs_deinit(drv_data->debugfs_root);
  447. mmrm_deinit(drv_data);
  448. mmrm_free_platform_resources(drv_data);
  449. }
  450. dev_set_drvdata(&pdev->dev, NULL);
  451. RESET_DRV_DATA(drv_data);
  452. return rc;
  453. err_exit:
  454. d_mpr_e("%s: error = %d\n", __func__, rc);
  455. return rc;
  456. }
  457. static const struct of_device_id msm_mmrm_dt_match[] = {
  458. {.compatible = "qcom,msm-mmrm"},
  459. {}
  460. };
  461. MODULE_DEVICE_TABLE(of, msm_mmrm_dt_match);
  462. static struct platform_driver msm_mmrm_driver = {
  463. .probe = msm_mmrm_probe,
  464. .remove = msm_mmrm_remove,
  465. .driver = {
  466. .name = "msm-mmrm",
  467. .of_match_table = msm_mmrm_dt_match,
  468. },
  469. };
  470. static int __init msm_mmrm_init(void)
  471. {
  472. int rc = 0;
  473. rc = platform_driver_register(&msm_mmrm_driver);
  474. if (rc) {
  475. d_mpr_e("%s: failed to register platform driver\n",
  476. __func__);
  477. goto err_platform_drv_reg;
  478. }
  479. d_mpr_h("%s: success\n", __func__);
  480. return rc;
  481. err_platform_drv_reg:
  482. d_mpr_e("%s: error = %d\n", __func__, rc);
  483. return rc;
  484. }
  485. static void __exit msm_mmrm_exit(void)
  486. {
  487. platform_driver_unregister(&msm_mmrm_driver);
  488. }
  489. module_init(msm_mmrm_init);
  490. module_exit(msm_mmrm_exit);
  491. MODULE_DESCRIPTION("QTI MMRM Driver");
  492. MODULE_LICENSE("GPL v2");