mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
ASoC: makes CPU/Codec channel connection map more
Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>: Current ASoC is supporting CPU/Codec = N:M (N < M) connection by using ch_map idea. This patch-set expands it that all connection uses this idea, and no longer N < M limit [1][2]. Link: https://lore.kernel.org/r/87fs6wuszr.wl-kuninori.morimoto.gx@renesas.com [1] Link: https://lore.kernel.org/r/878r7yqeo4.wl-kuninori.morimoto.gx@renesas.com [2] ASoC core code ([PATCH 1/5]) is same as v6 and it was tested by Pierre-Louis, and Jerome. Big change on v7 is basically for Audio-Graph-Card2.
This commit is contained in:
commit
b2b6b2d8f4
|
|
@ -655,8 +655,45 @@ struct snd_soc_dai_link_component {
|
|||
struct of_phandle_args *dai_args;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link_codec_ch_map {
|
||||
unsigned int connected_cpu_id;
|
||||
/*
|
||||
* [dai_link->ch_maps Image sample]
|
||||
*
|
||||
*-------------------------
|
||||
* CPU0 <---> Codec0
|
||||
*
|
||||
* ch-map[0].cpu = 0 ch-map[0].codec = 0
|
||||
*
|
||||
*-------------------------
|
||||
* CPU0 <---> Codec0
|
||||
* CPU1 <---> Codec1
|
||||
* CPU2 <---> Codec2
|
||||
*
|
||||
* ch-map[0].cpu = 0 ch-map[0].codec = 0
|
||||
* ch-map[1].cpu = 1 ch-map[1].codec = 1
|
||||
* ch-map[2].cpu = 2 ch-map[2].codec = 2
|
||||
*
|
||||
*-------------------------
|
||||
* CPU0 <---> Codec0
|
||||
* CPU1 <-+-> Codec1
|
||||
* CPU2 <-/
|
||||
*
|
||||
* ch-map[0].cpu = 0 ch-map[0].codec = 0
|
||||
* ch-map[1].cpu = 1 ch-map[1].codec = 1
|
||||
* ch-map[2].cpu = 2 ch-map[2].codec = 1
|
||||
*
|
||||
*-------------------------
|
||||
* CPU0 <---> Codec0
|
||||
* CPU1 <-+-> Codec1
|
||||
* \-> Codec2
|
||||
*
|
||||
* ch-map[0].cpu = 0 ch-map[0].codec = 0
|
||||
* ch-map[1].cpu = 1 ch-map[1].codec = 1
|
||||
* ch-map[2].cpu = 1 ch-map[2].codec = 2
|
||||
*
|
||||
*/
|
||||
struct snd_soc_dai_link_ch_map {
|
||||
unsigned int cpu;
|
||||
unsigned int codec;
|
||||
unsigned int ch_mask;
|
||||
};
|
||||
|
||||
|
|
@ -688,7 +725,9 @@ struct snd_soc_dai_link {
|
|||
struct snd_soc_dai_link_component *codecs;
|
||||
unsigned int num_codecs;
|
||||
|
||||
struct snd_soc_dai_link_codec_ch_map *codec_ch_maps;
|
||||
/* num_ch_maps = max(num_cpu, num_codecs) */
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
|
||||
/*
|
||||
* You MAY specify the link's platform/PCM/DMA driver, either by
|
||||
* device name, or by DT/OF node, but not both. Some forms of link
|
||||
|
|
@ -775,6 +814,10 @@ struct snd_soc_dai_link {
|
|||
#endif
|
||||
};
|
||||
|
||||
static inline int snd_soc_link_num_ch_map(struct snd_soc_dai_link *link) {
|
||||
return max(link->num_cpus, link->num_codecs);
|
||||
}
|
||||
|
||||
static inline struct snd_soc_dai_link_component*
|
||||
snd_soc_link_to_cpu(struct snd_soc_dai_link *link, int n) {
|
||||
return &(link)->cpus[n];
|
||||
|
|
@ -808,6 +851,12 @@ snd_soc_link_to_platform(struct snd_soc_dai_link *link, int n) {
|
|||
((cpu) = snd_soc_link_to_cpu(link, i)); \
|
||||
(i)++)
|
||||
|
||||
#define for_each_link_ch_maps(link, i, ch_map) \
|
||||
for ((i) = 0; \
|
||||
((i) < snd_soc_link_num_ch_map(link) && \
|
||||
((ch_map) = link->ch_maps + i)); \
|
||||
(i)++)
|
||||
|
||||
/*
|
||||
* Sample 1 : Single CPU/Codec/Platform
|
||||
*
|
||||
|
|
@ -1163,6 +1212,7 @@ struct snd_soc_pcm_runtime {
|
|||
((i) < (rtd)->dai_link->num_cpus + (rtd)->dai_link->num_codecs) && \
|
||||
((dai) = (rtd)->dais[i]); \
|
||||
(i)++)
|
||||
#define for_each_rtd_ch_maps(rtd, i, ch_maps) for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
|
||||
|
||||
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ audio-graph-card2-custom-sample {
|
|||
*/
|
||||
&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 @@ multi {
|
|||
#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 @@ ports@0 {
|
|||
|
||||
#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 @@ ports@1 {
|
|||
|
||||
#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 @@ ports@1 {
|
|||
codec2codec {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
/* [Codec2Codec] */
|
||||
/*
|
||||
* [Codec2Codec]
|
||||
*
|
||||
* +-@(c2c)-> codec6
|
||||
* |
|
||||
* +--------> codec7
|
||||
*/
|
||||
ports@0 {
|
||||
reg = <0>;
|
||||
|
||||
|
|
@ -289,7 +565,18 @@ ports@0 {
|
|||
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 @@ ports {
|
|||
/* [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 @@ ports {
|
|||
|
||||
/* [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 @@ ports {
|
|||
/* [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@3 {
|
|||
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>; }; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -83,32 +83,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 +328,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,38 +504,201 @@ static int __graph_parse_node(struct simple_util_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* +---+ +---+
|
||||
* | 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
|
||||
* <mcpu_port> 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
|
||||
* <mcodec_port>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 (cpu_idx > dai_link->num_cpus)
|
||||
goto mcpu_err;
|
||||
|
||||
while (1) {
|
||||
struct device_node *mcodec_ep_n;
|
||||
struct device_node *mcodec_port_i;
|
||||
struct device_node *mcodec_port;
|
||||
int codec_idx;
|
||||
|
||||
if (*nm_idx > nm_max)
|
||||
break;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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> port@0 { ... }; // to pair
|
||||
* port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element
|
||||
* port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* cpu {
|
||||
* ports {
|
||||
* <ep> 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)
|
||||
{
|
||||
struct device_node *ep;
|
||||
int ret = 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;
|
||||
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,
|
||||
|
|
@ -920,17 +1083,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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -570,16 +570,14 @@ int sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int ch = params_channels(params);
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
unsigned int ch_mask;
|
||||
int num_codecs;
|
||||
int step;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (!rtd->dai_link->codec_ch_maps)
|
||||
if (!rtd->dai_link->ch_maps)
|
||||
return 0;
|
||||
|
||||
/* Identical data will be sent to all codecs in playback */
|
||||
|
|
@ -605,13 +603,9 @@ int sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
* link has more than one codec DAIs. Set codec channel mask and
|
||||
* ASoC will set the corresponding channel numbers for each cpu dai.
|
||||
*/
|
||||
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
|
||||
for_each_rtd_codec_dais(rtd, j, codec_dai) {
|
||||
if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i)
|
||||
continue;
|
||||
rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step);
|
||||
}
|
||||
}
|
||||
for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
|
||||
ch_maps->ch_mask = ch_mask << (i * step);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1350,15 +1344,17 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps,
|
||||
static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps,
|
||||
int codec_num, int cpu_num)
|
||||
{
|
||||
int step;
|
||||
int i;
|
||||
|
||||
step = codec_num / cpu_num;
|
||||
for (i = 0; i < codec_num; i++)
|
||||
sdw_codec_ch_maps[i].connected_cpu_id = i / step;
|
||||
for (i = 0; i < codec_num; i++) {
|
||||
sdw_codec_ch_maps[i].cpu = i / step;
|
||||
sdw_codec_ch_maps[i].codec = i;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
|
||||
|
|
@ -1453,7 +1449,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
|
|||
*ignore_pch_dmic = true;
|
||||
|
||||
for_each_pcm_streams(stream) {
|
||||
struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps;
|
||||
struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps;
|
||||
char *name, *cpu_name;
|
||||
int playback, capture;
|
||||
static const char * const sdw_stream_name[] = {
|
||||
|
|
@ -1530,7 +1526,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
|
|||
dai_links[*link_index].nonatomic = true;
|
||||
|
||||
set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
|
||||
dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
|
||||
dai_links[*link_index].ch_maps = sdw_codec_ch_maps;
|
||||
ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
|
||||
playback, group_id, adr_index, dai_index);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
|
|
@ -1015,6 +1015,94 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#define MAX_DEFAULT_CH_MAP_SIZE 7
|
||||
static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = {
|
||||
{ .cpu = 0, .codec = 0 },
|
||||
{ .cpu = 1, .codec = 1 },
|
||||
{ .cpu = 2, .codec = 2 },
|
||||
{ .cpu = 3, .codec = 3 },
|
||||
{ .cpu = 4, .codec = 4 },
|
||||
{ .cpu = 5, .codec = 5 },
|
||||
{ .cpu = 6, .codec = 6 },
|
||||
};
|
||||
static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = {
|
||||
{ .cpu = 0, .codec = 0 },
|
||||
{ .cpu = 0, .codec = 1 },
|
||||
{ .cpu = 0, .codec = 2 },
|
||||
{ .cpu = 0, .codec = 3 },
|
||||
{ .cpu = 0, .codec = 4 },
|
||||
{ .cpu = 0, .codec = 5 },
|
||||
{ .cpu = 0, .codec = 6 },
|
||||
};
|
||||
static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = {
|
||||
{ .cpu = 0, .codec = 0 },
|
||||
{ .cpu = 1, .codec = 0 },
|
||||
{ .cpu = 2, .codec = 0 },
|
||||
{ .cpu = 3, .codec = 0 },
|
||||
{ .cpu = 4, .codec = 0 },
|
||||
{ .cpu = 5, .codec = 0 },
|
||||
{ .cpu = 6, .codec = 0 },
|
||||
};
|
||||
static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link *dai_link)
|
||||
{
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* dai_link->ch_maps indicates how CPU/Codec are connected.
|
||||
* It will be a map seen from a larger number of DAI.
|
||||
* see
|
||||
* soc.h :: [dai_link->ch_maps Image sample]
|
||||
*/
|
||||
|
||||
/* it should have ch_maps if connection was N:M */
|
||||
if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
|
||||
dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) {
|
||||
dev_err(card->dev, "need to have ch_maps when N:M connction (%s)",
|
||||
dai_link->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* do nothing if it has own maps */
|
||||
if (dai_link->ch_maps)
|
||||
goto sanity_check;
|
||||
|
||||
/* check default map size */
|
||||
if (dai_link->num_cpus > MAX_DEFAULT_CH_MAP_SIZE ||
|
||||
dai_link->num_codecs > MAX_DEFAULT_CH_MAP_SIZE) {
|
||||
dev_err(card->dev, "soc-core.c needs update default_connection_maps");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compensate missing map for ... */
|
||||
if (dai_link->num_cpus == dai_link->num_codecs)
|
||||
dai_link->ch_maps = default_ch_map_sync; /* for 1:1 or N:N */
|
||||
else if (dai_link->num_cpus < dai_link->num_codecs)
|
||||
dai_link->ch_maps = default_ch_map_1cpu; /* for 1:N */
|
||||
else
|
||||
dai_link->ch_maps = default_ch_map_1codec; /* for N:1 */
|
||||
|
||||
sanity_check:
|
||||
dev_dbg(card->dev, "dai_link %s\n", dai_link->stream_name);
|
||||
for_each_link_ch_maps(dai_link, i, ch_maps) {
|
||||
if ((ch_maps->cpu >= dai_link->num_cpus) ||
|
||||
(ch_maps->codec >= dai_link->num_codecs)) {
|
||||
dev_err(card->dev,
|
||||
"unexpected dai_link->ch_maps[%d] index (cpu(%d/%d) codec(%d/%d))",
|
||||
i,
|
||||
ch_maps->cpu, dai_link->num_cpus,
|
||||
ch_maps->codec, dai_link->num_codecs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(card->dev, " [%d] cpu%d <-> codec%d\n",
|
||||
i, ch_maps->cpu, ch_maps->codec);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card
|
||||
* @card: The ASoC card to which the pcm_runtime has
|
||||
|
|
@ -1121,8 +1209,13 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
|
|||
int num_dai_link)
|
||||
{
|
||||
for (int i = 0; i < num_dai_link; i++) {
|
||||
int ret = snd_soc_add_pcm_runtime(card, dai_link + i);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_compensate_channel_connection_map(card, dai_link + i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_add_pcm_runtime(card, dai_link + i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4436,11 +4436,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
|
|||
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int i;
|
||||
|
||||
/* for each BE DAI link... */
|
||||
for_each_card_rtds(card, rtd) {
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* dynamic FE links have no fixed DAI mapping.
|
||||
* CODEC<->CODEC links have no direct connection.
|
||||
|
|
@ -4448,39 +4451,15 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
|
|||
if (rtd->dai_link->dynamic)
|
||||
continue;
|
||||
|
||||
if (rtd->dai_link->num_cpus == 1) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai,
|
||||
snd_soc_rtd_to_cpu(rtd, 0));
|
||||
} else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) {
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai)
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai,
|
||||
snd_soc_rtd_to_cpu(rtd, i));
|
||||
} else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
|
||||
int cpu_id;
|
||||
/*
|
||||
* see
|
||||
* soc.h :: [dai_link->ch_maps Image sample]
|
||||
*/
|
||||
for_each_rtd_ch_maps(rtd, i, ch_maps) {
|
||||
cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
|
||||
codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
|
||||
|
||||
if (!rtd->dai_link->codec_ch_maps) {
|
||||
dev_err(card->dev, "%s: no codec channel mapping table provided\n",
|
||||
__func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
|
||||
if (cpu_id >= rtd->dai_link->num_cpus) {
|
||||
dev_err(card->dev,
|
||||
"%s: dai_link %s cpu_id %d too large, num_cpus is %d\n",
|
||||
__func__, rtd->dai_link->name, cpu_id,
|
||||
rtd->dai_link->num_cpus);
|
||||
continue;
|
||||
}
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai,
|
||||
snd_soc_rtd_to_cpu(rtd, cpu_id));
|
||||
}
|
||||
} else {
|
||||
dev_err(card->dev,
|
||||
"%s: codec number %d < cpu number %d is not supported\n",
|
||||
__func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus);
|
||||
dapm_connect_dai_pair(card, rtd, codec_dai, cpu_dai);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1050,6 +1050,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
|
|||
}
|
||||
|
||||
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
unsigned int ch_mask = 0;
|
||||
int j;
|
||||
|
||||
|
|
@ -1063,22 +1064,20 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
|
|||
/* copy params for each cpu */
|
||||
tmp_params = *params;
|
||||
|
||||
if (!rtd->dai_link->codec_ch_maps)
|
||||
goto hw_params;
|
||||
/*
|
||||
* construct cpu channel mask by combining ch_mask of each
|
||||
* codec which maps to the cpu.
|
||||
* see
|
||||
* soc.h :: [dai_link->ch_maps Image sample]
|
||||
*/
|
||||
for_each_rtd_codec_dais(rtd, j, codec_dai) {
|
||||
if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i)
|
||||
ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask;
|
||||
}
|
||||
for_each_rtd_ch_maps(rtd, j, ch_maps)
|
||||
if (ch_maps->cpu == i)
|
||||
ch_mask |= ch_maps->ch_mask;
|
||||
|
||||
/* fixup cpu channel number */
|
||||
if (ch_mask)
|
||||
soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
|
||||
|
||||
hw_params:
|
||||
ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
|
@ -2826,35 +2825,20 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
|
||||
/* Adapt stream for codec2codec links */
|
||||
int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE);
|
||||
int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
if (dai_link->num_cpus == 1) {
|
||||
cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
} else if (dai_link->num_cpus == dai_link->num_codecs) {
|
||||
cpu_dai = snd_soc_rtd_to_cpu(rtd, i);
|
||||
} else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
|
||||
int cpu_id;
|
||||
|
||||
if (!rtd->dai_link->codec_ch_maps) {
|
||||
dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
|
||||
cpu_dai = snd_soc_rtd_to_cpu(rtd, cpu_id);
|
||||
} else {
|
||||
dev_err(rtd->card->dev,
|
||||
"%s codec number %d < cpu number %d is not supported\n",
|
||||
__func__, rtd->dai_link->num_codecs,
|
||||
rtd->dai_link->num_cpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* see
|
||||
* soc.h :: [dai_link->ch_maps Image sample]
|
||||
*/
|
||||
for_each_rtd_ch_maps(rtd, i, ch_maps) {
|
||||
cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
|
||||
codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
|
||||
|
||||
if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
|
||||
snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user