[PATCH RFC 08/15] ASoC: audio-graph-card2: add Multi CPU/Codec support
Kuninori Morimoto
kuninori.morimoto.gx at renesas.com
Tue Jun 22 03:15:11 CEST 2021
From: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
This patch adds Multi CPU/Codec support to audio-graph-card2.
One note today is that ASoC doesn't support N CPUs to M CODECs
(It supports "1 CPU to N Codecs" or "N CPUs to N Codecs").
Multi CPU/Codec support needs to have extra node (X) to indicate it.
<- multi_CPU ->
<-- multi_Codec -->
******
CPU1 <--> * * <--> Codec1
CPU2 <--> * * <--> Codec2
******
sound {
compatible = "audio-graph-card2";
(A) links = <&multi>;
};
(X) multi_CPU_CODEC {
compatible = "audio-graph-card2-multi";
/* for CPU */
(B) multi: ports at 0 {
port at 0 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
port at 1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
/* for Codec */
ports at 1 {
port at 0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
port at 1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
};
};
CPU {
ports {
bitclock-master;
frame-master;
port at 0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
port at 1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
};
};
Codec {
ports {
port at 0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
port at 1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
};
};
"links" need to indicate Multi connection's CPU node (A)(B).
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
---
include/sound/graph_card.h | 3 +
sound/soc/generic/audio-graph-card2.c | 173 ++++++++++++++++++++++++++
2 files changed, 176 insertions(+)
diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h
index 03df4c5a7151..d0ccb7afda78 100644
--- a/include/sound/graph_card.h
+++ b/include/sound/graph_card.h
@@ -18,6 +18,7 @@ struct graph_custom_hooks {
int (*hook_post)(struct asoc_simple_priv *priv);
GRAPH_CUSTOM custom_normal;
GRAPH_CUSTOM custom_dpcm;
+ GRAPH_CUSTOM custom_multi;
};
int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
@@ -28,5 +29,7 @@ int audio_graph2_link_normal(struct asoc_simple_priv *priv,
struct device_node *lnk, struct link_info *li);
int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
struct device_node *lnk, struct link_info *li);
+int audio_graph2_link_multi(struct asoc_simple_priv *priv,
+ struct device_node *lnk, struct link_info *li);
#endif /* __GRAPH_CARD_H */
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index b288975ffde2..ece0f7d28437 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -134,14 +134,66 @@
...
};
};
+
+
+ ************************************
+ Multi-CPU/Codec
+ ************************************
+
+<- multi_CPU ->
+ <-- multi_Codec -->
+ ******
+CPU1 <--> * * <--> Codec1
+CPU2 <--> * * <--> Codec2
+ ******
+ *NOTE*
+ N cpus to M codecs is not yet supported
+ at ASoC framework for now.
+
+ sound {
+ compatible = "audio-graph-card2";
+
+ links = <&multi>;
+ };
+
+ multi_CPU_CODEC {
+ compatible = "audio-graph-card2-multi";
+
+ multi: ports at 0 {
+ port at 0 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
+ port at 1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
+ };
+ ports at 1 {
+ port at 0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
+ port at 1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
+ };
+};
+
+ CPU {
+ ports {
+ bitclock-master;
+ frame-master;
+ port at 0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
+ port at 1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
+ };
+ };
+
+ Codec {
+ ports {
+ port at 0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
+ port at 1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
+ };
+ };
*/
enum graph_type {
GRAPH_NORMAL,
GRAPH_DPCM,
+ GRAPH_MULTI,
};
#define GRAPH_COMPATIBLE_DPCM "audio-graph-card2-dsp"
+#define GRAPH_COMPATIBLE_MULTI "audio-graph-card2-multi"
#define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
@@ -166,6 +218,8 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
if (strcmp(string, GRAPH_COMPATIBLE_DPCM) == 0)
type = GRAPH_DPCM;
+ else if (strcmp(string, GRAPH_COMPATIBLE_MULTI) == 0)
+ type = GRAPH_MULTI;
end:
#ifdef DEBUG
{
@@ -179,6 +233,9 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
else
str = "DPCM Back-End";
break;
+ case GRAPH_MULTI:
+ str = "MULTI";
+ break;
default:
break;
}
@@ -649,6 +706,78 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
}
EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm);
+int audio_graph2_link_multi(struct asoc_simple_priv *priv,
+ struct device_node *lnk,
+ struct link_info *li)
+{
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+ struct device_node *top = of_get_parent(lnk);
+ struct device_node *first_rep = NULL;
+ struct device_node *ports = lnk;
+ struct device_node *port;
+ char dai_name[64];
+ int is_cpu = 1;
+ int i;
+
+ /*
+ * top: MULTI {
+ * compatible = "audio-graph-card2-multi";
+ *
+ * // CPU
+ * loop-0 ports at 0 {
+ * port at 0 { ep: endpoint { remote-endpoint = <&r_ep>; }; };
+ * ...
+ * };
+ * // Codec
+ * loop-1 ports at 1 {
+ * ...
+ * };
+ * };
+ */
+ports_loop:
+ i = 0;
+ for_each_port_of_node(ports, port) {
+ struct device_node *ep = port_to_endpoint(port);
+ struct device_node *rep = of_graph_get_remote_endpoint(ep);
+ int ret, is_single_links = 0;
+
+ if (!first_rep)
+ first_rep = rep;
+
+ ret = graph_parse_node(priv, rep, li, i,
+ is_cpu ? &is_single_links : NULL);
+
+ of_node_put(ep);
+ of_node_put(rep);
+
+ if (ret < 0)
+ return ret;
+
+ if (is_cpu) {
+ struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, i);
+
+ asoc_simple_canonicalize_cpu(cpus, is_single_links);
+ }
+
+ i++;
+ }
+
+ /*
+ * 1st turn was for CPU ports (is_cpu = 1)
+ * 2nd turn is for Codec ports (is_cpu = 0)
+ */
+ is_cpu--;
+ if (is_cpu == 0) {
+ ports = of_get_next_child(top, ports);
+ goto ports_loop;
+ }
+
+ snprintf(dai_name, sizeof(dai_name), "multi-%pOFP", top);
+
+ return graph_link_init(priv, first_rep, li, 1, dai_name);
+}
+EXPORT_SYMBOL_GPL(audio_graph2_link_multi);
+
static int graph_link(struct asoc_simple_priv *priv,
struct graph_custom_hooks *hooks,
enum graph_type gtype,
@@ -672,6 +801,12 @@ static int graph_link(struct asoc_simple_priv *priv,
else
func = audio_graph2_link_dpcm;
break;
+ case GRAPH_MULTI:
+ if (hooks && hooks->custom_multi)
+ func = hooks->custom_multi;
+ else
+ func = audio_graph2_link_multi;
+ break;
}
if (!func) {
@@ -734,6 +869,41 @@ static int graph_count_dsp(struct asoc_simple_priv *priv,
return 0;
}
+static int graph_count_multi(struct asoc_simple_priv *priv,
+ struct device_node *lnk,
+ struct link_info *li)
+{
+ struct device_node *top = of_get_parent(lnk);
+ struct device_node *cpu_ports = lnk;
+ struct device_node *codec_ports = of_get_next_child(top, cpu_ports);
+
+ of_node_get(cpu_ports); /* for vs of_get_next_child() */
+
+ /*
+ * MULTI {
+ * compatible = "audio-graph-card2-multi";
+ *
+ * // CPU
+ * => lnk: ports at 0 {
+ * port at 0 { endpoint { ... }; };
+ * ...
+ * };
+ * // Codec
+ * ports at 1 {
+ * port at 0 { endpoint { ... }; };
+ * ...
+ * };
+ * };
+ */
+ li->num[li->link].cpus = of_graph_get_port_count(cpu_ports);
+ li->num[li->link].codecs = of_graph_get_port_count(codec_ports);
+
+ of_node_put(top);
+ of_node_put(codec_ports);
+
+ return 0;
+}
+
static int graph_count(struct asoc_simple_priv *priv,
struct graph_custom_hooks *hooks,
enum graph_type gtype,
@@ -756,6 +926,9 @@ static int graph_count(struct asoc_simple_priv *priv,
case GRAPH_DPCM:
func = graph_count_dsp;
break;
+ case GRAPH_MULTI:
+ func = graph_count_multi;
+ break;
}
if (!func) {
--
2.25.1
More information about the Alsa-devel
mailing list