1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // Copyright 2021-2022 NXP
5 // Author: Peng Zhang <peng.zhang_8@nxp.com>
7 // Hardware interface for audio DSP on i.MX8ULP
9 #include <linux/arm-smccc.h>
10 #include <linux/clk.h>
11 #include <linux/firmware.h>
12 #include <linux/firmware/imx/dsp.h>
13 #include <linux/firmware/imx/ipc.h>
14 #include <linux/firmware/imx/svc/misc.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/module.h>
17 #include <linux/of_address.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_platform.h>
20 #include <linux/of_reserved_mem.h>
22 #include <sound/sof.h>
23 #include <sound/sof/xtensa.h>
26 #include "../sof-of-dev.h"
27 #include "imx-common.h"
29 #define FSL_SIP_HIFI_XRDC 0xc200000e
31 /* SIM Domain register */
33 #define EXECUTE_BIT BIT(13)
34 #define RESET_BIT BIT(16)
35 #define HIFI4_CLK_BIT BIT(17)
36 #define PB_CLK_BIT BIT(18)
37 #define PLAT_CLK_BIT BIT(19)
38 #define DEBUG_LOGIC_BIT BIT(25)
40 #define MBOX_OFFSET 0x800000
41 #define MBOX_SIZE 0x1000
45 struct snd_sof_dev
*sdev
;
48 struct imx_dsp_ipc
*dsp_ipc
;
49 struct platform_device
*ipc_dev
;
51 struct regmap
*regmap
;
52 struct clk_bulk_data
*clks
;
56 static void imx8ulp_sim_lpav_start(struct imx8ulp_priv
*priv
)
58 /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */
59 regmap_update_bits(priv
->regmap
, SYSCTRL0
, RESET_BIT
, 0);
61 /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/
62 regmap_update_bits(priv
->regmap
, SYSCTRL0
, DEBUG_LOGIC_BIT
, 0);
64 /* Stall HIFI4 DSP Execution: 1 stall, 0 run */
65 regmap_update_bits(priv
->regmap
, SYSCTRL0
, EXECUTE_BIT
, 0);
68 static int imx8ulp_get_mailbox_offset(struct snd_sof_dev
*sdev
)
73 static int imx8ulp_get_window_offset(struct snd_sof_dev
*sdev
, u32 id
)
78 static void imx8ulp_dsp_handle_reply(struct imx_dsp_ipc
*ipc
)
80 struct imx8ulp_priv
*priv
= imx_dsp_get_data(ipc
);
83 spin_lock_irqsave(&priv
->sdev
->ipc_lock
, flags
);
85 snd_sof_ipc_process_reply(priv
->sdev
, 0);
87 spin_unlock_irqrestore(&priv
->sdev
->ipc_lock
, flags
);
90 static void imx8ulp_dsp_handle_request(struct imx_dsp_ipc
*ipc
)
92 struct imx8ulp_priv
*priv
= imx_dsp_get_data(ipc
);
93 u32 p
; /* panic code */
95 /* Read the message from the debug box. */
96 sof_mailbox_read(priv
->sdev
, priv
->sdev
->debug_box
.offset
+ 4, &p
, sizeof(p
));
98 /* Check to see if the message is a panic code (0x0dead***) */
99 if ((p
& SOF_IPC_PANIC_MAGIC_MASK
) == SOF_IPC_PANIC_MAGIC
)
100 snd_sof_dsp_panic(priv
->sdev
, p
, true);
102 snd_sof_ipc_msgs_rx(priv
->sdev
);
105 static struct imx_dsp_ops dsp_ops
= {
106 .handle_reply
= imx8ulp_dsp_handle_reply
,
107 .handle_request
= imx8ulp_dsp_handle_request
,
110 static int imx8ulp_send_msg(struct snd_sof_dev
*sdev
, struct snd_sof_ipc_msg
*msg
)
112 struct imx8ulp_priv
*priv
= sdev
->pdata
->hw_pdata
;
114 sof_mailbox_write(sdev
, sdev
->host_box
.offset
, msg
->msg_data
,
116 imx_dsp_ring_doorbell(priv
->dsp_ipc
, 0);
121 static int imx8ulp_run(struct snd_sof_dev
*sdev
)
123 struct imx8ulp_priv
*priv
= sdev
->pdata
->hw_pdata
;
125 imx8ulp_sim_lpav_start(priv
);
130 static int imx8ulp_reset(struct snd_sof_dev
*sdev
)
132 struct imx8ulp_priv
*priv
= sdev
->pdata
->hw_pdata
;
133 struct arm_smccc_res smc_resource
;
135 /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */
136 regmap_update_bits(priv
->regmap
, SYSCTRL0
, PLAT_CLK_BIT
, PLAT_CLK_BIT
);
138 /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */
139 regmap_update_bits(priv
->regmap
, SYSCTRL0
, PB_CLK_BIT
, PB_CLK_BIT
);
141 /* HiFi4 Clock Enable: 1 enabled, 0 disabled */
142 regmap_update_bits(priv
->regmap
, SYSCTRL0
, HIFI4_CLK_BIT
, HIFI4_CLK_BIT
);
144 regmap_update_bits(priv
->regmap
, SYSCTRL0
, RESET_BIT
, RESET_BIT
);
147 /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */
148 regmap_update_bits(priv
->regmap
, SYSCTRL0
, EXECUTE_BIT
, EXECUTE_BIT
);
151 arm_smccc_smc(FSL_SIP_HIFI_XRDC
, 0, 0, 0, 0, 0, 0, 0, &smc_resource
);
156 static int imx8ulp_probe(struct snd_sof_dev
*sdev
)
158 struct platform_device
*pdev
=
159 container_of(sdev
->dev
, struct platform_device
, dev
);
160 struct device_node
*np
= pdev
->dev
.of_node
;
161 struct device_node
*res_node
;
162 struct resource
*mmio
;
163 struct imx8ulp_priv
*priv
;
168 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
173 sdev
->pdata
->hw_pdata
= priv
;
174 priv
->dev
= sdev
->dev
;
177 /* System integration module(SIM) control dsp configuration */
178 priv
->regmap
= syscon_regmap_lookup_by_phandle(np
, "fsl,dsp-ctrl");
179 if (IS_ERR(priv
->regmap
))
180 return PTR_ERR(priv
->regmap
);
182 priv
->ipc_dev
= platform_device_register_data(sdev
->dev
, "imx-dsp",
184 pdev
, sizeof(*pdev
));
185 if (IS_ERR(priv
->ipc_dev
))
186 return PTR_ERR(priv
->ipc_dev
);
188 priv
->dsp_ipc
= dev_get_drvdata(&priv
->ipc_dev
->dev
);
189 if (!priv
->dsp_ipc
) {
190 /* DSP IPC driver not probed yet, try later */
192 dev_err(sdev
->dev
, "Failed to get drvdata\n");
193 goto exit_pdev_unregister
;
196 imx_dsp_set_data(priv
->dsp_ipc
, priv
);
197 priv
->dsp_ipc
->ops
= &dsp_ops
;
200 mmio
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
203 size
= resource_size(mmio
);
205 dev_err(sdev
->dev
, "error: failed to get DSP base at idx 0\n");
207 goto exit_pdev_unregister
;
210 sdev
->bar
[SOF_FW_BLK_TYPE_IRAM
] = devm_ioremap(sdev
->dev
, base
, size
);
211 if (!sdev
->bar
[SOF_FW_BLK_TYPE_IRAM
]) {
212 dev_err(sdev
->dev
, "failed to ioremap base 0x%x size 0x%x\n",
215 goto exit_pdev_unregister
;
217 sdev
->mmio_bar
= SOF_FW_BLK_TYPE_IRAM
;
219 res_node
= of_parse_phandle(np
, "memory-reserved", 0);
221 dev_err(&pdev
->dev
, "failed to get memory region node\n");
223 goto exit_pdev_unregister
;
226 ret
= of_address_to_resource(res_node
, 0, &res
);
227 of_node_put(res_node
);
229 dev_err(&pdev
->dev
, "failed to get reserved region address\n");
230 goto exit_pdev_unregister
;
233 sdev
->bar
[SOF_FW_BLK_TYPE_SRAM
] = devm_ioremap_wc(sdev
->dev
, res
.start
,
234 resource_size(&res
));
235 if (!sdev
->bar
[SOF_FW_BLK_TYPE_SRAM
]) {
236 dev_err(sdev
->dev
, "failed to ioremap mem 0x%x size 0x%x\n",
239 goto exit_pdev_unregister
;
241 sdev
->mailbox_bar
= SOF_FW_BLK_TYPE_SRAM
;
243 /* set default mailbox offset for FW ready message */
244 sdev
->dsp_box
.offset
= MBOX_OFFSET
;
246 ret
= of_reserved_mem_device_init(sdev
->dev
);
248 dev_err(&pdev
->dev
, "failed to init reserved memory region %d\n", ret
);
249 goto exit_pdev_unregister
;
252 ret
= devm_clk_bulk_get_all(sdev
->dev
, &priv
->clks
);
254 dev_err(sdev
->dev
, "failed to fetch clocks: %d\n", ret
);
255 goto exit_pdev_unregister
;
259 ret
= clk_bulk_prepare_enable(priv
->clk_num
, priv
->clks
);
261 dev_err(sdev
->dev
, "failed to enable clocks: %d\n", ret
);
262 goto exit_pdev_unregister
;
267 exit_pdev_unregister
:
268 platform_device_unregister(priv
->ipc_dev
);
273 static void imx8ulp_remove(struct snd_sof_dev
*sdev
)
275 struct imx8ulp_priv
*priv
= sdev
->pdata
->hw_pdata
;
277 clk_bulk_disable_unprepare(priv
->clk_num
, priv
->clks
);
278 platform_device_unregister(priv
->ipc_dev
);
281 /* on i.MX8 there is 1 to 1 match between type and BAR idx */
282 static int imx8ulp_get_bar_index(struct snd_sof_dev
*sdev
, u32 type
)
287 static int imx8ulp_suspend(struct snd_sof_dev
*sdev
)
290 struct imx8ulp_priv
*priv
= (struct imx8ulp_priv
*)sdev
->pdata
->hw_pdata
;
292 /*Stall DSP, release in .run() */
293 regmap_update_bits(priv
->regmap
, SYSCTRL0
, EXECUTE_BIT
, EXECUTE_BIT
);
295 for (i
= 0; i
< DSP_MU_CHAN_NUM
; i
++)
296 imx_dsp_free_channel(priv
->dsp_ipc
, i
);
298 clk_bulk_disable_unprepare(priv
->clk_num
, priv
->clks
);
303 static int imx8ulp_resume(struct snd_sof_dev
*sdev
)
305 struct imx8ulp_priv
*priv
= (struct imx8ulp_priv
*)sdev
->pdata
->hw_pdata
;
308 ret
= clk_bulk_prepare_enable(priv
->clk_num
, priv
->clks
);
310 dev_err(sdev
->dev
, "failed to enable clocks: %d\n", ret
);
314 for (i
= 0; i
< DSP_MU_CHAN_NUM
; i
++)
315 imx_dsp_request_channel(priv
->dsp_ipc
, i
);
320 static int imx8ulp_dsp_runtime_resume(struct snd_sof_dev
*sdev
)
322 const struct sof_dsp_power_state target_dsp_state
= {
323 .state
= SOF_DSP_PM_D0
,
327 imx8ulp_resume(sdev
);
329 return snd_sof_dsp_set_power_state(sdev
, &target_dsp_state
);
332 static int imx8ulp_dsp_runtime_suspend(struct snd_sof_dev
*sdev
)
334 const struct sof_dsp_power_state target_dsp_state
= {
335 .state
= SOF_DSP_PM_D3
,
339 imx8ulp_suspend(sdev
);
341 return snd_sof_dsp_set_power_state(sdev
, &target_dsp_state
);
344 static int imx8ulp_dsp_suspend(struct snd_sof_dev
*sdev
, unsigned int target_state
)
346 const struct sof_dsp_power_state target_dsp_state
= {
347 .state
= target_state
,
351 if (!pm_runtime_suspended(sdev
->dev
))
352 imx8ulp_suspend(sdev
);
354 return snd_sof_dsp_set_power_state(sdev
, &target_dsp_state
);
357 static int imx8ulp_dsp_resume(struct snd_sof_dev
*sdev
)
359 const struct sof_dsp_power_state target_dsp_state
= {
360 .state
= SOF_DSP_PM_D0
,
364 imx8ulp_resume(sdev
);
366 if (pm_runtime_suspended(sdev
->dev
)) {
367 pm_runtime_disable(sdev
->dev
);
368 pm_runtime_set_active(sdev
->dev
);
369 pm_runtime_mark_last_busy(sdev
->dev
);
370 pm_runtime_enable(sdev
->dev
);
371 pm_runtime_idle(sdev
->dev
);
374 return snd_sof_dsp_set_power_state(sdev
, &target_dsp_state
);
377 static struct snd_soc_dai_driver imx8ulp_dai
[] = {
402 static int imx8ulp_dsp_set_power_state(struct snd_sof_dev
*sdev
,
403 const struct sof_dsp_power_state
*target_state
)
405 sdev
->dsp_power_state
= *target_state
;
411 static const struct snd_sof_dsp_ops sof_imx8ulp_ops
= {
412 /* probe and remove */
413 .probe
= imx8ulp_probe
,
414 .remove
= imx8ulp_remove
,
417 .reset
= imx8ulp_reset
,
420 .block_read
= sof_block_read
,
421 .block_write
= sof_block_write
,
424 .read64
= sof_io_read64
,
427 .mailbox_read
= sof_mailbox_read
,
428 .mailbox_write
= sof_mailbox_write
,
431 .send_msg
= imx8ulp_send_msg
,
432 .get_mailbox_offset
= imx8ulp_get_mailbox_offset
,
433 .get_window_offset
= imx8ulp_get_window_offset
,
435 .ipc_msg_data
= sof_ipc_msg_data
,
436 .set_stream_data_offset
= sof_set_stream_data_offset
,
438 /* stream callbacks */
439 .pcm_open
= sof_stream_pcm_open
,
440 .pcm_close
= sof_stream_pcm_close
,
443 .get_bar_index
= imx8ulp_get_bar_index
,
444 /* firmware loading */
445 .load_firmware
= snd_sof_load_firmware_memcpy
,
447 /* Debug information */
448 .dbg_dump
= imx8_dump
,
451 .dsp_arch_ops
= &sof_xtensa_arch_ops
,
455 .num_drv
= ARRAY_SIZE(imx8ulp_dai
),
457 /* ALSA HW info flags */
458 .hw_info
= SNDRV_PCM_INFO_MMAP
|
459 SNDRV_PCM_INFO_MMAP_VALID
|
460 SNDRV_PCM_INFO_INTERLEAVED
|
461 SNDRV_PCM_INFO_PAUSE
|
462 SNDRV_PCM_INFO_BATCH
|
463 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
,
466 .runtime_suspend
= imx8ulp_dsp_runtime_suspend
,
467 .runtime_resume
= imx8ulp_dsp_runtime_resume
,
469 .suspend
= imx8ulp_dsp_suspend
,
470 .resume
= imx8ulp_dsp_resume
,
472 .set_power_state
= imx8ulp_dsp_set_power_state
,
475 static struct snd_sof_of_mach sof_imx8ulp_machs
[] = {
477 .compatible
= "fsl,imx8ulp-evk",
478 .sof_tplg_filename
= "sof-imx8ulp-btsco.tplg",
479 .drv_name
= "asoc-audio-graph-card2",
484 static struct sof_dev_desc sof_of_imx8ulp_desc
= {
485 .of_machines
= sof_imx8ulp_machs
,
486 .ipc_supported_mask
= BIT(SOF_IPC_TYPE_3
),
487 .ipc_default
= SOF_IPC_TYPE_3
,
489 [SOF_IPC_TYPE_3
] = "imx/sof",
491 .default_tplg_path
= {
492 [SOF_IPC_TYPE_3
] = "imx/sof-tplg",
494 .default_fw_filename
= {
495 [SOF_IPC_TYPE_3
] = "sof-imx8ulp.ri",
497 .nocodec_tplg_filename
= "sof-imx8ulp-nocodec.tplg",
498 .ops
= &sof_imx8ulp_ops
,
501 static const struct of_device_id sof_of_imx8ulp_ids
[] = {
502 { .compatible
= "fsl,imx8ulp-dsp", .data
= &sof_of_imx8ulp_desc
},
505 MODULE_DEVICE_TABLE(of
, sof_of_imx8ulp_ids
);
507 /* DT driver definition */
508 static struct platform_driver snd_sof_of_imx8ulp_driver
= {
509 .probe
= sof_of_probe
,
510 .remove
= sof_of_remove
,
512 .name
= "sof-audio-of-imx8ulp",
514 .of_match_table
= sof_of_imx8ulp_ids
,
517 module_platform_driver(snd_sof_of_imx8ulp_driver
);
519 MODULE_LICENSE("Dual BSD/GPL");
520 MODULE_DESCRIPTION("SOF support for IMX8ULP platforms");
521 MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");