skl.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2021-2022 Intel Corporation
  4. //
  5. // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
  6. // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  7. //
  8. #include <linux/devcoredump.h>
  9. #include <linux/slab.h>
  10. #include <sound/hdaudio_ext.h>
  11. #include "avs.h"
  12. #include "cldma.h"
  13. #include "messages.h"
  14. #include "registers.h"
  15. void avs_skl_ipc_interrupt(struct avs_dev *adev)
  16. {
  17. const struct avs_spec *spec = adev->spec;
  18. u32 hipc_ack, hipc_rsp;
  19. snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
  20. AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
  21. hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
  22. hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
  23. /* DSP acked host's request. */
  24. if (hipc_ack & spec->hipc->ack_done_mask) {
  25. complete(&adev->ipc->done_completion);
  26. /* Tell DSP it has our attention. */
  27. snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
  28. spec->hipc->ack_done_mask);
  29. }
  30. /* DSP sent new response to process */
  31. if (hipc_rsp & spec->hipc->rsp_busy_mask) {
  32. union avs_reply_msg msg;
  33. msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
  34. msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
  35. avs_dsp_process_response(adev, msg.val);
  36. /* Tell DSP we accepted its message. */
  37. snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY,
  38. SKL_ADSP_HIPCT_BUSY);
  39. }
  40. snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
  41. AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
  42. AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
  43. }
  44. static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev)
  45. {
  46. u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
  47. irqreturn_t ret = IRQ_NONE;
  48. if (adspis == UINT_MAX)
  49. return ret;
  50. if (adspis & AVS_ADSP_ADSPIS_CLDMA) {
  51. hda_cldma_interrupt(&code_loader);
  52. ret = IRQ_HANDLED;
  53. }
  54. if (adspis & AVS_ADSP_ADSPIS_IPC) {
  55. avs_skl_ipc_interrupt(adev);
  56. ret = IRQ_HANDLED;
  57. }
  58. return ret;
  59. }
  60. static int __maybe_unused
  61. avs_skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
  62. u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
  63. {
  64. struct avs_skl_log_state_info *info;
  65. u32 size, num_cores = adev->hw_cfg.dsp_cores;
  66. int ret, i;
  67. if (fls_long(resource_mask) > num_cores)
  68. return -EINVAL;
  69. size = struct_size(info, logs_core, num_cores);
  70. info = kzalloc(size, GFP_KERNEL);
  71. if (!info)
  72. return -ENOMEM;
  73. info->core_mask = resource_mask;
  74. if (enable)
  75. for_each_set_bit(i, &resource_mask, num_cores) {
  76. info->logs_core[i].enable = enable;
  77. info->logs_core[i].min_priority = *priorities++;
  78. }
  79. else
  80. for_each_set_bit(i, &resource_mask, num_cores)
  81. info->logs_core[i].enable = enable;
  82. ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
  83. kfree(info);
  84. if (ret)
  85. return AVS_IPC_RET(ret);
  86. return 0;
  87. }
  88. int avs_skl_log_buffer_offset(struct avs_dev *adev, u32 core)
  89. {
  90. return core * avs_log_buffer_size(adev);
  91. }
  92. /* fw DbgLogWp registers */
  93. #define FW_REGS_DBG_LOG_WP(core) (0x30 + 0x4 * core)
  94. static int avs_skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
  95. {
  96. void __iomem *buf;
  97. u16 size, write, offset;
  98. if (!avs_logging_fw(adev))
  99. return 0;
  100. size = avs_log_buffer_size(adev) / 2;
  101. write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
  102. /* determine buffer half */
  103. offset = (write < size) ? size : 0;
  104. /* Address is guaranteed to exist in SRAM2. */
  105. buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
  106. avs_dump_fw_log_wakeup(adev, buf, size);
  107. return 0;
  108. }
  109. static int avs_skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
  110. {
  111. u8 *dump;
  112. dump = vzalloc(AVS_FW_REGS_SIZE);
  113. if (!dump)
  114. return -ENOMEM;
  115. memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
  116. dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE, GFP_KERNEL);
  117. return 0;
  118. }
  119. static bool avs_skl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
  120. {
  121. /* unsupported on cAVS 1.5 hw */
  122. return false;
  123. }
  124. static int avs_skl_set_d0ix(struct avs_dev *adev, bool enable)
  125. {
  126. /* unsupported on cAVS 1.5 hw */
  127. return 0;
  128. }
  129. const struct avs_dsp_ops avs_skl_dsp_ops = {
  130. .power = avs_dsp_core_power,
  131. .reset = avs_dsp_core_reset,
  132. .stall = avs_dsp_core_stall,
  133. .dsp_interrupt = avs_skl_dsp_interrupt,
  134. .int_control = avs_dsp_interrupt_control,
  135. .load_basefw = avs_cldma_load_basefw,
  136. .load_lib = avs_cldma_load_library,
  137. .transfer_mods = avs_cldma_transfer_modules,
  138. .log_buffer_offset = avs_skl_log_buffer_offset,
  139. .log_buffer_status = avs_skl_log_buffer_status,
  140. .coredump = avs_skl_coredump,
  141. .d0ix_toggle = avs_skl_d0ix_toggle,
  142. .set_d0ix = avs_skl_set_d0ix,
  143. AVS_SET_ENABLE_LOGS_OP(skl)
  144. };