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