1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2024 Intel Corporation 4 // 5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 // 8 9 #include <linux/slab.h> 10 #include <sound/hdaudio.h> 11 #include <sound/hdaudio_ext.h> 12 #include "avs.h" 13 #include "debug.h" 14 #include "messages.h" 15 16 #define ICL_VS_LTRP_GB_ICCMAX 95 17 18 #ifdef CONFIG_DEBUG_FS 19 int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, 20 u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) 21 { 22 struct avs_icl_log_state_info *info; 23 u32 size, num_libs = adev->fw_cfg.max_libs_count; 24 int i, ret; 25 26 if (fls_long(resource_mask) > num_libs) 27 return -EINVAL; 28 size = struct_size(info, logs_priorities_mask, num_libs); 29 info = kzalloc(size, GFP_KERNEL); 30 if (!info) 31 return -ENOMEM; 32 33 info->aging_timer_period = aging_period; 34 info->fifo_full_timer_period = fifo_full_period; 35 info->enable = enable; 36 if (enable) 37 for_each_set_bit(i, &resource_mask, num_libs) 38 info->logs_priorities_mask[i] = *priorities++; 39 40 ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size); 41 kfree(info); 42 if (ret) 43 return AVS_IPC_RET(ret); 44 45 return 0; 46 } 47 #endif 48 49 union avs_icl_memwnd2_slot_type { 50 u32 val; 51 struct { 52 u32 resource_id:8; 53 u32 type:24; 54 }; 55 } __packed; 56 static_assert(sizeof(union avs_icl_memwnd2_slot_type) == 4); 57 58 struct avs_icl_memwnd2_desc { 59 u32 resource_id; 60 union avs_icl_memwnd2_slot_type slot_id; 61 u32 vma; 62 } __packed; 63 static_assert(sizeof(struct avs_icl_memwnd2_desc) == 12); 64 65 #define AVS_ICL_MEMWND2_SLOTS_COUNT 15 66 67 struct avs_icl_memwnd2 { 68 union { 69 struct avs_icl_memwnd2_desc slot_desc[AVS_ICL_MEMWND2_SLOTS_COUNT]; 70 u8 rsvd[SZ_4K]; 71 }; 72 u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][SZ_4K]; 73 } __packed; 74 static_assert(sizeof(struct avs_icl_memwnd2) == 65536); 75 76 #define AVS_ICL_SLOT_UNUSED \ 77 ((union avs_icl_memwnd2_slot_type) { 0x00000000U }) 78 #define AVS_ICL_SLOT_CRITICAL_LOG \ 79 ((union avs_icl_memwnd2_slot_type) { 0x54524300U }) 80 #define AVS_ICL_SLOT_DEBUG_LOG \ 81 ((union avs_icl_memwnd2_slot_type) { 0x474f4c00U }) 82 #define AVS_ICL_SLOT_GDB_STUB \ 83 ((union avs_icl_memwnd2_slot_type) { 0x42444700U }) 84 #define AVS_ICL_SLOT_BROKEN \ 85 ((union avs_icl_memwnd2_slot_type) { 0x44414544U }) 86 87 static int avs_icl_slot_offset(struct avs_dev *adev, union avs_icl_memwnd2_slot_type slot_type) 88 { 89 struct avs_icl_memwnd2_desc desc[AVS_ICL_MEMWND2_SLOTS_COUNT]; 90 int i; 91 92 memcpy_fromio(&desc, avs_sram_addr(adev, AVS_DEBUG_WINDOW), sizeof(desc)); 93 94 for (i = 0; i < AVS_ICL_MEMWND2_SLOTS_COUNT; i++) 95 if (desc[i].slot_id.val == slot_type.val) 96 return offsetof(struct avs_icl_memwnd2, slot_array) + i * SZ_4K; 97 return -ENXIO; 98 } 99 100 int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core) 101 { 102 union avs_icl_memwnd2_slot_type slot_type = AVS_ICL_SLOT_DEBUG_LOG; 103 int ret; 104 105 slot_type.resource_id = core; 106 ret = avs_icl_slot_offset(adev, slot_type); 107 if (ret < 0) 108 dev_dbg(adev->dev, "No slot offset found for: %x\n", 109 slot_type.val); 110 111 return ret; 112 } 113 114 bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake) 115 { 116 /* Full-power when starting DMA engines. */ 117 if (tx->glb.set_ppl_state.state == AVS_PPL_STATE_RUNNING) 118 return true; 119 120 /* Payload-less IPCs do not take part in d0ix toggling. */ 121 return tx->size; 122 } 123 124 int avs_icl_set_d0ix(struct avs_dev *adev, bool enable) 125 { 126 int ret; 127 128 ret = avs_ipc_set_d0ix(adev, enable, false); 129 return AVS_IPC_RET(ret); 130 } 131 132 int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw) 133 { 134 struct hdac_bus *bus = &adev->base.core; 135 struct hdac_ext_stream *host_stream; 136 struct snd_pcm_substream substream; 137 struct snd_dma_buffer dmab; 138 unsigned int sd_fmt; 139 u8 ltrp_gb; 140 int ret; 141 142 /* 143 * ICCMAX: 144 * 145 * For ICL+ platforms, as per HW recommendation LTRP_GB is set to 95us 146 * during FW load. Its original value shall be restored once load completes. 147 * 148 * To avoid DMI/OPIO L1 entry during the load procedure, additional CAPTURE 149 * stream is allocated and set to run. 150 */ 151 152 memset(&substream, 0, sizeof(substream)); 153 substream.stream = SNDRV_PCM_STREAM_CAPTURE; 154 155 host_stream = snd_hdac_ext_stream_assign(bus, &substream, HDAC_EXT_STREAM_TYPE_HOST); 156 if (!host_stream) 157 return -EBUSY; 158 159 ltrp_gb = snd_hdac_chip_readb(bus, VS_LTRP) & AZX_REG_VS_LTRP_GB_MASK; 160 /* Carries no real data, use default format. */ 161 sd_fmt = snd_hdac_stream_format(1, 32, 48000); 162 163 ret = snd_hdac_dsp_prepare(hdac_stream(host_stream), sd_fmt, fw->size, &dmab); 164 if (ret < 0) 165 goto release_stream; 166 167 snd_hdac_chip_updateb(bus, VS_LTRP, AZX_REG_VS_LTRP_GB_MASK, ICL_VS_LTRP_GB_ICCMAX); 168 169 spin_lock(&bus->reg_lock); 170 snd_hdac_stream_start(hdac_stream(host_stream)); 171 spin_unlock(&bus->reg_lock); 172 173 ret = avs_hda_load_basefw(adev, fw); 174 175 spin_lock(&bus->reg_lock); 176 snd_hdac_stream_stop(hdac_stream(host_stream)); 177 spin_unlock(&bus->reg_lock); 178 179 snd_hdac_dsp_cleanup(hdac_stream(host_stream), &dmab); 180 181 release_stream: 182 snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST); 183 snd_hdac_chip_updateb(bus, VS_LTRP, AZX_REG_VS_LTRP_GB_MASK, ltrp_gb); 184 185 return ret; 186 } 187 188 const struct avs_dsp_ops avs_icl_dsp_ops = { 189 .power = avs_dsp_core_power, 190 .reset = avs_dsp_core_reset, 191 .stall = avs_dsp_core_stall, 192 .dsp_interrupt = avs_cnl_dsp_interrupt, 193 .int_control = avs_dsp_interrupt_control, 194 .load_basefw = avs_icl_load_basefw, 195 .load_lib = avs_hda_load_library, 196 .transfer_mods = avs_hda_transfer_modules, 197 .log_buffer_offset = avs_icl_log_buffer_offset, 198 .log_buffer_status = avs_apl_log_buffer_status, 199 .coredump = avs_apl_coredump, 200 .d0ix_toggle = avs_icl_d0ix_toggle, 201 .set_d0ix = avs_icl_set_d0ix, 202 AVS_SET_ENABLE_LOGS_OP(icl) 203 }; 204