18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2473eb87aSJeeja KP /* 3473eb87aSJeeja KP * skl-nhlt.c - Intel SKL Platform NHLT parsing 4473eb87aSJeeja KP * 5473eb87aSJeeja KP * Copyright (C) 2015 Intel Corp 6473eb87aSJeeja KP * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> 7473eb87aSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8473eb87aSJeeja KP * 9473eb87aSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10473eb87aSJeeja KP */ 11f65cf7d6SYong Zhi #include <linux/pci.h> 12473eb87aSJeeja KP #include "skl.h" 13bc2bd45bSSriram Periyasamy #include "skl-i2s.h" 14473eb87aSJeeja KP 153b47c9dcSPankaj Bharadiya #define NHLT_ACPI_HEADER_SIG "NHLT" 163b47c9dcSPankaj Bharadiya 17473eb87aSJeeja KP /* Unique identification for getting NHLT blobs */ 1894116f81SAndy Shevchenko static guid_t osc_guid = 1994116f81SAndy Shevchenko GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, 2094116f81SAndy Shevchenko 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); 21473eb87aSJeeja KP 229afbc5ecSSriram Periyasamy 23c286b3f9SJeeja KP struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) 24473eb87aSJeeja KP { 25473eb87aSJeeja KP acpi_handle handle; 26473eb87aSJeeja KP union acpi_object *obj; 27473eb87aSJeeja KP struct nhlt_resource_desc *nhlt_ptr = NULL; 28c286b3f9SJeeja KP struct nhlt_acpi_table *nhlt_table = NULL; 29473eb87aSJeeja KP 306ad0005fSVinod Koul handle = ACPI_HANDLE(dev); 316ad0005fSVinod Koul if (!handle) { 326ad0005fSVinod Koul dev_err(dev, "Didn't find ACPI_HANDLE\n"); 33473eb87aSJeeja KP return NULL; 34473eb87aSJeeja KP } 35473eb87aSJeeja KP 3694116f81SAndy Shevchenko obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); 37473eb87aSJeeja KP if (obj && obj->type == ACPI_TYPE_BUFFER) { 38473eb87aSJeeja KP nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; 3920a1ea22STakashi Iwai if (nhlt_ptr->length) 40c286b3f9SJeeja KP nhlt_table = (struct nhlt_acpi_table *) 41c286b3f9SJeeja KP memremap(nhlt_ptr->min_addr, nhlt_ptr->length, 42ba40a854SDan Williams MEMREMAP_WB); 43c286b3f9SJeeja KP ACPI_FREE(obj); 443b47c9dcSPankaj Bharadiya if (nhlt_table && (strncmp(nhlt_table->header.signature, 453b47c9dcSPankaj Bharadiya NHLT_ACPI_HEADER_SIG, 463b47c9dcSPankaj Bharadiya strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { 473b47c9dcSPankaj Bharadiya memunmap(nhlt_table); 483b47c9dcSPankaj Bharadiya dev_err(dev, "NHLT ACPI header signature incorrect\n"); 493b47c9dcSPankaj Bharadiya return NULL; 503b47c9dcSPankaj Bharadiya } 51c286b3f9SJeeja KP return nhlt_table; 52473eb87aSJeeja KP } 53473eb87aSJeeja KP 54473eb87aSJeeja KP dev_err(dev, "device specific method to extract NHLT blob failed\n"); 55473eb87aSJeeja KP return NULL; 56473eb87aSJeeja KP } 57473eb87aSJeeja KP 58c286b3f9SJeeja KP void skl_nhlt_free(struct nhlt_acpi_table *nhlt) 59473eb87aSJeeja KP { 60c286b3f9SJeeja KP memunmap((void *) nhlt); 61473eb87aSJeeja KP } 62473eb87aSJeeja KP 63473eb87aSJeeja KP static struct nhlt_specific_cfg *skl_get_specific_cfg( 64473eb87aSJeeja KP struct device *dev, struct nhlt_fmt *fmt, 6516882d24SJeeja KP u8 no_ch, u32 rate, u16 bps, u8 linktype) 66473eb87aSJeeja KP { 67473eb87aSJeeja KP struct nhlt_specific_cfg *sp_config; 68473eb87aSJeeja KP struct wav_fmt *wfmt; 69473eb87aSJeeja KP struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; 70473eb87aSJeeja KP int i; 71473eb87aSJeeja KP 72473eb87aSJeeja KP dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); 73473eb87aSJeeja KP 74473eb87aSJeeja KP for (i = 0; i < fmt->fmt_count; i++) { 75473eb87aSJeeja KP wfmt = &fmt_config->fmt_ext.fmt; 76473eb87aSJeeja KP dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, 77473eb87aSJeeja KP wfmt->bits_per_sample, wfmt->samples_per_sec); 7816882d24SJeeja KP if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { 7916882d24SJeeja KP /* 8016882d24SJeeja KP * if link type is dmic ignore rate check as the blob is 8116882d24SJeeja KP * generic for all rates 8216882d24SJeeja KP */ 83473eb87aSJeeja KP sp_config = &fmt_config->config; 8416882d24SJeeja KP if (linktype == NHLT_LINK_DMIC) 8516882d24SJeeja KP return sp_config; 86473eb87aSJeeja KP 8716882d24SJeeja KP if (wfmt->samples_per_sec == rate) 88473eb87aSJeeja KP return sp_config; 89473eb87aSJeeja KP } 90473eb87aSJeeja KP 91473eb87aSJeeja KP fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + 92473eb87aSJeeja KP fmt_config->config.size); 93473eb87aSJeeja KP } 94473eb87aSJeeja KP 95473eb87aSJeeja KP return NULL; 96473eb87aSJeeja KP } 97473eb87aSJeeja KP 98473eb87aSJeeja KP static void dump_config(struct device *dev, u32 instance_id, u8 linktype, 99473eb87aSJeeja KP u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) 100473eb87aSJeeja KP { 101473eb87aSJeeja KP dev_dbg(dev, "Input configuration\n"); 102473eb87aSJeeja KP dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); 103473eb87aSJeeja KP dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); 104473eb87aSJeeja KP dev_dbg(dev, "bits_per_sample=%d\n", bps); 105473eb87aSJeeja KP } 106473eb87aSJeeja KP 107473eb87aSJeeja KP static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, 108db2f586bSSenthilnathan Veppur u32 instance_id, u8 link_type, u8 dirn, u8 dev_type) 109473eb87aSJeeja KP { 110db2f586bSSenthilnathan Veppur dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n", 111db2f586bSSenthilnathan Veppur epnt->virtual_bus_id, epnt->linktype, 112db2f586bSSenthilnathan Veppur epnt->direction, epnt->device_type); 113473eb87aSJeeja KP 114473eb87aSJeeja KP if ((epnt->virtual_bus_id == instance_id) && 115473eb87aSJeeja KP (epnt->linktype == link_type) && 116e02b0330SGuneshwor Singh (epnt->direction == dirn)) { 117e02b0330SGuneshwor Singh /* do not check dev_type for DMIC link type */ 118e02b0330SGuneshwor Singh if (epnt->linktype == NHLT_LINK_DMIC) 119473eb87aSJeeja KP return true; 120e02b0330SGuneshwor Singh 121e02b0330SGuneshwor Singh if (epnt->device_type == dev_type) 122e02b0330SGuneshwor Singh return true; 123e02b0330SGuneshwor Singh } 124e02b0330SGuneshwor Singh 125473eb87aSJeeja KP return false; 126473eb87aSJeeja KP } 127473eb87aSJeeja KP 128473eb87aSJeeja KP struct nhlt_specific_cfg 129bcc2a2dcSCezary Rojewski *skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, 130db2f586bSSenthilnathan Veppur u8 s_fmt, u8 num_ch, u32 s_rate, 131db2f586bSSenthilnathan Veppur u8 dirn, u8 dev_type) 132473eb87aSJeeja KP { 133473eb87aSJeeja KP struct nhlt_fmt *fmt; 134473eb87aSJeeja KP struct nhlt_endpoint *epnt; 13576f56faeSRakesh Ughreja struct hdac_bus *bus = skl_to_bus(skl); 136473eb87aSJeeja KP struct device *dev = bus->dev; 137473eb87aSJeeja KP struct nhlt_specific_cfg *sp_config; 138c286b3f9SJeeja KP struct nhlt_acpi_table *nhlt = skl->nhlt; 13983b50246SJeeja KP u16 bps = (s_fmt == 16) ? 16 : 32; 140473eb87aSJeeja KP u8 j; 141473eb87aSJeeja KP 142473eb87aSJeeja KP dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); 143473eb87aSJeeja KP 144473eb87aSJeeja KP epnt = (struct nhlt_endpoint *)nhlt->desc; 145473eb87aSJeeja KP 146473eb87aSJeeja KP dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); 147473eb87aSJeeja KP 148473eb87aSJeeja KP for (j = 0; j < nhlt->endpoint_count; j++) { 149db2f586bSSenthilnathan Veppur if (skl_check_ep_match(dev, epnt, instance, link_type, 150db2f586bSSenthilnathan Veppur dirn, dev_type)) { 151473eb87aSJeeja KP fmt = (struct nhlt_fmt *)(epnt->config.caps + 152473eb87aSJeeja KP epnt->config.size); 15316882d24SJeeja KP sp_config = skl_get_specific_cfg(dev, fmt, num_ch, 15416882d24SJeeja KP s_rate, bps, link_type); 155473eb87aSJeeja KP if (sp_config) 156473eb87aSJeeja KP return sp_config; 157473eb87aSJeeja KP } 158473eb87aSJeeja KP 159473eb87aSJeeja KP epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 160473eb87aSJeeja KP } 161473eb87aSJeeja KP 162473eb87aSJeeja KP return NULL; 163473eb87aSJeeja KP } 1644b235c43SVinod Koul 165bcc2a2dcSCezary Rojewski int skl_get_dmic_geo(struct skl_dev *skl) 166f65cf7d6SYong Zhi { 167f65cf7d6SYong Zhi struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 168f65cf7d6SYong Zhi struct nhlt_endpoint *epnt; 169f65cf7d6SYong Zhi struct nhlt_dmic_array_config *cfg; 170f65cf7d6SYong Zhi struct device *dev = &skl->pci->dev; 171f65cf7d6SYong Zhi unsigned int dmic_geo = 0; 172f65cf7d6SYong Zhi u8 j; 173f65cf7d6SYong Zhi 174f231c34cSPierre-Louis Bossart if (!nhlt) 175f231c34cSPierre-Louis Bossart return 0; 176f231c34cSPierre-Louis Bossart 177f65cf7d6SYong Zhi epnt = (struct nhlt_endpoint *)nhlt->desc; 178f65cf7d6SYong Zhi 179f65cf7d6SYong Zhi for (j = 0; j < nhlt->endpoint_count; j++) { 180f65cf7d6SYong Zhi if (epnt->linktype == NHLT_LINK_DMIC) { 181f65cf7d6SYong Zhi cfg = (struct nhlt_dmic_array_config *) 182f65cf7d6SYong Zhi (epnt->config.caps); 183f65cf7d6SYong Zhi switch (cfg->array_type) { 184f65cf7d6SYong Zhi case NHLT_MIC_ARRAY_2CH_SMALL: 185f65cf7d6SYong Zhi case NHLT_MIC_ARRAY_2CH_BIG: 186f65cf7d6SYong Zhi dmic_geo |= MIC_ARRAY_2CH; 187f65cf7d6SYong Zhi break; 188f65cf7d6SYong Zhi 189f65cf7d6SYong Zhi case NHLT_MIC_ARRAY_4CH_1ST_GEOM: 190f65cf7d6SYong Zhi case NHLT_MIC_ARRAY_4CH_L_SHAPED: 191f65cf7d6SYong Zhi case NHLT_MIC_ARRAY_4CH_2ND_GEOM: 192f65cf7d6SYong Zhi dmic_geo |= MIC_ARRAY_4CH; 193f65cf7d6SYong Zhi break; 194f65cf7d6SYong Zhi 195f65cf7d6SYong Zhi default: 196f65cf7d6SYong Zhi dev_warn(dev, "undefined DMIC array_type 0x%0x\n", 197f65cf7d6SYong Zhi cfg->array_type); 198f65cf7d6SYong Zhi 199f65cf7d6SYong Zhi } 200f65cf7d6SYong Zhi } 201f65cf7d6SYong Zhi epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 202f65cf7d6SYong Zhi } 203f65cf7d6SYong Zhi 204f65cf7d6SYong Zhi return dmic_geo; 205f65cf7d6SYong Zhi } 206f65cf7d6SYong Zhi 2070cf5a171SSubhransu S. Prusty static void skl_nhlt_trim_space(char *trim) 2084b235c43SVinod Koul { 2090cf5a171SSubhransu S. Prusty char *s = trim; 2104b235c43SVinod Koul int cnt; 2114b235c43SVinod Koul int i; 2124b235c43SVinod Koul 2134b235c43SVinod Koul cnt = 0; 2144b235c43SVinod Koul for (i = 0; s[i]; i++) { 2154b235c43SVinod Koul if (!isspace(s[i])) 2164b235c43SVinod Koul s[cnt++] = s[i]; 2174b235c43SVinod Koul } 2184b235c43SVinod Koul 2194b235c43SVinod Koul s[cnt] = '\0'; 2204b235c43SVinod Koul } 2214b235c43SVinod Koul 222bcc2a2dcSCezary Rojewski int skl_nhlt_update_topology_bin(struct skl_dev *skl) 2234b235c43SVinod Koul { 2244b235c43SVinod Koul struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 22576f56faeSRakesh Ughreja struct hdac_bus *bus = skl_to_bus(skl); 2264b235c43SVinod Koul struct device *dev = bus->dev; 2274b235c43SVinod Koul 2284b235c43SVinod Koul dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n", 2294b235c43SVinod Koul nhlt->header.oem_id, nhlt->header.oem_table_id, 2304b235c43SVinod Koul nhlt->header.oem_revision); 2314b235c43SVinod Koul 2324b235c43SVinod Koul snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", 2334b235c43SVinod Koul skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, 2344b235c43SVinod Koul nhlt->header.oem_revision, "-tplg.bin"); 2354b235c43SVinod Koul 2360cf5a171SSubhransu S. Prusty skl_nhlt_trim_space(skl->tplg_name); 2374b235c43SVinod Koul 2384b235c43SVinod Koul return 0; 2394b235c43SVinod Koul } 2400cf5a171SSubhransu S. Prusty 2410cf5a171SSubhransu S. Prusty static ssize_t skl_nhlt_platform_id_show(struct device *dev, 2420cf5a171SSubhransu S. Prusty struct device_attribute *attr, char *buf) 2430cf5a171SSubhransu S. Prusty { 2440cf5a171SSubhransu S. Prusty struct pci_dev *pci = to_pci_dev(dev); 24576f56faeSRakesh Ughreja struct hdac_bus *bus = pci_get_drvdata(pci); 246bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus); 2470cf5a171SSubhransu S. Prusty struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 2480cf5a171SSubhransu S. Prusty char platform_id[32]; 2490cf5a171SSubhransu S. Prusty 2500cf5a171SSubhransu S. Prusty sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, 2510cf5a171SSubhransu S. Prusty nhlt->header.oem_id, nhlt->header.oem_table_id, 2520cf5a171SSubhransu S. Prusty nhlt->header.oem_revision); 2530cf5a171SSubhransu S. Prusty 2540cf5a171SSubhransu S. Prusty skl_nhlt_trim_space(platform_id); 2550cf5a171SSubhransu S. Prusty return sprintf(buf, "%s\n", platform_id); 2560cf5a171SSubhransu S. Prusty } 2570cf5a171SSubhransu S. Prusty 2580cf5a171SSubhransu S. Prusty static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); 2590cf5a171SSubhransu S. Prusty 260bcc2a2dcSCezary Rojewski int skl_nhlt_create_sysfs(struct skl_dev *skl) 2610cf5a171SSubhransu S. Prusty { 2620cf5a171SSubhransu S. Prusty struct device *dev = &skl->pci->dev; 2630cf5a171SSubhransu S. Prusty 2640cf5a171SSubhransu S. Prusty if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) 2650cf5a171SSubhransu S. Prusty dev_warn(dev, "Error creating sysfs entry\n"); 2660cf5a171SSubhransu S. Prusty 2670cf5a171SSubhransu S. Prusty return 0; 2680cf5a171SSubhransu S. Prusty } 2690cf5a171SSubhransu S. Prusty 270bcc2a2dcSCezary Rojewski void skl_nhlt_remove_sysfs(struct skl_dev *skl) 2710cf5a171SSubhransu S. Prusty { 2720cf5a171SSubhransu S. Prusty struct device *dev = &skl->pci->dev; 2730cf5a171SSubhransu S. Prusty 2740cf5a171SSubhransu S. Prusty sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); 2750cf5a171SSubhransu S. Prusty } 276bc2bd45bSSriram Periyasamy 277bc2bd45bSSriram Periyasamy /* 278bc2bd45bSSriram Periyasamy * Queries NHLT for all the fmt configuration for a particular endpoint and 279bc2bd45bSSriram Periyasamy * stores all possible rates supported in a rate table for the corresponding 280bc2bd45bSSriram Periyasamy * sclk/sclkfs. 281bc2bd45bSSriram Periyasamy */ 282bcc2a2dcSCezary Rojewski static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, 283bc2bd45bSSriram Periyasamy struct nhlt_fmt *fmt, u8 id) 284bc2bd45bSSriram Periyasamy { 2859afbc5ecSSriram Periyasamy struct skl_i2s_config_blob_ext *i2s_config_ext; 286bc2bd45bSSriram Periyasamy struct skl_i2s_config_blob_legacy *i2s_config; 287bc2bd45bSSriram Periyasamy struct skl_clk_parent_src *parent; 288bc2bd45bSSriram Periyasamy struct skl_ssp_clk *sclk, *sclkfs; 289bc2bd45bSSriram Periyasamy struct nhlt_fmt_cfg *fmt_cfg; 290bc2bd45bSSriram Periyasamy struct wav_fmt_ext *wav_fmt; 291bc2bd45bSSriram Periyasamy unsigned long rate = 0; 292bc2bd45bSSriram Periyasamy bool present = false; 293bc2bd45bSSriram Periyasamy int rate_index = 0; 294bc2bd45bSSriram Periyasamy u16 channels, bps; 295bc2bd45bSSriram Periyasamy u8 clk_src; 296bc2bd45bSSriram Periyasamy int i, j; 297bc2bd45bSSriram Periyasamy u32 fs; 298bc2bd45bSSriram Periyasamy 299bc2bd45bSSriram Periyasamy sclk = &ssp_clks[SKL_SCLK_OFS]; 300bc2bd45bSSriram Periyasamy sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; 301bc2bd45bSSriram Periyasamy 302bc2bd45bSSriram Periyasamy if (fmt->fmt_count == 0) 303bc2bd45bSSriram Periyasamy return; 304bc2bd45bSSriram Periyasamy 305bc2bd45bSSriram Periyasamy for (i = 0; i < fmt->fmt_count; i++) { 306bc2bd45bSSriram Periyasamy fmt_cfg = &fmt->fmt_config[i]; 307bc2bd45bSSriram Periyasamy wav_fmt = &fmt_cfg->fmt_ext; 308bc2bd45bSSriram Periyasamy 309bc2bd45bSSriram Periyasamy channels = wav_fmt->fmt.channels; 310bc2bd45bSSriram Periyasamy bps = wav_fmt->fmt.bits_per_sample; 311bc2bd45bSSriram Periyasamy fs = wav_fmt->fmt.samples_per_sec; 312bc2bd45bSSriram Periyasamy 313bc2bd45bSSriram Periyasamy /* 314bc2bd45bSSriram Periyasamy * In case of TDM configuration on a ssp, there can 315bc2bd45bSSriram Periyasamy * be more than one blob in which channel masks are 316bc2bd45bSSriram Periyasamy * different for each usecase for a specific rate and bps. 317bc2bd45bSSriram Periyasamy * But the sclk rate will be generated for the total 318bc2bd45bSSriram Periyasamy * number of channels used for that endpoint. 319bc2bd45bSSriram Periyasamy * 320bc2bd45bSSriram Periyasamy * So for the given fs and bps, choose blob which has 321bc2bd45bSSriram Periyasamy * the superset of all channels for that endpoint and 322bc2bd45bSSriram Periyasamy * derive the rate. 323bc2bd45bSSriram Periyasamy */ 324bc2bd45bSSriram Periyasamy for (j = i; j < fmt->fmt_count; j++) { 325bc2bd45bSSriram Periyasamy fmt_cfg = &fmt->fmt_config[j]; 326bc2bd45bSSriram Periyasamy wav_fmt = &fmt_cfg->fmt_ext; 327bc2bd45bSSriram Periyasamy if ((fs == wav_fmt->fmt.samples_per_sec) && 328bc2bd45bSSriram Periyasamy (bps == wav_fmt->fmt.bits_per_sample)) 329bc2bd45bSSriram Periyasamy channels = max_t(u16, channels, 330bc2bd45bSSriram Periyasamy wav_fmt->fmt.channels); 331bc2bd45bSSriram Periyasamy } 332bc2bd45bSSriram Periyasamy 333bc2bd45bSSriram Periyasamy rate = channels * bps * fs; 334bc2bd45bSSriram Periyasamy 335bc2bd45bSSriram Periyasamy /* check if the rate is added already to the given SSP's sclk */ 33687684d33SDan Carpenter for (j = 0; (j < SKL_MAX_CLK_RATES) && 33787684d33SDan Carpenter (sclk[id].rate_cfg[j].rate != 0); j++) { 338bc2bd45bSSriram Periyasamy if (sclk[id].rate_cfg[j].rate == rate) { 339bc2bd45bSSriram Periyasamy present = true; 340bc2bd45bSSriram Periyasamy break; 341bc2bd45bSSriram Periyasamy } 342bc2bd45bSSriram Periyasamy } 343bc2bd45bSSriram Periyasamy 344bc2bd45bSSriram Periyasamy /* Fill rate and parent for sclk/sclkfs */ 345bc2bd45bSSriram Periyasamy if (!present) { 3469afbc5ecSSriram Periyasamy i2s_config_ext = (struct skl_i2s_config_blob_ext *) 347bc2bd45bSSriram Periyasamy fmt->fmt_config[0].config.caps; 3489afbc5ecSSriram Periyasamy 3499afbc5ecSSriram Periyasamy /* MCLK Divider Source Select */ 3509afbc5ecSSriram Periyasamy if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 3519afbc5ecSSriram Periyasamy i2s_config = ext_to_legacy_blob(i2s_config_ext); 3529afbc5ecSSriram Periyasamy clk_src = get_clk_src(i2s_config->mclk, 3539afbc5ecSSriram Periyasamy SKL_MNDSS_DIV_CLK_SRC_MASK); 3549afbc5ecSSriram Periyasamy } else { 3559afbc5ecSSriram Periyasamy clk_src = get_clk_src(i2s_config_ext->mclk, 3569afbc5ecSSriram Periyasamy SKL_MNDSS_DIV_CLK_SRC_MASK); 3579afbc5ecSSriram Periyasamy } 358bc2bd45bSSriram Periyasamy 359bc2bd45bSSriram Periyasamy parent = skl_get_parent_clk(clk_src); 360bc2bd45bSSriram Periyasamy 361bc2bd45bSSriram Periyasamy /* 362bc2bd45bSSriram Periyasamy * Do not copy the config data if there is no parent 363bc2bd45bSSriram Periyasamy * clock available for this clock source select 364bc2bd45bSSriram Periyasamy */ 365bc2bd45bSSriram Periyasamy if (!parent) 366bc2bd45bSSriram Periyasamy continue; 367bc2bd45bSSriram Periyasamy 368bc2bd45bSSriram Periyasamy sclk[id].rate_cfg[rate_index].rate = rate; 369bc2bd45bSSriram Periyasamy sclk[id].rate_cfg[rate_index].config = fmt_cfg; 370bc2bd45bSSriram Periyasamy sclkfs[id].rate_cfg[rate_index].rate = rate; 371bc2bd45bSSriram Periyasamy sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; 372bc2bd45bSSriram Periyasamy sclk[id].parent_name = parent->name; 373bc2bd45bSSriram Periyasamy sclkfs[id].parent_name = parent->name; 374bc2bd45bSSriram Periyasamy 375bc2bd45bSSriram Periyasamy rate_index++; 376bc2bd45bSSriram Periyasamy } 377bc2bd45bSSriram Periyasamy } 378bc2bd45bSSriram Periyasamy } 379bc2bd45bSSriram Periyasamy 380bcc2a2dcSCezary Rojewski static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, 381bc2bd45bSSriram Periyasamy struct nhlt_fmt *fmt, u8 id) 382bc2bd45bSSriram Periyasamy { 3839afbc5ecSSriram Periyasamy struct skl_i2s_config_blob_ext *i2s_config_ext; 384bc2bd45bSSriram Periyasamy struct skl_i2s_config_blob_legacy *i2s_config; 385bc2bd45bSSriram Periyasamy struct nhlt_specific_cfg *fmt_cfg; 386bc2bd45bSSriram Periyasamy struct skl_clk_parent_src *parent; 387bc2bd45bSSriram Periyasamy u32 clkdiv, div_ratio; 388bc2bd45bSSriram Periyasamy u8 clk_src; 389bc2bd45bSSriram Periyasamy 390bc2bd45bSSriram Periyasamy fmt_cfg = &fmt->fmt_config[0].config; 3919afbc5ecSSriram Periyasamy i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; 392bc2bd45bSSriram Periyasamy 3939afbc5ecSSriram Periyasamy /* MCLK Divider Source Select and divider */ 3949afbc5ecSSriram Periyasamy if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 3959afbc5ecSSriram Periyasamy i2s_config = ext_to_legacy_blob(i2s_config_ext); 3969afbc5ecSSriram Periyasamy clk_src = get_clk_src(i2s_config->mclk, 3979afbc5ecSSriram Periyasamy SKL_MCLK_DIV_CLK_SRC_MASK); 3989afbc5ecSSriram Periyasamy clkdiv = i2s_config->mclk.mdivr & 3999afbc5ecSSriram Periyasamy SKL_MCLK_DIV_RATIO_MASK; 4009afbc5ecSSriram Periyasamy } else { 4019afbc5ecSSriram Periyasamy clk_src = get_clk_src(i2s_config_ext->mclk, 4029afbc5ecSSriram Periyasamy SKL_MCLK_DIV_CLK_SRC_MASK); 4039afbc5ecSSriram Periyasamy clkdiv = i2s_config_ext->mclk.mdivr[0] & 4049afbc5ecSSriram Periyasamy SKL_MCLK_DIV_RATIO_MASK; 4059afbc5ecSSriram Periyasamy } 406bc2bd45bSSriram Periyasamy 407bc2bd45bSSriram Periyasamy /* bypass divider */ 408bc2bd45bSSriram Periyasamy div_ratio = 1; 409bc2bd45bSSriram Periyasamy 410bc2bd45bSSriram Periyasamy if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) 411bc2bd45bSSriram Periyasamy /* Divider is 2 + clkdiv */ 412bc2bd45bSSriram Periyasamy div_ratio = clkdiv + 2; 413bc2bd45bSSriram Periyasamy 414bc2bd45bSSriram Periyasamy /* Calculate MCLK rate from source using div value */ 415bc2bd45bSSriram Periyasamy parent = skl_get_parent_clk(clk_src); 416bc2bd45bSSriram Periyasamy if (!parent) 417bc2bd45bSSriram Periyasamy return; 418bc2bd45bSSriram Periyasamy 419bc2bd45bSSriram Periyasamy mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; 420bc2bd45bSSriram Periyasamy mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; 421bc2bd45bSSriram Periyasamy mclk[id].parent_name = parent->name; 422bc2bd45bSSriram Periyasamy } 423bc2bd45bSSriram Periyasamy 424bcc2a2dcSCezary Rojewski void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) 425bc2bd45bSSriram Periyasamy { 426bc2bd45bSSriram Periyasamy struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 427bc2bd45bSSriram Periyasamy struct nhlt_endpoint *epnt; 428bc2bd45bSSriram Periyasamy struct nhlt_fmt *fmt; 429bc2bd45bSSriram Periyasamy int i; 430bc2bd45bSSriram Periyasamy u8 id; 431bc2bd45bSSriram Periyasamy 432bc2bd45bSSriram Periyasamy epnt = (struct nhlt_endpoint *)nhlt->desc; 433bc2bd45bSSriram Periyasamy for (i = 0; i < nhlt->endpoint_count; i++) { 434bc2bd45bSSriram Periyasamy if (epnt->linktype == NHLT_LINK_SSP) { 435bc2bd45bSSriram Periyasamy id = epnt->virtual_bus_id; 436bc2bd45bSSriram Periyasamy 437bc2bd45bSSriram Periyasamy fmt = (struct nhlt_fmt *)(epnt->config.caps 438bc2bd45bSSriram Periyasamy + epnt->config.size); 439bc2bd45bSSriram Periyasamy 440bc2bd45bSSriram Periyasamy skl_get_ssp_clks(skl, ssp_clks, fmt, id); 441bc2bd45bSSriram Periyasamy skl_get_mclk(skl, ssp_clks, fmt, id); 442bc2bd45bSSriram Periyasamy } 443bc2bd45bSSriram Periyasamy epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 444bc2bd45bSSriram Periyasamy } 445bc2bd45bSSriram Periyasamy } 446