From 50ba0232fd5312410f1b65247e774244f89a628e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 20:50:36 +0200 Subject: Merging upstream version 6.8.9. Signed-off-by: Daniel Baumann --- sound/soc/generic/audio-graph-card.c | 1 - .../generic/audio-graph-card2-custom-sample.dtsi | 380 ++++++++++++++++++--- sound/soc/generic/audio-graph-card2.c | 284 ++++++++++++--- sound/soc/generic/simple-card-utils.c | 20 +- 4 files changed, 594 insertions(+), 91 deletions(-) (limited to 'sound/soc/generic') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 76a9f1e8cd..83e3ba773f 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 8acaa2ddb3..9efd31206c 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -58,12 +58,32 @@ * | |-> codec13 * +-+ * - * [Multi-CPU/Codec] + * [Multi-CPU/Codec-0] * +-+ +-+ * cpu1 <--| |<-@--------->| |-> codec1 * cpu2 <--| | | |-> codec2 * +-+ +-+ * + * [Multi-CPU/Codec-1] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu8 <--| |<----------->| |-> codec14 + * cpu9 <--| |<---+------->| |-> codec15 + * +-+ \------>| |-> codec16 + * +-+ + * + * [Multi-CPU/Codec-2] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu10 <-| |<----------->| |-> codec17 + * cpu11 <-| |<-----+----->| |-> codec18 + * cpu12 <-| |<----/ +-+ + * +-+ + * * [DPCM] * * CPU3/CPU4 are converting rate to 44100 @@ -144,15 +164,38 @@ */ &cpu0 - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * cpu7/codec12/codec13 + */ &sm0 /* - * [Multi-CPU/Codec]: cpu side only + * [Multi-CPU/Codec-0]: cpu side only * cpu1/cpu2/codec1/codec2 */ &mcpu0 + /* + * [Multi-CPU/Codec-1]: cpu side only + * cpu8/cpu9/codec14/codec15/codec16 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu1 + + /* + * [Multi-CPU/Codec-2]: cpu side only + * cpu10/cpu11/cpu12/codec17/codec18 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu2 + /* * [DPCM]: both FE / BE * cpu3/cpu4/codec3 @@ -182,64 +225,259 @@ #address-cells = <1>; #size-cells = <0>; + /* + * [Multi-CPU-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; - /* [Multi-CPU] */ - mcpu0: port@0 { reg = <0>; mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; - port@1 { reg = <1>; mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; - port@2 { reg = <2>; mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; + mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */ }; - /* [Multi-Codec] */ + /* + * [Multi-Codec-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; - port@1 { reg = <1>; mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; - port@2 { reg = <2>; mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; + port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */ }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +---+ + * cpu5 <-@--* *-----@--->|x a|-> codec4 + * cpu6 <-@--* * | b|-> codec5 + * **** +---+ + */ ports@2 { reg = <2>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; }; - port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; }; - port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; }; + port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */ }; - /* [Codec2Codec-Multi]::CPU */ + /* + * [Codec2Codec-Multi]::CPU + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@3 { reg = <3>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; }; - port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; }; - port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; }; + port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */ }; - /* [Codec2Codec-Multi]::Codec */ + /* + * [Codec2Codec-Multi]::Codec + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@4 { reg = <4>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; }; - port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; }; - port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; }; }; + port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */ }; - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * + * +---+ + * cpu7 <-@------->|X A|-> codec12 + * | B|-> codec13 + * +---+ + */ ports@5 { reg = <5>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; }; }; - port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; }; - port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; }; + port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */ + }; + + /* + * [Multi-CPU-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@6 { + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */ + mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */ + mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */ + mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */ + }; + }; + + /* + * [Multi-Codec-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@7 { + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */ + mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */ + mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */ + mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */ + }; + }; + + /* + * [Multi-CPU-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@8 { + reg = <8>; + #address-cells = <1>; + #size-cells = <0>; + mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */ + mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */ + mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */ + mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */ + }; + }; + + /* + * [Multi-Codec-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@9 { + reg = <9>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */ + mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */ + mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */ + mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */ + }; }; }; @@ -252,11 +490,27 @@ #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::FE */ + /* + * [DPCM]::FE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; }; fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; }; - /* [DPCM-Multi]::FE */ + /* + * [DPCM-Multi]::FE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; }; fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; }; }; @@ -266,10 +520,26 @@ #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::BE */ + /* + * [DPCM]::BE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; }; }; }; @@ -277,7 +547,13 @@ codec2codec { #address-cells = <1>; #size-cells = <0>; - /* [Codec2Codec] */ + /* + * [Codec2Codec] + * + * +-@(c2c)-> codec6 + * | + * +--------> codec7 + */ ports@0 { reg = <0>; @@ -289,7 +565,18 @@ port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; }; }; - /* [Codec2Codec-Multi] */ + /* + * [Codec2Codec-Multi] + * + * +-+ + * +-@(c2c_m)-->| |-> codec8 + * | | |-> codec9 + * | +-+ + * | +-+ + * +----------->| |-> codec10 + * | |-> codec11 + * +-+ + */ ports@1 { reg = <1>; @@ -323,9 +610,9 @@ /* [Normal] */ cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; - /* [Multi-CPU] */ - port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; - port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; + /* [Multi-CPU-0] */ + port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; }; + port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; }; /* [DPCM]::FE */ port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; }; @@ -337,6 +624,14 @@ /* [Semi-Multi] */ sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; }; + + /* [Multi-CPU-1] */ + port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; }; + port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; }; + /* [Multi-CPU-2] */ + port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; }; + port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; }; + port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; }; }; }; @@ -363,9 +658,9 @@ /* [Normal] */ port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; }; - /* [Multi-Codec] */ - port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; - port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; + /* [Multi-Codec-0] */ + port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; }; + port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; }; /* [DPCM]::BE */ port@3 { @@ -395,6 +690,13 @@ port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; }; port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; }; + /* [Multi-Codec-1] */ + port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; }; + port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; }; + port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; }; + /* [Multi-Codec-2] */ + port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; }; + port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; }; }; }; }; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 7146611df7..62606e20be 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -8,7 +8,6 @@ // based on ${LINUX}/sound/soc/generic/audio-graph-card.c #include #include -#include #include #include #include @@ -83,32 +82,32 @@ Multi-CPU/Codec ************************************ -It has connection part (= X) and list part (= y). -links indicates connection part of CPU side (= A). +It has link connection part (= X,x) and list part (= A,B,a,b). +"links" is connection part of CPU side (= @). - +-+ (A) +-+ - CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 - CPU2 --(y) | | | | (y)-- Codec2 - +-+ +-+ + +----+ +---+ + CPU1 --|A X| <-@----> |x a|-- Codec1 + CPU2 --|B | | b|-- Codec2 + +----+ +---+ - sound { - compatible = "audio-graph-card2"; + sound { + compatible = "audio-graph-card2"; -(A) links = <&mcpu>; +(@) 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@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; - }; - ports@1 { -(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; -(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; -(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; - }; + multi { + ports@0 { +(@) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; // (X) to pair + port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; // (A) Multi Element + port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; // (B) Multi Element + }; + ports@1 { + port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; // (x) to pair + port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; // (a) Multi Element + port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; // (b) Multi Element }; }; + }; CPU { ports { @@ -328,9 +327,9 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port) /* * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ep { ... = rep0 } }; - * port@2 { ep { ... = rep1 } }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ep { ... = rep0 } }; // Multi Element + * port@2 { ep { ... = rep1 } }; // Multi Element * ... * }; * }; @@ -504,40 +503,203 @@ static int __graph_parse_node(struct simple_util_priv *priv, return 0; } -static int graph_parse_node(struct simple_util_priv *priv, - enum graph_type gtype, - struct device_node *port, - struct link_info *li, int is_cpu) +static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, + int *nm_idx, int cpu_idx, + struct device_node *mcpu_port) { - struct device_node *ep; - int ret = 0; + /* + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu0 <--|A 1|<--------->|4 a|-> codec0 + * cpu1 <--|B 2|<-----+--->|5 b|-> codec1 + * cpu2 <--|C 3|<----/ +---+ + * +---+ + * + * multi { + * ports { + * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair + * port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element + * mcpu0_ep_0 { ... = mcodec0_ep_0; }; }; // (1) connected Codec + * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element + * mcpu1_ep_0 { ... = mcodec1_ep_0; }; }; // (2) connected Codec + * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element + * mcpu2_ep_0 { ... = mcodec1_ep_1; }; }; // (3) connected Codec + * }; + * + * ports { + * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair + * port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element + * mcodec0_ep_0 { ... = mcpu0_ep_0; }; }; // (4) connected CPU + * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element + * mcodec1_ep_0 { ... = mcpu1_ep_0; }; // (5) connected CPU + * mcodec1_ep_1 { ... = mcpu2_ep_0; }; }; // (5) connected CPU + * }; + * }; + */ + struct device_node *mcpu_ep = port_to_endpoint(mcpu_port); + struct device_node *mcpu_ep_n = mcpu_ep; + struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL); + struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top); + struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top); + struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top); + struct device_node *mcodec_ports = of_get_parent(mcodec_port_top); + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + int ret = -EINVAL; - if (graph_lnk_is_multi(port)) { - int idx; + if (cpu_idx > dai_link->num_cpus) + goto mcpu_err; - of_node_get(port); + while (1) { + struct device_node *mcodec_ep_n; + struct device_node *mcodec_port_i; + struct device_node *mcodec_port; + int codec_idx; - for (idx = 0;; idx++) { - ep = graph_get_next_multi_ep(&port); - if (!ep) - break; + if (*nm_idx > nm_max) + break; - ret = __graph_parse_node(priv, gtype, ep, - li, is_cpu, idx); - of_node_put(ep); - if (ret < 0) + mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n); + if (!mcpu_ep_n) { + ret = 0; + break; + } + + mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n); + mcodec_port = of_get_parent(mcodec_ep_n); + + if (mcodec_ports != of_get_parent(mcodec_port)) + goto mcpu_err; + + codec_idx = 0; + mcodec_port_i = of_get_next_child(mcodec_ports, NULL); + while (1) { + if (codec_idx > dai_link->num_codecs) + goto mcodec_err; + + mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i); + + if (!mcodec_port_i) + goto mcodec_err; + + if (mcodec_port_i == mcodec_port) break; + + codec_idx++; } - } else { - /* Single CPU / Codec */ - ep = port_to_endpoint(port); - ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + + dai_link->ch_maps[*nm_idx].cpu = cpu_idx; + dai_link->ch_maps[*nm_idx].codec = codec_idx; + + (*nm_idx)++; + + of_node_put(mcodec_port_i); +mcodec_err: + of_node_put(mcodec_port); + of_node_put(mcpu_ep_n); + of_node_put(mcodec_ep_n); + } +mcpu_err: + of_node_put(mcpu_ep); + of_node_put(mcpu_port_top); + of_node_put(mcpu_ep_top); + of_node_put(mcodec_ep_top); + of_node_put(mcodec_port_top); + of_node_put(mcodec_ports); + + return ret; +} + +static int graph_parse_node_multi(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct device *dev = simple_priv_to_dev(priv); + struct device_node *ep; + int ret = -ENOMEM; + int nm_idx = 0; + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + + /* + * create ch_maps if CPU:Codec = N:M + * DPCM is out of scope + */ + if (gtype != GRAPH_DPCM && !dai_link->ch_maps && + dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && + dai_link->num_cpus != dai_link->num_codecs) { + + dai_link->ch_maps = devm_kcalloc(dev, nm_max, + sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL); + if (!dai_link->ch_maps) + goto multi_err; + } + + for (int idx = 0;; idx++) { + /* + * multi { + * ports { + * port@0 { ... }; // to pair + * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element + * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element + * }; + * }; + * + * cpu { + * ports { + * port@0 { cpu1_ep { ... = mcpu1_ep };}; + * }; + * }; + */ + 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) + goto multi_err; + + /* CPU:Codec = N:M */ + if (is_cpu && dai_link->ch_maps) { + ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port); + if (ret < 0) + goto multi_err; + } } + if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max)) + ret = -EINVAL; + +multi_err: return ret; } +static int graph_parse_node_single(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct device_node *ep = port_to_endpoint(port); + int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + + of_node_put(ep); + + return ret; +} + +static int graph_parse_node(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + if (graph_lnk_is_multi(port)) + return graph_parse_node_multi(priv, gtype, port, li, is_cpu); + else + return graph_parse_node_single(priv, gtype, port, li, is_cpu); +} + static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt, unsigned int *bit_frame) { @@ -597,6 +759,7 @@ static void graph_link_init(struct simple_util_priv *priv, struct device_node *ep; struct device_node *ports; unsigned int daifmt = 0, daiclk = 0; + bool playback_only = 0, capture_only = 0; unsigned int bit_frame = 0; if (graph_lnk_is_multi(port)) { @@ -635,6 +798,11 @@ static void graph_link_init(struct simple_util_priv *priv, if (is_cpu_node) daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk); + graph_util_parse_link_direction(port, &playback_only, &capture_only); + + dai_link->playback_only = playback_only; + dai_link->capture_only = capture_only; + dai_link->dai_fmt = daifmt | daiclk; dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; @@ -920,17 +1088,33 @@ static int graph_counter(struct device_node *lnk) * * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ... }; - * port@2 { ... }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ... }; // Multi Element + * port@2 { ... }; // Multi Element * ... * }; * }; * * ignore first lnk part */ - if (graph_lnk_is_multi(lnk)) - return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; + if (graph_lnk_is_multi(lnk)) { + struct device_node *ports = of_get_parent(lnk); + struct device_node *port = NULL; + int cnt = 0; + + /* + * CPU/Codec = N:M case has many endpoints. + * We can't use of_graph_get_endpoint_count() here + */ + while(1) { + port = of_get_next_child(ports, port); + if (!port) + break; + cnt++; + } + + return cnt - 1; + } /* * Single CPU / Codec */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index cfa70a56ff..81077d16d2 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -5,7 +5,6 @@ // Copyright (c) 2016 Kuninori Morimoto #include -#include #include #include #include @@ -1129,6 +1128,25 @@ parse_dai_end: } EXPORT_SYMBOL_GPL(graph_util_parse_dai); +int graph_util_parse_link_direction(struct device_node *np, + bool *playback_only, bool *capture_only) +{ + bool is_playback_only = false; + bool is_capture_only = false; + + is_playback_only = of_property_read_bool(np, "playback-only"); + is_capture_only = of_property_read_bool(np, "capture-only"); + + if (is_playback_only && is_capture_only) + return -EINVAL; + + *playback_only = is_playback_only; + *capture_only = is_capture_only; + + return 0; +} +EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); -- cgit v1.2.3