cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel-nhlt.c (6361B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright (c) 2015-2019 Intel Corporation
      3
      4#include <linux/acpi.h>
      5#include <sound/intel-nhlt.h>
      6
      7struct nhlt_acpi_table *intel_nhlt_init(struct device *dev)
      8{
      9	struct nhlt_acpi_table *nhlt;
     10	acpi_status status;
     11
     12	status = acpi_get_table(ACPI_SIG_NHLT, 0,
     13				(struct acpi_table_header **)&nhlt);
     14	if (ACPI_FAILURE(status)) {
     15		dev_warn(dev, "NHLT table not found\n");
     16		return NULL;
     17	}
     18
     19	return nhlt;
     20}
     21EXPORT_SYMBOL_GPL(intel_nhlt_init);
     22
     23void intel_nhlt_free(struct nhlt_acpi_table *nhlt)
     24{
     25	acpi_put_table((struct acpi_table_header *)nhlt);
     26}
     27EXPORT_SYMBOL_GPL(intel_nhlt_free);
     28
     29int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
     30{
     31	struct nhlt_endpoint *epnt;
     32	struct nhlt_dmic_array_config *cfg;
     33	struct nhlt_vendor_dmic_array_config *cfg_vendor;
     34	struct nhlt_fmt *fmt_configs;
     35	unsigned int dmic_geo = 0;
     36	u16 max_ch = 0;
     37	u8 i, j;
     38
     39	if (!nhlt)
     40		return 0;
     41
     42	if (nhlt->header.length <= sizeof(struct acpi_table_header)) {
     43		dev_warn(dev, "Invalid DMIC description table\n");
     44		return 0;
     45	}
     46
     47	for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++,
     48	     epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) {
     49
     50		if (epnt->linktype != NHLT_LINK_DMIC)
     51			continue;
     52
     53		cfg = (struct nhlt_dmic_array_config  *)(epnt->config.caps);
     54		fmt_configs = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
     55
     56		/* find max number of channels based on format_configuration */
     57		if (fmt_configs->fmt_count) {
     58			dev_dbg(dev, "found %d format definitions\n",
     59				fmt_configs->fmt_count);
     60
     61			for (i = 0; i < fmt_configs->fmt_count; i++) {
     62				struct wav_fmt_ext *fmt_ext;
     63
     64				fmt_ext = &fmt_configs->fmt_config[i].fmt_ext;
     65
     66				if (fmt_ext->fmt.channels > max_ch)
     67					max_ch = fmt_ext->fmt.channels;
     68			}
     69			dev_dbg(dev, "max channels found %d\n", max_ch);
     70		} else {
     71			dev_dbg(dev, "No format information found\n");
     72		}
     73
     74		if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) {
     75			dmic_geo = max_ch;
     76		} else {
     77			switch (cfg->array_type) {
     78			case NHLT_MIC_ARRAY_2CH_SMALL:
     79			case NHLT_MIC_ARRAY_2CH_BIG:
     80				dmic_geo = MIC_ARRAY_2CH;
     81				break;
     82
     83			case NHLT_MIC_ARRAY_4CH_1ST_GEOM:
     84			case NHLT_MIC_ARRAY_4CH_L_SHAPED:
     85			case NHLT_MIC_ARRAY_4CH_2ND_GEOM:
     86				dmic_geo = MIC_ARRAY_4CH;
     87				break;
     88			case NHLT_MIC_ARRAY_VENDOR_DEFINED:
     89				cfg_vendor = (struct nhlt_vendor_dmic_array_config *)cfg;
     90				dmic_geo = cfg_vendor->nb_mics;
     91				break;
     92			default:
     93				dev_warn(dev, "%s: undefined DMIC array_type 0x%0x\n",
     94					 __func__, cfg->array_type);
     95			}
     96
     97			if (dmic_geo > 0) {
     98				dev_dbg(dev, "Array with %d dmics\n", dmic_geo);
     99			}
    100			if (max_ch > dmic_geo) {
    101				dev_dbg(dev, "max channels %d exceed dmic number %d\n",
    102					max_ch, dmic_geo);
    103			}
    104		}
    105	}
    106
    107	dev_dbg(dev, "dmic number %d max_ch %d\n", dmic_geo, max_ch);
    108
    109	return dmic_geo;
    110}
    111EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
    112
    113bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type)
    114{
    115	struct nhlt_endpoint *epnt;
    116	int i;
    117
    118	if (!nhlt)
    119		return false;
    120
    121	epnt = (struct nhlt_endpoint *)nhlt->desc;
    122	for (i = 0; i < nhlt->endpoint_count; i++) {
    123		if (epnt->linktype == link_type)
    124			return true;
    125
    126		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
    127	}
    128	return false;
    129}
    130EXPORT_SYMBOL(intel_nhlt_has_endpoint_type);
    131
    132int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type)
    133{
    134	struct nhlt_endpoint *epnt;
    135	int ssp_mask = 0;
    136	int i;
    137
    138	if (!nhlt || (device_type != NHLT_DEVICE_BT && device_type != NHLT_DEVICE_I2S))
    139		return 0;
    140
    141	epnt = (struct nhlt_endpoint *)nhlt->desc;
    142	for (i = 0; i < nhlt->endpoint_count; i++) {
    143		if (epnt->linktype == NHLT_LINK_SSP && epnt->device_type == device_type) {
    144			/* for SSP the virtual bus id is the SSP port */
    145			ssp_mask |= BIT(epnt->virtual_bus_id);
    146		}
    147		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
    148	}
    149
    150	return ssp_mask;
    151}
    152EXPORT_SYMBOL(intel_nhlt_ssp_endpoint_mask);
    153
    154static struct nhlt_specific_cfg *
    155nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
    156		      u32 rate, u8 vbps, u8 bps)
    157{
    158	struct nhlt_fmt_cfg *cfg = fmt->fmt_config;
    159	struct wav_fmt *wfmt;
    160	u16 _bps, _vbps;
    161	int i;
    162
    163	dev_dbg(dev, "Endpoint format count=%d\n", fmt->fmt_count);
    164
    165	for (i = 0; i < fmt->fmt_count; i++) {
    166		wfmt = &cfg->fmt_ext.fmt;
    167		_bps = wfmt->bits_per_sample;
    168		_vbps = cfg->fmt_ext.sample.valid_bits_per_sample;
    169
    170		dev_dbg(dev, "Endpoint format: ch=%d fmt=%d/%d rate=%d\n",
    171			wfmt->channels, _vbps, _bps, wfmt->samples_per_sec);
    172
    173		if (wfmt->channels == num_ch && wfmt->samples_per_sec == rate &&
    174		    vbps == _vbps && bps == _bps)
    175			return &cfg->config;
    176
    177		cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size);
    178	}
    179
    180	return NULL;
    181}
    182
    183static bool nhlt_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
    184				u32 bus_id, u8 link_type, u8 dir, u8 dev_type)
    185{
    186	dev_dbg(dev, "Endpoint: vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
    187		epnt->virtual_bus_id, epnt->linktype,
    188		epnt->direction, epnt->device_type);
    189
    190	if ((epnt->virtual_bus_id != bus_id) ||
    191	    (epnt->linktype != link_type) ||
    192	    (epnt->direction != dir))
    193		return false;
    194
    195	/* link of type DMIC bypasses device_type check */
    196	return epnt->linktype == NHLT_LINK_DMIC ||
    197	       epnt->device_type == dev_type;
    198}
    199
    200struct nhlt_specific_cfg *
    201intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
    202			     u32 bus_id, u8 link_type, u8 vbps, u8 bps,
    203			     u8 num_ch, u32 rate, u8 dir, u8 dev_type)
    204{
    205	struct nhlt_specific_cfg *cfg;
    206	struct nhlt_endpoint *epnt;
    207	struct nhlt_fmt *fmt;
    208	int i;
    209
    210	if (!nhlt)
    211		return NULL;
    212
    213	dev_dbg(dev, "Looking for configuration:\n");
    214	dev_dbg(dev, "  vbus_id=%d link_type=%d dir=%d, dev_type=%d\n",
    215		bus_id, link_type, dir, dev_type);
    216	dev_dbg(dev, "  ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
    217	dev_dbg(dev, "Endpoint count=%d\n", nhlt->endpoint_count);
    218
    219	epnt = (struct nhlt_endpoint *)nhlt->desc;
    220
    221	for (i = 0; i < nhlt->endpoint_count; i++) {
    222		if (nhlt_check_ep_match(dev, epnt, bus_id, link_type, dir, dev_type)) {
    223			fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
    224
    225			cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate, vbps, bps);
    226			if (cfg)
    227				return cfg;
    228		}
    229
    230		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
    231	}
    232
    233	return NULL;
    234}
    235EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob);