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>
23 #define NHLT_ACPI_HEADER_SIG "NHLT"
25 /* Unique identification for getting NHLT blobs */
26 static guid_t osc_guid
=
27 GUID_INIT(0xA69F886E, 0x6CEB, 0x4594,
28 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53);
30 struct nhlt_acpi_table
*skl_nhlt_init(struct device
*dev
)
33 union acpi_object
*obj
;
34 struct nhlt_resource_desc
*nhlt_ptr
= NULL
;
35 struct nhlt_acpi_table
*nhlt_table
= NULL
;
37 handle
= ACPI_HANDLE(dev
);
39 dev_err(dev
, "Didn't find ACPI_HANDLE\n");
43 obj
= acpi_evaluate_dsm(handle
, &osc_guid
, 1, 1, NULL
);
44 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
) {
45 nhlt_ptr
= (struct nhlt_resource_desc
*)obj
->buffer
.pointer
;
47 nhlt_table
= (struct nhlt_acpi_table
*)
48 memremap(nhlt_ptr
->min_addr
, nhlt_ptr
->length
,
51 if (nhlt_table
&& (strncmp(nhlt_table
->header
.signature
,
53 strlen(NHLT_ACPI_HEADER_SIG
)) != 0)) {
55 dev_err(dev
, "NHLT ACPI header signature incorrect\n");
61 dev_err(dev
, "device specific method to extract NHLT blob failed\n");
65 void skl_nhlt_free(struct nhlt_acpi_table
*nhlt
)
67 memunmap((void *) nhlt
);
70 static struct nhlt_specific_cfg
*skl_get_specific_cfg(
71 struct device
*dev
, struct nhlt_fmt
*fmt
,
72 u8 no_ch
, u32 rate
, u16 bps
, u8 linktype
)
74 struct nhlt_specific_cfg
*sp_config
;
76 struct nhlt_fmt_cfg
*fmt_config
= fmt
->fmt_config
;
79 dev_dbg(dev
, "Format count =%d\n", fmt
->fmt_count
);
81 for (i
= 0; i
< fmt
->fmt_count
; i
++) {
82 wfmt
= &fmt_config
->fmt_ext
.fmt
;
83 dev_dbg(dev
, "ch=%d fmt=%d s_rate=%d\n", wfmt
->channels
,
84 wfmt
->bits_per_sample
, wfmt
->samples_per_sec
);
85 if (wfmt
->channels
== no_ch
&& wfmt
->bits_per_sample
== bps
) {
87 * if link type is dmic ignore rate check as the blob is
88 * generic for all rates
90 sp_config
= &fmt_config
->config
;
91 if (linktype
== NHLT_LINK_DMIC
)
94 if (wfmt
->samples_per_sec
== rate
)
98 fmt_config
= (struct nhlt_fmt_cfg
*)(fmt_config
->config
.caps
+
99 fmt_config
->config
.size
);
105 static void dump_config(struct device
*dev
, u32 instance_id
, u8 linktype
,
106 u8 s_fmt
, u8 num_channels
, u32 s_rate
, u8 dirn
, u16 bps
)
108 dev_dbg(dev
, "Input configuration\n");
109 dev_dbg(dev
, "ch=%d fmt=%d s_rate=%d\n", num_channels
, s_fmt
, s_rate
);
110 dev_dbg(dev
, "vbus_id=%d link_type=%d\n", instance_id
, linktype
);
111 dev_dbg(dev
, "bits_per_sample=%d\n", bps
);
114 static bool skl_check_ep_match(struct device
*dev
, struct nhlt_endpoint
*epnt
,
115 u32 instance_id
, u8 link_type
, u8 dirn
, u8 dev_type
)
117 dev_dbg(dev
, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n",
118 epnt
->virtual_bus_id
, epnt
->linktype
,
119 epnt
->direction
, epnt
->device_type
);
121 if ((epnt
->virtual_bus_id
== instance_id
) &&
122 (epnt
->linktype
== link_type
) &&
123 (epnt
->direction
== dirn
)) {
124 /* do not check dev_type for DMIC link type */
125 if (epnt
->linktype
== NHLT_LINK_DMIC
)
128 if (epnt
->device_type
== dev_type
)
135 struct nhlt_specific_cfg
136 *skl_get_ep_blob(struct skl
*skl
, u32 instance
, u8 link_type
,
137 u8 s_fmt
, u8 num_ch
, u32 s_rate
,
138 u8 dirn
, u8 dev_type
)
140 struct nhlt_fmt
*fmt
;
141 struct nhlt_endpoint
*epnt
;
142 struct hdac_bus
*bus
= ebus_to_hbus(&skl
->ebus
);
143 struct device
*dev
= bus
->dev
;
144 struct nhlt_specific_cfg
*sp_config
;
145 struct nhlt_acpi_table
*nhlt
= skl
->nhlt
;
146 u16 bps
= (s_fmt
== 16) ? 16 : 32;
149 dump_config(dev
, instance
, link_type
, s_fmt
, num_ch
, s_rate
, dirn
, bps
);
151 epnt
= (struct nhlt_endpoint
*)nhlt
->desc
;
153 dev_dbg(dev
, "endpoint count =%d\n", nhlt
->endpoint_count
);
155 for (j
= 0; j
< nhlt
->endpoint_count
; j
++) {
156 if (skl_check_ep_match(dev
, epnt
, instance
, link_type
,
158 fmt
= (struct nhlt_fmt
*)(epnt
->config
.caps
+
160 sp_config
= skl_get_specific_cfg(dev
, fmt
, num_ch
,
161 s_rate
, bps
, link_type
);
166 epnt
= (struct nhlt_endpoint
*)((u8
*)epnt
+ epnt
->length
);
172 int skl_get_dmic_geo(struct skl
*skl
)
174 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
175 struct nhlt_endpoint
*epnt
;
176 struct nhlt_dmic_array_config
*cfg
;
177 struct device
*dev
= &skl
->pci
->dev
;
178 unsigned int dmic_geo
= 0;
181 epnt
= (struct nhlt_endpoint
*)nhlt
->desc
;
183 for (j
= 0; j
< nhlt
->endpoint_count
; j
++) {
184 if (epnt
->linktype
== NHLT_LINK_DMIC
) {
185 cfg
= (struct nhlt_dmic_array_config
*)
187 switch (cfg
->array_type
) {
188 case NHLT_MIC_ARRAY_2CH_SMALL
:
189 case NHLT_MIC_ARRAY_2CH_BIG
:
190 dmic_geo
|= MIC_ARRAY_2CH
;
193 case NHLT_MIC_ARRAY_4CH_1ST_GEOM
:
194 case NHLT_MIC_ARRAY_4CH_L_SHAPED
:
195 case NHLT_MIC_ARRAY_4CH_2ND_GEOM
:
196 dmic_geo
|= MIC_ARRAY_4CH
;
200 dev_warn(dev
, "undefined DMIC array_type 0x%0x\n",
205 epnt
= (struct nhlt_endpoint
*)((u8
*)epnt
+ epnt
->length
);
211 static void skl_nhlt_trim_space(char *trim
)
218 for (i
= 0; s
[i
]; i
++) {
226 int skl_nhlt_update_topology_bin(struct skl
*skl
)
228 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
229 struct hdac_bus
*bus
= ebus_to_hbus(&skl
->ebus
);
230 struct device
*dev
= bus
->dev
;
232 dev_dbg(dev
, "oem_id %.6s, oem_table_id %8s oem_revision %d\n",
233 nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
234 nhlt
->header
.oem_revision
);
236 snprintf(skl
->tplg_name
, sizeof(skl
->tplg_name
), "%x-%.6s-%.8s-%d%s",
237 skl
->pci_id
, nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
238 nhlt
->header
.oem_revision
, "-tplg.bin");
240 skl_nhlt_trim_space(skl
->tplg_name
);
245 static ssize_t
skl_nhlt_platform_id_show(struct device
*dev
,
246 struct device_attribute
*attr
, char *buf
)
248 struct pci_dev
*pci
= to_pci_dev(dev
);
249 struct hdac_ext_bus
*ebus
= pci_get_drvdata(pci
);
250 struct skl
*skl
= ebus_to_skl(ebus
);
251 struct nhlt_acpi_table
*nhlt
= (struct nhlt_acpi_table
*)skl
->nhlt
;
252 char platform_id
[32];
254 sprintf(platform_id
, "%x-%.6s-%.8s-%d", skl
->pci_id
,
255 nhlt
->header
.oem_id
, nhlt
->header
.oem_table_id
,
256 nhlt
->header
.oem_revision
);
258 skl_nhlt_trim_space(platform_id
);
259 return sprintf(buf
, "%s\n", platform_id
);
262 static DEVICE_ATTR(platform_id
, 0444, skl_nhlt_platform_id_show
, NULL
);
264 int skl_nhlt_create_sysfs(struct skl
*skl
)
266 struct device
*dev
= &skl
->pci
->dev
;
268 if (sysfs_create_file(&dev
->kobj
, &dev_attr_platform_id
.attr
))
269 dev_warn(dev
, "Error creating sysfs entry\n");
274 void skl_nhlt_remove_sysfs(struct skl
*skl
)
276 struct device
*dev
= &skl
->pci
->dev
;
278 sysfs_remove_file(&dev
->kobj
, &dev_attr_platform_id
.attr
);