1c712be34SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2c712be34SPierre-Louis Bossart // 3c712be34SPierre-Louis Bossart // This file is provided under a dual BSD/GPLv2 license. When using or 4c712be34SPierre-Louis Bossart // redistributing this file, you may do so under either license. 5c712be34SPierre-Louis Bossart // 6c712be34SPierre-Louis Bossart // Copyright(c) 2018-2022 Intel Corporation. All rights reserved. 7c712be34SPierre-Louis Bossart // 8c712be34SPierre-Louis Bossart 9c712be34SPierre-Louis Bossart #include <linux/delay.h> 10c712be34SPierre-Louis Bossart #include <linux/device.h> 11c712be34SPierre-Louis Bossart #include <linux/dma-mapping.h> 12c712be34SPierre-Louis Bossart #include <linux/firmware.h> 13c712be34SPierre-Louis Bossart #include <linux/fs.h> 14c712be34SPierre-Louis Bossart #include <linux/interrupt.h> 15c712be34SPierre-Louis Bossart #include <linux/mm.h> 16c712be34SPierre-Louis Bossart #include <linux/module.h> 17c712be34SPierre-Louis Bossart #include <linux/pci.h> 18c712be34SPierre-Louis Bossart #include <linux/pm_runtime.h> 19c712be34SPierre-Louis Bossart #include <linux/slab.h> 20c712be34SPierre-Louis Bossart #include <sound/hdaudio_ext.h> 21c712be34SPierre-Louis Bossart #include <sound/sof.h> 22c712be34SPierre-Louis Bossart #include <sound/pcm_params.h> 23c712be34SPierre-Louis Bossart 24c712be34SPierre-Louis Bossart #include "../sof-priv.h" 25c712be34SPierre-Louis Bossart #include "../ops.h" 26c712be34SPierre-Louis Bossart #include "hda.h" 27c712be34SPierre-Louis Bossart 28c712be34SPierre-Louis Bossart #define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */ 29c712be34SPierre-Louis Bossart #define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) 30c712be34SPierre-Louis Bossart 31c712be34SPierre-Louis Bossart /* Stream Reset */ 32c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_SRST_SHIFT 0 33c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_SRST(x) (((x) & 0x1) << \ 34c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_SRST_SHIFT) 35c712be34SPierre-Louis Bossart 36c712be34SPierre-Louis Bossart /* Stream Run */ 37c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_RUN_SHIFT 1 38c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_RUN(x) (((x) & 0x1) << \ 39c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_RUN_SHIFT) 40c712be34SPierre-Louis Bossart 41c712be34SPierre-Louis Bossart /* Interrupt On Completion Enable */ 42c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_IOCE_SHIFT 2 43c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_IOCE(x) (((x) & 0x1) << \ 44c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_IOCE_SHIFT) 45c712be34SPierre-Louis Bossart 46c712be34SPierre-Louis Bossart /* FIFO Error Interrupt Enable */ 47c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_FEIE_SHIFT 3 48c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_FEIE(x) (((x) & 0x1) << \ 49c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_FEIE_SHIFT) 50c712be34SPierre-Louis Bossart 51c712be34SPierre-Louis Bossart /* Descriptor Error Interrupt Enable */ 52c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_DEIE_SHIFT 4 53c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_DEIE(x) (((x) & 0x1) << \ 54c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_DEIE_SHIFT) 55c712be34SPierre-Louis Bossart 56c712be34SPierre-Louis Bossart /* FIFO Limit Change */ 57c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_FIFOLC_SHIFT 5 58c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_FIFOLC(x) (((x) & 0x1) << \ 59c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_FIFOLC_SHIFT) 60c712be34SPierre-Louis Bossart 61c712be34SPierre-Louis Bossart /* Stripe Control */ 62c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_STRIPE_SHIFT 16 63c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_STRIPE(x) (((x) & 0x3) << \ 64c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_STRIPE_SHIFT) 65c712be34SPierre-Louis Bossart 66c712be34SPierre-Louis Bossart /* Traffic Priority */ 67c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_TP_SHIFT 18 68c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_TP(x) (((x) & 0x1) << \ 69c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_TP_SHIFT) 70c712be34SPierre-Louis Bossart 71c712be34SPierre-Louis Bossart /* Bidirectional Direction Control */ 72c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_DIR_SHIFT 19 73c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_DIR(x) (((x) & 0x1) << \ 74c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_DIR_SHIFT) 75c712be34SPierre-Louis Bossart 76c712be34SPierre-Louis Bossart /* Stream Number */ 77c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_STRM_SHIFT 20 78c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_STRM(x) (((x) & 0xf) << \ 79c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_STRM_SHIFT) 80c712be34SPierre-Louis Bossart 81c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_INT(x) \ 82c712be34SPierre-Louis Bossart (HDA_CL_SD_CTL_IOCE(x) | \ 83c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_FEIE(x) | \ 84c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_DEIE(x)) 85c712be34SPierre-Louis Bossart 86c712be34SPierre-Louis Bossart #define HDA_CL_SD_CTL_INT_MASK \ 87c712be34SPierre-Louis Bossart (HDA_CL_SD_CTL_IOCE(1) | \ 88c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_FEIE(1) | \ 89c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_DEIE(1)) 90c712be34SPierre-Louis Bossart 91c712be34SPierre-Louis Bossart #define DMA_ADDRESS_128_BITS_ALIGNMENT 7 92c712be34SPierre-Louis Bossart #define BDL_ALIGN(x) ((x) >> DMA_ADDRESS_128_BITS_ALIGNMENT) 93c712be34SPierre-Louis Bossart 94c712be34SPierre-Louis Bossart /* Buffer Descriptor List Lower Base Address */ 95c712be34SPierre-Louis Bossart #define HDA_CL_SD_BDLPLBA_SHIFT 7 96e2379d4aSPierre-Louis Bossart #define HDA_CL_SD_BDLPLBA_MASK GENMASK(31, 7) 97c712be34SPierre-Louis Bossart #define HDA_CL_SD_BDLPLBA(x) \ 98c712be34SPierre-Louis Bossart ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ 99c712be34SPierre-Louis Bossart HDA_CL_SD_BDLPLBA_MASK) 100c712be34SPierre-Louis Bossart 101c712be34SPierre-Louis Bossart /* Buffer Descriptor List Upper Base Address */ 102c712be34SPierre-Louis Bossart #define HDA_CL_SD_BDLPUBA(x) \ 103e2379d4aSPierre-Louis Bossart (upper_32_bits(x)) 104c712be34SPierre-Louis Bossart 105c712be34SPierre-Louis Bossart /* Software Position in Buffer Enable */ 106c712be34SPierre-Louis Bossart #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 107c712be34SPierre-Louis Bossart #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ 108c712be34SPierre-Louis Bossart (1 << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) 109c712be34SPierre-Louis Bossart 110c712be34SPierre-Louis Bossart #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ 111c712be34SPierre-Louis Bossart (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ 112c712be34SPierre-Louis Bossart HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) 113c712be34SPierre-Louis Bossart 114c712be34SPierre-Louis Bossart #define HDA_CL_DMA_SD_INT_COMPLETE 0x4 115c712be34SPierre-Louis Bossart 116c712be34SPierre-Louis Bossart static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, 117c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab_data, 118c712be34SPierre-Louis Bossart __le32 **bdlp, int size, int with_ioc) 119c712be34SPierre-Louis Bossart { 120c712be34SPierre-Louis Bossart phys_addr_t addr = virt_to_phys(dmab_data->area); 121c712be34SPierre-Louis Bossart __le32 *bdl = *bdlp; 122c712be34SPierre-Louis Bossart 123c712be34SPierre-Louis Bossart /* 124c712be34SPierre-Louis Bossart * This code is simplified by using one fragment of physical memory and assuming 125c712be34SPierre-Louis Bossart * all the code fits. This could be improved with scatter-gather but the firmware 126c712be34SPierre-Louis Bossart * size is limited by DSP memory anyways 127c712be34SPierre-Louis Bossart */ 128c712be34SPierre-Louis Bossart bdl[0] = cpu_to_le32(lower_32_bits(addr)); 129c712be34SPierre-Louis Bossart bdl[1] = cpu_to_le32(upper_32_bits(addr)); 130c712be34SPierre-Louis Bossart bdl[2] = cpu_to_le32(size); 131c712be34SPierre-Louis Bossart bdl[3] = (!with_ioc) ? 0 : cpu_to_le32(0x01); 132c712be34SPierre-Louis Bossart 133c712be34SPierre-Louis Bossart return 1; /* one fragment */ 134c712be34SPierre-Louis Bossart } 135c712be34SPierre-Louis Bossart 136c712be34SPierre-Louis Bossart static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) 137c712be34SPierre-Louis Bossart { 138c712be34SPierre-Louis Bossart int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 139c712be34SPierre-Louis Bossart unsigned char val; 140c712be34SPierre-Louis Bossart int retries; 141c712be34SPierre-Louis Bossart u32 run = enable ? 0x1 : 0; 142c712be34SPierre-Louis Bossart 143c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 144*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 145c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); 146c712be34SPierre-Louis Bossart 147c712be34SPierre-Louis Bossart retries = 300; 148c712be34SPierre-Louis Bossart do { 149c712be34SPierre-Louis Bossart udelay(3); 150c712be34SPierre-Louis Bossart 151c712be34SPierre-Louis Bossart /* waiting for hardware to report the stream Run bit set */ 152c712be34SPierre-Louis Bossart val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 153*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL); 154c712be34SPierre-Louis Bossart val &= HDA_CL_SD_CTL_RUN(1); 155c712be34SPierre-Louis Bossart if (enable && val) 156c712be34SPierre-Louis Bossart break; 157c712be34SPierre-Louis Bossart else if (!enable && !val) 158c712be34SPierre-Louis Bossart break; 159c712be34SPierre-Louis Bossart } while (--retries); 160c712be34SPierre-Louis Bossart 161c712be34SPierre-Louis Bossart if (retries == 0) 162c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: failed to set Run bit=%d enable=%d\n", 163c712be34SPierre-Louis Bossart __func__, val, enable); 164c712be34SPierre-Louis Bossart } 165c712be34SPierre-Louis Bossart 166c712be34SPierre-Louis Bossart static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) 167c712be34SPierre-Louis Bossart { 168c712be34SPierre-Louis Bossart int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 169c712be34SPierre-Louis Bossart 170c712be34SPierre-Louis Bossart /* make sure Run bit is cleared before setting stream register */ 171c712be34SPierre-Louis Bossart cl_skl_cldma_stream_run(sdev, 0); 172c712be34SPierre-Louis Bossart 173c712be34SPierre-Louis Bossart /* Disable the Interrupt On Completion, FIFO Error Interrupt, 174c712be34SPierre-Louis Bossart * Descriptor Error Interrupt and set the cldma stream number to 0. 175c712be34SPierre-Louis Bossart */ 176c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 177*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 178c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); 179c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 180*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 181c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); 182c712be34SPierre-Louis Bossart 183c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 184*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(0)); 185c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 186*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); 187c712be34SPierre-Louis Bossart 188c712be34SPierre-Louis Bossart /* Set the Cyclic Buffer Length to 0. */ 189c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 190*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CBL, 0); 191c712be34SPierre-Louis Bossart /* Set the Last Valid Index. */ 192c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 193*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0); 194c712be34SPierre-Louis Bossart } 195c712be34SPierre-Louis Bossart 196c712be34SPierre-Louis Bossart static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, 197c712be34SPierre-Louis Bossart unsigned int size, bool enable) 198c712be34SPierre-Louis Bossart { 199c712be34SPierre-Louis Bossart int sd_offset = SOF_DSP_REG_CL_SPBFIFO; 200c712be34SPierre-Louis Bossart 201c712be34SPierre-Louis Bossart if (enable) 202c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 203c712be34SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, 204c712be34SPierre-Louis Bossart HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, 205c712be34SPierre-Louis Bossart HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(1)); 206c712be34SPierre-Louis Bossart 207c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 208c712be34SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size); 209c712be34SPierre-Louis Bossart } 210c712be34SPierre-Louis Bossart 211c712be34SPierre-Louis Bossart static void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable) 212c712be34SPierre-Louis Bossart { 213c712be34SPierre-Louis Bossart u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0; 214c712be34SPierre-Louis Bossart 215c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 216c712be34SPierre-Louis Bossart HDA_DSP_ADSPIC_CL_DMA, val); 217c712be34SPierre-Louis Bossart } 218c712be34SPierre-Louis Bossart 219c712be34SPierre-Louis Bossart static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) 220c712be34SPierre-Louis Bossart { 221c712be34SPierre-Louis Bossart int sd_offset = SOF_DSP_REG_CL_SPBFIFO; 222c712be34SPierre-Louis Bossart 223c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 224c712be34SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, 225c712be34SPierre-Louis Bossart HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, 226c712be34SPierre-Louis Bossart HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(0)); 227c712be34SPierre-Louis Bossart 228c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 229c712be34SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, 0); 230c712be34SPierre-Louis Bossart } 231c712be34SPierre-Louis Bossart 232c712be34SPierre-Louis Bossart static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, 233c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab_bdl, 234c712be34SPierre-Louis Bossart unsigned int max_size, u32 count) 235c712be34SPierre-Louis Bossart { 236c712be34SPierre-Louis Bossart int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 237c712be34SPierre-Louis Bossart 238c712be34SPierre-Louis Bossart /* Clear the stream first and then set it. */ 239c712be34SPierre-Louis Bossart cl_skl_cldma_stream_clear(sdev); 240c712be34SPierre-Louis Bossart 241c712be34SPierre-Louis Bossart /* setting the stream register */ 242c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 243*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 244c712be34SPierre-Louis Bossart HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); 245c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 246*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 247c712be34SPierre-Louis Bossart HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); 248c712be34SPierre-Louis Bossart 249c712be34SPierre-Louis Bossart /* Set the Cyclic Buffer Length. */ 250c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 251*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CBL, max_size); 252c712be34SPierre-Louis Bossart /* Set the Last Valid Index. */ 253c712be34SPierre-Louis Bossart snd_sof_dsp_write(sdev, HDA_DSP_BAR, 254*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_LVI, count - 1); 255c712be34SPierre-Louis Bossart 256c712be34SPierre-Louis Bossart /* Set the Interrupt On Completion, FIFO Error Interrupt, 257c712be34SPierre-Louis Bossart * Descriptor Error Interrupt and the cldma stream number. 258c712be34SPierre-Louis Bossart */ 259c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 260*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 261c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); 262c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 263*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 264c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_STRM(0xf), 265c712be34SPierre-Louis Bossart HDA_CL_SD_CTL_STRM(1)); 266c712be34SPierre-Louis Bossart } 267c712be34SPierre-Louis Bossart 268c712be34SPierre-Louis Bossart static int cl_stream_prepare_skl(struct snd_sof_dev *sdev, 269c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab, 270c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab_bdl) 271c712be34SPierre-Louis Bossart 272c712be34SPierre-Louis Bossart { 273c712be34SPierre-Louis Bossart unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; 274c712be34SPierre-Louis Bossart __le32 *bdl; 275c712be34SPierre-Louis Bossart int frags; 276c712be34SPierre-Louis Bossart int ret; 277c712be34SPierre-Louis Bossart 278c712be34SPierre-Louis Bossart ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab); 279c712be34SPierre-Louis Bossart if (ret < 0) { 280c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: failed to alloc fw buffer: %x\n", __func__, ret); 281c712be34SPierre-Louis Bossart return ret; 282c712be34SPierre-Louis Bossart } 283c712be34SPierre-Louis Bossart 284c712be34SPierre-Louis Bossart ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab_bdl); 285c712be34SPierre-Louis Bossart if (ret < 0) { 286c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: failed to alloc blde: %x\n", __func__, ret); 287c712be34SPierre-Louis Bossart snd_dma_free_pages(dmab); 288c712be34SPierre-Louis Bossart return ret; 289c712be34SPierre-Louis Bossart } 290c712be34SPierre-Louis Bossart 291c712be34SPierre-Louis Bossart bdl = (__le32 *)dmab_bdl->area; 292c712be34SPierre-Louis Bossart frags = cl_skl_cldma_setup_bdle(sdev, dmab, &bdl, bufsize, 1); 293c712be34SPierre-Louis Bossart cl_skl_cldma_setup_controller(sdev, dmab_bdl, bufsize, frags); 294c712be34SPierre-Louis Bossart 295c712be34SPierre-Louis Bossart return ret; 296c712be34SPierre-Louis Bossart } 297c712be34SPierre-Louis Bossart 298c712be34SPierre-Louis Bossart static void cl_cleanup_skl(struct snd_sof_dev *sdev, 299c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab, 300c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab_bdl) 301c712be34SPierre-Louis Bossart { 302c712be34SPierre-Louis Bossart cl_skl_cldma_cleanup_spb(sdev); 303c712be34SPierre-Louis Bossart cl_skl_cldma_stream_clear(sdev); 304c712be34SPierre-Louis Bossart snd_dma_free_pages(dmab); 305c712be34SPierre-Louis Bossart snd_dma_free_pages(dmab_bdl); 306c712be34SPierre-Louis Bossart } 307c712be34SPierre-Louis Bossart 308c712be34SPierre-Louis Bossart static int cl_dsp_init_skl(struct snd_sof_dev *sdev, 309c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab, 310c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab_bdl) 311c712be34SPierre-Louis Bossart { 312c712be34SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 313c712be34SPierre-Louis Bossart const struct sof_intel_dsp_desc *chip = hda->desc; 314c712be34SPierre-Louis Bossart unsigned int status; 315c712be34SPierre-Louis Bossart u32 flags; 316c712be34SPierre-Louis Bossart int ret; 317c712be34SPierre-Louis Bossart 318c712be34SPierre-Louis Bossart /* check if the init_core is already enabled, if yes, reset and make it run, 319c712be34SPierre-Louis Bossart * if not, powerdown and enable it again. 320c712be34SPierre-Louis Bossart */ 321c712be34SPierre-Louis Bossart if (hda_dsp_core_is_enabled(sdev, chip->init_core_mask)) { 322c712be34SPierre-Louis Bossart /* if enabled, reset it, and run the init_core. */ 323c712be34SPierre-Louis Bossart ret = hda_dsp_core_stall_reset(sdev, chip->init_core_mask); 324c712be34SPierre-Louis Bossart if (ret < 0) 325c712be34SPierre-Louis Bossart goto err; 326c712be34SPierre-Louis Bossart 327c712be34SPierre-Louis Bossart ret = hda_dsp_core_run(sdev, chip->init_core_mask); 328c712be34SPierre-Louis Bossart if (ret < 0) { 329c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: dsp core start failed %d\n", __func__, ret); 330c712be34SPierre-Louis Bossart goto err; 331c712be34SPierre-Louis Bossart } 332c712be34SPierre-Louis Bossart } else { 333c712be34SPierre-Louis Bossart /* if not enabled, power down it first and then powerup and run 334c712be34SPierre-Louis Bossart * the init_core. 335c712be34SPierre-Louis Bossart */ 336c712be34SPierre-Louis Bossart ret = hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 337c712be34SPierre-Louis Bossart if (ret < 0) { 338c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: dsp core0 disable fail: %d\n", __func__, ret); 339c712be34SPierre-Louis Bossart goto err; 340c712be34SPierre-Louis Bossart } 341c712be34SPierre-Louis Bossart ret = hda_dsp_enable_core(sdev, chip->init_core_mask); 342c712be34SPierre-Louis Bossart if (ret < 0) { 343c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: dsp core0 enable fail: %d\n", __func__, ret); 344c712be34SPierre-Louis Bossart goto err; 345c712be34SPierre-Louis Bossart } 346c712be34SPierre-Louis Bossart } 347c712be34SPierre-Louis Bossart 348c712be34SPierre-Louis Bossart /* prepare DMA for code loader stream */ 349c712be34SPierre-Louis Bossart ret = cl_stream_prepare_skl(sdev, dmab, dmab_bdl); 350c712be34SPierre-Louis Bossart if (ret < 0) { 351c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: dma prepare fw loading err: %x\n", __func__, ret); 352c712be34SPierre-Louis Bossart return ret; 353c712be34SPierre-Louis Bossart } 354c712be34SPierre-Louis Bossart 355c712be34SPierre-Louis Bossart /* enable the interrupt */ 356c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 357c712be34SPierre-Louis Bossart HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); 358c712be34SPierre-Louis Bossart 359c712be34SPierre-Louis Bossart /* enable IPC DONE interrupt */ 360c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, 361c712be34SPierre-Louis Bossart HDA_DSP_REG_HIPCCTL_DONE, 362c712be34SPierre-Louis Bossart HDA_DSP_REG_HIPCCTL_DONE); 363c712be34SPierre-Louis Bossart 364c712be34SPierre-Louis Bossart /* enable IPC BUSY interrupt */ 365c712be34SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, 366c712be34SPierre-Louis Bossart HDA_DSP_REG_HIPCCTL_BUSY, 367c712be34SPierre-Louis Bossart HDA_DSP_REG_HIPCCTL_BUSY); 368c712be34SPierre-Louis Bossart 369c712be34SPierre-Louis Bossart /* polling the ROM init status information. */ 370c712be34SPierre-Louis Bossart ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 371c712be34SPierre-Louis Bossart chip->rom_status_reg, status, 372c712be34SPierre-Louis Bossart (FSR_TO_STATE_CODE(status) 373c712be34SPierre-Louis Bossart == FSR_STATE_INIT_DONE), 374c712be34SPierre-Louis Bossart HDA_DSP_REG_POLL_INTERVAL_US, 375c712be34SPierre-Louis Bossart chip->rom_init_timeout * 376c712be34SPierre-Louis Bossart USEC_PER_MSEC); 377c712be34SPierre-Louis Bossart if (ret < 0) 378c712be34SPierre-Louis Bossart goto err; 379c712be34SPierre-Louis Bossart 380c712be34SPierre-Louis Bossart return ret; 381c712be34SPierre-Louis Bossart 382c712be34SPierre-Louis Bossart err: 383c712be34SPierre-Louis Bossart flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; 384c712be34SPierre-Louis Bossart 385c712be34SPierre-Louis Bossart snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); 386c712be34SPierre-Louis Bossart cl_cleanup_skl(sdev, dmab, dmab_bdl); 387c712be34SPierre-Louis Bossart hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 388c712be34SPierre-Louis Bossart return ret; 389c712be34SPierre-Louis Bossart } 390c712be34SPierre-Louis Bossart 391c712be34SPierre-Louis Bossart static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, 392c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab, 393c712be34SPierre-Louis Bossart unsigned int bufsize, 394c712be34SPierre-Louis Bossart unsigned int copysize, 395c712be34SPierre-Louis Bossart const void *curr_pos, 396c712be34SPierre-Louis Bossart bool intr_enable) 397c712be34SPierre-Louis Bossart { 398c712be34SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 399c712be34SPierre-Louis Bossart 400c712be34SPierre-Louis Bossart /* copy the image into the buffer with the maximum buffer size. */ 401c712be34SPierre-Louis Bossart unsigned int size = (bufsize == copysize) ? bufsize : copysize; 402c712be34SPierre-Louis Bossart 403c712be34SPierre-Louis Bossart memcpy(dmab->area, curr_pos, size); 404c712be34SPierre-Louis Bossart 405c712be34SPierre-Louis Bossart /* Set the wait condition for every load. */ 406c712be34SPierre-Louis Bossart hda->code_loading = 1; 407c712be34SPierre-Louis Bossart 408c712be34SPierre-Louis Bossart /* Set the interrupt. */ 409c712be34SPierre-Louis Bossart if (intr_enable) 410c712be34SPierre-Louis Bossart cl_skl_cldma_set_intr(sdev, true); 411c712be34SPierre-Louis Bossart 412c712be34SPierre-Louis Bossart /* Set the SPB. */ 413c712be34SPierre-Louis Bossart cl_skl_cldma_setup_spb(sdev, size, true); 414c712be34SPierre-Louis Bossart 415c712be34SPierre-Louis Bossart /* Trigger the code loading stream. */ 416c712be34SPierre-Louis Bossart cl_skl_cldma_stream_run(sdev, true); 417c712be34SPierre-Louis Bossart } 418c712be34SPierre-Louis Bossart 419c712be34SPierre-Louis Bossart static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev, 420c712be34SPierre-Louis Bossart bool intr_wait) 421c712be34SPierre-Louis Bossart { 422c712be34SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 423c712be34SPierre-Louis Bossart const struct sof_intel_dsp_desc *chip = hda->desc; 424c712be34SPierre-Louis Bossart int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 425c712be34SPierre-Louis Bossart u8 cl_dma_intr_status; 426c712be34SPierre-Louis Bossart 427c712be34SPierre-Louis Bossart /* 428c712be34SPierre-Louis Bossart * Wait for CLDMA interrupt to inform the binary segment transfer is 429c712be34SPierre-Louis Bossart * complete. 430c712be34SPierre-Louis Bossart */ 431c712be34SPierre-Louis Bossart if (!wait_event_timeout(hda->waitq, !hda->code_loading, 432c712be34SPierre-Louis Bossart msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) { 433c712be34SPierre-Louis Bossart dev_err(sdev->dev, "cldma copy timeout\n"); 434c712be34SPierre-Louis Bossart dev_err(sdev->dev, "ROM code=%#x: FW status=%#x\n", 435c712be34SPierre-Louis Bossart snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), 436c712be34SPierre-Louis Bossart snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); 437c712be34SPierre-Louis Bossart return -EIO; 438c712be34SPierre-Louis Bossart } 439c712be34SPierre-Louis Bossart 440c712be34SPierre-Louis Bossart /* now check DMA interrupt status */ 441c712be34SPierre-Louis Bossart cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 442*38bf0780SPierre-Louis Bossart sd_offset + SOF_HDA_ADSP_REG_SD_STS); 443c712be34SPierre-Louis Bossart 444c712be34SPierre-Louis Bossart if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) { 445c712be34SPierre-Louis Bossart dev_err(sdev->dev, "cldma copy failed\n"); 446c712be34SPierre-Louis Bossart return -EIO; 447c712be34SPierre-Louis Bossart } 448c712be34SPierre-Louis Bossart 449c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "cldma buffer copy complete\n"); 450c712be34SPierre-Louis Bossart return 0; 451c712be34SPierre-Louis Bossart } 452c712be34SPierre-Louis Bossart 453c712be34SPierre-Louis Bossart static int 454c712be34SPierre-Louis Bossart cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, 455c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab, 456c712be34SPierre-Louis Bossart const void *bin, 457c712be34SPierre-Louis Bossart u32 total_size, u32 bufsize) 458c712be34SPierre-Louis Bossart { 459c712be34SPierre-Louis Bossart unsigned int bytes_left = total_size; 460c712be34SPierre-Louis Bossart const void *curr_pos = bin; 461c712be34SPierre-Louis Bossart int ret; 462c712be34SPierre-Louis Bossart 463c712be34SPierre-Louis Bossart if (total_size <= 0) 464c712be34SPierre-Louis Bossart return -EINVAL; 465c712be34SPierre-Louis Bossart 466c712be34SPierre-Louis Bossart while (bytes_left > 0) { 467c712be34SPierre-Louis Bossart if (bytes_left > bufsize) { 468c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bufsize); 469c712be34SPierre-Louis Bossart 470c712be34SPierre-Louis Bossart cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bufsize, curr_pos, true); 471c712be34SPierre-Louis Bossart 472c712be34SPierre-Louis Bossart ret = cl_skl_cldma_wait_interruptible(sdev, false); 473c712be34SPierre-Louis Bossart if (ret < 0) { 474c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: fw failed to load. %#x bytes remaining\n", 475c712be34SPierre-Louis Bossart __func__, bytes_left); 476c712be34SPierre-Louis Bossart return ret; 477c712be34SPierre-Louis Bossart } 478c712be34SPierre-Louis Bossart 479c712be34SPierre-Louis Bossart bytes_left -= bufsize; 480c712be34SPierre-Louis Bossart curr_pos += bufsize; 481c712be34SPierre-Louis Bossart } else { 482c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bytes_left); 483c712be34SPierre-Louis Bossart 484c712be34SPierre-Louis Bossart cl_skl_cldma_set_intr(sdev, false); 485c712be34SPierre-Louis Bossart cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bytes_left, curr_pos, false); 486c712be34SPierre-Louis Bossart return 0; 487c712be34SPierre-Louis Bossart } 488c712be34SPierre-Louis Bossart } 489c712be34SPierre-Louis Bossart 490c712be34SPierre-Louis Bossart return bytes_left; 491c712be34SPierre-Louis Bossart } 492c712be34SPierre-Louis Bossart 493c712be34SPierre-Louis Bossart static int cl_copy_fw_skl(struct snd_sof_dev *sdev, 494c712be34SPierre-Louis Bossart struct snd_dma_buffer *dmab) 495c712be34SPierre-Louis Bossart 496c712be34SPierre-Louis Bossart { 4974fd0f664SPeter Ujfalusi const struct firmware *fw = sdev->basefw.fw; 498c712be34SPierre-Louis Bossart struct firmware stripped_firmware; 499c712be34SPierre-Louis Bossart unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; 500c712be34SPierre-Louis Bossart int ret; 501c712be34SPierre-Louis Bossart 5024fd0f664SPeter Ujfalusi stripped_firmware.data = fw->data + sdev->basefw.payload_offset; 5034fd0f664SPeter Ujfalusi stripped_firmware.size = fw->size - sdev->basefw.payload_offset; 504c712be34SPierre-Louis Bossart 505c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize); 506c712be34SPierre-Louis Bossart 507c712be34SPierre-Louis Bossart ret = cl_skl_cldma_copy_to_buf(sdev, dmab, stripped_firmware.data, 508c712be34SPierre-Louis Bossart stripped_firmware.size, bufsize); 509c712be34SPierre-Louis Bossart if (ret < 0) 510c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: fw copy failed %d\n", __func__, ret); 511c712be34SPierre-Louis Bossart 512c712be34SPierre-Louis Bossart return ret; 513c712be34SPierre-Louis Bossart } 514c712be34SPierre-Louis Bossart 515c712be34SPierre-Louis Bossart int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) 516c712be34SPierre-Louis Bossart { 517c712be34SPierre-Louis Bossart struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 518c712be34SPierre-Louis Bossart const struct sof_intel_dsp_desc *chip = hda->desc; 519c712be34SPierre-Louis Bossart struct snd_dma_buffer dmab_bdl; 520c712be34SPierre-Louis Bossart struct snd_dma_buffer dmab; 521c712be34SPierre-Louis Bossart unsigned int reg; 522c712be34SPierre-Louis Bossart u32 flags; 523c712be34SPierre-Louis Bossart int ret; 524c712be34SPierre-Louis Bossart 525c712be34SPierre-Louis Bossart ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); 526c712be34SPierre-Louis Bossart 527c712be34SPierre-Louis Bossart /* retry enabling core and ROM load. seemed to help */ 528c712be34SPierre-Louis Bossart if (ret < 0) { 529c712be34SPierre-Louis Bossart ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); 530c712be34SPierre-Louis Bossart if (ret < 0) { 531c712be34SPierre-Louis Bossart dev_err(sdev->dev, "Error code=%#x: FW status=%#x\n", 532c712be34SPierre-Louis Bossart snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), 533c712be34SPierre-Louis Bossart snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); 534c712be34SPierre-Louis Bossart dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); 535c712be34SPierre-Louis Bossart return ret; 536c712be34SPierre-Louis Bossart } 537c712be34SPierre-Louis Bossart } 538c712be34SPierre-Louis Bossart 539c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "ROM init successful\n"); 540c712be34SPierre-Louis Bossart 541c712be34SPierre-Louis Bossart /* at this point DSP ROM has been initialized and should be ready for 542c712be34SPierre-Louis Bossart * code loading and firmware boot 543c712be34SPierre-Louis Bossart */ 544c712be34SPierre-Louis Bossart ret = cl_copy_fw_skl(sdev, &dmab); 545c712be34SPierre-Louis Bossart if (ret < 0) { 546c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: load firmware failed : %d\n", __func__, ret); 547c712be34SPierre-Louis Bossart goto err; 548c712be34SPierre-Louis Bossart } 549c712be34SPierre-Louis Bossart 550c712be34SPierre-Louis Bossart ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 551c712be34SPierre-Louis Bossart chip->rom_status_reg, reg, 552c712be34SPierre-Louis Bossart (FSR_TO_STATE_CODE(reg) 553c712be34SPierre-Louis Bossart == FSR_STATE_ROM_BASEFW_ENTERED), 554c712be34SPierre-Louis Bossart HDA_DSP_REG_POLL_INTERVAL_US, 555c712be34SPierre-Louis Bossart HDA_DSP_BASEFW_TIMEOUT_US); 556c712be34SPierre-Louis Bossart 557c712be34SPierre-Louis Bossart dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 558c712be34SPierre-Louis Bossart 559c712be34SPierre-Louis Bossart cl_skl_cldma_stream_run(sdev, false); 560c712be34SPierre-Louis Bossart cl_cleanup_skl(sdev, &dmab, &dmab_bdl); 561c712be34SPierre-Louis Bossart 562c712be34SPierre-Louis Bossart if (!ret) 563c712be34SPierre-Louis Bossart return chip->init_core_mask; 564c712be34SPierre-Louis Bossart 565c712be34SPierre-Louis Bossart return ret; 566c712be34SPierre-Louis Bossart 567c712be34SPierre-Louis Bossart err: 568c712be34SPierre-Louis Bossart flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; 569c712be34SPierre-Louis Bossart 570c712be34SPierre-Louis Bossart snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); 571c712be34SPierre-Louis Bossart 572c712be34SPierre-Louis Bossart /* power down DSP */ 573c712be34SPierre-Louis Bossart hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 574c712be34SPierre-Louis Bossart cl_skl_cldma_stream_run(sdev, false); 575c712be34SPierre-Louis Bossart cl_cleanup_skl(sdev, &dmab, &dmab_bdl); 576c712be34SPierre-Louis Bossart 577c712be34SPierre-Louis Bossart dev_err(sdev->dev, "%s: load fw failed err: %d\n", __func__, ret); 578c712be34SPierre-Louis Bossart return ret; 579c712be34SPierre-Louis Bossart } 580