2 * skl-nhlt.c - Intel SKL Platform NHLT parsing
4 * Copyright (C) 2015 Intel Corp
5 * Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 #include <linux/pci.h>
24 #define NHLT_ACPI_HEADER_SIG "NHLT"
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);
32 struct nhlt_acpi_table
*skl_nhlt_init(struct device
*dev
)
35 union acpi_object
*obj
;
36 struct nhlt_resource_desc
*nhlt_ptr
= NULL
;
37 struct nhlt_acpi_table
*nhlt_table
= NULL
;
39 handle
= ACPI_HANDLE(dev
);
41 dev_err(dev
, "Didn't find ACPI_HANDLE\n");
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
;
49 nhlt_table
= (struct nhlt_acpi_table
*)
50 memremap(nhlt_ptr
->min_addr
, nhlt_ptr
->length
,
53 if (nhlt_table
&& (strncmp(nhlt_table
->header
.signature
,
55 strlen(NHLT_ACPI_HEADER_SIG
)) != 0)) {
57 dev_err(dev
, "NHLT ACPI header signature incorrect\n");
63 dev_err(dev
, "device specific method to extract NHLT blob failed\n");
67 void skl_nhlt_free(struct nhlt_acpi_table
*nhlt
)
69 memunmap((void *) nhlt
);
72 static struct nhlt_specific_cfg
*skl_get_specific_cfg(
73 struct device
*dev
, struct nhlt_fmt
*fmt
,
74 u8 no_ch
, u32 rate
, u16 bps
, u8 linktype
)
76 struct nhlt_specific_cfg
*sp_config
;
78 struct nhlt_fmt_cfg
*fmt_config
= fmt
->fmt_config
;
81 dev_dbg(dev
, "Format count =%d\n", fmt
->fmt_count
);
83 for (i
= 0; i
< fmt
->fmt_count
; i
++) {
84 wfmt
= &fmt_config
->fmt_ext
.fmt
;
85 dev_dbg(dev
, "ch=%d fmt=%d s_rate=%d\n", wfmt
->channels
,
86 wfmt
->bits_per_sample
, wfmt
->samples_per_sec
);
87 if (wfmt
->channels
== no_ch
&& wfmt
->bits_per_sample
== bps
) {
89 * if link type is dmic ignore rate check as the blob is
90 * generic for all rates
92 sp_config
= &fmt_config
->config
;
93 if (linktype
== NHLT_LINK_DMIC
)
96 if (wfmt
->samples_per_sec
== rate
)
100 fmt_config
= (struct nhlt_fmt_cfg
*)(fmt_config
->config
.caps
+
101 fmt_config
->config
.size
);
107 static void dump_config(struct device
*dev
, u32 instance_id
, u8 linktype
,
108 u8 s_fmt
, u8 num_channels
, u32 s_rate
, u8 dirn
, u16 bps
)
110 dev_dbg(dev
, "Input configuration\n");
111 dev_dbg(dev
, "ch=%d fmt=%d s_rate=%d\n", num_channels
, s_fmt
, s_rate
);
112 dev_dbg(dev
, "vbus_id=%d link_type=%d\n", instance_id
, linktype
);
113 dev_dbg(dev
, "bits_per_sample=%d\n", bps
);
116 static bool skl_check_ep_match(struct device
*dev
, struct nhlt_endpoint
*epnt
,
117 u32 instance_id
, u8 link_type
, u8 dirn
, u8 dev_type
)
119 dev_dbg(dev
, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
120 epnt
->virtual_bus_id
, epnt
->linktype
,
121 epnt
->direction
, epnt
->device_type
);
123 if ((epnt
->virtual_bus_id
== instance_id
) &&
124 (epnt
->linktype
== link_type
) &&
125 (epnt
->direction
== dirn
)) {
126 /* do not check dev_type for DMIC link type */
127 if (epnt
->linktype
== NHLT_LINK_DMIC
)
130 if (epnt
->device_type
== dev_type
)
137 struct nhlt_specific_cfg
138 *skl_get_ep_blob(struct skl
*skl
, u32 instance
, u8 link_type
,
139 u8 s_fmt
, u8 num_ch
, u32 s_rate
,
140 u8 dirn
, u8 dev_type
)
142 struct nhlt_fmt
*fmt
;
143 struct nhlt_endpoint
*epnt
;
144 struct hdac_bus
*bus
= ebus_to_hbus(&skl
->ebus
);
145 struct device
*dev
= bus
->dev
;
146 struct nhlt_specific_cfg
*sp_config
;
147 struct nhlt_acpi_table
*nhlt
= skl
->nhlt
;
148 u16 bps
= (s_fmt
== 16) ? 16 : 32;
151 dump_config(dev
, instance
, link_type
, s_fmt
, num_ch
, s_rate
, dirn
, bps
);
153 epnt
= (struct nhlt_endpoint
*)nhlt
->desc
;
155 dev_dbg(dev
, "endpoint count =%d\n", nhlt
->endpoint_count
);
157 for (j
= 0; j
< nhlt
->endpoint_count
; j
++) {
158 if (skl_check_ep_match(dev
, epnt
, instance
, link_type
,
160 fmt
= (struct nhlt_fmt
*)(epnt
->config
.caps
+
162 sp_config
= skl_get_specific_cfg(dev
, fmt
, num_ch
,
163 s_rate
, bps
, link_type
);
168 epnt
= (struct nhlt_endpoint
*)((u8
*)epnt
+ epnt
->length
);
174 int skl_get_dmic_geo(struct skl
*skl
)
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;
183 epnt
= (struct nhlt_endpoint
*)nhlt
->desc
;
185 for (j
= 0; j
< nhlt
->endpoint_count
; j
++) {
186 if (epnt
->linktype
== NHLT_LINK_DMIC
) {
187 cfg
= (struct nhlt_dmic_array_config
*)
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
;
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
;
202 dev_warn(dev
, "undefined DMIC array_type 0x%0x\n",
207 epnt
= (struct nhlt_endpoint
*)((u8
*)epnt
+ epnt
->length
);
213 static void skl_nhlt_trim_space(char *trim
)
220 for (i
= 0; s
[i
]; i
++) {
228 int skl_nhlt_update_topology_bin(struct skl
*skl
)
230 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
231 struct hdac_bus
*bus
= ebus_to_hbus(&skl
->ebus
);
232 struct device
*dev
= bus
->dev
;
234 dev_dbg(dev
, "oem_id %.6s, oem_table_id %8s oem_revision %d\n",
235 nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
236 nhlt
->header
.oem_revision
);
238 snprintf(skl
->tplg_name
, sizeof(skl
->tplg_name
), "%x-%.6s-%.8s-%d%s",
239 skl
->pci_id
, nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
240 nhlt
->header
.oem_revision
, "-tplg.bin");
242 skl_nhlt_trim_space(skl
->tplg_name
);
247 static ssize_t
skl_nhlt_platform_id_show(struct device
*dev
,
248 struct device_attribute
*attr
, char *buf
)
250 struct pci_dev
*pci
= to_pci_dev(dev
);
251 struct hdac_ext_bus
*ebus
= pci_get_drvdata(pci
);
252 struct skl
*skl
= ebus_to_skl(ebus
);
253 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
254 char platform_id
[32];
256 sprintf(platform_id
, "%x-%.6s-%.8s-%d", skl
->pci_id
,
257 nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
258 nhlt
->header
.oem_revision
);
260 skl_nhlt_trim_space(platform_id
);
261 return sprintf(buf
, "%s\n", platform_id
);
264 static DEVICE_ATTR(platform_id
, 0444, skl_nhlt_platform_id_show
, NULL
);
266 int skl_nhlt_create_sysfs(struct skl
*skl
)
268 struct device
*dev
= &skl
->pci
->dev
;
270 if (sysfs_create_file(&dev
->kobj
, &dev_attr_platform_id
.attr
))
271 dev_warn(dev
, "Error creating sysfs entry\n");
276 void skl_nhlt_remove_sysfs(struct skl
*skl
)
278 struct device
*dev
= &skl
->pci
->dev
;
280 sysfs_remove_file(&dev
->kobj
, &dev_attr_platform_id
.attr
);
284 * Queries NHLT for all the fmt configuration for a particular endpoint and
285 * stores all possible rates supported in a rate table for the corresponding
288 static void skl_get_ssp_clks(struct skl
*skl
, struct skl_ssp_clk
*ssp_clks
,
289 struct nhlt_fmt
*fmt
, u8 id
)
291 struct skl_i2s_config_blob_ext
*i2s_config_ext
;
292 struct skl_i2s_config_blob_legacy
*i2s_config
;
293 struct skl_clk_parent_src
*parent
;
294 struct skl_ssp_clk
*sclk
, *sclkfs
;
295 struct nhlt_fmt_cfg
*fmt_cfg
;
296 struct wav_fmt_ext
*wav_fmt
;
297 unsigned long rate
= 0;
298 bool present
= false;
305 sclk
= &ssp_clks
[SKL_SCLK_OFS
];
306 sclkfs
= &ssp_clks
[SKL_SCLKFS_OFS
];
308 if (fmt
->fmt_count
== 0)
311 for (i
= 0; i
< fmt
->fmt_count
; i
++) {
312 fmt_cfg
= &fmt
->fmt_config
[i
];
313 wav_fmt
= &fmt_cfg
->fmt_ext
;
315 channels
= wav_fmt
->fmt
.channels
;
316 bps
= wav_fmt
->fmt
.bits_per_sample
;
317 fs
= wav_fmt
->fmt
.samples_per_sec
;
320 * In case of TDM configuration on a ssp, there can
321 * be more than one blob in which channel masks are
322 * different for each usecase for a specific rate and bps.
323 * But the sclk rate will be generated for the total
324 * number of channels used for that endpoint.
326 * So for the given fs and bps, choose blob which has
327 * the superset of all channels for that endpoint and
330 for (j
= i
; j
< fmt
->fmt_count
; j
++) {
331 fmt_cfg
= &fmt
->fmt_config
[j
];
332 wav_fmt
= &fmt_cfg
->fmt_ext
;
333 if ((fs
== wav_fmt
->fmt
.samples_per_sec
) &&
334 (bps
== wav_fmt
->fmt
.bits_per_sample
))
335 channels
= max_t(u16
, channels
,
336 wav_fmt
->fmt
.channels
);
339 rate
= channels
* bps
* fs
;
341 /* check if the rate is added already to the given SSP's sclk */
342 for (j
= 0; (j
< SKL_MAX_CLK_RATES
) &&
343 (sclk
[id
].rate_cfg
[j
].rate
!= 0); j
++) {
344 if (sclk
[id
].rate_cfg
[j
].rate
== rate
) {
350 /* Fill rate and parent for sclk/sclkfs */
352 i2s_config_ext
= (struct skl_i2s_config_blob_ext
*)
353 fmt
->fmt_config
[0].config
.caps
;
355 /* MCLK Divider Source Select */
356 if (is_legacy_blob(i2s_config_ext
->hdr
.sig
)) {
357 i2s_config
= ext_to_legacy_blob(i2s_config_ext
);
358 clk_src
= get_clk_src(i2s_config
->mclk
,
359 SKL_MNDSS_DIV_CLK_SRC_MASK
);
361 clk_src
= get_clk_src(i2s_config_ext
->mclk
,
362 SKL_MNDSS_DIV_CLK_SRC_MASK
);
365 parent
= skl_get_parent_clk(clk_src
);
368 * Do not copy the config data if there is no parent
369 * clock available for this clock source select
374 sclk
[id
].rate_cfg
[rate_index
].rate
= rate
;
375 sclk
[id
].rate_cfg
[rate_index
].config
= fmt_cfg
;
376 sclkfs
[id
].rate_cfg
[rate_index
].rate
= rate
;
377 sclkfs
[id
].rate_cfg
[rate_index
].config
= fmt_cfg
;
378 sclk
[id
].parent_name
= parent
->name
;
379 sclkfs
[id
].parent_name
= parent
->name
;
386 static void skl_get_mclk(struct skl
*skl
, struct skl_ssp_clk
*mclk
,
387 struct nhlt_fmt
*fmt
, u8 id
)
389 struct skl_i2s_config_blob_ext
*i2s_config_ext
;
390 struct skl_i2s_config_blob_legacy
*i2s_config
;
391 struct nhlt_specific_cfg
*fmt_cfg
;
392 struct skl_clk_parent_src
*parent
;
393 u32 clkdiv
, div_ratio
;
396 fmt_cfg
= &fmt
->fmt_config
[0].config
;
397 i2s_config_ext
= (struct skl_i2s_config_blob_ext
*)fmt_cfg
->caps
;
399 /* MCLK Divider Source Select and divider */
400 if (is_legacy_blob(i2s_config_ext
->hdr
.sig
)) {
401 i2s_config
= ext_to_legacy_blob(i2s_config_ext
);
402 clk_src
= get_clk_src(i2s_config
->mclk
,
403 SKL_MCLK_DIV_CLK_SRC_MASK
);
404 clkdiv
= i2s_config
->mclk
.mdivr
&
405 SKL_MCLK_DIV_RATIO_MASK
;
407 clk_src
= get_clk_src(i2s_config_ext
->mclk
,
408 SKL_MCLK_DIV_CLK_SRC_MASK
);
409 clkdiv
= i2s_config_ext
->mclk
.mdivr
[0] &
410 SKL_MCLK_DIV_RATIO_MASK
;
416 if (clkdiv
!= SKL_MCLK_DIV_RATIO_MASK
)
417 /* Divider is 2 + clkdiv */
418 div_ratio
= clkdiv
+ 2;
420 /* Calculate MCLK rate from source using div value */
421 parent
= skl_get_parent_clk(clk_src
);
425 mclk
[id
].rate_cfg
[0].rate
= parent
->rate
/div_ratio
;
426 mclk
[id
].rate_cfg
[0].config
= &fmt
->fmt_config
[0];
427 mclk
[id
].parent_name
= parent
->name
;
430 void skl_get_clks(struct skl
*skl
, struct skl_ssp_clk
*ssp_clks
)
432 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
433 struct nhlt_endpoint
*epnt
;
434 struct nhlt_fmt
*fmt
;
438 epnt
= (struct nhlt_endpoint
*)nhlt
->desc
;
439 for (i
= 0; i
< nhlt
->endpoint_count
; i
++) {
440 if (epnt
->linktype
== NHLT_LINK_SSP
) {
441 id
= epnt
->virtual_bus_id
;
443 fmt
= (struct nhlt_fmt
*)(epnt
->config
.caps
444 + epnt
->config
.size
);
446 skl_get_ssp_clks(skl
, ssp_clks
, fmt
, id
);
447 skl_get_mclk(skl
, ssp_clks
, fmt
, id
);
449 epnt
= (struct nhlt_endpoint
*)((u8
*)epnt
+ epnt
->length
);