162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 462306a36Sopenharmony_ci// redistributing this file, you may do so under either license. 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright(c) 2018-2022 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/firmware.h> 1362306a36Sopenharmony_ci#include <linux/fs.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/pci.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <sound/hdaudio_ext.h> 2062306a36Sopenharmony_ci#include <sound/sof.h> 2162306a36Sopenharmony_ci#include <sound/pcm_params.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "../sof-priv.h" 2462306a36Sopenharmony_ci#include "../ops.h" 2562306a36Sopenharmony_ci#include "hda.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */ 2862306a36Sopenharmony_ci#define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Stream Reset */ 3162306a36Sopenharmony_ci#define HDA_CL_SD_CTL_SRST_SHIFT 0 3262306a36Sopenharmony_ci#define HDA_CL_SD_CTL_SRST(x) (((x) & 0x1) << \ 3362306a36Sopenharmony_ci HDA_CL_SD_CTL_SRST_SHIFT) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Stream Run */ 3662306a36Sopenharmony_ci#define HDA_CL_SD_CTL_RUN_SHIFT 1 3762306a36Sopenharmony_ci#define HDA_CL_SD_CTL_RUN(x) (((x) & 0x1) << \ 3862306a36Sopenharmony_ci HDA_CL_SD_CTL_RUN_SHIFT) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Interrupt On Completion Enable */ 4162306a36Sopenharmony_ci#define HDA_CL_SD_CTL_IOCE_SHIFT 2 4262306a36Sopenharmony_ci#define HDA_CL_SD_CTL_IOCE(x) (((x) & 0x1) << \ 4362306a36Sopenharmony_ci HDA_CL_SD_CTL_IOCE_SHIFT) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* FIFO Error Interrupt Enable */ 4662306a36Sopenharmony_ci#define HDA_CL_SD_CTL_FEIE_SHIFT 3 4762306a36Sopenharmony_ci#define HDA_CL_SD_CTL_FEIE(x) (((x) & 0x1) << \ 4862306a36Sopenharmony_ci HDA_CL_SD_CTL_FEIE_SHIFT) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Descriptor Error Interrupt Enable */ 5162306a36Sopenharmony_ci#define HDA_CL_SD_CTL_DEIE_SHIFT 4 5262306a36Sopenharmony_ci#define HDA_CL_SD_CTL_DEIE(x) (((x) & 0x1) << \ 5362306a36Sopenharmony_ci HDA_CL_SD_CTL_DEIE_SHIFT) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* FIFO Limit Change */ 5662306a36Sopenharmony_ci#define HDA_CL_SD_CTL_FIFOLC_SHIFT 5 5762306a36Sopenharmony_ci#define HDA_CL_SD_CTL_FIFOLC(x) (((x) & 0x1) << \ 5862306a36Sopenharmony_ci HDA_CL_SD_CTL_FIFOLC_SHIFT) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Stripe Control */ 6162306a36Sopenharmony_ci#define HDA_CL_SD_CTL_STRIPE_SHIFT 16 6262306a36Sopenharmony_ci#define HDA_CL_SD_CTL_STRIPE(x) (((x) & 0x3) << \ 6362306a36Sopenharmony_ci HDA_CL_SD_CTL_STRIPE_SHIFT) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Traffic Priority */ 6662306a36Sopenharmony_ci#define HDA_CL_SD_CTL_TP_SHIFT 18 6762306a36Sopenharmony_ci#define HDA_CL_SD_CTL_TP(x) (((x) & 0x1) << \ 6862306a36Sopenharmony_ci HDA_CL_SD_CTL_TP_SHIFT) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Bidirectional Direction Control */ 7162306a36Sopenharmony_ci#define HDA_CL_SD_CTL_DIR_SHIFT 19 7262306a36Sopenharmony_ci#define HDA_CL_SD_CTL_DIR(x) (((x) & 0x1) << \ 7362306a36Sopenharmony_ci HDA_CL_SD_CTL_DIR_SHIFT) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Stream Number */ 7662306a36Sopenharmony_ci#define HDA_CL_SD_CTL_STRM_SHIFT 20 7762306a36Sopenharmony_ci#define HDA_CL_SD_CTL_STRM(x) (((x) & 0xf) << \ 7862306a36Sopenharmony_ci HDA_CL_SD_CTL_STRM_SHIFT) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define HDA_CL_SD_CTL_INT(x) \ 8162306a36Sopenharmony_ci (HDA_CL_SD_CTL_IOCE(x) | \ 8262306a36Sopenharmony_ci HDA_CL_SD_CTL_FEIE(x) | \ 8362306a36Sopenharmony_ci HDA_CL_SD_CTL_DEIE(x)) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define HDA_CL_SD_CTL_INT_MASK \ 8662306a36Sopenharmony_ci (HDA_CL_SD_CTL_IOCE(1) | \ 8762306a36Sopenharmony_ci HDA_CL_SD_CTL_FEIE(1) | \ 8862306a36Sopenharmony_ci HDA_CL_SD_CTL_DEIE(1)) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 9162306a36Sopenharmony_ci#define BDL_ALIGN(x) ((x) >> DMA_ADDRESS_128_BITS_ALIGNMENT) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Buffer Descriptor List Lower Base Address */ 9462306a36Sopenharmony_ci#define HDA_CL_SD_BDLPLBA_SHIFT 7 9562306a36Sopenharmony_ci#define HDA_CL_SD_BDLPLBA_MASK GENMASK(31, 7) 9662306a36Sopenharmony_ci#define HDA_CL_SD_BDLPLBA(x) \ 9762306a36Sopenharmony_ci ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ 9862306a36Sopenharmony_ci HDA_CL_SD_BDLPLBA_MASK) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Buffer Descriptor List Upper Base Address */ 10162306a36Sopenharmony_ci#define HDA_CL_SD_BDLPUBA(x) \ 10262306a36Sopenharmony_ci (upper_32_bits(x)) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Software Position in Buffer Enable */ 10562306a36Sopenharmony_ci#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 10662306a36Sopenharmony_ci#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ 10762306a36Sopenharmony_ci (1 << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ 11062306a36Sopenharmony_ci (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ 11162306a36Sopenharmony_ci HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define HDA_CL_DMA_SD_INT_COMPLETE 0x4 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, 11662306a36Sopenharmony_ci struct snd_dma_buffer *dmab_data, 11762306a36Sopenharmony_ci __le32 **bdlp, int size, int with_ioc) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci phys_addr_t addr = virt_to_phys(dmab_data->area); 12062306a36Sopenharmony_ci __le32 *bdl = *bdlp; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * This code is simplified by using one fragment of physical memory and assuming 12462306a36Sopenharmony_ci * all the code fits. This could be improved with scatter-gather but the firmware 12562306a36Sopenharmony_ci * size is limited by DSP memory anyways 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci bdl[0] = cpu_to_le32(lower_32_bits(addr)); 12862306a36Sopenharmony_ci bdl[1] = cpu_to_le32(upper_32_bits(addr)); 12962306a36Sopenharmony_ci bdl[2] = cpu_to_le32(size); 13062306a36Sopenharmony_ci bdl[3] = (!with_ioc) ? 0 : cpu_to_le32(0x01); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return 1; /* one fragment */ 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 13862306a36Sopenharmony_ci unsigned char val; 13962306a36Sopenharmony_ci int retries; 14062306a36Sopenharmony_ci u32 run = enable ? 0x1 : 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 14362306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 14462306a36Sopenharmony_ci HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci retries = 300; 14762306a36Sopenharmony_ci do { 14862306a36Sopenharmony_ci udelay(3); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* waiting for hardware to report the stream Run bit set */ 15162306a36Sopenharmony_ci val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 15262306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL); 15362306a36Sopenharmony_ci val &= HDA_CL_SD_CTL_RUN(1); 15462306a36Sopenharmony_ci if (enable && val) 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci else if (!enable && !val) 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci } while (--retries); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (retries == 0) 16162306a36Sopenharmony_ci dev_err(sdev->dev, "%s: failed to set Run bit=%d enable=%d\n", 16262306a36Sopenharmony_ci __func__, val, enable); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* make sure Run bit is cleared before setting stream register */ 17062306a36Sopenharmony_ci cl_skl_cldma_stream_run(sdev, 0); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Disable the Interrupt On Completion, FIFO Error Interrupt, 17362306a36Sopenharmony_ci * Descriptor Error Interrupt and set the cldma stream number to 0. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 17662306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 17762306a36Sopenharmony_ci HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); 17862306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 17962306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 18062306a36Sopenharmony_ci HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 18362306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(0)); 18462306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 18562306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Set the Cyclic Buffer Length to 0. */ 18862306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 18962306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CBL, 0); 19062306a36Sopenharmony_ci /* Set the Last Valid Index. */ 19162306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 19262306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, 19662306a36Sopenharmony_ci unsigned int size, bool enable) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int sd_offset = SOF_DSP_REG_CL_SPBFIFO; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (enable) 20162306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 20262306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, 20362306a36Sopenharmony_ci HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, 20462306a36Sopenharmony_ci HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(1)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 20762306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 21562306a36Sopenharmony_ci HDA_DSP_ADSPIC_CL_DMA, val); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci int sd_offset = SOF_DSP_REG_CL_SPBFIFO; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 22362306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, 22462306a36Sopenharmony_ci HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, 22562306a36Sopenharmony_ci HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(0)); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 22862306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, 0); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, 23262306a36Sopenharmony_ci struct snd_dma_buffer *dmab_bdl, 23362306a36Sopenharmony_ci unsigned int max_size, u32 count) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Clear the stream first and then set it. */ 23862306a36Sopenharmony_ci cl_skl_cldma_stream_clear(sdev); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* setting the stream register */ 24162306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 24262306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 24362306a36Sopenharmony_ci HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); 24462306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 24562306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 24662306a36Sopenharmony_ci HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Set the Cyclic Buffer Length. */ 24962306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 25062306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CBL, max_size); 25162306a36Sopenharmony_ci /* Set the Last Valid Index. */ 25262306a36Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_BAR, 25362306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_LVI, count - 1); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Set the Interrupt On Completion, FIFO Error Interrupt, 25662306a36Sopenharmony_ci * Descriptor Error Interrupt and the cldma stream number. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 25962306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 26062306a36Sopenharmony_ci HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); 26162306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 26262306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_CTL, 26362306a36Sopenharmony_ci HDA_CL_SD_CTL_STRM(0xf), 26462306a36Sopenharmony_ci HDA_CL_SD_CTL_STRM(1)); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int cl_stream_prepare_skl(struct snd_sof_dev *sdev, 26862306a36Sopenharmony_ci struct snd_dma_buffer *dmab, 26962306a36Sopenharmony_ci struct snd_dma_buffer *dmab_bdl) 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; 27362306a36Sopenharmony_ci __le32 *bdl; 27462306a36Sopenharmony_ci int frags; 27562306a36Sopenharmony_ci int ret; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab); 27862306a36Sopenharmony_ci if (ret < 0) { 27962306a36Sopenharmony_ci dev_err(sdev->dev, "%s: failed to alloc fw buffer: %x\n", __func__, ret); 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab_bdl); 28462306a36Sopenharmony_ci if (ret < 0) { 28562306a36Sopenharmony_ci dev_err(sdev->dev, "%s: failed to alloc blde: %x\n", __func__, ret); 28662306a36Sopenharmony_ci snd_dma_free_pages(dmab); 28762306a36Sopenharmony_ci return ret; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci bdl = (__le32 *)dmab_bdl->area; 29162306a36Sopenharmony_ci frags = cl_skl_cldma_setup_bdle(sdev, dmab, &bdl, bufsize, 1); 29262306a36Sopenharmony_ci cl_skl_cldma_setup_controller(sdev, dmab_bdl, bufsize, frags); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void cl_cleanup_skl(struct snd_sof_dev *sdev, 29862306a36Sopenharmony_ci struct snd_dma_buffer *dmab, 29962306a36Sopenharmony_ci struct snd_dma_buffer *dmab_bdl) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci cl_skl_cldma_cleanup_spb(sdev); 30262306a36Sopenharmony_ci cl_skl_cldma_stream_clear(sdev); 30362306a36Sopenharmony_ci snd_dma_free_pages(dmab); 30462306a36Sopenharmony_ci snd_dma_free_pages(dmab_bdl); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int cl_dsp_init_skl(struct snd_sof_dev *sdev, 30862306a36Sopenharmony_ci struct snd_dma_buffer *dmab, 30962306a36Sopenharmony_ci struct snd_dma_buffer *dmab_bdl) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 31262306a36Sopenharmony_ci const struct sof_intel_dsp_desc *chip = hda->desc; 31362306a36Sopenharmony_ci unsigned int status; 31462306a36Sopenharmony_ci u32 flags; 31562306a36Sopenharmony_ci int ret; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* check if the init_core is already enabled, if yes, reset and make it run, 31862306a36Sopenharmony_ci * if not, powerdown and enable it again. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci if (hda_dsp_core_is_enabled(sdev, chip->init_core_mask)) { 32162306a36Sopenharmony_ci /* if enabled, reset it, and run the init_core. */ 32262306a36Sopenharmony_ci ret = hda_dsp_core_stall_reset(sdev, chip->init_core_mask); 32362306a36Sopenharmony_ci if (ret < 0) 32462306a36Sopenharmony_ci goto err; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ret = hda_dsp_core_run(sdev, chip->init_core_mask); 32762306a36Sopenharmony_ci if (ret < 0) { 32862306a36Sopenharmony_ci dev_err(sdev->dev, "%s: dsp core start failed %d\n", __func__, ret); 32962306a36Sopenharmony_ci goto err; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci } else { 33262306a36Sopenharmony_ci /* if not enabled, power down it first and then powerup and run 33362306a36Sopenharmony_ci * the init_core. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci ret = hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 33662306a36Sopenharmony_ci if (ret < 0) { 33762306a36Sopenharmony_ci dev_err(sdev->dev, "%s: dsp core0 disable fail: %d\n", __func__, ret); 33862306a36Sopenharmony_ci goto err; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci ret = hda_dsp_enable_core(sdev, chip->init_core_mask); 34162306a36Sopenharmony_ci if (ret < 0) { 34262306a36Sopenharmony_ci dev_err(sdev->dev, "%s: dsp core0 enable fail: %d\n", __func__, ret); 34362306a36Sopenharmony_ci goto err; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* prepare DMA for code loader stream */ 34862306a36Sopenharmony_ci ret = cl_stream_prepare_skl(sdev, dmab, dmab_bdl); 34962306a36Sopenharmony_ci if (ret < 0) { 35062306a36Sopenharmony_ci dev_err(sdev->dev, "%s: dma prepare fw loading err: %x\n", __func__, ret); 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* enable the interrupt */ 35562306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 35662306a36Sopenharmony_ci HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* enable IPC DONE interrupt */ 35962306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, 36062306a36Sopenharmony_ci HDA_DSP_REG_HIPCCTL_DONE, 36162306a36Sopenharmony_ci HDA_DSP_REG_HIPCCTL_DONE); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* enable IPC BUSY interrupt */ 36462306a36Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, 36562306a36Sopenharmony_ci HDA_DSP_REG_HIPCCTL_BUSY, 36662306a36Sopenharmony_ci HDA_DSP_REG_HIPCCTL_BUSY); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* polling the ROM init status information. */ 36962306a36Sopenharmony_ci ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 37062306a36Sopenharmony_ci chip->rom_status_reg, status, 37162306a36Sopenharmony_ci (FSR_TO_STATE_CODE(status) 37262306a36Sopenharmony_ci == FSR_STATE_INIT_DONE), 37362306a36Sopenharmony_ci HDA_DSP_REG_POLL_INTERVAL_US, 37462306a36Sopenharmony_ci chip->rom_init_timeout * 37562306a36Sopenharmony_ci USEC_PER_MSEC); 37662306a36Sopenharmony_ci if (ret < 0) 37762306a36Sopenharmony_ci goto err; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cierr: 38262306a36Sopenharmony_ci flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); 38562306a36Sopenharmony_ci cl_cleanup_skl(sdev, dmab, dmab_bdl); 38662306a36Sopenharmony_ci hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, 39162306a36Sopenharmony_ci struct snd_dma_buffer *dmab, 39262306a36Sopenharmony_ci unsigned int bufsize, 39362306a36Sopenharmony_ci unsigned int copysize, 39462306a36Sopenharmony_ci const void *curr_pos, 39562306a36Sopenharmony_ci bool intr_enable) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* copy the image into the buffer with the maximum buffer size. */ 40062306a36Sopenharmony_ci unsigned int size = (bufsize == copysize) ? bufsize : copysize; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci memcpy(dmab->area, curr_pos, size); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Set the wait condition for every load. */ 40562306a36Sopenharmony_ci hda->code_loading = 1; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Set the interrupt. */ 40862306a36Sopenharmony_ci if (intr_enable) 40962306a36Sopenharmony_ci cl_skl_cldma_set_intr(sdev, true); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Set the SPB. */ 41262306a36Sopenharmony_ci cl_skl_cldma_setup_spb(sdev, size, true); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Trigger the code loading stream. */ 41562306a36Sopenharmony_ci cl_skl_cldma_stream_run(sdev, true); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev, 41962306a36Sopenharmony_ci bool intr_wait) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 42262306a36Sopenharmony_ci const struct sof_intel_dsp_desc *chip = hda->desc; 42362306a36Sopenharmony_ci int sd_offset = SOF_HDA_ADSP_LOADER_BASE; 42462306a36Sopenharmony_ci u8 cl_dma_intr_status; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Wait for CLDMA interrupt to inform the binary segment transfer is 42862306a36Sopenharmony_ci * complete. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci if (!wait_event_timeout(hda->waitq, !hda->code_loading, 43162306a36Sopenharmony_ci msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) { 43262306a36Sopenharmony_ci dev_err(sdev->dev, "cldma copy timeout\n"); 43362306a36Sopenharmony_ci dev_err(sdev->dev, "ROM code=%#x: FW status=%#x\n", 43462306a36Sopenharmony_ci snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), 43562306a36Sopenharmony_ci snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); 43662306a36Sopenharmony_ci return -EIO; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* now check DMA interrupt status */ 44062306a36Sopenharmony_ci cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 44162306a36Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_SD_STS); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) { 44462306a36Sopenharmony_ci dev_err(sdev->dev, "cldma copy failed\n"); 44562306a36Sopenharmony_ci return -EIO; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci dev_dbg(sdev->dev, "cldma buffer copy complete\n"); 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int 45362306a36Sopenharmony_cicl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, 45462306a36Sopenharmony_ci struct snd_dma_buffer *dmab, 45562306a36Sopenharmony_ci const void *bin, 45662306a36Sopenharmony_ci u32 total_size, u32 bufsize) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci unsigned int bytes_left = total_size; 45962306a36Sopenharmony_ci const void *curr_pos = bin; 46062306a36Sopenharmony_ci int ret; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (total_size <= 0) 46362306a36Sopenharmony_ci return -EINVAL; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci while (bytes_left > 0) { 46662306a36Sopenharmony_ci if (bytes_left > bufsize) { 46762306a36Sopenharmony_ci dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bufsize); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bufsize, curr_pos, true); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ret = cl_skl_cldma_wait_interruptible(sdev, false); 47262306a36Sopenharmony_ci if (ret < 0) { 47362306a36Sopenharmony_ci dev_err(sdev->dev, "%s: fw failed to load. %#x bytes remaining\n", 47462306a36Sopenharmony_ci __func__, bytes_left); 47562306a36Sopenharmony_ci return ret; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci bytes_left -= bufsize; 47962306a36Sopenharmony_ci curr_pos += bufsize; 48062306a36Sopenharmony_ci } else { 48162306a36Sopenharmony_ci dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bytes_left); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci cl_skl_cldma_set_intr(sdev, false); 48462306a36Sopenharmony_ci cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bytes_left, curr_pos, false); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return bytes_left; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int cl_copy_fw_skl(struct snd_sof_dev *sdev, 49362306a36Sopenharmony_ci struct snd_dma_buffer *dmab) 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci const struct firmware *fw = sdev->basefw.fw; 49762306a36Sopenharmony_ci struct firmware stripped_firmware; 49862306a36Sopenharmony_ci unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci stripped_firmware.data = fw->data + sdev->basefw.payload_offset; 50262306a36Sopenharmony_ci stripped_firmware.size = fw->size - sdev->basefw.payload_offset; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = cl_skl_cldma_copy_to_buf(sdev, dmab, stripped_firmware.data, 50762306a36Sopenharmony_ci stripped_firmware.size, bufsize); 50862306a36Sopenharmony_ci if (ret < 0) 50962306a36Sopenharmony_ci dev_err(sdev->dev, "%s: fw copy failed %d\n", __func__, ret); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return ret; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ciint hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 51762306a36Sopenharmony_ci const struct sof_intel_dsp_desc *chip = hda->desc; 51862306a36Sopenharmony_ci struct snd_dma_buffer dmab_bdl; 51962306a36Sopenharmony_ci struct snd_dma_buffer dmab; 52062306a36Sopenharmony_ci unsigned int reg; 52162306a36Sopenharmony_ci u32 flags; 52262306a36Sopenharmony_ci int ret; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* retry enabling core and ROM load. seemed to help */ 52762306a36Sopenharmony_ci if (ret < 0) { 52862306a36Sopenharmony_ci ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); 52962306a36Sopenharmony_ci if (ret < 0) { 53062306a36Sopenharmony_ci dev_err(sdev->dev, "Error code=%#x: FW status=%#x\n", 53162306a36Sopenharmony_ci snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), 53262306a36Sopenharmony_ci snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); 53362306a36Sopenharmony_ci dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); 53462306a36Sopenharmony_ci return ret; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dev_dbg(sdev->dev, "ROM init successful\n"); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* at this point DSP ROM has been initialized and should be ready for 54162306a36Sopenharmony_ci * code loading and firmware boot 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci ret = cl_copy_fw_skl(sdev, &dmab); 54462306a36Sopenharmony_ci if (ret < 0) { 54562306a36Sopenharmony_ci dev_err(sdev->dev, "%s: load firmware failed : %d\n", __func__, ret); 54662306a36Sopenharmony_ci goto err; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, 55062306a36Sopenharmony_ci chip->rom_status_reg, reg, 55162306a36Sopenharmony_ci (FSR_TO_STATE_CODE(reg) 55262306a36Sopenharmony_ci == FSR_STATE_ROM_BASEFW_ENTERED), 55362306a36Sopenharmony_ci HDA_DSP_REG_POLL_INTERVAL_US, 55462306a36Sopenharmony_ci HDA_DSP_BASEFW_TIMEOUT_US); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci cl_skl_cldma_stream_run(sdev, false); 55962306a36Sopenharmony_ci cl_cleanup_skl(sdev, &dmab, &dmab_bdl); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!ret) 56262306a36Sopenharmony_ci return chip->init_core_mask; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cierr: 56762306a36Sopenharmony_ci flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* power down DSP */ 57262306a36Sopenharmony_ci hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); 57362306a36Sopenharmony_ci cl_skl_cldma_stream_run(sdev, false); 57462306a36Sopenharmony_ci cl_cleanup_skl(sdev, &dmab, &dmab_bdl); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci dev_err(sdev->dev, "%s: load fw failed err: %d\n", __func__, ret); 57762306a36Sopenharmony_ci return ret; 57862306a36Sopenharmony_ci} 579