1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
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.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
12 * Hardware interface for audio DSP on Broadwell
15 #include <linux/module.h>
16 #include <sound/sof.h>
17 #include <sound/sof/xtensa.h>
20 #include "../sof-audio.h"
30 /* DSP memories for BDW */
31 #define IRAM_OFFSET 0xA0000
32 #define BDW_IRAM_SIZE (10 * 32 * 1024)
33 #define DRAM_OFFSET 0x00000
34 #define BDW_DRAM_SIZE (20 * 32 * 1024)
35 #define SHIM_OFFSET 0xFB000
36 #define SHIM_SIZE 0x100
37 #define MBOX_OFFSET 0x9E000
38 #define MBOX_SIZE 0x1000
39 #define MBOX_DUMP_SIZE 0x30
40 #define EXCEPT_OFFSET 0x800
41 #define EXCEPT_MAX_HDR_SIZE 0x400
44 #define DMAC0_OFFSET 0xFE000
45 #define DMAC1_OFFSET 0xFF000
46 #define DMAC_SIZE 0x420
47 #define SSP0_OFFSET 0xFC000
48 #define SSP1_OFFSET 0xFD000
49 #define SSP_SIZE 0x100
51 #define BDW_STACK_DUMP_SIZE 32
53 #define BDW_PANIC_OFFSET(x) ((x) & 0xFFFF)
55 static const struct snd_sof_debugfs_map bdw_debugfs
[] = {
56 {"dmac0", BDW_DSP_BAR
, DMAC0_OFFSET
, DMAC_SIZE
,
57 SOF_DEBUGFS_ACCESS_ALWAYS
},
58 {"dmac1", BDW_DSP_BAR
, DMAC1_OFFSET
, DMAC_SIZE
,
59 SOF_DEBUGFS_ACCESS_ALWAYS
},
60 {"ssp0", BDW_DSP_BAR
, SSP0_OFFSET
, SSP_SIZE
,
61 SOF_DEBUGFS_ACCESS_ALWAYS
},
62 {"ssp1", BDW_DSP_BAR
, SSP1_OFFSET
, SSP_SIZE
,
63 SOF_DEBUGFS_ACCESS_ALWAYS
},
64 {"iram", BDW_DSP_BAR
, IRAM_OFFSET
, BDW_IRAM_SIZE
,
65 SOF_DEBUGFS_ACCESS_D0_ONLY
},
66 {"dram", BDW_DSP_BAR
, DRAM_OFFSET
, BDW_DRAM_SIZE
,
67 SOF_DEBUGFS_ACCESS_D0_ONLY
},
68 {"shim", BDW_DSP_BAR
, SHIM_OFFSET
, SHIM_SIZE
,
69 SOF_DEBUGFS_ACCESS_ALWAYS
},
72 static void bdw_host_done(struct snd_sof_dev
*sdev
);
73 static void bdw_dsp_done(struct snd_sof_dev
*sdev
);
74 static void bdw_get_reply(struct snd_sof_dev
*sdev
);
80 static int bdw_run(struct snd_sof_dev
*sdev
)
82 /* set opportunistic mode on engine 0,1 for all channels */
83 snd_sof_dsp_update_bits(sdev
, BDW_DSP_BAR
, SHIM_HMDC
,
84 SHIM_HMDC_HDDA_E0_ALLCH
|
85 SHIM_HMDC_HDDA_E1_ALLCH
, 0);
88 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CSR
,
91 /* return init core mask */
95 static int bdw_reset(struct snd_sof_dev
*sdev
)
97 /* put DSP into reset and stall */
98 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CSR
,
99 SHIM_CSR_RST
| SHIM_CSR_STALL
,
100 SHIM_CSR_RST
| SHIM_CSR_STALL
);
102 /* keep in reset for 10ms */
105 /* take DSP out of reset and keep stalled for FW loading */
106 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CSR
,
107 SHIM_CSR_RST
| SHIM_CSR_STALL
,
113 static int bdw_set_dsp_D0(struct snd_sof_dev
*sdev
)
118 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
119 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_VDRTCTL2
,
121 PCI_VDRTCL2_DTCGE
, 0);
123 /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
124 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_VDRTCTL0
,
125 PCI_VDRTCL0_D3PGD
, PCI_VDRTCL0_D3PGD
);
128 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_PMCS
,
129 PCI_PMCS_PS_MASK
, 0);
131 /* check that ADSP shim is enabled */
133 reg
= readl(sdev
->bar
[BDW_PCI_BAR
] + PCI_PMCS
)
145 * select SSP1 19.2MHz base clock, SSP clock 0,
146 * turn off Low Power Clock
148 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CSR
,
149 SHIM_CSR_S1IOCS
| SHIM_CSR_SBCS1
|
152 /* stall DSP core, set clk to 192/96Mhz */
153 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
,
154 SHIM_CSR
, SHIM_CSR_STALL
|
159 /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
160 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CLKCTL
,
168 /* Stall and reset core, set CSR */
171 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
172 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_VDRTCTL2
,
178 usleep_range(50, 55);
180 /* switch on audio PLL */
181 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_VDRTCTL2
,
182 PCI_VDRTCL2_APLLSE_MASK
, 0);
185 * set default power gating control, enable power gating control for
186 * all blocks. that is, can't be accessed, please enable each block
189 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_PCI_BAR
, PCI_VDRTCTL0
,
192 /* disable DMA finish function for SSP0 & SSP1 */
193 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_CSR2
,
195 SHIM_CSR2_SDFD_SSP1
);
197 /* set on-demond mode on engine 0,1 for all channels */
198 snd_sof_dsp_update_bits(sdev
, BDW_DSP_BAR
, SHIM_HMDC
,
199 SHIM_HMDC_HDDA_E0_ALLCH
|
200 SHIM_HMDC_HDDA_E1_ALLCH
,
201 SHIM_HMDC_HDDA_E0_ALLCH
|
202 SHIM_HMDC_HDDA_E1_ALLCH
);
204 /* Enable Interrupt from both sides */
205 snd_sof_dsp_update_bits(sdev
, BDW_DSP_BAR
, SHIM_IMRX
,
206 (SHIM_IMRX_BUSY
| SHIM_IMRX_DONE
), 0x0);
207 snd_sof_dsp_update_bits(sdev
, BDW_DSP_BAR
, SHIM_IMRD
,
208 (SHIM_IMRD_DONE
| SHIM_IMRD_BUSY
|
209 SHIM_IMRD_SSP0
| SHIM_IMRD_DMAC
), 0x0);
211 /* clear IPC registers */
212 snd_sof_dsp_write(sdev
, BDW_DSP_BAR
, SHIM_IPCX
, 0x0);
213 snd_sof_dsp_write(sdev
, BDW_DSP_BAR
, SHIM_IPCD
, 0x0);
214 snd_sof_dsp_write(sdev
, BDW_DSP_BAR
, 0x80, 0x6);
215 snd_sof_dsp_write(sdev
, BDW_DSP_BAR
, 0xe0, 0x300a);
220 static void bdw_get_registers(struct snd_sof_dev
*sdev
,
221 struct sof_ipc_dsp_oops_xtensa
*xoops
,
222 struct sof_ipc_panic_info
*panic_info
,
223 u32
*stack
, size_t stack_words
)
225 u32 offset
= sdev
->dsp_oops_offset
;
227 /* first read registers */
228 sof_mailbox_read(sdev
, offset
, xoops
, sizeof(*xoops
));
230 /* note: variable AR register array is not read */
232 /* then get panic info */
233 if (xoops
->arch_hdr
.totalsize
> EXCEPT_MAX_HDR_SIZE
) {
234 dev_err(sdev
->dev
, "invalid header size 0x%x. FW oops is bogus\n",
235 xoops
->arch_hdr
.totalsize
);
238 offset
+= xoops
->arch_hdr
.totalsize
;
239 sof_mailbox_read(sdev
, offset
, panic_info
, sizeof(*panic_info
));
241 /* then get the stack */
242 offset
+= sizeof(*panic_info
);
243 sof_mailbox_read(sdev
, offset
, stack
, stack_words
* sizeof(u32
));
246 static void bdw_dump(struct snd_sof_dev
*sdev
, u32 flags
)
248 struct sof_ipc_dsp_oops_xtensa xoops
;
249 struct sof_ipc_panic_info panic_info
;
250 u32 stack
[BDW_STACK_DUMP_SIZE
];
251 u32 status
, panic
, imrx
, imrd
;
253 /* now try generic SOF status messages */
254 status
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IPCD
);
255 panic
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IPCX
);
256 bdw_get_registers(sdev
, &xoops
, &panic_info
, stack
,
257 BDW_STACK_DUMP_SIZE
);
258 snd_sof_get_status(sdev
, status
, panic
, &xoops
, &panic_info
, stack
,
259 BDW_STACK_DUMP_SIZE
);
261 /* provide some context for firmware debug */
262 imrx
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IMRX
);
263 imrd
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IMRD
);
265 "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n",
266 (panic
& SHIM_IPCX_BUSY
) ? "yes" : "no",
267 (panic
& SHIM_IPCX_DONE
) ? "yes" : "no", panic
);
269 "error: mask host: pending %s complete %s raw 0x%8.8x\n",
270 (imrx
& SHIM_IMRX_BUSY
) ? "yes" : "no",
271 (imrx
& SHIM_IMRX_DONE
) ? "yes" : "no", imrx
);
273 "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n",
274 (status
& SHIM_IPCD_BUSY
) ? "yes" : "no",
275 (status
& SHIM_IPCD_DONE
) ? "yes" : "no", status
);
277 "error: mask DSP: pending %s complete %s raw 0x%8.8x\n",
278 (imrd
& SHIM_IMRD_BUSY
) ? "yes" : "no",
279 (imrd
& SHIM_IMRD_DONE
) ? "yes" : "no", imrd
);
283 * IPC Doorbell IRQ handler and thread.
286 static irqreturn_t
bdw_irq_handler(int irq
, void *context
)
288 struct snd_sof_dev
*sdev
= context
;
292 /* Interrupt arrived, check src */
293 isr
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_ISRX
);
294 if (isr
& (SHIM_ISRX_DONE
| SHIM_ISRX_BUSY
))
295 ret
= IRQ_WAKE_THREAD
;
300 static irqreturn_t
bdw_irq_thread(int irq
, void *context
)
302 struct snd_sof_dev
*sdev
= context
;
303 u32 ipcx
, ipcd
, imrx
;
305 imrx
= snd_sof_dsp_read64(sdev
, BDW_DSP_BAR
, SHIM_IMRX
);
306 ipcx
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IPCX
);
308 /* reply message from DSP */
309 if (ipcx
& SHIM_IPCX_DONE
&&
310 !(imrx
& SHIM_IMRX_DONE
)) {
311 /* Mask Done interrupt before return */
312 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
,
313 SHIM_IMRX
, SHIM_IMRX_DONE
,
316 spin_lock_irq(&sdev
->ipc_lock
);
319 * handle immediate reply from DSP core. If the msg is
320 * found, set done bit in cmd_done which is called at the
321 * end of message processing function, else set it here
322 * because the done bit can't be set in cmd_done function
323 * which is triggered by msg
326 snd_sof_ipc_reply(sdev
, ipcx
);
330 spin_unlock_irq(&sdev
->ipc_lock
);
333 ipcd
= snd_sof_dsp_read(sdev
, BDW_DSP_BAR
, SHIM_IPCD
);
335 /* new message from DSP */
336 if (ipcd
& SHIM_IPCD_BUSY
&&
337 !(imrx
& SHIM_IMRX_BUSY
)) {
338 /* Mask Busy interrupt before return */
339 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
,
340 SHIM_IMRX
, SHIM_IMRX_BUSY
,
343 /* Handle messages from DSP Core */
344 if ((ipcd
& SOF_IPC_PANIC_MAGIC_MASK
) == SOF_IPC_PANIC_MAGIC
) {
345 snd_sof_dsp_panic(sdev
, BDW_PANIC_OFFSET(ipcx
) +
348 snd_sof_ipc_msgs_rx(sdev
);
361 static int bdw_send_msg(struct snd_sof_dev
*sdev
, struct snd_sof_ipc_msg
*msg
)
363 /* send the message */
364 sof_mailbox_write(sdev
, sdev
->host_box
.offset
, msg
->msg_data
,
366 snd_sof_dsp_write(sdev
, BDW_DSP_BAR
, SHIM_IPCX
, SHIM_IPCX_BUSY
);
371 static void bdw_get_reply(struct snd_sof_dev
*sdev
)
373 struct snd_sof_ipc_msg
*msg
= sdev
->msg
;
374 struct sof_ipc_reply reply
;
378 * Sometimes, there is unexpected reply ipc arriving. The reply
379 * ipc belongs to none of the ipcs sent from driver.
380 * In this case, the driver must ignore the ipc.
383 dev_warn(sdev
->dev
, "unexpected ipc interrupt raised!\n");
388 sof_mailbox_read(sdev
, sdev
->host_box
.offset
, &reply
, sizeof(reply
));
390 if (reply
.error
< 0) {
391 memcpy(msg
->reply_data
, &reply
, sizeof(reply
));
394 /* reply correct size ? */
395 if (reply
.hdr
.size
!= msg
->reply_size
) {
396 dev_err(sdev
->dev
, "error: reply expected %zu got %u bytes\n",
397 msg
->reply_size
, reply
.hdr
.size
);
401 /* read the message */
402 if (msg
->reply_size
> 0)
403 sof_mailbox_read(sdev
, sdev
->host_box
.offset
,
404 msg
->reply_data
, msg
->reply_size
);
407 msg
->reply_error
= ret
;
410 static int bdw_get_mailbox_offset(struct snd_sof_dev
*sdev
)
415 static int bdw_get_window_offset(struct snd_sof_dev
*sdev
, u32 id
)
420 static void bdw_host_done(struct snd_sof_dev
*sdev
)
422 /* clear BUSY bit and set DONE bit - accept new messages */
423 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_IPCD
,
424 SHIM_IPCD_BUSY
| SHIM_IPCD_DONE
,
427 /* unmask busy interrupt */
428 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_IMRX
,
432 static void bdw_dsp_done(struct snd_sof_dev
*sdev
)
434 /* clear DONE bit - tell DSP we have completed */
435 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_IPCX
,
438 /* unmask Done interrupt */
439 snd_sof_dsp_update_bits_unlocked(sdev
, BDW_DSP_BAR
, SHIM_IMRX
,
446 static int bdw_probe(struct snd_sof_dev
*sdev
)
448 struct snd_sof_pdata
*pdata
= sdev
->pdata
;
449 const struct sof_dev_desc
*desc
= pdata
->desc
;
450 struct platform_device
*pdev
=
451 container_of(sdev
->dev
, struct platform_device
, dev
);
452 struct resource
*mmio
;
457 mmio
= platform_get_resource(pdev
, IORESOURCE_MEM
,
458 desc
->resindex_lpe_base
);
461 size
= resource_size(mmio
);
463 dev_err(sdev
->dev
, "error: failed to get LPE base at idx %d\n",
464 desc
->resindex_lpe_base
);
468 dev_dbg(sdev
->dev
, "LPE PHY base at 0x%x size 0x%x", base
, size
);
469 sdev
->bar
[BDW_DSP_BAR
] = devm_ioremap(sdev
->dev
, base
, size
);
470 if (!sdev
->bar
[BDW_DSP_BAR
]) {
472 "error: failed to ioremap LPE base 0x%x size 0x%x\n",
476 dev_dbg(sdev
->dev
, "LPE VADDR %p\n", sdev
->bar
[BDW_DSP_BAR
]);
478 /* TODO: add offsets */
479 sdev
->mmio_bar
= BDW_DSP_BAR
;
480 sdev
->mailbox_bar
= BDW_DSP_BAR
;
481 sdev
->dsp_oops_offset
= MBOX_OFFSET
;
484 mmio
= platform_get_resource(pdev
, IORESOURCE_MEM
,
485 desc
->resindex_pcicfg_base
);
488 size
= resource_size(mmio
);
490 dev_err(sdev
->dev
, "error: failed to get PCI base at idx %d\n",
491 desc
->resindex_pcicfg_base
);
495 dev_dbg(sdev
->dev
, "PCI base at 0x%x size 0x%x", base
, size
);
496 sdev
->bar
[BDW_PCI_BAR
] = devm_ioremap(sdev
->dev
, base
, size
);
497 if (!sdev
->bar
[BDW_PCI_BAR
]) {
499 "error: failed to ioremap PCI base 0x%x size 0x%x\n",
503 dev_dbg(sdev
->dev
, "PCI VADDR %p\n", sdev
->bar
[BDW_PCI_BAR
]);
505 /* register our IRQ */
506 sdev
->ipc_irq
= platform_get_irq(pdev
, desc
->irqindex_host_ipc
);
507 if (sdev
->ipc_irq
< 0)
508 return sdev
->ipc_irq
;
510 dev_dbg(sdev
->dev
, "using IRQ %d\n", sdev
->ipc_irq
);
511 ret
= devm_request_threaded_irq(sdev
->dev
, sdev
->ipc_irq
,
512 bdw_irq_handler
, bdw_irq_thread
,
513 IRQF_SHARED
, "AudioDSP", sdev
);
515 dev_err(sdev
->dev
, "error: failed to register IRQ %d\n",
520 /* enable the DSP SHIM */
521 ret
= bdw_set_dsp_D0(sdev
);
523 dev_err(sdev
->dev
, "error: failed to set DSP D0\n");
527 /* DSP DMA can only access low 31 bits of host memory */
528 ret
= dma_coerce_mask_and_coherent(sdev
->dev
, DMA_BIT_MASK(31));
530 dev_err(sdev
->dev
, "error: failed to set DMA mask %d\n", ret
);
534 /* set default mailbox */
535 snd_sof_dsp_mailbox_init(sdev
, MBOX_OFFSET
, MBOX_SIZE
, 0, 0);
540 static void bdw_machine_select(struct snd_sof_dev
*sdev
)
542 struct snd_sof_pdata
*sof_pdata
= sdev
->pdata
;
543 const struct sof_dev_desc
*desc
= sof_pdata
->desc
;
544 struct snd_soc_acpi_mach
*mach
;
546 mach
= snd_soc_acpi_find_machine(desc
->machines
);
548 dev_warn(sdev
->dev
, "warning: No matching ASoC machine driver found\n");
552 sof_pdata
->tplg_filename
= mach
->sof_tplg_filename
;
553 mach
->mach_params
.acpi_ipc_irq_index
= desc
->irqindex_host_ipc
;
554 sof_pdata
->machine
= mach
;
557 static void bdw_set_mach_params(const struct snd_soc_acpi_mach
*mach
,
560 struct snd_soc_acpi_mach_params
*mach_params
;
562 mach_params
= (struct snd_soc_acpi_mach_params
*)&mach
->mach_params
;
563 mach_params
->platform
= dev_name(dev
);
567 static struct snd_soc_dai_driver bdw_dai
[] = {
577 const struct snd_sof_dsp_ops sof_bdw_ops
= {
581 /* DSP Core Control */
586 .write
= sof_io_write
,
588 .write64
= sof_io_write64
,
589 .read64
= sof_io_read64
,
592 .block_read
= sof_block_read
,
593 .block_write
= sof_block_write
,
596 .send_msg
= bdw_send_msg
,
597 .fw_ready
= sof_fw_ready
,
598 .get_mailbox_offset
= bdw_get_mailbox_offset
,
599 .get_window_offset
= bdw_get_window_offset
,
601 .ipc_msg_data
= intel_ipc_msg_data
,
602 .ipc_pcm_params
= intel_ipc_pcm_params
,
605 .machine_select
= bdw_machine_select
,
606 .machine_register
= sof_machine_register
,
607 .machine_unregister
= sof_machine_unregister
,
608 .set_mach_params
= bdw_set_mach_params
,
611 .debug_map
= bdw_debugfs
,
612 .debug_map_count
= ARRAY_SIZE(bdw_debugfs
),
613 .dbg_dump
= bdw_dump
,
615 /* stream callbacks */
616 .pcm_open
= intel_pcm_open
,
617 .pcm_close
= intel_pcm_close
,
620 .load_module
= snd_sof_parse_module_memcpy
,
622 /*Firmware loading */
623 .load_firmware
= snd_sof_load_firmware_memcpy
,
627 .num_drv
= ARRAY_SIZE(bdw_dai
),
629 /* ALSA HW info flags */
630 .hw_info
= SNDRV_PCM_INFO_MMAP
|
631 SNDRV_PCM_INFO_MMAP_VALID
|
632 SNDRV_PCM_INFO_INTERLEAVED
|
633 SNDRV_PCM_INFO_PAUSE
|
634 SNDRV_PCM_INFO_BATCH
,
636 .arch_ops
= &sof_xtensa_arch_ops
,
638 EXPORT_SYMBOL_NS(sof_bdw_ops
, SND_SOC_SOF_BROADWELL
);
640 const struct sof_intel_dsp_desc bdw_chip_info
= {
644 EXPORT_SYMBOL_NS(bdw_chip_info
, SND_SOC_SOF_BROADWELL
);
646 MODULE_LICENSE("Dual BSD/GPL");
647 MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC
);
648 MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA
);