From: Amadeusz Sławiński <amadeuszx.slawinski@xxxxxxxxxxxxxxx> Two key operations missings are: endpoint presence-check and retrieval of matching endpoint hardware configuration (blob). Add operations for both use cases. Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@xxxxxxxxxxxxxxx> Signed-off-by: Cezary Rojewski <cezary.rojewski@xxxxxxxxx> --- include/sound/intel-nhlt.h | 20 ++++++++ sound/hda/intel-nhlt.c | 99 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index b7eec4b3ca01..2cd3f27b7a72 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -132,6 +132,12 @@ void intel_nhlt_free(struct acpi_table_nhlt *addr); int intel_nhlt_get_dmic_geo(struct acpi_table_nhlt *nhlt); +bool intel_nhlt_has_endpoint_type(struct acpi_table_nhlt *nhlt, u8 link_type); +struct nhlt_specific_cfg * +intel_nhlt_get_endpoint_blob(struct acpi_table_nhlt *nhlt, + u32 bus_id, u8 link_type, u8 vbps, u8 bps, + u8 num_ch, u32 rate, u8 dir, u8 dev_type); + #else struct acpi_table_nhlt; @@ -149,6 +155,20 @@ static inline int intel_nhlt_get_dmic_geo(struct acpi_table_nhlt *nhlt) { return 0; } + +bool intel_nhlt_has_endpoint_type(struct acpi_table_nhlt *nhlt, u8 link_type) +{ + return false; +} + +struct nhlt_specific_cfg * +intel_nhlt_get_endpoint_blob(struct acpi_table_nhlt *nhlt, + u32 bus_id, u8 link_type, u8 vbps, u8 bps, + u8 num_ch, u32 rate, u8 dir, u8 dev_type) +{ + return NULL; +} + #endif #endif diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index c41d20e1b349..d97fe57a7ef2 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -112,3 +112,102 @@ int intel_nhlt_get_dmic_geo(struct acpi_table_nhlt *nhlt) return dmic_geo; } EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); + +bool intel_nhlt_has_endpoint_type(struct acpi_table_nhlt *nhlt, u8 link_type) +{ + struct nhlt_endpoint *epnt; + int i; + + if (!nhlt) + return false; + + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + if (epnt->linktype == link_type) + return true; + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + return false; +} +EXPORT_SYMBOL(intel_nhlt_has_endpoint_type); + +static struct nhlt_specific_cfg * +nhlt_get_specific_cfg(struct nhlt_fmt *fmt, u8 num_ch, u32 rate, u8 vbps, u8 bps) +{ + struct nhlt_fmt_cfg *cfg = fmt->fmt_config; + struct wav_fmt *wfmt; + u16 _bps, _vbps; + int i; + + pr_debug("Endpoint format count=%d\n", fmt->fmt_count); + + for (i = 0; i < fmt->fmt_count; i++) { + wfmt = &cfg->fmt_ext.fmt; + _bps = wfmt->bits_per_sample; + _vbps = cfg->fmt_ext.sample.valid_bits_per_sample; + + pr_debug("Endpoint format: ch=%d fmt=%d/%d rate=%d\n", + wfmt->channels, _vbps, _bps, wfmt->samples_per_sec); + + if (wfmt->channels == num_ch && wfmt->samples_per_sec == rate && + vbps == _vbps && bps == _bps) + return &cfg->config; + + cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size); + } + + return NULL; +} + +static bool nhlt_check_ep_match(struct nhlt_endpoint *epnt, + u32 bus_id, u8 link_type, u8 dir, u8 dev_type) +{ + pr_debug("Endpoint: vbus_id=%d link_type=%d dir=%d dev_type = %d\n", + epnt->virtual_bus_id, epnt->linktype, + epnt->direction, epnt->device_type); + + if ((epnt->virtual_bus_id != bus_id) || + (epnt->linktype != link_type) || + (epnt->direction != dir)) + return false; + + /* link of type DMIC bypasses device_type check */ + return epnt->linktype == NHLT_LINK_DMIC || + epnt->device_type == dev_type; +} + +struct nhlt_specific_cfg * +intel_nhlt_get_endpoint_blob(struct acpi_table_nhlt *nhlt, + u32 bus_id, u8 link_type, u8 vbps, u8 bps, + u8 num_ch, u32 rate, u8 dir, u8 dev_type) +{ + struct nhlt_specific_cfg *cfg; + struct nhlt_endpoint *epnt; + struct nhlt_fmt *fmt; + int i; + + if (!nhlt) + return NULL; + + pr_debug("Looking for configuration:\n"); + pr_debug(" vbus_id=%d link_type=%d dir=%d, dev_type=%d\n", + bus_id, link_type, dir, dev_type); + pr_debug(" ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate); + pr_debug("Endpoint count=%d\n", nhlt->endpoint_count); + + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + if (nhlt_check_ep_match(epnt, bus_id, link_type, dir, dev_type)) { + fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); + cfg = nhlt_get_specific_cfg(fmt, num_ch, rate, vbps, bps); + if (cfg) + return cfg; + } + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return NULL; +} +EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob); -- 2.25.1