From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Fri, 7 Jul 2017 08:40:49 +0530 Subject: [PATCH] Add support for CNL FPGA This includes IMR allocation Change-Id: If53609cd8626c5ab94a418b48b241f6a8572f5fb Signed-off-by: Guneshwor Singh --- sound/soc/intel/Kconfig | 7 +++ sound/soc/intel/common/sst-dsp-priv.h | 1 + sound/soc/intel/skylake/cnl-sst.c | 76 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 0caa1f4eb94d..221283d83619 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -123,7 +123,14 @@ config SND_SOC_ACPI_INTEL_MATCH # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. +config SND_SOC_INTEL_CNL_FPGA + tristate "Enable CNL FPGA board settings" + help + Select Y if you are using FPGA. + If unsure select "N". + endif ## SND_SOC_INTEL_SST_TOPLEVEL + # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 363145716a6d..acf06a4f5144 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -322,6 +322,7 @@ struct sst_dsp { u32 intr_status; const struct firmware *fw; struct snd_dma_buffer dmab; + struct snd_dma_buffer dsp_fw_buf; }; /* Size optimised DRAM/IRAM memcpy */ diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index 7b429c0fb4e5..27884c176dc6 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" @@ -52,11 +53,69 @@ #define CNL_ADSP_FW_HDR_OFFSET 0x2000 #define CNL_ROM_CTRL_DMA_ID 0x9 +#define CNL_IMR_MEMSIZE 0x400000 /*4MB*/ +#define HDA_ADSP_REG_ADSPCS_IMR_CACHED_TLB_START 0x100 +#define HDA_ADSP_REG_ADSPCS_IMR_UNCACHED_TLB_START 0x200 +#define HDA_ADSP_REG_ADSPCS_IMR_SIZE 0x8 + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val)), addr); + writel(((u32) (val >> 32)), addr + 4); +} +#endif + +/* Needed for presilicon platform based on FPGA */ +static int cnl_fpga_alloc_imr(struct sst_dsp *ctx) +{ + u32 pages; + u32 fw_size = CNL_IMR_MEMSIZE; + int ret; + + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, &ctx->dsp_fw_buf, fw_size); + + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); + return ret; + } + + pages = (fw_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + dev_dbg(ctx->dev, "sst_cnl_fpga_alloc_imr pages=0x%x\n", pages); + set_memory_uc((unsigned long)ctx->dsp_fw_buf.area, pages); + + writeq(virt_to_phys(ctx->dsp_fw_buf.area) + 1, + ctx->addr.shim + HDA_ADSP_REG_ADSPCS_IMR_CACHED_TLB_START); + writeq(virt_to_phys(ctx->dsp_fw_buf.area) + 1, + ctx->addr.shim + HDA_ADSP_REG_ADSPCS_IMR_UNCACHED_TLB_START); + + writel(CNL_IMR_MEMSIZE, ctx->addr.shim + + HDA_ADSP_REG_ADSPCS_IMR_CACHED_TLB_START + + HDA_ADSP_REG_ADSPCS_IMR_SIZE); + writel(CNL_IMR_MEMSIZE, ctx->addr.shim + + HDA_ADSP_REG_ADSPCS_IMR_UNCACHED_TLB_START + + HDA_ADSP_REG_ADSPCS_IMR_SIZE); + + memset(ctx->dsp_fw_buf.area, 0, fw_size); + + return 0; +} + +static inline void cnl_fpga_free_imr(struct sst_dsp *ctx) +{ + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->dsp_fw_buf); +} + static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) { int ret, stream_tag; + ret = cnl_fpga_alloc_imr(ctx); + if (ret < 0) + return ret; + stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); if (stream_tag <= 0) { dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag); @@ -78,6 +137,21 @@ static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) goto base_fw_load_failed; } + + for (ret = CNL_BASEFW_TIMEOUT; + ret > 0 && IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL_FPGA); --ret) { + u32 reg = sst_dsp_shim_read(ctx, CNL_ADSP_REG_HIPCIDA); + + if (reg & CNL_ADSP_REG_HIPCIDA_DONE) { + sst_dsp_shim_update_bits_forced(ctx, + CNL_ADSP_REG_HIPCIDA, + CNL_ADSP_REG_HIPCIDA_DONE, + CNL_ADSP_REG_HIPCIDA_DONE); + break; + } + + mdelay(1); + } /* enable interrupt */ cnl_ipc_int_enable(ctx); cnl_ipc_op_int_enable(ctx); @@ -95,6 +169,7 @@ static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) base_fw_load_failed: ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); + cnl_fpga_free_imr(ctx); return ret; } @@ -491,6 +566,7 @@ void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) cnl_ipc_free(&ctx->ipc); ctx->dsp->ops->free(ctx->dsp); + cnl_fpga_free_imr(ctx->dsp); } EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); -- https://clearlinux.org