Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: audio-graph-card2: add Multi CPU/Codec support

This patch adds Multi CPU/Codec support to audio-graph-card2.
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 = "audio-graph-card2";

(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>
Link: https://lore.kernel.org/r/871r4qn8pk.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Kuninori Morimoto and committed by
Mark Brown
c8c74939 6e5f68fe

+186 -10
+186 -10
sound/soc/generic/audio-graph-card2.c
··· 69 69 port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; }; 70 70 }; 71 71 72 + ************************************ 73 + Multi-CPU/Codec 74 + ************************************ 75 + 76 + It has connection part (= X) and list part (= y). 77 + links indicates connection part of CPU side (= A). 78 + 79 + +-+ (A) +-+ 80 + CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 81 + CPU2 --(y) | | | | (y)-- Codec2 82 + +-+ +-+ 83 + 84 + sound { 85 + compatible = "audio-graph-card2"; 86 + 87 + (A) links = <&mcpu>; 88 + 89 + multi { 90 + ports@0 { 91 + (X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; 92 + (y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; 93 + (y) port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; 94 + }; 95 + ports@1 { 96 + (X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; 97 + (y) port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; 98 + (y) port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; 99 + }; 100 + }; 101 + }; 102 + 103 + CPU { 104 + ports { 105 + bitclock-master; 106 + frame-master; 107 + port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; 108 + port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; 109 + }; 110 + }; 111 + 112 + Codec { 113 + ports { 114 + port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; 115 + port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; 116 + }; 117 + }; 118 + 72 119 */ 73 120 74 121 enum graph_type { 75 122 GRAPH_NORMAL, 123 + 124 + GRAPH_MULTI, /* don't use ! Use this only in __graph_get_type() */ 76 125 }; 77 126 127 + #define GRAPH_NODENAME_MULTI "multi" 128 + 78 129 #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") 130 + 131 + static enum graph_type __graph_get_type(struct device_node *lnk) 132 + { 133 + struct device_node *np; 134 + 135 + /* 136 + * target { 137 + * ports { 138 + * => lnk: port@0 { ... }; 139 + * port@1 { ... }; 140 + * }; 141 + * }; 142 + */ 143 + np = of_get_parent(lnk); 144 + if (of_node_name_eq(np, "ports")) 145 + np = of_get_parent(np); 146 + 147 + if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) 148 + return GRAPH_MULTI; 149 + 150 + return GRAPH_NORMAL; 151 + } 79 152 80 153 static enum graph_type graph_get_type(struct asoc_simple_priv *priv, 81 154 struct device_node *lnk) 82 155 { 83 - enum graph_type type = GRAPH_NORMAL; 156 + enum graph_type type = __graph_get_type(lnk); 157 + 158 + /* GRAPH_MULTI here means GRAPH_NORMAL */ 159 + if (type == GRAPH_MULTI) 160 + type = GRAPH_NORMAL; 84 161 85 162 #ifdef DEBUG 86 163 { ··· 168 91 } 169 92 #endif 170 93 return type; 94 + } 95 + 96 + static int graph_lnk_is_multi(struct device_node *lnk) 97 + { 98 + return __graph_get_type(lnk) == GRAPH_MULTI; 99 + } 100 + 101 + static struct device_node *graph_get_next_multi_ep(struct device_node **port) 102 + { 103 + struct device_node *ports = of_get_parent(*port); 104 + struct device_node *ep = NULL; 105 + struct device_node *rep = NULL; 106 + 107 + /* 108 + * multi { 109 + * ports { 110 + * => lnk: port@0 { ... }; 111 + * port@1 { ep { ... = rep0 } }; 112 + * port@2 { ep { ... = rep1 } }; 113 + * ... 114 + * }; 115 + * }; 116 + * 117 + * xxx { 118 + * port@0 { rep0 }; 119 + * port@1 { rep1 }; 120 + * }; 121 + */ 122 + do { 123 + *port = of_get_next_child(ports, *port); 124 + if (!*port) 125 + break; 126 + } while (!of_node_name_eq(*port, "port")); 127 + 128 + if (*port) { 129 + ep = port_to_endpoint(*port); 130 + rep = of_graph_get_remote_endpoint(ep); 131 + } 132 + 133 + of_node_put(ep); 134 + of_node_put(ports); 135 + 136 + return rep; 171 137 } 172 138 173 139 static const struct snd_soc_ops graph_ops = { ··· 378 258 if (!dai_link->name) { 379 259 struct snd_soc_dai_link_component *cpus = dlc; 380 260 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx); 261 + char *cpu_multi = ""; 262 + char *codec_multi = ""; 263 + 264 + if (dai_link->num_cpus > 1) 265 + cpu_multi = "_multi"; 266 + if (dai_link->num_codecs > 1) 267 + codec_multi = "_multi"; 381 268 382 269 switch (gtype) { 383 270 case GRAPH_NORMAL: 384 271 /* run is_cpu only. see audio_graph2_link_normal() */ 385 272 if (is_cpu) 386 - asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", 387 - cpus->dai_name, codecs->dai_name); 273 + asoc_simple_set_dailink_name(dev, dai_link, "%s%s-%s%s", 274 + cpus->dai_name, cpu_multi, 275 + codecs->dai_name, codec_multi); 388 276 break; 389 277 default: 390 278 break; ··· 415 287 struct device_node *port, 416 288 struct link_info *li, int is_cpu) 417 289 { 418 - struct device_node *ep = port_to_endpoint(port); 290 + struct device_node *ep; 291 + int ret = 0; 419 292 420 - /* Need Multi support later */ 421 - return __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); 293 + if (graph_lnk_is_multi(port)) { 294 + int idx; 295 + 296 + of_node_get(port); 297 + 298 + for (idx = 0;; idx++) { 299 + ep = graph_get_next_multi_ep(&port); 300 + if (!ep) 301 + break; 302 + 303 + ret = __graph_parse_node(priv, gtype, ep, 304 + li, is_cpu, idx); 305 + of_node_put(ep); 306 + if (ret < 0) 307 + break; 308 + } 309 + } else { 310 + /* Single CPU / Codec */ 311 + ep = port_to_endpoint(port); 312 + ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); 313 + of_node_put(ep); 314 + } 315 + 316 + return ret; 422 317 } 423 318 424 319 static void graph_parse_daifmt(struct device_node *node, ··· 505 354 unsigned int daifmt = 0, daiclk = 0; 506 355 unsigned int bit_frame = 0; 507 356 508 - /* Need Multi support later */ 509 - ep = port_to_endpoint(port); 357 + if (graph_lnk_is_multi(port)) { 358 + of_node_get(port); 359 + ep = graph_get_next_multi_ep(&port); 360 + port = of_get_parent(ep); 361 + } else { 362 + ep = port_to_endpoint(port); 363 + } 364 + 510 365 ports = of_get_parent(port); 511 366 512 367 /* ··· 619 462 620 463 static int graph_counter(struct device_node *lnk) 621 464 { 622 - /* Need Multi support later */ 623 - return 1; 465 + /* 466 + * Multi CPU / Codec 467 + * 468 + * multi { 469 + * ports { 470 + * => lnk: port@0 { ... }; 471 + * port@1 { ... }; 472 + * port@2 { ... }; 473 + * ... 474 + * }; 475 + * }; 476 + * 477 + * ignore first lnk part 478 + */ 479 + if (graph_lnk_is_multi(lnk)) 480 + return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; 481 + /* 482 + * Single CPU / Codec 483 + */ 484 + else 485 + return 1; 624 486 } 625 487 626 488 static int graph_count_normal(struct asoc_simple_priv *priv,