]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - sound/soc/intel/skylake/skl-nhlt.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 285
[mirror_ubuntu-hirsute-kernel.git] / sound / soc / intel / skylake / skl-nhlt.c
CommitLineData
8e8e69d6 1// SPDX-License-Identifier: GPL-2.0-only
473eb87a
JK
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 *
473eb87a 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
473eb87a 10 */
f65cf7d6 11#include <linux/pci.h>
473eb87a 12#include "skl.h"
bc2bd45b 13#include "skl-i2s.h"
473eb87a 14
3b47c9dc
PB
15#define NHLT_ACPI_HEADER_SIG "NHLT"
16
473eb87a 17/* Unique identification for getting NHLT blobs */
94116f81
AS
18static guid_t osc_guid =
19 GUID_INIT(0xA69F886E, 0x6CEB, 0x4594,
20 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53);
473eb87a 21
9afbc5ec 22
c286b3f9 23struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
473eb87a
JK
24{
25 acpi_handle handle;
26 union acpi_object *obj;
27 struct nhlt_resource_desc *nhlt_ptr = NULL;
c286b3f9 28 struct nhlt_acpi_table *nhlt_table = NULL;
473eb87a 29
6ad0005f
VK
30 handle = ACPI_HANDLE(dev);
31 if (!handle) {
32 dev_err(dev, "Didn't find ACPI_HANDLE\n");
473eb87a
JK
33 return NULL;
34 }
35
94116f81 36 obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL);
473eb87a
JK
37 if (obj && obj->type == ACPI_TYPE_BUFFER) {
38 nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
20a1ea22
TI
39 if (nhlt_ptr->length)
40 nhlt_table = (struct nhlt_acpi_table *)
c286b3f9 41 memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
ba40a854 42 MEMREMAP_WB);
c286b3f9 43 ACPI_FREE(obj);
3b47c9dc
PB
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 }
c286b3f9 51 return nhlt_table;
473eb87a
JK
52 }
53
54 dev_err(dev, "device specific method to extract NHLT blob failed\n");
55 return NULL;
56}
57
c286b3f9 58void skl_nhlt_free(struct nhlt_acpi_table *nhlt)
473eb87a 59{
c286b3f9 60 memunmap((void *) nhlt);
473eb87a
JK
61}
62
63static struct nhlt_specific_cfg *skl_get_specific_cfg(
64 struct device *dev, struct nhlt_fmt *fmt,
16882d24 65 u8 no_ch, u32 rate, u16 bps, u8 linktype)
473eb87a
JK
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);
16882d24
JK
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 */
473eb87a 83 sp_config = &fmt_config->config;
16882d24
JK
84 if (linktype == NHLT_LINK_DMIC)
85 return sp_config;
473eb87a 86
16882d24
JK
87 if (wfmt->samples_per_sec == rate)
88 return sp_config;
473eb87a
JK
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
98static 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
107static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
db2f586b 108 u32 instance_id, u8 link_type, u8 dirn, u8 dev_type)
473eb87a 109{
db2f586b
SV
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);
473eb87a
JK
113
114 if ((epnt->virtual_bus_id == instance_id) &&
115 (epnt->linktype == link_type) &&
e02b0330
GS
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;
473eb87a
JK
126}
127
128struct nhlt_specific_cfg
129*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type,
db2f586b
SV
130 u8 s_fmt, u8 num_ch, u32 s_rate,
131 u8 dirn, u8 dev_type)
473eb87a
JK
132{
133 struct nhlt_fmt *fmt;
134 struct nhlt_endpoint *epnt;
76f56fae 135 struct hdac_bus *bus = skl_to_bus(skl);
473eb87a
JK
136 struct device *dev = bus->dev;
137 struct nhlt_specific_cfg *sp_config;
c286b3f9 138 struct nhlt_acpi_table *nhlt = skl->nhlt;
83b50246 139 u16 bps = (s_fmt == 16) ? 16 : 32;
473eb87a
JK
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++) {
db2f586b
SV
149 if (skl_check_ep_match(dev, epnt, instance, link_type,
150 dirn, dev_type)) {
473eb87a
JK
151 fmt = (struct nhlt_fmt *)(epnt->config.caps +
152 epnt->config.size);
16882d24
JK
153 sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
154 s_rate, bps, link_type);
473eb87a
JK
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}
4b235c43 164
f65cf7d6
YZ
165int 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
f231c34c
PLB
174 if (!nhlt)
175 return 0;
176
f65cf7d6
YZ
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
0cf5a171 207static void skl_nhlt_trim_space(char *trim)
4b235c43 208{
0cf5a171 209 char *s = trim;
4b235c43
VK
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
222int skl_nhlt_update_topology_bin(struct skl *skl)
223{
224 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
76f56fae 225 struct hdac_bus *bus = skl_to_bus(skl);
4b235c43
VK
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
0cf5a171 236 skl_nhlt_trim_space(skl->tplg_name);
4b235c43
VK
237
238 return 0;
239}
0cf5a171
SP
240
241static 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);
76f56fae
RU
245 struct hdac_bus *bus = pci_get_drvdata(pci);
246 struct skl *skl = bus_to_skl(bus);
0cf5a171
SP
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
258static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL);
259
260int 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
270void 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}
bc2bd45b
SP
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 */
8e79ec98 282static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
bc2bd45b
SP
283 struct nhlt_fmt *fmt, u8 id)
284{
9afbc5ec 285 struct skl_i2s_config_blob_ext *i2s_config_ext;
bc2bd45b
SP
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 */
87684d33
DC
336 for (j = 0; (j < SKL_MAX_CLK_RATES) &&
337 (sclk[id].rate_cfg[j].rate != 0); j++) {
bc2bd45b
SP
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) {
9afbc5ec 346 i2s_config_ext = (struct skl_i2s_config_blob_ext *)
bc2bd45b 347 fmt->fmt_config[0].config.caps;
9afbc5ec
SP
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 }
bc2bd45b
SP
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
8e79ec98 380static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
bc2bd45b
SP
381 struct nhlt_fmt *fmt, u8 id)
382{
9afbc5ec 383 struct skl_i2s_config_blob_ext *i2s_config_ext;
bc2bd45b
SP
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;
9afbc5ec
SP
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 }
bc2bd45b
SP
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
424void 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}