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 struct nhlt_specific_cfg *skl_get_specific_cfg( 17 struct device *dev, struct nhlt_fmt *fmt, 18 u8 no_ch, u32 rate, u16 bps, u8 linktype) 19{ 20 struct nhlt_specific_cfg *sp_config; 21 struct wav_fmt *wfmt; 22 struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; 23 int i; 24 25 dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); 26 27 for (i = 0; i < fmt->fmt_count; i++) { 28 wfmt = &fmt_config->fmt_ext.fmt; 29 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, 30 wfmt->bits_per_sample, wfmt->samples_per_sec); 31 if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { 32 /* 33 * if link type is dmic ignore rate check as the blob is 34 * generic for all rates 35 */ 36 sp_config = &fmt_config->config; 37 if (linktype == NHLT_LINK_DMIC) 38 return sp_config; 39 40 if (wfmt->samples_per_sec == rate) 41 return sp_config; 42 } 43 44 fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + 45 fmt_config->config.size); 46 } 47 48 return NULL; 49} 50 51static void dump_config(struct device *dev, u32 instance_id, u8 linktype, 52 u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) 53{ 54 dev_dbg(dev, "Input configuration\n"); 55 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); 56 dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); 57 dev_dbg(dev, "bits_per_sample=%d\n", bps); 58} 59 60static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, 61 u32 instance_id, u8 link_type, u8 dirn, u8 dev_type) 62{ 63 dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n", 64 epnt->virtual_bus_id, epnt->linktype, 65 epnt->direction, epnt->device_type); 66 67 if ((epnt->virtual_bus_id == instance_id) && 68 (epnt->linktype == link_type) && 69 (epnt->direction == dirn)) { 70 /* do not check dev_type for DMIC link type */ 71 if (epnt->linktype == NHLT_LINK_DMIC) 72 return true; 73 74 if (epnt->device_type == dev_type) 75 return true; 76 } 77 78 return false; 79} 80 81struct nhlt_specific_cfg 82*skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, 83 u8 s_fmt, u8 num_ch, u32 s_rate, 84 u8 dirn, u8 dev_type) 85{ 86 struct nhlt_fmt *fmt; 87 struct nhlt_endpoint *epnt; 88 struct hdac_bus *bus = skl_to_bus(skl); 89 struct device *dev = bus->dev; 90 struct nhlt_specific_cfg *sp_config; 91 struct nhlt_acpi_table *nhlt = skl->nhlt; 92 u16 bps = (s_fmt == 16) ? 16 : 32; 93 u8 j; 94 95 dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); 96 97 epnt = (struct nhlt_endpoint *)nhlt->desc; 98 99 dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); 100 101 for (j = 0; j < nhlt->endpoint_count; j++) { 102 if (skl_check_ep_match(dev, epnt, instance, link_type, 103 dirn, dev_type)) { 104 fmt = (struct nhlt_fmt *)(epnt->config.caps + 105 epnt->config.size); 106 sp_config = skl_get_specific_cfg(dev, fmt, num_ch, 107 s_rate, bps, link_type); 108 if (sp_config) 109 return sp_config; 110 } 111 112 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 113 } 114 115 return NULL; 116} 117 118static void skl_nhlt_trim_space(char *trim) 119{ 120 char *s = trim; 121 int cnt; 122 int i; 123 124 cnt = 0; 125 for (i = 0; s[i]; i++) { 126 if (!isspace(s[i])) 127 s[cnt++] = s[i]; 128 } 129 130 s[cnt] = '\0'; 131} 132 133int skl_nhlt_update_topology_bin(struct skl_dev *skl) 134{ 135 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 136 struct hdac_bus *bus = skl_to_bus(skl); 137 struct device *dev = bus->dev; 138 139 dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n", 140 nhlt->header.oem_id, nhlt->header.oem_table_id, 141 nhlt->header.oem_revision); 142 143 snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", 144 skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, 145 nhlt->header.oem_revision, "-tplg.bin"); 146 147 skl_nhlt_trim_space(skl->tplg_name); 148 149 return 0; 150} 151 152static ssize_t skl_nhlt_platform_id_show(struct device *dev, 153 struct device_attribute *attr, char *buf) 154{ 155 struct pci_dev *pci = to_pci_dev(dev); 156 struct hdac_bus *bus = pci_get_drvdata(pci); 157 struct skl_dev *skl = bus_to_skl(bus); 158 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 159 char platform_id[32]; 160 161 sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, 162 nhlt->header.oem_id, nhlt->header.oem_table_id, 163 nhlt->header.oem_revision); 164 165 skl_nhlt_trim_space(platform_id); 166 return sprintf(buf, "%s\n", platform_id); 167} 168 169static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); 170 171int skl_nhlt_create_sysfs(struct skl_dev *skl) 172{ 173 struct device *dev = &skl->pci->dev; 174 175 if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) 176 dev_warn(dev, "Error creating sysfs entry\n"); 177 178 return 0; 179} 180 181void skl_nhlt_remove_sysfs(struct skl_dev *skl) 182{ 183 struct device *dev = &skl->pci->dev; 184 185 if (skl->nhlt) 186 sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); 187} 188 189/* 190 * Queries NHLT for all the fmt configuration for a particular endpoint and 191 * stores all possible rates supported in a rate table for the corresponding 192 * sclk/sclkfs. 193 */ 194static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, 195 struct nhlt_fmt *fmt, u8 id) 196{ 197 struct skl_i2s_config_blob_ext *i2s_config_ext; 198 struct skl_i2s_config_blob_legacy *i2s_config; 199 struct skl_clk_parent_src *parent; 200 struct skl_ssp_clk *sclk, *sclkfs; 201 struct nhlt_fmt_cfg *fmt_cfg; 202 struct wav_fmt_ext *wav_fmt; 203 unsigned long rate; 204 int rate_index = 0; 205 u16 channels, bps; 206 u8 clk_src; 207 int i, j; 208 u32 fs; 209 210 sclk = &ssp_clks[SKL_SCLK_OFS]; 211 sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; 212 213 if (fmt->fmt_count == 0) 214 return; 215 216 fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; 217 for (i = 0; i < fmt->fmt_count; i++) { 218 struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg; 219 bool present = false; 220 221 wav_fmt = &saved_fmt_cfg->fmt_ext; 222 223 channels = wav_fmt->fmt.channels; 224 bps = wav_fmt->fmt.bits_per_sample; 225 fs = wav_fmt->fmt.samples_per_sec; 226 227 /* 228 * In case of TDM configuration on a ssp, there can 229 * be more than one blob in which channel masks are 230 * different for each usecase for a specific rate and bps. 231 * But the sclk rate will be generated for the total 232 * number of channels used for that endpoint. 233 * 234 * So for the given fs and bps, choose blob which has 235 * the superset of all channels for that endpoint and 236 * derive the rate. 237 */ 238 for (j = i; j < fmt->fmt_count; j++) { 239 struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg; 240 241 wav_fmt = &tmp_fmt_cfg->fmt_ext; 242 if ((fs == wav_fmt->fmt.samples_per_sec) && 243 (bps == wav_fmt->fmt.bits_per_sample)) { 244 channels = max_t(u16, channels, 245 wav_fmt->fmt.channels); 246 saved_fmt_cfg = tmp_fmt_cfg; 247 } 248 /* Move to the next nhlt_fmt_cfg */ 249 tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps + 250 tmp_fmt_cfg->config.size); 251 } 252 253 rate = channels * bps * fs; 254 255 /* check if the rate is added already to the given SSP's sclk */ 256 for (j = 0; (j < SKL_MAX_CLK_RATES) && 257 (sclk[id].rate_cfg[j].rate != 0); j++) { 258 if (sclk[id].rate_cfg[j].rate == rate) { 259 present = true; 260 break; 261 } 262 } 263 264 /* Fill rate and parent for sclk/sclkfs */ 265 if (!present) { 266 struct nhlt_fmt_cfg *first_fmt_cfg; 267 268 first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; 269 i2s_config_ext = (struct skl_i2s_config_blob_ext *) 270 first_fmt_cfg->config.caps; 271 272 /* MCLK Divider Source Select */ 273 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 274 i2s_config = ext_to_legacy_blob(i2s_config_ext); 275 clk_src = get_clk_src(i2s_config->mclk, 276 SKL_MNDSS_DIV_CLK_SRC_MASK); 277 } else { 278 clk_src = get_clk_src(i2s_config_ext->mclk, 279 SKL_MNDSS_DIV_CLK_SRC_MASK); 280 } 281 282 parent = skl_get_parent_clk(clk_src); 283 284 /* Move to the next nhlt_fmt_cfg */ 285 fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + 286 fmt_cfg->config.size); 287 /* 288 * Do not copy the config data if there is no parent 289 * clock available for this clock source select 290 */ 291 if (!parent) 292 continue; 293 294 sclk[id].rate_cfg[rate_index].rate = rate; 295 sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg; 296 sclkfs[id].rate_cfg[rate_index].rate = rate; 297 sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg; 298 sclk[id].parent_name = parent->name; 299 sclkfs[id].parent_name = parent->name; 300 301 rate_index++; 302 } 303 } 304} 305 306static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, 307 struct nhlt_fmt *fmt, u8 id) 308{ 309 struct skl_i2s_config_blob_ext *i2s_config_ext; 310 struct skl_i2s_config_blob_legacy *i2s_config; 311 struct nhlt_fmt_cfg *fmt_cfg; 312 struct skl_clk_parent_src *parent; 313 u32 clkdiv, div_ratio; 314 u8 clk_src; 315 316 fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; 317 i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps; 318 319 /* MCLK Divider Source Select and divider */ 320 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 321 i2s_config = ext_to_legacy_blob(i2s_config_ext); 322 clk_src = get_clk_src(i2s_config->mclk, 323 SKL_MCLK_DIV_CLK_SRC_MASK); 324 clkdiv = i2s_config->mclk.mdivr & 325 SKL_MCLK_DIV_RATIO_MASK; 326 } else { 327 clk_src = get_clk_src(i2s_config_ext->mclk, 328 SKL_MCLK_DIV_CLK_SRC_MASK); 329 clkdiv = i2s_config_ext->mclk.mdivr[0] & 330 SKL_MCLK_DIV_RATIO_MASK; 331 } 332 333 /* bypass divider */ 334 div_ratio = 1; 335 336 if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) 337 /* Divider is 2 + clkdiv */ 338 div_ratio = clkdiv + 2; 339 340 /* Calculate MCLK rate from source using div value */ 341 parent = skl_get_parent_clk(clk_src); 342 if (!parent) 343 return; 344 345 mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; 346 mclk[id].rate_cfg[0].config = fmt_cfg; 347 mclk[id].parent_name = parent->name; 348} 349 350void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) 351{ 352 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 353 struct nhlt_endpoint *epnt; 354 struct nhlt_fmt *fmt; 355 int i; 356 u8 id; 357 358 epnt = (struct nhlt_endpoint *)nhlt->desc; 359 for (i = 0; i < nhlt->endpoint_count; i++) { 360 if (epnt->linktype == NHLT_LINK_SSP) { 361 id = epnt->virtual_bus_id; 362 363 fmt = (struct nhlt_fmt *)(epnt->config.caps 364 + epnt->config.size); 365 366 skl_get_ssp_clks(skl, ssp_clks, fmt, id); 367 skl_get_mclk(skl, ssp_clks, fmt, id); 368 } 369 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 370 } 371} 372