qcom-dload-mode.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2020, 2021 The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/delay.h>
  6. #include <linux/err.h>
  7. #include <linux/init.h>
  8. #include <linux/kernel.h>
  9. #include <linux/io.h>
  10. #include <linux/of.h>
  11. #include <linux/of_address.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/module.h>
  14. #include <linux/reboot.h>
  15. #include <linux/pm.h>
  16. #include <linux/panic_notifier.h>
  17. #include <linux/qcom_scm.h>
  18. #include <soc/qcom/minidump.h>
  19. enum qcom_download_dest {
  20. QCOM_DOWNLOAD_DEST_UNKNOWN = -1,
  21. QCOM_DOWNLOAD_DEST_QPST = 0,
  22. QCOM_DOWNLOAD_DEST_EMMC = 2,
  23. };
  24. struct qcom_dload {
  25. struct notifier_block panic_nb;
  26. struct notifier_block reboot_nb;
  27. struct notifier_block restart_nb;
  28. struct kobject kobj;
  29. bool in_panic;
  30. bool in_reboot;
  31. void __iomem *dload_dest_addr;
  32. };
  33. #define to_qcom_dload(o) container_of(o, struct qcom_dload, kobj)
  34. #define QCOM_DOWNLOAD_BOTHDUMP (QCOM_DOWNLOAD_FULLDUMP | QCOM_DOWNLOAD_MINIDUMP)
  35. static bool enable_dump =
  36. IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT);
  37. static enum qcom_download_mode current_download_mode = QCOM_DOWNLOAD_NODUMP;
  38. static enum qcom_download_mode dump_mode = QCOM_DOWNLOAD_FULLDUMP;
  39. static int set_download_mode(enum qcom_download_mode mode)
  40. {
  41. if ((mode & QCOM_DOWNLOAD_MINIDUMP) && !msm_minidump_enabled()) {
  42. mode &= ~QCOM_DOWNLOAD_MINIDUMP;
  43. pr_warn("Minidump not enabled.\n");
  44. if (!mode)
  45. return -ENODEV;
  46. }
  47. current_download_mode = mode;
  48. qcom_scm_set_download_mode(mode, 0);
  49. return 0;
  50. }
  51. static int set_dump_mode(enum qcom_download_mode mode)
  52. {
  53. int ret = 0, temp;
  54. if (enable_dump) {
  55. ret = set_download_mode(mode);
  56. if (likely(!ret))
  57. dump_mode = qcom_scm_get_download_mode(&temp, 0) ? dump_mode : temp;
  58. } else
  59. dump_mode = mode;
  60. if (dump_mode != mode)
  61. pr_err("Requested dload mode is not set\n");
  62. return ret;
  63. }
  64. int get_dump_mode(void)
  65. {
  66. return dump_mode;
  67. }
  68. EXPORT_SYMBOL(get_dump_mode);
  69. static void msm_enable_dump_mode(bool enable)
  70. {
  71. if (enable)
  72. set_download_mode(dump_mode);
  73. else
  74. set_download_mode(QCOM_DOWNLOAD_NODUMP);
  75. }
  76. static void set_download_dest(struct qcom_dload *poweroff,
  77. enum qcom_download_dest dest)
  78. {
  79. if (poweroff->dload_dest_addr)
  80. __raw_writel(dest, poweroff->dload_dest_addr);
  81. }
  82. static enum qcom_download_dest get_download_dest(struct qcom_dload *poweroff)
  83. {
  84. if (poweroff->dload_dest_addr)
  85. return __raw_readl(poweroff->dload_dest_addr);
  86. else
  87. return QCOM_DOWNLOAD_DEST_UNKNOWN;
  88. }
  89. static int param_set_download_mode(const char *val,
  90. const struct kernel_param *kp)
  91. {
  92. int ret;
  93. /* update enable_dump according to user input */
  94. ret = param_set_bool(val, kp);
  95. if (ret)
  96. return ret;
  97. msm_enable_dump_mode(true);
  98. return 0;
  99. }
  100. module_param_call(download_mode, param_set_download_mode, param_get_int,
  101. &enable_dump, 0644);
  102. /* interface for exporting attributes */
  103. struct reset_attribute {
  104. struct attribute attr;
  105. ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
  106. char *buf);
  107. ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
  108. const char *buf, size_t count);
  109. };
  110. #define to_reset_attr(_attr) \
  111. container_of(_attr, struct reset_attribute, attr)
  112. static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,
  113. char *buf)
  114. {
  115. struct reset_attribute *reset_attr = to_reset_attr(attr);
  116. ssize_t ret = -EIO;
  117. if (reset_attr->show)
  118. ret = reset_attr->show(kobj, attr, buf);
  119. return ret;
  120. }
  121. static ssize_t attr_store(struct kobject *kobj, struct attribute *attr,
  122. const char *buf, size_t count)
  123. {
  124. struct reset_attribute *reset_attr = to_reset_attr(attr);
  125. ssize_t ret = -EIO;
  126. if (reset_attr->store)
  127. ret = reset_attr->store(kobj, attr, buf, count);
  128. return ret;
  129. }
  130. static const struct sysfs_ops reset_sysfs_ops = {
  131. .show = attr_show,
  132. .store = attr_store,
  133. };
  134. static struct kobj_type qcom_dload_kobj_type = {
  135. .sysfs_ops = &reset_sysfs_ops,
  136. };
  137. static ssize_t emmc_dload_show(struct kobject *kobj,
  138. struct attribute *this,
  139. char *buf)
  140. {
  141. struct qcom_dload *poweroff = to_qcom_dload(kobj);
  142. if (!poweroff->dload_dest_addr)
  143. return -ENODEV;
  144. return scnprintf(buf, PAGE_SIZE, "%u\n",
  145. get_download_dest(poweroff) == QCOM_DOWNLOAD_DEST_EMMC);
  146. }
  147. static ssize_t emmc_dload_store(struct kobject *kobj,
  148. struct attribute *this,
  149. const char *buf, size_t count)
  150. {
  151. int ret;
  152. bool enabled;
  153. struct qcom_dload *poweroff = to_qcom_dload(kobj);
  154. if (!poweroff->dload_dest_addr)
  155. return -ENODEV;
  156. ret = kstrtobool(buf, &enabled);
  157. if (ret < 0)
  158. return ret;
  159. if (enabled)
  160. set_download_dest(poweroff, QCOM_DOWNLOAD_DEST_EMMC);
  161. else
  162. set_download_dest(poweroff, QCOM_DOWNLOAD_DEST_QPST);
  163. return count;
  164. }
  165. static struct reset_attribute attr_emmc_dload = __ATTR_RW(emmc_dload);
  166. static ssize_t dload_mode_show(struct kobject *kobj,
  167. struct attribute *this,
  168. char *buf)
  169. {
  170. const char *mode;
  171. switch ((unsigned int)dump_mode) {
  172. case QCOM_DOWNLOAD_FULLDUMP:
  173. mode = "full";
  174. break;
  175. case QCOM_DOWNLOAD_MINIDUMP:
  176. mode = "mini";
  177. break;
  178. case QCOM_DOWNLOAD_BOTHDUMP:
  179. mode = "both";
  180. break;
  181. default:
  182. mode = "unknown";
  183. break;
  184. }
  185. return scnprintf(buf, PAGE_SIZE, "DLOAD dump type: %s\n", mode);
  186. }
  187. static ssize_t dload_mode_store(struct kobject *kobj,
  188. struct attribute *this,
  189. const char *buf, size_t count)
  190. {
  191. enum qcom_download_mode mode;
  192. if (sysfs_streq(buf, "full"))
  193. mode = QCOM_DOWNLOAD_FULLDUMP;
  194. else if (sysfs_streq(buf, "mini"))
  195. mode = QCOM_DOWNLOAD_MINIDUMP;
  196. else if (sysfs_streq(buf, "both"))
  197. mode = QCOM_DOWNLOAD_BOTHDUMP;
  198. else {
  199. pr_err("Invalid dump mode request...\n");
  200. pr_err("Supported dumps: 'full', 'mini', or 'both'\n");
  201. return -EINVAL;
  202. }
  203. return set_dump_mode(mode) ? : count;
  204. }
  205. static struct reset_attribute attr_dload_mode = __ATTR_RW(dload_mode);
  206. static struct attribute *qcom_dload_attrs[] = {
  207. &attr_emmc_dload.attr,
  208. &attr_dload_mode.attr,
  209. NULL
  210. };
  211. static struct attribute_group qcom_dload_attr_group = {
  212. .attrs = qcom_dload_attrs,
  213. };
  214. static int qcom_dload_panic(struct notifier_block *this, unsigned long event,
  215. void *ptr)
  216. {
  217. struct qcom_dload *poweroff = container_of(this, struct qcom_dload,
  218. panic_nb);
  219. poweroff->in_panic = true;
  220. if (IS_ENABLED(CONFIG_SEC_QC_QCOM_REBOOT_REASON))
  221. return NOTIFY_OK;
  222. if (enable_dump)
  223. msm_enable_dump_mode(true);
  224. return NOTIFY_OK;
  225. }
  226. static int qcom_dload_restart(struct notifier_block *this, unsigned long event,
  227. void *ptr)
  228. {
  229. struct qcom_dload *poweroff = container_of(this, struct qcom_dload,
  230. restart_nb);
  231. if (!poweroff->in_panic && !poweroff->in_reboot) {
  232. qcom_scm_disable_sdi();
  233. set_download_mode(QCOM_DOWNLOAD_NODUMP);
  234. }
  235. return NOTIFY_OK;
  236. }
  237. static int qcom_dload_reboot(struct notifier_block *this, unsigned long event,
  238. void *ptr)
  239. {
  240. char *cmd = ptr;
  241. struct qcom_dload *poweroff = container_of(this, struct qcom_dload,
  242. reboot_nb);
  243. poweroff->in_reboot = true;
  244. set_download_mode(QCOM_DOWNLOAD_NODUMP);
  245. if (cmd) {
  246. if (!strcmp(cmd, "edl"))
  247. set_download_mode(QCOM_DOWNLOAD_EDL);
  248. else if (!strcmp(cmd, "qcom_dload"))
  249. msm_enable_dump_mode(true);
  250. }
  251. if (current_download_mode != QCOM_DOWNLOAD_NODUMP)
  252. reboot_mode = REBOOT_WARM;
  253. return NOTIFY_OK;
  254. }
  255. static void __iomem *map_prop_mem(const char *propname)
  256. {
  257. struct device_node *np = of_find_compatible_node(NULL, NULL, propname);
  258. void __iomem *addr;
  259. if (!np) {
  260. pr_err("Unable to find DT property: %s\n", propname);
  261. return NULL;
  262. }
  263. addr = of_iomap(np, 0);
  264. if (!addr)
  265. pr_err("Unable to map memory for DT property: %s\n", propname);
  266. return addr;
  267. }
  268. static int qcom_dload_probe(struct platform_device *pdev)
  269. {
  270. struct qcom_dload *poweroff;
  271. int ret, temp;
  272. poweroff = devm_kzalloc(&pdev->dev, sizeof(*poweroff), GFP_KERNEL);
  273. if (!poweroff)
  274. return -ENOMEM;
  275. ret = kobject_init_and_add(&poweroff->kobj, &qcom_dload_kobj_type,
  276. kernel_kobj, "dload");
  277. if (ret) {
  278. pr_err("%s: Error in creation kobject_add\n", __func__);
  279. kobject_put(&poweroff->kobj);
  280. return ret;
  281. }
  282. ret = sysfs_create_group(&poweroff->kobj, &qcom_dload_attr_group);
  283. if (ret) {
  284. pr_err("%s: Error in creation sysfs_create_group\n", __func__);
  285. kobject_del(&poweroff->kobj);
  286. return ret;
  287. }
  288. poweroff->dload_dest_addr = map_prop_mem("qcom,msm-imem-dload-type");
  289. msm_enable_dump_mode(enable_dump);
  290. dump_mode = qcom_scm_get_download_mode(&temp, 0) ? dump_mode : temp;
  291. pr_info("%s: Current dump mode: 0x%x\n", __func__, dump_mode);
  292. if (!enable_dump)
  293. qcom_scm_disable_sdi();
  294. poweroff->panic_nb.notifier_call = qcom_dload_panic;
  295. poweroff->panic_nb.priority = INT_MAX;
  296. atomic_notifier_chain_register(&panic_notifier_list,
  297. &poweroff->panic_nb);
  298. poweroff->reboot_nb.notifier_call = qcom_dload_reboot;
  299. poweroff->reboot_nb.priority = 255;
  300. register_reboot_notifier(&poweroff->reboot_nb);
  301. poweroff->restart_nb.notifier_call = qcom_dload_restart;
  302. poweroff->restart_nb.priority = 201;
  303. register_restart_handler(&poweroff->restart_nb);
  304. platform_set_drvdata(pdev, poweroff);
  305. return 0;
  306. }
  307. static int qcom_dload_remove(struct platform_device *pdev)
  308. {
  309. struct qcom_dload *poweroff = platform_get_drvdata(pdev);
  310. atomic_notifier_chain_unregister(&panic_notifier_list,
  311. &poweroff->panic_nb);
  312. unregister_restart_handler(&poweroff->restart_nb);
  313. unregister_reboot_notifier(&poweroff->reboot_nb);
  314. if (poweroff->dload_dest_addr)
  315. iounmap(poweroff->dload_dest_addr);
  316. return 0;
  317. }
  318. static const struct of_device_id of_qcom_dload_match[] = {
  319. { .compatible = "qcom,dload-mode", },
  320. {},
  321. };
  322. MODULE_DEVICE_TABLE(of, of_qcom_dload_match);
  323. static struct platform_driver qcom_dload_driver = {
  324. .probe = qcom_dload_probe,
  325. .remove = qcom_dload_remove,
  326. .driver = {
  327. .name = "qcom-dload-mode",
  328. .of_match_table = of_match_ptr(of_qcom_dload_match),
  329. },
  330. };
  331. static int __init qcom_dload_driver_init(void)
  332. {
  333. return platform_driver_register(&qcom_dload_driver);
  334. }
  335. #if IS_MODULE(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE)
  336. module_init(qcom_dload_driver_init);
  337. #else
  338. fs_initcall(qcom_dload_driver_init);
  339. #endif
  340. static void __exit qcom_dload_driver_exit(void)
  341. {
  342. return platform_driver_unregister(&qcom_dload_driver);
  343. }
  344. module_exit(qcom_dload_driver_exit);
  345. MODULE_DESCRIPTION("MSM Download Mode Driver");
  346. MODULE_LICENSE("GPL v2");
  347. #if IS_ENABLED(CONFIG_SEC_QC_QCOM_REBOOT_REASON)
  348. void qcom_set_dload_mode(int on)
  349. {
  350. if (on)
  351. set_download_mode(QCOM_DOWNLOAD_FULLDUMP);
  352. else
  353. set_download_mode(QCOM_DOWNLOAD_NODUMP);
  354. pr_warn("set_dload_mode <%d> (%pS)\n", on, __builtin_return_address(0));
  355. }
  356. EXPORT_SYMBOL(qcom_set_dload_mode);
  357. #endif