cdsp-loader.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012-2014, 2017-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/init.h>
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/err.h>
  9. #include <linux/delay.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/of_device.h>
  12. #include <linux/sysfs.h>
  13. #include <linux/remoteproc.h>
  14. #define BOOT_CMD 1
  15. #define IMAGE_UNLOAD_CMD 0
  16. #define CDSP_SUBSYS_DOWN 0
  17. #define CDSP_SUBSYS_LOADED 1
  18. static ssize_t cdsp_boot_store(struct kobject *kobj,
  19. struct kobj_attribute *attr,
  20. const char *buf, size_t count);
  21. struct cdsp_loader_private {
  22. void *pil_h;
  23. struct kobject *boot_cdsp_obj;
  24. struct attribute_group *attr_group;
  25. };
  26. static struct kobj_attribute cdsp_boot_attribute =
  27. __ATTR(boot, 0220, NULL, cdsp_boot_store);
  28. static struct attribute *attrs[] = {
  29. &cdsp_boot_attribute.attr,
  30. NULL,
  31. };
  32. static u32 cdsp_state = CDSP_SUBSYS_DOWN;
  33. static struct platform_device *cdsp_private;
  34. static void cdsp_loader_unload(struct platform_device *pdev);
  35. static int cdsp_loader_do(struct platform_device *pdev)
  36. {
  37. struct cdsp_loader_private *priv = NULL;
  38. phandle rproc_phandle;
  39. int rc = 0, sz = 0;
  40. const char *img_name;
  41. if (!pdev) {
  42. pr_err("%s: Platform device null\n", __func__);
  43. goto fail;
  44. }
  45. if (!pdev->dev.of_node) {
  46. dev_err(&pdev->dev,
  47. "%s: Device tree information missing\n", __func__);
  48. goto fail;
  49. }
  50. rc = of_property_read_string(pdev->dev.of_node,
  51. "qcom,proc-img-to-load",
  52. &img_name);
  53. if (rc)
  54. goto fail;
  55. if (!strcmp(img_name, "cdsp")) {
  56. /* cdsp_state always returns "0".*/
  57. if (cdsp_state == CDSP_SUBSYS_DOWN) {
  58. priv = platform_get_drvdata(pdev);
  59. if (!priv) {
  60. dev_err(&pdev->dev,
  61. "%s: Private data get failed\n", __func__);
  62. goto fail;
  63. }
  64. sz = of_property_read_u32(pdev->dev.of_node, "qcom,rproc-handle",
  65. &rproc_phandle);
  66. if (sz) {
  67. pr_err("%s: of_property_read failed, returned value %d\n",
  68. __func__, sz);
  69. dev_err(&pdev->dev, "error reading rproc phandle\n");
  70. goto fail;
  71. }
  72. priv->pil_h = rproc_get_by_phandle(rproc_phandle);
  73. if (!priv->pil_h) {
  74. dev_err(&pdev->dev, "rproc not found\n");
  75. goto fail;
  76. }
  77. dev_dbg(&pdev->dev, "%s: calling rproc_boot on %s\n",
  78. __func__, img_name);
  79. rc = rproc_boot(priv->pil_h);
  80. if (rc) {
  81. dev_err(&pdev->dev, "%s: rproc_boot failed with error %d\n",
  82. __func__, rc);
  83. goto fail;
  84. }
  85. /* Set the state of the CDSP.*/
  86. cdsp_state = CDSP_SUBSYS_LOADED;
  87. } else if (cdsp_state == CDSP_SUBSYS_LOADED) {
  88. dev_dbg(&pdev->dev,
  89. "%s: CDSP state = 0x%x\n", __func__, cdsp_state);
  90. }
  91. dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__);
  92. return rc;
  93. }
  94. fail:
  95. if (pdev)
  96. dev_err(&pdev->dev,
  97. "%s: CDSP image loading failed\n", __func__);
  98. return rc;
  99. }
  100. static ssize_t cdsp_boot_store(struct kobject *kobj,
  101. struct kobj_attribute *attr,
  102. const char *buf,
  103. size_t count)
  104. {
  105. int ret = 0;
  106. uint32_t boot = 0;
  107. ret = kstrtou32(buf, 0, &boot);
  108. if (ret) {
  109. pr_debug("%s: invalid arguments for cdsp_loader.\n", __func__);
  110. return ret;
  111. }
  112. if (boot == BOOT_CMD) {
  113. pr_debug("%s: going to call cdsp_loader_do\n", __func__);
  114. cdsp_loader_do(cdsp_private);
  115. } else if (boot == IMAGE_UNLOAD_CMD) {
  116. pr_debug("%s: going to call cdsp_unloader\n", __func__);
  117. cdsp_loader_unload(cdsp_private);
  118. }
  119. return count;
  120. }
  121. static void cdsp_loader_unload(struct platform_device *pdev)
  122. {
  123. struct cdsp_loader_private *priv = NULL;
  124. priv = platform_get_drvdata(pdev);
  125. if (!priv)
  126. return;
  127. if (priv->pil_h) {
  128. dev_dbg(&pdev->dev, "%s: calling subsystem_put\n", __func__);
  129. rproc_shutdown(priv->pil_h);
  130. priv->pil_h = NULL;
  131. }
  132. }
  133. static int cdsp_loader_init_sysfs(struct platform_device *pdev)
  134. {
  135. int ret = -EINVAL;
  136. struct cdsp_loader_private *priv = NULL;
  137. cdsp_private = NULL;
  138. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  139. if (!priv) {
  140. ret = -ENOMEM;
  141. return ret;
  142. }
  143. platform_set_drvdata(pdev, priv);
  144. priv->pil_h = NULL;
  145. priv->boot_cdsp_obj = NULL;
  146. priv->attr_group = devm_kzalloc(&pdev->dev,
  147. sizeof(*(priv->attr_group)),
  148. GFP_KERNEL);
  149. if (!priv->attr_group) {
  150. ret = -ENOMEM;
  151. goto error_return;
  152. }
  153. priv->attr_group->attrs = attrs;
  154. priv->boot_cdsp_obj = kobject_create_and_add("boot_cdsp", kernel_kobj);
  155. if (!priv->boot_cdsp_obj) {
  156. dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
  157. __func__);
  158. ret = -ENOMEM;
  159. goto error_return;
  160. }
  161. ret = sysfs_create_group(priv->boot_cdsp_obj, priv->attr_group);
  162. if (ret) {
  163. dev_err(&pdev->dev, "%s: sysfs create group failed %d\n",
  164. __func__, ret);
  165. goto error_return;
  166. }
  167. cdsp_private = pdev;
  168. return 0;
  169. error_return:
  170. if (priv->boot_cdsp_obj) {
  171. kobject_del(priv->boot_cdsp_obj);
  172. priv->boot_cdsp_obj = NULL;
  173. }
  174. if (ret)
  175. dev_err(&pdev->dev, "%s failed with ret %d\n",
  176. __func__, ret);
  177. return ret;
  178. }
  179. static int cdsp_loader_remove(struct platform_device *pdev)
  180. {
  181. struct cdsp_loader_private *priv = NULL;
  182. priv = platform_get_drvdata(pdev);
  183. if (!priv)
  184. return 0;
  185. if (priv->pil_h) {
  186. rproc_shutdown(priv->pil_h);
  187. priv->pil_h = NULL;
  188. }
  189. if (priv->boot_cdsp_obj) {
  190. sysfs_remove_group(priv->boot_cdsp_obj, priv->attr_group);
  191. kobject_del(priv->boot_cdsp_obj);
  192. priv->boot_cdsp_obj = NULL;
  193. }
  194. return 0;
  195. }
  196. static int cdsp_loader_probe(struct platform_device *pdev)
  197. {
  198. phandle rproc_phandle;
  199. struct property *prop = NULL;
  200. int size = 0;
  201. struct rproc *cdsp = NULL;
  202. int ret = 0;
  203. prop = of_find_property(pdev->dev.of_node, "qcom,rproc-handle", &size);
  204. if (!prop) {
  205. dev_err(&pdev->dev, "%s: error reading rproc phandle\n", __func__);
  206. return -ENOPARAM;
  207. }
  208. rproc_phandle = be32_to_cpup(prop->value);
  209. cdsp = rproc_get_by_phandle(rproc_phandle);
  210. if (!cdsp) {
  211. dev_err(&pdev->dev, "%s: rproc not found\n", __func__);
  212. return -EPROBE_DEFER;
  213. }
  214. ret = cdsp_loader_init_sysfs(pdev);
  215. if (ret != 0) {
  216. dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
  217. return ret;
  218. }
  219. return 0;
  220. }
  221. static const struct of_device_id cdsp_loader_dt_match[] = {
  222. { .compatible = "qcom,cdsp-loader" },
  223. { }
  224. };
  225. MODULE_DEVICE_TABLE(of, cdsp_loader_dt_match);
  226. static struct platform_driver cdsp_loader_driver = {
  227. .driver = {
  228. .name = "cdsp-loader",
  229. .of_match_table = cdsp_loader_dt_match,
  230. },
  231. .probe = cdsp_loader_probe,
  232. .remove = cdsp_loader_remove,
  233. };
  234. static int __init cdsp_loader_init(void)
  235. {
  236. return platform_driver_register(&cdsp_loader_driver);
  237. }
  238. module_init(cdsp_loader_init);
  239. static void __exit cdsp_loader_exit(void)
  240. {
  241. platform_driver_unregister(&cdsp_loader_driver);
  242. }
  243. module_exit(cdsp_loader_exit);
  244. MODULE_DESCRIPTION("CDSP Loader module");
  245. MODULE_LICENSE("GPL v2");