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