18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  skl-nhlt.c - Intel SKL Platform NHLT parsing
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2015 Intel Corp
68c2ecf20Sopenharmony_ci *  Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
78c2ecf20Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <sound/intel-nhlt.h>
138c2ecf20Sopenharmony_ci#include "skl.h"
148c2ecf20Sopenharmony_ci#include "skl-i2s.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic struct nhlt_specific_cfg *skl_get_specific_cfg(
178c2ecf20Sopenharmony_ci		struct device *dev, struct nhlt_fmt *fmt,
188c2ecf20Sopenharmony_ci		u8 no_ch, u32 rate, u16 bps, u8 linktype)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct nhlt_specific_cfg *sp_config;
218c2ecf20Sopenharmony_ci	struct wav_fmt *wfmt;
228c2ecf20Sopenharmony_ci	struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config;
238c2ecf20Sopenharmony_ci	int i;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	dev_dbg(dev, "Format count =%d\n", fmt->fmt_count);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	for (i = 0; i < fmt->fmt_count; i++) {
288c2ecf20Sopenharmony_ci		wfmt = &fmt_config->fmt_ext.fmt;
298c2ecf20Sopenharmony_ci		dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
308c2ecf20Sopenharmony_ci			 wfmt->bits_per_sample, wfmt->samples_per_sec);
318c2ecf20Sopenharmony_ci		if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) {
328c2ecf20Sopenharmony_ci			/*
338c2ecf20Sopenharmony_ci			 * if link type is dmic ignore rate check as the blob is
348c2ecf20Sopenharmony_ci			 * generic for all rates
358c2ecf20Sopenharmony_ci			 */
368c2ecf20Sopenharmony_ci			sp_config = &fmt_config->config;
378c2ecf20Sopenharmony_ci			if (linktype == NHLT_LINK_DMIC)
388c2ecf20Sopenharmony_ci				return sp_config;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci			if (wfmt->samples_per_sec == rate)
418c2ecf20Sopenharmony_ci				return sp_config;
428c2ecf20Sopenharmony_ci		}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
458c2ecf20Sopenharmony_ci						fmt_config->config.size);
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	return NULL;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void dump_config(struct device *dev, u32 instance_id, u8 linktype,
528c2ecf20Sopenharmony_ci		u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	dev_dbg(dev, "Input configuration\n");
558c2ecf20Sopenharmony_ci	dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate);
568c2ecf20Sopenharmony_ci	dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype);
578c2ecf20Sopenharmony_ci	dev_dbg(dev, "bits_per_sample=%d\n", bps);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
618c2ecf20Sopenharmony_ci		u32 instance_id, u8 link_type, u8 dirn, u8 dev_type)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
648c2ecf20Sopenharmony_ci			epnt->virtual_bus_id, epnt->linktype,
658c2ecf20Sopenharmony_ci			epnt->direction, epnt->device_type);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if ((epnt->virtual_bus_id == instance_id) &&
688c2ecf20Sopenharmony_ci			(epnt->linktype == link_type) &&
698c2ecf20Sopenharmony_ci			(epnt->direction == dirn)) {
708c2ecf20Sopenharmony_ci		/* do not check dev_type for DMIC link type */
718c2ecf20Sopenharmony_ci		if (epnt->linktype == NHLT_LINK_DMIC)
728c2ecf20Sopenharmony_ci			return true;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (epnt->device_type == dev_type)
758c2ecf20Sopenharmony_ci			return true;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return false;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct nhlt_specific_cfg
828c2ecf20Sopenharmony_ci*skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type,
838c2ecf20Sopenharmony_ci			u8 s_fmt, u8 num_ch, u32 s_rate,
848c2ecf20Sopenharmony_ci			u8 dirn, u8 dev_type)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct nhlt_fmt *fmt;
878c2ecf20Sopenharmony_ci	struct nhlt_endpoint *epnt;
888c2ecf20Sopenharmony_ci	struct hdac_bus *bus = skl_to_bus(skl);
898c2ecf20Sopenharmony_ci	struct device *dev = bus->dev;
908c2ecf20Sopenharmony_ci	struct nhlt_specific_cfg *sp_config;
918c2ecf20Sopenharmony_ci	struct nhlt_acpi_table *nhlt = skl->nhlt;
928c2ecf20Sopenharmony_ci	u16 bps = (s_fmt == 16) ? 16 : 32;
938c2ecf20Sopenharmony_ci	u8 j;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	epnt = (struct nhlt_endpoint *)nhlt->desc;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	for (j = 0; j < nhlt->endpoint_count; j++) {
1028c2ecf20Sopenharmony_ci		if (skl_check_ep_match(dev, epnt, instance, link_type,
1038c2ecf20Sopenharmony_ci						dirn, dev_type)) {
1048c2ecf20Sopenharmony_ci			fmt = (struct nhlt_fmt *)(epnt->config.caps +
1058c2ecf20Sopenharmony_ci						 epnt->config.size);
1068c2ecf20Sopenharmony_ci			sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
1078c2ecf20Sopenharmony_ci							s_rate, bps, link_type);
1088c2ecf20Sopenharmony_ci			if (sp_config)
1098c2ecf20Sopenharmony_ci				return sp_config;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return NULL;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic void skl_nhlt_trim_space(char *trim)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	char *s = trim;
1218c2ecf20Sopenharmony_ci	int cnt;
1228c2ecf20Sopenharmony_ci	int i;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	cnt = 0;
1258c2ecf20Sopenharmony_ci	for (i = 0; s[i]; i++) {
1268c2ecf20Sopenharmony_ci		if (!isspace(s[i]))
1278c2ecf20Sopenharmony_ci			s[cnt++] = s[i];
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	s[cnt] = '\0';
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciint skl_nhlt_update_topology_bin(struct skl_dev *skl)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
1368c2ecf20Sopenharmony_ci	struct hdac_bus *bus = skl_to_bus(skl);
1378c2ecf20Sopenharmony_ci	struct device *dev = bus->dev;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n",
1408c2ecf20Sopenharmony_ci		nhlt->header.oem_id, nhlt->header.oem_table_id,
1418c2ecf20Sopenharmony_ci		nhlt->header.oem_revision);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s",
1448c2ecf20Sopenharmony_ci		skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
1458c2ecf20Sopenharmony_ci		nhlt->header.oem_revision, "-tplg.bin");
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	skl_nhlt_trim_space(skl->tplg_name);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic ssize_t skl_nhlt_platform_id_show(struct device *dev,
1538c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
1568c2ecf20Sopenharmony_ci	struct hdac_bus *bus = pci_get_drvdata(pci);
1578c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
1588c2ecf20Sopenharmony_ci	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
1598c2ecf20Sopenharmony_ci	char platform_id[32];
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
1628c2ecf20Sopenharmony_ci			nhlt->header.oem_id, nhlt->header.oem_table_id,
1638c2ecf20Sopenharmony_ci			nhlt->header.oem_revision);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	skl_nhlt_trim_space(platform_id);
1668c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", platform_id);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciint skl_nhlt_create_sysfs(struct skl_dev *skl)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct device *dev = &skl->pci->dev;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
1768c2ecf20Sopenharmony_ci		dev_warn(dev, "Error creating sysfs entry\n");
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return 0;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_civoid skl_nhlt_remove_sysfs(struct skl_dev *skl)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct device *dev = &skl->pci->dev;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (skl->nhlt)
1868c2ecf20Sopenharmony_ci		sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/*
1908c2ecf20Sopenharmony_ci * Queries NHLT for all the fmt configuration for a particular endpoint and
1918c2ecf20Sopenharmony_ci * stores all possible rates supported in a rate table for the corresponding
1928c2ecf20Sopenharmony_ci * sclk/sclkfs.
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_cistatic void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
1958c2ecf20Sopenharmony_ci				struct nhlt_fmt *fmt, u8 id)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct skl_i2s_config_blob_ext *i2s_config_ext;
1988c2ecf20Sopenharmony_ci	struct skl_i2s_config_blob_legacy *i2s_config;
1998c2ecf20Sopenharmony_ci	struct skl_clk_parent_src *parent;
2008c2ecf20Sopenharmony_ci	struct skl_ssp_clk *sclk, *sclkfs;
2018c2ecf20Sopenharmony_ci	struct nhlt_fmt_cfg *fmt_cfg;
2028c2ecf20Sopenharmony_ci	struct wav_fmt_ext *wav_fmt;
2038c2ecf20Sopenharmony_ci	unsigned long rate;
2048c2ecf20Sopenharmony_ci	int rate_index = 0;
2058c2ecf20Sopenharmony_ci	u16 channels, bps;
2068c2ecf20Sopenharmony_ci	u8 clk_src;
2078c2ecf20Sopenharmony_ci	int i, j;
2088c2ecf20Sopenharmony_ci	u32 fs;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	sclk = &ssp_clks[SKL_SCLK_OFS];
2118c2ecf20Sopenharmony_ci	sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (fmt->fmt_count == 0)
2148c2ecf20Sopenharmony_ci		return;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
2178c2ecf20Sopenharmony_ci	for (i = 0; i < fmt->fmt_count; i++) {
2188c2ecf20Sopenharmony_ci		struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
2198c2ecf20Sopenharmony_ci		bool present = false;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		wav_fmt = &saved_fmt_cfg->fmt_ext;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		channels = wav_fmt->fmt.channels;
2248c2ecf20Sopenharmony_ci		bps = wav_fmt->fmt.bits_per_sample;
2258c2ecf20Sopenharmony_ci		fs = wav_fmt->fmt.samples_per_sec;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		/*
2288c2ecf20Sopenharmony_ci		 * In case of TDM configuration on a ssp, there can
2298c2ecf20Sopenharmony_ci		 * be more than one blob in which channel masks are
2308c2ecf20Sopenharmony_ci		 * different for each usecase for a specific rate and bps.
2318c2ecf20Sopenharmony_ci		 * But the sclk rate will be generated for the total
2328c2ecf20Sopenharmony_ci		 * number of channels used for that endpoint.
2338c2ecf20Sopenharmony_ci		 *
2348c2ecf20Sopenharmony_ci		 * So for the given fs and bps, choose blob which has
2358c2ecf20Sopenharmony_ci		 * the superset of all channels for that endpoint and
2368c2ecf20Sopenharmony_ci		 * derive the rate.
2378c2ecf20Sopenharmony_ci		 */
2388c2ecf20Sopenharmony_ci		for (j = i; j < fmt->fmt_count; j++) {
2398c2ecf20Sopenharmony_ci			struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci			wav_fmt = &tmp_fmt_cfg->fmt_ext;
2428c2ecf20Sopenharmony_ci			if ((fs == wav_fmt->fmt.samples_per_sec) &&
2438c2ecf20Sopenharmony_ci			   (bps == wav_fmt->fmt.bits_per_sample)) {
2448c2ecf20Sopenharmony_ci				channels = max_t(u16, channels,
2458c2ecf20Sopenharmony_ci						wav_fmt->fmt.channels);
2468c2ecf20Sopenharmony_ci				saved_fmt_cfg = tmp_fmt_cfg;
2478c2ecf20Sopenharmony_ci			}
2488c2ecf20Sopenharmony_ci			/* Move to the next nhlt_fmt_cfg */
2498c2ecf20Sopenharmony_ci			tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
2508c2ecf20Sopenharmony_ci							      tmp_fmt_cfg->config.size);
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		rate = channels * bps * fs;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		/* check if the rate is added already to the given SSP's sclk */
2568c2ecf20Sopenharmony_ci		for (j = 0; (j < SKL_MAX_CLK_RATES) &&
2578c2ecf20Sopenharmony_ci			    (sclk[id].rate_cfg[j].rate != 0); j++) {
2588c2ecf20Sopenharmony_ci			if (sclk[id].rate_cfg[j].rate == rate) {
2598c2ecf20Sopenharmony_ci				present = true;
2608c2ecf20Sopenharmony_ci				break;
2618c2ecf20Sopenharmony_ci			}
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		/* Fill rate and parent for sclk/sclkfs */
2658c2ecf20Sopenharmony_ci		if (!present) {
2668c2ecf20Sopenharmony_ci			struct nhlt_fmt_cfg *first_fmt_cfg;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci			first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
2698c2ecf20Sopenharmony_ci			i2s_config_ext = (struct skl_i2s_config_blob_ext *)
2708c2ecf20Sopenharmony_ci						first_fmt_cfg->config.caps;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci			/* MCLK Divider Source Select */
2738c2ecf20Sopenharmony_ci			if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
2748c2ecf20Sopenharmony_ci				i2s_config = ext_to_legacy_blob(i2s_config_ext);
2758c2ecf20Sopenharmony_ci				clk_src = get_clk_src(i2s_config->mclk,
2768c2ecf20Sopenharmony_ci						SKL_MNDSS_DIV_CLK_SRC_MASK);
2778c2ecf20Sopenharmony_ci			} else {
2788c2ecf20Sopenharmony_ci				clk_src = get_clk_src(i2s_config_ext->mclk,
2798c2ecf20Sopenharmony_ci						SKL_MNDSS_DIV_CLK_SRC_MASK);
2808c2ecf20Sopenharmony_ci			}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			parent = skl_get_parent_clk(clk_src);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci			/* Move to the next nhlt_fmt_cfg */
2858c2ecf20Sopenharmony_ci			fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
2868c2ecf20Sopenharmony_ci							  fmt_cfg->config.size);
2878c2ecf20Sopenharmony_ci			/*
2888c2ecf20Sopenharmony_ci			 * Do not copy the config data if there is no parent
2898c2ecf20Sopenharmony_ci			 * clock available for this clock source select
2908c2ecf20Sopenharmony_ci			 */
2918c2ecf20Sopenharmony_ci			if (!parent)
2928c2ecf20Sopenharmony_ci				continue;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci			sclk[id].rate_cfg[rate_index].rate = rate;
2958c2ecf20Sopenharmony_ci			sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
2968c2ecf20Sopenharmony_ci			sclkfs[id].rate_cfg[rate_index].rate = rate;
2978c2ecf20Sopenharmony_ci			sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
2988c2ecf20Sopenharmony_ci			sclk[id].parent_name = parent->name;
2998c2ecf20Sopenharmony_ci			sclkfs[id].parent_name = parent->name;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci			rate_index++;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
3078c2ecf20Sopenharmony_ci				struct nhlt_fmt *fmt, u8 id)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct skl_i2s_config_blob_ext *i2s_config_ext;
3108c2ecf20Sopenharmony_ci	struct skl_i2s_config_blob_legacy *i2s_config;
3118c2ecf20Sopenharmony_ci	struct nhlt_fmt_cfg *fmt_cfg;
3128c2ecf20Sopenharmony_ci	struct skl_clk_parent_src *parent;
3138c2ecf20Sopenharmony_ci	u32 clkdiv, div_ratio;
3148c2ecf20Sopenharmony_ci	u8 clk_src;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
3178c2ecf20Sopenharmony_ci	i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* MCLK Divider Source Select and divider */
3208c2ecf20Sopenharmony_ci	if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
3218c2ecf20Sopenharmony_ci		i2s_config = ext_to_legacy_blob(i2s_config_ext);
3228c2ecf20Sopenharmony_ci		clk_src = get_clk_src(i2s_config->mclk,
3238c2ecf20Sopenharmony_ci				SKL_MCLK_DIV_CLK_SRC_MASK);
3248c2ecf20Sopenharmony_ci		clkdiv = i2s_config->mclk.mdivr &
3258c2ecf20Sopenharmony_ci				SKL_MCLK_DIV_RATIO_MASK;
3268c2ecf20Sopenharmony_ci	} else {
3278c2ecf20Sopenharmony_ci		clk_src = get_clk_src(i2s_config_ext->mclk,
3288c2ecf20Sopenharmony_ci				SKL_MCLK_DIV_CLK_SRC_MASK);
3298c2ecf20Sopenharmony_ci		clkdiv = i2s_config_ext->mclk.mdivr[0] &
3308c2ecf20Sopenharmony_ci				SKL_MCLK_DIV_RATIO_MASK;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* bypass divider */
3348c2ecf20Sopenharmony_ci	div_ratio = 1;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
3378c2ecf20Sopenharmony_ci		/* Divider is 2 + clkdiv */
3388c2ecf20Sopenharmony_ci		div_ratio = clkdiv + 2;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* Calculate MCLK rate from source using div value */
3418c2ecf20Sopenharmony_ci	parent = skl_get_parent_clk(clk_src);
3428c2ecf20Sopenharmony_ci	if (!parent)
3438c2ecf20Sopenharmony_ci		return;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
3468c2ecf20Sopenharmony_ci	mclk[id].rate_cfg[0].config = fmt_cfg;
3478c2ecf20Sopenharmony_ci	mclk[id].parent_name = parent->name;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_civoid skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
3538c2ecf20Sopenharmony_ci	struct nhlt_endpoint *epnt;
3548c2ecf20Sopenharmony_ci	struct nhlt_fmt *fmt;
3558c2ecf20Sopenharmony_ci	int i;
3568c2ecf20Sopenharmony_ci	u8 id;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	epnt = (struct nhlt_endpoint *)nhlt->desc;
3598c2ecf20Sopenharmony_ci	for (i = 0; i < nhlt->endpoint_count; i++) {
3608c2ecf20Sopenharmony_ci		if (epnt->linktype == NHLT_LINK_SSP) {
3618c2ecf20Sopenharmony_ci			id = epnt->virtual_bus_id;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			fmt = (struct nhlt_fmt *)(epnt->config.caps
3648c2ecf20Sopenharmony_ci					+ epnt->config.size);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci			skl_get_ssp_clks(skl, ssp_clks, fmt, id);
3678c2ecf20Sopenharmony_ci			skl_get_mclk(skl, ssp_clks, fmt, id);
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci		epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci}
372