xrp_hw_hikey960.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * xrp_hw_hikey: Simple xtensa/arm low-level XRP driver
  3. *
  4. * Copyright (c) 2018 Cadence Design Systems, Inc.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  21. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. *
  25. * Alternatively you can use and distribute this file under the terms of
  26. * the GNU General Public License version 2 or later.
  27. */
  28. #include <linux/delay.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/module.h>
  31. #include <linux/of.h>
  32. #include <linux/of_address.h>
  33. #include <linux/of_device.h>
  34. #include <linux/platform_device.h>
  35. #include <linux/slab.h>
  36. #include "xrp_hw.h"
  37. #include "xrp_hw_hikey960_dsp_interface.h"
  38. #include "xrp_ring_buffer.h"
  39. #include <linux/hisi/hisi_rproc.h>
  40. #include <ipcm/bsp_drv_ipc.h>
  41. #include <mailbox/drv_mailbox_msg.h>
  42. #define DRIVER_NAME "xrp-hw-hikey960"
  43. enum xrp_irq_mode {
  44. XRP_IRQ_NONE,
  45. XRP_IRQ_LEVEL,
  46. XRP_IRQ_EDGE,
  47. XRP_IRQ_MAX,
  48. };
  49. struct xrp_hw_hikey {
  50. struct xvp *xrp;
  51. struct device *dev;
  52. struct xrp_hw_hikey960_panic __iomem *panic;
  53. uint32_t last_read;
  54. /* how IRQ is used to notify the device of incoming data */
  55. enum xrp_irq_mode device_irq_mode;
  56. /* device IRQ# */
  57. u32 device_irq;
  58. /* how IRQ is used to notify the host of incoming data */
  59. enum xrp_irq_mode host_irq_mode;
  60. /* dummy host IRQ */
  61. u32 host_irq;
  62. };
  63. static void *get_hw_sync_data(void *hw_arg, size_t *sz)
  64. {
  65. struct xrp_hw_hikey *hw = hw_arg;
  66. struct xrp_hw_hikey960_sync_data *hw_sync_data =
  67. kmalloc(sizeof(*hw_sync_data), GFP_KERNEL);
  68. if (!hw_sync_data)
  69. return NULL;
  70. *hw_sync_data = (struct xrp_hw_hikey960_sync_data){
  71. .host_irq_mode = hw->host_irq_mode,
  72. .device_irq_mode = hw->device_irq_mode,
  73. .device_irq = hw->device_irq,
  74. };
  75. *sz = sizeof(*hw_sync_data);
  76. return hw_sync_data;
  77. }
  78. static int send_cmd_async(struct xrp_hw_hikey *hw, uint32_t mbx, uint32_t cmd)
  79. {
  80. int ret = RPROC_ASYNC_SEND(mbx, &cmd, 1);
  81. if (ret != 0) {
  82. dev_err(hw->dev, "%s: RPROC_ASYNC_SEND ret = %d\n",
  83. __func__, ret);
  84. }
  85. return ret;
  86. }
  87. static int send_cmd_sync(struct xrp_hw_hikey *hw, uint32_t mbx, uint32_t cmd)
  88. {
  89. int ret = hisi_rproc_xfer_sync_auto(mbx, &cmd, 1, NULL, 0);
  90. if (ret != 0) {
  91. dev_err(hw->dev, "%s: RPROC_SYNC_SEND ret = %d\n",
  92. __func__, ret);
  93. }
  94. return ret;
  95. }
  96. static int enable(void *hw_arg)
  97. {
  98. return 0;
  99. }
  100. static void disable(void *hw_arg)
  101. {
  102. }
  103. static void reset(void *hw_arg)
  104. {
  105. }
  106. static void dump_regs(const char *fn, void *hw_arg)
  107. {
  108. struct xrp_hw_hikey *hw = hw_arg;
  109. if (!hw->panic)
  110. return;
  111. dev_info(hw->dev, "%s: panic = 0x%08x, ccount = 0x%08x\n",
  112. fn,
  113. __raw_readl(&hw->panic->panic),
  114. __raw_readl(&hw->panic->ccount));
  115. dev_info(hw->dev, "%s: read = 0x%08x, write = 0x%08x, size = 0x%08x\n",
  116. fn,
  117. __raw_readl(&hw->panic->rb.read),
  118. __raw_readl(&hw->panic->rb.write),
  119. __raw_readl(&hw->panic->rb.size));
  120. }
  121. static void dump_log_page(struct xrp_hw_hikey *hw)
  122. {
  123. char *buf;
  124. size_t i;
  125. if (!hw->panic)
  126. return;
  127. dump_regs(__func__, hw);
  128. buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  129. if (buf) {
  130. memcpy_fromio(buf, hw->panic, PAGE_SIZE);
  131. for (i = 0; i < PAGE_SIZE; i += 64)
  132. dev_info(hw->dev, " %*pEhp\n", 64, buf + i);
  133. kfree(buf);
  134. } else {
  135. dev_err(hw->dev, " (couldn't allocate copy buffer)\n");
  136. }
  137. }
  138. static void halt(void *hw_arg)
  139. {
  140. struct xrp_hw_hikey *hw = hw_arg;
  141. int i;
  142. dev_dbg(hw->dev, "%s\n", __func__);
  143. dump_regs(__func__, hw);
  144. dump_log_page(hw);
  145. send_cmd_sync(hw_arg, HISI_RPROC_LPM3_MBX17,
  146. (16 << 16) | (3 << 8) | (1 << 0));
  147. for (i = 0; i < 10; ++i) {
  148. schedule();
  149. mdelay(1);
  150. dump_regs(__func__, hw);
  151. }
  152. dev_dbg(hw->dev, "%s done\n", __func__);
  153. }
  154. static void release(void *hw_arg)
  155. {
  156. struct xrp_hw_hikey *hw = hw_arg;
  157. int i;
  158. dev_dbg(hw->dev, "%s\n", __func__);
  159. dump_regs(__func__, hw);
  160. send_cmd_async(hw_arg, HISI_RPROC_HIFI_MBX18, 0xb007);
  161. for (i = 0; i < 10; ++i) {
  162. schedule();
  163. mdelay(1);
  164. dump_regs(__func__, hw);
  165. }
  166. dev_dbg(hw->dev, "%s done\n", __func__);
  167. }
  168. static void send_irq(void *hw_arg)
  169. {
  170. struct xrp_hw_hikey *hw = hw_arg;
  171. switch (hw->device_irq_mode) {
  172. case XRP_IRQ_EDGE:
  173. case XRP_IRQ_LEVEL:
  174. send_cmd_async(hw_arg, HISI_RPROC_HIFI_MBX18, 0);
  175. break;
  176. default:
  177. break;
  178. }
  179. }
  180. static void irq_handler(void *dev_id)
  181. {
  182. struct xrp_hw_hikey *hw = dev_id;
  183. dev_dbg(hw->dev, "%s\n", __func__);
  184. xrp_irq_handler(0, hw->xrp);
  185. DRV_k3IpcIntHandler_Autoack();
  186. }
  187. static void *irq_handler_context;
  188. static void irq1_handler(unsigned int dummy)
  189. {
  190. irq_handler(irq_handler_context);
  191. }
  192. static bool panic_check(void *hw_arg)
  193. {
  194. struct xrp_hw_hikey *hw = hw_arg;
  195. uint32_t panic;
  196. uint32_t ccount;
  197. uint32_t read;
  198. uint32_t write;
  199. uint32_t size;
  200. if (!hw->panic)
  201. return false;
  202. panic = __raw_readl(&hw->panic->panic);
  203. ccount = __raw_readl(&hw->panic->ccount);
  204. read = __raw_readl(&hw->panic->rb.read);
  205. write = __raw_readl(&hw->panic->rb.write);
  206. size = __raw_readl(&hw->panic->rb.size);
  207. if (read == 0 && read != hw->last_read) {
  208. dev_warn(hw->dev, "****************** device restarted >>>>>>>>>>>>>>>>>\n");
  209. dump_log_page(hw);
  210. dev_warn(hw->dev, "<<<<<<<<<<<<<<<<<< device restarted *****************\n");
  211. }
  212. if (write < size && read < size && size < PAGE_SIZE) {
  213. uint32_t tail;
  214. uint32_t total;
  215. char *buf = NULL;
  216. hw->last_read = read;
  217. if (read < write) {
  218. tail = write - read;
  219. total = tail;
  220. } else if (read == write) {
  221. tail = 0;
  222. total = 0;
  223. } else {
  224. tail = size - read;
  225. total = write + tail;
  226. }
  227. if (total)
  228. buf = kmalloc(total, GFP_KERNEL);
  229. if (buf) {
  230. uint32_t off = 0;
  231. dev_dbg(hw->dev, "panic = 0x%08x, ccount = 0x%08x read = %d, write = %d, size = %d, total = %d",
  232. panic, ccount, read, write, size, total);
  233. while (off != total) {
  234. memcpy_fromio(buf + off,
  235. hw->panic->rb.data + read,
  236. tail);
  237. read = 0;
  238. off += tail;
  239. tail = total - tail;
  240. }
  241. __raw_writel(write, &hw->panic->rb.read);
  242. hw->last_read = write;
  243. dev_info(hw->dev, "<<<\n%.*s\n>>>\n",
  244. total, buf);
  245. kfree(buf);
  246. } else if (total) {
  247. dev_err(hw->dev,
  248. "%s: couldn't allocate memory (%d) to read the dump\n",
  249. __func__, total);
  250. }
  251. } else {
  252. if (read != hw->last_read) {
  253. dev_warn(hw->dev,
  254. "nonsense in the log buffer: read = %d, write = %d, size = %d\n",
  255. read, write, size);
  256. hw->last_read = read;
  257. }
  258. }
  259. if (panic == 0xdeadbabe) {
  260. dev_info(hw->dev, "%s: panic detected, log dump:\n", __func__);
  261. dump_log_page(hw);
  262. }
  263. return panic == 0xdeadbabe;
  264. }
  265. static const struct xrp_hw_ops hw_ops = {
  266. .enable = enable,
  267. .disable = disable,
  268. .halt = halt,
  269. .release = release,
  270. .reset = reset,
  271. .get_hw_sync_data = get_hw_sync_data,
  272. .send_irq = send_irq,
  273. .panic_check = panic_check,
  274. };
  275. static long init_hw(struct platform_device *pdev, struct xrp_hw_hikey *hw,
  276. int mem_idx, enum xrp_init_flags *init_flags)
  277. {
  278. struct resource *mem;
  279. long ret;
  280. mem = platform_get_resource(pdev, IORESOURCE_MEM, mem_idx);
  281. if (mem) {
  282. hw->panic = devm_ioremap_resource(&pdev->dev, mem);
  283. if (IS_ERR(hw->panic)) {
  284. dev_dbg(&pdev->dev,
  285. "%s: couldn't ioremap abort/log region: %ld\n",
  286. __func__, PTR_ERR(hw->panic));
  287. hw->panic = NULL;
  288. } else {
  289. dev_dbg(&pdev->dev,
  290. "%s: log ring buffer = %pap, mapped at %p\n",
  291. __func__, &mem->start, hw->panic);
  292. }
  293. }
  294. ret = of_property_read_u32(pdev->dev.of_node,
  295. "device-irq",
  296. &hw->device_irq);
  297. if (ret == 0) {
  298. hw->device_irq_mode = XRP_IRQ_LEVEL;
  299. dev_dbg(&pdev->dev,
  300. "%s: device IRQ = %d\n",
  301. __func__, hw->device_irq);
  302. } else {
  303. dev_info(&pdev->dev,
  304. "using polling mode on the device side\n");
  305. }
  306. ret = of_property_read_u32(pdev->dev.of_node,
  307. "host-irq",
  308. &hw->host_irq);
  309. if (ret == 0) {
  310. hw->host_irq_mode = XRP_IRQ_LEVEL;
  311. dev_dbg(&pdev->dev, "%s: using host IRQ\n", __func__);
  312. irq_handler_context = hw;
  313. DRV_IPCIntInit();
  314. IPC_IntConnect(IPC_ACPU_INT_SRC_HIFI_MSG,
  315. irq1_handler, 0);
  316. IPC_IntEnable(IPC_ACPU_INT_SRC_HIFI_MSG);
  317. *init_flags |= XRP_INIT_USE_HOST_IRQ;
  318. } else {
  319. dev_info(&pdev->dev, "using polling mode on the host side\n");
  320. }
  321. return 0;
  322. }
  323. typedef long init_function(struct platform_device *pdev,
  324. struct xrp_hw_hikey *hw);
  325. static init_function init_v1;
  326. static long init_v1(struct platform_device *pdev, struct xrp_hw_hikey *hw)
  327. {
  328. long ret;
  329. enum xrp_init_flags init_flags = 0;
  330. ret = init_hw(pdev, hw, 1, &init_flags);
  331. if (ret < 0)
  332. return ret;
  333. return xrp_init_v1(pdev, init_flags, &hw_ops, hw);
  334. }
  335. static init_function init_cma;
  336. static long init_cma(struct platform_device *pdev, struct xrp_hw_hikey *hw)
  337. {
  338. long ret;
  339. enum xrp_init_flags init_flags = 0;
  340. ret = init_hw(pdev, hw, 0, &init_flags);
  341. if (ret < 0)
  342. return ret;
  343. return xrp_init_cma(pdev, init_flags, &hw_ops, hw);
  344. }
  345. #ifdef CONFIG_OF
  346. static const struct of_device_id xrp_hw_hikey_match[] = {
  347. {
  348. .compatible = "cdns,xrp-hw-hikey960,v1",
  349. .data = init_v1,
  350. }, {
  351. .compatible = "cdns,xrp-hw-hikey960,cma",
  352. .data = init_cma,
  353. }, {},
  354. };
  355. MODULE_DEVICE_TABLE(of, xrp_hw_hikey_match);
  356. #endif
  357. static int xrp_hw_hikey_probe(struct platform_device *pdev)
  358. {
  359. struct xrp_hw_hikey *hw =
  360. devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
  361. const struct of_device_id *match;
  362. init_function *init;
  363. long ret;
  364. if (!hw)
  365. return -ENOMEM;
  366. match = of_match_device(of_match_ptr(xrp_hw_hikey_match),
  367. &pdev->dev);
  368. if (!match)
  369. return -ENODEV;
  370. hw->dev = &pdev->dev;
  371. init = match->data;
  372. ret = init(pdev, hw);
  373. if (IS_ERR_VALUE(ret)) {
  374. xrp_deinit(pdev);
  375. return ret;
  376. } else {
  377. hw->xrp = ERR_PTR(ret);
  378. return 0;
  379. }
  380. }
  381. static int xrp_hw_hikey_remove(struct platform_device *pdev)
  382. {
  383. /*
  384. * There's no way to disconnect from IPC or disable IPC IRQ.
  385. * Do it here when it's available.
  386. */
  387. return xrp_deinit(pdev);
  388. }
  389. static int xrp_hw_hikey_idle(struct device *dev)
  390. {
  391. /* Power management is flaky, don't do it now. */
  392. return 1;
  393. }
  394. static const struct dev_pm_ops xrp_hw_hikey_pm_ops = {
  395. SET_RUNTIME_PM_OPS(xrp_runtime_suspend,
  396. xrp_runtime_resume,
  397. xrp_hw_hikey_idle)
  398. };
  399. static struct platform_driver xrp_hw_hikey_driver = {
  400. .probe = xrp_hw_hikey_probe,
  401. .remove = xrp_hw_hikey_remove,
  402. .driver = {
  403. .name = DRIVER_NAME,
  404. .of_match_table = of_match_ptr(xrp_hw_hikey_match),
  405. .pm = &xrp_hw_hikey_pm_ops,
  406. },
  407. };
  408. module_platform_driver(xrp_hw_hikey_driver);
  409. MODULE_AUTHOR("Max Filippov");
  410. MODULE_DESCRIPTION("XRP HiKey960: low level device driver for Xtensa Remote Processing");
  411. MODULE_LICENSE("Dual MIT/GPL");