sst-dsp.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Intel Smart Sound Technology (SST) DSP Core Driver
  4. *
  5. * Copyright (C) 2013, Intel Corporation. All rights reserved.
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/export.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/io-64-nonatomic-lo-hi.h>
  13. #include <linux/delay.h>
  14. #include "sst-dsp.h"
  15. #include "sst-dsp-priv.h"
  16. #define CREATE_TRACE_POINTS
  17. #include <trace/events/intel-sst.h>
  18. /* Internal generic low-level SST IO functions - can be overidden */
  19. void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
  20. {
  21. writel(value, addr + offset);
  22. }
  23. EXPORT_SYMBOL_GPL(sst_shim32_write);
  24. u32 sst_shim32_read(void __iomem *addr, u32 offset)
  25. {
  26. return readl(addr + offset);
  27. }
  28. EXPORT_SYMBOL_GPL(sst_shim32_read);
  29. void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
  30. {
  31. writeq(value, addr + offset);
  32. }
  33. EXPORT_SYMBOL_GPL(sst_shim32_write64);
  34. u64 sst_shim32_read64(void __iomem *addr, u32 offset)
  35. {
  36. return readq(addr + offset);
  37. }
  38. EXPORT_SYMBOL_GPL(sst_shim32_read64);
  39. /* Public API */
  40. void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
  41. {
  42. unsigned long flags;
  43. spin_lock_irqsave(&sst->spinlock, flags);
  44. sst->ops->write(sst->addr.shim, offset, value);
  45. spin_unlock_irqrestore(&sst->spinlock, flags);
  46. }
  47. EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
  48. u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
  49. {
  50. unsigned long flags;
  51. u32 val;
  52. spin_lock_irqsave(&sst->spinlock, flags);
  53. val = sst->ops->read(sst->addr.shim, offset);
  54. spin_unlock_irqrestore(&sst->spinlock, flags);
  55. return val;
  56. }
  57. EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
  58. void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
  59. {
  60. sst->ops->write(sst->addr.shim, offset, value);
  61. }
  62. EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
  63. u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
  64. {
  65. return sst->ops->read(sst->addr.shim, offset);
  66. }
  67. EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
  68. int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
  69. u32 mask, u32 value)
  70. {
  71. bool change;
  72. unsigned int old, new;
  73. u32 ret;
  74. ret = sst_dsp_shim_read_unlocked(sst, offset);
  75. old = ret;
  76. new = (old & (~mask)) | (value & mask);
  77. change = (old != new);
  78. if (change)
  79. sst_dsp_shim_write_unlocked(sst, offset, new);
  80. return change;
  81. }
  82. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
  83. /* This is for registers bits with attribute RWC */
  84. void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
  85. u32 mask, u32 value)
  86. {
  87. unsigned int old, new;
  88. u32 ret;
  89. ret = sst_dsp_shim_read_unlocked(sst, offset);
  90. old = ret;
  91. new = (old & (~mask)) | (value & mask);
  92. sst_dsp_shim_write_unlocked(sst, offset, new);
  93. }
  94. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
  95. int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
  96. u32 mask, u32 value)
  97. {
  98. unsigned long flags;
  99. bool change;
  100. spin_lock_irqsave(&sst->spinlock, flags);
  101. change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
  102. spin_unlock_irqrestore(&sst->spinlock, flags);
  103. return change;
  104. }
  105. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
  106. /* This is for registers bits with attribute RWC */
  107. void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
  108. u32 mask, u32 value)
  109. {
  110. unsigned long flags;
  111. spin_lock_irqsave(&sst->spinlock, flags);
  112. sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
  113. spin_unlock_irqrestore(&sst->spinlock, flags);
  114. }
  115. EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
  116. int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
  117. u32 target, u32 time, char *operation)
  118. {
  119. u32 reg;
  120. unsigned long timeout;
  121. int k = 0, s = 500;
  122. /*
  123. * split the loop into sleeps of varying resolution. more accurately,
  124. * the range of wakeups are:
  125. * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
  126. * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
  127. * (usleep_range (500, 1000) and usleep_range(5000, 10000) are
  128. * both possible in this phase depending on whether k > 10 or not).
  129. * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
  130. */
  131. timeout = jiffies + msecs_to_jiffies(time);
  132. while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
  133. && time_before(jiffies, timeout)) {
  134. k++;
  135. if (k > 10)
  136. s = 5000;
  137. usleep_range(s, 2*s);
  138. }
  139. if ((reg & mask) == target) {
  140. dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
  141. reg, operation);
  142. return 0;
  143. }
  144. dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n",
  145. reg, operation);
  146. return -ETIME;
  147. }
  148. EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
  149. int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
  150. u32 outbox_offset, size_t outbox_size)
  151. {
  152. sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
  153. sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
  154. sst->mailbox.in_size = inbox_size;
  155. sst->mailbox.out_size = outbox_size;
  156. return 0;
  157. }
  158. EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
  159. void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
  160. {
  161. u32 i;
  162. trace_sst_ipc_outbox_write(bytes);
  163. memcpy_toio(sst->mailbox.out_base, message, bytes);
  164. for (i = 0; i < bytes; i += 4)
  165. trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
  166. }
  167. EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
  168. void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
  169. {
  170. u32 i;
  171. trace_sst_ipc_outbox_read(bytes);
  172. memcpy_fromio(message, sst->mailbox.out_base, bytes);
  173. for (i = 0; i < bytes; i += 4)
  174. trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
  175. }
  176. EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
  177. void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
  178. {
  179. u32 i;
  180. trace_sst_ipc_inbox_write(bytes);
  181. memcpy_toio(sst->mailbox.in_base, message, bytes);
  182. for (i = 0; i < bytes; i += 4)
  183. trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
  184. }
  185. EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
  186. void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
  187. {
  188. u32 i;
  189. trace_sst_ipc_inbox_read(bytes);
  190. memcpy_fromio(message, sst->mailbox.in_base, bytes);
  191. for (i = 0; i < bytes; i += 4)
  192. trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
  193. }
  194. EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
  195. /* Module information */
  196. MODULE_AUTHOR("Liam Girdwood");
  197. MODULE_DESCRIPTION("Intel SST Core");
  198. MODULE_LICENSE("GPL v2");