.. | .. |
---|
| 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; |
---|