From patchwork Mon Mar 14 20:05:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780755 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 979A3C433FE for ; Mon, 14 Mar 2022 20:07:42 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id BD2101741; Mon, 14 Mar 2022 21:06:50 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz BD2101741 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288460; bh=KyGFR7GQKbIjELhAeh95O3NZ/wi/fjlySV1ylTb+DGc=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=fl9ZEo8Myc5jUIuvwjVABy5RzXITZZLW5dRS2V7wVKf5W3wRCJ4ZrPcNR8WEkB0Fh 8qjI8z4MOB2kTy3sBPZJ3rysqBTMLqJk9lqoYgwMd8wv+qL9lzEmXQTetFZ1iw6b9h M6RZ0T2Z0kNjGvDt75BhVTczxRx9H9rdH5ZrtzYU= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id E23A9F80524; Mon, 14 Mar 2022 21:05:47 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id B2845F80510; Mon, 14 Mar 2022 21:05:44 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E1028F8011C for ; Mon, 14 Mar 2022 21:05:35 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E1028F8011C Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="BbHWsfzs" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288339; x=1678824339; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=KyGFR7GQKbIjELhAeh95O3NZ/wi/fjlySV1ylTb+DGc=; b=BbHWsfzsImGjSVandBtKo7d9xAHBjqDqa0E1uJ3dshr66F+EbYVSe6ky Nb0oT9oZfHDZDN511bjwve3oA+adSbIWNRq9Dksa2kNot6s5piFA71jgA UM72Bp2DV/6EoM3hTt2yknEWkkj6QwRhzj1Mg1ZgVryjcOs9a41hu/yUS ZGT2gvgZP/ZBO6mxGiwG+u8H3KyoSxiUMRpzdH2CVKRwlGYx+wr/hIT13 mq5R63QNgcSib8nbK4nFyxq0t0OCXNm7qk/qo13bgRgc8PFoI3QqjegoW ex3WcedDgHqG2K/Vh+WIbqr9o6Fh/UQxJiNKlb/rYuzgzXyhSkRmUBJgA w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563466" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563466" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339883" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 01/18] ASoC: SOF: Introduce struct snd_sof_dai_link Date: Mon, 14 Mar 2022 13:05:02 -0700 Message-Id: <20220314200520.1233427-2-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Introduce a new struct for DAI links to save the DAI link information parsed from topology. Also add a list of dai_links to struct snd_sof_dev that will be populated during topology parsing. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 1 + sound/soc/sof/sof-audio.h | 21 ++++++++++++++++++++- sound/soc/sof/sof-priv.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 9217644e2eab..e91631618bff 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -370,6 +370,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->dai_list); + INIT_LIST_HEAD(&sdev->dai_link_list); INIT_LIST_HEAD(&sdev->route_list); INIT_LIST_HEAD(&sdev->ipc_client_list); INIT_LIST_HEAD(&sdev->ipc_rx_handler_list); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 450ee9977c55..548d443e83b0 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -96,7 +96,26 @@ struct snd_sof_control { bool comp_data_dirty; }; -struct snd_sof_widget; +/** struct snd_sof_dai_link - DAI link info + * @tuples: array of parsed tuples + * @num_tuples: number of tuples in the tuples array + * @link: Pointer to snd_soc_dai_link + * @hw_configs: Pointer to hw configs in topology + * @num_hw_configs: Number of hw configs in topology + * @default_hw_cfg_id: Default hw config ID + * @type: DAI type + * @list: item in snd_sof_dev dai_link list + */ +struct snd_sof_dai_link { + struct snd_sof_tuple *tuples; + int num_tuples; + struct snd_soc_dai_link *link; + struct snd_soc_tplg_hw_config *hw_configs; + int num_hw_configs; + int default_hw_cfg_id; + int type; + struct list_head list; +}; /* ASoC SOF DAPM widget */ struct snd_sof_widget { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ef5a2adae5c7..28d3f1ac8be8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -441,6 +441,7 @@ struct snd_sof_dev { struct list_head kcontrol_list; struct list_head widget_list; struct list_head dai_list; + struct list_head dai_link_list; struct list_head route_list; struct snd_soc_component *component; u32 enabled_cores_mask; /* keep track of enabled cores */ From patchwork Mon Mar 14 20:05:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780754 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 55880C433F5 for ; Mon, 14 Mar 2022 20:07:26 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 5B39A176B; Mon, 14 Mar 2022 21:06:34 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 5B39A176B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288444; bh=VVVYSwdmNeQo6PpJMzYLgQ0vNK678XGoWOAeE8mXLxg=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=HO5a6WNinHsrBAix1ZUQ+q/yKkUtiidRZ1vb023qClLmnDhnvWuLD299ljh+WeAC2 vVehblnVPdp2JonjbahmtrOtBBG88J9Sufd1EGrbPsuQKoaaESOu0twDLkoRDtTUGV +QcyvPPPB4jJBfNvZ2re4GvMerjmuM/i8GK+ywhY= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id F1D67F8051A; Mon, 14 Mar 2022 21:05:46 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id F3885F80517; Mon, 14 Mar 2022 21:05:43 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 83CA5F801EC for ; Mon, 14 Mar 2022 21:05:40 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 83CA5F801EC Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Ab5JYuqE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288341; x=1678824341; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VVVYSwdmNeQo6PpJMzYLgQ0vNK678XGoWOAeE8mXLxg=; b=Ab5JYuqEES3CecC5IZ2gmMQA98NFdg8gzTR7/oEiDAvMfJXfL1ZPYRXU VJEMc80dszFYCS1a+pgoHslJNNEhZhTdAxJOZQ33H/nO5WFODDNsPB84g j5QcI8mR/JmjXV7Afetq3ek3OLsPdVrH3M+j+KlryXaNsKWQ1lA1XEYdM 265iW5DUcXIUz1Y/IdA8nR3M9Mk7PnxI1h6a9YMnpU3U5xOYXo/cKh5BW Plawzvi3KZDkNahAZdb4sdmBv3gGXxiqJIIll8aeB/hZ7HCubgIntOgpQ t3ADC4FN1caEApjrYlmfAmLB416va/BdT/xrRUSFuhu8MovarhCYjx8qG Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563468" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563468" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339886" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 02/18] ASoC: SOF: IPC: Introduce IPC ops Date: Mon, 14 Mar 2022 13:05:04 -0700 Message-Id: <20220314200520.1233427-4-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" In preparation for supporting a new IPC version that will be introduced in the SOF firmware, add a new set of ops that will be version specific. For now, the IPC ops contain only the topology-related ops for setting up widgets and pipeline connections. It will be expanded later to also abstract the IPC-specific items in the component driver and DAI driver. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/sof-audio.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 13 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 548d443e83b0..79041622987f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -30,6 +30,42 @@ #define WIDGET_IS_DAI(id) ((id) == snd_soc_dapm_dai_in || (id) == snd_soc_dapm_dai_out) +struct snd_sof_widget; +struct snd_sof_route; + +/** + * struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets + * @ipc_setup: Function pointer for setting up widget IPC params + * @ipc_free: Function pointer for freeing widget IPC params + * @token_list: List of token ID's that should be parsed for the widget + * @token_list_size: number of elements in token_list + * @bind_event: Function pointer for binding events to the widget + */ +struct sof_ipc_tplg_widget_ops { + int (*ipc_setup)(struct snd_sof_widget *swidget); + void (*ipc_free)(struct snd_sof_widget *swidget); + enum sof_tokens *token_list; + int token_list_size; + int (*bind_event)(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, + u16 event_type); +}; + +/** + * struct sof_ipc_tplg_ops - IPC-specific topology ops + * @widget: Array of pointers to IPC-specific ops for widgets. This should always be of size + * SND_SOF_DAPM_TYPE_COUNT i.e one per widget type. Unsupported widget types will be + * initialized to 0. + * @route_setup: Function pointer for setting up pipeline connections + * @token_list: List of all tokens supported by the IPC version. The size of the token_list + * array should be SOF_TOKEN_COUNT. The unused elements in the array will be + * initialized to 0. + */ +struct sof_ipc_tplg_ops { + const struct sof_ipc_tplg_widget_ops *widget; + int (*route_setup)(struct snd_sof_dev *sdev, struct snd_sof_route *sroute); + const struct sof_token_info *token_list; +}; + /** struct snd_sof_tuple - Tuple info * @token: Token ID * @value: union of a string or a u32 values diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 28d3f1ac8be8..0dab5b70406e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -360,6 +360,16 @@ struct snd_sof_ipc_msg { bool ipc_complete; }; +struct sof_ipc_tplg_ops; + +/** + * struct sof_ipc_ops - IPC-specific ops + * @tplg: Pointer to IPC-specific topology ops + */ +struct sof_ipc_ops { + const struct sof_ipc_tplg_ops *tplg; +}; + /* SOF generic IPC data */ struct snd_sof_ipc { struct snd_sof_dev *sdev; @@ -370,6 +380,9 @@ struct snd_sof_ipc { bool disable_ipc_tx; struct snd_sof_ipc_msg msg; + + /* IPC ops based on version */ + const struct sof_ipc_ops *ops; }; /* From patchwork Mon Mar 14 20:05:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780756 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9EA76C433F5 for ; Mon, 14 Mar 2022 20:08:00 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id ACA7D17CF; Mon, 14 Mar 2022 21:07:08 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz ACA7D17CF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288478; bh=u3bwTvbNX9x0xvyI0+4ZlXRcVsxh2WQH7lYr92L3+U4=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=RptKktWufp5SbYNNEw+Z5Z4BvF2726DNVYbtdNZts6uuhnkdfd0y+kU6Py1cMkK+k zVN5F+kdGTj1Md+n6rI2POHzWFcaJlKiz9rhPiB1x7IHrQe/WqbeJgMeEgNm1c1C6f yqZ55SuF1ECyZ/vIJEkbrvCxSuv5enEao9LfCsdE= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id EA9A6F8052E; Mon, 14 Mar 2022 21:05:51 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 83C67F8052D; Mon, 14 Mar 2022 21:05:49 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1D709F80475 for ; Mon, 14 Mar 2022 21:05:41 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1D709F80475 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Dz0+ujyu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288343; x=1678824343; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=u3bwTvbNX9x0xvyI0+4ZlXRcVsxh2WQH7lYr92L3+U4=; b=Dz0+ujyuEl741WLkFDGqeQKfMkgEiLk4BoXCpufBnPqFFkqHMhfl5rGZ lwJI80AckV24gwjBpk322S/B4cGB0DWWlTEsC3RA7vO/dFzmeUQp/b5Bs HLr0dAI9RxT/lsHyedECFBAX+lB9J4yw37iOQ99oclOmHSJM25eGVQ0bI MWN0gw6D10doQCSJCc9rs0wQBbp8dABzamsLkOjewZdp1RsBAx+LPa//b PQk6kFfM1M9/KTCy3WeLRyWlnCLo52SqBY2gYw9gCO7giUnFSyv8E/8kq hStaO0LgDLap6Pbfek2cLHTzwXjq/XxlkbMs8+ItTLNzuc+tSwyoK9DJy w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563470" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563470" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339888" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 03/18] ASoC: SOF: topology: Add helper function for processing tuple arrays Date: Mon, 14 Mar 2022 13:05:05 -0700 Message-Id: <20220314200520.1233427-5-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add a helper function for processing tuple arrays and populating the IPC structure objects based on the token ID passed. Introduce a new enum representing token ID for the tokens currently used in the topology parse and a new struct sof_token_info to store the information about a token set. Finally, expose the struct snd_sof_topology token as it will be used by IPC-specific code. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/sof-audio.h | 54 +++++++++++++++++++ sound/soc/sof/topology.c | 106 +++++++++++++++++++++++++++++++++----- 2 files changed, 148 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 79041622987f..bde86e078e08 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -78,6 +78,57 @@ struct snd_sof_tuple { } value; }; +/* + * List of SOF token ID's. The order of ID's does not matter as token arrays are looked up based on + * the ID. + */ +enum sof_tokens { + SOF_PCM_TOKENS, + SOF_PIPELINE_TOKENS, + SOF_SCHED_TOKENS, + SOF_ASRC_TOKENS, + SOF_SRC_TOKENS, + SOF_COMP_TOKENS, + SOF_BUFFER_TOKENS, + SOF_VOLUME_TOKENS, + SOF_PROCESS_TOKENS, + SOF_DAI_TOKENS, + SOF_DAI_LINK_TOKENS, + SOF_HDA_TOKENS, + SOF_SSP_TOKENS, + SOF_ALH_TOKENS, + SOF_DMIC_TOKENS, + SOF_DMIC_PDM_TOKENS, + SOF_ESAI_TOKENS, + SOF_SAI_TOKENS, + SOF_AFE_TOKENS, + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + + /* this should be the last */ + SOF_TOKEN_COUNT, +}; + +/** + * struct sof_topology_token - SOF topology token definition + * @token: Token number + * @type: Token type + * @get_token: Function pointer to parse the token value and save it in a object + * @offset: Offset within an object to save the token value into + */ +struct sof_topology_token { + u32 token; + u32 type; + int (*get_token)(void *elem, void *object, u32 offset); + u32 offset; +}; + +struct sof_token_info { + const char *name; + const struct sof_topology_token *tokens; + int count; +}; + /* PCM stream, mapped to FW component */ struct snd_sof_pcm_stream { u32 comp_id; @@ -333,4 +384,7 @@ int get_token_u16(void *elem, void *object, u32 offset); int get_token_comp_format(void *elem, void *object, u32 offset); int get_token_dai_type(void *elem, void *object, u32 offset); int get_token_uuid(void *elem, void *object, u32 offset); +int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id, + struct snd_sof_tuple *tuples, int num_tuples, + size_t object_size, int token_instance_num); #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index afd9eda67631..a127d3d2eab7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -47,6 +47,100 @@ /* size of tplg abi in byte */ #define SOF_TPLG_ABI_SIZE 3 +/** + * sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the + * token ID. + * @scomp: pointer to SOC component + * @object: target IPC struct to save the parsed values + * @token_id: token ID for the token array to be searched + * @tuples: pointer to the tuples array + * @num_tuples: number of tuples in the tuples array + * @object_size: size of the object + * @token_instance_num: number of times the same @token_id needs to be parsed i.e. the function + * looks for @token_instance_num of each token in the token array associated + * with the @token_id + */ +int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id, + struct snd_sof_tuple *tuples, int num_tuples, + size_t object_size, int token_instance_num) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_topology_token *tokens; + int i, j; + + if (token_list[token_id].count < 0) { + dev_err(scomp->dev, "Invalid token count for token ID: %d\n", token_id); + return -EINVAL; + } + + /* No tokens to match */ + if (!token_list[token_id].count) + return 0; + + tokens = token_list[token_id].tokens; + if (!tokens) { + dev_err(scomp->dev, "Invalid tokens for token id: %d\n", token_id); + return -EINVAL; + } + + for (i = 0; i < token_list[token_id].count; i++) { + int offset = 0; + int num_tokens_matched = 0; + + for (j = 0; j < num_tuples; j++) { + if (tokens[i].token == tuples[j].token) { + switch (tokens[i].type) { + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + { + u32 *val = (u32 *)((u8 *)object + tokens[i].offset + + offset); + + *val = tuples[j].value.v; + break; + } + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + { + u16 *val = (u16 *)((u8 *)object + tokens[i].offset + + offset); + + *val = (u16)tuples[j].value.v; + break; + } + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + { + if (!tokens[i].get_token) { + dev_err(scomp->dev, + "get_token not defined for token %d in %s\n", + tokens[i].token, token_list[token_id].name); + return -EINVAL; + } + + tokens[i].get_token((void *)tuples[j].value.s, object, + tokens[i].offset + offset); + break; + } + default: + break; + } + + num_tokens_matched++; + + /* found all required sets of current token. Move to the next one */ + if (!(num_tokens_matched % token_instance_num)) + break; + + /* move to the next object */ + offset += object_size; + } + } + } + + return 0; +} + struct sof_widget_data { int ctrl_type; int ipc_cmd; @@ -465,18 +559,6 @@ static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) return SOF_COMP_NONE; } -/* - * Topology Token Parsing. - * New tokens should be added to headers and parsing tables below. - */ - -struct sof_topology_token { - u32 token; - u32 type; - int (*get_token)(void *elem, void *object, u32 offset); - u32 offset; -}; - int get_token_u32(void *elem, void *object, u32 offset) { struct snd_soc_tplg_vendor_value_elem *velem = elem; From patchwork Mon Mar 14 20:05:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780757 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E6276C433F5 for ; Mon, 14 Mar 2022 20:08:16 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 26EEC1777; Mon, 14 Mar 2022 21:07:25 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 26EEC1777 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288495; bh=0+UbyEz6sOba64pK9D/b4PlCXAPs658/a5uoSbGe63Q=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=ZdP66PDRrouyQSu4uyiBCqk7bnWU4qS0RyDLYgA43eSkIQo7xQIcd9atRMW6ZUGa/ i/9cvTEwHVS+uihZijaBqcP00BwIRBAugrTihc5KFF+LG5LfBUz/0ivk24brO3aOYT G7TVGxtkNAawRLW2vMzMkM1eg+CPcCXYLsJoAHJI= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 70B3DF80534; Mon, 14 Mar 2022 21:05:54 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id C9B8BF8052E; Mon, 14 Mar 2022 21:05:49 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id DCB55F80139 for ; Mon, 14 Mar 2022 21:05:41 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz DCB55F80139 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="L1f35ijq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288343; x=1678824343; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0+UbyEz6sOba64pK9D/b4PlCXAPs658/a5uoSbGe63Q=; b=L1f35ijq3gWkKLJjCs6IbfziucLFAgUmE+oSyH8A6oH4W7cB0fU9UA69 txZ3ixXOimPOkHuD42kK7//p7GNwZjQOuH9YKRM6f6Nij174WcYwDZ1Ow mhuMYZFW4V0Sib1bbvfMczTguTa4X0MCZdwo07kV2OboBx5VgMe7hcozw 43AfsBNWoGIifaJr+VxWTygsLK4CZKDZMtOPZCqsv2/LhZ16niB7GRtks YI5UFF6eDs4wak/IyYMdE/j2AYX+O5TmXaZ6jjwd1Q0fhYO3TqOQV7hM8 Qs7VFtBFdx2BALYhfH/bQ9GM+FAaVrzNyj2XCei6bazHpFBdBbVORLvLm A==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563471" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563471" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339889" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 04/18] ASoC: SOF: Introduce IPC3 ops Date: Mon, 14 Mar 2022 13:05:06 -0700 Message-Id: <20220314200520.1233427-6-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add the IPC ops including the topology-related IPC ops for the current version (IPC3, named after the current SOF firmware ABI major version 3.0) of IPC supported by the SOF firmware and set it as default. The topology IPC ops and the widget ops within the topology IPC ops are both mandatory. With the introduction of IPC3 ops, we define the list of tokens pertaining to the AIF_IN/AIF_OUT widgets. Then these tokens are parsed during topology parsing and saved as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the host component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/Makefile | 3 +- sound/soc/sof/ipc.c | 12 ++ sound/soc/sof/ipc3-topology.c | 173 +++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 + sound/soc/sof/topology.c | 258 +++++++++++++++++++++++++++------- 5 files changed, 397 insertions(+), 51 deletions(-) create mode 100644 sound/soc/sof/ipc3-topology.c diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index a0459f06c68a..e13dab59764c 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o + control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\ + ipc3-topology.o ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) snd-sof-objs += sof-client.o endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 34084e0008f1..cf892859355a 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -1023,6 +1023,18 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) init_waitqueue_head(&msg->waitq); + /* + * Use IPC3 ops as it is the only available version now. With the addition of new IPC + * versions, this will need to be modified to use the selected version at runtime. + */ + ipc->ops = &ipc3_ops; + + /* check for mandatory ops */ + if (!ipc->ops->tplg || !ipc->ops->tplg->widget) { + dev_err(sdev->dev, "Invalid topology IPC ops\n"); + return NULL; + } + return ipc; } EXPORT_SYMBOL(snd_sof_ipc_init); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c new file mode 100644 index 000000000000..33d07b0df640 --- /dev/null +++ b/sound/soc/sof/ipc3-topology.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Intel Corporation. All rights reserved. +// +// + +#include +#include +#include "sof-priv.h" +#include "sof-audio.h" +#include "ops.h" + +/* PCM */ +static const struct sof_topology_token pcm_tokens[] = { + {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_host, dmac_config)}, +}; + +/* Generic components */ +static const struct sof_topology_token comp_tokens[] = { + {SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_sink)}, + {SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_source)}, + {SOF_TKN_COMP_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_comp_config, frame_fmt)}, +}; + +/* Core tokens */ +static const struct sof_topology_token core_tokens[] = { + {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp, core)}, +}; + +/* Component extended tokens */ +static const struct sof_topology_token comp_ext_tokens[] = { + {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, + offsetof(struct snd_sof_widget, uuid)}, +}; + +static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { + [SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)}, + [SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)}, + [SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)}, + [SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)}, +}; + +/** + * sof_comp_alloc - allocate and initialize buffer for a new component + * @swidget: pointer to struct snd_sof_widget containing extended data + * @ipc_size: IPC payload size that will be updated depending on valid + * extended data. + * @index: ID of the pipeline the component belongs to + * + * Return: The pointer to the new allocated component, NULL if failed. + */ +static void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size, + int index) +{ + struct sof_ipc_comp *comp; + size_t total_size = *ipc_size; + size_t ext_size = sizeof(swidget->uuid); + + /* only non-zero UUID is valid */ + if (!guid_is_null(&swidget->uuid)) + total_size += ext_size; + + comp = kzalloc(total_size, GFP_KERNEL); + if (!comp) + return NULL; + + /* configure comp new IPC message */ + comp->hdr.size = total_size; + comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + comp->id = swidget->comp_id; + comp->pipeline_id = index; + comp->core = swidget->core; + + /* handle the extended data if needed */ + if (total_size > *ipc_size) { + /* append extended data to the end of the component */ + memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size); + comp->ext_data_length = ext_size; + } + + /* update ipc_size and return */ + *ipc_size = total_size; + return comp; +} + +static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config) +{ + dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n", + config->periods_sink, config->periods_source, + config->frame_fmt); +} + +static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_host *host; + size_t ipc_size = sizeof(*host); + int ret; + + host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!host) + return -ENOMEM; + swidget->private = host; + + /* configure host comp IPC message */ + host->comp.type = SOF_COMP_HOST; + host->config.hdr.size = sizeof(host->config); + + if (swidget->id == snd_soc_dapm_aif_out) + host->direction = SOF_IPC_STREAM_CAPTURE; + else + host->direction = SOF_IPC_STREAM_PLAYBACK; + + /* parse one set of pcm_tokens */ + ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*host), 1); + if (ret < 0) + goto err; + + /* parse one set of comp_tokens */ + ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(host->config), 1); + if (ret < 0) + goto err; + + dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &host->config); + + return 0; +err: + kfree(swidget->private); + swidget->private = NULL; + + return ret; +} + +static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget) +{ + kfree(swidget->private); +} + +/* token list for each topology object */ +static enum sof_tokens host_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_PCM_TOKENS, + SOF_COMP_TOKENS, +}; + +static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { + [snd_soc_dapm_aif_in] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, + host_token_list, ARRAY_SIZE(host_token_list), NULL}, + [snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, + host_token_list, ARRAY_SIZE(host_token_list), NULL}, +}; + +static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { + .widget = tplg_ipc3_widget_ops, + .token_list = ipc3_token_list, +}; + +const struct sof_ipc_ops ipc3_ops = { + .tplg = &ipc3_tplg_ops, +}; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0dab5b70406e..0b89c3e6ef21 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -370,6 +370,8 @@ struct sof_ipc_ops { const struct sof_ipc_tplg_ops *tplg; }; +extern const struct sof_ipc_ops ipc3_ops; + /* SOF generic IPC data */ struct snd_sof_ipc { struct snd_sof_dev *sdev; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a127d3d2eab7..2258317d7f57 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -701,12 +701,6 @@ static const struct sof_topology_token process_tokens[] = { offsetof(struct sof_ipc_comp_process, type)}, }; -/* PCM */ -static const struct sof_topology_token pcm_tokens[] = { - {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_host, dmac_config)}, -}; - /* PCM */ static const struct sof_topology_token stream_tokens[] = { {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, @@ -934,6 +928,123 @@ static int sof_parse_uuid_tokens(struct snd_soc_component *scomp, return found; } +/** + * sof_copy_tuples - Parse tokens and copy them to the @tuples array + * @sdev: pointer to struct snd_sof_dev + * @array: source pointer to consecutive vendor arrays in topology + * @array_size: size of @array + * @token_id: Token ID associated with a token array + * @token_instance_num: number of times the same @token_id needs to be parsed i.e. the function + * looks for @token_instance_num of each token in the token array associated + * with the @token_id + * @tuples: tuples array to copy the matched tuples to + * @tuples_size: size of @tuples + * @num_copied_tuples: pointer to the number of copied tuples in the tuples array + * + */ +static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_array *array, + int array_size, u32 token_id, int token_instance_num, + struct snd_sof_tuple *tuples, int tuples_size, int *num_copied_tuples) +{ + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_topology_token *tokens; + int found = 0; + int num_tokens, asize; + int i, j; + + /* nothing to do if token_list is NULL */ + if (!token_list) + return 0; + + if (!tuples || !num_copied_tuples) { + dev_err(sdev->dev, "Invalid tuples array\n"); + return -EINVAL; + } + + tokens = token_list[token_id].tokens; + num_tokens = token_list[token_id].count; + + if (!tokens) { + dev_err(sdev->dev, "No token array defined for token ID: %d\n", token_id); + return -EINVAL; + } + + /* check if there's space in the tuples array for new tokens */ + if (*num_copied_tuples >= tuples_size) { + dev_err(sdev->dev, "No space in tuples array for new tokens from %s", + token_list[token_id].name); + return -EINVAL; + } + + while (array_size > 0 && found < num_tokens * token_instance_num) { + asize = le32_to_cpu(array->size); + + /* validate asize */ + if (asize < 0) { + dev_err(sdev->dev, "Invalid array size 0x%x\n", asize); + return -EINVAL; + } + + /* make sure there is enough data before parsing */ + array_size -= asize; + if (array_size < 0) { + dev_err(sdev->dev, "Invalid array size 0x%x\n", asize); + return -EINVAL; + } + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + /* search for token */ + for (j = 0; j < num_tokens; j++) { + /* match token type */ + if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_STRING)) + continue; + + if (tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_STRING) { + struct snd_soc_tplg_vendor_string_elem *elem; + + elem = &array->string[i]; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + tuples[*num_copied_tuples].token = tokens[j].token; + tuples[*num_copied_tuples].value.s = elem->string; + } else { + struct snd_soc_tplg_vendor_value_elem *elem; + + elem = &array->value[i]; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + tuples[*num_copied_tuples].token = tokens[j].token; + tuples[*num_copied_tuples].value.v = + le32_to_cpu(elem->value); + } + found++; + (*num_copied_tuples)++; + + /* stop if there's no space for any more new tuples */ + if (*num_copied_tuples == tuples_size) + return 0; + } + } + + /* next array */ + array = (struct snd_soc_tplg_vendor_array *)((u8 *)array + asize); + } + + return 0; +} + /** * sof_parse_string_tokens - Parse multiple sets of tokens * @scomp: pointer to soc component @@ -1693,56 +1804,72 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, return 0; } -/* - * PCM Topology - */ - -static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - enum sof_ipc_stream_direction dir, - struct snd_soc_tplg_dapm_widget *tw) +static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + enum sof_tokens *object_token_list, int count) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_token_info *token_list = ipc_tplg_ops->token_list; struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_host *host; - size_t ipc_size = sizeof(*host); - int ret; + int num_tuples = 0; + size_t size; + int ret, i; - host = (struct sof_ipc_comp_host *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!host) - return -ENOMEM; + if (count > 0 && !object_token_list) { + dev_err(scomp->dev, "No token list for widget %s\n", swidget->widget->name); + return -EINVAL; + } - /* configure host comp IPC message */ - host->comp.type = SOF_COMP_HOST; - host->direction = dir; - host->config.hdr.size = sizeof(host->config); + /* calculate max size of tuples array */ + for (i = 0; i < count; i++) + num_tuples += token_list[object_token_list[i]].count; - ret = sof_parse_tokens(scomp, host, pcm_tokens, - ARRAY_SIZE(pcm_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse host tokens failed %d\n", - private->size); - goto err; - } + /* allocate memory for tuples array */ + size = sizeof(struct snd_sof_tuple) * num_tuples; + swidget->tuples = kzalloc(size, GFP_KERNEL); + if (!swidget->tuples) + return -ENOMEM; - ret = sof_parse_tokens(scomp, &host->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse host.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } + /* parse token list for widget */ + for (i = 0; i < count; i++) { + if (object_token_list[i] >= SOF_TOKEN_COUNT) { + dev_err(scomp->dev, "Invalid token id %d for widget %s\n", + object_token_list[i], swidget->widget->name); + ret = -EINVAL; + goto err; + } - dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name); - sof_dbg_comp_config(scomp, &host->config); + /* parse and save UUID in swidget */ + if (object_token_list[i] == SOF_COMP_EXT_TOKENS) { + ret = sof_parse_tokens(scomp, swidget, + token_list[object_token_list[i]].tokens, + token_list[object_token_list[i]].count, + private->array, le32_to_cpu(private->size)); + if (ret < 0) { + dev_err(scomp->dev, "Failed parsing %s for widget %s\n", + token_list[object_token_list[i]].name, + swidget->widget->name); + goto err; + } - swidget->private = host; + continue; + } + + /* copy one set of tuples per token ID into swidget->tuples */ + ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + object_token_list[i], 1, swidget->tuples, + num_tuples, &swidget->num_tuples); + if (ret < 0) { + dev_err(scomp->dev, "Failed parsing %s for widget %s err: %d\n", + token_list[object_token_list[i]].name, swidget->widget->name, ret); + goto err; + } + } return 0; err: - kfree(host); + kfree(swidget->tuples); return ret; } @@ -2367,8 +2494,12 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_dapm_widget *tw) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; struct snd_sof_widget *swidget; struct snd_sof_dai *dai; + enum sof_tokens *token_list; + int token_list_size; struct sof_ipc_comp comp = { .core = SOF_DSP_PRIMARY_CORE, }; @@ -2391,6 +2522,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? tw->sname : "none"); + token_list = widget_ops[w->id].token_list; + token_list_size = widget_ops[w->id].token_list_size; + ret = sof_parse_tokens(scomp, &comp, core_tokens, ARRAY_SIZE(core_tokens), tw->priv.array, le32_to_cpu(tw->priv.size)); @@ -2448,12 +2582,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ret = sof_widget_load_pipeline(scomp, index, swidget, tw); break; case snd_soc_dapm_aif_out: - ret = sof_widget_load_pcm(scomp, index, swidget, - SOF_IPC_STREAM_CAPTURE, tw); - break; case snd_soc_dapm_aif_in: - ret = sof_widget_load_pcm(scomp, index, swidget, - SOF_IPC_STREAM_PLAYBACK, tw); + ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; case snd_soc_dapm_src: ret = sof_widget_load_src(scomp, index, swidget, tw); @@ -2497,6 +2627,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (ret) { dev_err(scomp->dev, "error: widget event binding failed\n"); kfree(swidget->private); + kfree(swidget->tuples); kfree(swidget); return ret; } @@ -2527,6 +2658,9 @@ static int sof_route_unload(struct snd_soc_component *scomp, static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; const struct snd_kcontrol_new *kc; struct snd_soc_dapm_widget *widget; struct snd_sof_control *scontrol; @@ -2588,9 +2722,15 @@ static int sof_widget_unload(struct snd_soc_component *scomp, } out: + /* free IPC related data */ + if (widget_ops[swidget->id].ipc_free) + widget_ops[swidget->id].ipc_free(swidget); + /* free private value */ kfree(swidget->private); + kfree(swidget->tuples); + /* remove and free swidget object */ list_del(&swidget->list); kfree(swidget); @@ -3597,8 +3737,26 @@ static int sof_complete(struct snd_soc_component *scomp) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_sof_widget *swidget, *comp_swidget; + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; int ret; + /* + * now update all widget IPC structures. If any of the ipc_setup callbacks fail, the + * topology will be removed and all widgets will be unloaded resulting in freeing all + * associated memories. + */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (widget_ops[swidget->id].ipc_setup) { + ret = widget_ops[swidget->id].ipc_setup(swidget); + if (ret < 0) { + dev_err(sdev->dev, "failed updating IPC struct for %s\n", + swidget->widget->name); + return ret; + } + } + } + /* set the pipe_widget and apply the dynamic_pipeline_widget_flag */ list_for_each_entry(swidget, &sdev->widget_list, list) { switch (swidget->id) { From patchwork Mon Mar 14 20:05:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780758 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 38E5AC433EF for ; Mon, 14 Mar 2022 20:08:33 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 7720F176C; Mon, 14 Mar 2022 21:07:41 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 7720F176C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288511; bh=US4rwkr+I2e0yF2bgNFrnpAGavSAAIg7krwfslCO3ko=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=aYe1RblRc7FNDnWpd5FXfitH11PdZ+6+VBI5p6ccvxjeIXFBfHvNlHe7AuI8pIy2B UPAYl/x+fb/jeszApbNOrooxxoRdEc/OY0xfea+iPaSIX5tB28YxvrwWLciz3MWMrC dCLLsWghEML6PW4gtFd45/Ko4BYkOCFi1BdqQ6bM= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 5C715F80538; Mon, 14 Mar 2022 21:05:55 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id BE8C6F80529; Mon, 14 Mar 2022 21:05:50 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 6F9D6F80516 for ; Mon, 14 Mar 2022 21:05:42 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 6F9D6F80516 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="I520NWmo" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288343; x=1678824343; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=US4rwkr+I2e0yF2bgNFrnpAGavSAAIg7krwfslCO3ko=; b=I520NWmo19198/a3pX9tTWjfnxMaYaqTGsdOPtpndqVxtoMYtMJyScVy ZkmNbjZatWSE9OulO63BKjyQ2N4Gm38R0BKvTbnjLc3KfL8rL6DA1CHy/ UVy2RrzxfvEDY0CN9n4Zk0qzIXbAxrzdwzi8CqNMFWAkloCl7AJbR7863 0eeeBMprbhngSB/duozL3RjJClaOlRoPtZRWEQId8rPOYJ2dSy6uIciZp 9tXfqxvMFGrarjjDhWKaKyGDCsIc4mSQvpymwCu1dbjzN9kTgJAOfKiLm ynmY8E3/TXO3AlHgUiN8uIIdUwQ/lU2x9WIkYnIW2WcDIEWL7lpeGhXLG g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563472" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563472" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339890" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 05/18] ASoC: SOF: topology: Make scheduler widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:07 -0700 Message-Id: <20220314200520.1233427-7-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the scheduler widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the pipeline component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 98 ++++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 99 ----------------------------------- 2 files changed, 98 insertions(+), 99 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 33d07b0df640..15299ffb7b15 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -13,6 +13,28 @@ #include "sof-audio.h" #include "ops.h" +/* scheduling */ +static const struct sof_topology_token sched_tokens[] = { + {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, period)}, + {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, priority)}, + {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, period_mips)}, + {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, core)}, + {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, frames_per_sched)}, + {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, time_domain)}, +}; + +static const struct sof_topology_token pipeline_tokens[] = { + {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, + +}; + /* PCM */ static const struct sof_topology_token pcm_tokens[] = { {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -44,6 +66,8 @@ static const struct sof_topology_token comp_ext_tokens[] = { static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)}, + [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, + [SOF_SCHED_TOKENS] = {"Scheduler tokens", sched_tokens, ARRAY_SIZE(sched_tokens)}, [SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)}, [SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)}, [SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)}, @@ -148,6 +172,71 @@ static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget) kfree(swidget->private); } +static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_widget *comp_swidget; + int ret; + + pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); + if (!pipeline) + return -ENOMEM; + + /* configure pipeline IPC message */ + pipeline->hdr.size = sizeof(*pipeline); + pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW; + pipeline->pipeline_id = swidget->pipeline_id; + pipeline->comp_id = swidget->comp_id; + + swidget->private = pipeline; + + /* component at start of pipeline is our stream id */ + comp_swidget = snd_sof_find_swidget(scomp, swidget->widget->sname); + if (!comp_swidget) { + dev_err(scomp->dev, "scheduler %s refers to non existent widget %s\n", + swidget->widget->name, swidget->widget->sname); + ret = -EINVAL; + goto err; + } + + pipeline->sched_id = comp_swidget->comp_id; + + /* parse one set of scheduler tokens */ + ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*pipeline), 1); + if (ret < 0) + goto err; + + /* parse one set of pipeline tokens */ + ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*swidget), 1); + if (ret < 0) + goto err; + + if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) + pipeline->core = SOF_DSP_PRIMARY_CORE; + + if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE)) + swidget->dynamic_pipeline_widget = + sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE); + + dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n", + swidget->widget->name, pipeline->period, pipeline->priority, + pipeline->period_mips, pipeline->core, pipeline->frames_per_sched, + swidget->dynamic_pipeline_widget); + + swidget->core = pipeline->core; + + return 0; + +err: + kfree(swidget->private); + swidget->private = NULL; + + return ret; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -156,11 +245,20 @@ static enum sof_tokens host_token_list[] = { SOF_COMP_TOKENS, }; +static enum sof_tokens pipeline_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_PIPELINE_TOKENS, + SOF_SCHED_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, [snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, + [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, + pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, }; static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2258317d7f57..4dd4e98e87cf 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -637,28 +637,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* scheduling */ -static const struct sof_topology_token sched_tokens[] = { - {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, period)}, - {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, priority)}, - {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, period_mips)}, - {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, core)}, - {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, frames_per_sched)}, - {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, time_domain)}, -}; - -static const struct sof_topology_token pipeline_tokens[] = { - {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, - offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, - -}; - /* volume */ static const struct sof_topology_token volume_tokens[] = { {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, @@ -1873,81 +1851,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -/* - * Pipeline Topology - */ -static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_pipe_new *pipeline; - struct snd_sof_widget *comp_swidget; - int ret; - - pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); - if (!pipeline) - return -ENOMEM; - - /* configure dai IPC message */ - pipeline->hdr.size = sizeof(*pipeline); - pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW; - pipeline->pipeline_id = index; - pipeline->comp_id = swidget->comp_id; - - /* component at start of pipeline is our stream id */ - comp_swidget = snd_sof_find_swidget(scomp, tw->sname); - if (!comp_swidget) { - dev_err(scomp->dev, "error: widget %s refers to non existent widget %s\n", - tw->name, tw->sname); - ret = -EINVAL; - goto err; - } - - pipeline->sched_id = comp_swidget->comp_id; - - dev_dbg(scomp->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n", - pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id); - - ret = sof_parse_tokens(scomp, pipeline, sched_tokens, - ARRAY_SIZE(sched_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse pipeline tokens failed %d\n", - private->size); - goto err; - } - - ret = sof_parse_tokens(scomp, swidget, pipeline_tokens, - ARRAY_SIZE(pipeline_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse dynamic pipeline token failed %d\n", - private->size); - goto err; - } - - if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) - pipeline->core = SOF_DSP_PRIMARY_CORE; - - if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE)) - swidget->dynamic_pipeline_widget = - sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE); - - dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n", - swidget->widget->name, pipeline->period, pipeline->priority, - pipeline->period_mips, pipeline->core, pipeline->frames_per_sched, - swidget->dynamic_pipeline_widget); - - swidget->core = pipeline->core; - swidget->private = pipeline; - - return 0; -err: - kfree(pipeline); - return ret; -} - /* * Mixer topology */ @@ -2579,8 +2482,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ret = sof_widget_load_buffer(scomp, index, swidget, tw); break; case snd_soc_dapm_scheduler: - ret = sof_widget_load_pipeline(scomp, index, swidget, tw); - break; case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_in: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); From patchwork Mon Mar 14 20:05:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780769 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3C1FAC433F5 for ; Mon, 14 Mar 2022 20:09:25 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 60C8C1856; Mon, 14 Mar 2022 21:08:33 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 60C8C1856 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288563; bh=P+BzivRfqWu4OiXUzHCbevL7Fg+IUHhO4d6QAvee0Zo=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=VdqkNdgTwaVPZq++MMLhJc0qRcW7tB7JGExoin/4l5g1zm7hQXyUP3EuLiaG7C7eb mL+aWgfpjVSxfKTHsWXjegeeUE2syZdKnI71PCTnvyqAh+/S9M1JDhtwwaRlSqsRDS T5V58qz4BtgEqO1DqMyCs9AKXg5WJzgyDkyL3CyA= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id DDBD9F80475; Mon, 14 Mar 2022 21:06:03 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id D6AFCF8053B; Mon, 14 Mar 2022 21:05:55 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 0CB6EF8011C for ; Mon, 14 Mar 2022 21:05:43 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 0CB6EF8011C Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="PDiKwUey" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288345; x=1678824345; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=P+BzivRfqWu4OiXUzHCbevL7Fg+IUHhO4d6QAvee0Zo=; b=PDiKwUey0RYzRMJohWUCxUpvrqzT4PUYYjiOzKwJn+SfgzWLvY9waob2 slE1gseoRnnNE4JcXmMT1d4r5UKR7JjRYlF4alyqM9XMu9D6gv3FGDK83 +wALvuKdZY43c1c3PcGKpvFkCESKg9eMcjq1EnbqN5/WYe9RS441Q47xB AhenyMcqVUROWB47xgrArQ3jXAGRFE8EW8sIhfgK3NRj4sBmRci7/EBP+ I+Il6kVwkTWyCaLUMDzQ0qQ09ShLGoGwHu07UovaYbr6q8KbTq9lc3ZN+ 0VQo1SdRFaua6hkJVNObe8rXOHzZSIs9JCj0vimPfZE3pshZtwl8ft8FD A==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563473" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563473" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339893" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:32 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 06/18] ASoC: SOF: topology: Make buffer widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:08 -0700 Message-Id: <20220314200520.1233427-8-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the buffer widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the buffer component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 50 +++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 52 ----------------------------------- 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 15299ffb7b15..e05d6b816fac 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -13,6 +13,14 @@ #include "sof-audio.h" #include "ops.h" +/* Buffers */ +static const struct sof_topology_token buffer_tokens[] = { + {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, size)}, + {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, caps)}, +}; + /* scheduling */ static const struct sof_topology_token sched_tokens[] = { {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -71,6 +79,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)}, [SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)}, [SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)}, + [SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)}, }; /** @@ -237,6 +246,41 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) return ret; } +static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_buffer *buffer; + int ret; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + swidget->private = buffer; + + /* configure dai IPC message */ + buffer->comp.hdr.size = sizeof(*buffer); + buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW; + buffer->comp.id = swidget->comp_id; + buffer->comp.type = SOF_COMP_BUFFER; + buffer->comp.pipeline_id = swidget->pipeline_id; + buffer->comp.core = swidget->core; + + /* parse one set of buffer tokens */ + ret = sof_update_ipc_object(scomp, buffer, SOF_BUFFER_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*buffer), 1); + if (ret < 0) { + kfree(swidget->private); + swidget->private = NULL; + return ret; + } + + dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n", + swidget->widget->name, buffer->size, buffer->caps); + + return 0; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -245,6 +289,10 @@ static enum sof_tokens host_token_list[] = { SOF_COMP_TOKENS, }; +static enum sof_tokens buffer_token_list[] = { + SOF_BUFFER_TOKENS, +}; + static enum sof_tokens pipeline_token_list[] = { SOF_CORE_TOKENS, SOF_COMP_EXT_TOKENS, @@ -257,6 +305,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY host_token_list, ARRAY_SIZE(host_token_list), NULL}, [snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, + [snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp, + buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 4dd4e98e87cf..88214ec2df5a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -611,14 +611,6 @@ static int get_token_process_type(void *elem, void *object, u32 offset) return 0; } -/* Buffers */ -static const struct sof_topology_token buffer_tokens[] = { - {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_buffer, size)}, - {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_buffer, caps)}, -}; - /* DAI */ static const struct sof_topology_token dai_tokens[] = { {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, @@ -1721,48 +1713,6 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, return ret; } -/* - * Buffer topology - */ - -static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_buffer *buffer; - int ret; - - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - /* configure dai IPC message */ - buffer->comp.hdr.size = sizeof(*buffer); - buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW; - buffer->comp.id = swidget->comp_id; - buffer->comp.type = SOF_COMP_BUFFER; - buffer->comp.pipeline_id = index; - buffer->comp.core = swidget->core; - - ret = sof_parse_tokens(scomp, buffer, buffer_tokens, - ARRAY_SIZE(buffer_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse buffer tokens failed %d\n", - private->size); - kfree(buffer); - return ret; - } - - dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n", - swidget->widget->name, buffer->size, buffer->caps); - - swidget->private = buffer; - - return 0; -} - /* bind PCM ID to host component ID */ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int dir) @@ -2479,8 +2429,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ret = sof_widget_load_pga(scomp, index, swidget, tw); break; case snd_soc_dapm_buffer: - ret = sof_widget_load_buffer(scomp, index, swidget, tw); - break; case snd_soc_dapm_scheduler: case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_in: From patchwork Mon Mar 14 20:05:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780759 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 00297C433EF for ; Mon, 14 Mar 2022 20:08:58 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3DE021845; Mon, 14 Mar 2022 21:08:07 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3DE021845 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288537; bh=MF/NrejJ9f0K+Zj2qwVH2Hg8IO/qPb32lo2W44pYOtE=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=IWgCaHuEnZbnfiHAXaZZehUXdt4WmA9GzuFePM+YlGlZMTh2CNO0a7zdsIYoIQQoa n8x1Mz+z4A7DadwOB4yauwucyVosuCrQGWk+rRPSMJa/nfTaCICJkh1ggQPxpYM6AK duQUxpyQcYqhbnKhqW+s5FSOta3nPqbpnbzofDJs= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 000C3F80528; Mon, 14 Mar 2022 21:06:01 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 61FA7F80533; Mon, 14 Mar 2022 21:05:52 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1097BF8012C for ; Mon, 14 Mar 2022 21:05:43 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1097BF8012C Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="FMUFdEMW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288345; x=1678824345; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MF/NrejJ9f0K+Zj2qwVH2Hg8IO/qPb32lo2W44pYOtE=; b=FMUFdEMWY6UOakuYYxHjw8hLclHIx5ko99f1yw0QFThg+FvO+UGqrH1P YegjbRdtk+RfLsRBOQd3ACUYVEB9W/qRVplcYjktQBi/7EBRQaxYaML6M a4V1l8SyLsX7Kh0vjLd/1d+JLYyXf1cyHjTuhgINMgPMh1Tr3ovgakmkB B+ewcBvs+LPxZCN5Mh41fyM+jg8A0g3xUilGnjvVNP8ZOvFPKT8E9OJ5q AB9hZ6sZY9BkX2wJbBalwR6XZy4PIGCyXK1NxmQoQGZ+LL9LeV9HkJ2qJ ZG+UV3Q3oDp/wy96nU0YiKCjF+1q8q42q2OM3xLA6fyIZ5yQ9Dx86lAu+ g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563474" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563474" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339894" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 07/18] ASoC: SOF: topology: Make pga widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:09 -0700 Message-Id: <20220314200520.1233427-9-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the pga type widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the pga component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 78 ++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 91 +++-------------------------------- 2 files changed, 86 insertions(+), 83 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index e05d6b816fac..517ba84eb4c4 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -43,6 +43,14 @@ static const struct sof_topology_token pipeline_tokens[] = { }; +/* volume */ +static const struct sof_topology_token volume_tokens[] = { + {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_volume, ramp)}, + {SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_volume, initial_ramp)}, +}; + /* PCM */ static const struct sof_topology_token pcm_tokens[] = { {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -80,6 +88,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)}, [SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)}, [SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)}, + [SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)}, }; /** @@ -281,6 +290,66 @@ static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget) return 0; } +/* + * PGA Topology + */ + +static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_comp_volume *volume; + struct snd_sof_control *scontrol; + size_t ipc_size = sizeof(*volume); + int min_step, max_step; + int ret; + + volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!volume) + return -ENOMEM; + + swidget->private = volume; + + /* configure volume IPC message */ + volume->comp.type = SOF_COMP_VOLUME; + volume->config.hdr.size = sizeof(volume->config); + + /* parse one set of volume tokens */ + ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*volume), 1); + if (ret < 0) + goto err; + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, + sizeof(volume->config), 1); + if (ret < 0) + goto err; + + dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &volume->config); + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id && + scontrol->volume_table) { + min_step = scontrol->min_volume_step; + max_step = scontrol->max_volume_step; + volume->min_value = scontrol->volume_table[min_step]; + volume->max_value = scontrol->volume_table[max_step]; + volume->channels = scontrol->num_channels; + break; + } + } + + return 0; +err: + kfree(swidget->private); + swidget->private = NULL; + + return ret; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -300,6 +369,13 @@ static enum sof_tokens pipeline_token_list[] = { SOF_SCHED_TOKENS, }; +static enum sof_tokens pga_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_VOLUME_TOKENS, + SOF_COMP_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, @@ -309,6 +385,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, + [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, + pga_token_list, ARRAY_SIZE(pga_token_list), NULL}, }; static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 88214ec2df5a..bd62658629f5 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -629,15 +629,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* volume */ -static const struct sof_topology_token volume_tokens[] = { - {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp)}, - {SOF_TKN_VOLUME_RAMP_STEP_MS, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_volume, initial_ramp)}, -}; - /* SRC */ static const struct sof_topology_token src_tokens[] = { {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -1878,78 +1869,6 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, return 0; } -/* - * PGA Topology - */ - -static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_volume *volume; - struct snd_sof_control *scontrol; - size_t ipc_size = sizeof(*volume); - int min_step; - int max_step; - int ret; - - volume = (struct sof_ipc_comp_volume *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!volume) - return -ENOMEM; - - if (!le32_to_cpu(tw->num_kcontrols)) { - dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n", - tw->num_kcontrols); - ret = -EINVAL; - goto err; - } - - /* configure volume IPC message */ - volume->comp.type = SOF_COMP_VOLUME; - volume->config.hdr.size = sizeof(volume->config); - - ret = sof_parse_tokens(scomp, volume, volume_tokens, - ARRAY_SIZE(volume_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse volume tokens failed %d\n", - private->size); - goto err; - } - ret = sof_parse_tokens(scomp, &volume->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - sof_dbg_comp_config(scomp, &volume->config); - - swidget->private = volume; - - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - if (scontrol->comp_id == swidget->comp_id && - scontrol->volume_table) { - min_step = scontrol->min_volume_step; - max_step = scontrol->max_volume_step; - volume->min_value = scontrol->volume_table[min_step]; - volume->max_value = scontrol->volume_table[max_step]; - volume->channels = scontrol->num_channels; - break; - } - } - - return 0; -err: - kfree(volume); - return ret; -} - /* * SRC Topology */ @@ -2426,8 +2345,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ret = sof_widget_load_mixer(scomp, index, swidget, tw); break; case snd_soc_dapm_pga: - ret = sof_widget_load_pga(scomp, index, swidget, tw); - break; + if (!le32_to_cpu(tw->num_kcontrols)) { + dev_err(scomp->dev, "invalid kcontrol count %d for volume\n", + tw->num_kcontrols); + ret = -EINVAL; + break; + } + + fallthrough; case snd_soc_dapm_buffer: case snd_soc_dapm_scheduler: case snd_soc_dapm_aif_out: From patchwork Mon Mar 14 20:05:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780760 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 71F2DC433FE for ; Mon, 14 Mar 2022 20:09:08 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A0D791841; Mon, 14 Mar 2022 21:08:16 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A0D791841 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288546; bh=DLVbX390zjtwOfniwOrd6dypSejIyzp13WbbBNKN9Oc=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=UdRn83pS9qmM6v7OKa4iqWpTCMbIHezJn8LPvxa7Bk/uR5yg9lgsUAjf7E4uZRd60 nz/69tz8h2QhXY/iDCXPipbKwMkjwAmcfC3ArQ1vwR3lQ7AP8w5tqNMCXse6K2RdRh 7vZmZXM55Y93sT3K5nGofJdfEQNUT+gcbTuWGaGo= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id B1703F8054A; Mon, 14 Mar 2022 21:06:02 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id DB815F80535; Mon, 14 Mar 2022 21:05:53 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id B3848F801EC for ; Mon, 14 Mar 2022 21:05:44 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz B3848F801EC Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="AaWMVAxu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288346; x=1678824346; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DLVbX390zjtwOfniwOrd6dypSejIyzp13WbbBNKN9Oc=; b=AaWMVAxuzwCAaJfRstxHxozaT0dZrNhXUPIjjSmAc21WLVFBQ9gi03RO XATXu4zr/JAk/mxh1VFgVjTSOKzKpFjZTd/J9TaZwPhhxGwQ0gdF4s3mx TqBAfKtziooFTsRDP/Qe2vu4/cmoHpsLUboU4W7Y9DApavcEEVOR0v/WV kfOXpZkA/kC5MVfV3OeaGTmbzEm2akZqO0uelfR1wrz+3HwKQeNcOh7mU DxSijeGmxfJON4IhhyQGtqxRHkFPP2tutNlWpERWDO6HLHHwBE53Pjayj l66lL9JY7T4yaxGW/OgFIBlisDYLeAlF3H5UErg6SXvhtKzSJ8UGvTYYz g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563475" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563475" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339895" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 08/18] ASoC: SOF: topology: Make mixer widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:10 -0700 Message-Id: <20220314200520.1233427-10-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the mixer widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the mixer component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 43 +++++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 43 +---------------------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 517ba84eb4c4..d8a91f461bf9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -190,6 +190,40 @@ static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget) kfree(swidget->private); } +static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_mixer *mixer; + size_t ipc_size = sizeof(*mixer); + int ret; + + mixer = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!mixer) + return -ENOMEM; + + swidget->private = mixer; + + /* configure mixer IPC message */ + mixer->comp.type = SOF_COMP_MIXER; + mixer->config.hdr.size = sizeof(mixer->config); + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &mixer->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, + sizeof(mixer->config), 1); + if (ret < 0) { + kfree(swidget->private); + swidget->private = NULL; + + return ret; + } + + dev_dbg(scomp->dev, "loaded mixer %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &mixer->config); + + return 0; +} + static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; @@ -358,6 +392,12 @@ static enum sof_tokens host_token_list[] = { SOF_COMP_TOKENS, }; +static enum sof_tokens comp_generic_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_COMP_TOKENS, +}; + static enum sof_tokens buffer_token_list[] = { SOF_BUFFER_TOKENS, }; @@ -383,6 +423,9 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY host_token_list, ARRAY_SIZE(host_token_list), NULL}, [snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp, buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL}, + [snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp, + comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), + NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bd62658629f5..9e9a41018458 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1792,45 +1792,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -/* - * Mixer topology - */ - -static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_mixer *mixer; - size_t ipc_size = sizeof(*mixer); - int ret; - - mixer = (struct sof_ipc_comp_mixer *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!mixer) - return -ENOMEM; - - /* configure mixer IPC message */ - mixer->comp.type = SOF_COMP_MIXER; - mixer->config.hdr.size = sizeof(mixer->config); - - ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse mixer.cfg tokens failed %d\n", - private->size); - kfree(mixer); - return ret; - } - - sof_dbg_comp_config(scomp, &mixer->config); - - swidget->private = mixer; - - return 0; -} - /* * Mux topology */ @@ -2341,9 +2302,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, list_add(&dai->list, &sdev->dai_list); swidget->private = dai; break; - case snd_soc_dapm_mixer: - ret = sof_widget_load_mixer(scomp, index, swidget, tw); - break; case snd_soc_dapm_pga: if (!le32_to_cpu(tw->num_kcontrols)) { dev_err(scomp->dev, "invalid kcontrol count %d for volume\n", @@ -2353,6 +2311,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, } fallthrough; + case snd_soc_dapm_mixer: case snd_soc_dapm_buffer: case snd_soc_dapm_scheduler: case snd_soc_dapm_aif_out: From patchwork Mon Mar 14 20:05:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780771 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 76285C433F5 for ; Mon, 14 Mar 2022 20:10:00 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A649B18A4; Mon, 14 Mar 2022 21:09:08 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A649B18A4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288598; bh=17+3Br/SQ9CshebSb6xP8u3yof0W7n5/3ytw0k2NAas=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=sfxvJBtyjRT9JwB4MmH2G4NhiSxT1vSt9xmDcZdvgyAAxXnUcU63BoIzsvGLK/B9s 3lz2EzGDXundFYw2+85RAjdEYe/PwYvsg7Jbz++M+P5d1aRuhBBtWAFbw2gXq1fiRb oIMTT03+pOVG8gKhMHA8BoUf30FKqfsw1WHYR67U= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 179EFF8055B; Mon, 14 Mar 2022 21:06:06 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 7D371F80537; Mon, 14 Mar 2022 21:05:57 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 21AD8F80518 for ; Mon, 14 Mar 2022 21:05:45 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 21AD8F80518 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="M+5E+MQU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288347; x=1678824347; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=17+3Br/SQ9CshebSb6xP8u3yof0W7n5/3ytw0k2NAas=; b=M+5E+MQUBeq+Ob4rb4vBKonWlMHWuVaKp6NqVpvrMSNTcqYumiAkmjpI /GSpS34AAmB6uaEF/mKKwhFr/+Q5pLue+1jWlqFRS2VntDcEeQGWh8Vqj zWZKzwgmrE1Mv63Hv38OCjxbT4R/neY3LzyLOD9J6AQxJemaSpiCU3yUh qO6PAgdclhjYsAB5Jk74bnwmjZ8wv9vtU09sNujJ0ojODR0Cmw4nC1wx1 iimOEprTziiuHCSLrYOqqSjcGcGGWBbPyuqIeTUHhlz1QUh2219OH1lZA YmxpZtKqJhnA0ArnTBmWlp/8YwGmrVyKtfpw4O7/+j43QuNJs6ku6sGqd w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563476" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563476" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339896" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 09/18] ASoC: SOF: topology: Make mux/demux widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:11 -0700 Message-Id: <20220314200520.1233427-11-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the mux/demux widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the mux/demux component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 40 +++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 44 ++--------------------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index d8a91f461bf9..5501a18babaf 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -324,6 +324,41 @@ static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget) return 0; } +/* + * Mux topology + */ +static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_mux *mux; + size_t ipc_size = sizeof(*mux); + int ret; + + mux = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!mux) + return -ENOMEM; + + swidget->private = mux; + + /* configure mux IPC message */ + mux->comp.type = SOF_COMP_MUX; + mux->config.hdr.size = sizeof(mux->config); + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &mux->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, sizeof(mux->config), 1); + if (ret < 0) { + kfree(swidget->private); + swidget->private = NULL; + return ret; + } + + dev_dbg(scomp->dev, "loaded mux %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &mux->config); + + return 0; +} + /* * PGA Topology */ @@ -430,6 +465,11 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, pga_token_list, ARRAY_SIZE(pga_token_list), NULL}, + [snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp, + comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL}, + [snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp, + comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), + NULL}, }; static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9e9a41018458..42da7b8e7180 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1792,44 +1792,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -/* - * Mux topology - */ -static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_mux *mux; - size_t ipc_size = sizeof(*mux); - int ret; - - mux = (struct sof_ipc_comp_mux *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!mux) - return -ENOMEM; - - /* configure mux IPC message */ - mux->comp.type = SOF_COMP_MUX; - mux->config.hdr.size = sizeof(mux->config); - - ret = sof_parse_tokens(scomp, &mux->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse mux.cfg tokens failed %d\n", - private->size); - kfree(mux); - return ret; - } - - sof_dbg_comp_config(scomp, &mux->config); - - swidget->private = mux; - - return 0; -} - /* * SRC Topology */ @@ -2316,6 +2278,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_scheduler: case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_in: + case snd_soc_dapm_mux: + case snd_soc_dapm_demux: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; case snd_soc_dapm_src: @@ -2330,10 +2294,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_effect: ret = sof_widget_load_process(scomp, index, swidget, tw); break; - case snd_soc_dapm_mux: - case snd_soc_dapm_demux: - ret = sof_widget_load_mux(scomp, index, swidget, tw); - break; case snd_soc_dapm_switch: case snd_soc_dapm_dai_link: case snd_soc_dapm_kcontrol: From patchwork Mon Mar 14 20:05:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780770 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2297FC433F5 for ; Mon, 14 Mar 2022 20:09:47 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 5266A184D; Mon, 14 Mar 2022 21:08:55 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 5266A184D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288585; bh=7Q8YP3IiZPAWOO+benVq2T2wSSIZzIILNOt5YGoW1vA=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=NbFnzwPhFPQ0Nw0bib6DObt1NvnqxSaTyAhI7QyK6wda4PX9CQqkBHf7jSx3EZg2W azHeesd+dgFo2ivBjsPt9YO4yP/URGkaLVfe0XeoJKlhl+oNWHMHfC7HBN2WdXM6Zc 1VKRGTn3VNWqoCNA4uhLdSQOLlVeVgzAmI1FTBpQ= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id C3BDAF8055A; Mon, 14 Mar 2022 21:06:04 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 740FDF8053B; Mon, 14 Mar 2022 21:05:56 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 2B2E2F8051D for ; Mon, 14 Mar 2022 21:05:45 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 2B2E2F8051D Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TgXAjXxd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288347; x=1678824347; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7Q8YP3IiZPAWOO+benVq2T2wSSIZzIILNOt5YGoW1vA=; b=TgXAjXxd9MEvS7FAzK+Rq1Mwrc/we+Fr/wOPLHiBrvrh1KDl4f0KWmlx LoKXzAJf9FHWGv2ggpA/Whj/wMgU7ifWarZMPleF1bFepmu+uFNChD5sB S1zDYi/sQnJ+8mbwGADWeq19Qs2sG3QKg7ii8GpOSirNNzDOuiyEpaO3o GRKFvmQr1xlwW2tNCMI9Hatn0d1tTPlHWajXpVDgrbCn8fwLHjpBt5D3N S9zcLMLKmZuW2rB6HQuY8d6StYJ12ZZPjukifPCaWbP/xDLNFzfu0hGTM ke67OB8SgHU+GP3nUcYz7sCgh/WWCcpLjGxI8INNCZuCjYLJvHPXMMyEz w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563477" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563477" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339897" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 10/18] ASoC: SOF: topology: Make src widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:12 -0700 Message-Id: <20220314200520.1233427-12-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the src widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the src component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 59 ++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 64 +---------------------------------- 2 files changed, 60 insertions(+), 63 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 5501a18babaf..44ba3190e570 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -51,6 +51,14 @@ static const struct sof_topology_token volume_tokens[] = { offsetof(struct sof_ipc_comp_volume, initial_ramp)}, }; +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, source_rate)}, + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, sink_rate)}, +}; + /* PCM */ static const struct sof_topology_token pcm_tokens[] = { {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -89,6 +97,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)}, [SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)}, [SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)}, + [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; /** @@ -324,6 +333,47 @@ static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget) return 0; } +static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_src *src; + size_t ipc_size = sizeof(*src); + int ret; + + src = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!src) + return -ENOMEM; + + swidget->private = src; + + /* configure src IPC message */ + src->comp.type = SOF_COMP_SRC; + src->config.hdr.size = sizeof(src->config); + + /* parse one set of src tokens */ + ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*src), 1); + if (ret < 0) + goto err; + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &src->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, sizeof(src->config), 1); + if (ret < 0) + goto err; + + dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n", + swidget->widget->name, src->source_rate, src->sink_rate); + sof_dbg_comp_config(scomp, &src->config); + + return 0; +err: + kfree(swidget->private); + swidget->private = NULL; + + return ret; +} + /* * Mux topology */ @@ -444,6 +494,13 @@ static enum sof_tokens pipeline_token_list[] = { SOF_SCHED_TOKENS, }; +static enum sof_tokens src_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_SRC_TOKENS, + SOF_COMP_TOKENS +}; + static enum sof_tokens pga_token_list[] = { SOF_CORE_TOKENS, SOF_COMP_EXT_TOKENS, @@ -461,6 +518,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY [snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp, comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL}, + [snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp, + src_token_list, ARRAY_SIZE(src_token_list), NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 42da7b8e7180..f41bf7dfbd02 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -629,14 +629,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* SRC */ -static const struct sof_topology_token src_tokens[] = { - {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_src, source_rate)}, - {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_src, sink_rate)}, -}; - /* ASRC */ static const struct sof_topology_token asrc_tokens[] = { {SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -1792,58 +1784,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -/* - * SRC Topology - */ - -static int sof_widget_load_src(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_src *src; - size_t ipc_size = sizeof(*src); - int ret; - - src = (struct sof_ipc_comp_src *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!src) - return -ENOMEM; - - /* configure src IPC message */ - src->comp.type = SOF_COMP_SRC; - src->config.hdr.size = sizeof(src->config); - - ret = sof_parse_tokens(scomp, src, src_tokens, - ARRAY_SIZE(src_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse src tokens failed %d\n", - private->size); - goto err; - } - - ret = sof_parse_tokens(scomp, &src->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse src.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n", - swidget->widget->name, src->source_rate, src->sink_rate); - sof_dbg_comp_config(scomp, &src->config); - - swidget->private = src; - - return 0; -err: - kfree(src); - return ret; -} - /* * ASRC Topology */ @@ -2278,13 +2218,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_scheduler: case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_in: + case snd_soc_dapm_src: case snd_soc_dapm_mux: case snd_soc_dapm_demux: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; - case snd_soc_dapm_src: - ret = sof_widget_load_src(scomp, index, swidget, tw); - break; case snd_soc_dapm_asrc: ret = sof_widget_load_asrc(scomp, index, swidget, tw); break; From patchwork Mon Mar 14 20:05:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780772 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 199BCC433F5 for ; Mon, 14 Mar 2022 20:10:17 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 410A6182B; Mon, 14 Mar 2022 21:09:25 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 410A6182B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288615; bh=iaRoFYy4FnEZ37BwiDr88p/xxJXd7c3vK+pQm98Kt8E=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Cd/1qCII7xiji3LMIu9smAv0qxvpUMkHIzhqIWQBUTYvOJfRLu1Mpp/DxIVccCE1y EwfV/5Fca/Hq/fdXexf6XiDHdymwgyEhoB+uwWzgpaaLur7KupJ2mICqeKY4xas2/R uXQSxdQc+phS6DJd29jerKhtoIlOEijfG0WKkbug= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id D9701F80566; Mon, 14 Mar 2022 21:06:06 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9B9ABF8051D; Mon, 14 Mar 2022 21:05:58 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id C9903F8051B for ; Mon, 14 Mar 2022 21:05:46 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz C9903F8051B Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TaIQQ3He" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288348; x=1678824348; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iaRoFYy4FnEZ37BwiDr88p/xxJXd7c3vK+pQm98Kt8E=; b=TaIQQ3Her/+aQZWEhK337ijJLUtEvEnyNx+FSLAofA9p7SGp5FSMX9wW RzBkqFVI3tB1u++D09EvHT9fMLySuOuQB2uYCvlVc+5QYU9OudrFBOBaC qfGirStXooKGQF9tHZLadZh/1s42KjfIVvID6x8FMQ7HPojeAJ52NTH1G SbGr5oL//Zwoiy1S4z5NDGjfshYT7/K1ArYj3df8l8z8Wmxwyks9tIv0A MQpB5vU+qSu4UtmyYGuQzQBlrRfC8Kh3E3ML+AM1M3veHwrqh2aL51/Zq th5utBJqUQQ0ATuzxFgUKPvvCbcIjlF7L/MdE1FoWYavGD+GQzS/vsC9N w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563478" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563478" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339898" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 11/18] ASoC: SOF: topology: Make asrc widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:13 -0700 Message-Id: <20220314200520.1233427-13-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the asrc widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the asrc component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 65 +++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 72 +---------------------------------- 2 files changed, 66 insertions(+), 71 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 44ba3190e570..7dc6530efdba 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -59,6 +59,18 @@ static const struct sof_topology_token src_tokens[] = { offsetof(struct sof_ipc_comp_src, sink_rate)}, }; +/* 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)}, + {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_asrc, sink_rate)}, + {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)}, + {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_asrc, operation_mode)}, +}; + /* PCM */ static const struct sof_topology_token pcm_tokens[] = { {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -98,6 +110,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)}, [SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)}, [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, + [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)}, }; /** @@ -374,6 +387,49 @@ static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget) return ret; } +static int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_asrc *asrc; + size_t ipc_size = sizeof(*asrc); + int ret; + + asrc = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!asrc) + return -ENOMEM; + + swidget->private = asrc; + + /* configure ASRC IPC message */ + asrc->comp.type = SOF_COMP_ASRC; + asrc->config.hdr.size = sizeof(asrc->config); + + /* parse one set of asrc tokens */ + ret = sof_update_ipc_object(scomp, asrc, SOF_ASRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*asrc), 1); + if (ret < 0) + goto err; + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &asrc->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, sizeof(asrc->config), 1); + if (ret < 0) + 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); + + return 0; +err: + kfree(swidget->private); + swidget->private = NULL; + + return ret; +} + /* * Mux topology */ @@ -494,6 +550,13 @@ static enum sof_tokens pipeline_token_list[] = { SOF_SCHED_TOKENS, }; +static enum sof_tokens asrc_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_ASRC_TOKENS, + SOF_COMP_TOKENS, +}; + static enum sof_tokens src_token_list[] = { SOF_CORE_TOKENS, SOF_COMP_EXT_TOKENS, @@ -520,6 +583,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY NULL}, [snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp, src_token_list, ARRAY_SIZE(src_token_list), NULL}, + [snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp, + asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f41bf7dfbd02..94449ed370af 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -629,20 +629,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* 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)}, - {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_asrc, sink_rate)}, - {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, - offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)}, - {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, - offsetof(struct sof_ipc_comp_asrc, operation_mode)}, -}; - /* Tone */ static const struct sof_topology_token tone_tokens[] = { }; @@ -1784,60 +1770,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s 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 snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_asrc *asrc; - size_t ipc_size = sizeof(*asrc); - int ret; - - asrc = (struct sof_ipc_comp_asrc *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!asrc) - return -ENOMEM; - - /* configure ASRC IPC message */ - asrc->comp.type = SOF_COMP_ASRC; - 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; - - return 0; -err: - kfree(asrc); - return ret; -} - /* * Signal Generator Topology */ @@ -2219,13 +2151,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_aif_out: case snd_soc_dapm_aif_in: case snd_soc_dapm_src: + case snd_soc_dapm_asrc: case snd_soc_dapm_mux: case snd_soc_dapm_demux: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; - case snd_soc_dapm_asrc: - ret = sof_widget_load_asrc(scomp, index, swidget, tw); - break; case snd_soc_dapm_siggen: ret = sof_widget_load_siggen(scomp, index, swidget, tw); break; From patchwork Mon Mar 14 20:05:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780774 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EC108C433EF for ; Mon, 14 Mar 2022 20:11:01 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 32B8C18C5; Mon, 14 Mar 2022 21:10:10 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 32B8C18C5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288660; bh=w3S9W6gWT3L+wropLpgQA8Tcj43Qg57AAWLS9JoRIAc=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=jKTIyunZNuhAtk3WzUBm/36KtHGfpgAIVa8dGADilcQ17Dok/tfMI6XU6S6OSZAA0 8yZMtSpgK0Ata/vWs44bPqT/Xza630h5s2jPdyihMRI8X2/8pH0aAlLNQfnTVNFLJ6 3Bu7N380lQ/opVtPTWEg3uBU6ntgzfuR8tzSZo3I= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id C924BF805A0; Mon, 14 Mar 2022 21:06:10 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 6B977F8053E; Mon, 14 Mar 2022 21:06:01 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 2ED3FF80528 for ; Mon, 14 Mar 2022 21:05:48 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 2ED3FF80528 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="HqO69I53" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288349; x=1678824349; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=w3S9W6gWT3L+wropLpgQA8Tcj43Qg57AAWLS9JoRIAc=; b=HqO69I53vh0MZdKarBKf+P5LGHq/hZrCwyej+oXuq5/jjXeN1mH38iVa UsMFWvWrKb+5We2RWZzME4DnKFWZ5h1QGll/C6VQGpnwjPC0q42b/+joT qJpgNrxPwLOV9tH1Y2GVt9n8eQDn2s8E0Zi+PHWO7sWjij7JLLV053df+ qWXYGRXYBc6CFC241krNrr83PWa3WZ4/i1ymJCqYkHA37MWboaWVNMYo1 pnejlRd0IOU3GB7btEn8A6Eu6IJ4FE1tpbT0OhxgZ/dS3ZsWwi6vb7XE3 TPVMAL24Dgh75I8dq988zZakANFcBEcCGDb3aDFnJe4hokMrGPBbMG9wy Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563479" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563479" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339899" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 12/18] ASoC: SOF: topology: Make siggen widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:14 -0700 Message-Id: <20220314200520.1233427-14-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the siggen widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the tone component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 36 +++++++++++++++++++++ sound/soc/sof/topology.c | 60 +---------------------------------- 2 files changed, 37 insertions(+), 59 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 7dc6530efdba..6fef96fee5f2 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -212,6 +212,39 @@ static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget) kfree(swidget->private); } +static int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_tone *tone; + size_t ipc_size = sizeof(*tone); + int ret; + + tone = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!tone) + return -ENOMEM; + + swidget->private = tone; + + /* configure siggen IPC message */ + tone->comp.type = SOF_COMP_TONE; + tone->config.hdr.size = sizeof(tone->config); + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &tone->config, SOF_COMP_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(tone->config), 1); + if (ret < 0) { + kfree(swidget->private); + swidget->private = NULL; + return ret; + } + + dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n", + swidget->widget->name, tone->frequency, tone->amplitude); + sof_dbg_comp_config(scomp, &tone->config); + + return 0; +} + static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget) { struct snd_soc_component *scomp = swidget->scomp; @@ -585,6 +618,9 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY src_token_list, ARRAY_SIZE(src_token_list), NULL}, [snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp, asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL}, + [snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp, + comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), + NULL}, [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp, pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL}, [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 94449ed370af..f5b25ffee5b7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -629,10 +629,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* Tone */ -static const struct sof_topology_token tone_tokens[] = { -}; - /* EFFECT */ static const struct sof_topology_token process_tokens[] = { {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, @@ -1770,58 +1766,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -/* - * Signal Generator Topology - */ - -static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_tone *tone; - size_t ipc_size = sizeof(*tone); - int ret; - - tone = (struct sof_ipc_comp_tone *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!tone) - return -ENOMEM; - - /* configure siggen IPC message */ - tone->comp.type = SOF_COMP_TONE; - tone->config.hdr.size = sizeof(tone->config); - - ret = sof_parse_tokens(scomp, tone, tone_tokens, - ARRAY_SIZE(tone_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse tone tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - ret = sof_parse_tokens(scomp, &tone->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse tone.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n", - swidget->widget->name, tone->frequency, tone->amplitude); - sof_dbg_comp_config(scomp, &tone->config); - - swidget->private = tone; - - return 0; -err: - kfree(tone); - return ret; -} - static int sof_get_control_data(struct snd_soc_component *scomp, struct snd_soc_dapm_widget *widget, struct sof_widget_data *wdata, @@ -2152,13 +2096,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_aif_in: case snd_soc_dapm_src: case snd_soc_dapm_asrc: + case snd_soc_dapm_siggen: case snd_soc_dapm_mux: case snd_soc_dapm_demux: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; - case snd_soc_dapm_siggen: - ret = sof_widget_load_siggen(scomp, index, swidget, tw); - break; case snd_soc_dapm_effect: ret = sof_widget_load_process(scomp, index, swidget, tw); break; From patchwork Mon Mar 14 20:05:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780773 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E6C47C433EF for ; Mon, 14 Mar 2022 20:10:34 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 19A3A1866; Mon, 14 Mar 2022 21:09:43 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 19A3A1866 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288633; bh=RO12hlXGbb8/icUyg0KQNpeqvnvRA0gd1mw9+jPXWcQ=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Mcf+yhVY7hTHke3p5ZUTemOKg/aYMYegME5PcrujJT1/huo4jBQnLKd+T5XeOmj8N 7gVfKCiobnhq6SpKM6n2lf5n08srWjs8dnHIEPVHW2GM7wrPnibUR9992w0Jiclajy WztRqGKCxmgK0WxiMMQ/oX8XkXMGd4pzxh1aHhDo= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 0F39EF80570; Mon, 14 Mar 2022 21:06:08 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 39822F8051B; Mon, 14 Mar 2022 21:06:00 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 2EC88F80527 for ; Mon, 14 Mar 2022 21:05:48 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 2EC88F80527 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="O77YLFm5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288349; x=1678824349; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RO12hlXGbb8/icUyg0KQNpeqvnvRA0gd1mw9+jPXWcQ=; b=O77YLFm5PjAeJDE4SM3C1/irO9PaQ/uG+esg3iEsoHelAi/m0xTQUm3c 4t2Sr/FrPTh5wBmsjzsfqge7c2YHPPWzGA3ASuV9BbYfSuBZWFPIJ9aNo PHH0jaOMprp4NkYOk0zRZmwAQw43Dij11GHpDGE3vIuqQ84KHg904vuHE wco0NTxDhwbbSotzN2+YtX06GmcsBmrz5EUBK7sEA07HdHHRu0W5yrqCw 2mhdeRixq823se96QlqSdeUDw5473qiXDKYqTtUcl9kcDTFBsyBlZb3bi 2qhNJ/nS2XunLite35ZZbv5MZlxP8Tmi+qKWefS7Ejjs6gBaT890ypQVB g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563480" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563480" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339900" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 13/18] ASoC: SOF: topology: Make effect widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:15 -0700 Message-Id: <20220314200520.1233427-15-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to effect type widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the process component based on the topology widget_setup op in ipc3_tplg_ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 248 ++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 277 ++-------------------------------- 2 files changed, 257 insertions(+), 268 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 6fef96fee5f2..b710129374c8 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -13,6 +13,51 @@ #include "sof-audio.h" #include "ops.h" +struct sof_widget_data { + int ctrl_type; + int ipc_cmd; + struct sof_abi_hdr *pdata; + struct snd_sof_control *control; +}; + +struct sof_process_types { + const char *name; + enum sof_ipc_process_type type; + enum sof_comp_type comp_type; +}; + +static const struct sof_process_types sof_process[] = { + {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR}, + {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR}, + {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT}, + {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB}, + {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR}, + {"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX}, + {"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX}, + {"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK}, + {"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP}, +}; + +static enum sof_ipc_process_type find_process(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (strcmp(name, sof_process[i].name) == 0) + return sof_process[i].type; + } + + return SOF_PROCESS_NONE; +} + +static int get_token_process_type(void *elem, void *object, u32 offset) +{ + u32 *val = (u32 *)((u8 *)object + offset); + + *val = find_process((const char *)elem); + return 0; +} + /* Buffers */ static const struct sof_topology_token buffer_tokens[] = { {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -71,6 +116,12 @@ static const struct sof_topology_token asrc_tokens[] = { offsetof(struct sof_ipc_comp_asrc, operation_mode)}, }; +/* EFFECT */ +static const struct sof_topology_token process_tokens[] = { + {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_process_type, + offsetof(struct sof_ipc_comp_process, type)}, +}; + /* PCM */ static const struct sof_topology_token pcm_tokens[] = { {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -111,6 +162,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)}, [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)}, + [SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)}, }; /** @@ -558,6 +610,193 @@ static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget) return ret; } +static int sof_get_control_data(struct snd_soc_component *scomp, + struct snd_soc_dapm_widget *widget, + struct sof_widget_data *wdata, size_t *size) +{ + const struct snd_kcontrol_new *kc; + struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; + struct soc_enum *se; + int i; + + *size = 0; + + for (i = 0; i < widget->num_kcontrols; i++) { + kc = &widget->kcontrol_news[i]; + + switch (widget->dobj.widget.kcontrol_type[i]) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + wdata[i].control = sm->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + wdata[i].control = sbe->dobj.private; + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + wdata[i].control = se->dobj.private; + break; + default: + dev_err(scomp->dev, "Unknown kcontrol type %u in widget %s\n", + widget->dobj.widget.kcontrol_type[i], widget->name); + return -EINVAL; + } + + if (!wdata[i].control) { + dev_err(scomp->dev, "No scontrol for widget %s\n", widget->name); + return -EINVAL; + } + + wdata[i].pdata = wdata[i].control->control_data->data; + if (!wdata[i].pdata) + return -EINVAL; + + /* make sure data is valid - data can be updated at runtime */ + if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES && + wdata[i].pdata->magic != SOF_ABI_MAGIC) + return -EINVAL; + + *size += wdata[i].pdata->size; + + /* get data type */ + switch (wdata[i].control->control_data->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE; + wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + break; + case SOF_CTRL_CMD_BINARY: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA; + wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET; + break; + default: + break; + } + } + + return 0; +} + +static int sof_process_load(struct snd_soc_component *scomp, + struct snd_sof_widget *swidget, int type) +{ + struct snd_soc_dapm_widget *widget = swidget->widget; + struct sof_ipc_comp_process *process; + struct sof_widget_data *wdata = NULL; + size_t ipc_data_size = 0; + size_t ipc_size; + int offset = 0; + int ret; + int i; + + /* allocate struct for widget control data sizes and types */ + if (widget->num_kcontrols) { + wdata = kcalloc(widget->num_kcontrols, sizeof(*wdata), GFP_KERNEL); + if (!wdata) + return -ENOMEM; + + /* get possible component controls and get size of all pdata */ + ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size); + if (ret < 0) + goto out; + } + + ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size; + + /* we are exceeding max ipc size, config needs to be sent separately */ + if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { + ipc_size -= ipc_data_size; + ipc_data_size = 0; + } + + process = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!process) { + ret = -ENOMEM; + goto out; + } + + swidget->private = process; + + /* configure iir IPC message */ + process->comp.type = type; + process->config.hdr.size = sizeof(process->config); + + /* parse one set of comp tokens */ + ret = sof_update_ipc_object(scomp, &process->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, + sizeof(process->config), 1); + if (ret < 0) + goto err; + + dev_dbg(scomp->dev, "loaded process %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &process->config); + + /* + * found private data in control, so copy it. + * get possible component controls - get size of all pdata, + * then memcpy with headers + */ + if (ipc_data_size) { + for (i = 0; i < widget->num_kcontrols; i++) { + memcpy(&process->data[offset], + wdata[i].pdata->data, + wdata[i].pdata->size); + offset += wdata[i].pdata->size; + } + } + + process->size = ipc_data_size; + + kfree(wdata); + + return 0; +err: + kfree(swidget->private); + swidget->private = NULL; +out: + kfree(wdata); + return ret; +} + +static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (sof_process[i].type == type) + return sof_process[i].comp_type; + } + + return SOF_COMP_NONE; +} + +/* + * Processing Component Topology - can be "effect", "codec", or general + * "processing". + */ + +static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc_comp_process config; + int ret; + + memset(&config, 0, sizeof(config)); + config.comp.core = swidget->core; + + /* parse one set of process tokens */ + ret = sof_update_ipc_object(scomp, &config, SOF_PROCESS_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(config), 1); + if (ret < 0) + return ret; + + /* now load process specific data and send IPC */ + return sof_process_load(scomp, swidget, find_process_comp_type(config.type)); +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -604,6 +843,13 @@ static enum sof_tokens pga_token_list[] = { SOF_COMP_TOKENS, }; +static enum sof_tokens process_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_PROCESS_TOKENS, + SOF_COMP_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, @@ -630,6 +876,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY [snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp, comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL}, + [snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp, + process_token_list, ARRAY_SIZE(process_token_list), NULL}, }; static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f5b25ffee5b7..187f7c46a42b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -141,13 +141,6 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so return 0; } -struct sof_widget_data { - int ctrl_type; - int ipc_cmd; - struct sof_abi_hdr *pdata; - struct snd_sof_control *control; -}; - /* send pcm params ipc */ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { @@ -517,48 +510,6 @@ static enum sof_ipc_frame find_format(const char *name) return SOF_IPC_FRAME_S32_LE; } -struct sof_process_types { - const char *name; - enum sof_ipc_process_type type; - enum sof_comp_type comp_type; -}; - -static const struct sof_process_types sof_process[] = { - {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR}, - {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR}, - {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT}, - {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB}, - {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR}, - {"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX}, - {"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX}, - {"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK}, - {"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP}, -}; - -static enum sof_ipc_process_type find_process(const char *name) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sof_process); i++) { - if (strcmp(name, sof_process[i].name) == 0) - return sof_process[i].type; - } - - return SOF_PROCESS_NONE; -} - -static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sof_process); i++) { - if (sof_process[i].type == type) - return sof_process[i].comp_type; - } - - return SOF_COMP_NONE; -} - int get_token_u32(void *elem, void *object, u32 offset) { struct snd_soc_tplg_vendor_value_elem *velem = elem; @@ -603,14 +554,6 @@ int get_token_dai_type(void *elem, void *object, u32 offset) return 0; } -static int get_token_process_type(void *elem, void *object, u32 offset) -{ - u32 *val = (u32 *)((u8 *)object + offset); - - *val = find_process((const char *)elem); - return 0; -} - /* DAI */ static const struct sof_topology_token dai_tokens[] = { {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, @@ -629,13 +572,6 @@ static const struct sof_topology_token dai_link_tokens[] = { offsetof(struct sof_ipc_dai_config, dai_index)}, }; -/* EFFECT */ -static const struct sof_topology_token process_tokens[] = { - {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, - get_token_process_type, - offsetof(struct sof_ipc_comp_process, type)}, -}; - /* PCM */ static const struct sof_topology_token stream_tokens[] = { {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, @@ -1766,207 +1702,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -static int sof_get_control_data(struct snd_soc_component *scomp, - struct snd_soc_dapm_widget *widget, - struct sof_widget_data *wdata, - size_t *size) -{ - const struct snd_kcontrol_new *kc; - struct soc_mixer_control *sm; - struct soc_bytes_ext *sbe; - struct soc_enum *se; - int i; - - *size = 0; - - for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; - - switch (widget->dobj.widget.kcontrol_type[i]) { - case SND_SOC_TPLG_TYPE_MIXER: - sm = (struct soc_mixer_control *)kc->private_value; - wdata[i].control = sm->dobj.private; - break; - case SND_SOC_TPLG_TYPE_BYTES: - sbe = (struct soc_bytes_ext *)kc->private_value; - wdata[i].control = sbe->dobj.private; - break; - case SND_SOC_TPLG_TYPE_ENUM: - se = (struct soc_enum *)kc->private_value; - wdata[i].control = se->dobj.private; - break; - default: - dev_err(scomp->dev, "error: unknown kcontrol type %u in widget %s\n", - widget->dobj.widget.kcontrol_type[i], - widget->name); - return -EINVAL; - } - - if (!wdata[i].control) { - dev_err(scomp->dev, "error: no scontrol for widget %s\n", - widget->name); - return -EINVAL; - } - - wdata[i].pdata = wdata[i].control->control_data->data; - if (!wdata[i].pdata) - return -EINVAL; - - /* make sure data is valid - data can be updated at runtime */ - if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES && - wdata[i].pdata->magic != SOF_ABI_MAGIC) - return -EINVAL; - - *size += wdata[i].pdata->size; - - /* get data type */ - switch (wdata[i].control->control_data->cmd) { - case SOF_CTRL_CMD_VOLUME: - case SOF_CTRL_CMD_ENUM: - case SOF_CTRL_CMD_SWITCH: - wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE; - wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; - break; - case SOF_CTRL_CMD_BINARY: - wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA; - wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET; - break; - default: - break; - } - } - - return 0; -} - -static int sof_process_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - int type) -{ - struct snd_soc_dapm_widget *widget = swidget->widget; - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_process *process; - struct sof_widget_data *wdata = NULL; - size_t ipc_data_size = 0; - size_t ipc_size; - int offset = 0; - int ret; - int i; - - /* allocate struct for widget control data sizes and types */ - if (widget->num_kcontrols) { - wdata = kcalloc(widget->num_kcontrols, - sizeof(*wdata), - GFP_KERNEL); - - if (!wdata) - return -ENOMEM; - - /* get possible component controls and get size of all pdata */ - ret = sof_get_control_data(scomp, widget, wdata, - &ipc_data_size); - - if (ret < 0) - goto out; - } - - ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size; - - /* we are exceeding max ipc size, config needs to be sent separately */ - if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { - ipc_size -= ipc_data_size; - ipc_data_size = 0; - } - - process = (struct sof_ipc_comp_process *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!process) { - ret = -ENOMEM; - goto out; - } - - /* configure iir IPC message */ - process->comp.type = type; - process->config.hdr.size = sizeof(process->config); - - ret = sof_parse_tokens(scomp, &process->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse process.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - sof_dbg_comp_config(scomp, &process->config); - - /* - * found private data in control, so copy it. - * get possible component controls - get size of all pdata, - * then memcpy with headers - */ - if (ipc_data_size) { - for (i = 0; i < widget->num_kcontrols; i++) { - memcpy(&process->data[offset], - wdata[i].pdata->data, - wdata[i].pdata->size); - offset += wdata[i].pdata->size; - } - } - - process->size = ipc_data_size; - swidget->private = process; -err: - if (ret < 0) - kfree(process); -out: - kfree(wdata); - return ret; -} - -/* - * Processing Component Topology - can be "effect", "codec", or general - * "processing". - */ - -static int sof_widget_load_process(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_process config; - int ret; - - /* check we have some tokens - we need at least process type */ - if (le32_to_cpu(private->size) == 0) { - dev_err(scomp->dev, "error: process tokens not found\n"); - return -EINVAL; - } - - memset(&config, 0, sizeof(config)); - config.comp.core = swidget->core; - - /* get the process token */ - ret = sof_parse_tokens(scomp, &config, process_tokens, - ARRAY_SIZE(process_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse process tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - /* now load process specific data and send IPC */ - ret = sof_process_load(scomp, index, swidget, tw, find_process_comp_type(config.type)); - if (ret < 0) { - dev_err(scomp->dev, "error: process loading failed\n"); - return ret; - } - - return 0; -} - static int sof_widget_bind_event(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, u16 event_type) @@ -2080,6 +1815,15 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, list_add(&dai->list, &sdev->dai_list); swidget->private = dai; break; + case snd_soc_dapm_effect: + /* check we have some tokens - we need at least process type */ + if (le32_to_cpu(tw->priv.size) == 0) { + dev_err(scomp->dev, "error: process tokens not found\n"); + ret = -EINVAL; + break; + } + ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); + break; case snd_soc_dapm_pga: if (!le32_to_cpu(tw->num_kcontrols)) { dev_err(scomp->dev, "invalid kcontrol count %d for volume\n", @@ -2101,9 +1845,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_demux: ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); break; - case snd_soc_dapm_effect: - ret = sof_widget_load_process(scomp, index, swidget, tw); - break; case snd_soc_dapm_switch: case snd_soc_dapm_dai_link: case snd_soc_dapm_kcontrol: From patchwork Mon Mar 14 20:05:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780775 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 30B13C433F5 for ; Mon, 14 Mar 2022 20:11:12 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 756A418CC; Mon, 14 Mar 2022 21:10:20 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 756A418CC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288670; bh=YqBw2e1h0zdtpzGSw1IPJ/rOT/2dwUW7NYgdmzDgSfE=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Ou0qqDRcSs7alEIxgVNQXOs4XifYcgt5xmHIB7bp5g+HSb7qJ7YhMUNiudAMzA1T2 c3Q2pi9XY42SizAUiYNr6Vpmiqm1pHXeSfhb5NhiPMkLDDAT+VeiMx1SekNLqtTbuz Hc8JeUvWjuRx3QPYqzaZXxTtPefbBG9eoToA9GvQ= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 40730F805A8; Mon, 14 Mar 2022 21:06:11 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id CFC97F80553; Mon, 14 Mar 2022 21:06:03 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id BA23AF80475 for ; Mon, 14 Mar 2022 21:05:48 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz BA23AF80475 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Lu0RCkDN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288350; x=1678824350; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=YqBw2e1h0zdtpzGSw1IPJ/rOT/2dwUW7NYgdmzDgSfE=; b=Lu0RCkDNUJtO7xfT/U+GKnFq51Kx9zcevTzPoMPZDd/ICRY+PDUDUgKT Wcuov4hOTTPFkYrqbNbC5+suM6buWoDlMiJdE/0Cd3Q96lrjkeT/SUIA1 xF75llm3EkVf6aVxSaJi0sKRZXXqt+4SqvvJtgcQrPKqKVpqvnQHWI1DH BbKoPKUmMoA4vO9heHWIaBIIoyOP1wSxMC13CVzM6xIDECPHVFBPi+sCn /Vmy2DILgoLTXLjONOzW3niV8FA4SiQV8yyqb7OQOuJLVZPAbXDFCyH3A Ofdxd1EwNdnL+axb+t+DTFQoLSXORpf1624Ns6NI264mRT++P6THj6sE8 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563482" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563482" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339902" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:33 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 14/18] ASoC: SOF: topology: Make route setup IPC agnostic Date: Mon, 14 Mar 2022 13:05:16 -0700 Message-Id: <20220314200520.1233427-16-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define and set the route_setup op for IPC3 topology ops and use it for setting up routes. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 26 +++++++++++++++++++ sound/soc/sof/sof-audio.c | 48 ++++++++++------------------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index b710129374c8..a9d55c1d1f84 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -797,6 +797,31 @@ static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget) return sof_process_load(scomp, swidget, find_process_comp_type(config.type)); } +static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) +{ + struct sof_ipc_pipe_comp_connect connect; + struct sof_ipc_reply reply; + int ret; + + connect.hdr.size = sizeof(connect); + connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT; + connect.source_id = sroute->src_widget->comp_id; + connect.sink_id = sroute->sink_widget->comp_id; + + dev_dbg(sdev->dev, "setting up route %s -> %s\n", + sroute->src_widget->widget->name, + sroute->sink_widget->widget->name); + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect), + &reply, sizeof(reply)); + if (ret < 0) + dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__, + sroute->src_widget->widget->name, sroute->sink_widget->widget->name); + + return ret; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -882,6 +907,7 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { .widget = tplg_ipc3_widget_ops, + .route_setup = sof_ipc3_route_setup, .token_list = ipc3_token_list, }; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 15c36a51f89f..c02dcad03b23 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -263,45 +263,15 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } EXPORT_SYMBOL(sof_widget_setup); -static int sof_route_setup_ipc(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) -{ - struct sof_ipc_pipe_comp_connect connect; - struct sof_ipc_reply reply; - int ret; - - /* nothing to do if route is already set up */ - if (sroute->setup) - return 0; - - connect.hdr.size = sizeof(connect); - connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT; - connect.source_id = sroute->src_widget->comp_id; - connect.sink_id = sroute->sink_widget->comp_id; - - dev_dbg(sdev->dev, "setting up route %s -> %s\n", - sroute->src_widget->widget->name, - sroute->sink_widget->widget->name); - - /* send ipc */ - ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect), - &reply, sizeof(reply)); - if (ret < 0) { - dev_err(sdev->dev, "%s: route setup failed %d\n", __func__, ret); - return ret; - } - - sroute->setup = true; - - return 0; -} - static int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink) { + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct snd_sof_widget *src_widget = wsource->dobj.private; struct snd_sof_widget *sink_widget = wsink->dobj.private; struct snd_sof_route *sroute; bool route_found = false; + int ret; /* ignore routes involving virtual widgets in topology */ switch (src_widget->id) { @@ -335,7 +305,16 @@ static int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget return -EINVAL; } - return sof_route_setup_ipc(sdev, sroute); + /* nothing to do if route is already set up */ + if (sroute->setup) + return 0; + + ret = ipc_tplg_ops->route_setup(sdev, sroute); + if (ret < 0) + return ret; + + sroute->setup = true; + return 0; } static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, @@ -604,6 +583,7 @@ int sof_set_hw_params_upon_resume(struct device *dev) int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) { + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_sof_widget *swidget; struct snd_sof_route *sroute; @@ -656,7 +636,7 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) sroute->sink_widget->dynamic_pipeline_widget)) continue; - ret = sof_route_setup_ipc(sdev, sroute); + ret = ipc_tplg_ops->route_setup(sdev, sroute); if (ret < 0) { dev_err(sdev->dev, "%s: restore pipeline connections failed\n", __func__); return ret; From patchwork Mon Mar 14 20:05:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780779 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0D09CC433EF for ; Mon, 14 Mar 2022 20:12:22 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3D12B18BD; Mon, 14 Mar 2022 21:11:30 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3D12B18BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288740; bh=yAikUdDTknd7ufuQKuG3oDSy4RqFv1att9mhKKb2Am0=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=l6zr52Yt4X4J1Jza3pPH1ZPJIrAzXy+8PryHa5lL0ASW0FrcWfkdWEBlg4nw33Me8 HWe/i5pwQ95nHRu0Sw+WPkiZjsUV7YWlYir78Ev82g5XF46bzidQThdHO97SVo8OXe t+wn+EIFT/4d9y7OBu6m9kLKFPcQ7FmPI/ZeTqF4= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 3B54BF805C1; Mon, 14 Mar 2022 21:06:13 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id DF4F3F8057D; Mon, 14 Mar 2022 21:06:09 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 31B19F80516 for ; Mon, 14 Mar 2022 21:05:49 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 31B19F80516 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="OrWOra4m" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288351; x=1678824351; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yAikUdDTknd7ufuQKuG3oDSy4RqFv1att9mhKKb2Am0=; b=OrWOra4m+CTgGVvPD8dILtk8LBs7utXFC4D65jB0rwFRrqo4zyDDh1yf wc8AG+WccvsXXY2rZsfciAihvB+w9TUwyN1QdtYGY/V+WJd3gJGKQCHbW 7bgqHzSdf++0oqX2GslO1cgDPDv/2ek2QRO1i1HYd80kZ480rukGxQOfn +Mc/q+Pj+WJHyZH6aaPogYZrvxj2wkpQhluT/ywntGRuy+fkCQMJxemRj 9SvklDqxoLQBuF6dszTF7vOdKdI2JZnJI50Dwh2NjBFW5SII2PEPj5NnY nzV4WEw848cZChQI+jjtOXFboLP7fQCFaByCAegLX6TfTnwa6a9lzahA+ w==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563485" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563485" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339906" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 15/18] ASoC: SOF: topology: Make DAI widget parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:17 -0700 Message-Id: <20220314200520.1233427-17-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Define the list of tokens pertaining to the dai_in/out widgets, parse and save them as part of the swidget tuples array. Once topology parsing is complete, these tokens will be applied to create the IPC structure for the DAI component based on the topology widget_setup op in ipc3_tplg_ops. DAI link parsing is also made IPC agnostic by parsing the list of tokens associated with all DAI types. The config will be applied to the respective DAI widgets during topology complete. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 745 ++++++++++++++++++++- sound/soc/sof/topology.c | 1157 +++++---------------------------- 2 files changed, 915 insertions(+), 987 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index a9d55c1d1f84..e6aa78d492ea 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -8,7 +8,6 @@ // #include -#include #include "sof-priv.h" #include "sof-audio.h" #include "ops.h" @@ -66,6 +65,24 @@ static const struct sof_topology_token buffer_tokens[] = { offsetof(struct sof_ipc_buffer, caps)}, }; +/* DAI */ +static const struct sof_topology_token dai_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_comp_dai, type)}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, dai_index)}, + {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, direction)}, +}; + +/* BE DAI link */ +static const struct sof_topology_token dai_link_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_dai_config, type)}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_config, dai_index)}, +}; + /* scheduling */ static const struct sof_topology_token sched_tokens[] = { {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -139,6 +156,107 @@ static const struct sof_topology_token comp_tokens[] = { offsetof(struct sof_ipc_comp_config, frame_fmt)}, }; +/* SSP */ +static const struct sof_topology_token ssp_tokens[] = { + {SOF_TKN_INTEL_SSP_CLKS_CONTROL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, clks_control)}, + {SOF_TKN_INTEL_SSP_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, mclk_id)}, + {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)}, + {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)}, + {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, quirks)}, + {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag)}, + {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)}, +}; + +/* ALH */ +static const struct sof_topology_token alh_tokens[] = { + {SOF_TKN_INTEL_ALH_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_alh_params, rate)}, + {SOF_TKN_INTEL_ALH_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_alh_params, channels)}, +}; + +/* DMIC */ +static const struct sof_topology_token dmic_tokens[] = { + {SOF_TKN_INTEL_DMIC_DRIVER_VERSION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)}, + {SOF_TKN_INTEL_DMIC_CLK_MIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)}, + {SOF_TKN_INTEL_DMIC_CLK_MAX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)}, + {SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)}, + {SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_min)}, + {SOF_TKN_INTEL_DMIC_DUTY_MAX, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_max)}, + {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, num_pdm_active)}, + {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)}, + {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)}, +}; + +/* ESAI */ +static const struct sof_topology_token esai_tokens[] = { + {SOF_TKN_IMX_ESAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_esai_params, mclk_id)}, +}; + +/* SAI */ +static const struct sof_topology_token sai_tokens[] = { + {SOF_TKN_IMX_SAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_sai_params, mclk_id)}, +}; + +/* + * DMIC PDM Tokens + * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token + * as it increments the index while parsing the array of pdm tokens + * and determines the correct offset + */ +static const struct sof_topology_token dmic_pdm_tokens[] = { + {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id)}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)}, + {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)}, + {SOF_TKN_INTEL_DMIC_PDM_SKEW, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)}, +}; + +/* HDA */ +static const struct sof_topology_token hda_tokens[] = { + {SOF_TKN_INTEL_HDA_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_hda_params, rate)}, + {SOF_TKN_INTEL_HDA_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_hda_params, channels)}, +}; + +/* AFE */ +static const struct sof_topology_token afe_tokens[] = { + {SOF_TKN_MEDIATEK_AFE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, rate)}, + {SOF_TKN_MEDIATEK_AFE_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, channels)}, + {SOF_TKN_MEDIATEK_AFE_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_dai_mtk_afe_params, format)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -163,6 +281,16 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)}, [SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)}, + [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, + [SOF_DAI_LINK_TOKENS] = {"DAI link tokens", dai_link_tokens, ARRAY_SIZE(dai_link_tokens)}, + [SOF_HDA_TOKENS] = {"HDA tokens", hda_tokens, ARRAY_SIZE(hda_tokens)}, + [SOF_SSP_TOKENS] = {"SSP tokens", ssp_tokens, ARRAY_SIZE(ssp_tokens)}, + [SOF_ALH_TOKENS] = {"ALH tokens", alh_tokens, ARRAY_SIZE(alh_tokens)}, + [SOF_DMIC_TOKENS] = {"DMIC tokens", dmic_tokens, ARRAY_SIZE(dmic_tokens)}, + [SOF_DMIC_PDM_TOKENS] = {"DMIC PDM tokens", dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens)}, + [SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)}, + [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)}, + [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, }; /** @@ -797,6 +925,609 @@ static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget) return sof_process_load(scomp, swidget, find_process_comp_type(config.type)); } +static int sof_link_hda_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* init IPC */ + memset(&config->hda, 0, sizeof(config->hda)); + config->hdr.size = size; + + /* parse one set of HDA tokens */ + ret = sof_update_ipc_object(scomp, &config->hda, SOF_HDA_TOKENS, slink->tuples, + slink->num_tuples, size, 1); + if (ret < 0) + return ret; + + dev_dbg(scomp->dev, "HDA config rate %d channels %d\n", + config->hda.rate, config->hda.channels); + + config->hda.link_dma_ch = DMA_CHAN_INVALID; + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /* clock directions wrt codec */ + config->format &= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK; + if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) { + /* codec is bclk provider */ + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) + config->format |= SOF_DAI_FMT_CBP_CFP; + else + config->format |= SOF_DAI_FMT_CBP_CFC; + } else { + /* codec is bclk consumer */ + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) + config->format |= SOF_DAI_FMT_CBC_CFP; + else + config->format |= SOF_DAI_FMT_CBC_CFC; + } + + /* inverted clocks ? */ + config->format &= ~SOF_DAI_FMT_INV_MASK; + if (hw_config->invert_bclk) { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_IB_IF; + else + config->format |= SOF_DAI_FMT_IB_NF; + } else { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_NB_IF; + else + config->format |= SOF_DAI_FMT_NB_NF; + } +} + +static int sof_link_sai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->sai, 0, sizeof(config->sai)); + config->hdr.size = size; + + /* parse one set of SAI tokens */ + ret = sof_update_ipc_object(scomp, &config->sai, SOF_SAI_TOKENS, slink->tuples, + slink->num_tuples, size, 1); + if (ret < 0) + return ret; + + config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->sai.mclk_direction = hw_config->mclk_direction; + + config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_info(scomp->dev, + "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", + config->dai_index, config->format, + config->sai.mclk_rate, config->sai.tdm_slot_width, + config->sai.tdm_slots, config->sai.mclk_id); + + if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) { + dev_err(scomp->dev, "Invalid channel count for SAI%d\n", config->dai_index); + return -EINVAL; + } + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->esai, 0, sizeof(config->esai)); + config->hdr.size = size; + + /* parse one set of ESAI tokens */ + ret = sof_update_ipc_object(scomp, &config->esai, SOF_ESAI_TOKENS, slink->tuples, + slink->num_tuples, size, 1); + if (ret < 0) + return ret; + + config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->esai.mclk_direction = hw_config->mclk_direction; + config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_info(scomp->dev, + "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", + config->dai_index, config->format, + config->esai.mclk_rate, config->esai.tdm_slot_width, + config->esai.tdm_slots, config->esai.mclk_id); + + if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) { + dev_err(scomp->dev, "Invalid channel count for ESAI%d\n", config->dai_index); + return -EINVAL; + } + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpdmic, 0, sizeof(config->acpdmic)); + config->hdr.size = size; + + config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", + config->dai_index, config->acpdmic.tdm_slots, + config->acpdmic.fsync_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpbt, 0, sizeof(config->acpbt)); + config->hdr.size = size; + + config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n", + config->dai_index, config->acpbt.tdm_slots, + config->acpbt.fsync_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpsp, 0, sizeof(config->acpsp)); + config->hdr.size = size; + + config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n", + config->dai_index, config->acpsp.tdm_slots, + config->acpsp.fsync_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + config->hdr.size = size; + + /* parse the required set of AFE tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->afe, SOF_AFE_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n", + config->afe.rate, config->afe.channels, config->afe.format); + + config->afe.stream_id = DMA_CHAN_INVALID; + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int current_config = 0; + int i, ret; + + /* + * Parse common data, we should have 1 common data per hw_config. + */ + ret = sof_update_ipc_object(scomp, &config->ssp, SOF_SSP_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + /* process all possible hw configs */ + for (i = 0; i < slink->num_hw_configs; i++) { + if (le32_to_cpu(hw_config[i].id) == slink->default_hw_cfg_id) + current_config = i; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(&hw_config[i], &config[i]); + + config[i].hdr.size = size; + + /* copy differentiating hw configs to ipc structs */ + config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate); + config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate); + config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate); + config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots); + config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width); + config[i].ssp.mclk_direction = hw_config[i].mclk_direction; + config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots); + config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots); + + dev_dbg(scomp->dev, "tplg: config SSP%d fmt %#x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d clks_control %#x\n", + config[i].dai_index, config[i].format, + config[i].ssp.mclk_rate, config[i].ssp.bclk_rate, + config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits, + config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots, + config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control); + + /* validate SSP fsync rate and channel count */ + if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) { + dev_err(scomp->dev, "Invalid fsync rate for SSP%d\n", config[i].dai_index); + return -EINVAL; + } + + if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) { + dev_err(scomp->dev, "Invalid channel count for SSP%d\n", + config[i].dai_index); + return -EINVAL; + } + } + + dai->number_configs = slink->num_hw_configs; + dai->current_config = current_config; + private->dai_config = kmemdup(config, size * slink->num_hw_configs, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_dai_private_data *private = dai->private; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + size_t size = sizeof(*config); + int i, ret; + + /* Ensure the entire DMIC config struct is zeros */ + memset(&config->dmic, 0, sizeof(config->dmic)); + + /* parse the required set of DMIC tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->dmic, SOF_DMIC_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + /* parse the required set of DMIC PDM tokens based on number of active PDM's */ + ret = sof_update_ipc_object(scomp, &config->dmic.pdm[0], SOF_DMIC_PDM_TOKENS, + slink->tuples, slink->num_tuples, + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl), + config->dmic.num_pdm_active); + if (ret < 0) + return ret; + + /* set IPC header size */ + config->hdr.size = size; + + /* debug messages */ + dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n", + config->dai_index, config->dmic.driver_ipc_version); + dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %d\n", + config->dmic.pdmclk_min, config->dmic.pdmclk_max, + config->dmic.duty_min); + dev_dbg(scomp->dev, "duty_max %d fifo_fs %d num_pdms active %d\n", + config->dmic.duty_max, config->dmic.fifo_fs, + config->dmic.num_pdm_active); + dev_dbg(scomp->dev, "fifo word length %d\n", config->dmic.fifo_bits); + + for (i = 0; i < config->dmic.num_pdm_active; i++) { + dev_dbg(scomp->dev, "pdm %d mic a %d mic b %d\n", + config->dmic.pdm[i].id, + config->dmic.pdm[i].enable_mic_a, + config->dmic.pdm[i].enable_mic_b); + dev_dbg(scomp->dev, "pdm %d polarity a %d polarity b %d\n", + config->dmic.pdm[i].id, + config->dmic.pdm[i].polarity_mic_a, + config->dmic.pdm[i].polarity_mic_b); + dev_dbg(scomp->dev, "pdm %d clk_edge %d skew %d\n", + config->dmic.pdm[i].id, + config->dmic.pdm[i].clk_edge, + config->dmic.pdm[i].skew); + } + + /* + * this takes care of backwards compatible handling of fifo_bits_b. + * It is deprecated since firmware ABI version 3.0.1. + */ + if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) + config->dmic.fifo_bits_b = config->dmic.fifo_bits; + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* parse the required set of ALH tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->alh, SOF_ALH_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + /* init IPC */ + config->hdr.size = size; + + /* set config for all DAI's with name matching the link name */ + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + +static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dai *dai = swidget->private; + struct sof_dai_private_data *private; + struct sof_ipc_comp_dai *comp_dai; + size_t ipc_size = sizeof(*comp_dai); + struct sof_ipc_dai_config *config; + struct snd_sof_dai_link *slink; + int ret; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) + return -ENOMEM; + + dai->private = private; + + private->comp_dai = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id); + if (!private->comp_dai) { + ret = -ENOMEM; + goto free; + } + + /* configure dai IPC message */ + comp_dai = private->comp_dai; + comp_dai->comp.type = SOF_COMP_DAI; + comp_dai->config.hdr.size = sizeof(comp_dai->config); + + /* parse one set of DAI tokens */ + ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*comp_dai), 1); + if (ret < 0) + goto free; + + /* update comp_tokens */ + ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS, + swidget->tuples, swidget->num_tuples, + sizeof(comp_dai->config), 1); + if (ret < 0) + goto free; + + dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n", + __func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index); + sof_dbg_comp_config(scomp, &comp_dai->config); + + /* now update DAI config */ + list_for_each_entry(slink, &sdev->dai_link_list, list) { + struct sof_ipc_dai_config common_config; + int i; + + if (strcmp(slink->link->name, dai->name)) + continue; + + /* Reserve memory for all hw configs, eventually freed by widget */ + config = kcalloc(slink->num_hw_configs, sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto free_comp; + } + + /* parse one set of DAI link tokens */ + ret = sof_update_ipc_object(scomp, &common_config, SOF_DAI_LINK_TOKENS, + slink->tuples, slink->num_tuples, + sizeof(common_config), 1); + if (ret < 0) + goto free_config; + + for (i = 0; i < slink->num_hw_configs; i++) { + config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config[i].format = le32_to_cpu(slink->hw_configs[i].fmt); + config[i].type = common_config.type; + config[i].dai_index = comp_dai->dai_index; + } + + switch (common_config.type) { + case SOF_DAI_INTEL_SSP: + ret = sof_link_ssp_load(scomp, slink, config, dai); + break; + case SOF_DAI_INTEL_DMIC: + ret = sof_link_dmic_load(scomp, slink, config, dai); + break; + case SOF_DAI_INTEL_HDA: + ret = sof_link_hda_load(scomp, slink, config, dai); + break; + case SOF_DAI_INTEL_ALH: + ret = sof_link_alh_load(scomp, slink, config, dai); + break; + case SOF_DAI_IMX_SAI: + ret = sof_link_sai_load(scomp, slink, config, dai); + break; + case SOF_DAI_IMX_ESAI: + ret = sof_link_esai_load(scomp, slink, config, dai); + break; + case SOF_DAI_AMD_BT: + ret = sof_link_acp_bt_load(scomp, slink, config, dai); + break; + case SOF_DAI_AMD_SP: + ret = sof_link_acp_sp_load(scomp, slink, config, dai); + break; + case SOF_DAI_AMD_DMIC: + ret = sof_link_acp_dmic_load(scomp, slink, config, dai); + break; + case SOF_DAI_MEDIATEK_AFE: + ret = sof_link_afe_load(scomp, slink, config, dai); + break; + default: + break; + } + if (ret < 0) { + dev_err(scomp->dev, "failed to load config for dai %s\n", dai->name); + goto free_config; + } + + kfree(config); + } + + return 0; +free_config: + kfree(config); +free_comp: + kfree(comp_dai); +free: + kfree(private); + dai->private = NULL; + return ret; +} + +static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget) +{ + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + struct snd_sof_dai *dai = swidget->private; + struct sof_dai_private_data *dai_data; + + if (!dai) + return; + + dai_data = dai->private; + if (dai_data) { + kfree(dai_data->comp_dai); + kfree(dai_data->dai_config); + kfree(dai_data); + } + kfree(dai); + break; + } + default: + break; + } +} + static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) { struct sof_ipc_pipe_comp_connect connect; @@ -868,6 +1599,13 @@ static enum sof_tokens pga_token_list[] = { SOF_COMP_TOKENS, }; +static enum sof_tokens dai_token_list[] = { + SOF_CORE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_DAI_TOKENS, + SOF_COMP_TOKENS, +}; + static enum sof_tokens process_token_list[] = { SOF_CORE_TOKENS, SOF_COMP_EXT_TOKENS, @@ -880,6 +1618,11 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY host_token_list, ARRAY_SIZE(host_token_list), NULL}, [snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp, host_token_list, ARRAY_SIZE(host_token_list), NULL}, + + [snd_soc_dapm_dai_in] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai, + dai_token_list, ARRAY_SIZE(dai_token_list), NULL}, + [snd_soc_dapm_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai, + dai_token_list, ARRAY_SIZE(dai_token_list), NULL}, [snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp, buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL}, [snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 187f7c46a42b..c9c72e94f696 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -554,204 +554,20 @@ int get_token_dai_type(void *elem, void *object, u32 offset) return 0; } -/* DAI */ -static const struct sof_topology_token dai_tokens[] = { - {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, - offsetof(struct sof_ipc_comp_dai, type)}, - {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_dai, dai_index)}, - {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_dai, direction)}, -}; - -/* BE DAI link */ -static const struct sof_topology_token dai_link_tokens[] = { - {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, - offsetof(struct sof_ipc_dai_config, type)}, - {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_config, dai_index)}, -}; - /* PCM */ static const struct sof_topology_token stream_tokens[] = { - {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, - SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible)}, - {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, - SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible)}, }; -/* Generic components */ -static const struct sof_topology_token comp_tokens[] = { - {SOF_TKN_COMP_PERIOD_SINK_COUNT, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_config, periods_sink)}, - {SOF_TKN_COMP_PERIOD_SOURCE_COUNT, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_config, periods_source)}, - {SOF_TKN_COMP_FORMAT, - SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, - offsetof(struct sof_ipc_comp_config, frame_fmt)}, -}; - -/* SSP */ -static const struct sof_topology_token ssp_tokens[] = { - {SOF_TKN_INTEL_SSP_CLKS_CONTROL, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_ssp_params, clks_control)}, - {SOF_TKN_INTEL_SSP_MCLK_ID, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_ssp_params, mclk_id)}, - {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, - offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)}, - {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, - get_token_u16, - offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)}, - {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, - offsetof(struct sof_ipc_dai_ssp_params, quirks)}, - {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, - get_token_u16, - offsetof(struct sof_ipc_dai_ssp_params, - tdm_per_slot_padding_flag)}, - {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, - offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)}, - -}; - -/* ALH */ -static const struct sof_topology_token alh_tokens[] = { - {SOF_TKN_INTEL_ALH_RATE, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_alh_params, rate)}, - {SOF_TKN_INTEL_ALH_CH, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_alh_params, channels)}, -}; - -/* DMIC */ -static const struct sof_topology_token dmic_tokens[] = { - {SOF_TKN_INTEL_DMIC_DRIVER_VERSION, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)}, - {SOF_TKN_INTEL_DMIC_CLK_MIN, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)}, - {SOF_TKN_INTEL_DMIC_CLK_MAX, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)}, - {SOF_TKN_INTEL_DMIC_SAMPLE_RATE, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)}, - {SOF_TKN_INTEL_DMIC_DUTY_MIN, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_params, duty_min)}, - {SOF_TKN_INTEL_DMIC_DUTY_MAX, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_params, duty_max)}, - {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, - num_pdm_active)}, - {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)}, - {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)}, - -}; - -/* ESAI */ -static const struct sof_topology_token esai_tokens[] = { - {SOF_TKN_IMX_ESAI_MCLK_ID, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_esai_params, mclk_id)}, -}; - -/* SAI */ -static const struct sof_topology_token sai_tokens[] = { - {SOF_TKN_IMX_SAI_MCLK_ID, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_sai_params, mclk_id)}, -}; - -/* Core tokens */ -static const struct sof_topology_token core_tokens[] = { - {SOF_TKN_COMP_CORE_ID, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp, core)}, -}; - -/* Component extended tokens */ -static const struct sof_topology_token comp_ext_tokens[] = { - {SOF_TKN_COMP_UUID, - SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, - offsetof(struct snd_sof_widget, uuid)}, -}; - -/* - * DMIC PDM Tokens - * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token - * as it increments the index while parsing the array of pdm tokens - * and determines the correct offset - */ -static const struct sof_topology_token dmic_pdm_tokens[] = { - {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id),}, - {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)}, - {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)}, - {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)}, - {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)}, - {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)}, - {SOF_TKN_INTEL_DMIC_PDM_SKEW, - SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)}, -}; - -/* HDA */ -static const struct sof_topology_token hda_tokens[] = { - {SOF_TKN_INTEL_HDA_RATE, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_hda_params, rate)}, - {SOF_TKN_INTEL_HDA_CH, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_hda_params, channels)}, -}; - /* Leds */ static const struct sof_topology_token led_tokens[] = { {SOF_TKN_MUTE_LED_USE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_led_control, use_led)}, - {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, offsetof(struct snd_sof_led_control, direction)}, -}; - -/* AFE */ -static const struct sof_topology_token afe_tokens[] = { - {SOF_TKN_MEDIATEK_AFE_RATE, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_mtk_afe_params, rate)}, - {SOF_TKN_MEDIATEK_AFE_CH, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_mtk_afe_params, channels)}, - {SOF_TKN_MEDIATEK_AFE_FORMAT, - SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, - offsetof(struct sof_ipc_dai_mtk_afe_params, format)}, + offsetof(struct snd_sof_led_control, use_led)}, + {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_led_control, direction)}, }; /** @@ -1116,14 +932,6 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, void *object, array_size, 1, 0); } -static void sof_dbg_comp_config(struct snd_soc_component *scomp, - struct sof_ipc_comp_config *config) -{ - dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n", - config->periods_sink, config->periods_source, - config->frame_fmt); -} - /* * Standard Kcontrols. */ @@ -1510,110 +1318,6 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, return 0; } -/** - * sof_comp_alloc - allocate and initialize buffer for a new component - * @swidget: pointer to struct snd_sof_widget containing extended data - * @ipc_size: IPC payload size that will be updated depending on valid - * extended data. - * @index: ID of the pipeline the component belongs to - * - * Return: The pointer to the new allocated component, NULL if failed. - */ -static struct sof_ipc_comp *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size, - int index) -{ - struct sof_ipc_comp *comp; - size_t total_size = *ipc_size; - size_t ext_size = sizeof(swidget->uuid); - - /* only non-zero UUID is valid */ - if (!guid_is_null(&swidget->uuid)) - total_size += ext_size; - - comp = kzalloc(total_size, GFP_KERNEL); - if (!comp) - return NULL; - - /* configure comp new IPC message */ - comp->hdr.size = total_size; - comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - comp->id = swidget->comp_id; - comp->pipeline_id = index; - comp->core = swidget->core; - - /* handle the extended data if needed */ - if (total_size > *ipc_size) { - /* append extended data to the end of the component */ - memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size); - comp->ext_data_length = ext_size; - } - - /* update ipc_size and return */ - *ipc_size = total_size; - return comp; -} - -static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct snd_sof_dai *dai) -{ - struct snd_soc_tplg_private *private = &tw->priv; - struct sof_dai_private_data *dai_data; - struct sof_ipc_comp_dai *comp_dai; - size_t ipc_size = sizeof(*comp_dai); - int ret; - - dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL); - if (!dai_data) - return -ENOMEM; - - comp_dai = (struct sof_ipc_comp_dai *) - sof_comp_alloc(swidget, &ipc_size, index); - if (!comp_dai) { - ret = -ENOMEM; - goto free; - } - - /* configure dai IPC message */ - comp_dai->comp.type = SOF_COMP_DAI; - comp_dai->config.hdr.size = sizeof(comp_dai->config); - - ret = sof_parse_tokens(scomp, comp_dai, dai_tokens, - ARRAY_SIZE(dai_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse dai tokens failed %d\n", - le32_to_cpu(private->size)); - goto free; - } - - ret = sof_parse_tokens(scomp, &comp_dai->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n", - private->size); - goto free; - } - - dev_dbg(scomp->dev, "dai %s: type %d index %d\n", - swidget->widget->name, comp_dai->type, comp_dai->dai_index); - sof_dbg_comp_config(scomp, &comp_dai->config); - - if (dai) { - dai->scomp = scomp; - dai_data->comp_dai = comp_dai; - dai->private = dai_data; - } - - return 0; - -free: - kfree(dai_data); - return ret; -} - /* bind PCM ID to host component ID */ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int dir) @@ -1734,6 +1438,21 @@ static int sof_widget_bind_event(struct snd_soc_component *scomp, return -EINVAL; } +static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples) +{ + int i; + + if (!tuples) + return -EINVAL; + + for (i = 0; i < num_tuples; i++) { + if (tuples[i].token == token_id) + return tuples[i].value.v; + } + + return -EINVAL; +} + /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1746,9 +1465,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_sof_dai *dai; enum sof_tokens *token_list; int token_list_size; - struct sof_ipc_comp comp = { - .core = SOF_DSP_PRIMARY_CORE, - }; int ret = 0; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); @@ -1771,30 +1487,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, token_list = widget_ops[w->id].token_list; token_list_size = widget_ops[w->id].token_list_size; - ret = sof_parse_tokens(scomp, &comp, core_tokens, - ARRAY_SIZE(core_tokens), tw->priv.array, - le32_to_cpu(tw->priv.size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parsing core tokens failed %d\n", - ret); - kfree(swidget); - return ret; - } - - if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) - comp.core = SOF_DSP_PRIMARY_CORE; - - swidget->core = comp.core; - - ret = sof_parse_tokens(scomp, swidget, comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens), - tw->priv.array, le32_to_cpu(tw->priv.size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parsing comp_ext_tokens failed %d\n", - ret); - kfree(swidget); - return ret; - } - /* handle any special case widgets */ switch (w->id) { case snd_soc_dapm_dai_in: @@ -1803,9 +1495,10 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (!dai) { kfree(swidget); return -ENOMEM; + } - ret = sof_widget_load_dai(scomp, index, swidget, tw, dai); + ret = sof_widget_parse_tokens(scomp, swidget, tw, token_list, token_list_size); if (!ret) ret = sof_connect_dai_widget(scomp, w, tw, dai); if (ret < 0) { @@ -1853,7 +1546,17 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, break; } - /* check IPC reply */ + if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) { + swidget->core = SOF_DSP_PRIMARY_CORE; + } else { + int core = sof_get_token_value(SOF_TKN_COMP_CORE_ID, swidget->tuples, + swidget->num_tuples); + + if (core >= 0) + swidget->core = core; + } + + /* check token parsing reply */ if (ret < 0) { dev_err(scomp->dev, "error: failed to add widget id %d type %d name : %s stream %s\n", @@ -1927,14 +1630,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp, case snd_soc_dapm_dai_out: dai = swidget->private; - if (dai) { - struct sof_dai_private_data *dai_data = dai->private; - - kfree(dai_data->comp_dai); - kfree(dai_data->dai_config); - kfree(dai_data); + if (dai) list_del(&dai->list); - } break; default: break; @@ -1970,9 +1667,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp, if (widget_ops[swidget->id].ipc_free) widget_ops[swidget->id].ipc_free(swidget); - /* free private value */ - kfree(swidget->private); - kfree(swidget->tuples); /* remove and free swidget object */ @@ -2118,589 +1812,24 @@ static int sof_dai_unload(struct snd_soc_component *scomp, return 0; } -static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - /* clock directions wrt codec */ - if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) { - /* codec is bclk provider */ - if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) - config->format |= SOF_DAI_FMT_CBP_CFP; - else - config->format |= SOF_DAI_FMT_CBP_CFC; - } else { - /* codec is bclk consumer */ - if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) - config->format |= SOF_DAI_FMT_CBC_CFP; - else - config->format |= SOF_DAI_FMT_CBC_CFC; - } - - /* inverted clocks ? */ - if (hw_config->invert_bclk) { - if (hw_config->invert_fsync) - config->format |= SOF_DAI_FMT_IB_IF; - else - config->format |= SOF_DAI_FMT_IB_NF; - } else { - if (hw_config->invert_fsync) - config->format |= SOF_DAI_FMT_NB_IF; - else - config->format |= SOF_DAI_FMT_NB_NF; - } -} - -/* - * Send IPC and set the same config for all DAIs with name matching the link - * name. Note that the function can only be used for the case that all DAIs - * have a common DAI config for now. - */ -static int sof_set_dai_config_multi(struct snd_sof_dev *sdev, u32 size, - struct snd_soc_dai_link *link, - struct sof_ipc_dai_config *config, - int num_conf, int curr_conf) -{ - struct sof_dai_private_data *dai_data; - struct snd_sof_dai *dai; - int found = 0; - int i; - - list_for_each_entry(dai, &sdev->dai_list, list) { - dai_data = dai->private; - if (!dai->name) - continue; - - if (strcmp(link->name, dai->name) == 0) { - /* - * the same dai config will be applied to all DAIs in - * the same dai link. We have to ensure that the ipc - * dai config's dai_index match to the component's - * dai_index. - */ - for (i = 0; i < num_conf; i++) - config[i].dai_index = dai_data->comp_dai->dai_index; - - dev_dbg(sdev->dev, "set DAI config for %s index %d\n", - dai->name, config[curr_conf].dai_index); - - dai->number_configs = num_conf; - dai->current_config = curr_conf; - dai_data->dai_config = kmemdup(config, size * num_conf, GFP_KERNEL); - if (!dai_data->dai_config) - return -ENOMEM; - - found = 1; - } - } - - /* - * machine driver may define a dai link with playback and capture - * dai enabled, but the dai link in topology would support both, one - * or none of them. Here print a warning message to notify user - */ - if (!found) { - dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", - link->name); - } - - return 0; -} - -static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, - struct snd_soc_dai_link *link, - struct sof_ipc_dai_config *config) -{ - return sof_set_dai_config_multi(sdev, size, link, config, 1, 0); -} - -static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config, int curr_conf) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - int num_conf = le32_to_cpu(cfg->num_hw_configs); - u32 size = sizeof(*config); - int ret; - int i; - - /* - * Parse common data, we should have 1 common data per hw_config. - */ - ret = sof_parse_token_sets(scomp, &config->ssp, ssp_tokens, - ARRAY_SIZE(ssp_tokens), private->array, - le32_to_cpu(private->size), - num_conf, size); - - if (ret != 0) { - dev_err(scomp->dev, "error: parse ssp tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - /* process all possible hw configs */ - for (i = 0; i < num_conf; i++) { - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(&hw_config[i], &config[i]); - - config[i].hdr.size = size; - - /* copy differentiating hw configs to ipc structs */ - config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate); - config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate); - config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate); - config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots); - config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width); - config[i].ssp.mclk_direction = hw_config[i].mclk_direction; - config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots); - config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots); - - dev_dbg(scomp->dev, "tplg: config SSP%d fmt %#x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d clks_control %#x\n", - config[i].dai_index, config[i].format, - config[i].ssp.mclk_rate, config[i].ssp.bclk_rate, - config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits, - config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots, - config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control); - - /* validate SSP fsync rate and channel count */ - if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) { - dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n", - config[i].dai_index); - return -EINVAL; - } - - if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) { - dev_err(scomp->dev, "error: invalid channel count for SSP%d\n", - config[i].dai_index); - return -EINVAL; - } - } - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config_multi(sdev, size, link, config, num_conf, curr_conf); - if (ret < 0) - dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n", - config->dai_index); - - return ret; -} - -static int sof_link_sai_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - u32 size = sizeof(*config); - int ret; - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); - - /* init IPC */ - memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params)); - config->hdr.size = size; - - ret = sof_parse_tokens(scomp, &config->sai, sai_tokens, - ARRAY_SIZE(sai_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse sai tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); - config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); - config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->sai.mclk_direction = hw_config->mclk_direction; - - config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); - config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots); - config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots); - - dev_info(scomp->dev, - "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", - config->dai_index, config->format, - config->sai.mclk_rate, config->sai.tdm_slot_width, - config->sai.tdm_slots, config->sai.mclk_id); - - if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) { - dev_err(scomp->dev, "error: invalid channel count for SAI%d\n", - config->dai_index); - return -EINVAL; - } - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "error: failed to save DAI config for SAI%d\n", - config->dai_index); - - return ret; -} - -static int sof_link_esai_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - u32 size = sizeof(*config); - int ret; - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); - - /* init IPC */ - memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params)); - config->hdr.size = size; - - ret = sof_parse_tokens(scomp, &config->esai, esai_tokens, - ARRAY_SIZE(esai_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse esai tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); - config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); - config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->esai.mclk_direction = hw_config->mclk_direction; - config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); - config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots); - config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots); - - dev_info(scomp->dev, - "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", - config->dai_index, config->format, - config->esai.mclk_rate, config->esai.tdm_slot_width, - config->esai.tdm_slots, config->esai.mclk_id); - - if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) { - dev_err(scomp->dev, "error: invalid channel count for ESAI%d\n", - config->dai_index); - return -EINVAL; - } - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "error: failed to save DAI config for ESAI%d\n", - config->dai_index); - - return ret; -} - -static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - u32 size = sizeof(*config); - int ret; - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); - - /* init IPC */ - memset(&config->acpdmic, 0, sizeof(struct sof_ipc_dai_acp_params)); - config->hdr.size = size; - - config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - - dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", - config->dai_index, config->acpdmic.tdm_slots, - config->acpdmic.fsync_rate); - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "ACP_DMIC failed to save DAI config for ACP%d\n", - config->dai_index); - return ret; -} - -static int sof_link_acp_bt_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - u32 size = sizeof(*config); - int ret; - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); - - /* init IPC */ - memset(&config->acpbt, 0, sizeof(struct sof_ipc_dai_acp_params)); - config->hdr.size = size; - - config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - - dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n", - config->dai_index, config->acpbt.tdm_slots, - config->acpbt.fsync_rate); - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "ACP_BT failed to save DAI config for ACP%d\n", - config->dai_index); - return ret; -} - -static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - u32 size = sizeof(*config); - int ret; - - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); - - /* init IPC */ - memset(&config->acpsp, 0, sizeof(struct sof_ipc_dai_acp_params)); - config->hdr.size = size; - - config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - - dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n", - config->dai_index, config->acpsp.tdm_slots, - config->acpsp.fsync_rate); - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "ACP_SP failed to save DAI config for ACP%d\n", - config->dai_index); - return ret; -} - -static int sof_link_afe_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - u32 size = sizeof(*config); - int ret; - - config->hdr.size = size; - - /* get any bespoke DAI tokens */ - ret = sof_parse_tokens(scomp, &config->afe, afe_tokens, - ARRAY_SIZE(afe_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "parse afe tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n", - config->afe.rate, config->afe.channels, config->afe.format); - - config->afe.stream_id = DMA_CHAN_INVALID; - - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "failed to process afe dai link %s", link->name); - - return ret; -} - -static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_fw_ready *ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &ready->version; - size_t size = sizeof(*config); - int ret, j; - - /* Ensure the entire DMIC config struct is zeros */ - memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params)); - - /* get DMIC tokens */ - ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens, - ARRAY_SIZE(dmic_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse dmic tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - /* get DMIC PDM tokens */ - ret = sof_parse_token_sets(scomp, &config->dmic.pdm[0], dmic_pdm_tokens, - ARRAY_SIZE(dmic_pdm_tokens), private->array, - le32_to_cpu(private->size), - config->dmic.num_pdm_active, - sizeof(struct sof_ipc_dai_dmic_pdm_ctrl)); - - if (ret != 0) { - dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - /* set IPC header size */ - config->hdr.size = size; - - /* debug messages */ - dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n", - config->dai_index, config->dmic.driver_ipc_version); - dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n", - config->dmic.pdmclk_min, config->dmic.pdmclk_max, - config->dmic.duty_min); - dev_dbg(scomp->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", - config->dmic.duty_max, config->dmic.fifo_fs, - config->dmic.num_pdm_active); - dev_dbg(scomp->dev, "fifo word length %hd\n", config->dmic.fifo_bits); - - for (j = 0; j < config->dmic.num_pdm_active; j++) { - dev_dbg(scomp->dev, "pdm %hd mic a %hd mic b %hd\n", - config->dmic.pdm[j].id, - config->dmic.pdm[j].enable_mic_a, - config->dmic.pdm[j].enable_mic_b); - dev_dbg(scomp->dev, "pdm %hd polarity a %hd polarity b %hd\n", - config->dmic.pdm[j].id, - config->dmic.pdm[j].polarity_mic_a, - config->dmic.pdm[j].polarity_mic_b); - dev_dbg(scomp->dev, "pdm %hd clk_edge %hd skew %hd\n", - config->dmic.pdm[j].id, - config->dmic.pdm[j].clk_edge, - config->dmic.pdm[j].skew); - } - - /* - * this takes care of backwards compatible handling of fifo_bits_b. - * It is deprecated since firmware ABI version 3.0.1. - */ - if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) - config->dmic.fifo_bits_b = config->dmic.fifo_bits; - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n", - config->dai_index); - - return ret; -} - -static int sof_link_hda_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - u32 size = sizeof(*config); - int ret; - - /* init IPC */ - memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params)); - config->hdr.size = size; - - /* get any bespoke DAI tokens */ - ret = sof_parse_tokens(scomp, &config->hda, hda_tokens, - ARRAY_SIZE(hda_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse hda tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - dev_dbg(scomp->dev, "HDA config rate %d channels %d\n", - config->hda.rate, config->hda.channels); - - config->hda.link_dma_ch = DMA_CHAN_INVALID; - - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "error: failed to process hda dai link %s", - link->name); - - return ret; -} - -static int sof_link_alh_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, - struct snd_soc_tplg_link_config *cfg, - struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &cfg->priv; - u32 size = sizeof(*config); - int ret; - - ret = sof_parse_tokens(scomp, &config->alh, alh_tokens, - ARRAY_SIZE(alh_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse alh tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; - } - - /* init IPC */ - config->hdr.size = size; - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) - dev_err(scomp->dev, "error: failed to save DAI config for ALH %d\n", - config->dai_index); - - return ret; -} +static const struct sof_topology_token common_dai_link_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct snd_sof_dai_link, type)}, +}; /* DAI link - used for any driver specific init */ -static int sof_link_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dai_link *link, +static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_token_info *token_list = ipc_tplg_ops->token_list; struct snd_soc_tplg_private *private = &cfg->priv; - struct snd_soc_tplg_hw_config *hw_config; - struct sof_ipc_dai_config common_config; - struct sof_ipc_dai_config *config; - int curr_conf; - int num_conf; - int ret; - int i; + struct snd_sof_dai_link *slink; + size_t size; + u32 token_id = 0; + int num_tuples = 0; + int ret, num_sets; if (!link->platforms) { dev_err(scomp->dev, "error: no platforms\n"); @@ -2737,104 +1866,159 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - memset(&common_config, 0, sizeof(common_config)); + slink = kzalloc(sizeof(*slink), GFP_KERNEL); + if (!slink) + return -ENOMEM; - /* get any common DAI tokens */ - ret = sof_parse_tokens(scomp, &common_config, dai_link_tokens, ARRAY_SIZE(dai_link_tokens), - private->array, le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(scomp->dev, "error: parse link tokens failed %d\n", - le32_to_cpu(private->size)); - return ret; + slink->num_hw_configs = le32_to_cpu(cfg->num_hw_configs); + slink->hw_configs = kmemdup(cfg->hw_config, + sizeof(*slink->hw_configs) * slink->num_hw_configs, + GFP_KERNEL); + if (!slink->hw_configs) { + kfree(slink); + return -ENOMEM; } - /* - * DAI links are expected to have at least 1 hw_config. - * But some older topologies might have no hw_config for HDA dai links. - */ - hw_config = cfg->hw_config; - num_conf = le32_to_cpu(cfg->num_hw_configs); - if (!num_conf) { - if (common_config.type != SOF_DAI_INTEL_HDA) { - dev_err(scomp->dev, "error: unexpected DAI config count %d!\n", - le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; - } - num_conf = 1; - curr_conf = 0; - } else { - dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d!\n", - cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id)); + slink->default_hw_cfg_id = le32_to_cpu(cfg->default_hw_config_id); + slink->link = link; - for (curr_conf = 0; curr_conf < num_conf; curr_conf++) { - if (hw_config[curr_conf].id == cfg->default_hw_config_id) - break; - } + dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d for dai link %s!\n", + slink->num_hw_configs, slink->default_hw_cfg_id, link->name); - if (curr_conf == num_conf) { - dev_err(scomp->dev, "error: default hw_config id: %d not found!\n", - le32_to_cpu(cfg->default_hw_config_id)); - return -EINVAL; - } + ret = sof_parse_tokens(scomp, slink, common_dai_link_tokens, + ARRAY_SIZE(common_dai_link_tokens), + private->array, le32_to_cpu(private->size)); + if (ret < 0) { + dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n"); + kfree(slink->hw_configs); + kfree(slink); + return ret; } - /* Reserve memory for all hw configs, eventually freed by widget */ - config = kcalloc(num_conf, sizeof(*config), GFP_KERNEL); - if (!config) - return -ENOMEM; - - /* Copy common data to all config ipc structs */ - for (i = 0; i < num_conf; i++) { - config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; - config[i].format = le32_to_cpu(hw_config[i].fmt); - config[i].type = common_config.type; - config[i].dai_index = common_config.dai_index; - } + if (!token_list) + goto out; - /* now load DAI specific data and send IPC - type comes from token */ - switch (common_config.type) { + /* calculate size of tuples array */ + num_tuples += token_list[SOF_DAI_LINK_TOKENS].count; + num_sets = slink->num_hw_configs; + switch (slink->type) { case SOF_DAI_INTEL_SSP: - ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, config, curr_conf); + token_id = SOF_SSP_TOKENS; + num_tuples += token_list[SOF_SSP_TOKENS].count * slink->num_hw_configs; break; case SOF_DAI_INTEL_DMIC: - ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, config); + token_id = SOF_DMIC_TOKENS; + num_tuples += token_list[SOF_DMIC_TOKENS].count; + + /* Allocate memory for max PDM controllers */ + num_tuples += token_list[SOF_DMIC_PDM_TOKENS].count * SOF_DAI_INTEL_DMIC_NUM_CTRL; break; case SOF_DAI_INTEL_HDA: - ret = sof_link_hda_load(scomp, index, link, cfg, hw_config + curr_conf, config); + token_id = SOF_HDA_TOKENS; + num_tuples += token_list[SOF_HDA_TOKENS].count; break; case SOF_DAI_INTEL_ALH: - ret = sof_link_alh_load(scomp, index, link, cfg, hw_config + curr_conf, config); + token_id = SOF_ALH_TOKENS; + num_tuples += token_list[SOF_ALH_TOKENS].count; break; case SOF_DAI_IMX_SAI: - ret = sof_link_sai_load(scomp, index, link, cfg, hw_config + curr_conf, config); + token_id = SOF_SAI_TOKENS; + num_tuples += token_list[SOF_SAI_TOKENS].count; break; case SOF_DAI_IMX_ESAI: - ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config); - break; - case SOF_DAI_AMD_BT: - ret = sof_link_acp_bt_load(scomp, index, link, cfg, hw_config + curr_conf, config); - break; - case SOF_DAI_AMD_SP: - ret = sof_link_acp_sp_load(scomp, index, link, cfg, hw_config + curr_conf, config); - break; - case SOF_DAI_AMD_DMIC: - ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, - config); + token_id = SOF_ESAI_TOKENS; + num_tuples += token_list[SOF_ESAI_TOKENS].count; break; case SOF_DAI_MEDIATEK_AFE: - ret = sof_link_afe_load(scomp, index, link, cfg, hw_config + curr_conf, config); + token_id = SOF_AFE_TOKENS; + num_tuples += token_list[SOF_AFE_TOKENS].count; break; default: - dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); - ret = -EINVAL; break; } - kfree(config); + /* allocate memory for tuples array */ + size = sizeof(struct snd_sof_tuple) * num_tuples; + slink->tuples = kzalloc(size, GFP_KERNEL); + if (!slink->tuples) { + kfree(slink->hw_configs); + kfree(slink); + return -ENOMEM; + } + + /* parse one set of DAI link tokens */ + ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + SOF_DAI_LINK_TOKENS, 1, slink->tuples, + num_tuples, &slink->num_tuples); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse %s for dai link %s\n", + token_list[SOF_DAI_LINK_TOKENS].name, link->name); + goto err; + } + + /* nothing more to do if there are no DAI type-specific tokens defined */ + if (!token_id || !token_list[token_id].tokens) + goto out; + + /* parse "num_sets" sets of DAI-specific tokens */ + ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + token_id, num_sets, slink->tuples, num_tuples, &slink->num_tuples); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse %s for dai link %s\n", + token_list[token_id].name, link->name); + goto err; + } + + /* for DMIC, also parse all sets of DMIC PDM tokens based on active PDM count */ + if (token_id == SOF_DMIC_TOKENS) { + num_sets = sof_get_token_value(SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, + slink->tuples, slink->num_tuples); + + if (num_sets < 0) { + dev_err(sdev->dev, "Invalid active PDM count for %s\n", link->name); + ret = num_sets; + goto err; + } + + ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + SOF_DMIC_PDM_TOKENS, num_sets, slink->tuples, + num_tuples, &slink->num_tuples); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse %s for dai link %s\n", + token_list[SOF_DMIC_PDM_TOKENS].name, link->name); + goto err; + } + } +out: + link->dobj.private = slink; + list_add(&slink->list, &sdev->dai_link_list); + + return 0; + +err: + kfree(slink->tuples); + kfree(slink->hw_configs); + kfree(slink); return ret; } +static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) +{ + struct snd_sof_dai_link *slink = dobj->private; + + if (!slink) + return 0; + + kfree(slink->tuples); + list_del(&slink->list); + kfree(slink->hw_configs); + kfree(slink); + dobj->private = NULL; + + return 0; +} + /* DAI link - used for any driver specific init */ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) @@ -3121,6 +2305,7 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { /* DAI link - used for any driver specific init */ .link_load = sof_link_load, + .link_unload = sof_link_unload, /* completion - called at completion of firmware loading */ .complete = sof_complete, From patchwork Mon Mar 14 20:05:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780777 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 53A46C433F5 for ; Mon, 14 Mar 2022 20:11:50 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 95CC118D2; Mon, 14 Mar 2022 21:10:58 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 95CC118D2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288708; bh=eQ0F73q5x+cYEqTjfiXAvssGk9YEa8QeRTdoWQa1dpc=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Rl2s7GvJwRN55v2cBBDUrEszdkPK2Qy0cgCvt6vOFs9n21lKX4hZXYnbWbyMM7Qhs F7AHsSjLlP68Sv0Q6kcQvIaLyOspxlOcNkiInERkh5pnEkt5+WnFEMi/zRl/hO8PuB dy1usKH4YHl6gNXxXmVXjcuNrYY1MP6FjDm5I58A= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 2D31AF805B5; Mon, 14 Mar 2022 21:06:12 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 38BCAF80566; Mon, 14 Mar 2022 21:06:06 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 32ECDF80525 for ; Mon, 14 Mar 2022 21:05:49 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 32ECDF80525 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GvtV/CP3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288351; x=1678824351; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eQ0F73q5x+cYEqTjfiXAvssGk9YEa8QeRTdoWQa1dpc=; b=GvtV/CP3BIiCkMBwi/ErUjoak2dDLyVjZCDihzW/6yiMqxIDpZEXDnAt nNOC/8oKvai+0L34xAUDikPF1TxoxYk6LGdvZOPMGLKQFO+8e3HUCDPhg WnanOc72/Ve0rqCU40FSYPqaWxTnCA1AF44c053j3r84IiBFtZoG2Ps9F V+vYNJggzr5zKyO6Exrg4a5dxAiSLZD+Rk7cjNTbd1k70D9Io68n1+HXh dg9PUgMAX9gHi90CclVbxBrfBN5HZPJ+APymRZefJI+DC1eWrR6rK5ppN zzo7CjpZrqY6ByEwJ3803QCiO3y4THdNor8AJu1d6UcglJnVRxtymN34O g==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563487" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563487" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339912" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 16/18] ASoC: SOF: topology: Make control parsing IPC agnostic Date: Mon, 14 Mar 2022 13:05:18 -0700 Message-Id: <20220314200520.1233427-18-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Make the control parser in topology IPC agnostic by introducing 2 new topology IPC ops, control_setup and control_free. These ops handle setting up/freeing the control data in the IPC format based on the IPC version. Along with this, modify the struct snd_sof_control to remove the IPC-specific field, control_data and replace it with the void pointer to ipc_control_data. Also, add a few new fields to store all the information parsed from topology. Finally, define and set the control setup/free ops for IPC3. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 26 ++--- sound/soc/sof/ipc.c | 2 +- sound/soc/sof/ipc3-topology.c | 151 ++++++++++++++++++++++++++++- sound/soc/sof/sof-audio.h | 20 +++- sound/soc/sof/topology.c | 177 ++++++++++------------------------ 5 files changed, 235 insertions(+), 141 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index ef61936dad59..21ee0545945d 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -67,7 +67,7 @@ static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) static void snd_sof_refresh_control(struct snd_sof_control *scontrol) { - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; int ret; @@ -97,7 +97,7 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; snd_sof_refresh_control(scontrol); @@ -118,7 +118,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; u32 value; @@ -166,7 +166,7 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; snd_sof_refresh_control(scontrol); @@ -185,7 +185,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; u32 value; @@ -214,7 +214,7 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; snd_sof_refresh_control(scontrol); @@ -233,7 +233,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; u32 value; @@ -260,7 +260,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct sof_abi_hdr *data = cdata->data; size_t size; @@ -296,7 +296,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct sof_abi_hdr *data = cdata->data; size_t size; @@ -335,7 +335,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_ctl_tlv header; const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data; @@ -409,7 +409,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; size_t data_size; @@ -482,7 +482,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; @@ -534,7 +534,7 @@ static void snd_sof_update_control(struct snd_sof_control *scontrol, struct sof_ipc_ctrl_data *local_cdata; int i; - local_cdata = scontrol->control_data; + local_cdata = scontrol->ipc_control_data; if (cdata->cmd == SOF_CTRL_CMD_BINARY) { if (cdata->num_elems != local_cdata->data->size) { diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index cf892859355a..19a294cbbb8d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -812,7 +812,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) { struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index e6aa78d492ea..96553d103c85 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -12,6 +12,9 @@ #include "sof-audio.h" #include "ops.h" +/* Full volume for default values */ +#define VOL_ZERO_DB BIT(VOLUME_FWL) + struct sof_widget_data { int ctrl_type; int ipc_cmd; @@ -743,6 +746,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp, struct sof_widget_data *wdata, size_t *size) { const struct snd_kcontrol_new *kc; + struct sof_ipc_ctrl_data *cdata; struct soc_mixer_control *sm; struct soc_bytes_ext *sbe; struct soc_enum *se; @@ -777,7 +781,8 @@ static int sof_get_control_data(struct snd_soc_component *scomp, return -EINVAL; } - wdata[i].pdata = wdata[i].control->control_data->data; + cdata = wdata[i].control->ipc_control_data; + wdata[i].pdata = cdata->data; if (!wdata[i].pdata) return -EINVAL; @@ -789,7 +794,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp, *size += wdata[i].pdata->size; /* get data type */ - switch (wdata[i].control->control_data->cmd) { + switch (cdata->cmd) { case SOF_CTRL_CMD_VOLUME: case SOF_CTRL_CMD_ENUM: case SOF_CTRL_CMD_SWITCH: @@ -1553,6 +1558,146 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * return ret; } +static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + struct sof_ipc_ctrl_data *cdata; + int ret; + + scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL); + if (!scontrol->ipc_control_data) + return -ENOMEM; + + if (scontrol->max_size < sizeof(*cdata) || + scontrol->max_size < sizeof(struct sof_abi_hdr)) { + ret = -EINVAL; + goto err; + } + + /* init the get/put bytes data */ + if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) { + dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n", + scontrol->priv_size, scontrol->max_size - sizeof(*cdata)); + ret = -EINVAL; + goto err; + } + + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size; + + cdata = scontrol->ipc_control_data; + cdata->cmd = SOF_CTRL_CMD_BINARY; + cdata->index = scontrol->index; + + if (scontrol->priv_size > 0) { + memcpy(cdata->data, scontrol->priv, scontrol->priv_size); + kfree(scontrol->priv); + + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic); + ret = -EINVAL; + goto err; + } + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { + dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + ret = -EINVAL; + goto err; + } + + if (cdata->data->size + sizeof(struct sof_abi_hdr) != scontrol->priv_size) { + dev_err(sdev->dev, "Conflict in bytes vs. priv size.\n"); + ret = -EINVAL; + goto err; + } + } + + return 0; +err: + kfree(scontrol->ipc_control_data); + return ret; +} + +static int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + struct sof_ipc_ctrl_data *cdata; + int i; + + /* init the volume get/put data */ + scontrol->size = struct_size(cdata, chanv, scontrol->num_channels); + + scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->ipc_control_data) + return -ENOMEM; + + cdata = scontrol->ipc_control_data; + cdata->index = scontrol->index; + + /* set cmd for mixer control */ + if (scontrol->max == 1) { + cdata->cmd = SOF_CTRL_CMD_SWITCH; + return 0; + } + + cdata->cmd = SOF_CTRL_CMD_VOLUME; + + /* set default volume values to 0dB in control */ + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } + + return 0; +} + +static int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + struct sof_ipc_ctrl_data *cdata; + + /* init the enum get/put data */ + scontrol->size = struct_size(cdata, chanv, scontrol->num_channels); + + scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->ipc_control_data) + return -ENOMEM; + + cdata = scontrol->ipc_control_data; + cdata->index = scontrol->index; + cdata->cmd = SOF_CTRL_CMD_ENUM; + + return 0; +} + +static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + switch (scontrol->info_type) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + return sof_ipc3_control_load_volume(sdev, scontrol); + case SND_SOC_TPLG_CTL_BYTES: + return sof_ipc3_control_load_bytes(sdev, scontrol); + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + return sof_ipc3_control_load_enum(sdev, scontrol); + default: + break; + } + + return 0; +} + +static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) +{ + struct sof_ipc_free fcomp; + + fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE; + fcomp.hdr.size = sizeof(fcomp); + fcomp.id = scontrol->comp_id; + + /* send IPC to the DSP */ + return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0); +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -1651,6 +1796,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { .widget = tplg_ipc3_widget_ops, .route_setup = sof_ipc3_route_setup, + .control_setup = sof_ipc3_control_setup, + .control_free = sof_ipc3_control_free, .token_list = ipc3_token_list, }; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index bde86e078e08..a14b872ea261 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -30,8 +30,15 @@ #define WIDGET_IS_DAI(id) ((id) == snd_soc_dapm_dai_in || (id) == snd_soc_dapm_dai_out) +/* + * Volume fractional word length define to 16 sets + * the volume linear gain value to use Qx.16 format + */ +#define VOLUME_FWL 16 + struct snd_sof_widget; struct snd_sof_route; +struct snd_sof_control; /** * struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets @@ -59,11 +66,15 @@ struct sof_ipc_tplg_widget_ops { * @token_list: List of all tokens supported by the IPC version. The size of the token_list * array should be SOF_TOKEN_COUNT. The unused elements in the array will be * initialized to 0. + * @control_setup: Function pointer for setting up kcontrol IPC-specific data + * @control_free: Function pointer for freeing kcontrol IPC-specific data */ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; int (*route_setup)(struct snd_sof_dev *sdev, struct snd_sof_route *sroute); const struct sof_token_info *token_list; + int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); + int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); }; /** struct snd_sof_tuple - Tuple info @@ -165,13 +176,20 @@ struct snd_sof_led_control { /* ALSA SOF Kcontrol device */ struct snd_sof_control { struct snd_soc_component *scomp; + const char *name; int comp_id; int min_volume_step; /* min volume step for volume_table */ int max_volume_step; /* max volume step for volume_table */ int num_channels; unsigned int access; u32 readback_offset; /* offset to mmapped data if used */ - struct sof_ipc_ctrl_data *control_data; + int info_type; + int index; /* pipeline ID */ + void *priv; /* private data copied from topology */ + size_t priv_size; /* size of private data */ + size_t max_size; + void *ipc_control_data; + int max; /* applicable to volume controls */ u32 size; /* cdata size */ u32 *volume_table; /* volume table computed from tlv data*/ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c9c72e94f696..f7adf058a768 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -28,15 +28,9 @@ #define VOL_TWENTIETH_ROOT_OF_TEN 73533 /* 40th root of 10 in Q1.16 fixed-point notation*/ #define VOL_FORTIETH_ROOT_OF_TEN 69419 -/* - * Volume fractional word length define to 16 sets - * the volume linear gain value to use Qx.16 format - */ -#define VOLUME_FWL 16 + /* 0.5 dB step value in topology TLV */ #define VOL_HALF_DB_STEP 50 -/* Full volume for default values */ -#define VOL_ZERO_DB BIT(VOLUME_FWL) /* TLV data items */ #define TLV_ITEMS 3 @@ -944,16 +938,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_mixer_control *mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); - struct sof_ipc_ctrl_data *cdata; int tlv[TLV_ITEMS]; - unsigned int i; int ret; /* validate topology data */ - if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) { - ret = -EINVAL; - goto out; - } + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; /* * If control has more than 2 channels we need to override the info. This is because even if @@ -964,48 +954,26 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, if (le32_to_cpu(mc->num_channels) > 2) kc->info = snd_sof_volume_info; - /* init the volume get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(mc->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) { - ret = -ENOMEM; - goto out; - } - scontrol->comp_id = sdev->next_comp_id; scontrol->min_volume_step = le32_to_cpu(mc->min); scontrol->max_volume_step = le32_to_cpu(mc->max); scontrol->num_channels = le32_to_cpu(mc->num_channels); - scontrol->control_data->index = kc->index; - /* set cmd for mixer control */ - if (le32_to_cpu(mc->max) == 1) { - scontrol->control_data->cmd = SOF_CTRL_CMD_SWITCH; + scontrol->max = le32_to_cpu(mc->max); + if (le32_to_cpu(mc->max) == 1) goto skip; - } - - scontrol->control_data->cmd = SOF_CTRL_CMD_VOLUME; /* extract tlv data */ if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) { dev_err(scomp->dev, "error: invalid TLV data\n"); - ret = -EINVAL; - goto out_free; + return -EINVAL; } /* set up volume table */ ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); if (ret < 0) { dev_err(scomp->dev, "error: setting up volume table\n"); - goto out_free; - } - - /* set default volume values to 0dB in control */ - cdata = scontrol->control_data; - for (i = 0; i < scontrol->num_channels; i++) { - cdata->chanv[i].channel = i; - cdata->chanv[i].value = VOL_ZERO_DB; + return ret; } skip: @@ -1016,7 +984,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, if (ret != 0) { dev_err(scomp->dev, "error: parse led tokens failed %d\n", le32_to_cpu(mc->priv.size)); - goto out_free_table; + goto err; } dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", @@ -1024,12 +992,10 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, return 0; -out_free_table: +err: if (le32_to_cpu(mc->max) > 1) kfree(scontrol->volume_table); -out_free: - kfree(scontrol->control_data); -out: + return ret; } @@ -1046,17 +1012,8 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) return -EINVAL; - /* init the enum get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(ec->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; - scontrol->comp_id = sdev->next_comp_id; scontrol->num_channels = le32_to_cpu(ec->num_channels); - scontrol->control_data->index = kc->index; - scontrol->control_data->cmd = SOF_CTRL_CMD_ENUM; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); @@ -1070,77 +1027,27 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct snd_soc_tplg_ctl_hdr *hdr) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_ctrl_data *cdata; struct snd_soc_tplg_bytes_control *control = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; - size_t max_size = sbe->max; size_t priv_size = le32_to_cpu(control->priv.size); - int ret; - - if (max_size < sizeof(struct sof_ipc_ctrl_data) || - max_size < sizeof(struct sof_abi_hdr)) { - ret = -EINVAL; - goto out; - } - - /* init the get/put bytes data */ - if (priv_size > max_size - sizeof(struct sof_ipc_ctrl_data)) { - dev_err(scomp->dev, "err: bytes data size %zu exceeds max %zu.\n", - priv_size, max_size - sizeof(struct sof_ipc_ctrl_data)); - ret = -EINVAL; - goto out; - } - - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + priv_size; - - scontrol->control_data = kzalloc(max_size, GFP_KERNEL); - cdata = scontrol->control_data; - if (!scontrol->control_data) { - ret = -ENOMEM; - goto out; - } + scontrol->max_size = sbe->max; scontrol->comp_id = sdev->next_comp_id; - scontrol->control_data->cmd = SOF_CTRL_CMD_BINARY; - scontrol->control_data->index = kc->index; - dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", - scontrol->comp_id, scontrol->num_channels); + dev_dbg(scomp->dev, "tplg: load kcontrol index %d\n", scontrol->comp_id); - if (le32_to_cpu(control->priv.size) > 0) { - memcpy(cdata->data, control->priv.data, - le32_to_cpu(control->priv.size)); + /* copy the private data */ + if (priv_size > 0) { + scontrol->priv = kzalloc(priv_size, GFP_KERNEL); + if (!scontrol->priv) + return -ENOMEM; - if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(scomp->dev, "error: Wrong ABI magic 0x%08x.\n", - cdata->data->magic); - ret = -EINVAL; - goto out_free; - } - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, - cdata->data->abi)) { - dev_err(scomp->dev, - "error: Incompatible ABI version 0x%08x.\n", - cdata->data->abi); - ret = -EINVAL; - goto out_free; - } - if (cdata->data->size + sizeof(struct sof_abi_hdr) != - le32_to_cpu(control->priv.size)) { - dev_err(scomp->dev, - "error: Conflict in bytes vs. priv size.\n"); - ret = -EINVAL; - goto out_free; - } + memcpy(scontrol->priv, control->priv.data, priv_size); + scontrol->priv_size = priv_size; } return 0; - -out_free: - kfree(scontrol->control_data); -out: - return ret; } /* external kcontrol init - used for any driver specific init */ @@ -1163,8 +1070,14 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, if (!scontrol) return -ENOMEM; + scontrol->name = kstrdup(hdr->name, GFP_KERNEL); + if (!scontrol->name) + return -ENOMEM; + scontrol->scomp = scomp; scontrol->access = kc->access; + scontrol->info_type = le32_to_cpu(hdr->ops.info); + scontrol->index = kc->index; switch (le32_to_cpu(hdr->ops.info)) { case SND_SOC_TPLG_CTL_VOLSW: @@ -1215,22 +1128,26 @@ static int sof_control_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_free fcomp; + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct snd_sof_control *scontrol = dobj->private; + int ret = 0; - dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scomp->name); + dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scontrol->name); - fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE; - fcomp.hdr.size = sizeof(fcomp); - fcomp.id = scontrol->comp_id; + if (ipc_tplg_ops->control_free) { + ret = ipc_tplg_ops->control_free(sdev, scontrol); + if (ret < 0) + dev_err(scomp->dev, "failed to free control: %s\n", scontrol->name); + } - kfree(scontrol->control_data); + /* free all data before returning in case of error too */ + kfree(scontrol->ipc_control_data); + kfree(scontrol->priv); + kfree(scontrol->name); list_del(&scontrol->list); kfree(scontrol); - /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, - fcomp.hdr.cmd, &fcomp, sizeof(fcomp), - NULL, 0); + + return ret; } /* @@ -1657,7 +1574,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, dev_warn(scomp->dev, "unsupported kcontrol_type\n"); goto out; } - kfree(scontrol->control_data); + kfree(scontrol->ipc_control_data); list_del(&scontrol->list); kfree(scontrol); } @@ -2167,10 +2084,22 @@ static int sof_complete(struct snd_soc_component *scomp) struct snd_sof_widget *swidget, *comp_swidget; const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + struct snd_sof_control *scontrol; int ret; + /* first update all control IPC structures based on the IPC version */ + if (ipc_tplg_ops->control_setup) + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + ret = ipc_tplg_ops->control_setup(sdev, scontrol); + if (ret < 0) { + dev_err(sdev->dev, "failed updating IPC struct for control %s\n", + scontrol->name); + return ret; + } + } + /* - * now update all widget IPC structures. If any of the ipc_setup callbacks fail, the + * then update all widget IPC structures. If any of the ipc_setup callbacks fail, the * topology will be removed and all widgets will be unloaded resulting in freeing all * associated memories. */ From patchwork Mon Mar 14 20:05:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780778 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0F3B1C433F5 for ; Mon, 14 Mar 2022 20:12:04 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 57E0417DD; Mon, 14 Mar 2022 21:11:12 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 57E0417DD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288722; bh=o9mAhem1fMAhHakxRbYGaHAwvOG4JLgvwqq9NzfK0zE=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=IktgpY9Bd71cycAzfO8VaBcsuFBOpc9VknWtYTjn4XW01/4RE+K6eZlRoFEE0eIKF 8fojgD6bk5DpUn11kIOfyPIxYUdSYk73vTYbSqxbJJE+/THoEi7wtwsje3Us98BtWS w7XfH54x7vLKZKQKvkS8Sn/7Q1K+Z4D3ghf3pClM= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id A7FDFF805BA; Mon, 14 Mar 2022 21:06:12 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 07437F8056F; Mon, 14 Mar 2022 21:06:07 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E4F19F80529 for ; Mon, 14 Mar 2022 21:05:50 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E4F19F80529 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="PYEjsOzm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288352; x=1678824352; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=o9mAhem1fMAhHakxRbYGaHAwvOG4JLgvwqq9NzfK0zE=; b=PYEjsOzmz5+KXRfz5HjxGJFOMmStVUQiUeh9pEb7DvOl6wg/Z2Cp4Tf5 uAhwF4ne7hPTp+Ouzr+IC1h/TqhUbL1EBnHNuQoMuGWjsbdJjYDhaipbh lbqj4RLm+QxxxBzt5jhpDVl0yTYUy1BSRo8TmfEJV06IRlOW3Uz3KyH/P Nee3cns3aH8flzHrKRY1OvLTwL/Mu3lSTP1JbmdSj3j+ivQIVXzMxji2/ x6TWIAsLH1YL72T0KaBatH2gyvEJsTQmGE2SlA8LraDuZHu450BezomK8 RBlYDIGWDmE4nNagNAIcVmLTt119HXhKZu0YOAAmftrcURzFwxVU5kPvl Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563488" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563488" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339913" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 17/18] ASoC: SOF: topology: Make widget binding IPC agnostic Date: Mon, 14 Mar 2022 13:05:19 -0700 Message-Id: <20220314200520.1233427-19-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Make widget binding in the topology parser IPC agnostic by introducing a new op, bind_event, in struct ipc_tplg_widget_ops. Also set the op for all widget types in the IPC3 topology ops. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 192 +++++++++++++++++++++++++++++- sound/soc/sof/topology.c | 217 ++-------------------------------- 2 files changed, 202 insertions(+), 207 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 96553d103c85..ea1311192877 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -8,6 +8,7 @@ // #include +#include #include "sof-priv.h" #include "sof-audio.h" #include "ops.h" @@ -1698,6 +1699,194 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0); } +/* send pcm params ipc */ +static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_pcm_params_reply ipc_params_reply; + struct snd_pcm_hw_params *params; + struct sof_ipc_pcm_params pcm; + struct snd_sof_pcm *spcm; + int ret; + + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); + if (!spcm) { + dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name); + return -EINVAL; + } + + params = &spcm->params[dir]; + + /* set IPC PCM params */ + memset(&pcm, 0, sizeof(pcm)); + pcm.hdr.size = sizeof(pcm); + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; + pcm.comp_id = swidget->comp_id; + pcm.params.hdr.size = sizeof(pcm.params); + pcm.params.direction = dir; + pcm.params.sample_valid_bytes = params_width(params) >> 3; + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + pcm.params.rate = params_rate(params); + pcm.params.channels = params_channels(params); + pcm.params.host_period_bytes = params_period_bytes(params); + + /* set format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24: + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + break; + case SNDRV_PCM_FORMAT_S32: + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; + break; + default: + return -EINVAL; + } + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + &ipc_params_reply, sizeof(ipc_params_reply)); + if (ret < 0) + dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__, + swidget->widget->name); + + return ret; +} + + /* send stream trigger ipc */ +static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + /* set IPC stream params */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd; + stream.comp_id = swidget->comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (ret < 0) + dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name); + + return ret; +} + +static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_soc_component *scomp; + int stream = SNDRV_PCM_STREAM_CAPTURE; + struct snd_sof_pcm *spcm; + int ret = 0; + + if (!swidget) + return 0; + + scomp = swidget->scomp; + + dev_dbg(scomp->dev, "received event %d for widget %s\n", + event, w->name); + + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); + if (!spcm) { + dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__, + swidget->widget->name); + return -EINVAL; + } + + /* process events */ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); + return 0; + } + + /* set pcm params */ + ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream); + if (ret < 0) { + dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n", + __func__, swidget->widget->name); + break; + } + + /* start trigger */ + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START); + if (ret < 0) + dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__, + swidget->widget->name); + break; + case SND_SOC_DAPM_POST_PMD: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(scomp->dev, + "POST_PMD event ignored, KWD pipeline will remain RUNNING\n"); + return 0; + } + + /* stop trigger */ + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); + if (ret < 0) + dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__, + swidget->widget->name); + + /* pcm free */ + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); + if (ret < 0) + dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__, + swidget->widget->name); + break; + default: + break; + } + + return ret; +} + +/* event handlers for keyword detect component */ +static const struct snd_soc_tplg_widget_events sof_kwd_events[] = { + {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event}, +}; + +static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp, + struct snd_sof_widget *swidget, u16 event_type) +{ + struct sof_ipc_comp *ipc_comp; + + /* validate widget event type */ + switch (event_type) { + case SOF_KEYWORD_DETECT_DAPM_EVENT: + /* only KEYWORD_DETECT comps should handle this */ + if (swidget->id != snd_soc_dapm_effect) + break; + + ipc_comp = swidget->private; + if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT) + break; + + /* bind event to keyword detect comp */ + return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events, + ARRAY_SIZE(sof_kwd_events), event_type); + default: + break; + } + + dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type, + swidget->widget->name); + + return -EINVAL; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -1790,7 +1979,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL}, [snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp, - process_token_list, ARRAY_SIZE(process_token_list), NULL}, + process_token_list, ARRAY_SIZE(process_token_list), + sof_ipc3_widget_bind_event}, }; static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f7adf058a768..70677a36c304 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "sof-priv.h" #include "sof-audio.h" @@ -135,171 +134,6 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so return 0; } -/* send pcm params ipc */ -static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) -{ - struct sof_ipc_pcm_params_reply ipc_params_reply; - struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_pcm_params pcm; - struct snd_pcm_hw_params *params; - struct snd_sof_pcm *spcm; - int ret; - - memset(&pcm, 0, sizeof(pcm)); - - /* get runtime PCM params using widget's stream name */ - spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); - if (!spcm) { - dev_err(scomp->dev, "error: cannot find PCM for %s\n", - swidget->widget->name); - return -EINVAL; - } - - params = &spcm->params[dir]; - - /* set IPC PCM params */ - pcm.hdr.size = sizeof(pcm); - pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; - pcm.comp_id = swidget->comp_id; - pcm.params.hdr.size = sizeof(pcm.params); - pcm.params.direction = dir; - pcm.params.sample_valid_bytes = params_width(params) >> 3; - pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; - pcm.params.rate = params_rate(params); - pcm.params.channels = params_channels(params); - pcm.params.host_period_bytes = params_period_bytes(params); - - /* set format */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16: - pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; - break; - case SNDRV_PCM_FORMAT_S24: - pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; - break; - case SNDRV_PCM_FORMAT_S32: - pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; - break; - default: - return -EINVAL; - } - - /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), - &ipc_params_reply, sizeof(ipc_params_reply)); - if (ret < 0) - dev_err(scomp->dev, "error: pcm params failed for %s\n", - swidget->widget->name); - - return ret; -} - - /* send stream trigger ipc */ -static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) -{ - struct snd_soc_component *scomp = swidget->scomp; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_stream stream; - struct sof_ipc_reply reply; - int ret; - - /* set IPC stream params */ - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd; - stream.comp_id = swidget->comp_id; - - /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); - if (ret < 0) - dev_err(scomp->dev, "error: failed to trigger %s\n", - swidget->widget->name); - - return ret; -} - -static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_soc_component *scomp; - int stream = SNDRV_PCM_STREAM_CAPTURE; - struct snd_sof_pcm *spcm; - int ret = 0; - - if (!swidget) - return 0; - - scomp = swidget->scomp; - - dev_dbg(scomp->dev, "received event %d for widget %s\n", - event, w->name); - - /* get runtime PCM params using widget's stream name */ - spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); - if (!spcm) { - dev_err(scomp->dev, "error: cannot find PCM for %s\n", - swidget->widget->name); - return -EINVAL; - } - - /* process events */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - if (spcm->stream[stream].suspend_ignored) { - dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); - return 0; - } - - /* set pcm params */ - ret = ipc_pcm_params(swidget, stream); - if (ret < 0) { - dev_err(scomp->dev, - "error: failed to set pcm params for widget %s\n", - swidget->widget->name); - break; - } - - /* start trigger */ - ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START); - if (ret < 0) - dev_err(scomp->dev, - "error: failed to trigger widget %s\n", - swidget->widget->name); - break; - case SND_SOC_DAPM_POST_PMD: - if (spcm->stream[stream].suspend_ignored) { - dev_dbg(scomp->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n"); - return 0; - } - - /* stop trigger */ - ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); - if (ret < 0) - dev_err(scomp->dev, - "error: failed to trigger widget %s\n", - swidget->widget->name); - - /* pcm free */ - ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); - if (ret < 0) - dev_err(scomp->dev, - "error: failed to trigger widget %s\n", - swidget->widget->name); - break; - default: - break; - } - - return ret; -} - -/* event handlers for keyword detect component */ -static const struct snd_soc_tplg_widget_events sof_kwd_events[] = { - {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event}, -}; - static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) { /* we only support dB scale TLV type at the moment */ @@ -1323,38 +1157,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s return ret; } -static int sof_widget_bind_event(struct snd_soc_component *scomp, - struct snd_sof_widget *swidget, - u16 event_type) -{ - struct sof_ipc_comp *ipc_comp; - - /* validate widget event type */ - switch (event_type) { - case SOF_KEYWORD_DETECT_DAPM_EVENT: - /* only KEYWORD_DETECT comps should handle this */ - if (swidget->id != snd_soc_dapm_effect) - break; - - ipc_comp = swidget->private; - if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT) - break; - - /* bind event to keyword detect comp */ - return snd_soc_tplg_widget_bind_event(swidget->widget, - sof_kwd_events, - ARRAY_SIZE(sof_kwd_events), - event_type); - default: - break; - } - - dev_err(scomp->dev, - "error: invalid event type %d for widget %s\n", - event_type, swidget->widget->name); - return -EINVAL; -} - static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples) { int i; @@ -1486,14 +1288,17 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, /* bind widget to external event */ if (tw->event_type) { - ret = sof_widget_bind_event(scomp, swidget, - le16_to_cpu(tw->event_type)); - if (ret) { - dev_err(scomp->dev, "error: widget event binding failed\n"); - kfree(swidget->private); - kfree(swidget->tuples); - kfree(swidget); - return ret; + if (widget_ops[w->id].bind_event) { + ret = widget_ops[w->id].bind_event(scomp, swidget, + le16_to_cpu(tw->event_type)); + if (ret) { + dev_err(scomp->dev, "widget event binding failed for %s\n", + swidget->widget->name); + kfree(swidget->private); + kfree(swidget->tuples); + kfree(swidget); + return ret; + } } } From patchwork Mon Mar 14 20:05:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ranjani Sridharan X-Patchwork-Id: 12780776 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7886CC433F5 for ; Mon, 14 Mar 2022 20:11:31 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A48C31884; Mon, 14 Mar 2022 21:10:39 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A48C31884 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1647288689; bh=D4oK3/Yt88ByafrlpUL4x3bzy7SU57aD3JwElD4+SuQ=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=HnyiVgLitG42ehlhcUGzOIp52UiMQicHMJXWtDAjpGuiuBV+Ih4ysNN1Mu7zmrTEQ EaB/IAKVL82SK4PmPd7+14PABR4qJ8FFxRdkRT65edLPukq+LR9Fy5QfDlPt6azTUi XR3uibhkG8SslGSQP4qt0uPdX38dO2gI1oZ5c/mc= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id AD8B4F805B1; Mon, 14 Mar 2022 21:06:11 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 24AD7F8055C; Mon, 14 Mar 2022 21:06:05 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 49068F8052F for ; Mon, 14 Mar 2022 21:05:51 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 49068F8052F Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="DyW5xWt+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1647288353; x=1678824353; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=D4oK3/Yt88ByafrlpUL4x3bzy7SU57aD3JwElD4+SuQ=; b=DyW5xWt+xV6SuyLBJKfzd2Ti8/us+9ul+mpr0t8vCgJB3UZpKWjDxOZ0 hNWrMAksHX6157rKMnoU/o2NJdoAMUWndWjGkerOjuuHmhSoeSYeIlVfZ yz6sfevzX6K4Mkg8vucf9fE9/KCNHRNHwbYajwZLO5O8H6tQEuNdMbAog gVmJhmljf7oVMK9n9jtCMyekjr6iw83SjjgD5tptc2n74UhleAmLazWho LCh6I7xMsLKdVRKDJKifGk/vqW0yz94e5K4M3AVBkVD2VtQpAsf3j0Jaj /cExwthx2juLZll5bih4YF+Fu2rUNmtBypO6cecYY6tHEiqyAqnzzs6fm Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10286"; a="342563489" X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="342563489" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 X-IronPort-AV: E=Sophos;i="5.90,181,1643702400"; d="scan'208";a="634339917" Received: from pmishr1-mobl1.amr.corp.intel.com (HELO rsridh2-mobl1.localdomain) ([10.254.25.117]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Mar 2022 13:05:34 -0700 From: Ranjani Sridharan To: alsa-devel@alsa-project.org Subject: [PATCH 18/18] ASoC: SOF: topology: remove snd_sof_complete_pipeline() Date: Mon, 14 Mar 2022 13:05:20 -0700 Message-Id: <20220314200520.1233427-20-ranjani.sridharan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> References: <20220314200520.1233427-1-ranjani.sridharan@linux.intel.com> MIME-Version: 1.0 Cc: =tiwai@suse.com, =?utf-8?q?P=C3=A9ter_Ujfalusi?= , Pierre-Louis Bossart , Ranjani Sridharan , broonie@kernel.org, Bard Liao X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add a new topology IPC op, pipeline_complete in struct ipc_tplg_ops and set the op for IPC3. Replace the calls to snd_sof_complete_pipeline() with the calls to the topology IPC pipeline_complete op. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart --- sound/soc/sof/ipc3-topology.c | 23 +++++++++++++++++++++++ sound/soc/sof/sof-audio.c | 18 ++++++++++++------ sound/soc/sof/sof-audio.h | 4 ++-- sound/soc/sof/topology.c | 23 ----------------------- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index ea1311192877..fe1d5a56080a 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1887,6 +1887,28 @@ static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp, return -EINVAL; } +static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) +{ + struct sof_ipc_pipe_ready ready; + struct sof_ipc_reply reply; + int ret; + + dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", + swidget->widget->name, swidget->comp_id); + + memset(&ready, 0, sizeof(ready)); + ready.hdr.size = sizeof(ready); + ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE; + ready.comp_id = swidget->comp_id; + + ret = sof_ipc_tx_message(sdev->ipc, ready.hdr.cmd, &ready, sizeof(ready), &reply, + sizeof(reply)); + if (ret < 0) + return ret; + + return 1; +} + /* token list for each topology object */ static enum sof_tokens host_token_list[] = { SOF_CORE_TOKENS, @@ -1988,6 +2010,7 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { .route_setup = sof_ipc3_route_setup, .control_setup = sof_ipc3_control_setup, .control_free = sof_ipc3_control_free, + .pipeline_complete = sof_ipc3_complete_pipeline, .token_list = ipc3_token_list, }; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index c02dcad03b23..683c290bb69a 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -362,6 +362,7 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) { + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; struct snd_soc_dapm_widget *widget; int i, ret, num_widgets; @@ -432,10 +433,12 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in if (pipe_widget->complete) continue; - pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget); - if (pipe_widget->complete < 0) { - ret = pipe_widget->complete; - goto widget_free; + if (ipc_tplg_ops->pipeline_complete) { + pipe_widget->complete = ipc_tplg_ops->pipeline_complete(sdev, pipe_widget); + if (pipe_widget->complete < 0) { + ret = pipe_widget->complete; + goto widget_free; + } } } @@ -657,8 +660,11 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) return ret; } - swidget->complete = - snd_sof_complete_pipeline(sdev, swidget); + if (ipc_tplg_ops->pipeline_complete) { + swidget->complete = ipc_tplg_ops->pipeline_complete(sdev, swidget); + if (swidget->complete < 0) + return swidget->complete; + } break; default: break; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index a14b872ea261..622d43707b27 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -68,6 +68,7 @@ struct sof_ipc_tplg_widget_ops { * initialized to 0. * @control_setup: Function pointer for setting up kcontrol IPC-specific data * @control_free: Function pointer for freeing kcontrol IPC-specific data + * @pipeline_complete: Function pointer for pipeline complete IPC */ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; @@ -75,6 +76,7 @@ struct sof_ipc_tplg_ops { const struct sof_token_info *token_list; int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); + int (*pipeline_complete)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); }; /** struct snd_sof_tuple - Tuple info @@ -318,8 +320,6 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev, * be freed by snd_soc_unregister_component, */ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file); -int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget); /* * Stream IPC diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 70677a36c304..367fbe2d5b31 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1825,29 +1825,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, return ret; } -int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget) -{ - struct sof_ipc_pipe_ready ready; - struct sof_ipc_reply reply; - int ret; - - dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", - swidget->widget->name, swidget->comp_id); - - memset(&ready, 0, sizeof(ready)); - ready.hdr.size = sizeof(ready); - ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE; - ready.comp_id = swidget->comp_id; - - ret = sof_ipc_tx_message(sdev->ipc, - ready.hdr.cmd, &ready, sizeof(ready), &reply, - sizeof(reply)); - if (ret < 0) - return ret; - return 1; -} - /** * sof_set_pipe_widget - Set pipe_widget for a component * @sdev: pointer to struct snd_sof_dev