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; 91*2f148430SPeter Ujfalusi char *dump_msg; 92d4165199SRanjani Sridharan u32 flags, j; 93d16046ffSLiam Girdwood int ret; 9474ed4097SZhu Yingjiang int i; 95d16046ffSLiam Girdwood 96d16046ffSLiam Girdwood /* step 1: power up corex */ 97d4165199SRanjani Sridharan ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask); 98d16046ffSLiam Girdwood if (ret < 0) { 99776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 100d16046ffSLiam Girdwood dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); 101d16046ffSLiam Girdwood goto err; 102d16046ffSLiam Girdwood } 103d16046ffSLiam Girdwood 10474ed4097SZhu Yingjiang /* DSP is powered up, set all SSPs to slave mode */ 10574ed4097SZhu Yingjiang for (i = 0; i < chip->ssp_count; i++) { 10674ed4097SZhu Yingjiang snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, 10774ed4097SZhu Yingjiang chip->ssp_base_offset 10874ed4097SZhu Yingjiang + i * SSP_DEV_MEM_SIZE 10974ed4097SZhu Yingjiang + SSP_SSC1_OFFSET, 11074ed4097SZhu Yingjiang SSP_SET_SLAVE, 11174ed4097SZhu Yingjiang SSP_SET_SLAVE); 11274ed4097SZhu Yingjiang } 11374ed4097SZhu Yingjiang 114d16046ffSLiam Girdwood /* step 2: purge FW request */ 115d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, 116d16046ffSLiam Girdwood chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | 117d16046ffSLiam Girdwood ((stream_tag - 1) << 9))); 118d16046ffSLiam Girdwood 119d16046ffSLiam Girdwood /* step 3: unset core 0 reset state & unstall/run core 0 */ 120fde10655SRanjani Sridharan ret = hda_dsp_core_run(sdev, BIT(0)); 121d16046ffSLiam Girdwood if (ret < 0) { 122776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 12353ec7531SRanjani Sridharan dev_err(sdev->dev, 12453ec7531SRanjani Sridharan "error: dsp core start failed %d\n", ret); 125d16046ffSLiam Girdwood ret = -EIO; 126d16046ffSLiam Girdwood goto err; 127d16046ffSLiam Girdwood } 128d16046ffSLiam Girdwood 129d16046ffSLiam Girdwood /* step 4: wait for IPC DONE bit from ROM */ 130d16046ffSLiam Girdwood ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 131d16046ffSLiam Girdwood chip->ipc_ack, status, 132d16046ffSLiam Girdwood ((status & chip->ipc_ack_mask) 133d16046ffSLiam Girdwood == chip->ipc_ack_mask), 134d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 135d16046ffSLiam Girdwood HDA_DSP_INIT_TIMEOUT_US); 136d16046ffSLiam Girdwood 137d16046ffSLiam Girdwood if (ret < 0) { 138776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 13953ec7531SRanjani Sridharan dev_err(sdev->dev, 14053ec7531SRanjani Sridharan "error: %s: timeout for HIPCIE done\n", 1416a414489SPierre-Louis Bossart __func__); 142d16046ffSLiam Girdwood goto err; 143d16046ffSLiam Girdwood } 144d16046ffSLiam Girdwood 1458354d9b4SKeyon Jie /* set DONE bit to clear the reply IPC message */ 1468354d9b4SKeyon Jie snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 1478354d9b4SKeyon Jie chip->ipc_ack, 1488354d9b4SKeyon Jie chip->ipc_ack_mask, 1498354d9b4SKeyon Jie chip->ipc_ack_mask); 1508354d9b4SKeyon Jie 151cedd502dSBard Liao /* step 5: power down cores that are no longer needed */ 152d4165199SRanjani Sridharan ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask & 153cedd502dSBard Liao ~(chip->init_core_mask)); 154d16046ffSLiam Girdwood if (ret < 0) { 155776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 15653ec7531SRanjani Sridharan dev_err(sdev->dev, 15753ec7531SRanjani Sridharan "error: dsp core x power down failed\n"); 158d16046ffSLiam Girdwood goto err; 159d16046ffSLiam Girdwood } 160d16046ffSLiam Girdwood 161d16046ffSLiam Girdwood /* step 6: enable IPC interrupts */ 162d16046ffSLiam Girdwood hda_dsp_ipc_int_enable(sdev); 163d16046ffSLiam Girdwood 164d16046ffSLiam Girdwood /* step 7: wait for ROM init */ 165d16046ffSLiam Girdwood ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 166d16046ffSLiam Girdwood HDA_DSP_SRAM_REG_ROM_STATUS, status, 167d16046ffSLiam Girdwood ((status & HDA_DSP_ROM_STS_MASK) 168d16046ffSLiam Girdwood == HDA_DSP_ROM_INIT), 169d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 170d16046ffSLiam Girdwood chip->rom_init_timeout * 171d16046ffSLiam Girdwood USEC_PER_MSEC); 172d4165199SRanjani Sridharan if (!ret) { 173d4165199SRanjani Sridharan /* set enabled cores mask and increment ref count for cores in init_core_mask */ 174d4165199SRanjani Sridharan sdev->enabled_cores_mask |= chip->init_core_mask; 175d4165199SRanjani Sridharan mask = sdev->enabled_cores_mask; 176d4165199SRanjani Sridharan for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES) 177d4165199SRanjani Sridharan sdev->dsp_core_ref_count[j]++; 178d16046ffSLiam Girdwood return 0; 179d4165199SRanjani Sridharan } 180d16046ffSLiam Girdwood 181776100a4SPierre-Louis Bossart if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1826a414489SPierre-Louis Bossart dev_err(sdev->dev, 1836a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 1846a414489SPierre-Louis Bossart __func__); 1856a414489SPierre-Louis Bossart 186d16046ffSLiam Girdwood err: 1877511b0edSPeter Ujfalusi flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; 1888f7ef6fcSRanjani Sridharan 18923013335SPeter Ujfalusi /* after max boot attempts make sure that the dump is printed */ 19023013335SPeter Ujfalusi if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 1910ecaa2ffSPeter Ujfalusi flags &= ~SOF_DBG_DUMP_OPTIONAL; 1928f7ef6fcSRanjani Sridharan 193*2f148430SPeter Ujfalusi dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d", 194*2f148430SPeter Ujfalusi hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS); 195*2f148430SPeter Ujfalusi snd_sof_dsp_dbg_dump(sdev, dump_msg, flags); 196d4165199SRanjani Sridharan hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); 197d16046ffSLiam Girdwood 198*2f148430SPeter Ujfalusi kfree(dump_msg); 199d16046ffSLiam Girdwood return ret; 200d16046ffSLiam Girdwood } 201d16046ffSLiam Girdwood 202d16046ffSLiam Girdwood static int cl_trigger(struct snd_sof_dev *sdev, 203d16046ffSLiam Girdwood struct hdac_ext_stream *stream, int cmd) 204d16046ffSLiam Girdwood { 205d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 206d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 207d16046ffSLiam Girdwood 208d16046ffSLiam Girdwood /* code loader is special case that reuses stream ops */ 209d16046ffSLiam Girdwood switch (cmd) { 210d16046ffSLiam Girdwood case SNDRV_PCM_TRIGGER_START: 211d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 212d16046ffSLiam Girdwood 1 << hstream->index, 213d16046ffSLiam Girdwood 1 << hstream->index); 214d16046ffSLiam Girdwood 215d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 216d16046ffSLiam Girdwood sd_offset, 217d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 218d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK, 219d16046ffSLiam Girdwood SOF_HDA_SD_CTL_DMA_START | 220d16046ffSLiam Girdwood SOF_HDA_CL_DMA_SD_INT_MASK); 221d16046ffSLiam Girdwood 222d16046ffSLiam Girdwood hstream->running = true; 223d16046ffSLiam Girdwood return 0; 224d16046ffSLiam Girdwood default: 225d16046ffSLiam Girdwood return hda_dsp_stream_trigger(sdev, stream, cmd); 226d16046ffSLiam Girdwood } 227d16046ffSLiam Girdwood } 228d16046ffSLiam Girdwood 229d16046ffSLiam Girdwood static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, 230d16046ffSLiam Girdwood struct hdac_ext_stream *stream) 231d16046ffSLiam Girdwood { 232d16046ffSLiam Girdwood struct hdac_stream *hstream = &stream->hstream; 233d16046ffSLiam Girdwood int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 234acf705a4SRanjani Sridharan int ret = 0; 235d16046ffSLiam Girdwood 236acf705a4SRanjani Sridharan if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) 237d16046ffSLiam Girdwood ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); 238acf705a4SRanjani Sridharan else 239acf705a4SRanjani Sridharan snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 240acf705a4SRanjani Sridharan SOF_HDA_SD_CTL_DMA_START, 0); 241d16046ffSLiam Girdwood 242acf705a4SRanjani Sridharan hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); 243d16046ffSLiam Girdwood hstream->running = 0; 244d16046ffSLiam Girdwood hstream->substream = NULL; 245d16046ffSLiam Girdwood 246d16046ffSLiam Girdwood /* reset BDL address */ 247d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 248d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); 249d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 250d16046ffSLiam Girdwood sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); 251d16046ffSLiam Girdwood 252d16046ffSLiam Girdwood snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); 253d16046ffSLiam Girdwood snd_dma_free_pages(dmab); 254d16046ffSLiam Girdwood dmab->area = NULL; 255d16046ffSLiam Girdwood hstream->bufsize = 0; 256d16046ffSLiam Girdwood hstream->format_val = 0; 257d16046ffSLiam Girdwood 258d16046ffSLiam Girdwood return ret; 259d16046ffSLiam Girdwood } 260d16046ffSLiam Girdwood 261d16046ffSLiam Girdwood static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) 262d16046ffSLiam Girdwood { 263d16046ffSLiam Girdwood unsigned int reg; 264d16046ffSLiam Girdwood int ret, status; 265d16046ffSLiam Girdwood 266d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); 267d16046ffSLiam Girdwood if (ret < 0) { 268d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger start failed\n"); 269d16046ffSLiam Girdwood return ret; 270d16046ffSLiam Girdwood } 271d16046ffSLiam Girdwood 272d16046ffSLiam Girdwood status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 273d16046ffSLiam Girdwood HDA_DSP_SRAM_REG_ROM_STATUS, reg, 274d16046ffSLiam Girdwood ((reg & HDA_DSP_ROM_STS_MASK) 275d16046ffSLiam Girdwood == HDA_DSP_ROM_FW_ENTERED), 276d16046ffSLiam Girdwood HDA_DSP_REG_POLL_INTERVAL_US, 277d16046ffSLiam Girdwood HDA_DSP_BASEFW_TIMEOUT_US); 278d16046ffSLiam Girdwood 27976dc6a2bSPierre-Louis Bossart /* 28076dc6a2bSPierre-Louis Bossart * even in case of errors we still need to stop the DMAs, 28176dc6a2bSPierre-Louis Bossart * but we return the initial error should the DMA stop also fail 28276dc6a2bSPierre-Louis Bossart */ 28376dc6a2bSPierre-Louis Bossart 2846a414489SPierre-Louis Bossart if (status < 0) { 2856a414489SPierre-Louis Bossart dev_err(sdev->dev, 2866a414489SPierre-Louis Bossart "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", 2876a414489SPierre-Louis Bossart __func__); 2886a414489SPierre-Louis Bossart } 2896a414489SPierre-Louis Bossart 290d16046ffSLiam Girdwood ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); 291d16046ffSLiam Girdwood if (ret < 0) { 292d16046ffSLiam Girdwood dev_err(sdev->dev, "error: DMA trigger stop failed\n"); 29376dc6a2bSPierre-Louis Bossart if (!status) 29476dc6a2bSPierre-Louis Bossart status = ret; 295d16046ffSLiam Girdwood } 296d16046ffSLiam Girdwood 297d16046ffSLiam Girdwood return status; 298d16046ffSLiam Girdwood } 299d16046ffSLiam Girdwood 300acf705a4SRanjani Sridharan int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) 301acf705a4SRanjani Sridharan { 302acf705a4SRanjani Sridharan struct snd_sof_pdata *plat_data = sdev->pdata; 303acf705a4SRanjani Sridharan struct hdac_ext_stream *iccmax_stream; 304acf705a4SRanjani Sridharan struct hdac_bus *bus = sof_to_bus(sdev); 305acf705a4SRanjani Sridharan struct firmware stripped_firmware; 306acf705a4SRanjani Sridharan int ret, ret1; 307acf705a4SRanjani Sridharan u8 original_gb; 308acf705a4SRanjani Sridharan 309acf705a4SRanjani Sridharan /* save the original LTRP guardband value */ 310acf705a4SRanjani Sridharan original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; 311acf705a4SRanjani Sridharan 312acf705a4SRanjani Sridharan if (plat_data->fw->size <= plat_data->fw_offset) { 313acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 314acf705a4SRanjani Sridharan return -EINVAL; 315acf705a4SRanjani Sridharan } 316acf705a4SRanjani Sridharan 317acf705a4SRanjani Sridharan stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 318acf705a4SRanjani Sridharan 319acf705a4SRanjani Sridharan /* prepare capture stream for ICCMAX */ 32001d42d5aSRanjani Sridharan iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 321acf705a4SRanjani Sridharan &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); 32201d42d5aSRanjani Sridharan if (IS_ERR(iccmax_stream)) { 32301d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); 32401d42d5aSRanjani Sridharan return PTR_ERR(iccmax_stream); 325acf705a4SRanjani Sridharan } 326acf705a4SRanjani Sridharan 327acf705a4SRanjani Sridharan ret = hda_dsp_cl_boot_firmware(sdev); 328acf705a4SRanjani Sridharan 329acf705a4SRanjani Sridharan /* 330acf705a4SRanjani Sridharan * Perform iccmax stream cleanup. This should be done even if firmware loading fails. 331acf705a4SRanjani Sridharan * If the cleanup also fails, we return the initial error 332acf705a4SRanjani Sridharan */ 333acf705a4SRanjani Sridharan ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream); 334acf705a4SRanjani Sridharan if (ret1 < 0) { 335acf705a4SRanjani Sridharan dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); 336acf705a4SRanjani Sridharan 337acf705a4SRanjani Sridharan /* set return value to indicate cleanup failure */ 338acf705a4SRanjani Sridharan if (!ret) 339acf705a4SRanjani Sridharan ret = ret1; 340acf705a4SRanjani Sridharan } 341acf705a4SRanjani Sridharan 342acf705a4SRanjani Sridharan /* restore the original guardband value after FW boot */ 343acf705a4SRanjani Sridharan snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb); 344acf705a4SRanjani Sridharan 345acf705a4SRanjani Sridharan return ret; 346acf705a4SRanjani Sridharan } 347acf705a4SRanjani Sridharan 348d16046ffSLiam Girdwood int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) 349d16046ffSLiam Girdwood { 350776100a4SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 351d16046ffSLiam Girdwood struct snd_sof_pdata *plat_data = sdev->pdata; 352d16046ffSLiam Girdwood const struct sof_dev_desc *desc = plat_data->desc; 353d16046ffSLiam Girdwood const struct sof_intel_dsp_desc *chip_info; 354d16046ffSLiam Girdwood struct hdac_ext_stream *stream; 355d16046ffSLiam Girdwood struct firmware stripped_firmware; 35601d42d5aSRanjani Sridharan int ret, ret1, i; 357d16046ffSLiam Girdwood 358d16046ffSLiam Girdwood chip_info = desc->chip_info; 359d16046ffSLiam Girdwood 360523773b9SKarol Trzcinski if (plat_data->fw->size <= plat_data->fw_offset) { 36192be17a5SKarol Trzcinski dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 36292be17a5SKarol Trzcinski return -EINVAL; 36392be17a5SKarol Trzcinski } 36492be17a5SKarol Trzcinski 36592be17a5SKarol Trzcinski stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; 36692be17a5SKarol Trzcinski stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 367d16046ffSLiam Girdwood 368d16046ffSLiam Girdwood /* init for booting wait */ 369d16046ffSLiam Girdwood init_waitqueue_head(&sdev->boot_wait); 370d16046ffSLiam Girdwood 371d16046ffSLiam Girdwood /* prepare DMA for code loader stream */ 37201d42d5aSRanjani Sridharan stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 373d16046ffSLiam Girdwood &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); 37401d42d5aSRanjani Sridharan if (IS_ERR(stream)) { 37501d42d5aSRanjani Sridharan dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); 37601d42d5aSRanjani Sridharan return PTR_ERR(stream); 377d16046ffSLiam Girdwood } 378d16046ffSLiam Girdwood 379d16046ffSLiam Girdwood memcpy(sdev->dmab.area, stripped_firmware.data, 380d16046ffSLiam Girdwood stripped_firmware.size); 381d16046ffSLiam Girdwood 382d16046ffSLiam Girdwood /* try ROM init a few times before giving up */ 383d16046ffSLiam Girdwood for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { 38453ec7531SRanjani Sridharan dev_dbg(sdev->dev, 38553ec7531SRanjani Sridharan "Attempting iteration %d of Core En/ROM load...\n", i); 38653ec7531SRanjani Sridharan 387776100a4SPierre-Louis Bossart hda->boot_iteration = i + 1; 388776100a4SPierre-Louis Bossart ret = cl_dsp_init(sdev, stream->hstream.stream_tag); 389d16046ffSLiam Girdwood 390d16046ffSLiam Girdwood /* don't retry anymore if successful */ 391d16046ffSLiam Girdwood if (!ret) 392d16046ffSLiam Girdwood break; 393d16046ffSLiam Girdwood } 394d16046ffSLiam Girdwood 395d16046ffSLiam Girdwood if (i == HDA_FW_BOOT_ATTEMPTS) { 396d16046ffSLiam Girdwood dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", 397d16046ffSLiam Girdwood i, ret); 398d16046ffSLiam Girdwood goto cleanup; 399d16046ffSLiam Girdwood } 400d16046ffSLiam Girdwood 401d16046ffSLiam Girdwood /* 402bbd19cdcSRander Wang * When a SoundWire link is in clock stop state, a Slave 403bbd19cdcSRander Wang * device may trigger in-band wakes for events such as jack 404bbd19cdcSRander Wang * insertion or acoustic event detection. This event will lead 405bbd19cdcSRander Wang * to a WAKEEN interrupt, handled by the PCI device and routed 406bbd19cdcSRander Wang * to PME if the PCI device is in D3. The resume function in 407bbd19cdcSRander Wang * audio PCI driver will be invoked by ACPI for PME event and 408bbd19cdcSRander Wang * initialize the device and process WAKEEN interrupt. 409bbd19cdcSRander Wang * 410bbd19cdcSRander Wang * The WAKEEN interrupt should be processed ASAP to prevent an 411bbd19cdcSRander Wang * interrupt flood, otherwise other interrupts, such IPC, 412bbd19cdcSRander Wang * cannot work normally. The WAKEEN is handled after the ROM 413bbd19cdcSRander Wang * is initialized successfully, which ensures power rails are 414bbd19cdcSRander Wang * enabled before accessing the SoundWire SHIM registers 415bbd19cdcSRander Wang */ 416bbd19cdcSRander Wang if (!sdev->first_boot) 417bbd19cdcSRander Wang hda_sdw_process_wakeen(sdev); 418bbd19cdcSRander Wang 419bbd19cdcSRander Wang /* 420b2b10aa7SPeter Ujfalusi * Set the boot_iteration to the last attempt, indicating that the 421b2b10aa7SPeter Ujfalusi * DSP ROM has been initialized and from this point there will be no 422b2b10aa7SPeter Ujfalusi * retry done to boot. 423b2b10aa7SPeter Ujfalusi * 424b2b10aa7SPeter Ujfalusi * Continue with code loading and firmware boot 425d16046ffSLiam Girdwood */ 426b2b10aa7SPeter Ujfalusi hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS; 427d16046ffSLiam Girdwood ret = cl_copy_fw(sdev, stream); 428*2f148430SPeter Ujfalusi if (!ret) 429d16046ffSLiam Girdwood dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 430*2f148430SPeter Ujfalusi else 431*2f148430SPeter Ujfalusi snd_sof_dsp_dbg_dump(sdev, "Firmware download failed", 432*2f148430SPeter Ujfalusi SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); 433d16046ffSLiam Girdwood 434d16046ffSLiam Girdwood cleanup: 435d16046ffSLiam Girdwood /* 436d16046ffSLiam Girdwood * Perform codeloader stream cleanup. 437d16046ffSLiam Girdwood * This should be done even if firmware loading fails. 43876dc6a2bSPierre-Louis Bossart * If the cleanup also fails, we return the initial error 439d16046ffSLiam Girdwood */ 440d16046ffSLiam Girdwood ret1 = cl_cleanup(sdev, &sdev->dmab, stream); 441d16046ffSLiam Girdwood if (ret1 < 0) { 442d16046ffSLiam Girdwood dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); 443d16046ffSLiam Girdwood 444d16046ffSLiam Girdwood /* set return value to indicate cleanup failure */ 44576dc6a2bSPierre-Louis Bossart if (!ret) 446d16046ffSLiam Girdwood ret = ret1; 447d16046ffSLiam Girdwood } 448d16046ffSLiam Girdwood 449d16046ffSLiam Girdwood /* 45052e4d0aeSPierre-Louis Bossart * return primary core id if both fw copy 451d16046ffSLiam Girdwood * and stream clean up are successful 452d16046ffSLiam Girdwood */ 453d16046ffSLiam Girdwood if (!ret) 454d16046ffSLiam Girdwood return chip_info->init_core_mask; 455d16046ffSLiam Girdwood 456d16046ffSLiam Girdwood /* disable DSP */ 457d16046ffSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, 458d16046ffSLiam Girdwood SOF_HDA_REG_PP_PPCTL, 459d16046ffSLiam Girdwood SOF_HDA_PPCTL_GPROCEN, 0); 460d16046ffSLiam Girdwood return ret; 461d16046ffSLiam Girdwood } 462d16046ffSLiam Girdwood 463d16046ffSLiam Girdwood /* pre fw run operations */ 464d16046ffSLiam Girdwood int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) 465d16046ffSLiam Girdwood { 466d16046ffSLiam Girdwood /* disable clock gating and power gating */ 467d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, false); 468d16046ffSLiam Girdwood } 469d16046ffSLiam Girdwood 470d16046ffSLiam Girdwood /* post fw run operations */ 471d16046ffSLiam Girdwood int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) 472d16046ffSLiam Girdwood { 47351dfed1eSPierre-Louis Bossart int ret; 47451dfed1eSPierre-Louis Bossart 47551dfed1eSPierre-Louis Bossart if (sdev->first_boot) { 47651dfed1eSPierre-Louis Bossart ret = hda_sdw_startup(sdev); 47751dfed1eSPierre-Louis Bossart if (ret < 0) { 47851dfed1eSPierre-Louis Bossart dev_err(sdev->dev, 47951dfed1eSPierre-Louis Bossart "error: could not startup SoundWire links\n"); 48051dfed1eSPierre-Louis Bossart return ret; 48151dfed1eSPierre-Louis Bossart } 48251dfed1eSPierre-Louis Bossart } 48351dfed1eSPierre-Louis Bossart 48451dfed1eSPierre-Louis Bossart hda_sdw_int_enable(sdev, true); 48551dfed1eSPierre-Louis Bossart 486d16046ffSLiam Girdwood /* re-enable clock gating and power gating */ 487d16046ffSLiam Girdwood return hda_dsp_ctrl_clock_power_gating(sdev, true); 488d16046ffSLiam Girdwood } 489edbaaadaSFred Oh 490edbaaadaSFred Oh int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, 491edbaaadaSFred Oh const struct sof_ext_man_elem_header *hdr) 492edbaaadaSFred Oh { 493edbaaadaSFred Oh const struct sof_ext_man_cavs_config_data *config_data = 494edbaaadaSFred Oh container_of(hdr, struct sof_ext_man_cavs_config_data, hdr); 495edbaaadaSFred Oh struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 496edbaaadaSFred Oh int i, elem_num; 497edbaaadaSFred Oh 498edbaaadaSFred Oh /* calculate total number of config data elements */ 499edbaaadaSFred Oh elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header)) 500edbaaadaSFred Oh / sizeof(struct sof_config_elem); 501edbaaadaSFred Oh if (elem_num <= 0) { 502edbaaadaSFred Oh dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num); 503edbaaadaSFred Oh return -EINVAL; 504edbaaadaSFred Oh } 505edbaaadaSFred Oh 506edbaaadaSFred Oh for (i = 0; i < elem_num; i++) 507edbaaadaSFred Oh switch (config_data->elems[i].token) { 508edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_EMPTY: 509edbaaadaSFred Oh /* skip empty token */ 510edbaaadaSFred Oh break; 511edbaaadaSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO: 512edbaaadaSFred Oh hda->clk_config_lpro = config_data->elems[i].value; 513edbaaadaSFred Oh dev_dbg(sdev->dev, "FW clock config: %s\n", 514edbaaadaSFred Oh hda->clk_config_lpro ? "LPRO" : "HPRO"); 515edbaaadaSFred Oh break; 516e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE: 517e3a85dbeSFred Oh case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE: 518e3a85dbeSFred Oh /* These elements are defined but not being used yet. No warn is required */ 519e3a85dbeSFred Oh break; 520edbaaadaSFred Oh default: 521e3a85dbeSFred Oh dev_info(sdev->dev, "unsupported token type: %d\n", 522edbaaadaSFred Oh config_data->elems[i].token); 523edbaaadaSFred Oh } 524edbaaadaSFred Oh 525edbaaadaSFred Oh return 0; 526edbaaadaSFred Oh } 527