| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * skl-nhlt.c - Intel SKL Platform NHLT parsing |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> |
|---|
| 6 | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 7 | 8 | * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; version 2 of the License. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 13 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 15 | | - * General Public License for more details. |
|---|
| 16 | | - * |
|---|
| 17 | 9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 18 | | - * |
|---|
| 19 | 10 | */ |
|---|
| 20 | 11 | #include <linux/pci.h> |
|---|
| 12 | +#include <sound/intel-nhlt.h> |
|---|
| 21 | 13 | #include "skl.h" |
|---|
| 22 | 14 | #include "skl-i2s.h" |
|---|
| 23 | | - |
|---|
| 24 | | -#define NHLT_ACPI_HEADER_SIG "NHLT" |
|---|
| 25 | | - |
|---|
| 26 | | -/* Unique identification for getting NHLT blobs */ |
|---|
| 27 | | -static guid_t osc_guid = |
|---|
| 28 | | - GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, |
|---|
| 29 | | - 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); |
|---|
| 30 | | - |
|---|
| 31 | | - |
|---|
| 32 | | -struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) |
|---|
| 33 | | -{ |
|---|
| 34 | | - acpi_handle handle; |
|---|
| 35 | | - union acpi_object *obj; |
|---|
| 36 | | - struct nhlt_resource_desc *nhlt_ptr = NULL; |
|---|
| 37 | | - struct nhlt_acpi_table *nhlt_table = NULL; |
|---|
| 38 | | - |
|---|
| 39 | | - handle = ACPI_HANDLE(dev); |
|---|
| 40 | | - if (!handle) { |
|---|
| 41 | | - dev_err(dev, "Didn't find ACPI_HANDLE\n"); |
|---|
| 42 | | - return NULL; |
|---|
| 43 | | - } |
|---|
| 44 | | - |
|---|
| 45 | | - obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); |
|---|
| 46 | | - if (obj && obj->type == ACPI_TYPE_BUFFER) { |
|---|
| 47 | | - nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; |
|---|
| 48 | | - if (nhlt_ptr->length) |
|---|
| 49 | | - nhlt_table = (struct nhlt_acpi_table *) |
|---|
| 50 | | - memremap(nhlt_ptr->min_addr, nhlt_ptr->length, |
|---|
| 51 | | - MEMREMAP_WB); |
|---|
| 52 | | - ACPI_FREE(obj); |
|---|
| 53 | | - if (nhlt_table && (strncmp(nhlt_table->header.signature, |
|---|
| 54 | | - NHLT_ACPI_HEADER_SIG, |
|---|
| 55 | | - strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { |
|---|
| 56 | | - memunmap(nhlt_table); |
|---|
| 57 | | - dev_err(dev, "NHLT ACPI header signature incorrect\n"); |
|---|
| 58 | | - return NULL; |
|---|
| 59 | | - } |
|---|
| 60 | | - return nhlt_table; |
|---|
| 61 | | - } |
|---|
| 62 | | - |
|---|
| 63 | | - dev_err(dev, "device specific method to extract NHLT blob failed\n"); |
|---|
| 64 | | - return NULL; |
|---|
| 65 | | -} |
|---|
| 66 | | - |
|---|
| 67 | | -void skl_nhlt_free(struct nhlt_acpi_table *nhlt) |
|---|
| 68 | | -{ |
|---|
| 69 | | - memunmap((void *) nhlt); |
|---|
| 70 | | -} |
|---|
| 71 | 15 | |
|---|
| 72 | 16 | static struct nhlt_specific_cfg *skl_get_specific_cfg( |
|---|
| 73 | 17 | struct device *dev, struct nhlt_fmt *fmt, |
|---|
| .. | .. |
|---|
| 135 | 79 | } |
|---|
| 136 | 80 | |
|---|
| 137 | 81 | struct nhlt_specific_cfg |
|---|
| 138 | | -*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, |
|---|
| 82 | +*skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, |
|---|
| 139 | 83 | u8 s_fmt, u8 num_ch, u32 s_rate, |
|---|
| 140 | 84 | u8 dirn, u8 dev_type) |
|---|
| 141 | 85 | { |
|---|
| .. | .. |
|---|
| 171 | 115 | return NULL; |
|---|
| 172 | 116 | } |
|---|
| 173 | 117 | |
|---|
| 174 | | -int skl_get_dmic_geo(struct skl *skl) |
|---|
| 175 | | -{ |
|---|
| 176 | | - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; |
|---|
| 177 | | - struct nhlt_endpoint *epnt; |
|---|
| 178 | | - struct nhlt_dmic_array_config *cfg; |
|---|
| 179 | | - struct device *dev = &skl->pci->dev; |
|---|
| 180 | | - unsigned int dmic_geo = 0; |
|---|
| 181 | | - u8 j; |
|---|
| 182 | | - |
|---|
| 183 | | - epnt = (struct nhlt_endpoint *)nhlt->desc; |
|---|
| 184 | | - |
|---|
| 185 | | - for (j = 0; j < nhlt->endpoint_count; j++) { |
|---|
| 186 | | - if (epnt->linktype == NHLT_LINK_DMIC) { |
|---|
| 187 | | - cfg = (struct nhlt_dmic_array_config *) |
|---|
| 188 | | - (epnt->config.caps); |
|---|
| 189 | | - switch (cfg->array_type) { |
|---|
| 190 | | - case NHLT_MIC_ARRAY_2CH_SMALL: |
|---|
| 191 | | - case NHLT_MIC_ARRAY_2CH_BIG: |
|---|
| 192 | | - dmic_geo |= MIC_ARRAY_2CH; |
|---|
| 193 | | - break; |
|---|
| 194 | | - |
|---|
| 195 | | - case NHLT_MIC_ARRAY_4CH_1ST_GEOM: |
|---|
| 196 | | - case NHLT_MIC_ARRAY_4CH_L_SHAPED: |
|---|
| 197 | | - case NHLT_MIC_ARRAY_4CH_2ND_GEOM: |
|---|
| 198 | | - dmic_geo |= MIC_ARRAY_4CH; |
|---|
| 199 | | - break; |
|---|
| 200 | | - |
|---|
| 201 | | - default: |
|---|
| 202 | | - dev_warn(dev, "undefined DMIC array_type 0x%0x\n", |
|---|
| 203 | | - cfg->array_type); |
|---|
| 204 | | - |
|---|
| 205 | | - } |
|---|
| 206 | | - } |
|---|
| 207 | | - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); |
|---|
| 208 | | - } |
|---|
| 209 | | - |
|---|
| 210 | | - return dmic_geo; |
|---|
| 211 | | -} |
|---|
| 212 | | - |
|---|
| 213 | 118 | static void skl_nhlt_trim_space(char *trim) |
|---|
| 214 | 119 | { |
|---|
| 215 | 120 | char *s = trim; |
|---|
| .. | .. |
|---|
| 225 | 130 | s[cnt] = '\0'; |
|---|
| 226 | 131 | } |
|---|
| 227 | 132 | |
|---|
| 228 | | -int skl_nhlt_update_topology_bin(struct skl *skl) |
|---|
| 133 | +int skl_nhlt_update_topology_bin(struct skl_dev *skl) |
|---|
| 229 | 134 | { |
|---|
| 230 | 135 | struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; |
|---|
| 231 | 136 | struct hdac_bus *bus = skl_to_bus(skl); |
|---|
| .. | .. |
|---|
| 249 | 154 | { |
|---|
| 250 | 155 | struct pci_dev *pci = to_pci_dev(dev); |
|---|
| 251 | 156 | struct hdac_bus *bus = pci_get_drvdata(pci); |
|---|
| 252 | | - struct skl *skl = bus_to_skl(bus); |
|---|
| 157 | + struct skl_dev *skl = bus_to_skl(bus); |
|---|
| 253 | 158 | struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; |
|---|
| 254 | 159 | char platform_id[32]; |
|---|
| 255 | 160 | |
|---|
| .. | .. |
|---|
| 263 | 168 | |
|---|
| 264 | 169 | static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); |
|---|
| 265 | 170 | |
|---|
| 266 | | -int skl_nhlt_create_sysfs(struct skl *skl) |
|---|
| 171 | +int skl_nhlt_create_sysfs(struct skl_dev *skl) |
|---|
| 267 | 172 | { |
|---|
| 268 | 173 | struct device *dev = &skl->pci->dev; |
|---|
| 269 | 174 | |
|---|
| .. | .. |
|---|
| 273 | 178 | return 0; |
|---|
| 274 | 179 | } |
|---|
| 275 | 180 | |
|---|
| 276 | | -void skl_nhlt_remove_sysfs(struct skl *skl) |
|---|
| 181 | +void skl_nhlt_remove_sysfs(struct skl_dev *skl) |
|---|
| 277 | 182 | { |
|---|
| 278 | 183 | struct device *dev = &skl->pci->dev; |
|---|
| 279 | 184 | |
|---|
| 280 | | - sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); |
|---|
| 185 | + if (skl->nhlt) |
|---|
| 186 | + sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); |
|---|
| 281 | 187 | } |
|---|
| 282 | 188 | |
|---|
| 283 | 189 | /* |
|---|
| .. | .. |
|---|
| 285 | 191 | * stores all possible rates supported in a rate table for the corresponding |
|---|
| 286 | 192 | * sclk/sclkfs. |
|---|
| 287 | 193 | */ |
|---|
| 288 | | -static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, |
|---|
| 194 | +static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, |
|---|
| 289 | 195 | struct nhlt_fmt *fmt, u8 id) |
|---|
| 290 | 196 | { |
|---|
| 291 | 197 | struct skl_i2s_config_blob_ext *i2s_config_ext; |
|---|
| .. | .. |
|---|
| 294 | 200 | struct skl_ssp_clk *sclk, *sclkfs; |
|---|
| 295 | 201 | struct nhlt_fmt_cfg *fmt_cfg; |
|---|
| 296 | 202 | struct wav_fmt_ext *wav_fmt; |
|---|
| 297 | | - unsigned long rate = 0; |
|---|
| 298 | | - bool present = false; |
|---|
| 203 | + unsigned long rate; |
|---|
| 299 | 204 | int rate_index = 0; |
|---|
| 300 | 205 | u16 channels, bps; |
|---|
| 301 | 206 | u8 clk_src; |
|---|
| .. | .. |
|---|
| 308 | 213 | if (fmt->fmt_count == 0) |
|---|
| 309 | 214 | return; |
|---|
| 310 | 215 | |
|---|
| 216 | + fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; |
|---|
| 311 | 217 | for (i = 0; i < fmt->fmt_count; i++) { |
|---|
| 312 | | - fmt_cfg = &fmt->fmt_config[i]; |
|---|
| 313 | | - wav_fmt = &fmt_cfg->fmt_ext; |
|---|
| 218 | + struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg; |
|---|
| 219 | + bool present = false; |
|---|
| 220 | + |
|---|
| 221 | + wav_fmt = &saved_fmt_cfg->fmt_ext; |
|---|
| 314 | 222 | |
|---|
| 315 | 223 | channels = wav_fmt->fmt.channels; |
|---|
| 316 | 224 | bps = wav_fmt->fmt.bits_per_sample; |
|---|
| .. | .. |
|---|
| 328 | 236 | * derive the rate. |
|---|
| 329 | 237 | */ |
|---|
| 330 | 238 | for (j = i; j < fmt->fmt_count; j++) { |
|---|
| 331 | | - fmt_cfg = &fmt->fmt_config[j]; |
|---|
| 332 | | - wav_fmt = &fmt_cfg->fmt_ext; |
|---|
| 239 | + struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg; |
|---|
| 240 | + |
|---|
| 241 | + wav_fmt = &tmp_fmt_cfg->fmt_ext; |
|---|
| 333 | 242 | if ((fs == wav_fmt->fmt.samples_per_sec) && |
|---|
| 334 | | - (bps == wav_fmt->fmt.bits_per_sample)) |
|---|
| 243 | + (bps == wav_fmt->fmt.bits_per_sample)) { |
|---|
| 335 | 244 | channels = max_t(u16, channels, |
|---|
| 336 | 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); |
|---|
| 337 | 251 | } |
|---|
| 338 | 252 | |
|---|
| 339 | 253 | rate = channels * bps * fs; |
|---|
| .. | .. |
|---|
| 349 | 263 | |
|---|
| 350 | 264 | /* Fill rate and parent for sclk/sclkfs */ |
|---|
| 351 | 265 | if (!present) { |
|---|
| 266 | + struct nhlt_fmt_cfg *first_fmt_cfg; |
|---|
| 267 | + |
|---|
| 268 | + first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; |
|---|
| 352 | 269 | i2s_config_ext = (struct skl_i2s_config_blob_ext *) |
|---|
| 353 | | - fmt->fmt_config[0].config.caps; |
|---|
| 270 | + first_fmt_cfg->config.caps; |
|---|
| 354 | 271 | |
|---|
| 355 | 272 | /* MCLK Divider Source Select */ |
|---|
| 356 | 273 | if (is_legacy_blob(i2s_config_ext->hdr.sig)) { |
|---|
| .. | .. |
|---|
| 364 | 281 | |
|---|
| 365 | 282 | parent = skl_get_parent_clk(clk_src); |
|---|
| 366 | 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); |
|---|
| 367 | 287 | /* |
|---|
| 368 | 288 | * Do not copy the config data if there is no parent |
|---|
| 369 | 289 | * clock available for this clock source select |
|---|
| .. | .. |
|---|
| 372 | 292 | continue; |
|---|
| 373 | 293 | |
|---|
| 374 | 294 | sclk[id].rate_cfg[rate_index].rate = rate; |
|---|
| 375 | | - sclk[id].rate_cfg[rate_index].config = fmt_cfg; |
|---|
| 295 | + sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg; |
|---|
| 376 | 296 | sclkfs[id].rate_cfg[rate_index].rate = rate; |
|---|
| 377 | | - sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; |
|---|
| 297 | + sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg; |
|---|
| 378 | 298 | sclk[id].parent_name = parent->name; |
|---|
| 379 | 299 | sclkfs[id].parent_name = parent->name; |
|---|
| 380 | 300 | |
|---|
| .. | .. |
|---|
| 383 | 303 | } |
|---|
| 384 | 304 | } |
|---|
| 385 | 305 | |
|---|
| 386 | | -static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, |
|---|
| 306 | +static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, |
|---|
| 387 | 307 | struct nhlt_fmt *fmt, u8 id) |
|---|
| 388 | 308 | { |
|---|
| 389 | 309 | struct skl_i2s_config_blob_ext *i2s_config_ext; |
|---|
| 390 | 310 | struct skl_i2s_config_blob_legacy *i2s_config; |
|---|
| 391 | | - struct nhlt_specific_cfg *fmt_cfg; |
|---|
| 311 | + struct nhlt_fmt_cfg *fmt_cfg; |
|---|
| 392 | 312 | struct skl_clk_parent_src *parent; |
|---|
| 393 | 313 | u32 clkdiv, div_ratio; |
|---|
| 394 | 314 | u8 clk_src; |
|---|
| 395 | 315 | |
|---|
| 396 | | - fmt_cfg = &fmt->fmt_config[0].config; |
|---|
| 397 | | - i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; |
|---|
| 316 | + fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; |
|---|
| 317 | + i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps; |
|---|
| 398 | 318 | |
|---|
| 399 | 319 | /* MCLK Divider Source Select and divider */ |
|---|
| 400 | 320 | if (is_legacy_blob(i2s_config_ext->hdr.sig)) { |
|---|
| .. | .. |
|---|
| 423 | 343 | return; |
|---|
| 424 | 344 | |
|---|
| 425 | 345 | mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; |
|---|
| 426 | | - mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; |
|---|
| 346 | + mclk[id].rate_cfg[0].config = fmt_cfg; |
|---|
| 427 | 347 | mclk[id].parent_name = parent->name; |
|---|
| 428 | 348 | } |
|---|
| 429 | 349 | |
|---|
| 430 | | -void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks) |
|---|
| 350 | +void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) |
|---|
| 431 | 351 | { |
|---|
| 432 | 352 | struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; |
|---|
| 433 | 353 | struct nhlt_endpoint *epnt; |
|---|