sst-dsp.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Intel Smart Sound Technology (SST) DSP Core Driver
  3. *
  4. * Copyright (C) 2013, Intel Corporation. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/slab.h>
  17. #include <linux/export.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/module.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/io.h>
  22. #include "sst-dsp.h"
  23. #include "sst-dsp-priv.h"
  24. #define CREATE_TRACE_POINTS
  25. #include <trace/events/intel-sst.h>
  26. /* Internal generic low-level SST IO functions - can be overidden */
  27. void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
  28. {
  29. writel(value, addr + offset);
  30. }
  31. EXPORT_SYMBOL_GPL(sst_shim32_write);
  32. u32 sst_shim32_read(void __iomem *addr, u32 offset)
  33. {
  34. return readl(addr + offset);
  35. }
  36. EXPORT_SYMBOL_GPL(sst_shim32_read);
  37. void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
  38. {
  39. memcpy_toio(addr + offset, &value, sizeof(value));
  40. }
  41. EXPORT_SYMBOL_GPL(sst_shim32_write64);
  42. u64 sst_shim32_read64(void __iomem *addr, u32 offset)
  43. {
  44. u64 val;
  45. memcpy_fromio(&val, addr + offset, sizeof(val));
  46. return val;
  47. }
  48. EXPORT_SYMBOL_GPL(sst_shim32_read64);
  49. static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
  50. u32 *src, size_t bytes)
  51. {
  52. int i, words = bytes >> 2;
  53. for (i = 0; i < words; i++)
  54. writel(src[i], dest + i);
  55. }
  56. static inline void _sst_memcpy_fromio_32(u32 *dest,
  57. const volatile __iomem u32 *src, size_t bytes)
  58. {
  59. int i, words = bytes >> 2;
  60. for (i = 0; i < words; i++)
  61. dest[i] = readl(src + i);
  62. }
  63. void sst_memcpy_toio_32(struct sst_dsp *sst,
  64. void __iomem *dest, void *src, size_t bytes)
  65. {
  66. _sst_memcpy_toio_32(dest, src, bytes);
  67. }
  68. EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
  69. void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
  70. void __iomem *src, size_t bytes)
  71. {
  72. _sst_memcpy_fromio_32(dest, src, bytes);
  73. }
  74. EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
  75. /* Public API */
  76. void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
  77. {
  78. unsigned long flags;
  79. spin_lock_irqsave(&sst->spinlock, flags);
  80. sst->ops->write(sst->addr.shim, offset, value);
  81. spin_unlock_irqrestore(&sst->spinlock, flags);
  82. }
  83. EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
  84. u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
  85. {
  86. unsigned long flags;
  87. u32 val;
  88. spin_lock_irqsave(&sst->spinlock, flags);
  89. val = sst->ops->read(sst->addr.shim, offset);
  90. spin_unlock_irqrestore(&sst->spinlock, flags);
  91. return val;
  92. }
  93. EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
  94. void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
  95. {
  96. unsigned long flags;
  97. spin_lock_irqsave(&sst->spinlock, flags);
  98. sst->ops->write64(sst->addr.shim, offset, value);
  99. spin_unlock_irqrestore(&sst->spinlock, flags);
  100. }
  101. EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
  102. u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
  103. {
  104. unsigned long flags;
  105. u64 val;
  106. spin_lock_irqsave(&sst->spinlock, flags);
  107. val = sst->ops->read64(sst->addr.shim, offset);
  108. spin_unlock_irqrestore(&sst->spinlock, flags);
  109. return val;
  110. }
  111. EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
  112. void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
  113. {
  114. sst->ops->write(sst->addr.shim, offset, value);
  115. }
  116. EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
  117. u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
  118. {
  119. return sst->ops->read(sst->addr.shim, offset);
  120. }
  121. EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
  122. void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
  123. {
  124. sst->ops->write64(sst->addr.shim, offset, value);
  125. }
  126. EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
  127. u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
  128. {
  129. return sst->ops->read64(sst->addr.shim, offset);
  130. }
  131. EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
  132. int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
  133. u32 mask, u32 value)
  134. {
  135. bool change;
  136. unsigned int old, new;
  137. u32 ret;
  138. ret = sst_dsp_shim_read_unlocked(sst, offset);
  139. old = ret;
  140. new = (old & (~mask)) | (value & mask);
  141. change = (old != new);
  142. if (change)
  143. sst_dsp_shim_write_unlocked(sst, offset, new);
  144. return change;
  145. }
  146. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
  147. int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
  148. u64 mask, u64 value)
  149. {
  150. bool change;
  151. u64 old, new;
  152. old = sst_dsp_shim_read64_unlocked(sst, offset);
  153. new = (old & (~mask)) | (value & mask);
  154. change = (old != new);
  155. if (change)
  156. sst_dsp_shim_write64_unlocked(sst, offset, new);
  157. return change;
  158. }
  159. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
  160. int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
  161. u32 mask, u32 value)
  162. {
  163. unsigned long flags;
  164. bool change;
  165. spin_lock_irqsave(&sst->spinlock, flags);
  166. change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
  167. spin_unlock_irqrestore(&sst->spinlock, flags);
  168. return change;
  169. }
  170. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
  171. int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
  172. u64 mask, u64 value)
  173. {
  174. unsigned long flags;
  175. bool change;
  176. spin_lock_irqsave(&sst->spinlock, flags);
  177. change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
  178. spin_unlock_irqrestore(&sst->spinlock, flags);
  179. return change;
  180. }
  181. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
  182. void sst_dsp_dump(struct sst_dsp *sst)
  183. {
  184. if (sst->ops->dump)
  185. sst->ops->dump(sst);
  186. }
  187. EXPORT_SYMBOL_GPL(sst_dsp_dump);
  188. void sst_dsp_reset(struct sst_dsp *sst)
  189. {
  190. if (sst->ops->reset)
  191. sst->ops->reset(sst);
  192. }
  193. EXPORT_SYMBOL_GPL(sst_dsp_reset);
  194. int sst_dsp_boot(struct sst_dsp *sst)
  195. {
  196. if (sst->ops->boot)
  197. sst->ops->boot(sst);
  198. return 0;
  199. }
  200. EXPORT_SYMBOL_GPL(sst_dsp_boot);
  201. int sst_dsp_wake(struct sst_dsp *sst)
  202. {
  203. if (sst->ops->wake)
  204. return sst->ops->wake(sst);
  205. return 0;
  206. }
  207. EXPORT_SYMBOL_GPL(sst_dsp_wake);
  208. void sst_dsp_sleep(struct sst_dsp *sst)
  209. {
  210. if (sst->ops->sleep)
  211. sst->ops->sleep(sst);
  212. }
  213. EXPORT_SYMBOL_GPL(sst_dsp_sleep);
  214. void sst_dsp_stall(struct sst_dsp *sst)
  215. {
  216. if (sst->ops->stall)
  217. sst->ops->stall(sst);
  218. }
  219. EXPORT_SYMBOL_GPL(sst_dsp_stall);
  220. void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
  221. {
  222. sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
  223. trace_sst_ipc_msg_tx(msg);
  224. }
  225. EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
  226. u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
  227. {
  228. u32 msg;
  229. msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
  230. trace_sst_ipc_msg_rx(msg);
  231. return msg;
  232. }
  233. EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
  234. int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
  235. u32 outbox_offset, size_t outbox_size)
  236. {
  237. sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
  238. sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
  239. sst->mailbox.in_size = inbox_size;
  240. sst->mailbox.out_size = outbox_size;
  241. return 0;
  242. }
  243. EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
  244. void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
  245. {
  246. u32 i;
  247. trace_sst_ipc_outbox_write(bytes);
  248. memcpy_toio(sst->mailbox.out_base, message, bytes);
  249. for (i = 0; i < bytes; i += 4)
  250. trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
  251. }
  252. EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
  253. void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
  254. {
  255. u32 i;
  256. trace_sst_ipc_outbox_read(bytes);
  257. memcpy_fromio(message, sst->mailbox.out_base, bytes);
  258. for (i = 0; i < bytes; i += 4)
  259. trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
  260. }
  261. EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
  262. void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
  263. {
  264. u32 i;
  265. trace_sst_ipc_inbox_write(bytes);
  266. memcpy_toio(sst->mailbox.in_base, message, bytes);
  267. for (i = 0; i < bytes; i += 4)
  268. trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
  269. }
  270. EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
  271. void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
  272. {
  273. u32 i;
  274. trace_sst_ipc_inbox_read(bytes);
  275. memcpy_fromio(message, sst->mailbox.in_base, bytes);
  276. for (i = 0; i < bytes; i += 4)
  277. trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
  278. }
  279. EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
  280. struct sst_dsp *sst_dsp_new(struct device *dev,
  281. struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
  282. {
  283. struct sst_dsp *sst;
  284. int err;
  285. dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
  286. sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
  287. if (sst == NULL)
  288. return NULL;
  289. spin_lock_init(&sst->spinlock);
  290. mutex_init(&sst->mutex);
  291. sst->dev = dev;
  292. sst->dma_dev = pdata->dma_dev;
  293. sst->thread_context = sst_dev->thread_context;
  294. sst->sst_dev = sst_dev;
  295. sst->id = pdata->id;
  296. sst->irq = pdata->irq;
  297. sst->ops = sst_dev->ops;
  298. sst->pdata = pdata;
  299. INIT_LIST_HEAD(&sst->used_block_list);
  300. INIT_LIST_HEAD(&sst->free_block_list);
  301. INIT_LIST_HEAD(&sst->module_list);
  302. INIT_LIST_HEAD(&sst->fw_list);
  303. INIT_LIST_HEAD(&sst->scratch_block_list);
  304. /* Initialise SST Audio DSP */
  305. if (sst->ops->init) {
  306. err = sst->ops->init(sst, pdata);
  307. if (err < 0)
  308. return NULL;
  309. }
  310. /* Register the ISR */
  311. err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
  312. sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
  313. if (err)
  314. goto irq_err;
  315. err = sst_dma_new(sst);
  316. if (err)
  317. dev_warn(dev, "sst_dma_new failed %d\n", err);
  318. return sst;
  319. irq_err:
  320. if (sst->ops->free)
  321. sst->ops->free(sst);
  322. return NULL;
  323. }
  324. EXPORT_SYMBOL_GPL(sst_dsp_new);
  325. void sst_dsp_free(struct sst_dsp *sst)
  326. {
  327. free_irq(sst->irq, sst);
  328. if (sst->ops->free)
  329. sst->ops->free(sst);
  330. sst_dma_free(sst->dma);
  331. }
  332. EXPORT_SYMBOL_GPL(sst_dsp_free);
  333. /* Module information */
  334. MODULE_AUTHOR("Liam Girdwood");
  335. MODULE_DESCRIPTION("Intel SST Core");
  336. MODULE_LICENSE("GPL v2");