1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // Copyright(c) 2020 Intel Corporation. All rights reserved. 4 // 5 // Author: Fred Oh <fred.oh@linux.intel.com> 6 // 7 8 /* 9 * Hardware interface for audio DSP on IceLake. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/kconfig.h> 14 #include <linux/export.h> 15 #include <linux/bits.h> 16 #include "../ops.h" 17 #include "hda.h" 18 #include "hda-ipc.h" 19 #include "../sof-audio.h" 20 21 #define ICL_DSP_HPRO_CORE_ID 3 22 23 static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = { 24 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, 25 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, 26 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, 27 }; 28 29 static int icl_dsp_core_stall(struct snd_sof_dev *sdev, unsigned int core_mask) 30 { 31 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 32 const struct sof_intel_dsp_desc *chip = hda->desc; 33 34 /* make sure core_mask in host managed cores */ 35 core_mask &= chip->host_managed_cores_mask; 36 if (!core_mask) { 37 dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); 38 return -EINVAL; 39 } 40 41 /* stall core */ 42 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, 43 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), 44 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); 45 46 return 0; 47 } 48 49 /* 50 * post fw run operation for ICL. 51 * Core 3 will be powered up and in stall when HPRO is enabled 52 */ 53 static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev) 54 { 55 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 56 int ret; 57 58 if (sdev->first_boot) { 59 ret = hda_sdw_startup(sdev); 60 if (ret < 0) { 61 dev_err(sdev->dev, "error: could not startup SoundWire links\n"); 62 return ret; 63 } 64 } 65 66 hda_sdw_int_enable(sdev, true); 67 68 /* 69 * The recommended HW programming sequence for ICL is to 70 * power up core 3 and keep it in stall if HPRO is enabled. 71 */ 72 if (!hda->clk_config_lpro) { 73 ret = hda_dsp_enable_core(sdev, BIT(ICL_DSP_HPRO_CORE_ID)); 74 if (ret < 0) { 75 dev_err(sdev->dev, "error: dsp core power up failed on core %d\n", 76 ICL_DSP_HPRO_CORE_ID); 77 return ret; 78 } 79 80 sdev->enabled_cores_mask |= BIT(ICL_DSP_HPRO_CORE_ID); 81 sdev->dsp_core_ref_count[ICL_DSP_HPRO_CORE_ID]++; 82 83 snd_sof_dsp_stall(sdev, BIT(ICL_DSP_HPRO_CORE_ID)); 84 } 85 86 /* re-enable clock gating and power gating */ 87 return hda_dsp_ctrl_clock_power_gating(sdev, true); 88 } 89 90 /* Icelake ops */ 91 const struct snd_sof_dsp_ops sof_icl_ops = { 92 /* probe/remove/shutdown */ 93 .probe = hda_dsp_probe, 94 .remove = hda_dsp_remove, 95 .shutdown = hda_dsp_shutdown, 96 97 /* Register IO */ 98 .write = sof_io_write, 99 .read = sof_io_read, 100 .write64 = sof_io_write64, 101 .read64 = sof_io_read64, 102 103 /* Block IO */ 104 .block_read = sof_block_read, 105 .block_write = sof_block_write, 106 107 /* Mailbox IO */ 108 .mailbox_read = sof_mailbox_read, 109 .mailbox_write = sof_mailbox_write, 110 111 /* doorbell */ 112 .irq_thread = cnl_ipc_irq_thread, 113 114 /* ipc */ 115 .send_msg = cnl_ipc_send_msg, 116 .fw_ready = sof_fw_ready, 117 .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, 118 .get_window_offset = hda_dsp_ipc_get_window_offset, 119 120 .ipc_msg_data = hda_ipc_msg_data, 121 .set_stream_data_offset = hda_set_stream_data_offset, 122 123 /* machine driver */ 124 .machine_select = hda_machine_select, 125 .machine_register = sof_machine_register, 126 .machine_unregister = sof_machine_unregister, 127 .set_mach_params = hda_set_mach_params, 128 129 /* debug */ 130 .debug_map = icl_dsp_debugfs, 131 .debug_map_count = ARRAY_SIZE(icl_dsp_debugfs), 132 .dbg_dump = hda_dsp_dump, 133 .ipc_dump = cnl_ipc_dump, 134 .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, 135 136 /* stream callbacks */ 137 .pcm_open = hda_dsp_pcm_open, 138 .pcm_close = hda_dsp_pcm_close, 139 .pcm_hw_params = hda_dsp_pcm_hw_params, 140 .pcm_hw_free = hda_dsp_stream_hw_free, 141 .pcm_trigger = hda_dsp_pcm_trigger, 142 .pcm_pointer = hda_dsp_pcm_pointer, 143 .pcm_ack = hda_dsp_pcm_ack, 144 145 /* firmware loading */ 146 .load_firmware = snd_sof_load_firmware_raw, 147 148 /* pre/post fw run */ 149 .pre_fw_run = hda_dsp_pre_fw_run, 150 .post_fw_run = icl_dsp_post_fw_run, 151 152 /* parse platform specific extended manifest */ 153 .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, 154 155 /* dsp core get/put */ 156 .core_get = hda_dsp_core_get, 157 158 /* firmware run */ 159 .run = hda_dsp_cl_boot_firmware_iccmax, 160 .stall = icl_dsp_core_stall, 161 162 /* trace callback */ 163 .trace_init = hda_dsp_trace_init, 164 .trace_release = hda_dsp_trace_release, 165 .trace_trigger = hda_dsp_trace_trigger, 166 167 /* client ops */ 168 .register_ipc_clients = hda_register_clients, 169 .unregister_ipc_clients = hda_unregister_clients, 170 171 /* DAI drivers */ 172 .drv = skl_dai, 173 .num_drv = SOF_SKL_NUM_DAIS, 174 175 /* PM */ 176 .suspend = hda_dsp_suspend, 177 .resume = hda_dsp_resume, 178 .runtime_suspend = hda_dsp_runtime_suspend, 179 .runtime_resume = hda_dsp_runtime_resume, 180 .runtime_idle = hda_dsp_runtime_idle, 181 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, 182 .set_power_state = hda_dsp_set_power_state, 183 184 /* ALSA HW info flags */ 185 .hw_info = SNDRV_PCM_INFO_MMAP | 186 SNDRV_PCM_INFO_MMAP_VALID | 187 SNDRV_PCM_INFO_INTERLEAVED | 188 SNDRV_PCM_INFO_PAUSE | 189 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 190 191 .dsp_arch_ops = &sof_xtensa_arch_ops, 192 }; 193 EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); 194 195 const struct sof_intel_dsp_desc icl_chip_info = { 196 /* Icelake */ 197 .cores_num = 4, 198 .init_core_mask = 1, 199 .host_managed_cores_mask = GENMASK(3, 0), 200 .ipc_req = CNL_DSP_REG_HIPCIDR, 201 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 202 .ipc_ack = CNL_DSP_REG_HIPCIDA, 203 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 204 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 205 .rom_init_timeout = 300, 206 .ssp_count = ICL_SSP_COUNT, 207 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 208 .sdw_shim_base = SDW_SHIM_BASE, 209 .sdw_alh_base = SDW_ALH_BASE, 210 .check_sdw_irq = hda_common_check_sdw_irq, 211 }; 212 EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); 213