xref: /linux/sound/soc/sof/imx/imx8.c (revision 45e02edd8422b6c4a511f38403dbd805cd139733)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // Copyright 2019-2025 NXP
4 //
5 // Author: Daniel Baluta <daniel.baluta@nxp.com>
6 //
7 // Hardware interface for audio DSP on i.MX8
8 
9 #include <linux/firmware/imx/svc/misc.h>
10 #include <dt-bindings/firmware/imx/rsrc.h>
11 #include "imx-common.h"
12 
13 #define RESET_VECTOR_VADDR	0x596f8000
14 
15 /*
16  * DSP control.
17  */
18 static int imx8x_run(struct snd_sof_dev *sdev)
19 {
20 	int ret;
21 
22 	ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
23 				      IMX_SC_C_OFS_SEL, 1);
24 	if (ret < 0) {
25 		dev_err(sdev->dev, "Error system address offset source select\n");
26 		return ret;
27 	}
28 
29 	ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
30 				      IMX_SC_C_OFS_AUDIO, 0x80);
31 	if (ret < 0) {
32 		dev_err(sdev->dev, "Error system address offset of AUDIO\n");
33 		return ret;
34 	}
35 
36 	ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
37 				      IMX_SC_C_OFS_PERIPH, 0x5A);
38 	if (ret < 0) {
39 		dev_err(sdev->dev, "Error system address offset of PERIPH %d\n",
40 			ret);
41 		return ret;
42 	}
43 
44 	ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
45 				      IMX_SC_C_OFS_IRQ, 0x51);
46 	if (ret < 0) {
47 		dev_err(sdev->dev, "Error system address offset of IRQ\n");
48 		return ret;
49 	}
50 
51 	imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
52 			    RESET_VECTOR_VADDR);
53 
54 	return 0;
55 }
56 
57 static int imx8_run(struct snd_sof_dev *sdev)
58 {
59 	int ret;
60 
61 	ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
62 				      IMX_SC_C_OFS_SEL, 0);
63 	if (ret < 0) {
64 		dev_err(sdev->dev, "Error system address offset source select\n");
65 		return ret;
66 	}
67 
68 	imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
69 			    RESET_VECTOR_VADDR);
70 
71 	return 0;
72 }
73 
74 static int imx8_probe(struct snd_sof_dev *sdev)
75 {
76 	struct imx_sc_ipc *sc_ipc_handle;
77 	struct imx_common_data *common;
78 	int ret;
79 
80 	common = sdev->pdata->hw_pdata;
81 
82 	ret = imx_scu_get_handle(&sc_ipc_handle);
83 	if (ret < 0)
84 		return dev_err_probe(sdev->dev, ret,
85 				     "failed to fetch SC IPC handle\n");
86 
87 	common->chip_pdata = sc_ipc_handle;
88 
89 	return 0;
90 }
91 
92 static struct snd_soc_dai_driver imx8_dai[] = {
93 	IMX_SOF_DAI_DRV_ENTRY_BIDIR("esai0", 1, 8),
94 	IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32),
95 };
96 
97 static struct snd_sof_dsp_ops sof_imx8_ops;
98 
99 static int imx8_ops_init(struct snd_sof_dev *sdev)
100 {
101 	/* first copy from template */
102 	memcpy(&sof_imx8_ops, &sof_imx_ops, sizeof(sof_imx_ops));
103 
104 	/* then set common imx8 ops */
105 	sof_imx8_ops.dbg_dump = imx8_dump;
106 	sof_imx8_ops.dsp_arch_ops = &sof_xtensa_arch_ops;
107 	sof_imx8_ops.debugfs_add_region_item =
108 		snd_sof_debugfs_add_region_item_iomem;
109 
110 	/* ... and finally set DAI driver */
111 	sof_imx8_ops.drv = get_chip_info(sdev)->drv;
112 	sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv;
113 
114 	return 0;
115 }
116 
117 static const struct imx_chip_ops imx8_chip_ops = {
118 	.probe = imx8_probe,
119 	.core_kick = imx8_run,
120 };
121 
122 static const struct imx_chip_ops imx8x_chip_ops = {
123 	.probe = imx8_probe,
124 	.core_kick = imx8x_run,
125 };
126 
127 static struct imx_memory_info imx8_memory_regions[] = {
128 	{ .name = "iram", .reserved = false },
129 	{ .name = "sram", .reserved = true },
130 	{ }
131 };
132 
133 static const struct imx_chip_info imx8_chip_info = {
134 	.ipc_info = {
135 		.has_panic_code = true,
136 		.boot_mbox_offset = 0x800000,
137 		.window_offset = 0x800000,
138 	},
139 	.memory = imx8_memory_regions,
140 	.drv = imx8_dai,
141 	.num_drv = ARRAY_SIZE(imx8_dai),
142 	.ops = &imx8_chip_ops,
143 };
144 
145 static const struct imx_chip_info imx8x_chip_info = {
146 	.ipc_info = {
147 		.has_panic_code = true,
148 		.boot_mbox_offset = 0x800000,
149 		.window_offset = 0x800000,
150 	},
151 	.memory = imx8_memory_regions,
152 	.drv = imx8_dai,
153 	.num_drv = ARRAY_SIZE(imx8_dai),
154 	.ops = &imx8x_chip_ops,
155 };
156 
157 static struct snd_sof_of_mach sof_imx8_machs[] = {
158 	{
159 		.compatible = "fsl,imx8qxp-mek",
160 		.sof_tplg_filename = "sof-imx8-wm8960.tplg",
161 		.drv_name = "asoc-audio-graph-card2",
162 	},
163 	{
164 		.compatible = "fsl,imx8qxp-mek-wcpu",
165 		.sof_tplg_filename = "sof-imx8-wm8962.tplg",
166 		.drv_name = "asoc-audio-graph-card2",
167 	},
168 	{
169 		.compatible = "fsl,imx8qm-mek",
170 		.sof_tplg_filename = "sof-imx8-wm8960.tplg",
171 		.drv_name = "asoc-audio-graph-card2",
172 	},
173 	{
174 		.compatible = "fsl,imx8qm-mek-revd",
175 		.sof_tplg_filename = "sof-imx8-wm8962.tplg",
176 		.drv_name = "asoc-audio-graph-card2",
177 	},
178 	{
179 		.compatible = "fsl,imx8qxp-mek-bb",
180 		.sof_tplg_filename = "sof-imx8-cs42888.tplg",
181 		.drv_name = "asoc-audio-graph-card2",
182 	},
183 	{
184 		.compatible = "fsl,imx8qm-mek-bb",
185 		.sof_tplg_filename = "sof-imx8-cs42888.tplg",
186 		.drv_name = "asoc-audio-graph-card2",
187 	},
188 
189 	{}
190 };
191 
192 IMX_SOF_DEV_DESC(imx8, sof_imx8_machs, &imx8_chip_info, &sof_imx8_ops, imx8_ops_init);
193 IMX_SOF_DEV_DESC(imx8x, sof_imx8_machs, &imx8x_chip_info, &sof_imx8_ops, imx8_ops_init);
194 
195 static const struct of_device_id sof_of_imx8_ids[] = {
196 	{
197 		.compatible = "fsl,imx8qxp-dsp",
198 		.data = &IMX_SOF_DEV_DESC_NAME(imx8x),
199 	},
200 	{
201 		.compatible = "fsl,imx8qm-dsp",
202 		.data = &IMX_SOF_DEV_DESC_NAME(imx8),
203 	},
204 	{ }
205 };
206 MODULE_DEVICE_TABLE(of, sof_of_imx8_ids);
207 
208 /* DT driver definition */
209 static struct platform_driver snd_sof_of_imx8_driver = {
210 	.probe = sof_of_probe,
211 	.remove = sof_of_remove,
212 	.driver = {
213 		.name = "sof-audio-of-imx8",
214 		.pm = &sof_of_pm,
215 		.of_match_table = sof_of_imx8_ids,
216 	},
217 };
218 module_platform_driver(snd_sof_of_imx8_driver);
219 
220 MODULE_LICENSE("Dual BSD/GPL");
221 MODULE_DESCRIPTION("SOF support for IMX8 platforms");
222 MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
223