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