vha_plat_thead.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*!
  2. *****************************************************************************
  3. *
  4. * @File vha_plat_thead.c
  5. * ---------------------------------------------------------------------------
  6. *
  7. * Copyright (C) 2020 Alibaba Group Holding Limited
  8. *
  9. *****************************************************************************/
  10. #define DEBUG
  11. #include <linux/interrupt.h>
  12. #include <linux/device.h>
  13. #include <linux/module.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/of_address.h>
  16. #include <linux/of_irq.h>
  17. #include <linux/io.h>
  18. #include <linux/pm.h>
  19. #include <linux/version.h>
  20. #include <img_mem_man.h>
  21. #include "vha_common.h"
  22. #include "uapi/version.h"
  23. #include "vha_plat.h"
  24. #include "vha_plat_dt.h"
  25. #if defined(CFG_SYS_VAGUS)
  26. #include <hwdefs/vagus_system.h>
  27. #elif defined(CFG_SYS_AURA)
  28. #include <hwdefs/aura_system.h>
  29. #elif defined(CFG_SYS_MIRAGE)
  30. #include <hwdefs/mirage_system.h>
  31. #endif
  32. #define DEVICE_NAME "vha"
  33. /* Number of core cycles used to measure the core clock frequency */
  34. #define FREQ_MEASURE_CYCLES 0xfffffff
  35. static bool poll_interrupts; /* Disabled by default */
  36. module_param(poll_interrupts, bool, 0444);
  37. MODULE_PARM_DESC(poll_interrupts, "Poll for interrupts? 0: No, 1: Yes");
  38. static unsigned int irq_poll_interval_ms = 100; /* 100 ms */
  39. module_param(irq_poll_interval_ms, uint, 0444);
  40. MODULE_PARM_DESC(irq_poll_interval_ms, "Time in ms between each interrupt poll");
  41. /* Global timer used when irq poll mode is switched on.
  42. * NOTE: only single core instance is supported in polling mode */
  43. static struct poll_timer {
  44. struct platform_device *pdev;
  45. struct timer_list tmr;
  46. bool enabled;
  47. } irq_poll_timer;
  48. static ssize_t info_show(struct device_driver *drv, char *buf);
  49. static irqreturn_t dt_plat_thread_irq(int irq, void *dev_id)
  50. {
  51. struct platform_device *ofdev = (struct platform_device *)dev_id;
  52. return vha_handle_thread_irq(&ofdev->dev);
  53. }
  54. static irqreturn_t dt_plat_isrcb(int irq, void *dev_id)
  55. {
  56. struct platform_device *ofdev = (struct platform_device *)dev_id;
  57. if (!ofdev)
  58. return IRQ_NONE;
  59. return vha_handle_irq(&ofdev->dev);
  60. }
  61. /* Interrupt polling function */
  62. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
  63. static void dt_plat_poll_interrupt(struct timer_list *t)
  64. {
  65. struct poll_timer *poll_timer = from_timer(poll_timer, t, tmr);
  66. #else
  67. static void dt_plat_poll_interrupt(unsigned long ctx)
  68. {
  69. struct poll_timer *poll_timer = (struct poll_timer *)ctx;
  70. #endif
  71. struct platform_device *ofdev = poll_timer->pdev;
  72. int ret;
  73. if (!poll_timer->enabled)
  74. return;
  75. preempt_disable();
  76. ret = vha_handle_irq(&ofdev->dev);
  77. preempt_enable();
  78. if (ret == IRQ_WAKE_THREAD)
  79. vha_handle_thread_irq(&ofdev->dev);
  80. /* retrigger */
  81. mod_timer(&poll_timer->tmr,
  82. jiffies + msecs_to_jiffies(irq_poll_interval_ms));
  83. }
  84. static int vha_plat_probe(struct platform_device *ofdev)
  85. {
  86. int ret, module_irq;
  87. struct resource res;
  88. void __iomem *reg_addr;
  89. uint32_t reg_size, core_size;
  90. char info[256];
  91. info_show(ofdev->dev.driver, info);
  92. pr_info("%s: Version: %s\n", __func__, info);
  93. ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
  94. if (ret) {
  95. dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
  96. return ret;
  97. }
  98. pr_info("%s: registers %#llx-%#llx\n", __func__,
  99. (unsigned long long)res.start, (unsigned long long)res.end);
  100. module_irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
  101. if (module_irq == 0) {
  102. dev_err(&ofdev->dev, "could not map IRQ\n");
  103. return -ENXIO;
  104. }
  105. /* Assuming DT holds a single registers space entry that covers all regions,
  106. * So we need to do the split accordingly */
  107. reg_size = res.end - res.start + 1;
  108. #ifdef CFG_SYS_VAGUS
  109. core_size = _REG_SIZE + _REG_NNSYS_SIZE;
  110. #else
  111. core_size = _REG_SIZE;
  112. #endif
  113. if ((res.start + _REG_START) > res.end) {
  114. dev_err(&ofdev->dev, "wrong system conf for core region!\n");
  115. return -ENXIO;
  116. }
  117. if ((res.start + _REG_START + core_size) > res.end) {
  118. dev_warn(&ofdev->dev, "trimming system conf for core region!\n");
  119. core_size = reg_size - _REG_START;
  120. }
  121. #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
  122. reg_addr = devm_ioremap_nocache(&ofdev->dev, res.start +
  123. _REG_START, core_size);
  124. #else
  125. reg_addr = devm_ioremap(&ofdev->dev, res.start +
  126. _REG_START, core_size);
  127. #endif
  128. if (!reg_addr) {
  129. dev_err(&ofdev->dev, "failed to map core registers\n");
  130. return -ENXIO;
  131. }
  132. ret = vha_plat_dt_hw_init(ofdev);
  133. if (ret) {
  134. dev_err(&ofdev->dev, "failed to init platform-specific hw!\n");
  135. goto out_add_dev;
  136. }
  137. /* no 'per device' memory heaps used */
  138. ret = vha_add_dev(&ofdev->dev, NULL, 0,
  139. NULL /* plat priv data */, reg_addr, core_size);
  140. if (ret) {
  141. dev_err(&ofdev->dev, "failed to intialize driver core!\n");
  142. goto out_add_dev;
  143. }
  144. if (!poll_interrupts) {
  145. ret = devm_request_threaded_irq(&ofdev->dev, module_irq, &dt_plat_isrcb,
  146. &dt_plat_thread_irq, IRQF_SHARED, DEVICE_NAME, ofdev);
  147. if (ret) {
  148. dev_err(&ofdev->dev, "failed to request irq\n");
  149. goto out_irq;
  150. }
  151. } else {
  152. irq_poll_timer.pdev = ofdev;
  153. irq_poll_timer.enabled = true;
  154. /* Setup and start poll timer */
  155. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
  156. timer_setup(&irq_poll_timer.tmr, dt_plat_poll_interrupt, 0);
  157. #else
  158. setup_timer(&irq_poll_timer.tmr, dt_plat_poll_interrupt,
  159. (uintptr_t)&irq_poll_timer);
  160. #endif
  161. mod_timer(&irq_poll_timer.tmr,
  162. jiffies + msecs_to_jiffies(irq_poll_interval_ms));
  163. }
  164. /* Try to calibrate the core if needed */
  165. ret = vha_dev_calibrate(&ofdev->dev, FREQ_MEASURE_CYCLES);
  166. if (ret) {
  167. dev_err(&ofdev->dev, "%s: Failed to start clock calibration!\n", __func__);
  168. goto out_irq;
  169. }
  170. return ret;
  171. out_irq:
  172. vha_rm_dev(&ofdev->dev);
  173. out_add_dev:
  174. devm_iounmap(&ofdev->dev, reg_addr);
  175. return ret;
  176. }
  177. static int vha_plat_remove(struct platform_device *ofdev)
  178. {
  179. vha_rm_dev(&ofdev->dev);
  180. vha_plat_dt_hw_destroy(ofdev);
  181. return 0;
  182. }
  183. #ifdef CONFIG_PM
  184. static int vha_plat_suspend(struct device *dev)
  185. {
  186. struct platform_device *ofdev =
  187. container_of(dev, struct platform_device, dev);
  188. int ret = 0;
  189. ret = vha_suspend_dev(dev);
  190. if (ret)
  191. dev_err(dev, "failed to suspend the core!\n");
  192. else {
  193. ret = vha_plat_dt_hw_suspend(ofdev);
  194. if (ret)
  195. dev_err(dev, "failed to suspend platform-specific hw!\n");
  196. }
  197. return ret;
  198. }
  199. static int vha_plat_resume(struct device *dev)
  200. {
  201. struct platform_device *ofdev =
  202. container_of(dev, struct platform_device, dev);
  203. int ret = 0;
  204. ret = vha_plat_dt_hw_resume(ofdev);
  205. if (ret)
  206. dev_err(dev, "failed to resume platform-specific hw!\n");
  207. else {
  208. ret = vha_resume_dev(dev);
  209. if (ret)
  210. dev_err(dev, "failed to resume the core!\n");
  211. }
  212. return ret;
  213. }
  214. static int vha_plat_runtime_idle(struct device *dev)
  215. {
  216. return 0;
  217. }
  218. static int vha_plat_runtime_suspend(struct device *dev)
  219. {
  220. struct platform_device *ofdev =
  221. container_of(dev, struct platform_device, dev);
  222. int ret = 0;
  223. ret = vha_plat_dt_hw_suspend(ofdev);
  224. if (ret)
  225. dev_err(dev, "failed to suspend platform-specific hw!\n");
  226. return ret;
  227. }
  228. static int vha_plat_runtime_resume(struct device *dev)
  229. {
  230. struct platform_device *ofdev =
  231. container_of(dev, struct platform_device, dev);
  232. int ret = 0;
  233. ret = vha_plat_dt_hw_resume(ofdev);
  234. if (ret)
  235. dev_err(dev, "failed to resume platform-specific hw!\n");
  236. return ret;
  237. }
  238. #endif
  239. static struct dev_pm_ops vha_pm_plat_ops = {
  240. SET_RUNTIME_PM_OPS(vha_plat_runtime_suspend,
  241. vha_plat_runtime_resume, NULL)
  242. SET_SYSTEM_SLEEP_PM_OPS(vha_plat_suspend, vha_plat_resume)
  243. };
  244. static ssize_t info_show(struct device_driver *drv, char *buf)
  245. {
  246. return sprintf(buf, "VHA DT driver version : " VERSION_STRING "\n");
  247. }
  248. static DRIVER_ATTR_RO(info);
  249. static struct attribute *drv_attrs[] = {
  250. &driver_attr_info.attr,
  251. NULL
  252. };
  253. ATTRIBUTE_GROUPS(drv);
  254. static struct platform_driver vha_plat_drv = {
  255. .probe = vha_plat_probe,
  256. .remove = vha_plat_remove,
  257. .driver = {
  258. .name = "ax3xxx-nna",
  259. .groups = drv_groups,
  260. .owner = THIS_MODULE,
  261. .of_match_table = vha_plat_dt_of_ids,
  262. .pm = &vha_pm_plat_ops,
  263. },
  264. };
  265. int vha_plat_init(void)
  266. {
  267. int ret = 0;
  268. struct heap_config *heap_configs;
  269. int num_heaps;
  270. vha_plat_dt_get_heaps(&heap_configs, &num_heaps);
  271. ret = vha_init_plat_heaps(heap_configs, num_heaps);
  272. if (ret) {
  273. pr_err("failed to initialize global heaps\n");
  274. return -ENOMEM;
  275. }
  276. ret = platform_driver_register(&vha_plat_drv);
  277. if (ret) {
  278. pr_err("failed to register VHA driver!\n");
  279. return ret;
  280. }
  281. return 0;
  282. }
  283. int vha_plat_deinit(void)
  284. {
  285. int ret;
  286. if (poll_interrupts) {
  287. irq_poll_timer.enabled = false;
  288. del_timer_sync(&irq_poll_timer.tmr);
  289. }
  290. /* Unregister the driver from the OS */
  291. platform_driver_unregister(&vha_plat_drv);
  292. ret = vha_deinit();
  293. if (ret)
  294. pr_err("VHA driver deinit failed\n");
  295. return ret;
  296. }
  297. /*
  298. * coding style for emacs
  299. *
  300. * Local variables:
  301. * indent-tabs-mode: t
  302. * tab-width: 8
  303. * c-basic-offset: 8
  304. * End:
  305. */