Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (c) 2015-2019 Intel Corporation
0003 
0004 #include <linux/acpi.h>
0005 #include <sound/intel-nhlt.h>
0006 
0007 struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
0008 {
0009     struct nhlt_acpi_table *nhlt;
0010     acpi_status status;
0011 
0012     status = acpi_get_table(ACPI_SIG_NHLT, 0,
0013                 (struct acpi_table_header **)&nhlt);
0014     if (ACPI_FAILURE(status)) {
0015         dev_warn(dev, "NHLT table not found\n");
0016         return NULL;
0017     }
0018 
0019     return nhlt;
0020 }
0021 EXPORT_SYMBOL_GPL(intel_nhlt_init);
0022 
0023 void intel_nhlt_free(struct nhlt_acpi_table *nhlt)
0024 {
0025     acpi_put_table((struct acpi_table_header *)nhlt);
0026 }
0027 EXPORT_SYMBOL_GPL(intel_nhlt_free);
0028 
0029 int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
0030 {
0031     struct nhlt_endpoint *epnt;
0032     struct nhlt_dmic_array_config *cfg;
0033     struct nhlt_vendor_dmic_array_config *cfg_vendor;
0034     struct nhlt_fmt *fmt_configs;
0035     unsigned int dmic_geo = 0;
0036     u16 max_ch = 0;
0037     u8 i, j;
0038 
0039     if (!nhlt)
0040         return 0;
0041 
0042     if (nhlt->header.length <= sizeof(struct acpi_table_header)) {
0043         dev_warn(dev, "Invalid DMIC description table\n");
0044         return 0;
0045     }
0046 
0047     for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++,
0048          epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) {
0049 
0050         if (epnt->linktype != NHLT_LINK_DMIC)
0051             continue;
0052 
0053         cfg = (struct nhlt_dmic_array_config  *)(epnt->config.caps);
0054         fmt_configs = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
0055 
0056         /* find max number of channels based on format_configuration */
0057         if (fmt_configs->fmt_count) {
0058             struct nhlt_fmt_cfg *fmt_cfg = fmt_configs->fmt_config;
0059 
0060             dev_dbg(dev, "found %d format definitions\n",
0061                 fmt_configs->fmt_count);
0062 
0063             for (i = 0; i < fmt_configs->fmt_count; i++) {
0064                 struct wav_fmt_ext *fmt_ext;
0065 
0066                 fmt_ext = &fmt_cfg->fmt_ext;
0067 
0068                 if (fmt_ext->fmt.channels > max_ch)
0069                     max_ch = fmt_ext->fmt.channels;
0070 
0071                 /* Move to the next nhlt_fmt_cfg */
0072                 fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
0073                                   fmt_cfg->config.size);
0074             }
0075             dev_dbg(dev, "max channels found %d\n", max_ch);
0076         } else {
0077             dev_dbg(dev, "No format information found\n");
0078         }
0079 
0080         if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) {
0081             dmic_geo = max_ch;
0082         } else {
0083             switch (cfg->array_type) {
0084             case NHLT_MIC_ARRAY_2CH_SMALL:
0085             case NHLT_MIC_ARRAY_2CH_BIG:
0086                 dmic_geo = MIC_ARRAY_2CH;
0087                 break;
0088 
0089             case NHLT_MIC_ARRAY_4CH_1ST_GEOM:
0090             case NHLT_MIC_ARRAY_4CH_L_SHAPED:
0091             case NHLT_MIC_ARRAY_4CH_2ND_GEOM:
0092                 dmic_geo = MIC_ARRAY_4CH;
0093                 break;
0094             case NHLT_MIC_ARRAY_VENDOR_DEFINED:
0095                 cfg_vendor = (struct nhlt_vendor_dmic_array_config *)cfg;
0096                 dmic_geo = cfg_vendor->nb_mics;
0097                 break;
0098             default:
0099                 dev_warn(dev, "%s: undefined DMIC array_type 0x%0x\n",
0100                      __func__, cfg->array_type);
0101             }
0102 
0103             if (dmic_geo > 0) {
0104                 dev_dbg(dev, "Array with %d dmics\n", dmic_geo);
0105             }
0106             if (max_ch > dmic_geo) {
0107                 dev_dbg(dev, "max channels %d exceed dmic number %d\n",
0108                     max_ch, dmic_geo);
0109             }
0110         }
0111     }
0112 
0113     dev_dbg(dev, "dmic number %d max_ch %d\n", dmic_geo, max_ch);
0114 
0115     return dmic_geo;
0116 }
0117 EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
0118 
0119 bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type)
0120 {
0121     struct nhlt_endpoint *epnt;
0122     int i;
0123 
0124     if (!nhlt)
0125         return false;
0126 
0127     epnt = (struct nhlt_endpoint *)nhlt->desc;
0128     for (i = 0; i < nhlt->endpoint_count; i++) {
0129         if (epnt->linktype == link_type)
0130             return true;
0131 
0132         epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
0133     }
0134     return false;
0135 }
0136 EXPORT_SYMBOL(intel_nhlt_has_endpoint_type);
0137 
0138 int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type)
0139 {
0140     struct nhlt_endpoint *epnt;
0141     int ssp_mask = 0;
0142     int i;
0143 
0144     if (!nhlt || (device_type != NHLT_DEVICE_BT && device_type != NHLT_DEVICE_I2S))
0145         return 0;
0146 
0147     epnt = (struct nhlt_endpoint *)nhlt->desc;
0148     for (i = 0; i < nhlt->endpoint_count; i++) {
0149         if (epnt->linktype == NHLT_LINK_SSP && epnt->device_type == device_type) {
0150             /* for SSP the virtual bus id is the SSP port */
0151             ssp_mask |= BIT(epnt->virtual_bus_id);
0152         }
0153         epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
0154     }
0155 
0156     return ssp_mask;
0157 }
0158 EXPORT_SYMBOL(intel_nhlt_ssp_endpoint_mask);
0159 
0160 static struct nhlt_specific_cfg *
0161 nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
0162               u32 rate, u8 vbps, u8 bps)
0163 {
0164     struct nhlt_fmt_cfg *cfg = fmt->fmt_config;
0165     struct wav_fmt *wfmt;
0166     u16 _bps, _vbps;
0167     int i;
0168 
0169     dev_dbg(dev, "Endpoint format count=%d\n", fmt->fmt_count);
0170 
0171     for (i = 0; i < fmt->fmt_count; i++) {
0172         wfmt = &cfg->fmt_ext.fmt;
0173         _bps = wfmt->bits_per_sample;
0174         _vbps = cfg->fmt_ext.sample.valid_bits_per_sample;
0175 
0176         dev_dbg(dev, "Endpoint format: ch=%d fmt=%d/%d rate=%d\n",
0177             wfmt->channels, _vbps, _bps, wfmt->samples_per_sec);
0178 
0179         if (wfmt->channels == num_ch && wfmt->samples_per_sec == rate &&
0180             vbps == _vbps && bps == _bps)
0181             return &cfg->config;
0182 
0183         cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size);
0184     }
0185 
0186     return NULL;
0187 }
0188 
0189 static bool nhlt_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
0190                 u32 bus_id, u8 link_type, u8 dir, u8 dev_type)
0191 {
0192     dev_dbg(dev, "Endpoint: vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
0193         epnt->virtual_bus_id, epnt->linktype,
0194         epnt->direction, epnt->device_type);
0195 
0196     if ((epnt->virtual_bus_id != bus_id) ||
0197         (epnt->linktype != link_type) ||
0198         (epnt->direction != dir))
0199         return false;
0200 
0201     /* link of type DMIC bypasses device_type check */
0202     return epnt->linktype == NHLT_LINK_DMIC ||
0203            epnt->device_type == dev_type;
0204 }
0205 
0206 struct nhlt_specific_cfg *
0207 intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
0208                  u32 bus_id, u8 link_type, u8 vbps, u8 bps,
0209                  u8 num_ch, u32 rate, u8 dir, u8 dev_type)
0210 {
0211     struct nhlt_specific_cfg *cfg;
0212     struct nhlt_endpoint *epnt;
0213     struct nhlt_fmt *fmt;
0214     int i;
0215 
0216     if (!nhlt)
0217         return NULL;
0218 
0219     dev_dbg(dev, "Looking for configuration:\n");
0220     dev_dbg(dev, "  vbus_id=%d link_type=%d dir=%d, dev_type=%d\n",
0221         bus_id, link_type, dir, dev_type);
0222     dev_dbg(dev, "  ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
0223     dev_dbg(dev, "Endpoint count=%d\n", nhlt->endpoint_count);
0224 
0225     epnt = (struct nhlt_endpoint *)nhlt->desc;
0226 
0227     for (i = 0; i < nhlt->endpoint_count; i++) {
0228         if (nhlt_check_ep_match(dev, epnt, bus_id, link_type, dir, dev_type)) {
0229             fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
0230 
0231             cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate, vbps, bps);
0232             if (cfg)
0233                 return cfg;
0234         }
0235 
0236         epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
0237     }
0238 
0239     return NULL;
0240 }
0241 EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob);