From patchwork Fri Sep 10 01:22:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 12484211 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E768C433F5 for ; Fri, 10 Sep 2021 01:24:32 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id CF0AB610C8 for ; Fri, 10 Sep 2021 01:24:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org CF0AB610C8 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=renesas.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-project.org 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 5F74916C0; Fri, 10 Sep 2021 03:23:40 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 5F74916C0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1631237070; bh=lc1icJ162vouWYxZX+CMYnIriIS2aewjmM4YBVjpEWU=; h=Date:From:Subject:To:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=jEfhyAX92dXZQdE8O7fJ4dVq2OFNg/gLbJG/OuWEY4u4lC0PUnd0jwzUhcuU6Pf15 MQevxtyJ/7nOWazAMewTl22Qo4UYWsFQxcZLvdFNztLLy5+xjspDS04fSPuVurM8/6 cUMBVRqzInISGIrFLg58/Szf72nr9mECt1W210is= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 66AECF804E4; Fri, 10 Sep 2021 03:22:27 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id BB07BF804FF; Fri, 10 Sep 2021 03:22:25 +0200 (CEST) Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by alsa1.perex.cz (Postfix) with ESMTP id EEE32F804FB for ; Fri, 10 Sep 2021 03:22:20 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz EEE32F804FB Date: 10 Sep 2021 10:22:20 +0900 X-IronPort-AV: E=Sophos;i="5.85,282,1624287600"; d="scan'208";a="93549095" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 10 Sep 2021 10:22:20 +0900 Received: from mercury.renesas.com (unknown [10.166.252.133]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 866924017D77; Fri, 10 Sep 2021 10:22:20 +0900 (JST) Message-ID: <87lf45usvn.wl-kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH v3 06/16] ASoC: rich-graph-card: add Multi CPU/Codec support User-Agent: Wanderlust/2.15.9 Emacs/26.3 Mule/6.0 To: Mark Brown In-Reply-To: <87tuitusy4.wl-kuninori.morimoto.gx@renesas.com> References: <87tuitusy4.wl-kuninori.morimoto.gx@renesas.com> MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Cc: Linux-ALSA 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" From: Kuninori Morimoto This patch adds Multi CPU/Codec support to rich-graph-card. Multi CPU/Codec will have connection part (= X) and CPU/Codec list part (= y). links indicates connection part of CPU side (= A). +-+ (A) +-+ CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 CPU2 --(y) | | | | (y)-- Codec2 +-+ +-+ sound { compatible = "rich-graph-card"; (A) links = <&mcpu>; multi { ports@0 { (X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; (y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; (y) port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; }; ports@1 { (X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; (y) port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; (y) port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; }; }; }; CPU { ports { bitclock-master; frame-master; port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; }; }; Codec { ports { port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; }; }; Link: https://lore.kernel.org/r/87k0xszlep.wl-kuninori.morimoto.gx@renesas.com Link: https://lore.kernel.org/r/20210804171748.GC26252@sirena.org.uk Signed-off-by: Kuninori Morimoto --- sound/soc/generic/rich-graph-card.c | 196 ++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/rich-graph-card.c b/sound/soc/generic/rich-graph-card.c index a01a7c575622..6ce7001fab2e 100644 --- a/sound/soc/generic/rich-graph-card.c +++ b/sound/soc/generic/rich-graph-card.c @@ -69,18 +69,95 @@ port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; }; }; + ************************************ + Multi-CPU/Codec + ************************************ + +It has connection part (= X) and list part (= y). +links indicates connection part of CPU side (= A). + + +-+ (A) +-+ + CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 + CPU2 --(y) | | | | (y)-- Codec2 + +-+ +-+ + + sound { + compatible = "rich-graph-card"; + +(A) links = <&mcpu>; + + multi { + ports@0 { +(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; +(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; +(y) port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; + }; + ports@1 { +(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; +(y) port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; +(y) port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; + }; + }; + }; + + CPU { + ports { + bitclock-master; + frame-master; + port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; + port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; + }; + }; + + Codec { + ports { + port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; + port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; + }; + }; + */ enum graph_type { GRAPH_NORMAL, + + GRAPH_MULTI, /* don't use ! Use this only in __graph_get_type() */ }; +#define GRAPH_NODENAME_MULTI "multi" + #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") +static enum graph_type __graph_get_type(struct device_node *lnk) +{ + struct device_node *np; + + /* + * target { + * ports { + * => lnk: port@0 { ... }; + * port@1 { ... }; + * }; + * }; + */ + np = of_get_parent(lnk); + if (of_node_name_eq(np, "ports")) + np = of_get_parent(np); + + if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) + return GRAPH_MULTI; + + return GRAPH_NORMAL; +} + static enum graph_type graph_get_type(struct asoc_simple_priv *priv, struct device_node *lnk) { - enum graph_type type = GRAPH_NORMAL; + enum graph_type type = __graph_get_type(lnk); + + /* GRAPH_MULTI here means GRAPH_NORMAL */ + if (type == GRAPH_MULTI) + type = GRAPH_NORMAL; #ifdef DEBUG { @@ -93,6 +170,49 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv, return type; } +static int graph_lnk_is_multi(struct device_node *lnk) +{ + return __graph_get_type(lnk) == GRAPH_MULTI; +} + +static struct device_node *graph_get_next_multi_ep(struct device_node **port) +{ + struct device_node *ports = of_get_parent(*port); + struct device_node *ep = NULL; + struct device_node *rep = NULL; + + /* + * multi { + * ports { + * => lnk: port@0 { ... }; + * port@1 { ep { ... = rep0 } }; + * port@2 { ep { ... = rep1 } }; + * ... + * }; + * }; + * + * xxx { + * port@0 { rep0 }; + * port@1 { rep1 }; + * }; + */ + do { + *port = of_get_next_child(ports, *port); + if (!*port) + break; + } while (!of_node_name_eq(*port, "port")); + + if (*port) { + ep = port_to_endpoint(*port); + rep = of_graph_get_remote_endpoint(ep); + } + + of_node_put(ep); + of_node_put(ports); + + return rep; +} + static const struct snd_soc_ops graph_ops = { .startup = asoc_simple_startup, .shutdown = asoc_simple_shutdown, @@ -258,13 +378,21 @@ static int __graph_parse_node(struct asoc_simple_priv *priv, if (!dai_link->name) { struct snd_soc_dai_link_component *cpus = dlc; struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx); + char *cpu_multi = ""; + char *codec_multi = ""; + + if (dai_link->num_cpus > 1) + cpu_multi = "_multi"; + if (dai_link->num_codecs > 1) + codec_multi = "_multi"; switch (gtype) { case GRAPH_NORMAL: /* run is_cpu only. see rich_graph_link_normal() */ if (is_cpu) - asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", - cpus->dai_name, codecs->dai_name); + asoc_simple_set_dailink_name(dev, dai_link, "%s%s-%s%s", + cpus->dai_name, cpu_multi, + codecs->dai_name, codec_multi); break; default: break; @@ -287,10 +415,33 @@ static int graph_parse_node(struct asoc_simple_priv *priv, struct device_node *port, struct link_info *li, int is_cpu) { - struct device_node *ep = port_to_endpoint(port); + struct device_node *ep; + int ret = 0; - /* Need Multi support later */ - return __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + if (graph_lnk_is_multi(port)) { + int idx; + + of_node_get(port); + + for (idx = 0;; idx++) { + ep = graph_get_next_multi_ep(&port); + if (!ep) + break; + + ret = __graph_parse_node(priv, gtype, ep, + li, is_cpu, idx); + of_node_put(ep); + if (ret < 0) + break; + } + } else { + /* Single CPU / Codec */ + ep = port_to_endpoint(port); + ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + of_node_put(ep); + } + + return ret; } static void graph_parse_daifmt(struct device_node *node, @@ -354,8 +505,14 @@ static void graph_link_init(struct asoc_simple_priv *priv, unsigned int daifmt = 0, daiclk = 0; unsigned int bit_frame = 0; - /* Need Multi support later */ - ep = port_to_endpoint(port); + if (graph_lnk_is_multi(port)) { + of_node_get(port); + ep = graph_get_next_multi_ep(&port); + port = of_get_parent(ep); + } else { + ep = port_to_endpoint(port); + } + ports = of_get_parent(port); /* @@ -462,8 +619,27 @@ static int graph_link(struct asoc_simple_priv *priv, static int graph_counter(struct device_node *lnk) { - /* Need Multi support later */ - return 1; + /* + * Multi CPU / Codec + * + * multi { + * ports { + * => lnk: port@0 { ... }; + * port@1 { ... }; + * port@2 { ... }; + * ... + * }; + * }; + * + * ignore first lnk part + */ + if (graph_lnk_is_multi(lnk)) + return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; + /* + * Single CPU / Codec + */ + else + return 1; } static int graph_count_normal(struct asoc_simple_priv *priv,