Skip to content
Open
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
3 changes: 3 additions & 0 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,

port_bo += bps * ch;
slave_total_ch += ch;

if (m_rt->stream->type == SDW_STREAM_COMPANION)
port_bo = t_data->block_offset;
Comment on lines +74 to +75

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not following this one.

}
Comment on lines +73 to 76

if (m_rt->direction == SDW_DATA_DIR_TX &&
Expand Down
1 change: 1 addition & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ enum sdw_stream_type {
SDW_STREAM_PCM = 0,
SDW_STREAM_PDM = 1,
SDW_STREAM_BPT = 2,
SDW_STREAM_COMPANION = 3,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah but it could be PDM or PCM.

It think you'd need to add a new transport type, such as MANAGER_PERIPHERAL or PERIPHERAL_PERIPHERAL.

There are other uses cases where device-to-device communication is needed, e.g. to share the amp feedback. Don't make this just for the companion case.

};

/**
Expand Down
4 changes: 3 additions & 1 deletion include/sound/soc-acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ struct snd_soc_acpi_mach_params {
* struct snd_soc_acpi_endpoint - endpoint descriptor
* @num: endpoint number (mandatory, unique per device)
* @aggregated: 0 (independent) or 1 (logically grouped)
* @companion: 0 (independent) or 1 (within a companion amp group)
* @group_position: zero-based order (only when @aggregated is 1)
* @group_id: platform-unique group identifier (only when @aggregrated is 1)
* @group_id: platform-unique group identifier (only when @aggregrated or companion is 1)
*/
struct snd_soc_acpi_endpoint {
u8 num;
u8 aggregated;
u8 companion;
u8 group_position;
u8 group_id;
};
Expand Down
12 changes: 11 additions & 1 deletion include/sound/soc_sdw_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
*/
#define SOC_SDW_SIDECAR_AMPS BIT(16)
#define SOC_SDW_CODEC_MIC BIT(17)
#define SOC_SDW_COMPANION_AMPS BIT(18)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be useful to describe the difference between sidecar and companion amps


#define SOC_SDW_UNUSED_DAI_ID -1
#define SOC_SDW_JACK_OUT_DAI_ID 0
Expand Down Expand Up @@ -128,6 +129,11 @@ struct asoc_sdw_dailink {
struct list_head endpoints;
};

struct asoc_sdw_companion_amp_endpoint {
struct asoc_sdw_endpoint *main_amp;
struct list_head comp_ends;
};

extern struct asoc_sdw_codec_info codec_info_list[];
int asoc_sdw_get_codec_info_list_count(void);

Expand Down Expand Up @@ -176,17 +182,21 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d
const struct snd_soc_ops *ops);

int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
int *num_devs, int *num_ends, int *num_aux);
int *num_devs, int *num_ends, int *num_aux, int *num_comp_amps);

struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_find_amp_endpoints(struct asoc_sdw_dailink *dailink,
struct asoc_sdw_endpoint **amp_ends,
int max_ends);
int asoc_sdw_get_dai_type(u32 type);

int asoc_sdw_parse_sdw_endpoints(struct device *dev,
struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
struct asoc_sdw_companion_amp_endpoint *comp_ends,
int *num_devs);

int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd);
Expand Down
17 changes: 14 additions & 3 deletions sound/soc/amd/acp/acp-sdw-legacy-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,18 +415,21 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
struct device *dev = card->dev;
int sdw_be_num = 0, dmic_num = 0;
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct asoc_sdw_companion_amp_endpoint *sof_comp_ends;
struct snd_soc_aux_dev *soc_aux;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_dai_link *dai_links;
int num_comp_amps = 0;
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
int num_confs;
int num_links;
int be_id = 0;
int ret;
int i;

ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps);
if (ret < 0) {
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
Expand All @@ -442,15 +445,23 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)

/* One per endpoint, ie. each DAI on each codec/amp */
struct asoc_sdw_endpoint *soc_ends __free(kfree) =
kzalloc_objs(*soc_ends, num_ends);
kzalloc_objs(*soc_ends, num_ends + num_comp_amps);
if (!soc_ends)
return -ENOMEM;

soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL);
if (!soc_aux)
return -ENOMEM;

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs);
sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL);
if (!sof_comp_ends)
return -ENOMEM;

for (i = 0; i < num_comp_amps; i++)
INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends);

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, sof_comp_ends,
&num_confs);
if (ret < 0)
return ret;

Expand Down
17 changes: 14 additions & 3 deletions sound/soc/amd/acp/acp-sdw-sof-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,18 +280,21 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
int sdw_be_num = 0, dmic_num = 0;
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct asoc_sdw_companion_amp_endpoint *sof_comp_ends;
struct snd_soc_aux_dev *sof_aux;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_dai_link *dai_links;
int num_comp_amps = 0;
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
int num_confs;
int num_links;
int be_id = 0;
int ret;
int i;

ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps);
if (ret < 0) {
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
Expand All @@ -306,15 +309,23 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)

/* One per endpoint, ie. each DAI on each codec/amp */
struct asoc_sdw_endpoint *sof_ends __free(kfree) =
kzalloc_objs(*sof_ends, num_ends);
kzalloc_objs(*sof_ends, num_ends + num_comp_amps);
if (!sof_ends)
return -ENOMEM;

sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL);
if (!sof_aux)
return -ENOMEM;

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL);
if (!sof_comp_ends)
return -ENOMEM;

for (i = 0; i < num_comp_amps; i++)
INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends);

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, sof_comp_ends,
&num_confs);
if (ret < 0)
return ret;

Expand Down
111 changes: 107 additions & 4 deletions sound/soc/intel/boards/sof_sdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,89 @@ static int create_bt_dailinks(struct snd_soc_card *card,
return 0;
}

static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
};

static const struct snd_soc_dai_link bridge_dai_template = {
.name = "SDW Companion Amp",
.stream_name = "Companion Amp",
.c2c_params = &asoc_sdw_bridge_params,
.num_c2c_params = 1,
};

static int create_sdw_comp_dailinks(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links, int *be_id,
struct asoc_sdw_companion_amp_endpoint *comp_ends,
int comp_ends_num)
{
struct device *dev = card->dev;
struct asoc_sdw_endpoint *end;
struct snd_soc_dai_link_component *platform;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *cpus;
char *name;
int num_codecs;
int i;

for (i = 0; i < comp_ends_num; i++) {
if (!comp_ends[i].main_amp || list_empty(&comp_ends[i].comp_ends)) {
dev_err(dev, "companion amp group %d: missing main amp or companion amps\n", i);
return -EINVAL;
}

num_codecs = 0;
list_for_each_entry(end, &comp_ends[i].comp_ends, list)
num_codecs++;

cpus = devm_kzalloc(dev, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;

codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
if (!codecs)
return -ENOMEM;

platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
if (!platform)
return -ENOMEM;

name = devm_kasprintf(dev, GFP_KERNEL, "SDW Companion Amp %d", i);
if (!name)
return -ENOMEM;

cpus[0].name = comp_ends[i].main_amp->codec_name;
cpus[0].dai_name = comp_ends[i].main_amp->dai_info->dai_name;

num_codecs = 0;
list_for_each_entry(end, &comp_ends[i].comp_ends, list) {
codecs[num_codecs].name = end->codec_name;
codecs[num_codecs].dai_name = end->dai_info->dai_name;
num_codecs++;
Comment on lines +1289 to +1291
}

**dai_links = bridge_dai_template;
(*dai_links)->name = name;
(*dai_links)->stream_name = name;
(*dai_links)->cpus = cpus;
(*dai_links)->num_cpus = 1;
(*dai_links)->codecs = codecs;
(*dai_links)->num_codecs = num_codecs;
(*dai_links)->platforms = platform;
(*dai_links)->num_platforms = 1;
Comment on lines +1301 to +1302
(*dai_links)++;
}

dev_dbg(dev, "Added SDW Companion AMP Codec to Codec link\n");

return 0;
}

static int create_echoref_dailink(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links, int *be_id)
{
Expand Down Expand Up @@ -1261,11 +1344,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct asoc_sdw_companion_amp_endpoint *sof_comp_ends;
struct snd_soc_codec_conf *codec_conf;
struct asoc_sdw_codec_info *ssp_info;
struct asoc_sdw_endpoint *sof_ends;
struct asoc_sdw_dailink *sof_dais;
struct snd_soc_aux_dev *sof_aux;
int num_comp_amps = 0;
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
Expand All @@ -1276,8 +1361,9 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
int hdmi_num;
unsigned long ssp_mask;
int ret;
int i;

ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps);
if (ret < 0) {
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
Expand Down Expand Up @@ -1307,7 +1393,17 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL);
if (!sof_comp_ends) {
ret = -ENOMEM;
goto err_dai;
}

for (i = 0; i < num_comp_amps; i++)
INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends);

ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, sof_comp_ends,
&num_confs);
if (ret < 0)
goto err_end;

Expand Down Expand Up @@ -1366,8 +1462,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
* This should be the last DAI link and it is expected both for monolithic
* and functional SOF topologies to support echo reference.
*/
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1;
dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + num_comp_amps + 1;
dai_links = devm_kcalloc(dev, num_links + 1, sizeof(*dai_links), GFP_KERNEL);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should explain why there's an additional dailink.

What's not clear specifically is how this dailink is handled, i.e. how it's allocated, prepared, triggered.

so far the device-to-device connections are not handled by the SoundWire core, so it's not clear how this might work?

if (!dai_links) {
ret = -ENOMEM;
goto err_end;
Expand Down Expand Up @@ -1415,6 +1511,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_end;
}

/* Companion amp */
if (num_comp_amps) {
ret = create_sdw_comp_dailinks(card, &dai_links, &be_id, sof_comp_ends,
num_comp_amps);
if (ret)
goto err_end;
}
/* dummy echo ref link. keep this as the last DAI link. The DAI link ID does not matter */
ret = create_echoref_dailink(card, &dai_links, &be_id);
if (ret) {
Expand Down
Loading
Loading