mpfs-sys-controller.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Microchip PolarFire SoC (MPFS) system controller driver
  4. *
  5. * Copyright (c) 2020-2021 Microchip Corporation. All rights reserved.
  6. *
  7. * Author: Conor Dooley <conor.dooley@microchip.com>
  8. *
  9. */
  10. #include <linux/slab.h>
  11. #include <linux/kref.h>
  12. #include <linux/module.h>
  13. #include <linux/jiffies.h>
  14. #include <linux/mtd/mtd.h>
  15. #include <linux/spi/spi.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/of.h>
  18. #include <linux/mailbox_client.h>
  19. #include <linux/platform_device.h>
  20. #include <soc/microchip/mpfs.h>
  21. /*
  22. * This timeout must be long, as some services (example: image authentication)
  23. * take significant time to complete
  24. */
  25. #define MPFS_SYS_CTRL_TIMEOUT_MS 30000
  26. static DEFINE_MUTEX(transaction_lock);
  27. struct mpfs_sys_controller {
  28. struct mbox_client client;
  29. struct mbox_chan *chan;
  30. struct completion c;
  31. struct mtd_info *flash;
  32. struct kref consumers;
  33. };
  34. int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
  35. {
  36. unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
  37. int ret;
  38. ret = mutex_lock_interruptible(&transaction_lock);
  39. if (ret)
  40. return ret;
  41. reinit_completion(&sys_controller->c);
  42. ret = mbox_send_message(sys_controller->chan, msg);
  43. if (ret < 0) {
  44. dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n");
  45. goto out;
  46. }
  47. /*
  48. * Unfortunately, the system controller will only deliver an interrupt
  49. * if a service succeeds. mbox_send_message() will block until the busy
  50. * flag is gone. If the busy flag is gone but no interrupt has arrived
  51. * to trigger the rx callback then the service can be deemed to have
  52. * failed.
  53. * The caller can then interrogate msg::response::resp_status to
  54. * determine the cause of the failure.
  55. * mbox_send_message() returns positive integers in the success path, so
  56. * ret needs to be cleared if we do get an interrupt.
  57. */
  58. if (!wait_for_completion_timeout(&sys_controller->c, timeout)) {
  59. ret = -EBADMSG;
  60. dev_warn(sys_controller->client.dev,
  61. "MPFS sys controller service failed with status: %d\n",
  62. msg->response->resp_status);
  63. } else {
  64. ret = 0;
  65. }
  66. out:
  67. mutex_unlock(&transaction_lock);
  68. return ret;
  69. }
  70. EXPORT_SYMBOL(mpfs_blocking_transaction);
  71. static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg)
  72. {
  73. struct mpfs_sys_controller *sys_controller =
  74. container_of(client, struct mpfs_sys_controller, client);
  75. complete(&sys_controller->c);
  76. }
  77. static void mpfs_sys_controller_delete(struct kref *kref)
  78. {
  79. struct mpfs_sys_controller *sys_controller =
  80. container_of(kref, struct mpfs_sys_controller, consumers);
  81. mbox_free_channel(sys_controller->chan);
  82. kfree(sys_controller);
  83. }
  84. static void mpfs_sys_controller_put(void *data)
  85. {
  86. struct mpfs_sys_controller *sys_controller = data;
  87. kref_put(&sys_controller->consumers, mpfs_sys_controller_delete);
  88. }
  89. struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_client)
  90. {
  91. return mpfs_client->flash;
  92. }
  93. EXPORT_SYMBOL(mpfs_sys_controller_get_flash);
  94. static struct platform_device subdevs[] = {
  95. {
  96. .name = "mpfs-rng",
  97. .id = -1,
  98. },
  99. {
  100. .name = "mpfs-generic-service",
  101. .id = -1,
  102. },
  103. {
  104. .name = "mpfs-auto-update",
  105. .id = -1,
  106. },
  107. };
  108. static int mpfs_sys_controller_probe(struct platform_device *pdev)
  109. {
  110. struct device *dev = &pdev->dev;
  111. struct mpfs_sys_controller *sys_controller;
  112. struct device_node *np;
  113. int i, ret;
  114. sys_controller = kzalloc_obj(*sys_controller);
  115. if (!sys_controller)
  116. return -ENOMEM;
  117. np = of_parse_phandle(dev->of_node, "microchip,bitstream-flash", 0);
  118. if (!np)
  119. goto no_flash;
  120. sys_controller->flash = of_get_mtd_device_by_node(np);
  121. of_node_put(np);
  122. if (IS_ERR(sys_controller->flash)) {
  123. ret = dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
  124. goto out_free;
  125. }
  126. no_flash:
  127. sys_controller->client.dev = dev;
  128. sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback;
  129. sys_controller->client.tx_block = 1U;
  130. sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
  131. sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
  132. if (IS_ERR(sys_controller->chan)) {
  133. ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan),
  134. "Failed to get mbox channel\n");
  135. goto out_free;
  136. }
  137. init_completion(&sys_controller->c);
  138. kref_init(&sys_controller->consumers);
  139. platform_set_drvdata(pdev, sys_controller);
  140. for (i = 0; i < ARRAY_SIZE(subdevs); i++) {
  141. subdevs[i].dev.parent = dev;
  142. if (platform_device_register(&subdevs[i]))
  143. dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);
  144. }
  145. dev_info(&pdev->dev, "Registered MPFS system controller\n");
  146. return 0;
  147. out_free:
  148. kfree(sys_controller);
  149. return ret;
  150. }
  151. static void mpfs_sys_controller_remove(struct platform_device *pdev)
  152. {
  153. struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev);
  154. mpfs_sys_controller_put(sys_controller);
  155. }
  156. static const struct of_device_id mpfs_sys_controller_of_match[] = {
  157. {.compatible = "microchip,mpfs-sys-controller", },
  158. {},
  159. };
  160. MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match);
  161. struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev)
  162. {
  163. const struct of_device_id *match;
  164. struct mpfs_sys_controller *sys_controller;
  165. int ret;
  166. if (!dev->parent)
  167. goto err_no_device;
  168. match = of_match_node(mpfs_sys_controller_of_match, dev->parent->of_node);
  169. of_node_put(dev->parent->of_node);
  170. if (!match)
  171. goto err_no_device;
  172. sys_controller = dev_get_drvdata(dev->parent);
  173. if (!sys_controller)
  174. goto err_bad_device;
  175. if (!kref_get_unless_zero(&sys_controller->consumers))
  176. goto err_bad_device;
  177. ret = devm_add_action_or_reset(dev, mpfs_sys_controller_put, sys_controller);
  178. if (ret)
  179. return ERR_PTR(ret);
  180. return sys_controller;
  181. err_no_device:
  182. dev_dbg(dev, "Parent device was not an MPFS system controller\n");
  183. return ERR_PTR(-ENODEV);
  184. err_bad_device:
  185. dev_dbg(dev, "MPFS system controller found but could not register as a sub device\n");
  186. return ERR_PTR(-EPROBE_DEFER);
  187. }
  188. EXPORT_SYMBOL(mpfs_sys_controller_get);
  189. static struct platform_driver mpfs_sys_controller_driver = {
  190. .driver = {
  191. .name = "mpfs-sys-controller",
  192. .of_match_table = mpfs_sys_controller_of_match,
  193. },
  194. .probe = mpfs_sys_controller_probe,
  195. .remove = mpfs_sys_controller_remove,
  196. };
  197. module_platform_driver(mpfs_sys_controller_driver);
  198. MODULE_LICENSE("GPL v2");
  199. MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
  200. MODULE_DESCRIPTION("MPFS system controller driver");