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 26d16046ffSLiam Girdwood #define HDA_FW_BOOT_ATTEMPTS 3 27d43e3813SRanjani Sridharan #define HDA_CL_STREAM_FORMAT 0x40 28d16046ffSLiam Girdwood 2901d42d5aSRanjani Sridharan static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, 30d16046ffSLiam Girdwood unsigned int size, struct snd_dma_buffer *dmab, 31d16046ffSLiam Girdwood int direction) 32d16046ffSLiam Girdwood { 33d16046ffSLiam Girdwood struct hdac_ext_stream *dsp_stream; 34d16046ffSLiam Girdwood struct hdac_stream *hstream; 35d16046ffSLiam Girdwood struct pci_dev *pci = to_pci_dev(sdev->dev); 36d16046ffSLiam Girdwood int ret; 37d16046ffSLiam Girdwood 3889a400bdSRanjani Sridharan dsp_stream = hda_dsp_stream_get(sdev, direction, 0); 39d16046ffSLiam Girdwood 40d16046ffSLiam Girdwood if (!dsp_stream) { 41d16046ffSLiam Girdwood dev_err(sdev->dev, "error: no stream available\n"); 4201d42d5aSRanjani Sridharan return ERR_PTR(-ENODEV); 43d16046ffSLiam Girdwood } 44d16046ffSLiam Girdwood hstream = &dsp_stream->hstream; 454ff5f643SKai Vehmanen hstream->substream = NULL; 46d16046ffSLiam Girdwood 47d16046ffSLiam Girdwood /* allocate DMA buffer */ 48d16046ffSLiam Girdwood ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); 49d16046ffSLiam Girdwood if (ret < 0) { 50d16046ffSLiam Girdwood dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret); 51d16046ffSLiam Girdwood goto error; 52d16046ffSLiam Girdwood } 53d16046ffSLiam Girdwood 54d16046ffSLiam Girdwood hstream->period_bytes = 0;/* initialize period_bytes */ 55d16046ffSLiam Girdwood hstream->format_val = format; 56d16046ffSLiam Girdwood hstream->bufsize = size; 57d16046ffSLiam Girdwood 58acf705a4SRanjani Sridharan if (direction == SNDRV_PCM_STREAM_CAPTURE) { 59acf705a4SRanjani Sridharan ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); 60acf705a4SRanjani Sridharan if (ret < 0) { 61acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret); 62acf705a4SRanjani Sridharan goto error; 63acf705a4SRanjani Sridharan } 64acf705a4SRanjani Sridharan } else { 65d16046ffSLiam Girdwood ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); 66d16046ffSLiam Girdwood if (ret < 0) { 67d16046ffSLiam Girdwood dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); 68d16046ffSLiam Girdwood goto error; 69d16046ffSLiam Girdwood } 70d16046ffSLiam Girdwood hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); 71acf705a4SRanjani Sridharan } 72d16046ffSLiam Girdwood 7301d42d5aSRanjani Sridharan return dsp_stream; 74d16046ffSLiam Girdwood 75d16046ffSLiam Girdwood error: 76d16046ffSLiam Girdwood hda_dsp_stream_put(sdev, direction, hstream->stream_tag); 77d16046ffSLiam Girdwood snd_dma_free_pages(dmab); 7801d42d5aSRanjani Sridharan return ERR_PTR(ret); 79d16046ffSLiam Girdwood } 80d16046ffSLiam Girdwood 81d16046ffSLiam Girdwood /* 82d16046ffSLiam Girdwood * first boot sequence has some extra steps. core 0 waits for power 83d16046ffSLiam Girdwood * status on core 1, so power up core 1 also momentarily, keep it in 84d16046ffSLiam Girdwood * reset/stall and then turn it off 85d16046ffSLiam Girdwood */ 86776100a4SPierre-Louis Bossart static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) 87d16046ffSLiam Girdwood { 88d16046ffSLiam Girdwood struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 89d16046ffSLiam Girdwood const struct sof_intel_dsp_desc *chip = hda->desc; 90d16046ffSLiam Girdwood unsigned int status; 918f7ef6fcSRanjani Sridharan u32 flags; 92d16046ffSLiam Girdwood int ret; 9374ed4097SZhu Yingjiang int i; 94d16046ffSLiam Girdwood 95d16046ffSLiam Girdwood /* step 1: power up corex */ 9664b96917SRanjani Sridharan ret = hda_dsp_core_power_up(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 150*cedd502dSBard Liao /* step 5: power down cores that are no longer needed */ 151*cedd502dSBard Liao ret = hda_dsp_core_power_down(sdev, chip->host_managed_cores_mask & 152*cedd502dSBard 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); 171d16046ffSLiam Girdwood if (!ret) 172d16046ffSLiam Girdwood return 0; 173d16046ffSLiam Girdwood 174776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1756a414489SPierre-Louis Bossart dev_err(sdev->dev, 1766a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 1776a414489SPierre-Louis Bossart __func__); 1786a414489SPierre-Louis Bossart 179d16046ffSLiam Girdwood err: 1808f7ef6fcSRanjani Sridharan flags = SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; 1818f7ef6fcSRanjani Sridharan 1828f7ef6fcSRanjani Sridharan /* force error log level after max boot attempts */ 1838f7ef6fcSRanjani Sridharan if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1848f7ef6fcSRanjani Sridharan flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL; 1858f7ef6fcSRanjani Sridharan 1868f7ef6fcSRanjani Sridharan hda_dsp_dump(sdev, flags); 187f6c246eaSBard Liao snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask); 188d16046ffSLiam Girdwood 189d16046ffSLiam Girdwood return ret; 190d16046ffSLiam Girdwood } 191d16046ffSLiam Girdwood 192d16046ffSLiam Girdwood static int cl_trigger(struct snd_sof_dev *sdev, 193d16046ffSLiam Girdwood struct hdac_ext_stream *stream, int cmd) 194d16046ffSLiam Girdwood { 195d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 196d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 197d16046ffSLiam Girdwood 198d16046ffSLiam Girdwood /* code loader is special case that reuses stream ops */ 199d16046ffSLiam Girdwood switch (cmd) { 200d16046ffSLiam Girdwood case SNDRV_PCM_TRIGGER_START: 201d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 202d16046ffSLiam Girdwood 1 << hstream->index, 203d16046ffSLiam Girdwood 1 << hstream->index); 204d16046ffSLiam Girdwood 205d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 206d16046ffSLiam Girdwood sd_offset, 207d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 208d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK, 209d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 210d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK); 211d16046ffSLiam Girdwood 212d16046ffSLiam Girdwood hstream->running = true; 213d16046ffSLiam Girdwood return 0; 214d16046ffSLiam Girdwood default: 215d16046ffSLiam Girdwood return hda_dsp_stream_trigger(sdev, stream, cmd); 216d16046ffSLiam Girdwood } 217d16046ffSLiam Girdwood } 218d16046ffSLiam Girdwood 219d16046ffSLiam Girdwood static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, 220d16046ffSLiam Girdwood struct hdac_ext_stream *stream) 221d16046ffSLiam Girdwood { 222d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 223d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 224acf705a4SRanjani Sridharan int ret = 0; 225d16046ffSLiam Girdwood 226acf705a4SRanjani Sridharan if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) 227d16046ffSLiam Girdwood ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); 228acf705a4SRanjani Sridharan else 229acf705a4SRanjani Sridharan snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 230acf705a4SRanjani Sridharan SOF_HDA_SD_CTL_DMA_START, 0); 231d16046ffSLiam Girdwood 232acf705a4SRanjani Sridharan hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); 233d16046ffSLiam Girdwood hstream->running = 0; 234d16046ffSLiam Girdwood hstream->substream = NULL; 235d16046ffSLiam Girdwood 236d16046ffSLiam Girdwood /* reset BDL address */ 237d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 238d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); 239d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 240d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); 241d16046ffSLiam Girdwood 242d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); 243d16046ffSLiam Girdwood snd_dma_free_pages(dmab); 244d16046ffSLiam Girdwood dmab->area = NULL; 245d16046ffSLiam Girdwood hstream->bufsize = 0; 246d16046ffSLiam Girdwood hstream->format_val = 0; 247d16046ffSLiam Girdwood 248d16046ffSLiam Girdwood return ret; 249d16046ffSLiam Girdwood } 250d16046ffSLiam Girdwood 251d16046ffSLiam Girdwood static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) 252d16046ffSLiam Girdwood { 253d16046ffSLiam Girdwood unsigned int reg; 254d16046ffSLiam Girdwood int ret, status; 255d16046ffSLiam Girdwood 256d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); 257d16046ffSLiam Girdwood if (ret < 0) { 258d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger start failed\n"); 259d16046ffSLiam Girdwood return ret; 260d16046ffSLiam Girdwood } 261d16046ffSLiam Girdwood 262d16046ffSLiam Girdwood status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 263d16046ffSLiam Girdwood HDA_DSP_SRAM_REG_ROM_STATUS, reg, 264d16046ffSLiam Girdwood ((reg & HDA_DSP_ROM_STS_MASK) 265d16046ffSLiam Girdwood == HDA_DSP_ROM_FW_ENTERED), 266d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 267d16046ffSLiam Girdwood HDA_DSP_BASEFW_TIMEOUT_US); 268d16046ffSLiam Girdwood 26976dc6a2bSPierre-Louis Bossart /* 27076dc6a2bSPierre-Louis Bossart * even in case of errors we still need to stop the DMAs, 27176dc6a2bSPierre-Louis Bossart * but we return the initial error should the DMA stop also fail 27276dc6a2bSPierre-Louis Bossart */ 27376dc6a2bSPierre-Louis Bossart 2746a414489SPierre-Louis Bossart if (status < 0) { 2756a414489SPierre-Louis Bossart dev_err(sdev->dev, 2766a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 2776a414489SPierre-Louis Bossart __func__); 2786a414489SPierre-Louis Bossart } 2796a414489SPierre-Louis Bossart 280d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); 281d16046ffSLiam Girdwood if (ret < 0) { 282d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger stop failed\n"); 28376dc6a2bSPierre-Louis Bossart if (!status) 28476dc6a2bSPierre-Louis Bossart status = ret; 285d16046ffSLiam Girdwood } 286d16046ffSLiam Girdwood 287d16046ffSLiam Girdwood return status; 288d16046ffSLiam Girdwood } 289d16046ffSLiam Girdwood 290acf705a4SRanjani Sridharan int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) 291acf705a4SRanjani Sridharan { 292acf705a4SRanjani Sridharan struct snd_sof_pdata *plat_data = sdev->pdata; 293acf705a4SRanjani Sridharan struct hdac_ext_stream *iccmax_stream; 294acf705a4SRanjani Sridharan struct hdac_bus *bus = sof_to_bus(sdev); 295acf705a4SRanjani Sridharan struct firmware stripped_firmware; 296acf705a4SRanjani Sridharan int ret, ret1; 297acf705a4SRanjani Sridharan u8 original_gb; 298acf705a4SRanjani Sridharan 299acf705a4SRanjani Sridharan /* save the original LTRP guardband value */ 300acf705a4SRanjani Sridharan original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; 301acf705a4SRanjani Sridharan 302acf705a4SRanjani Sridharan if (plat_data->fw->size <= plat_data->fw_offset) { 303acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 304acf705a4SRanjani Sridharan return -EINVAL; 305acf705a4SRanjani Sridharan } 306acf705a4SRanjani Sridharan 307acf705a4SRanjani Sridharan stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 308acf705a4SRanjani Sridharan 309acf705a4SRanjani Sridharan /* prepare capture stream for ICCMAX */ 31001d42d5aSRanjani Sridharan iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 311acf705a4SRanjani Sridharan &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); 31201d42d5aSRanjani Sridharan if (IS_ERR(iccmax_stream)) { 31301d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); 31401d42d5aSRanjani Sridharan return PTR_ERR(iccmax_stream); 315acf705a4SRanjani Sridharan } 316acf705a4SRanjani Sridharan 317acf705a4SRanjani Sridharan ret = hda_dsp_cl_boot_firmware(sdev); 318acf705a4SRanjani Sridharan 319acf705a4SRanjani Sridharan /* 320acf705a4SRanjani Sridharan * Perform iccmax stream cleanup. This should be done even if firmware loading fails. 321acf705a4SRanjani Sridharan * If the cleanup also fails, we return the initial error 322acf705a4SRanjani Sridharan */ 323acf705a4SRanjani Sridharan ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream); 324acf705a4SRanjani Sridharan if (ret1 < 0) { 325acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); 326acf705a4SRanjani Sridharan 327acf705a4SRanjani Sridharan /* set return value to indicate cleanup failure */ 328acf705a4SRanjani Sridharan if (!ret) 329acf705a4SRanjani Sridharan ret = ret1; 330acf705a4SRanjani Sridharan } 331acf705a4SRanjani Sridharan 332acf705a4SRanjani Sridharan /* restore the original guardband value after FW boot */ 333acf705a4SRanjani Sridharan snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb); 334acf705a4SRanjani Sridharan 335acf705a4SRanjani Sridharan return ret; 336acf705a4SRanjani Sridharan } 337acf705a4SRanjani Sridharan 338d16046ffSLiam Girdwood int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) 339d16046ffSLiam Girdwood { 340776100a4SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 341d16046ffSLiam Girdwood struct snd_sof_pdata *plat_data = sdev->pdata; 342d16046ffSLiam Girdwood const struct sof_dev_desc *desc = plat_data->desc; 343d16046ffSLiam Girdwood const struct sof_intel_dsp_desc *chip_info; 344d16046ffSLiam Girdwood struct hdac_ext_stream *stream; 345d16046ffSLiam Girdwood struct firmware stripped_firmware; 34601d42d5aSRanjani Sridharan int ret, ret1, i; 347d16046ffSLiam Girdwood 348d16046ffSLiam Girdwood chip_info = desc->chip_info; 349d16046ffSLiam Girdwood 350523773b9SKarol Trzcinski if (plat_data->fw->size <= plat_data->fw_offset) { 35192be17a5SKarol Trzcinski dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 35292be17a5SKarol Trzcinski return -EINVAL; 35392be17a5SKarol Trzcinski } 35492be17a5SKarol Trzcinski 35592be17a5SKarol Trzcinski stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; 35692be17a5SKarol Trzcinski stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 357d16046ffSLiam Girdwood 358d16046ffSLiam Girdwood /* init for booting wait */ 359d16046ffSLiam Girdwood init_waitqueue_head(&sdev->boot_wait); 360d16046ffSLiam Girdwood 361d16046ffSLiam Girdwood /* prepare DMA for code loader stream */ 36201d42d5aSRanjani Sridharan stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 363d16046ffSLiam Girdwood &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); 36401d42d5aSRanjani Sridharan if (IS_ERR(stream)) { 36501d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); 36601d42d5aSRanjani Sridharan return PTR_ERR(stream); 367d16046ffSLiam Girdwood } 368d16046ffSLiam Girdwood 369d16046ffSLiam Girdwood memcpy(sdev->dmab.area, stripped_firmware.data, 370d16046ffSLiam Girdwood stripped_firmware.size); 371d16046ffSLiam Girdwood 372d16046ffSLiam Girdwood /* try ROM init a few times before giving up */ 373d16046ffSLiam Girdwood for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { 37453ec7531SRanjani Sridharan dev_dbg(sdev->dev, 37553ec7531SRanjani Sridharan "Attempting iteration %d of Core En/ROM load...\n", i); 37653ec7531SRanjani Sridharan 377776100a4SPierre-Louis Bossart hda->boot_iteration = i + 1; 378776100a4SPierre-Louis Bossart ret = cl_dsp_init(sdev, stream->hstream.stream_tag); 379d16046ffSLiam Girdwood 380d16046ffSLiam Girdwood /* don't retry anymore if successful */ 381d16046ffSLiam Girdwood if (!ret) 382d16046ffSLiam Girdwood break; 383d16046ffSLiam Girdwood } 384d16046ffSLiam Girdwood 385d16046ffSLiam Girdwood if (i == HDA_FW_BOOT_ATTEMPTS) { 386d16046ffSLiam Girdwood dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", 387d16046ffSLiam Girdwood i, ret); 38853ec7531SRanjani Sridharan dev_err(sdev->dev, "ROM error=0x%x: FW status=0x%x\n", 38953ec7531SRanjani Sridharan snd_sof_dsp_read(sdev, HDA_DSP_BAR, 39053ec7531SRanjani Sridharan HDA_DSP_SRAM_REG_ROM_ERROR), 39153ec7531SRanjani Sridharan snd_sof_dsp_read(sdev, HDA_DSP_BAR, 39253ec7531SRanjani Sridharan HDA_DSP_SRAM_REG_ROM_STATUS)); 393d16046ffSLiam Girdwood goto cleanup; 394d16046ffSLiam Girdwood } 395d16046ffSLiam Girdwood 396d16046ffSLiam Girdwood /* 397bbd19cdcSRander Wang * When a SoundWire link is in clock stop state, a Slave 398bbd19cdcSRander Wang * device may trigger in-band wakes for events such as jack 399bbd19cdcSRander Wang * insertion or acoustic event detection. This event will lead 400bbd19cdcSRander Wang * to a WAKEEN interrupt, handled by the PCI device and routed 401bbd19cdcSRander Wang * to PME if the PCI device is in D3. The resume function in 402bbd19cdcSRander Wang * audio PCI driver will be invoked by ACPI for PME event and 403bbd19cdcSRander Wang * initialize the device and process WAKEEN interrupt. 404bbd19cdcSRander Wang * 405bbd19cdcSRander Wang * The WAKEEN interrupt should be processed ASAP to prevent an 406bbd19cdcSRander Wang * interrupt flood, otherwise other interrupts, such IPC, 407bbd19cdcSRander Wang * cannot work normally. The WAKEEN is handled after the ROM 408bbd19cdcSRander Wang * is initialized successfully, which ensures power rails are 409bbd19cdcSRander Wang * enabled before accessing the SoundWire SHIM registers 410bbd19cdcSRander Wang */ 411bbd19cdcSRander Wang if (!sdev->first_boot) 412bbd19cdcSRander Wang hda_sdw_process_wakeen(sdev); 413bbd19cdcSRander Wang 414bbd19cdcSRander Wang /* 415d16046ffSLiam Girdwood * at this point DSP ROM has been initialized and 416d16046ffSLiam Girdwood * should be ready for code loading and firmware boot 417d16046ffSLiam Girdwood */ 418d16046ffSLiam Girdwood ret = cl_copy_fw(sdev, stream); 419b278fc55SRanjani Sridharan if (!ret) { 420d16046ffSLiam Girdwood dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 421b278fc55SRanjani Sridharan } else { 4228f7ef6fcSRanjani Sridharan hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | 4238f7ef6fcSRanjani Sridharan SOF_DBG_DUMP_FORCE_ERR_LEVEL); 424d16046ffSLiam Girdwood dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); 425b278fc55SRanjani Sridharan } 426d16046ffSLiam Girdwood 427d16046ffSLiam Girdwood cleanup: 428d16046ffSLiam Girdwood /* 429d16046ffSLiam Girdwood * Perform codeloader stream cleanup. 430d16046ffSLiam Girdwood * This should be done even if firmware loading fails. 43176dc6a2bSPierre-Louis Bossart * If the cleanup also fails, we return the initial error 432d16046ffSLiam Girdwood */ 433d16046ffSLiam Girdwood ret1 = cl_cleanup(sdev, &sdev->dmab, stream); 434d16046ffSLiam Girdwood if (ret1 < 0) { 435d16046ffSLiam Girdwood dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); 436d16046ffSLiam Girdwood 437d16046ffSLiam Girdwood /* set return value to indicate cleanup failure */ 43876dc6a2bSPierre-Louis Bossart if (!ret) 439d16046ffSLiam Girdwood ret = ret1; 440d16046ffSLiam Girdwood } 441d16046ffSLiam Girdwood 442d16046ffSLiam Girdwood /* 44352e4d0aeSPierre-Louis Bossart * return primary core id if both fw copy 444d16046ffSLiam Girdwood * and stream clean up are successful 445d16046ffSLiam Girdwood */ 446d16046ffSLiam Girdwood if (!ret) 447d16046ffSLiam Girdwood return chip_info->init_core_mask; 448d16046ffSLiam Girdwood 449d16046ffSLiam Girdwood /* disable DSP */ 450d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, 451d16046ffSLiam Girdwood SOF_HDA_REG_PP_PPCTL, 452d16046ffSLiam Girdwood SOF_HDA_PPCTL_GPROCEN, 0); 453d16046ffSLiam Girdwood return ret; 454d16046ffSLiam Girdwood } 455d16046ffSLiam Girdwood 456d16046ffSLiam Girdwood /* pre fw run operations */ 457d16046ffSLiam Girdwood int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) 458d16046ffSLiam Girdwood { 459d16046ffSLiam Girdwood /* disable clock gating and power gating */ 460d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, false); 461d16046ffSLiam Girdwood } 462d16046ffSLiam Girdwood 463d16046ffSLiam Girdwood /* post fw run operations */ 464d16046ffSLiam Girdwood int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) 465d16046ffSLiam Girdwood { 46651dfed1eSPierre-Louis Bossart int ret; 46751dfed1eSPierre-Louis Bossart 46851dfed1eSPierre-Louis Bossart if (sdev->first_boot) { 46951dfed1eSPierre-Louis Bossart ret = hda_sdw_startup(sdev); 47051dfed1eSPierre-Louis Bossart if (ret < 0) { 47151dfed1eSPierre-Louis Bossart dev_err(sdev->dev, 47251dfed1eSPierre-Louis Bossart "error: could not startup SoundWire links\n"); 47351dfed1eSPierre-Louis Bossart return ret; 47451dfed1eSPierre-Louis Bossart } 47551dfed1eSPierre-Louis Bossart } 47651dfed1eSPierre-Louis Bossart 47751dfed1eSPierre-Louis Bossart hda_sdw_int_enable(sdev, true); 47851dfed1eSPierre-Louis Bossart 479d16046ffSLiam Girdwood /* re-enable clock gating and power gating */ 480d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, true); 481d16046ffSLiam Girdwood } 482edbaaadaSFred Oh 4830cde3e9fSFred Oh /* 4840cde3e9fSFred Oh * post fw run operations for ICL, 4850cde3e9fSFred Oh * Core 3 will be powered up and in stall when HPRO is enabled 4860cde3e9fSFred Oh */ 4870cde3e9fSFred Oh int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev) 4880cde3e9fSFred Oh { 4890cde3e9fSFred Oh struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 4900cde3e9fSFred Oh int ret; 4910cde3e9fSFred Oh 4920cde3e9fSFred Oh if (sdev->first_boot) { 4930cde3e9fSFred Oh ret = hda_sdw_startup(sdev); 4940cde3e9fSFred Oh if (ret < 0) { 4950cde3e9fSFred Oh dev_err(sdev->dev, 4960cde3e9fSFred Oh "error: could not startup SoundWire links\n"); 4970cde3e9fSFred Oh return ret; 4980cde3e9fSFred Oh } 4990cde3e9fSFred Oh } 5000cde3e9fSFred Oh 5010cde3e9fSFred Oh hda_sdw_int_enable(sdev, true); 5020cde3e9fSFred Oh 5030cde3e9fSFred Oh /* 5040cde3e9fSFred Oh * The recommended HW programming sequence for ICL is to 5050cde3e9fSFred Oh * power up core 3 and keep it in stall if HPRO is enabled. 5060cde3e9fSFred Oh * Major difference between ICL and TGL, on ICL core 3 is managed by 5070cde3e9fSFred Oh * the host whereas on TGL it is handled by the firmware. 5080cde3e9fSFred Oh */ 5090cde3e9fSFred Oh if (!hda->clk_config_lpro) { 5100cde3e9fSFred Oh ret = snd_sof_dsp_core_power_up(sdev, BIT(3)); 5110cde3e9fSFred Oh if (ret < 0) { 5120cde3e9fSFred Oh dev_err(sdev->dev, "error: dsp core power up failed on core 3\n"); 5130cde3e9fSFred Oh return ret; 5140cde3e9fSFred Oh } 5150cde3e9fSFred Oh 5160cde3e9fSFred Oh snd_sof_dsp_stall(sdev, BIT(3)); 5170cde3e9fSFred Oh } 5180cde3e9fSFred Oh 5190cde3e9fSFred Oh /* re-enable clock gating and power gating */ 5200cde3e9fSFred Oh return hda_dsp_ctrl_clock_power_gating(sdev, true); 5210cde3e9fSFred Oh } 5220cde3e9fSFred Oh 523edbaaadaSFred Oh int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, 524edbaaadaSFred Oh const struct sof_ext_man_elem_header *hdr) 525edbaaadaSFred Oh { 526edbaaadaSFred Oh const struct sof_ext_man_cavs_config_data *config_data = 527edbaaadaSFred Oh container_of(hdr, struct sof_ext_man_cavs_config_data, hdr); 528edbaaadaSFred Oh struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 529edbaaadaSFred Oh int i, elem_num; 530edbaaadaSFred Oh 531edbaaadaSFred Oh /* calculate total number of config data elements */ 532edbaaadaSFred Oh elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header)) 533edbaaadaSFred Oh / sizeof(struct sof_config_elem); 534edbaaadaSFred Oh if (elem_num <= 0) { 535edbaaadaSFred Oh dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num); 536edbaaadaSFred Oh return -EINVAL; 537edbaaadaSFred Oh } 538edbaaadaSFred Oh 539edbaaadaSFred Oh for (i = 0; i < elem_num; i++) 540edbaaadaSFred Oh switch (config_data->elems[i].token) { 541edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_EMPTY: 542edbaaadaSFred Oh /* skip empty token */ 543edbaaadaSFred Oh break; 544edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO: 545edbaaadaSFred Oh hda->clk_config_lpro = config_data->elems[i].value; 546edbaaadaSFred Oh dev_dbg(sdev->dev, "FW clock config: %s\n", 547edbaaadaSFred Oh hda->clk_config_lpro ? "LPRO" : "HPRO"); 548edbaaadaSFred Oh break; 549e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE: 550e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE: 551e3a85dbeSFred Oh /* These elements are defined but not being used yet. No warn is required */ 552e3a85dbeSFred Oh break; 553edbaaadaSFred Oh default: 554e3a85dbeSFred Oh dev_info(sdev->dev, "unsupported token type: %d\n", 555edbaaadaSFred Oh config_data->elems[i].token); 556edbaaadaSFred Oh } 557edbaaadaSFred Oh 558edbaaadaSFred Oh return 0; 559edbaaadaSFred Oh } 5600cde3e9fSFred Oh 5610cde3e9fSFred Oh int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask) 5620cde3e9fSFred Oh { 5630cde3e9fSFred Oh struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 5640cde3e9fSFred Oh const struct sof_intel_dsp_desc *chip = hda->desc; 5650cde3e9fSFred Oh 5660cde3e9fSFred Oh /* make sure core_mask in host managed cores */ 5670cde3e9fSFred Oh core_mask &= chip->host_managed_cores_mask; 5680cde3e9fSFred Oh if (!core_mask) { 5690cde3e9fSFred Oh dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); 5700cde3e9fSFred Oh return -EINVAL; 5710cde3e9fSFred Oh } 5720cde3e9fSFred Oh 5730cde3e9fSFred Oh /* stall core */ 5740cde3e9fSFred Oh snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, 5750cde3e9fSFred Oh HDA_DSP_REG_ADSPCS, 5760cde3e9fSFred Oh HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), 5770cde3e9fSFred Oh HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); 5780cde3e9fSFred Oh 5790cde3e9fSFred Oh return 0; 5800cde3e9fSFred Oh } 581