History

ASoC: Intel: avs: PCI driver implementation

HD-Audio bus is a PCI device. Add all functions necessary to probe such device along with its removal sequence. Behaviour implemented for all standard operations is similar to existing solutions: sound/pci/hda and sound/soc/intel/skylake.

Cezary Rojewski committed 4 years ago

Commit 1affc441 parent beed9836 files · +499 −4Browse files

Unified · Split

6 files
  1. include/sound/intel-dsp-config.h +2 −1
  2. sound/soc/intel/Kconfig +1 −0
  3. sound/soc/intel/avs/avs.h +1 −0
  4. sound/soc/intel/avs/core.c +494 −0
  5. sound/soc/intel/avs/dsp.c +0 −3
  6. sound/soc/intel/avs/registers.h +1 −0
include/sound/intel-dsp-config.h+2−1
@@ -15,7 +15,8 @@ enum { · 14 unmodified lines
15 SND_INTEL_DSP_DRIVER_LEGACY,15 SND_INTEL_DSP_DRIVER_LEGACY,
16 SND_INTEL_DSP_DRIVER_SST,16 SND_INTEL_DSP_DRIVER_SST,
17 SND_INTEL_DSP_DRIVER_SOF,17 SND_INTEL_DSP_DRIVER_SOF,
18 SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_SOF18 SND_INTEL_DSP_DRIVER_AVS,
19 SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_AVS
19};20};
20 21
21#if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)22#if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
sound/soc/intel/Kconfig+1−0
@@ -216,6 +216,7 @@ config SND_SOC_INTEL_AVS · 215 unmodified lines
216 depends on COMMON_CLK216 depends on COMMON_CLK
217 select SND_SOC_ACPI if ACPI217 select SND_SOC_ACPI if ACPI
218 select SND_SOC_TOPOLOGY218 select SND_SOC_TOPOLOGY
219 select SND_HDA
219 select SND_HDA_EXT_CORE220 select SND_HDA_EXT_CORE
220 select SND_HDA_DSP_LOADER221 select SND_HDA_DSP_LOADER
221 select SND_INTEL_DSP_CONFIG222 select SND_INTEL_DSP_CONFIG
sound/soc/intel/avs/avs.h+1−0
@@ -126,6 +126,7 @@ struct avs_dev { · 125 unmodified lines
126 char **lib_names;126 char **lib_names;
127 127
128 struct completion fw_ready;128 struct completion fw_ready;
129 struct work_struct probe_work;
129 130
130 struct nhlt_acpi_table *nhlt;131 struct nhlt_acpi_table *nhlt;
131 struct list_head comp_list;132 struct list_head comp_list;
sound/soc/intel/avs/core.c+494−0
@@ -14,9 +14,17 @@ · 13 unmodified lines
14// foundation of this driver14// foundation of this driver
15//15//
16 16
17#include <linux/module.h>
17#include <linux/pci.h>18#include <linux/pci.h>
19#include <sound/hda_codec.h>
20#include <sound/hda_i915.h>
21#include <sound/hda_register.h>
18#include <sound/hdaudio.h>22#include <sound/hdaudio.h>
23#include <sound/hdaudio_ext.h>
24#include <sound/intel-dsp-config.h>
25#include <sound/intel-nhlt.h>
19#include "avs.h"26#include "avs.h"
27#include "cldma.h"
20 28
21static void29static void
22avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)30avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
@@ -59,3 +67,489 @@ void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) · 36 unmodified lines
59 value = enable ? AZX_VS_EM2_L1SEN : 0;67 value = enable ? AZX_VS_EM2_L1SEN : 0;
60 snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);68 snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
61}69}
70
71static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
72{
73 unsigned int cp_streams, pb_streams;
74 unsigned int gcap;
75
76 gcap = snd_hdac_chip_readw(bus, GCAP);
77 cp_streams = (gcap >> 8) & 0x0F;
78 pb_streams = (gcap >> 12) & 0x0F;
79 bus->num_streams = cp_streams + pb_streams;
80
81 snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
82 snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
83
84 return snd_hdac_bus_alloc_stream_pages(bus);
85}
86
87static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
88{
89 struct hdac_ext_link *hlink;
90 bool ret;
91
92 avs_hdac_clock_gating_enable(bus, false);
93 ret = snd_hdac_bus_init_chip(bus, full_reset);
94
95 /* Reset stream-to-link mapping */
96 list_for_each_entry(hlink, &bus->hlink_list, list)
97 writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
98
99 avs_hdac_clock_gating_enable(bus, true);
100
101 /* Set DUM bit to address incorrect position reporting for capture
102 * streams. In order to do so, CTRL needs to be out of reset state
103 */
104 snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
105
106 return ret;
107}
108
109static int probe_codec(struct hdac_bus *bus, int addr)
110{
111 struct hda_codec *codec;
112 unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
113 (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
114 unsigned int res = -1;
115 int ret;
116
117 mutex_lock(&bus->cmd_mutex);
118 snd_hdac_bus_send_cmd(bus, cmd);
119 snd_hdac_bus_get_response(bus, addr, &res);
120 mutex_unlock(&bus->cmd_mutex);
121 if (res == -1)
122 return -EIO;
123
124 dev_dbg(bus->dev, "codec #%d probed OK: 0x%x\n", addr, res);
125
126 codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "hdaudioB%dD%d", bus->idx, addr);
127 if (IS_ERR(codec)) {
128 dev_err(bus->dev, "init codec failed: %ld\n", PTR_ERR(codec));
129 return PTR_ERR(codec);
130 }
131 /*
132 * Allow avs_core suspend by forcing suspended state on all
133 * of its codec child devices. Component interested in
134 * dealing with hda codecs directly takes pm responsibilities
135 */
136 pm_runtime_set_suspended(hda_codec_dev(codec));
137
138 /* configure effectively creates new ASoC component */
139 ret = snd_hda_codec_configure(codec);
140 if (ret < 0) {
141 dev_err(bus->dev, "failed to config codec %d\n", ret);
142 return ret;
143 }
144
145 return 0;
146}
147
148static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus)
149{
150 int c;
151
152 /* First try to probe all given codec slots */
153 for (c = 0; c < HDA_MAX_CODECS; c++) {
154 if (!(bus->codec_mask & BIT(c)))
155 continue;
156
157 if (!probe_codec(bus, c))
158 /* success, continue probing */
159 continue;
160
161 /*
162 * Some BIOSen give you wrong codec addresses
163 * that don't exist
164 */
165 dev_warn(bus->dev, "Codec #%d probe error; disabling it...\n", c);
166 bus->codec_mask &= ~BIT(c);
167 /*
168 * More badly, accessing to a non-existing
169 * codec often screws up the controller bus,
170 * and disturbs the further communications.
171 * Thus if an error occurs during probing,
172 * better to reset the controller bus to get
173 * back to the sanity state.
174 */
175 snd_hdac_bus_stop_chip(bus);
176 avs_hdac_bus_init_chip(bus, true);
177 }
178}
179
180static void avs_hda_probe_work(struct work_struct *work)
181{
182 struct avs_dev *adev = container_of(work, struct avs_dev, probe_work);
183 struct hdac_bus *bus = &adev->base.core;
184 struct hdac_ext_link *hlink;
185 int ret;
186
187 pm_runtime_set_active(bus->dev); /* clear runtime_error flag */
188
189 ret = snd_hdac_i915_init(bus);
190 if (ret < 0)
191 dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);
192
193 snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
194 avs_hdac_bus_init_chip(bus, true);
195 avs_hdac_bus_probe_codecs(bus);
196 snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
197
198 /* with all codecs probed, links can be powered down */
199 list_for_each_entry(hlink, &bus->hlink_list, list)
200 snd_hdac_ext_bus_link_put(bus, hlink);
201
202 snd_hdac_ext_bus_ppcap_enable(bus, true);
203 snd_hdac_ext_bus_ppcap_int_enable(bus, true);
204
205 ret = avs_dsp_first_boot_firmware(adev);
206 if (ret < 0)
207 return;
208
209 adev->nhlt = intel_nhlt_init(adev->dev);
210 if (!adev->nhlt)
211 dev_info(bus->dev, "platform has no NHLT\n");
212
213 avs_register_all_boards(adev);
214
215 /* configure PM */
216 pm_runtime_set_autosuspend_delay(bus->dev, 2000);
217 pm_runtime_use_autosuspend(bus->dev);
218 pm_runtime_mark_last_busy(bus->dev);
219 pm_runtime_put_autosuspend(bus->dev);
220 pm_runtime_allow(bus->dev);
221}
222
223static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
224{
225 u64 prev_pos, pos, num_bytes;
226
227 div64_u64_rem(stream->curr_pos, buffer_size, &prev_pos);
228 pos = snd_hdac_stream_get_pos_posbuf(stream);
229
230 if (pos < prev_pos)
231 num_bytes = (buffer_size - prev_pos) + pos;
232 else
233 num_bytes = pos - prev_pos;
234
235 stream->curr_pos += num_bytes;
236}
237
238/* called from IRQ */
239static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
240{
241 if (stream->substream) {
242 snd_pcm_period_elapsed(stream->substream);
243 } else if (stream->cstream) {
244 u64 buffer_size = stream->cstream->runtime->buffer_size;
245
246 hdac_stream_update_pos(stream, buffer_size);
247 snd_compr_fragment_elapsed(stream->cstream);
248 }
249}
250
251static irqreturn_t hdac_bus_irq_handler(int irq, void *context)
252{
253 struct hdac_bus *bus = context;
254 u32 mask, int_enable;
255 u32 status;
256 int ret = IRQ_NONE;
257
258 if (!pm_runtime_active(bus->dev))
259 return ret;
260
261 spin_lock(&bus->reg_lock);
262
263 status = snd_hdac_chip_readl(bus, INTSTS);
264 if (status == 0 || status == UINT_MAX) {
265 spin_unlock(&bus->reg_lock);
266 return ret;
267 }
268
269 /* clear rirb int */
270 status = snd_hdac_chip_readb(bus, RIRBSTS);
271 if (status & RIRB_INT_MASK) {
272 if (status & RIRB_INT_RESPONSE)
273 snd_hdac_bus_update_rirb(bus);
274 snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
275 }
276
277 mask = (0x1 << bus->num_streams) - 1;
278
279 status = snd_hdac_chip_readl(bus, INTSTS);
280 status &= mask;
281 if (status) {
282 /* Disable stream interrupts; Re-enable in bottom half */
283 int_enable = snd_hdac_chip_readl(bus, INTCTL);
284 snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask)));
285 ret = IRQ_WAKE_THREAD;
286 } else {
287 ret = IRQ_HANDLED;
288 }
289
290 spin_unlock(&bus->reg_lock);
291 return ret;
292}
293
294static irqreturn_t hdac_bus_irq_thread(int irq, void *context)
295{
296 struct hdac_bus *bus = context;
297 u32 status;
298 u32 int_enable;
299 u32 mask;
300 unsigned long flags;
301
302 status = snd_hdac_chip_readl(bus, INTSTS);
303
304 snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream);
305
306 /* Re-enable stream interrupts */
307 mask = (0x1 << bus->num_streams) - 1;
308 spin_lock_irqsave(&bus->reg_lock, flags);
309 int_enable = snd_hdac_chip_readl(bus, INTCTL);
310 snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask));
311 spin_unlock_irqrestore(&bus->reg_lock, flags);
312
313 return IRQ_HANDLED;
314}
315
316static int avs_hdac_acquire_irq(struct avs_dev *adev)
317{
318 struct hdac_bus *bus = &adev->base.core;
319 struct pci_dev *pci = to_pci_dev(bus->dev);
320 int ret;
321
322 /* request one and check that we only got one interrupt */
323 ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY);
324 if (ret != 1) {
325 dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret);
326 return ret;
327 }
328
329 ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus,
330 KBUILD_MODNAME);
331 if (ret < 0) {
332 dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret);
333 goto free_vector;
334 }
335
336 ret = pci_request_irq(pci, 0, avs_dsp_irq_handler, avs_dsp_irq_thread, adev,
337 KBUILD_MODNAME);
338 if (ret < 0) {
339 dev_err(adev->dev, "Failed to request IPC IRQ handler: %d\n", ret);
340 goto free_stream_irq;
341 }
342
343 return 0;
344
345free_stream_irq:
346 pci_free_irq(pci, 0, bus);
347free_vector:
348 pci_free_irq_vectors(pci);
349 return ret;
350}
351
352static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct pci_device_id *id)
353{
354 struct hda_bus *bus = &adev->base;
355 struct avs_ipc *ipc;
356 struct device *dev = &pci->dev;
357 int ret;
358
359 ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, NULL);
360 if (ret < 0)
361 return ret;
362
363 bus->core.use_posbuf = 1;
364 bus->core.bdl_pos_adj = 0;
365 bus->core.sync_write = 1;
366 bus->pci = pci;
367 bus->mixer_assigned = -1;
368 mutex_init(&bus->prepare_mutex);
369
370 ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
371 if (!ipc)
372 return -ENOMEM;
373 ret = avs_ipc_init(ipc, dev);
374 if (ret < 0)
375 return ret;
376
377 adev->dev = dev;
378 adev->spec = (const struct avs_spec *)id->driver_data;
379 adev->ipc = ipc;
380 adev->hw_cfg.dsp_cores = hweight_long(AVS_MAIN_CORE_MASK);
381 INIT_WORK(&adev->probe_work, avs_hda_probe_work);
382 INIT_LIST_HEAD(&adev->comp_list);
383 INIT_LIST_HEAD(&adev->path_list);
384 INIT_LIST_HEAD(&adev->fw_list);
385 init_completion(&adev->fw_ready);
386 spin_lock_init(&adev->path_list_lock);
387 mutex_init(&adev->modres_mutex);
388 mutex_init(&adev->comp_list_mutex);
389 mutex_init(&adev->path_mutex);
390
391 return 0;
392}
393
394static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
395{
396 struct hdac_bus *bus;
397 struct avs_dev *adev;
398 struct device *dev = &pci->dev;
399 int ret;
400
401 ret = snd_intel_dsp_driver_probe(pci);
402 if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS)
403 return -ENODEV;
404
405 ret = pcim_enable_device(pci);
406 if (ret < 0)
407 return ret;
408
409 adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
410 if (!adev)
411 return -ENOMEM;
412 ret = avs_bus_init(adev, pci, id);
413 if (ret < 0) {
414 dev_err(dev, "failed to init avs bus: %d\n", ret);
415 return ret;
416 }
417
418 ret = pci_request_regions(pci, "AVS HDAudio");
419 if (ret < 0)
420 return ret;
421
422 bus = &adev->base.core;
423 bus->addr = pci_resource_start(pci, 0);
424 bus->remap_addr = pci_ioremap_bar(pci, 0);
425 if (!bus->remap_addr) {
426 dev_err(bus->dev, "ioremap error\n");
427 ret = -ENXIO;
428 goto err_remap_bar0;
429 }
430
431 adev->dsp_ba = pci_ioremap_bar(pci, 4);
432 if (!adev->dsp_ba) {
433 dev_err(bus->dev, "ioremap error\n");
434 ret = -ENXIO;
435 goto err_remap_bar4;
436 }
437
438 snd_hdac_bus_parse_capabilities(bus);
439 if (bus->mlcap)
440 snd_hdac_ext_bus_get_ml_capabilities(bus);
441
442 if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
443 dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
444 } else {
445 dma_set_mask(dev, DMA_BIT_MASK(32));
446 dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
447 }
448
449 ret = avs_hdac_bus_init_streams(bus);
450 if (ret < 0) {
451 dev_err(dev, "failed to init streams: %d\n", ret);
452 goto err_init_streams;
453 }
454
455 ret = avs_hdac_acquire_irq(adev);
456 if (ret < 0) {
457 dev_err(bus->dev, "failed to acquire irq: %d\n", ret);
458 goto err_acquire_irq;
459 }
460
461 pci_set_master(pci);
462 pci_set_drvdata(pci, bus);
463 device_disable_async_suspend(dev);
464
465 schedule_work(&adev->probe_work);
466
467 return 0;
468
469err_acquire_irq:
470 snd_hdac_bus_free_stream_pages(bus);
471 snd_hdac_stream_free_all(bus);
472err_init_streams:
473 iounmap(adev->dsp_ba);
474err_remap_bar4:
475 iounmap(bus->remap_addr);
476err_remap_bar0:
477 pci_release_regions(pci);
478 return ret;
479}
480
481static void avs_pci_remove(struct pci_dev *pci)
482{
483 struct hdac_device *hdev, *save;
484 struct hdac_bus *bus = pci_get_drvdata(pci);
485 struct avs_dev *adev = hdac_to_avs(bus);
486
487 cancel_work_sync(&adev->probe_work);
488 avs_ipc_block(adev->ipc);
489
490 avs_unregister_all_boards(adev);
491
492 if (adev->nhlt)
493 intel_nhlt_free(adev->nhlt);
494
495 if (avs_platattr_test(adev, CLDMA))
496 hda_cldma_free(&code_loader);
497
498 snd_hdac_stop_streams_and_chip(bus);
499 avs_dsp_op(adev, int_control, false);
500 snd_hdac_ext_bus_ppcap_int_enable(bus, false);
501
502 /* it is safe to remove all codecs from the system now */
503 list_for_each_entry_safe(hdev, save, &bus->codec_list, list)
504 snd_hda_codec_unregister(hdac_to_hda_codec(hdev));
505
506 snd_hdac_bus_free_stream_pages(bus);
507 snd_hdac_stream_free_all(bus);
508 /* reverse ml_capabilities */
509 snd_hdac_link_free_all(bus);
510 snd_hdac_ext_bus_exit(bus);
511
512 avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
513 snd_hdac_ext_bus_ppcap_enable(bus, false);
514
515 /* snd_hdac_stop_streams_and_chip does that already? */
516 snd_hdac_bus_stop_chip(bus);
517 snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
518 if (bus->audio_component)
519 snd_hdac_i915_exit(bus);
520
521 avs_module_info_free(adev);
522 pci_free_irq(pci, 0, adev);
523 pci_free_irq(pci, 0, bus);
524 pci_free_irq_vectors(pci);
525 iounmap(bus->remap_addr);
526 iounmap(adev->dsp_ba);
527 pci_release_regions(pci);
528
529 /* Firmware is not needed anymore */
530 avs_release_firmwares(adev);
531
532 /* pm_runtime_forbid() can rpm_resume() which we do not want */
533 pm_runtime_disable(&pci->dev);
534 pm_runtime_forbid(&pci->dev);
535 pm_runtime_enable(&pci->dev);
536 pm_runtime_get_noresume(&pci->dev);
537}
538
539static const struct pci_device_id avs_ids[] = {
540 { 0 }
541};
542MODULE_DEVICE_TABLE(pci, avs_ids);
543
544static struct pci_driver avs_pci_driver = {
545 .name = KBUILD_MODNAME,
546 .id_table = avs_ids,
547 .probe = avs_pci_probe,
548 .remove = avs_pci_remove,
549};
550module_pci_driver(avs_pci_driver);
551
552MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
553MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>");
554MODULE_DESCRIPTION("Intel cAVS sound driver");
555MODULE_LICENSE("GPL");
sound/soc/intel/avs/dsp.c+0−3
@@ -6,7 +6,6 @@ · 5 unmodified lines
6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7//7//
8 8
9#include <linux/module.h>
10#include <sound/hdaudio_ext.h>9#include <sound/hdaudio_ext.h>
11#include "avs.h"10#include "avs.h"
12#include "registers.h"11#include "registers.h"
@@ -322,5 +321,3 @@ int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id) · 309 unmodified lines
322 ida_free(&adev->ppl_ida, instance_id);321 ida_free(&adev->ppl_ida, instance_id);
323 return ret;322 return ret;
324}323}
325
326MODULE_LICENSE("GPL");
sound/soc/intel/avs/registers.h+1−0
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#define AZX_PGCTL_LSRMD_MASK BIT(4)14#define AZX_PGCTL_LSRMD_MASK BIT(4)
15#define AZX_CGCTL_MISCBDCGE_MASK BIT(6)15#define AZX_CGCTL_MISCBDCGE_MASK BIT(6)
16#define AZX_VS_EM2_L1SEN BIT(13)16#define AZX_VS_EM2_L1SEN BIT(13)
17#define AZX_VS_EM2_DUM BIT(23)
17 18
18/* Intel HD Audio General DSP Registers */19/* Intel HD Audio General DSP Registers */
19#define AVS_ADSP_GEN_BASE 0x020#define AVS_ADSP_GEN_BASE 0x0

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t