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

skl-nhlt.c (6934B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  skl-nhlt.c - Intel SKL Platform NHLT parsing
      4 *
      5 *  Copyright (C) 2015 Intel Corp
      6 *  Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
      7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      8 *
      9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     10 */
     11#include <linux/pci.h>
     12#include <sound/intel-nhlt.h>
     13#include "skl.h"
     14#include "skl-i2s.h"
     15
     16static void skl_nhlt_trim_space(char *trim)
     17{
     18	char *s = trim;
     19	int cnt;
     20	int i;
     21
     22	cnt = 0;
     23	for (i = 0; s[i]; i++) {
     24		if (!isspace(s[i]))
     25			s[cnt++] = s[i];
     26	}
     27
     28	s[cnt] = '\0';
     29}
     30
     31int skl_nhlt_update_topology_bin(struct skl_dev *skl)
     32{
     33	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
     34	struct hdac_bus *bus = skl_to_bus(skl);
     35	struct device *dev = bus->dev;
     36
     37	dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n",
     38		nhlt->header.oem_id, nhlt->header.oem_table_id,
     39		nhlt->header.oem_revision);
     40
     41	snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s",
     42		skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
     43		nhlt->header.oem_revision, "-tplg.bin");
     44
     45	skl_nhlt_trim_space(skl->tplg_name);
     46
     47	return 0;
     48}
     49
     50static ssize_t platform_id_show(struct device *dev,
     51				struct device_attribute *attr, char *buf)
     52{
     53	struct pci_dev *pci = to_pci_dev(dev);
     54	struct hdac_bus *bus = pci_get_drvdata(pci);
     55	struct skl_dev *skl = bus_to_skl(bus);
     56	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
     57	char platform_id[32];
     58
     59	sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
     60			nhlt->header.oem_id, nhlt->header.oem_table_id,
     61			nhlt->header.oem_revision);
     62
     63	skl_nhlt_trim_space(platform_id);
     64	return sprintf(buf, "%s\n", platform_id);
     65}
     66
     67static DEVICE_ATTR_RO(platform_id);
     68
     69int skl_nhlt_create_sysfs(struct skl_dev *skl)
     70{
     71	struct device *dev = &skl->pci->dev;
     72
     73	if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
     74		dev_warn(dev, "Error creating sysfs entry\n");
     75
     76	return 0;
     77}
     78
     79void skl_nhlt_remove_sysfs(struct skl_dev *skl)
     80{
     81	struct device *dev = &skl->pci->dev;
     82
     83	if (skl->nhlt)
     84		sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
     85}
     86
     87/*
     88 * Queries NHLT for all the fmt configuration for a particular endpoint and
     89 * stores all possible rates supported in a rate table for the corresponding
     90 * sclk/sclkfs.
     91 */
     92static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
     93				struct nhlt_fmt *fmt, u8 id)
     94{
     95	struct skl_i2s_config_blob_ext *i2s_config_ext;
     96	struct skl_i2s_config_blob_legacy *i2s_config;
     97	struct skl_clk_parent_src *parent;
     98	struct skl_ssp_clk *sclk, *sclkfs;
     99	struct nhlt_fmt_cfg *fmt_cfg;
    100	struct wav_fmt_ext *wav_fmt;
    101	unsigned long rate;
    102	bool present = false;
    103	int rate_index = 0;
    104	u16 channels, bps;
    105	u8 clk_src;
    106	int i, j;
    107	u32 fs;
    108
    109	sclk = &ssp_clks[SKL_SCLK_OFS];
    110	sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
    111
    112	if (fmt->fmt_count == 0)
    113		return;
    114
    115	for (i = 0; i < fmt->fmt_count; i++) {
    116		fmt_cfg = &fmt->fmt_config[i];
    117		wav_fmt = &fmt_cfg->fmt_ext;
    118
    119		channels = wav_fmt->fmt.channels;
    120		bps = wav_fmt->fmt.bits_per_sample;
    121		fs = wav_fmt->fmt.samples_per_sec;
    122
    123		/*
    124		 * In case of TDM configuration on a ssp, there can
    125		 * be more than one blob in which channel masks are
    126		 * different for each usecase for a specific rate and bps.
    127		 * But the sclk rate will be generated for the total
    128		 * number of channels used for that endpoint.
    129		 *
    130		 * So for the given fs and bps, choose blob which has
    131		 * the superset of all channels for that endpoint and
    132		 * derive the rate.
    133		 */
    134		for (j = i; j < fmt->fmt_count; j++) {
    135			fmt_cfg = &fmt->fmt_config[j];
    136			wav_fmt = &fmt_cfg->fmt_ext;
    137			if ((fs == wav_fmt->fmt.samples_per_sec) &&
    138			   (bps == wav_fmt->fmt.bits_per_sample))
    139				channels = max_t(u16, channels,
    140						wav_fmt->fmt.channels);
    141		}
    142
    143		rate = channels * bps * fs;
    144
    145		/* check if the rate is added already to the given SSP's sclk */
    146		for (j = 0; (j < SKL_MAX_CLK_RATES) &&
    147			    (sclk[id].rate_cfg[j].rate != 0); j++) {
    148			if (sclk[id].rate_cfg[j].rate == rate) {
    149				present = true;
    150				break;
    151			}
    152		}
    153
    154		/* Fill rate and parent for sclk/sclkfs */
    155		if (!present) {
    156			i2s_config_ext = (struct skl_i2s_config_blob_ext *)
    157						fmt->fmt_config[0].config.caps;
    158
    159			/* MCLK Divider Source Select */
    160			if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
    161				i2s_config = ext_to_legacy_blob(i2s_config_ext);
    162				clk_src = get_clk_src(i2s_config->mclk,
    163						SKL_MNDSS_DIV_CLK_SRC_MASK);
    164			} else {
    165				clk_src = get_clk_src(i2s_config_ext->mclk,
    166						SKL_MNDSS_DIV_CLK_SRC_MASK);
    167			}
    168
    169			parent = skl_get_parent_clk(clk_src);
    170
    171			/*
    172			 * Do not copy the config data if there is no parent
    173			 * clock available for this clock source select
    174			 */
    175			if (!parent)
    176				continue;
    177
    178			sclk[id].rate_cfg[rate_index].rate = rate;
    179			sclk[id].rate_cfg[rate_index].config = fmt_cfg;
    180			sclkfs[id].rate_cfg[rate_index].rate = rate;
    181			sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
    182			sclk[id].parent_name = parent->name;
    183			sclkfs[id].parent_name = parent->name;
    184
    185			rate_index++;
    186		}
    187	}
    188}
    189
    190static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
    191				struct nhlt_fmt *fmt, u8 id)
    192{
    193	struct skl_i2s_config_blob_ext *i2s_config_ext;
    194	struct skl_i2s_config_blob_legacy *i2s_config;
    195	struct nhlt_specific_cfg *fmt_cfg;
    196	struct skl_clk_parent_src *parent;
    197	u32 clkdiv, div_ratio;
    198	u8 clk_src;
    199
    200	fmt_cfg = &fmt->fmt_config[0].config;
    201	i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
    202
    203	/* MCLK Divider Source Select and divider */
    204	if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
    205		i2s_config = ext_to_legacy_blob(i2s_config_ext);
    206		clk_src = get_clk_src(i2s_config->mclk,
    207				SKL_MCLK_DIV_CLK_SRC_MASK);
    208		clkdiv = i2s_config->mclk.mdivr &
    209				SKL_MCLK_DIV_RATIO_MASK;
    210	} else {
    211		clk_src = get_clk_src(i2s_config_ext->mclk,
    212				SKL_MCLK_DIV_CLK_SRC_MASK);
    213		clkdiv = i2s_config_ext->mclk.mdivr[0] &
    214				SKL_MCLK_DIV_RATIO_MASK;
    215	}
    216
    217	/* bypass divider */
    218	div_ratio = 1;
    219
    220	if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
    221		/* Divider is 2 + clkdiv */
    222		div_ratio = clkdiv + 2;
    223
    224	/* Calculate MCLK rate from source using div value */
    225	parent = skl_get_parent_clk(clk_src);
    226	if (!parent)
    227		return;
    228
    229	mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
    230	mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
    231	mclk[id].parent_name = parent->name;
    232}
    233
    234void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks)
    235{
    236	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
    237	struct nhlt_endpoint *epnt;
    238	struct nhlt_fmt *fmt;
    239	int i;
    240	u8 id;
    241
    242	epnt = (struct nhlt_endpoint *)nhlt->desc;
    243	for (i = 0; i < nhlt->endpoint_count; i++) {
    244		if (epnt->linktype == NHLT_LINK_SSP) {
    245			id = epnt->virtual_bus_id;
    246
    247			fmt = (struct nhlt_fmt *)(epnt->config.caps
    248					+ epnt->config.size);
    249
    250			skl_get_ssp_clks(skl, ssp_clks, fmt, id);
    251			skl_get_mclk(skl, ssp_clks, fmt, id);
    252		}
    253		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
    254	}
    255}