All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
To: Mark Brown <broonie@kernel.org>
Cc: Linux-ALSA <alsa-devel@alsa-project.org>
Subject: [PATCH v3 06/16] ASoC: rich-graph-card: add Multi CPU/Codec support
Date: 10 Sep 2021 10:22:20 +0900	[thread overview]
Message-ID: <87lf45usvn.wl-kuninori.morimoto.gx@renesas.com> (raw)
In-Reply-To: <87tuitusy4.wl-kuninori.morimoto.gx@renesas.com>


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

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 <kuninori.morimoto.gx@renesas.com>
---
 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,
-- 
2.25.1


  parent reply	other threads:[~2021-09-10  1:24 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-10  1:20 [PATCH v3 00/16] ASoC: Add Rich Graph Card support Kuninori Morimoto
2021-09-10  1:21 ` [PATCH v3 01/16] ASoC: test-component: add Test Component YAML bindings Kuninori Morimoto
2021-10-01 20:11   ` Mark Brown
2021-09-10  1:21 ` [PATCH v3 02/16] ASoC: test-component: add Test Component for Sound debug/test Kuninori Morimoto
2021-09-10  1:21 ` [PATCH v3 03/16] ASoC: simple-card-utils: add asoc_graph_is_ports0() Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 04/16] ASoC: simple-card-utils: add codec2codec support Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 05/16] ASoC: add Rich Graph Card driver Kuninori Morimoto
2021-09-12 10:24   ` kernel test robot
2021-09-12 10:24     ` kernel test robot
2021-09-10  1:22 ` Kuninori Morimoto [this message]
2021-09-10  1:22 ` [PATCH v3 07/16] ASoC: rich-graph-card: add DPCM support Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 08/16] ASoC: rich-graph-card: add Codec2Codec support Kuninori Morimoto
2021-09-12  6:43   ` kernel test robot
2021-09-12  6:43     ` kernel test robot
2021-09-10  1:22 ` [PATCH v3 09/16] ASoC: add Rich Graph Card Yaml Document Kuninori Morimoto
2021-10-01 21:06   ` Mark Brown
2021-10-04  1:50     ` Kuninori Morimoto
2021-10-05 17:26       ` Mark Brown
2021-09-10  1:22 ` [PATCH v3 10/16] ASoC: add Rich Graph Card Custom Sample Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 11/16] ASoC: rich-graph-card-sample.dtsi: add Sample DT for Normal (Single) Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 12/16] ASoC: rich-graph-card-sample.dtsi: add Sample DT for Normal (Nulti) Kuninori Morimoto
2021-09-10  1:22 ` [PATCH v3 13/16] ASoC: rich-graph-card-sample.dtsi: add DPCM sample (Single) Kuninori Morimoto
2021-09-10  1:23 ` [PATCH v3 14/16] ASoC: rich-graph-card-sample.dtsi: add DPCM sample (Multi) Kuninori Morimoto
2021-09-10  1:23 ` [PATCH v3 15/16] ASoC: rich-graph-card-sample.dtsi: add Codec2Codec sample (Single) Kuninori Morimoto
2021-09-10  1:23 ` [PATCH v3 16/16] ASoC: rich-graph-card-sample.dtsi: add Codec2Codec sample (Multi) Kuninori Morimoto
2021-09-29 22:23 ` [PATCH v3 00/16] ASoC: Add Rich Graph Card support Kuninori Morimoto
2021-09-30 12:15   ` Mark Brown
2021-09-30 22:38     ` Kuninori Morimoto
2021-10-01  5:43 ` Péter Ujfalusi
2021-10-01  6:48   ` Kuninori Morimoto
2021-10-01 20:01     ` Mark Brown
2021-10-03 23:52       ` Kuninori Morimoto
2021-10-04 16:54         ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lf45usvn.wl-kuninori.morimoto.gx@renesas.com \
    --to=kuninori.morimoto.gx@renesas.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.