1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2d16046ffSLiam Girdwood // 3d16046ffSLiam Girdwood // This file is provided under a dual BSD/GPLv2 license. When using or 4d16046ffSLiam Girdwood // redistributing this file, you may do so under either license. 5d16046ffSLiam Girdwood // 6d16046ffSLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved. 7d16046ffSLiam Girdwood // 8d16046ffSLiam Girdwood // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9d16046ffSLiam Girdwood // Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 10d16046ffSLiam Girdwood // Rander Wang <rander.wang@intel.com> 11d16046ffSLiam Girdwood // Keyon Jie <yang.jie@linux.intel.com> 12d16046ffSLiam Girdwood // 13d16046ffSLiam Girdwood 14d16046ffSLiam Girdwood /* 15d16046ffSLiam Girdwood * Hardware interface for HDA DSP code loader 16d16046ffSLiam Girdwood */ 17d16046ffSLiam Girdwood 18d16046ffSLiam Girdwood #include <linux/firmware.h> 19d16046ffSLiam Girdwood #include <sound/hdaudio_ext.h> 20acf705a4SRanjani Sridharan #include <sound/hda_register.h> 21d16046ffSLiam Girdwood #include <sound/sof.h> 22edbaaadaSFred Oh #include "ext_manifest.h" 23d16046ffSLiam Girdwood #include "../ops.h" 24d16046ffSLiam Girdwood #include "hda.h" 25d16046ffSLiam Girdwood 26d43e3813SRanjani Sridharan #define HDA_CL_STREAM_FORMAT 0x40 27d16046ffSLiam Girdwood 2801d42d5aSRanjani Sridharan static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, 29d16046ffSLiam Girdwood unsigned int size, struct snd_dma_buffer *dmab, 30d16046ffSLiam Girdwood int direction) 31d16046ffSLiam Girdwood { 32d16046ffSLiam Girdwood struct hdac_ext_stream *dsp_stream; 33d16046ffSLiam Girdwood struct hdac_stream *hstream; 34d16046ffSLiam Girdwood struct pci_dev *pci = to_pci_dev(sdev->dev); 35d16046ffSLiam Girdwood int ret; 36d16046ffSLiam Girdwood 3789a400bdSRanjani Sridharan dsp_stream = hda_dsp_stream_get(sdev, direction, 0); 38d16046ffSLiam Girdwood 39d16046ffSLiam Girdwood if (!dsp_stream) { 40d16046ffSLiam Girdwood dev_err(sdev->dev, "error: no stream available\n"); 4101d42d5aSRanjani Sridharan return ERR_PTR(-ENODEV); 42d16046ffSLiam Girdwood } 43d16046ffSLiam Girdwood hstream = &dsp_stream->hstream; 444ff5f643SKai Vehmanen hstream->substream = NULL; 45d16046ffSLiam Girdwood 46d16046ffSLiam Girdwood /* allocate DMA buffer */ 47d16046ffSLiam Girdwood ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); 48d16046ffSLiam Girdwood if (ret < 0) { 49ce1f55baSCurtis Malainey dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret); 50d16046ffSLiam Girdwood goto error; 51d16046ffSLiam Girdwood } 52d16046ffSLiam Girdwood 53d16046ffSLiam Girdwood hstream->period_bytes = 0;/* initialize period_bytes */ 54d16046ffSLiam Girdwood hstream->format_val = format; 55d16046ffSLiam Girdwood hstream->bufsize = size; 56d16046ffSLiam Girdwood 57acf705a4SRanjani Sridharan if (direction == SNDRV_PCM_STREAM_CAPTURE) { 58acf705a4SRanjani Sridharan ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); 59acf705a4SRanjani Sridharan if (ret < 0) { 60ce1f55baSCurtis Malainey dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret); 61acf705a4SRanjani Sridharan goto error; 62acf705a4SRanjani Sridharan } 63acf705a4SRanjani Sridharan } else { 64d16046ffSLiam Girdwood ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); 65d16046ffSLiam Girdwood if (ret < 0) { 66ce1f55baSCurtis Malainey dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret); 67d16046ffSLiam Girdwood goto error; 68d16046ffSLiam Girdwood } 69d16046ffSLiam Girdwood hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); 70acf705a4SRanjani Sridharan } 71d16046ffSLiam Girdwood 7201d42d5aSRanjani Sridharan return dsp_stream; 73d16046ffSLiam Girdwood 74d16046ffSLiam Girdwood error: 75d16046ffSLiam Girdwood hda_dsp_stream_put(sdev, direction, hstream->stream_tag); 76d16046ffSLiam Girdwood snd_dma_free_pages(dmab); 7701d42d5aSRanjani Sridharan return ERR_PTR(ret); 78d16046ffSLiam Girdwood } 79d16046ffSLiam Girdwood 80d16046ffSLiam Girdwood /* 81d16046ffSLiam Girdwood * first boot sequence has some extra steps. core 0 waits for power 82d16046ffSLiam Girdwood * status on core 1, so power up core 1 also momentarily, keep it in 83d16046ffSLiam Girdwood * reset/stall and then turn it off 84d16046ffSLiam Girdwood */ 85776100a4SPierre-Louis Bossart static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) 86d16046ffSLiam Girdwood { 87d16046ffSLiam Girdwood struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 88d16046ffSLiam Girdwood const struct sof_intel_dsp_desc *chip = hda->desc; 89d16046ffSLiam Girdwood unsigned int status; 90d4165199SRanjani Sridharan unsigned long mask; 91d4165199SRanjani Sridharan u32 flags, j; 92d16046ffSLiam Girdwood int ret; 9374ed4097SZhu Yingjiang int i; 94d16046ffSLiam Girdwood 95d16046ffSLiam Girdwood /* step 1: power up corex */ 96d4165199SRanjani Sridharan ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask); 97d16046ffSLiam Girdwood if (ret < 0) { 98776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 99d16046ffSLiam Girdwood dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); 100d16046ffSLiam Girdwood goto err; 101d16046ffSLiam Girdwood } 102d16046ffSLiam Girdwood 10374ed4097SZhu Yingjiang /* DSP is powered up, set all SSPs to slave mode */ 10474ed4097SZhu Yingjiang for (i = 0; i < chip->ssp_count; i++) { 10574ed4097SZhu Yingjiang snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, 10674ed4097SZhu Yingjiang chip->ssp_base_offset 10774ed4097SZhu Yingjiang + i * SSP_DEV_MEM_SIZE 10874ed4097SZhu Yingjiang + SSP_SSC1_OFFSET, 10974ed4097SZhu Yingjiang SSP_SET_SLAVE, 11074ed4097SZhu Yingjiang SSP_SET_SLAVE); 11174ed4097SZhu Yingjiang } 11274ed4097SZhu Yingjiang 113d16046ffSLiam Girdwood /* step 2: purge FW request */ 114d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, 115d16046ffSLiam Girdwood chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | 116d16046ffSLiam Girdwood ((stream_tag - 1) << 9))); 117d16046ffSLiam Girdwood 118d16046ffSLiam Girdwood /* step 3: unset core 0 reset state & unstall/run core 0 */ 119fde10655SRanjani Sridharan ret = hda_dsp_core_run(sdev, BIT(0)); 120d16046ffSLiam Girdwood if (ret < 0) { 121776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 12253ec7531SRanjani Sridharan dev_err(sdev->dev, 12353ec7531SRanjani Sridharan "error: dsp core start failed %d\n", ret); 124d16046ffSLiam Girdwood ret = -EIO; 125d16046ffSLiam Girdwood goto err; 126d16046ffSLiam Girdwood } 127d16046ffSLiam Girdwood 128d16046ffSLiam Girdwood /* step 4: wait for IPC DONE bit from ROM */ 129d16046ffSLiam Girdwood ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 130d16046ffSLiam Girdwood chip->ipc_ack, status, 131d16046ffSLiam Girdwood ((status & chip->ipc_ack_mask) 132d16046ffSLiam Girdwood == chip->ipc_ack_mask), 133d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 134d16046ffSLiam Girdwood HDA_DSP_INIT_TIMEOUT_US); 135d16046ffSLiam Girdwood 136d16046ffSLiam Girdwood if (ret < 0) { 137776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 13853ec7531SRanjani Sridharan dev_err(sdev->dev, 13953ec7531SRanjani Sridharan "error: %s: timeout for HIPCIE done\n", 1406a414489SPierre-Louis Bossart __func__); 141d16046ffSLiam Girdwood goto err; 142d16046ffSLiam Girdwood } 143d16046ffSLiam Girdwood 1448354d9b4SKeyon Jie /* set DONE bit to clear the reply IPC message */ 1458354d9b4SKeyon Jie snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 1468354d9b4SKeyon Jie chip->ipc_ack, 1478354d9b4SKeyon Jie chip->ipc_ack_mask, 1488354d9b4SKeyon Jie chip->ipc_ack_mask); 1498354d9b4SKeyon Jie 150cedd502dSBard Liao /* step 5: power down cores that are no longer needed */ 151d4165199SRanjani Sridharan ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask & 152cedd502dSBard Liao ~(chip->init_core_mask)); 153d16046ffSLiam Girdwood if (ret < 0) { 154776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 15553ec7531SRanjani Sridharan dev_err(sdev->dev, 15653ec7531SRanjani Sridharan "error: dsp core x power down failed\n"); 157d16046ffSLiam Girdwood goto err; 158d16046ffSLiam Girdwood } 159d16046ffSLiam Girdwood 160d16046ffSLiam Girdwood /* step 6: enable IPC interrupts */ 161d16046ffSLiam Girdwood hda_dsp_ipc_int_enable(sdev); 162d16046ffSLiam Girdwood 163d16046ffSLiam Girdwood /* step 7: wait for ROM init */ 164d16046ffSLiam Girdwood ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 165d16046ffSLiam Girdwood HDA_DSP_SRAM_REG_ROM_STATUS, status, 166d16046ffSLiam Girdwood ((status & HDA_DSP_ROM_STS_MASK) 167d16046ffSLiam Girdwood == HDA_DSP_ROM_INIT), 168d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 169d16046ffSLiam Girdwood chip->rom_init_timeout * 170d16046ffSLiam Girdwood USEC_PER_MSEC); 171d4165199SRanjani Sridharan if (!ret) { 172d4165199SRanjani Sridharan /* set enabled cores mask and increment ref count for cores in init_core_mask */ 173d4165199SRanjani Sridharan sdev->enabled_cores_mask |= chip->init_core_mask; 174d4165199SRanjani Sridharan mask = sdev->enabled_cores_mask; 175d4165199SRanjani Sridharan for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES) 176d4165199SRanjani Sridharan sdev->dsp_core_ref_count[j]++; 177d16046ffSLiam Girdwood return 0; 178d4165199SRanjani Sridharan } 179d16046ffSLiam Girdwood 180776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1816a414489SPierre-Louis Bossart dev_err(sdev->dev, 1826a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 1836a414489SPierre-Louis Bossart __func__); 1846a414489SPierre-Louis Bossart 185d16046ffSLiam Girdwood err: 1867511b0edSPeter Ujfalusi flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; 1878f7ef6fcSRanjani Sridharan 18823013335SPeter Ujfalusi /* after max boot attempts make sure that the dump is printed */ 18923013335SPeter Ujfalusi if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1900ecaa2ffSPeter Ujfalusi flags &= ~SOF_DBG_DUMP_OPTIONAL; 1918f7ef6fcSRanjani Sridharan 1920ecaa2ffSPeter Ujfalusi snd_sof_dsp_dbg_dump(sdev, flags); 193d4165199SRanjani Sridharan hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); 194d16046ffSLiam Girdwood 195d16046ffSLiam Girdwood return ret; 196d16046ffSLiam Girdwood } 197d16046ffSLiam Girdwood 198d16046ffSLiam Girdwood static int cl_trigger(struct snd_sof_dev *sdev, 199d16046ffSLiam Girdwood struct hdac_ext_stream *stream, int cmd) 200d16046ffSLiam Girdwood { 201d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 202d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 203d16046ffSLiam Girdwood 204d16046ffSLiam Girdwood /* code loader is special case that reuses stream ops */ 205d16046ffSLiam Girdwood switch (cmd) { 206d16046ffSLiam Girdwood case SNDRV_PCM_TRIGGER_START: 207d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 208d16046ffSLiam Girdwood 1 << hstream->index, 209d16046ffSLiam Girdwood 1 << hstream->index); 210d16046ffSLiam Girdwood 211d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 212d16046ffSLiam Girdwood sd_offset, 213d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 214d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK, 215d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 216d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK); 217d16046ffSLiam Girdwood 218d16046ffSLiam Girdwood hstream->running = true; 219d16046ffSLiam Girdwood return 0; 220d16046ffSLiam Girdwood default: 221d16046ffSLiam Girdwood return hda_dsp_stream_trigger(sdev, stream, cmd); 222d16046ffSLiam Girdwood } 223d16046ffSLiam Girdwood } 224d16046ffSLiam Girdwood 225d16046ffSLiam Girdwood static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, 226d16046ffSLiam Girdwood struct hdac_ext_stream *stream) 227d16046ffSLiam Girdwood { 228d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 229d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 230acf705a4SRanjani Sridharan int ret = 0; 231d16046ffSLiam Girdwood 232acf705a4SRanjani Sridharan if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) 233d16046ffSLiam Girdwood ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); 234acf705a4SRanjani Sridharan else 235acf705a4SRanjani Sridharan snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 236acf705a4SRanjani Sridharan SOF_HDA_SD_CTL_DMA_START, 0); 237d16046ffSLiam Girdwood 238acf705a4SRanjani Sridharan hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); 239d16046ffSLiam Girdwood hstream->running = 0; 240d16046ffSLiam Girdwood hstream->substream = NULL; 241d16046ffSLiam Girdwood 242d16046ffSLiam Girdwood /* reset BDL address */ 243d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 244d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); 245d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 246d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); 247d16046ffSLiam Girdwood 248d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); 249d16046ffSLiam Girdwood snd_dma_free_pages(dmab); 250d16046ffSLiam Girdwood dmab->area = NULL; 251d16046ffSLiam Girdwood hstream->bufsize = 0; 252d16046ffSLiam Girdwood hstream->format_val = 0; 253d16046ffSLiam Girdwood 254d16046ffSLiam Girdwood return ret; 255d16046ffSLiam Girdwood } 256d16046ffSLiam Girdwood 257d16046ffSLiam Girdwood static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) 258d16046ffSLiam Girdwood { 259d16046ffSLiam Girdwood unsigned int reg; 260d16046ffSLiam Girdwood int ret, status; 261d16046ffSLiam Girdwood 262d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); 263d16046ffSLiam Girdwood if (ret < 0) { 264d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger start failed\n"); 265d16046ffSLiam Girdwood return ret; 266d16046ffSLiam Girdwood } 267d16046ffSLiam Girdwood 268d16046ffSLiam Girdwood status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 269d16046ffSLiam Girdwood HDA_DSP_SRAM_REG_ROM_STATUS, reg, 270d16046ffSLiam Girdwood ((reg & HDA_DSP_ROM_STS_MASK) 271d16046ffSLiam Girdwood == HDA_DSP_ROM_FW_ENTERED), 272d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 273d16046ffSLiam Girdwood HDA_DSP_BASEFW_TIMEOUT_US); 274d16046ffSLiam Girdwood 27576dc6a2bSPierre-Louis Bossart /* 27676dc6a2bSPierre-Louis Bossart * even in case of errors we still need to stop the DMAs, 27776dc6a2bSPierre-Louis Bossart * but we return the initial error should the DMA stop also fail 27876dc6a2bSPierre-Louis Bossart */ 27976dc6a2bSPierre-Louis Bossart 2806a414489SPierre-Louis Bossart if (status < 0) { 2816a414489SPierre-Louis Bossart dev_err(sdev->dev, 2826a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 2836a414489SPierre-Louis Bossart __func__); 2846a414489SPierre-Louis Bossart } 2856a414489SPierre-Louis Bossart 286d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); 287d16046ffSLiam Girdwood if (ret < 0) { 288d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger stop failed\n"); 28976dc6a2bSPierre-Louis Bossart if (!status) 29076dc6a2bSPierre-Louis Bossart status = ret; 291d16046ffSLiam Girdwood } 292d16046ffSLiam Girdwood 293d16046ffSLiam Girdwood return status; 294d16046ffSLiam Girdwood } 295d16046ffSLiam Girdwood 296acf705a4SRanjani Sridharan int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) 297acf705a4SRanjani Sridharan { 298acf705a4SRanjani Sridharan struct snd_sof_pdata *plat_data = sdev->pdata; 299acf705a4SRanjani Sridharan struct hdac_ext_stream *iccmax_stream; 300acf705a4SRanjani Sridharan struct hdac_bus *bus = sof_to_bus(sdev); 301acf705a4SRanjani Sridharan struct firmware stripped_firmware; 302acf705a4SRanjani Sridharan int ret, ret1; 303acf705a4SRanjani Sridharan u8 original_gb; 304acf705a4SRanjani Sridharan 305acf705a4SRanjani Sridharan /* save the original LTRP guardband value */ 306acf705a4SRanjani Sridharan original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; 307acf705a4SRanjani Sridharan 308acf705a4SRanjani Sridharan if (plat_data->fw->size <= plat_data->fw_offset) { 309acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 310acf705a4SRanjani Sridharan return -EINVAL; 311acf705a4SRanjani Sridharan } 312acf705a4SRanjani Sridharan 313acf705a4SRanjani Sridharan stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 314acf705a4SRanjani Sridharan 315acf705a4SRanjani Sridharan /* prepare capture stream for ICCMAX */ 31601d42d5aSRanjani Sridharan iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 317acf705a4SRanjani Sridharan &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); 31801d42d5aSRanjani Sridharan if (IS_ERR(iccmax_stream)) { 31901d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); 32001d42d5aSRanjani Sridharan return PTR_ERR(iccmax_stream); 321acf705a4SRanjani Sridharan } 322acf705a4SRanjani Sridharan 323acf705a4SRanjani Sridharan ret = hda_dsp_cl_boot_firmware(sdev); 324acf705a4SRanjani Sridharan 325acf705a4SRanjani Sridharan /* 326acf705a4SRanjani Sridharan * Perform iccmax stream cleanup. This should be done even if firmware loading fails. 327acf705a4SRanjani Sridharan * If the cleanup also fails, we return the initial error 328acf705a4SRanjani Sridharan */ 329acf705a4SRanjani Sridharan ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream); 330acf705a4SRanjani Sridharan if (ret1 < 0) { 331acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); 332acf705a4SRanjani Sridharan 333acf705a4SRanjani Sridharan /* set return value to indicate cleanup failure */ 334acf705a4SRanjani Sridharan if (!ret) 335acf705a4SRanjani Sridharan ret = ret1; 336acf705a4SRanjani Sridharan } 337acf705a4SRanjani Sridharan 338acf705a4SRanjani Sridharan /* restore the original guardband value after FW boot */ 339acf705a4SRanjani Sridharan snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb); 340acf705a4SRanjani Sridharan 341acf705a4SRanjani Sridharan return ret; 342acf705a4SRanjani Sridharan } 343acf705a4SRanjani Sridharan 344d16046ffSLiam Girdwood int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) 345d16046ffSLiam Girdwood { 346776100a4SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 347d16046ffSLiam Girdwood struct snd_sof_pdata *plat_data = sdev->pdata; 348d16046ffSLiam Girdwood const struct sof_dev_desc *desc = plat_data->desc; 349d16046ffSLiam Girdwood const struct sof_intel_dsp_desc *chip_info; 350d16046ffSLiam Girdwood struct hdac_ext_stream *stream; 351d16046ffSLiam Girdwood struct firmware stripped_firmware; 35201d42d5aSRanjani Sridharan int ret, ret1, i; 353d16046ffSLiam Girdwood 354d16046ffSLiam Girdwood chip_info = desc->chip_info; 355d16046ffSLiam Girdwood 356523773b9SKarol Trzcinski if (plat_data->fw->size <= plat_data->fw_offset) { 35792be17a5SKarol Trzcinski dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 35892be17a5SKarol Trzcinski return -EINVAL; 35992be17a5SKarol Trzcinski } 36092be17a5SKarol Trzcinski 36192be17a5SKarol Trzcinski stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; 36292be17a5SKarol Trzcinski stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 363d16046ffSLiam Girdwood 364d16046ffSLiam Girdwood /* init for booting wait */ 365d16046ffSLiam Girdwood init_waitqueue_head(&sdev->boot_wait); 366d16046ffSLiam Girdwood 367d16046ffSLiam Girdwood /* prepare DMA for code loader stream */ 36801d42d5aSRanjani Sridharan stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 369d16046ffSLiam Girdwood &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); 37001d42d5aSRanjani Sridharan if (IS_ERR(stream)) { 37101d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); 37201d42d5aSRanjani Sridharan return PTR_ERR(stream); 373d16046ffSLiam Girdwood } 374d16046ffSLiam Girdwood 375d16046ffSLiam Girdwood memcpy(sdev->dmab.area, stripped_firmware.data, 376d16046ffSLiam Girdwood stripped_firmware.size); 377d16046ffSLiam Girdwood 378d16046ffSLiam Girdwood /* try ROM init a few times before giving up */ 379d16046ffSLiam Girdwood for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { 38053ec7531SRanjani Sridharan dev_dbg(sdev->dev, 38153ec7531SRanjani Sridharan "Attempting iteration %d of Core En/ROM load...\n", i); 38253ec7531SRanjani Sridharan 383776100a4SPierre-Louis Bossart hda->boot_iteration = i + 1; 384776100a4SPierre-Louis Bossart ret = cl_dsp_init(sdev, stream->hstream.stream_tag); 385d16046ffSLiam Girdwood 386d16046ffSLiam Girdwood /* don't retry anymore if successful */ 387d16046ffSLiam Girdwood if (!ret) 388d16046ffSLiam Girdwood break; 389d16046ffSLiam Girdwood } 390d16046ffSLiam Girdwood 391d16046ffSLiam Girdwood if (i == HDA_FW_BOOT_ATTEMPTS) { 392d16046ffSLiam Girdwood dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", 393d16046ffSLiam Girdwood i, ret); 394d16046ffSLiam Girdwood goto cleanup; 395d16046ffSLiam Girdwood } 396d16046ffSLiam Girdwood 397d16046ffSLiam Girdwood /* 398bbd19cdcSRander Wang * When a SoundWire link is in clock stop state, a Slave 399bbd19cdcSRander Wang * device may trigger in-band wakes for events such as jack 400bbd19cdcSRander Wang * insertion or acoustic event detection. This event will lead 401bbd19cdcSRander Wang * to a WAKEEN interrupt, handled by the PCI device and routed 402bbd19cdcSRander Wang * to PME if the PCI device is in D3. The resume function in 403bbd19cdcSRander Wang * audio PCI driver will be invoked by ACPI for PME event and 404bbd19cdcSRander Wang * initialize the device and process WAKEEN interrupt. 405bbd19cdcSRander Wang * 406bbd19cdcSRander Wang * The WAKEEN interrupt should be processed ASAP to prevent an 407bbd19cdcSRander Wang * interrupt flood, otherwise other interrupts, such IPC, 408bbd19cdcSRander Wang * cannot work normally. The WAKEEN is handled after the ROM 409bbd19cdcSRander Wang * is initialized successfully, which ensures power rails are 410bbd19cdcSRander Wang * enabled before accessing the SoundWire SHIM registers 411bbd19cdcSRander Wang */ 412bbd19cdcSRander Wang if (!sdev->first_boot) 413bbd19cdcSRander Wang hda_sdw_process_wakeen(sdev); 414bbd19cdcSRander Wang 415bbd19cdcSRander Wang /* 416*b2b10aa7SPeter Ujfalusi * Set the boot_iteration to the last attempt, indicating that the 417*b2b10aa7SPeter Ujfalusi * DSP ROM has been initialized and from this point there will be no 418*b2b10aa7SPeter Ujfalusi * retry done to boot. 419*b2b10aa7SPeter Ujfalusi * 420*b2b10aa7SPeter Ujfalusi * Continue with code loading and firmware boot 421d16046ffSLiam Girdwood */ 422*b2b10aa7SPeter Ujfalusi hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS; 423d16046ffSLiam Girdwood ret = cl_copy_fw(sdev, stream); 424b278fc55SRanjani Sridharan if (!ret) { 425d16046ffSLiam Girdwood dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 426b278fc55SRanjani Sridharan } else { 4277511b0edSPeter Ujfalusi snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); 428d16046ffSLiam Girdwood dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); 429b278fc55SRanjani Sridharan } 430d16046ffSLiam Girdwood 431d16046ffSLiam Girdwood cleanup: 432d16046ffSLiam Girdwood /* 433d16046ffSLiam Girdwood * Perform codeloader stream cleanup. 434d16046ffSLiam Girdwood * This should be done even if firmware loading fails. 43576dc6a2bSPierre-Louis Bossart * If the cleanup also fails, we return the initial error 436d16046ffSLiam Girdwood */ 437d16046ffSLiam Girdwood ret1 = cl_cleanup(sdev, &sdev->dmab, stream); 438d16046ffSLiam Girdwood if (ret1 < 0) { 439d16046ffSLiam Girdwood dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); 440d16046ffSLiam Girdwood 441d16046ffSLiam Girdwood /* set return value to indicate cleanup failure */ 44276dc6a2bSPierre-Louis Bossart if (!ret) 443d16046ffSLiam Girdwood ret = ret1; 444d16046ffSLiam Girdwood } 445d16046ffSLiam Girdwood 446d16046ffSLiam Girdwood /* 44752e4d0aeSPierre-Louis Bossart * return primary core id if both fw copy 448d16046ffSLiam Girdwood * and stream clean up are successful 449d16046ffSLiam Girdwood */ 450d16046ffSLiam Girdwood if (!ret) 451d16046ffSLiam Girdwood return chip_info->init_core_mask; 452d16046ffSLiam Girdwood 453d16046ffSLiam Girdwood /* disable DSP */ 454d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, 455d16046ffSLiam Girdwood SOF_HDA_REG_PP_PPCTL, 456d16046ffSLiam Girdwood SOF_HDA_PPCTL_GPROCEN, 0); 457d16046ffSLiam Girdwood return ret; 458d16046ffSLiam Girdwood } 459d16046ffSLiam Girdwood 460d16046ffSLiam Girdwood /* pre fw run operations */ 461d16046ffSLiam Girdwood int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) 462d16046ffSLiam Girdwood { 463d16046ffSLiam Girdwood /* disable clock gating and power gating */ 464d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, false); 465d16046ffSLiam Girdwood } 466d16046ffSLiam Girdwood 467d16046ffSLiam Girdwood /* post fw run operations */ 468d16046ffSLiam Girdwood int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) 469d16046ffSLiam Girdwood { 47051dfed1eSPierre-Louis Bossart int ret; 47151dfed1eSPierre-Louis Bossart 47251dfed1eSPierre-Louis Bossart if (sdev->first_boot) { 47351dfed1eSPierre-Louis Bossart ret = hda_sdw_startup(sdev); 47451dfed1eSPierre-Louis Bossart if (ret < 0) { 47551dfed1eSPierre-Louis Bossart dev_err(sdev->dev, 47651dfed1eSPierre-Louis Bossart "error: could not startup SoundWire links\n"); 47751dfed1eSPierre-Louis Bossart return ret; 47851dfed1eSPierre-Louis Bossart } 47951dfed1eSPierre-Louis Bossart } 48051dfed1eSPierre-Louis Bossart 48151dfed1eSPierre-Louis Bossart hda_sdw_int_enable(sdev, true); 48251dfed1eSPierre-Louis Bossart 483d16046ffSLiam Girdwood /* re-enable clock gating and power gating */ 484d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, true); 485d16046ffSLiam Girdwood } 486edbaaadaSFred Oh 487edbaaadaSFred Oh int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, 488edbaaadaSFred Oh const struct sof_ext_man_elem_header *hdr) 489edbaaadaSFred Oh { 490edbaaadaSFred Oh const struct sof_ext_man_cavs_config_data *config_data = 491edbaaadaSFred Oh container_of(hdr, struct sof_ext_man_cavs_config_data, hdr); 492edbaaadaSFred Oh struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 493edbaaadaSFred Oh int i, elem_num; 494edbaaadaSFred Oh 495edbaaadaSFred Oh /* calculate total number of config data elements */ 496edbaaadaSFred Oh elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header)) 497edbaaadaSFred Oh / sizeof(struct sof_config_elem); 498edbaaadaSFred Oh if (elem_num <= 0) { 499edbaaadaSFred Oh dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num); 500edbaaadaSFred Oh return -EINVAL; 501edbaaadaSFred Oh } 502edbaaadaSFred Oh 503edbaaadaSFred Oh for (i = 0; i < elem_num; i++) 504edbaaadaSFred Oh switch (config_data->elems[i].token) { 505edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_EMPTY: 506edbaaadaSFred Oh /* skip empty token */ 507edbaaadaSFred Oh break; 508edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO: 509edbaaadaSFred Oh hda->clk_config_lpro = config_data->elems[i].value; 510edbaaadaSFred Oh dev_dbg(sdev->dev, "FW clock config: %s\n", 511edbaaadaSFred Oh hda->clk_config_lpro ? "LPRO" : "HPRO"); 512edbaaadaSFred Oh break; 513e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE: 514e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE: 515e3a85dbeSFred Oh /* These elements are defined but not being used yet. No warn is required */ 516e3a85dbeSFred Oh break; 517edbaaadaSFred Oh default: 518e3a85dbeSFred Oh dev_info(sdev->dev, "unsupported token type: %d\n", 519edbaaadaSFred Oh config_data->elems[i].token); 520edbaaadaSFred Oh } 521edbaaadaSFred Oh 522edbaaadaSFred Oh return 0; 523edbaaadaSFred Oh } 524