summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@nxp.com>2019-09-04 14:09:28 +0300
committerZhang Peng <peng_zhang_8@nxp.com>2020-02-13 19:26:37 +0800
commitd9e26ed3a504763db970a9af2891d5ebda1d53f5 (patch)
tree7b4a0cc62391e257e7e0ac20285153ee2ca37d53
parenta504bca19c74341d0f4576fc76c7ab65c6bc1038 (diff)
MLK-23255-3: ASoC: fsl_dsp: Add support i.MX8MP
1. Introduce new board type and compatible string in preparation for i.MX8MP board. 2. Add support configure and start DSP for i.MX8MP. 3. Add clocks for i.MX8MP, and do special process when suspend and resume because dsp haven't independent power. 4. Add special handle for i.MX8MP, because in imx8mp there is audiomix power domains, and only one power domain. Signed-off-by: Zhang Peng <peng_zhang_8@nxp.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
-rw-r--r--sound/soc/fsl/fsl_dsp.c184
-rw-r--r--sound/soc/fsl/fsl_dsp.h7
2 files changed, 164 insertions, 27 deletions
diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c
index 2818c56634f0..64e9b4f7b3e6 100644
--- a/sound/soc/fsl/fsl_dsp.c
+++ b/sound/soc/fsl/fsl_dsp.c
@@ -638,9 +638,18 @@ void *memcpy_dsp(void *dest, const void *src, size_t count)
static void fsl_dsp_start(struct fsl_dsp *dsp_priv)
{
- imx_sc_pm_cpu_start(dsp_priv->dsp_ipcHandle,
- IMX_SC_R_DSP, true, dsp_priv->iram);
-
+ switch (dsp_priv->dsp_board_type){
+ case DSP_IMX8QM_TYPE:
+ case DSP_IMX8QXP_TYPE:
+ imx_sc_pm_cpu_start(dsp_priv->dsp_ipcHandle,
+ IMX_SC_R_DSP, true, dsp_priv->iram);
+ break;
+ case DSP_IMX8MP_TYPE:
+ imx_audiomix_dsp_start(dsp_priv->audiomix);
+ break;
+ default:
+ break;
+ }
}
static void dsp_load_firmware(const struct firmware *fw, void *context)
@@ -780,15 +789,39 @@ static const struct snd_soc_component_driver dsp_soc_platform_drv = {
.compr_ops = &dsp_platform_compr_ops,
};
+
+int fsl_dsp_configure_audmix(struct fsl_dsp *dsp_priv) {
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = of_find_node_by_name(NULL, "audiomix_dsp");
+ if (!np)
+ return -EPROBE_DEFER;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ return -EPROBE_DEFER;
+
+ dsp_priv->audiomix = dev_get_drvdata(&pdev->dev);
+ if (!dsp_priv->audiomix)
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
int fsl_dsp_configure_scu(struct fsl_dsp *dsp_priv)
{
int ret;
+ /* there is no SCU on i.MX8MP */
+ if (dsp_priv->dsp_board_type == DSP_IMX8MP_TYPE)
+ return 0;
+
ret = imx_scu_get_handle(&dsp_priv->dsp_ipcHandle);
if (ret) {
dev_err(dsp_priv->dev, "Cannot get scu handle %d\n", ret);
return ret;
- };
+ }
if (dsp_priv->dsp_board_type == DSP_IMX8QXP_TYPE) {
ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP,
@@ -831,6 +864,19 @@ int fsl_dsp_configure_scu(struct fsl_dsp *dsp_priv)
return 0;
}
+int fsl_dsp_configure(struct fsl_dsp *dsp_priv)
+{
+ switch (dsp_priv->dsp_board_type) {
+ case DSP_IMX8QM_TYPE:
+ case DSP_IMX8QXP_TYPE:
+ return fsl_dsp_configure_scu(dsp_priv);
+ case DSP_IMX8MP_TYPE:
+ return fsl_dsp_configure_audmix(dsp_priv);
+ default:
+ return -ENODEV;
+ }
+}
+
static int fsl_dsp_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -853,8 +899,10 @@ static int fsl_dsp_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,imx8qxp-dsp-v1"))
dsp_priv->dsp_board_type = DSP_IMX8QXP_TYPE;
- else
+ else if (of_device_is_compatible(np, "fsl,imx8qm-dsp-v1"))
dsp_priv->dsp_board_type = DSP_IMX8QM_TYPE;
+ else
+ dsp_priv->dsp_board_type = DSP_IMX8MP_TYPE;
dsp_priv->dev = &pdev->dev;
@@ -874,23 +922,25 @@ static int fsl_dsp_probe(struct platform_device *pdev)
num_domains = of_count_phandle_with_args(np, "power-domains",
"#power-domain-cells");
- for (i = 0; i < num_domains; i++) {
- struct device *pd_dev;
- struct device_link *link;
-
- pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
- if (IS_ERR(pd_dev))
- return PTR_ERR(pd_dev);
-
- link = device_link_add(&pdev->dev, pd_dev,
- DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (IS_ERR(link))
- return PTR_ERR(link);
+ if (num_domains > 1) {
+ for (i = 0; i < num_domains; i++) {
+ struct device *pd_dev;
+ struct device_link *link;
+
+ pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(pd_dev))
+ return PTR_ERR(pd_dev);
+
+ link = device_link_add(&pdev->dev, pd_dev,
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(link))
+ return PTR_ERR(link);
+ }
}
- ret = fsl_dsp_configure_scu(dsp_priv);
+ ret = fsl_dsp_configure(dsp_priv);
if (ret < 0)
return ret;
@@ -1017,6 +1067,22 @@ static int fsl_dsp_probe(struct platform_device *pdev)
dsp_priv->asrck_clk[i] = NULL;
}
+ dsp_priv->dsp_ocrama_clk = devm_clk_get(&pdev->dev, "ocram");
+ if (IS_ERR(dsp_priv->dsp_ocrama_clk))
+ dsp_priv->dsp_ocrama_clk = NULL;
+
+ dsp_priv->dsp_root_clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(dsp_priv->dsp_root_clk))
+ dsp_priv->dsp_root_clk = NULL;
+
+ dsp_priv->debug_clk = devm_clk_get(&pdev->dev, "debug");
+ if (IS_ERR(dsp_priv->debug_clk))
+ dsp_priv->debug_clk = NULL;
+
+ dsp_priv->mu2_clk = devm_clk_get(&pdev->dev, "mu2");
+ if (IS_ERR(dsp_priv->mu2_clk))
+ dsp_priv->mu2_clk = NULL;
+
return 0;
}
@@ -1047,27 +1113,57 @@ static int fsl_dsp_runtime_resume(struct device *dev)
ret = clk_prepare_enable(dsp_priv->esai_ipg_clk);
if (ret) {
dev_err(dev, "failed to enable esai ipg clock: %d\n", ret);
- return ret;
+ goto esai_ipg_clk;
}
ret = clk_prepare_enable(dsp_priv->esai_mclk);
if (ret) {
dev_err(dev, "failed to enable esai mclk: %d\n", ret);
- return ret;
+ goto esai_mclk;
}
ret = clk_prepare_enable(dsp_priv->asrc_mem_clk);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to enable asrc_mem_clk ret = %d\n", ret);
+ goto asrc_mem_clk;
+ }
ret = clk_prepare_enable(dsp_priv->asrc_ipg_clk);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to enable asrc_ipg_clk ret = %d\n", ret);
+ goto asrc_ipg_clk;
+ }
for (i = 0; i < 4; i++) {
ret = clk_prepare_enable(dsp_priv->asrck_clk[i]);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "failed to prepare arc clk %d\n", i);
+ goto asrck_clk;
+ }
+ }
+
+ ret = clk_prepare_enable(dsp_priv->dsp_ocrama_clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable dsp_ocrama_clk ret = %d\n", ret);
+ goto ocrama_clk;
+ }
+
+ ret = clk_prepare_enable(dsp_priv->dsp_root_clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable dsp_root_clk ret = %d\n", ret);
+ goto dsp_root_clk;
+ }
+
+ ret = clk_prepare_enable(dsp_priv->debug_clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable debug_clk ret = %d\n", ret);
+ goto debug_clk;
+ }
+
+ ret = clk_prepare_enable(dsp_priv->mu2_clk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable mu2_clk ret = %d\n", ret);
+ goto mu2_clk;
}
if (!dsp_priv->dsp_mu_init) {
@@ -1097,6 +1193,26 @@ static int fsl_dsp_runtime_resume(struct device *dev)
}
return 0;
+
+mu2_clk:
+ clk_disable_unprepare(dsp_priv->debug_clk);
+debug_clk:
+ clk_disable_unprepare(dsp_priv->dsp_root_clk);
+dsp_root_clk:
+ clk_disable_unprepare(dsp_priv->dsp_ocrama_clk);
+ocrama_clk:
+ for (i = 0; i < 4; i++)
+ clk_disable_unprepare(dsp_priv->asrck_clk[i]);
+asrck_clk:
+ clk_disable_unprepare(dsp_priv->asrc_ipg_clk);
+asrc_ipg_clk:
+ clk_disable_unprepare(dsp_priv->asrc_mem_clk);
+asrc_mem_clk:
+ clk_disable_unprepare(dsp_priv->esai_mclk);
+esai_mclk:
+ clk_disable_unprepare(dsp_priv->esai_ipg_clk);
+esai_ipg_clk:
+ return ret;
}
static int fsl_dsp_runtime_suspend(struct device *dev)
@@ -1105,8 +1221,16 @@ static int fsl_dsp_runtime_suspend(struct device *dev)
struct xf_proxy *proxy = &dsp_priv->proxy;
int i;
- dsp_priv->dsp_mu_init = 0;
- proxy->is_ready = 0;
+ /*
+ * FIXME:
+ * DSP in i.MX865 don't have dedicate power control
+ * which bind with audiomix. if the audiomix power
+ * on, we can't reload the firmware.
+ */
+ if (dsp_priv->dsp_board_type != DSP_IMX8MP_TYPE) {
+ dsp_priv->dsp_mu_init = 0;
+ proxy->is_ready = 0;
+ }
for (i = 0; i < 4; i++)
clk_disable_unprepare(dsp_priv->asrck_clk[i]);
@@ -1117,6 +1241,11 @@ static int fsl_dsp_runtime_suspend(struct device *dev)
clk_disable_unprepare(dsp_priv->esai_mclk);
clk_disable_unprepare(dsp_priv->esai_ipg_clk);
+ clk_disable_unprepare(dsp_priv->dsp_ocrama_clk);
+ clk_disable_unprepare(dsp_priv->dsp_root_clk);
+ clk_disable_unprepare(dsp_priv->debug_clk);
+ clk_disable_unprepare(dsp_priv->mu2_clk);
+
return 0;
}
#endif /* CONFIG_PM */
@@ -1173,6 +1302,7 @@ static const struct dev_pm_ops fsl_dsp_pm = {
static const struct of_device_id fsl_dsp_ids[] = {
{ .compatible = "fsl,imx8qxp-dsp-v1", },
{ .compatible = "fsl,imx8qm-dsp-v1", },
+ { .compatible = "fsl,imx8mp-dsp-v1", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_dsp_ids);
diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h
index a66b083124ae..c731cd9a0e94 100644
--- a/sound/soc/fsl/fsl_dsp.h
+++ b/sound/soc/fsl/fsl_dsp.h
@@ -11,6 +11,7 @@
#include <linux/firmware/imx/ipc.h>
#include "fsl_dsp_proxy.h"
#include "fsl_dsp_platform.h"
+#include "fsl_dsp_audiomix.h"
#define FSL_DSP_COMP_NAME "fsl-dsp-component"
@@ -24,6 +25,7 @@ typedef void (*memset_func) (void *s, int c, size_t n);
enum {
DSP_IMX8QXP_TYPE = 0,
DSP_IMX8QM_TYPE,
+ DSP_IMX8MP_TYPE,
};
/* ...proxy client data */
@@ -71,6 +73,7 @@ struct fsl_dsp {
void __iomem *regs;
void __iomem *mu_base_virtaddr;
struct imx_sc_ipc *dsp_ipcHandle;
+ struct imx_audiomix_dsp_data *audiomix;
unsigned int dsp_mu_id;
int dsp_mu_init;
atomic_long_t refcnt;
@@ -110,6 +113,10 @@ struct fsl_dsp {
struct clk *asrc_mem_clk;
struct clk *asrc_ipg_clk;
struct clk *asrck_clk[4];
+ struct clk *dsp_ocrama_clk;
+ struct clk *dsp_root_clk;
+ struct clk *debug_clk;
+ struct clk *mu2_clk;
};
#define IRAM_OFFSET 0x10000