Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ definitions:
properties:
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
ch-maps:
$ref: /schemas/types.yaml#/definitions/uint32-array

endpoint-base:
allOf:
Expand Down
55 changes: 52 additions & 3 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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
*
Expand Down
138 changes: 121 additions & 17 deletions sound/soc/generic/audio-graph-card2-custom-sample.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,32 @@
* | |-> codec13
* +-+
*
* [Multi-CPU/Codec]
* [Multi-CPU/Codec-0]
* +-+ +-+
* cpu1 <--| |<-@--------->| |-> codec1
* cpu2 <--| | | |-> codec2
* +-+ +-+
*
* [Multi-CPU/Codec-1]
* About ch-map (*), see
* soc-core.c :: [dai_link->ch_maps Image sample]
*
* +-+ +-+
* cpu8 <--| |<-@--------->| |-> codec14 [0]codec14 <---> [0]cpu8
* cpu9 <--| | | |-> codec15 [1]codec15 <-+-> [1]cpu9
* +-+ | |-> codec16 [2]codec16 <-/
* +-+ (*) ch-map = [0, 1, 1]
*
* [Multi-CPU/Codec-2]
* About ch-map (*), see
* soc-core.c :: [dai_link->ch_maps Image sample]
*
* +-+ +-+
* cpu10 <-| |<-@--------->| |-> codec17 [1]cpu11 <---> [0]codec17
* cpu11 <-| | | |-> codec18 [0]cpu10 <-+-> [1]codec18
* cpu12 <-| | +-+ [2]cpu12 <-/
* +-+ (*) ch-map = [1, 0, 1]
*
* [DPCM]
*
* CPU3/CPU4 are converting rate to 44100
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -182,24 +225,24 @@
#address-cells = <1>;
#size-cells = <0>;

/* [Multi-CPU-0] */
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>; }; };
port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
};

/* [Multi-Codec] */
/* [Multi-Codec-0] */
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>; }; };
port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
};

/* [DPCM-Multi]::BE */
Expand Down Expand Up @@ -241,6 +284,50 @@
port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; };
port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; };
};

/* [Multi-CPU-1] */
ports@6 {
reg = <6>;
#address-cells = <1>;
#size-cells = <0>;
mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; }; };
port@1 { reg = <1>; mcpu11_ep: endpoint { remote-endpoint = <&cpu8_ep>; }; };
port@2 { reg = <2>; mcpu12_ep: endpoint { remote-endpoint = <&cpu9_ep>; }; };
};

/* [Multi-Codec-1] */
ports@7 {
reg = <7>;
ch-maps = <0 1 1>; /* see [Multi-CPU/Codec-1] */
#address-cells = <1>;
#size-cells = <0>;
port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; }; };
port@1 { reg = <1>; mcodec11_ep: endpoint { remote-endpoint = <&codec14_ep>; }; };
port@2 { reg = <2>; mcodec12_ep: endpoint { remote-endpoint = <&codec15_ep>; }; };
port@3 { reg = <3>; mcodec13_ep: endpoint { remote-endpoint = <&codec16_ep>; }; };
};

/* [Multi-CPU-2] */
ports@8 {
reg = <8>;
ch-maps = <1 0 1>; /* see [Multi-CPU/Codec-2] */
#address-cells = <1>;
#size-cells = <0>;
mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; }; };
port@1 { reg = <1>; mcpu21_ep: endpoint { remote-endpoint = <&cpu10_ep>; }; };
port@2 { reg = <2>; mcpu22_ep: endpoint { remote-endpoint = <&cpu11_ep>; }; };
port@3 { reg = <3>; mcpu23_ep: endpoint { remote-endpoint = <&cpu12_ep>; }; };
};

/* [Multi-Codec-2] */
ports@9 {
reg = <9>;
#address-cells = <1>;
#size-cells = <0>;
port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; }; };
port@1 { reg = <1>; mcodec21_ep: endpoint { remote-endpoint = <&codec17_ep>; }; };
port@2 { reg = <2>; mcodec22_ep: endpoint { remote-endpoint = <&codec18_ep>; }; };
};
};

dpcm {
Expand Down Expand Up @@ -323,9 +410,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>; }; };
Expand All @@ -337,6 +424,15 @@

/* [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>; }; };
};
};

Expand All @@ -363,9 +459,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 {
Expand Down Expand Up @@ -395,6 +491,14 @@
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>; }; };
};
};
};
29 changes: 29 additions & 0 deletions sound/soc/generic/audio-graph-card2.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,10 @@ static int graph_parse_node(struct simple_util_priv *priv,
int ret = 0;

if (graph_lnk_is_multi(port)) {
struct device_node *ports = of_get_parent(port);
int idx;
int num;
char *props = "ch-maps";

of_node_get(port);

Expand All @@ -528,6 +531,32 @@ static int graph_parse_node(struct simple_util_priv *priv,
if (ret < 0)
break;
}

/* read "ch-maps" property if exist */
num = of_property_count_elems_of_size(ports, props, sizeof(u32));
if (num > 0) {
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link_ch_map *ch_maps = devm_kcalloc(dev, num, sizeof(*ch_maps), GFP_KERNEL);
int *temp = devm_kcalloc(dev, num, sizeof(int), GFP_KERNEL);
int i;

if (!ch_maps || !temp) {
ret = -ENOMEM;
goto multi_end;
}

ret = of_property_read_u32_array(ports, props, temp, num);
if (ret < 0)
goto multi_end;

dai_link->ch_maps = ch_maps;
for (i = 0; i < num; i++)
dai_link->ch_maps[i].connected_node = temp[i];
multi_end:
devm_kfree(dev, temp);
}
of_node_put(ports);
} else {
/* Single CPU / Codec */
ep = port_to_endpoint(port);
Expand Down
Loading