0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bits.h>
0010 #include <linux/firmware.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_irq.h>
0015 #include <linux/regmap.h>
0016
0017 #include <linux/module.h>
0018 #include <sound/sof.h>
0019 #include <sound/sof/xtensa.h>
0020 #include <linux/firmware/imx/dsp.h>
0021
0022 #include "../ops.h"
0023 #include "../sof-of-dev.h"
0024 #include "imx-common.h"
0025
0026 #define MBOX_OFFSET 0x800000
0027 #define MBOX_SIZE 0x1000
0028
0029 static struct clk_bulk_data imx8m_dsp_clks[] = {
0030 { .id = "ipg" },
0031 { .id = "ocram" },
0032 { .id = "core" },
0033 };
0034
0035
0036 #define IMX8M_DAP_DEBUG 0x28800000
0037 #define IMX8M_DAP_DEBUG_SIZE (64 * 1024)
0038 #define IMX8M_DAP_PWRCTL (0x4000 + 0x3020)
0039 #define IMX8M_PWRCTL_CORERESET BIT(16)
0040
0041
0042 #define AudioDSP_REG0 0x100
0043 #define AudioDSP_REG1 0x104
0044 #define AudioDSP_REG2 0x108
0045 #define AudioDSP_REG3 0x10c
0046
0047 #define AudioDSP_REG2_RUNSTALL BIT(5)
0048
0049 struct imx8m_priv {
0050 struct device *dev;
0051 struct snd_sof_dev *sdev;
0052
0053
0054 struct imx_dsp_ipc *dsp_ipc;
0055 struct platform_device *ipc_dev;
0056
0057 struct imx_clocks *clks;
0058
0059 void __iomem *dap;
0060 struct regmap *regmap;
0061 };
0062
0063 static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev)
0064 {
0065 return MBOX_OFFSET;
0066 }
0067
0068 static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id)
0069 {
0070 return MBOX_OFFSET;
0071 }
0072
0073 static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc)
0074 {
0075 struct imx8m_priv *priv = imx_dsp_get_data(ipc);
0076 unsigned long flags;
0077
0078 spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
0079 snd_sof_ipc_process_reply(priv->sdev, 0);
0080 spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
0081 }
0082
0083 static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc)
0084 {
0085 struct imx8m_priv *priv = imx_dsp_get_data(ipc);
0086 u32 p;
0087
0088
0089 sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
0090
0091
0092 if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
0093 snd_sof_dsp_panic(priv->sdev, p, true);
0094 else
0095 snd_sof_ipc_msgs_rx(priv->sdev);
0096 }
0097
0098 static struct imx_dsp_ops imx8m_dsp_ops = {
0099 .handle_reply = imx8m_dsp_handle_reply,
0100 .handle_request = imx8m_dsp_handle_request,
0101 };
0102
0103 static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
0104 {
0105 struct imx8m_priv *priv = sdev->pdata->hw_pdata;
0106
0107 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
0108 msg->msg_size);
0109 imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
0110
0111 return 0;
0112 }
0113
0114
0115
0116
0117 static int imx8m_run(struct snd_sof_dev *sdev)
0118 {
0119 struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
0120
0121 regmap_update_bits(priv->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0);
0122
0123 return 0;
0124 }
0125
0126 static int imx8m_reset(struct snd_sof_dev *sdev)
0127 {
0128 struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
0129 u32 pwrctl;
0130
0131
0132 pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
0133 pwrctl |= IMX8M_PWRCTL_CORERESET;
0134 writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
0135
0136
0137 usleep_range(1, 2);
0138
0139 regmap_update_bits(priv->regmap, AudioDSP_REG2,
0140 AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL);
0141
0142
0143 pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
0144 pwrctl &= ~IMX8M_PWRCTL_CORERESET;
0145 writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
0146
0147 return 0;
0148 }
0149
0150 static int imx8m_probe(struct snd_sof_dev *sdev)
0151 {
0152 struct platform_device *pdev =
0153 container_of(sdev->dev, struct platform_device, dev);
0154 struct device_node *np = pdev->dev.of_node;
0155 struct device_node *res_node;
0156 struct resource *mmio;
0157 struct imx8m_priv *priv;
0158 struct resource res;
0159 u32 base, size;
0160 int ret = 0;
0161
0162 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0163 if (!priv)
0164 return -ENOMEM;
0165
0166 priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
0167 if (!priv->clks)
0168 return -ENOMEM;
0169
0170 sdev->num_cores = 1;
0171 sdev->pdata->hw_pdata = priv;
0172 priv->dev = sdev->dev;
0173 priv->sdev = sdev;
0174
0175 priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
0176 PLATFORM_DEVID_NONE,
0177 pdev, sizeof(*pdev));
0178 if (IS_ERR(priv->ipc_dev))
0179 return PTR_ERR(priv->ipc_dev);
0180
0181 priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
0182 if (!priv->dsp_ipc) {
0183
0184 ret = -EPROBE_DEFER;
0185 dev_err(sdev->dev, "Failed to get drvdata\n");
0186 goto exit_pdev_unregister;
0187 }
0188
0189 imx_dsp_set_data(priv->dsp_ipc, priv);
0190 priv->dsp_ipc->ops = &imx8m_dsp_ops;
0191
0192
0193 mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0194 if (mmio) {
0195 base = mmio->start;
0196 size = resource_size(mmio);
0197 } else {
0198 dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
0199 ret = -EINVAL;
0200 goto exit_pdev_unregister;
0201 }
0202
0203 priv->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE);
0204 if (!priv->dap) {
0205 dev_err(sdev->dev, "error: failed to map DAP debug memory area");
0206 ret = -ENODEV;
0207 goto exit_pdev_unregister;
0208 }
0209
0210 sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
0211 if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
0212 dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
0213 base, size);
0214 ret = -ENODEV;
0215 goto exit_pdev_unregister;
0216 }
0217 sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
0218
0219 res_node = of_parse_phandle(np, "memory-region", 0);
0220 if (!res_node) {
0221 dev_err(&pdev->dev, "failed to get memory region node\n");
0222 ret = -ENODEV;
0223 goto exit_pdev_unregister;
0224 }
0225
0226 ret = of_address_to_resource(res_node, 0, &res);
0227 of_node_put(res_node);
0228 if (ret) {
0229 dev_err(&pdev->dev, "failed to get reserved region address\n");
0230 goto exit_pdev_unregister;
0231 }
0232
0233 sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
0234 resource_size(&res));
0235 if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
0236 dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
0237 base, size);
0238 ret = -ENOMEM;
0239 goto exit_pdev_unregister;
0240 }
0241 sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
0242
0243
0244 sdev->dsp_box.offset = MBOX_OFFSET;
0245
0246 priv->regmap = syscon_regmap_lookup_by_compatible("fsl,dsp-ctrl");
0247 if (IS_ERR(priv->regmap)) {
0248 dev_err(sdev->dev, "cannot find dsp-ctrl registers");
0249 ret = PTR_ERR(priv->regmap);
0250 goto exit_pdev_unregister;
0251 }
0252
0253
0254 priv->clks->dsp_clks = imx8m_dsp_clks;
0255 priv->clks->num_dsp_clks = ARRAY_SIZE(imx8m_dsp_clks);
0256
0257 ret = imx8_parse_clocks(sdev, priv->clks);
0258 if (ret < 0)
0259 goto exit_pdev_unregister;
0260
0261 ret = imx8_enable_clocks(sdev, priv->clks);
0262 if (ret < 0)
0263 goto exit_pdev_unregister;
0264
0265 return 0;
0266
0267 exit_pdev_unregister:
0268 platform_device_unregister(priv->ipc_dev);
0269 return ret;
0270 }
0271
0272 static int imx8m_remove(struct snd_sof_dev *sdev)
0273 {
0274 struct imx8m_priv *priv = sdev->pdata->hw_pdata;
0275
0276 imx8_disable_clocks(sdev, priv->clks);
0277 platform_device_unregister(priv->ipc_dev);
0278
0279 return 0;
0280 }
0281
0282
0283 static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type)
0284 {
0285
0286 switch (type) {
0287 case SOF_FW_BLK_TYPE_IRAM:
0288 case SOF_FW_BLK_TYPE_SRAM:
0289 return type;
0290 default:
0291 return -EINVAL;
0292 }
0293 }
0294
0295 static struct snd_soc_dai_driver imx8m_dai[] = {
0296 {
0297 .name = "sai1",
0298 .playback = {
0299 .channels_min = 1,
0300 .channels_max = 32,
0301 },
0302 .capture = {
0303 .channels_min = 1,
0304 .channels_max = 32,
0305 },
0306 },
0307 {
0308 .name = "sai3",
0309 .playback = {
0310 .channels_min = 1,
0311 .channels_max = 32,
0312 },
0313 .capture = {
0314 .channels_min = 1,
0315 .channels_max = 32,
0316 },
0317 },
0318 };
0319
0320 static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev,
0321 const struct sof_dsp_power_state *target_state)
0322 {
0323 sdev->dsp_power_state = *target_state;
0324
0325 return 0;
0326 }
0327
0328 static int imx8m_resume(struct snd_sof_dev *sdev)
0329 {
0330 struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
0331 int ret;
0332 int i;
0333
0334 ret = imx8_enable_clocks(sdev, priv->clks);
0335 if (ret < 0)
0336 return ret;
0337
0338 for (i = 0; i < DSP_MU_CHAN_NUM; i++)
0339 imx_dsp_request_channel(priv->dsp_ipc, i);
0340
0341 return 0;
0342 }
0343
0344 static void imx8m_suspend(struct snd_sof_dev *sdev)
0345 {
0346 struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
0347 int i;
0348
0349 for (i = 0; i < DSP_MU_CHAN_NUM; i++)
0350 imx_dsp_free_channel(priv->dsp_ipc, i);
0351
0352 imx8_disable_clocks(sdev, priv->clks);
0353 }
0354
0355 static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev)
0356 {
0357 int ret;
0358 const struct sof_dsp_power_state target_dsp_state = {
0359 .state = SOF_DSP_PM_D0,
0360 };
0361
0362 ret = imx8m_resume(sdev);
0363 if (ret < 0)
0364 return ret;
0365
0366 return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
0367 }
0368
0369 static int imx8m_dsp_runtime_suspend(struct snd_sof_dev *sdev)
0370 {
0371 const struct sof_dsp_power_state target_dsp_state = {
0372 .state = SOF_DSP_PM_D3,
0373 };
0374
0375 imx8m_suspend(sdev);
0376
0377 return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
0378 }
0379
0380 static int imx8m_dsp_resume(struct snd_sof_dev *sdev)
0381 {
0382 int ret;
0383 const struct sof_dsp_power_state target_dsp_state = {
0384 .state = SOF_DSP_PM_D0,
0385 };
0386
0387 ret = imx8m_resume(sdev);
0388 if (ret < 0)
0389 return ret;
0390
0391 if (pm_runtime_suspended(sdev->dev)) {
0392 pm_runtime_disable(sdev->dev);
0393 pm_runtime_set_active(sdev->dev);
0394 pm_runtime_mark_last_busy(sdev->dev);
0395 pm_runtime_enable(sdev->dev);
0396 pm_runtime_idle(sdev->dev);
0397 }
0398
0399 return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
0400 }
0401
0402 static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
0403 {
0404 const struct sof_dsp_power_state target_dsp_state = {
0405 .state = target_state,
0406 };
0407
0408 if (!pm_runtime_suspended(sdev->dev))
0409 imx8m_suspend(sdev);
0410
0411 return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
0412 }
0413
0414
0415 static struct snd_sof_dsp_ops sof_imx8m_ops = {
0416
0417 .probe = imx8m_probe,
0418 .remove = imx8m_remove,
0419
0420 .run = imx8m_run,
0421 .reset = imx8m_reset,
0422
0423
0424 .block_read = sof_block_read,
0425 .block_write = sof_block_write,
0426
0427
0428 .mailbox_read = sof_mailbox_read,
0429 .mailbox_write = sof_mailbox_write,
0430
0431
0432 .send_msg = imx8m_send_msg,
0433 .get_mailbox_offset = imx8m_get_mailbox_offset,
0434 .get_window_offset = imx8m_get_window_offset,
0435
0436 .ipc_msg_data = sof_ipc_msg_data,
0437 .set_stream_data_offset = sof_set_stream_data_offset,
0438
0439 .get_bar_index = imx8m_get_bar_index,
0440
0441
0442 .load_firmware = snd_sof_load_firmware_memcpy,
0443
0444
0445 .dbg_dump = imx8_dump,
0446 .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
0447
0448
0449 .pcm_open = sof_stream_pcm_open,
0450 .pcm_close = sof_stream_pcm_close,
0451
0452 .dsp_arch_ops = &sof_xtensa_arch_ops,
0453
0454
0455 .drv = imx8m_dai,
0456 .num_drv = ARRAY_SIZE(imx8m_dai),
0457
0458 .suspend = imx8m_dsp_suspend,
0459 .resume = imx8m_dsp_resume,
0460
0461 .runtime_suspend = imx8m_dsp_runtime_suspend,
0462 .runtime_resume = imx8m_dsp_runtime_resume,
0463
0464 .set_power_state = imx8m_dsp_set_power_state,
0465
0466 .hw_info = SNDRV_PCM_INFO_MMAP |
0467 SNDRV_PCM_INFO_MMAP_VALID |
0468 SNDRV_PCM_INFO_INTERLEAVED |
0469 SNDRV_PCM_INFO_PAUSE |
0470 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
0471 };
0472
0473 static struct sof_dev_desc sof_of_imx8mp_desc = {
0474 .ipc_supported_mask = BIT(SOF_IPC),
0475 .ipc_default = SOF_IPC,
0476 .default_fw_path = {
0477 [SOF_IPC] = "imx/sof",
0478 },
0479 .default_tplg_path = {
0480 [SOF_IPC] = "imx/sof-tplg",
0481 },
0482 .default_fw_filename = {
0483 [SOF_IPC] = "sof-imx8m.ri",
0484 },
0485 .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
0486 .ops = &sof_imx8m_ops,
0487 };
0488
0489 static const struct of_device_id sof_of_imx8m_ids[] = {
0490 { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
0491 { }
0492 };
0493 MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids);
0494
0495
0496 static struct platform_driver snd_sof_of_imx8m_driver = {
0497 .probe = sof_of_probe,
0498 .remove = sof_of_remove,
0499 .driver = {
0500 .name = "sof-audio-of-imx8m",
0501 .pm = &sof_of_pm,
0502 .of_match_table = sof_of_imx8m_ids,
0503 },
0504 };
0505 module_platform_driver(snd_sof_of_imx8m_driver);
0506
0507 MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
0508 MODULE_LICENSE("Dual BSD/GPL");