0001
0002
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
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
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
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
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);