Unverified Commit 4b15c497 authored by Mark Brown's avatar Mark Brown
Browse files

Merge series "SOF fixes and updates for FW boot" from Ranjani Sridharan...

Merge series "SOF fixes and updates for FW boot" from Ranjani Sridharan <ranjani.sridharan@linux.intel.com>:

This series includes fixes and updates for the FW boot sequence for
Intel platforms.

Ranjani Sridharan (7):
  ALSA: hda: fix VS_LTRC register name
  ASoC: SOF: Intel: hda: Add helper function to program ICCMAX stream
  ASoC: SOF: Intel: hda: modify the signature of get_stream_with_tag()
  ASoC: SOF: Intel: hda: define macro for code loader stream format
  ASoC: SOF: Intel: hda: Define FW boot sequence with ICCMAX
  ASoC: SOF: Intel: hda: Add sof_tgl_ops for TGL platforms
  ASoC: SOF: Intel: hda: Simplify error handling during FW boot

Yong Zhi (1):
  ASoC: SOF: Intel: hda: Remove unused parameters in cl_dsp_init()

 include/sound/hda_register.h     |   2 +-
 sound/soc/sof/intel/Makefile     |   2 +-
 sound/soc/sof/intel/cnl.c        |  23 +----
 sound/soc/sof/intel/hda-ipc.h    |   4 +
 sound/soc/sof/intel/hda-loader.c | 145 ++++++++++++++++++-------------
 sound/soc/sof/intel/hda-stream.c |  69 +++++++++++++++
 sound/soc/sof/intel/hda.h        |   6 ++
 sound/soc/sof/intel/tgl.c        | 137 +++++++++++++++++++++++++++++
 sound/soc/sof/sof-pci-dev.c      |   2 +-
 9 files changed, 306 insertions(+), 84 deletions(-)
 create mode 100644 sound/soc/sof/intel/tgl.c

--
2.25.1
parents c1c277b2 01d42d5a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_VS_EM3U			0x103C
#define AZX_REG_VS_EM4L			0x1040
#define AZX_REG_VS_EM4U			0x1044
#define AZX_REG_VS_LTRC			0x1048
#define AZX_REG_VS_LTRP			0x1048
#define AZX_REG_VS_D0I3C		0x104A
#define AZX_REG_VS_PCE			0x104B
#define AZX_REG_VS_L2MAGC		0x1050
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o
snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
				 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
				 hda-dai.o hda-bus.o \
				 apl.o cnl.o
				 apl.o cnl.o tgl.o
snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o

snd-sof-intel-hda-objs := hda-codec.o
+3 −20
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
static void cnl_ipc_host_done(struct snd_sof_dev *sdev);
static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev);

static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{
	struct snd_sof_dev *sdev = context;
	u32 hipci;
@@ -163,8 +163,7 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
	return false;
}

static int cnl_ipc_send_msg(struct snd_sof_dev *sdev,
			    struct snd_sof_ipc_msg *msg)
int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
	struct sof_ipc_cmd_hdr *hdr;
@@ -211,7 +210,7 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev,
	return 0;
}

static void cnl_ipc_dump(struct snd_sof_dev *sdev)
void cnl_ipc_dump(struct snd_sof_dev *sdev)
{
	u32 hipcctl;
	u32 hipcida;
@@ -369,22 +368,6 @@ const struct sof_intel_dsp_desc icl_chip_info = {
};
EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

const struct sof_intel_dsp_desc tgl_chip_info = {
	/* Tigerlake */
	.cores_num = 4,
	.init_core_mask = 1,
	.cores_mask = HDA_DSP_CORE_MASK(0),
	.ipc_req = CNL_DSP_REG_HIPCIDR,
	.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
	.ipc_ack = CNL_DSP_REG_HIPCIDA,
	.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
	.ipc_ctl = CNL_DSP_REG_HIPCCTL,
	.rom_init_timeout	= 300,
	.ssp_count = ICL_SSP_COUNT,
	.ssp_base_offset = CNL_SSP_BASE_OFFSET,
};
EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

const struct sof_intel_dsp_desc ehl_chip_info = {
	/* Elkhartlake */
	.cores_num = 4,
+4 −0
Original line number Diff line number Diff line
@@ -48,4 +48,8 @@
#define HDA_PM_PG_STREAMING	BIT(1)
#define HDA_PM_PG_RSVD		BIT(0)

irqreturn_t cnl_ipc_irq_thread(int irq, void *context);
int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void cnl_ipc_dump(struct snd_sof_dev *sdev);

#endif
+84 −61
Original line number Diff line number Diff line
@@ -17,13 +17,15 @@

#include <linux/firmware.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
#include "../ops.h"
#include "hda.h"

#define HDA_FW_BOOT_ATTEMPTS	3
#define HDA_CL_STREAM_FORMAT 0x40

static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
						 unsigned int size, struct snd_dma_buffer *dmab,
						 int direction)
{
@@ -32,16 +34,11 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
	struct pci_dev *pci = to_pci_dev(sdev->dev);
	int ret;

	if (direction != SNDRV_PCM_STREAM_PLAYBACK) {
		dev_err(sdev->dev, "error: code loading DMA is playback only\n");
		return -EINVAL;
	}

	dsp_stream = hda_dsp_stream_get(sdev, direction);

	if (!dsp_stream) {
		dev_err(sdev->dev, "error: no stream available\n");
		return -ENODEV;
		return ERR_PTR(-ENODEV);
	}
	hstream = &dsp_stream->hstream;
	hstream->substream = NULL;
@@ -57,20 +54,27 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
	hstream->format_val = format;
	hstream->bufsize = size;

	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
		ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL);
		if (ret < 0) {
			dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret);
			goto error;
		}
	} else {
		ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
		if (ret < 0) {
			dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
			goto error;
		}

		hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
	}

	return hstream->stream_tag;
	return dsp_stream;

error:
	hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
	snd_dma_free_pages(dmab);
	return ret;
	return ERR_PTR(ret);
}

/*
@@ -78,8 +82,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
 * status on core 1, so power up core 1 also momentarily, keep it in
 * reset/stall and then turn it off
 */
static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata,
		       u32 fwsize, int stream_tag, int iteration)
static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration)
{
	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
	const struct sof_intel_dsp_desc *chip = hda->desc;
@@ -205,34 +208,20 @@ static int cl_trigger(struct snd_sof_dev *sdev,
	}
}

static struct hdac_ext_stream *get_stream_with_tag(struct snd_sof_dev *sdev,
						   int tag)
{
	struct hdac_bus *bus = sof_to_bus(sdev);
	struct hdac_stream *s;

	/* get stream with tag */
	list_for_each_entry(s, &bus->stream_list, list) {
		if (s->direction == SNDRV_PCM_STREAM_PLAYBACK &&
		    s->stream_tag == tag) {
			return stream_to_hdac_ext_stream(s);
		}
	}

	return NULL;
}

static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
		      struct hdac_ext_stream *stream)
{
	struct hdac_stream *hstream = &stream->hstream;
	int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
	int ret;
	int ret = 0;

	if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
		ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0);
	else
		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
					SOF_HDA_SD_CTL_DMA_START, 0);

	hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK,
			   hstream->stream_tag);
	hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag);
	hstream->running = 0;
	hstream->substream = NULL;

@@ -290,6 +279,54 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream)
	return status;
}

int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
{
	struct snd_sof_pdata *plat_data = sdev->pdata;
	struct hdac_ext_stream *iccmax_stream;
	struct hdac_bus *bus = sof_to_bus(sdev);
	struct firmware stripped_firmware;
	int ret, ret1;
	u8 original_gb;

	/* save the original LTRP guardband value */
	original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK;

	if (plat_data->fw->size <= plat_data->fw_offset) {
		dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
		return -EINVAL;
	}

	stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;

	/* prepare capture stream for ICCMAX */
	iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
					  &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
	if (IS_ERR(iccmax_stream)) {
		dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
		return PTR_ERR(iccmax_stream);
	}

	ret = hda_dsp_cl_boot_firmware(sdev);

	/*
	 * Perform iccmax stream cleanup. This should be done even if firmware loading fails.
	 * If the cleanup also fails, we return the initial error
	 */
	ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream);
	if (ret1 < 0) {
		dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");

		/* set return value to indicate cleanup failure */
		if (!ret)
			ret = ret1;
	}

	/* restore the original guardband value after FW boot */
	snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb);

	return ret;
}

int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
{
	struct snd_sof_pdata *plat_data = sdev->pdata;
@@ -297,7 +334,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
	const struct sof_intel_dsp_desc *chip_info;
	struct hdac_ext_stream *stream;
	struct firmware stripped_firmware;
	int ret, ret1, tag, i;
	int ret, ret1, i;

	chip_info = desc->chip_info;

@@ -313,23 +350,11 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
	init_waitqueue_head(&sdev->boot_wait);

	/* prepare DMA for code loader stream */
	tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size,
	stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
				   &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK);

	if (tag < 0) {
		dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n",
			tag);
		return tag;
	}

	/* get stream with tag */
	stream = get_stream_with_tag(sdev, tag);
	if (!stream) {
		dev_err(sdev->dev,
			"error: could not get stream with stream tag %d\n",
			tag);
		ret = -ENODEV;
		goto err;
	if (IS_ERR(stream)) {
		dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
		return PTR_ERR(stream);
	}

	memcpy(sdev->dmab.area, stripped_firmware.data,
@@ -340,8 +365,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
		dev_dbg(sdev->dev,
			"Attempting iteration %d of Core En/ROM load...\n", i);

		ret = cl_dsp_init(sdev, stripped_firmware.data,
				  stripped_firmware.size, tag, i + 1);
		ret = cl_dsp_init(sdev, stream->hstream.stream_tag, i + 1);

		/* don't retry anymore if successful */
		if (!ret)
@@ -410,7 +434,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
		return chip_info->init_core_mask;

	/* dump dsp registers and disable DSP upon error */
err:
	hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);

	/* disable DSP */
Loading