Unverified Commit 433363e7 authored by Seppo Ingalsuo's avatar Seppo Ingalsuo Committed by Mark Brown
Browse files

ASoC: SOF: Add asynchronous sample rate converter topology support



This patch adds into SOF topology the handling of ASRC DAPM type,
adds the tokens to configure the ASRC, and implement component IPC
into the driver.

Signed-off-by: default avatarSeppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191210004854.16845-2-pierre-louis.bossart@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent d612b455
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ enum sof_comp_type {
	SOF_COMP_KPB,			/* A key phrase buffer component */
	SOF_COMP_SELECTOR,		/**< channel selector component */
	SOF_COMP_DEMUX,
	SOF_COMP_ASRC,		/**< Asynchronous sample rate converter */
	/* keep FILEREAD/FILEWRITE as the last ones */
	SOF_COMP_FILEREAD = 10000,	/**< host test based file IO */
	SOF_COMP_FILEWRITE = 10001,	/**< host test based file IO */
@@ -147,6 +148,32 @@ struct sof_ipc_comp_src {
	uint32_t rate_mask;	/**< SOF_RATE_ supported rates */
} __packed;

/* generic ASRC component */
struct sof_ipc_comp_asrc {
	struct sof_ipc_comp comp;
	struct sof_ipc_comp_config config;
	/* either source or sink rate must be non zero */
	uint32_t source_rate;		/**< Define fixed source rate or */
					/**< use 0 to indicate need to get */
					/**< the rate from stream */
	uint32_t sink_rate;		/**< Define fixed sink rate or */
					/**< use 0 to indicate need to get */
					/**< the rate from stream */
	uint32_t asynchronous_mode;	/**< synchronous 0, asynchronous 1 */
					/**< When 1 the ASRC tracks and */
					/**< compensates for drift. */
	uint32_t operation_mode;	/**< push 0, pull 1, In push mode the */
					/**< ASRC consumes a defined number */
					/**< of frames at input, with varying */
					/**< number of frames at output. */
					/**< In pull mode the ASRC outputs */
					/**< a defined number of frames while */
					/**< number of input frames varies. */

	/* reserved for future use */
	uint32_t reserved[4];
} __attribute__((packed));

/* generic MUX component */
struct sof_ipc_comp_mux {
	struct sof_ipc_comp comp;
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@

/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 11
#define SOF_ABI_MINOR 12
#define SOF_ABI_PATCH 0

/* SOF ABI version number. Format within 32bit word is MMmmmppp */
+6 −0
Original line number Diff line number Diff line
@@ -57,6 +57,12 @@
#define SOF_TKN_SRC_RATE_IN			300
#define SOF_TKN_SRC_RATE_OUT			301

/* ASRC */
#define SOF_TKN_ASRC_RATE_IN			320
#define SOF_TKN_ASRC_RATE_OUT			321
#define SOF_TKN_ASRC_ASYNCHRONOUS_MODE		322
#define SOF_TKN_ASRC_OPERATION_MODE		323

/* PCM */
#define SOF_TKN_PCM_DMAC_CONFIG			353

+78 −0
Original line number Diff line number Diff line
@@ -573,6 +573,20 @@ static const struct sof_topology_token src_tokens[] = {
		offsetof(struct sof_ipc_comp_src, sink_rate), 0},
};

/* ASRC */
static const struct sof_topology_token asrc_tokens[] = {
	{SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
		offsetof(struct sof_ipc_comp_asrc, source_rate), 0},
	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
		offsetof(struct sof_ipc_comp_asrc, sink_rate), 0},
	{SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
		get_token_u32,
		offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0},
	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
		get_token_u32,
		offsetof(struct sof_ipc_comp_asrc, operation_mode), 0},
};

/* Tone */
static const struct sof_topology_token tone_tokens[] = {
};
@@ -1782,6 +1796,67 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
	return ret;
}

/*
 * ASRC Topology
 */

static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index,
				struct snd_sof_widget *swidget,
				struct snd_soc_tplg_dapm_widget *tw,
				struct sof_ipc_comp_reply *r)
{
	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
	struct snd_soc_tplg_private *private = &tw->priv;
	struct sof_ipc_comp_asrc *asrc;
	int ret;

	asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
	if (!asrc)
		return -ENOMEM;

	/* configure ASRC IPC message */
	asrc->comp.hdr.size = sizeof(*asrc);
	asrc->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
	asrc->comp.id = swidget->comp_id;
	asrc->comp.type = SOF_COMP_ASRC;
	asrc->comp.pipeline_id = index;
	asrc->config.hdr.size = sizeof(asrc->config);

	ret = sof_parse_tokens(scomp, asrc, asrc_tokens,
			       ARRAY_SIZE(asrc_tokens), private->array,
			       le32_to_cpu(private->size));
	if (ret != 0) {
		dev_err(scomp->dev, "error: parse asrc tokens failed %d\n",
			private->size);
		goto err;
	}

	ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens,
			       ARRAY_SIZE(comp_tokens), private->array,
			       le32_to_cpu(private->size));
	if (ret != 0) {
		dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n",
			le32_to_cpu(private->size));
		goto err;
	}

	dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d "
		"asynch %d operation %d\n",
		swidget->widget->name, asrc->source_rate, asrc->sink_rate,
		asrc->asynchronous_mode, asrc->operation_mode);
	sof_dbg_comp_config(scomp, &asrc->config);

	swidget->private = asrc;

	ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc,
				 sizeof(*asrc), r, sizeof(*r));
	if (ret >= 0)
		return ret;
err:
	kfree(asrc);
	return ret;
}

/*
 * Signal Generator Topology
 */
@@ -2195,6 +2270,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
	case snd_soc_dapm_src:
		ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
		break;
	case snd_soc_dapm_asrc:
		ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply);
		break;
	case snd_soc_dapm_siggen:
		ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
		break;