Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for HDA DSP code loader
16 */
17
18#include <linux/firmware.h>
19#include <sound/hdaudio_ext.h>
20#include <sound/hda_register.h>
21#include <sound/sof.h>
22#include "ext_manifest.h"
23#include "../ops.h"
24#include "hda.h"
25
26#define HDA_CL_STREAM_FORMAT 0x40
27
28static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
29 unsigned int size, struct snd_dma_buffer *dmab,
30 int direction)
31{
32 struct hdac_ext_stream *dsp_stream;
33 struct hdac_stream *hstream;
34 struct pci_dev *pci = to_pci_dev(sdev->dev);
35 int ret;
36
37 dsp_stream = hda_dsp_stream_get(sdev, direction, 0);
38
39 if (!dsp_stream) {
40 dev_err(sdev->dev, "error: no stream available\n");
41 return ERR_PTR(-ENODEV);
42 }
43 hstream = &dsp_stream->hstream;
44 hstream->substream = NULL;
45
46 /* allocate DMA buffer */
47 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
48 if (ret < 0) {
49 dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
50 goto error;
51 }
52
53 hstream->period_bytes = 0;/* initialize period_bytes */
54 hstream->format_val = format;
55 hstream->bufsize = size;
56
57 if (direction == SNDRV_PCM_STREAM_CAPTURE) {
58 ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL);
59 if (ret < 0) {
60 dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
61 goto error;
62 }
63 } else {
64 ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
65 if (ret < 0) {
66 dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
67 goto error;
68 }
69 hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
70 }
71
72 return dsp_stream;
73
74error:
75 hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
76 snd_dma_free_pages(dmab);
77 return ERR_PTR(ret);
78}
79
80/*
81 * first boot sequence has some extra steps. core 0 waits for power
82 * status on core 1, so power up core 1 also momentarily, keep it in
83 * reset/stall and then turn it off
84 */
85static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
86{
87 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
88 const struct sof_intel_dsp_desc *chip = hda->desc;
89 unsigned int status;
90 unsigned long mask;
91 char *dump_msg;
92 u32 flags, j;
93 int ret;
94 int i;
95
96 /* step 1: power up corex */
97 ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask);
98 if (ret < 0) {
99 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
100 dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
101 goto err;
102 }
103
104 /* DSP is powered up, set all SSPs to slave mode */
105 for (i = 0; i < chip->ssp_count; i++) {
106 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
107 chip->ssp_base_offset
108 + i * SSP_DEV_MEM_SIZE
109 + SSP_SSC1_OFFSET,
110 SSP_SET_SLAVE,
111 SSP_SET_SLAVE);
112 }
113
114 /* step 2: purge FW request */
115 snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req,
116 chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW |
117 ((stream_tag - 1) << 9)));
118
119 /* step 3: unset core 0 reset state & unstall/run core 0 */
120 ret = hda_dsp_core_run(sdev, BIT(0));
121 if (ret < 0) {
122 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
123 dev_err(sdev->dev,
124 "error: dsp core start failed %d\n", ret);
125 ret = -EIO;
126 goto err;
127 }
128
129 /* step 4: wait for IPC DONE bit from ROM */
130 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
131 chip->ipc_ack, status,
132 ((status & chip->ipc_ack_mask)
133 == chip->ipc_ack_mask),
134 HDA_DSP_REG_POLL_INTERVAL_US,
135 HDA_DSP_INIT_TIMEOUT_US);
136
137 if (ret < 0) {
138 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
139 dev_err(sdev->dev,
140 "error: %s: timeout for HIPCIE done\n",
141 __func__);
142 goto err;
143 }
144
145 /* set DONE bit to clear the reply IPC message */
146 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
147 chip->ipc_ack,
148 chip->ipc_ack_mask,
149 chip->ipc_ack_mask);
150
151 /* step 5: power down cores that are no longer needed */
152 ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask &
153 ~(chip->init_core_mask));
154 if (ret < 0) {
155 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
156 dev_err(sdev->dev,
157 "error: dsp core x power down failed\n");
158 goto err;
159 }
160
161 /* step 6: enable IPC interrupts */
162 hda_dsp_ipc_int_enable(sdev);
163
164 /* step 7: wait for ROM init */
165 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
166 HDA_DSP_SRAM_REG_ROM_STATUS, status,
167 ((status & HDA_DSP_ROM_STS_MASK)
168 == HDA_DSP_ROM_INIT),
169 HDA_DSP_REG_POLL_INTERVAL_US,
170 chip->rom_init_timeout *
171 USEC_PER_MSEC);
172 if (!ret) {
173 /* set enabled cores mask and increment ref count for cores in init_core_mask */
174 sdev->enabled_cores_mask |= chip->init_core_mask;
175 mask = sdev->enabled_cores_mask;
176 for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES)
177 sdev->dsp_core_ref_count[j]++;
178 return 0;
179 }
180
181 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
182 dev_err(sdev->dev,
183 "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
184 __func__);
185
186err:
187 flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
188
189 /* after max boot attempts make sure that the dump is printed */
190 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
191 flags &= ~SOF_DBG_DUMP_OPTIONAL;
192
193 dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
194 hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
195 snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
196 hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
197
198 kfree(dump_msg);
199 return ret;
200}
201
202static int cl_trigger(struct snd_sof_dev *sdev,
203 struct hdac_ext_stream *stream, int cmd)
204{
205 struct hdac_stream *hstream = &stream->hstream;
206 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
207
208 /* code loader is special case that reuses stream ops */
209 switch (cmd) {
210 case SNDRV_PCM_TRIGGER_START:
211 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
212 1 << hstream->index,
213 1 << hstream->index);
214
215 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
216 sd_offset,
217 SOF_HDA_SD_CTL_DMA_START |
218 SOF_HDA_CL_DMA_SD_INT_MASK,
219 SOF_HDA_SD_CTL_DMA_START |
220 SOF_HDA_CL_DMA_SD_INT_MASK);
221
222 hstream->running = true;
223 return 0;
224 default:
225 return hda_dsp_stream_trigger(sdev, stream, cmd);
226 }
227}
228
229static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
230 struct hdac_ext_stream *stream)
231{
232 struct hdac_stream *hstream = &stream->hstream;
233 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
234 int ret = 0;
235
236 if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
237 ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0);
238 else
239 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
240 SOF_HDA_SD_CTL_DMA_START, 0);
241
242 hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag);
243 hstream->running = 0;
244 hstream->substream = NULL;
245
246 /* reset BDL address */
247 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
248 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0);
249 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
250 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
251
252 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
253 snd_dma_free_pages(dmab);
254 dmab->area = NULL;
255 hstream->bufsize = 0;
256 hstream->format_val = 0;
257
258 return ret;
259}
260
261static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream)
262{
263 unsigned int reg;
264 int ret, status;
265
266 ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START);
267 if (ret < 0) {
268 dev_err(sdev->dev, "error: DMA trigger start failed\n");
269 return ret;
270 }
271
272 status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
273 HDA_DSP_SRAM_REG_ROM_STATUS, reg,
274 ((reg & HDA_DSP_ROM_STS_MASK)
275 == HDA_DSP_ROM_FW_ENTERED),
276 HDA_DSP_REG_POLL_INTERVAL_US,
277 HDA_DSP_BASEFW_TIMEOUT_US);
278
279 /*
280 * even in case of errors we still need to stop the DMAs,
281 * but we return the initial error should the DMA stop also fail
282 */
283
284 if (status < 0) {
285 dev_err(sdev->dev,
286 "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
287 __func__);
288 }
289
290 ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP);
291 if (ret < 0) {
292 dev_err(sdev->dev, "error: DMA trigger stop failed\n");
293 if (!status)
294 status = ret;
295 }
296
297 return status;
298}
299
300int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
301{
302 struct snd_sof_pdata *plat_data = sdev->pdata;
303 struct hdac_ext_stream *iccmax_stream;
304 struct hdac_bus *bus = sof_to_bus(sdev);
305 struct firmware stripped_firmware;
306 int ret, ret1;
307 u8 original_gb;
308
309 /* save the original LTRP guardband value */
310 original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK;
311
312 if (plat_data->fw->size <= plat_data->fw_offset) {
313 dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
314 return -EINVAL;
315 }
316
317 stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
318
319 /* prepare capture stream for ICCMAX */
320 iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
321 &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
322 if (IS_ERR(iccmax_stream)) {
323 dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
324 return PTR_ERR(iccmax_stream);
325 }
326
327 ret = hda_dsp_cl_boot_firmware(sdev);
328
329 /*
330 * Perform iccmax stream cleanup. This should be done even if firmware loading fails.
331 * If the cleanup also fails, we return the initial error
332 */
333 ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream);
334 if (ret1 < 0) {
335 dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
336
337 /* set return value to indicate cleanup failure */
338 if (!ret)
339 ret = ret1;
340 }
341
342 /* restore the original guardband value after FW boot */
343 snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb);
344
345 return ret;
346}
347
348int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
349{
350 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
351 struct snd_sof_pdata *plat_data = sdev->pdata;
352 const struct sof_dev_desc *desc = plat_data->desc;
353 const struct sof_intel_dsp_desc *chip_info;
354 struct hdac_ext_stream *stream;
355 struct firmware stripped_firmware;
356 int ret, ret1, i;
357
358 chip_info = desc->chip_info;
359
360 if (plat_data->fw->size <= plat_data->fw_offset) {
361 dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
362 return -EINVAL;
363 }
364
365 stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
366 stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
367
368 /* init for booting wait */
369 init_waitqueue_head(&sdev->boot_wait);
370
371 /* prepare DMA for code loader stream */
372 stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
373 &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK);
374 if (IS_ERR(stream)) {
375 dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
376 return PTR_ERR(stream);
377 }
378
379 memcpy(sdev->dmab.area, stripped_firmware.data,
380 stripped_firmware.size);
381
382 /* try ROM init a few times before giving up */
383 for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
384 dev_dbg(sdev->dev,
385 "Attempting iteration %d of Core En/ROM load...\n", i);
386
387 hda->boot_iteration = i + 1;
388 ret = cl_dsp_init(sdev, stream->hstream.stream_tag);
389
390 /* don't retry anymore if successful */
391 if (!ret)
392 break;
393 }
394
395 if (i == HDA_FW_BOOT_ATTEMPTS) {
396 dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n",
397 i, ret);
398 goto cleanup;
399 }
400
401 /*
402 * When a SoundWire link is in clock stop state, a Slave
403 * device may trigger in-band wakes for events such as jack
404 * insertion or acoustic event detection. This event will lead
405 * to a WAKEEN interrupt, handled by the PCI device and routed
406 * to PME if the PCI device is in D3. The resume function in
407 * audio PCI driver will be invoked by ACPI for PME event and
408 * initialize the device and process WAKEEN interrupt.
409 *
410 * The WAKEEN interrupt should be processed ASAP to prevent an
411 * interrupt flood, otherwise other interrupts, such IPC,
412 * cannot work normally. The WAKEEN is handled after the ROM
413 * is initialized successfully, which ensures power rails are
414 * enabled before accessing the SoundWire SHIM registers
415 */
416 if (!sdev->first_boot)
417 hda_sdw_process_wakeen(sdev);
418
419 /*
420 * Set the boot_iteration to the last attempt, indicating that the
421 * DSP ROM has been initialized and from this point there will be no
422 * retry done to boot.
423 *
424 * Continue with code loading and firmware boot
425 */
426 hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
427 ret = cl_copy_fw(sdev, stream);
428 if (!ret)
429 dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
430 else
431 snd_sof_dsp_dbg_dump(sdev, "Firmware download failed",
432 SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX);
433
434cleanup:
435 /*
436 * Perform codeloader stream cleanup.
437 * This should be done even if firmware loading fails.
438 * If the cleanup also fails, we return the initial error
439 */
440 ret1 = cl_cleanup(sdev, &sdev->dmab, stream);
441 if (ret1 < 0) {
442 dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
443
444 /* set return value to indicate cleanup failure */
445 if (!ret)
446 ret = ret1;
447 }
448
449 /*
450 * return primary core id if both fw copy
451 * and stream clean up are successful
452 */
453 if (!ret)
454 return chip_info->init_core_mask;
455
456 /* disable DSP */
457 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
458 SOF_HDA_REG_PP_PPCTL,
459 SOF_HDA_PPCTL_GPROCEN, 0);
460 return ret;
461}
462
463/* pre fw run operations */
464int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
465{
466 /* disable clock gating and power gating */
467 return hda_dsp_ctrl_clock_power_gating(sdev, false);
468}
469
470/* post fw run operations */
471int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
472{
473 int ret;
474
475 if (sdev->first_boot) {
476 ret = hda_sdw_startup(sdev);
477 if (ret < 0) {
478 dev_err(sdev->dev,
479 "error: could not startup SoundWire links\n");
480 return ret;
481 }
482 }
483
484 hda_sdw_int_enable(sdev, true);
485
486 /* re-enable clock gating and power gating */
487 return hda_dsp_ctrl_clock_power_gating(sdev, true);
488}
489
490int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
491 const struct sof_ext_man_elem_header *hdr)
492{
493 const struct sof_ext_man_cavs_config_data *config_data =
494 container_of(hdr, struct sof_ext_man_cavs_config_data, hdr);
495 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
496 int i, elem_num;
497
498 /* calculate total number of config data elements */
499 elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header))
500 / sizeof(struct sof_config_elem);
501 if (elem_num <= 0) {
502 dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num);
503 return -EINVAL;
504 }
505
506 for (i = 0; i < elem_num; i++)
507 switch (config_data->elems[i].token) {
508 case SOF_EXT_MAN_CAVS_CONFIG_EMPTY:
509 /* skip empty token */
510 break;
511 case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO:
512 hda->clk_config_lpro = config_data->elems[i].value;
513 dev_dbg(sdev->dev, "FW clock config: %s\n",
514 hda->clk_config_lpro ? "LPRO" : "HPRO");
515 break;
516 case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE:
517 case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE:
518 /* These elements are defined but not being used yet. No warn is required */
519 break;
520 default:
521 dev_info(sdev->dev, "unsupported token type: %d\n",
522 config_data->elems[i].token);
523 }
524
525 return 0;
526}