[alsa-devel] [PATCH 0/7] ASoC: Intel: Skylake: Add code loader DMA support
This series add code loader DMA support to Skylake driver and then adds the IPC init routines along with few smaller changes
Omair M Abdullah (1): ASoC: Intel: Skylake: Print error code in IPC for SKL
Subhransu S. Prusty (3): ASoC: Intel: Skylake: Add dsp loader ops ASoC: Intel: Skylake: Process code loader DMA interrupt ASoC: Intel: Skylake: Add SKL DSP initialization
Vinod Koul (3): ASoC: Intel: Skylake: Add code loader DMA registers ASoC: Intel: Skylake: add code loader DMA operations ASoC: Intel: Skylake: Add code loader DMA APIs
sound/soc/intel/common/sst-dsp-priv.h | 3 + sound/soc/intel/skylake/Makefile | 3 +- sound/soc/intel/skylake/skl-sst-cldma.c | 327 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-cldma.h | 251 ++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.c | 5 + sound/soc/intel/skylake/skl-sst-dsp.h | 26 +++ sound/soc/intel/skylake/skl-sst-ipc.c | 11 ++ sound/soc/intel/skylake/skl-sst.c | 280 +++++++++++++++++++++++++++ 8 files changed, 905 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.c create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.h create mode 100644 sound/soc/intel/skylake/skl-sst.c
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com
The ops is initialized during the dsp registration and used for the allocating dma buffers.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-sst-dsp.h | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index cdfca9be4120..c2d28781309a 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__
+#include <sound/memalloc.h> + struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -104,6 +106,13 @@ struct skl_dsp_fw_ops { int (*set_state_D3)(struct sst_dsp *ctx); };
+struct skl_dsp_loader_ops { + int (*alloc_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab, size_t size); + int (*free_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab); +}; + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq);
The patch
ASoC: Intel: Skylake: Add dsp loader ops
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From b662680252fa6e3bc53ad087078dd1fe7496449c Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Fri, 10 Jul 2015 22:18:39 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add dsp loader ops
The ops is initialized during the dsp registration and used for the allocating dma buffers.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-sst-dsp.h | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index cdfca9b..c2d2878 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__
+#include <sound/memalloc.h> + struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -104,6 +106,13 @@ struct skl_dsp_fw_ops { int (*set_state_D3)(struct sst_dsp *ctx); };
+struct skl_dsp_loader_ops { + int (*alloc_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab, size_t size); + int (*free_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab); +}; + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq);
Skylake has a DMA controller for loading DSP code and modules to memory. Add the register defines for this DMA
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-sst-cldma.h | 191 ++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.h
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h new file mode 100644 index 000000000000..34c366f050ee --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -0,0 +1,191 @@ +/* + * Intel Code Loader DMA support + * + * Copyright (C) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef SKL_SST_CLDMA_H_ +#define SKL_SST_CLDMA_H_ + +#define FW_CL_STREAM_NUMBER 0x1 + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +#define SKL_ADSPIC_CL_DMA 0x2 +#define SKL_ADSPIS_CL_DMA 0x2 +#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ +#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ + +/* Intel HD Audio Code Loader DMA Registers */ + +#define HDA_ADSP_LOADER_BASE 0x80 + +/* Stream Registers */ +#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) +#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) +#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) +#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) +#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) +#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) +#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) +#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) +#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) +#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) +#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) + +/* CL: Software Position Based FIFO Capability Registers */ +#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) +#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) +#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) + +/* CL: Stream Descriptor x Control */ + +/* Stream Reset */ +#define CL_SD_CTL_SRST_SHIFT 0 +#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) +#define CL_SD_CTL_SRST(x) \ + ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) + +/* Stream Run */ +#define CL_SD_CTL_RUN_SHIFT 1 +#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) +#define CL_SD_CTL_RUN(x) \ + ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) + +/* Interrupt On Completion Enable */ +#define CL_SD_CTL_IOCE_SHIFT 2 +#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) +#define CL_SD_CTL_IOCE(x) \ + ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) + +/* FIFO Error Interrupt Enable */ +#define CL_SD_CTL_FEIE_SHIFT 3 +#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) +#define CL_SD_CTL_FEIE(x) \ + ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) + +/* Descriptor Error Interrupt Enable */ +#define CL_SD_CTL_DEIE_SHIFT 4 +#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) +#define CL_SD_CTL_DEIE(x) \ + ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) + +/* FIFO Limit Change */ +#define CL_SD_CTL_FIFOLC_SHIFT 5 +#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) +#define CL_SD_CTL_FIFOLC(x) \ + ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) + +/* Stripe Control */ +#define CL_SD_CTL_STRIPE_SHIFT 16 +#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) +#define CL_SD_CTL_STRIPE(x) \ + ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) + +/* Traffic Priority */ +#define CL_SD_CTL_TP_SHIFT 18 +#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) +#define CL_SD_CTL_TP(x) \ + ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) + +/* Bidirectional Direction Control */ +#define CL_SD_CTL_DIR_SHIFT 19 +#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) +#define CL_SD_CTL_DIR(x) \ + ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) + +/* Stream Number */ +#define CL_SD_CTL_STRM_SHIFT 20 +#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) +#define CL_SD_CTL_STRM(x) \ + ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) + +/* CL: Stream Descriptor x Status */ + +/* Buffer Completion Interrupt Status */ +#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) + +/* FIFO Error */ +#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) + +/* Descriptor Error */ +#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) + +/* FIFO Ready */ +#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) + + +/* CL: Stream Descriptor x Last Valid Index */ +#define CL_SD_LVI_SHIFT 0 +#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) +#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) + +/* CL: Stream Descriptor x FIFO Eviction Watermark */ +#define CL_SD_FIFOW_SHIFT 0 +#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) +#define CL_SD_FIFOW(x) \ + ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) + +/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ + +/* Protect Bits */ +#define CL_SD_BDLPLBA_PROT_SHIFT 0 +#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) +#define CL_SD_BDLPLBA_PROT(x) \ + ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) + +/* Buffer Descriptor List Lower Base Address */ +#define CL_SD_BDLPLBA_SHIFT 7 +#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) +#define CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define CL_SD_BDLPUBA_SHIFT 0 +#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) +#define CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) + +/* + * Code Loader - Software Position Based FIFO + * Capability Registers x Software Position Based FIFO Header + */ + +/* Next Capability Pointer */ +#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 +#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) +#define CL_SPBFIFO_SPBFCH_PTR(x) \ + ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) + +/* Capability Identifier */ +#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 +#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) +#define CL_SPBFIFO_SPBFCH_ID(x) \ + ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) + +/* Capability Version */ +#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 +#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) +#define CL_SPBFIFO_SPBFCH_VER(x) \ + ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) + +/* Software Position in Buffer Enable */ +#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) +#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +#endif /* SKL_SST_CLDMA_H_ */
The patch
ASoC: Intel: Skylake: Add code loader DMA registers
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From e30903877fde33192b80100b7f63f2af97b2bd86 Mon Sep 17 00:00:00 2001
From: Vinod Koul vinod.koul@intel.com Date: Fri, 10 Jul 2015 22:18:40 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add code loader DMA registers
Skylake has a DMA controller for loading DSP code and modules to memory. Add the register defines for this DMA
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-sst-cldma.h | 191 ++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.h
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h new file mode 100644 index 0000000..34c366f --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -0,0 +1,191 @@ +/* + * Intel Code Loader DMA support + * + * Copyright (C) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef SKL_SST_CLDMA_H_ +#define SKL_SST_CLDMA_H_ + +#define FW_CL_STREAM_NUMBER 0x1 + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +#define SKL_ADSPIC_CL_DMA 0x2 +#define SKL_ADSPIS_CL_DMA 0x2 +#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ +#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ + +/* Intel HD Audio Code Loader DMA Registers */ + +#define HDA_ADSP_LOADER_BASE 0x80 + +/* Stream Registers */ +#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) +#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) +#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) +#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) +#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) +#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) +#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) +#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) +#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) +#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) +#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) + +/* CL: Software Position Based FIFO Capability Registers */ +#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) +#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) +#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) + +/* CL: Stream Descriptor x Control */ + +/* Stream Reset */ +#define CL_SD_CTL_SRST_SHIFT 0 +#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) +#define CL_SD_CTL_SRST(x) \ + ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) + +/* Stream Run */ +#define CL_SD_CTL_RUN_SHIFT 1 +#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) +#define CL_SD_CTL_RUN(x) \ + ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) + +/* Interrupt On Completion Enable */ +#define CL_SD_CTL_IOCE_SHIFT 2 +#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) +#define CL_SD_CTL_IOCE(x) \ + ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) + +/* FIFO Error Interrupt Enable */ +#define CL_SD_CTL_FEIE_SHIFT 3 +#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) +#define CL_SD_CTL_FEIE(x) \ + ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) + +/* Descriptor Error Interrupt Enable */ +#define CL_SD_CTL_DEIE_SHIFT 4 +#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) +#define CL_SD_CTL_DEIE(x) \ + ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) + +/* FIFO Limit Change */ +#define CL_SD_CTL_FIFOLC_SHIFT 5 +#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) +#define CL_SD_CTL_FIFOLC(x) \ + ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) + +/* Stripe Control */ +#define CL_SD_CTL_STRIPE_SHIFT 16 +#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) +#define CL_SD_CTL_STRIPE(x) \ + ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) + +/* Traffic Priority */ +#define CL_SD_CTL_TP_SHIFT 18 +#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) +#define CL_SD_CTL_TP(x) \ + ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) + +/* Bidirectional Direction Control */ +#define CL_SD_CTL_DIR_SHIFT 19 +#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) +#define CL_SD_CTL_DIR(x) \ + ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) + +/* Stream Number */ +#define CL_SD_CTL_STRM_SHIFT 20 +#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) +#define CL_SD_CTL_STRM(x) \ + ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) + +/* CL: Stream Descriptor x Status */ + +/* Buffer Completion Interrupt Status */ +#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) + +/* FIFO Error */ +#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) + +/* Descriptor Error */ +#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) + +/* FIFO Ready */ +#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) + + +/* CL: Stream Descriptor x Last Valid Index */ +#define CL_SD_LVI_SHIFT 0 +#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) +#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) + +/* CL: Stream Descriptor x FIFO Eviction Watermark */ +#define CL_SD_FIFOW_SHIFT 0 +#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) +#define CL_SD_FIFOW(x) \ + ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) + +/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ + +/* Protect Bits */ +#define CL_SD_BDLPLBA_PROT_SHIFT 0 +#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) +#define CL_SD_BDLPLBA_PROT(x) \ + ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) + +/* Buffer Descriptor List Lower Base Address */ +#define CL_SD_BDLPLBA_SHIFT 7 +#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) +#define CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define CL_SD_BDLPUBA_SHIFT 0 +#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) +#define CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) + +/* + * Code Loader - Software Position Based FIFO + * Capability Registers x Software Position Based FIFO Header + */ + +/* Next Capability Pointer */ +#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 +#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) +#define CL_SPBFIFO_SPBFCH_PTR(x) \ + ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) + +/* Capability Identifier */ +#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 +#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) +#define CL_SPBFIFO_SPBFCH_ID(x) \ + ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) + +/* Capability Version */ +#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 +#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) +#define CL_SPBFIFO_SPBFCH_VER(x) \ + ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) + +/* Software Position in Buffer Enable */ +#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) +#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +#endif /* SKL_SST_CLDMA_H_ */
This patch starts adding code loader DMA handling internal operations for setting up bdle, controller, spb, cleanup routines and buffer filling
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-sst-cldma.c | 194 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-cldma.h | 60 ++++++++++ 2 files changed, 254 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.c
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c new file mode 100644 index 000000000000..44019eef6114 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -0,0 +1,194 @@ +/* + * skl-sst-cldma.c - Code Loader DMA handler + * + * Copyright (C) 2015, Intel Corporation. + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/device.h> +#include <linux/mm.h> +#include <linux/kthread.h> +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static void skl_cldma_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); +} + +void skl_cldma_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); +} + +/* Code loader helper APIs */ +static void skl_cldma_setup_bdle(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + + ctx->cl_dev.frags = 0; + while (size > 0) { + phys_addr_t addr = virt_to_phys(dmab_data->area + + (ctx->cl_dev.frags * ctx->cl_dev.bufsize)); + + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + + bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize); + + size -= ctx->cl_dev.bufsize; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + + bdl += 4; + ctx->cl_dev.frags++; + } +} + +/* + * Setup controller + * Configure the registers to update the dma buffer address and + * enable interrupts. + * Note: Using the channel 1 for transfer + */ +static void skl_cldma_setup_controller(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, unsigned int max_size, + u32 count) +{ + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, + CL_SD_BDLPLBA(dmab_bdl->addr)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, + CL_SD_BDLPUBA(dmab_bdl->addr)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); +} + +static void skl_cldma_setup_spb(struct sst_dsp *ctx, + unsigned int size, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); + else + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); +} + +static void skl_cldma_cleanup(struct sst_dsp *ctx) +{ + skl_cldma_cleanup_spb(ctx); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + +static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +{ + int ret = 0; + + if (!wait_event_timeout(ctx->cl_dev.wait_queue, + ctx->cl_dev.wait_condition, + msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { + dev_err(ctx->dev, "%s: Wait timeout\n", __func__); + ret = -EIO; + goto cleanup; + } + + dev_dbg(ctx->dev, "%s: Event wake\n", __func__); + if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { + dev_err(ctx->dev, "%s: DMA Error\n", __func__); + ret = -EIO; + } + +cleanup: + ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; + return ret; +} + +static void skl_cldma_stop(struct sst_dsp *ctx) +{ + ctx->cl_dev.ops.cl_trigger(ctx, false); +} + +static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, + const void *curr_pos, bool intr_enable, bool trigger) +{ + dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); + dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", + ctx->cl_dev.dma_buffer_offset, trigger); + dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size); + + if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) + ctx->cl_dev.dma_buffer_offset = 0; + else + ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; + + ctx->cl_dev.wait_condition = false; + + if (intr_enable) + skl_cldma_int_enable(ctx); + + ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); + if (trigger) + ctx->cl_dev.ops.cl_trigger(ctx, true); +} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 34c366f050ee..99e4c86b6358 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -188,4 +188,64 @@ #define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK)
+/* SST IPC SKL defines */ +#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +enum skl_cl_dma_wake_states { + SKL_CL_DMA_STATUS_NONE = 0, + SKL_CL_DMA_BUF_COMPLETE, + SKL_CL_DMA_ERR, /* TODO: Expand the error states */ +}; + +struct sst_dsp; + +struct skl_cl_dev_ops { + void (*cl_setup_bdle)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc); + void (*cl_setup_controller)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 page_count); + void (*cl_setup_spb)(struct sst_dsp *ctx, + unsigned int size, bool enable); + void (*cl_cleanup_spb)(struct sst_dsp *ctx); + void (*cl_trigger)(struct sst_dsp *ctx, bool enable); + void (*cl_cleanup_controller)(struct sst_dsp *ctx); + int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, + const void *bin, u32 size); + void (*cl_stop_dma)(struct sst_dsp *ctx); +}; + +/** + * skl_cl_dev - holds information for code loader dma transfer + * + * @dmab_data: buffer pointer + * @dmab_bdl: buffer descriptor list + * @bufsize: ring buffer size + * @frags: Last valid buffer descriptor index in the BDL + * @curr_spib_pos: Current position in ring buffer + * @dma_buffer_offset: dma buffer offset + * @ops: operations supported on CL dma + * @wait_queue: wait queue to wake for wake event + * @wake_status: DMA wake status + * @wait_condition: condition to wait on wait queue + * @cl_dma_lock: for synchronized access to cldma + */ +struct skl_cl_dev { + struct snd_dma_buffer dmab_data; + struct snd_dma_buffer dmab_bdl; + + unsigned int bufsize; + unsigned int frags; + + unsigned int curr_spib_pos; + unsigned int dma_buffer_offset; + struct skl_cl_dev_ops ops; + + wait_queue_head_t wait_queue; + int wake_status; + bool wait_condition; +}; + #endif /* SKL_SST_CLDMA_H_ */
The patch
ASoC: Intel: Skylake: add code loader DMA operations
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 914426c8657c1e934b015ffa32e7bfd0cb34f47f Mon Sep 17 00:00:00 2001
From: Vinod Koul vinod.koul@intel.com Date: Fri, 10 Jul 2015 22:18:41 +0530 Subject: [PATCH] ASoC: Intel: Skylake: add code loader DMA operations
This patch starts adding code loader DMA handling internal operations for setting up bdle, controller, spb, cleanup routines and buffer filling
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-sst-cldma.c | 194 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-cldma.h | 60 ++++++++++ 2 files changed, 254 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.c
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c new file mode 100644 index 0000000..44019ee --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -0,0 +1,194 @@ +/* + * skl-sst-cldma.c - Code Loader DMA handler + * + * Copyright (C) 2015, Intel Corporation. + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/device.h> +#include <linux/mm.h> +#include <linux/kthread.h> +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static void skl_cldma_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); +} + +void skl_cldma_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); +} + +/* Code loader helper APIs */ +static void skl_cldma_setup_bdle(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + + ctx->cl_dev.frags = 0; + while (size > 0) { + phys_addr_t addr = virt_to_phys(dmab_data->area + + (ctx->cl_dev.frags * ctx->cl_dev.bufsize)); + + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + + bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize); + + size -= ctx->cl_dev.bufsize; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + + bdl += 4; + ctx->cl_dev.frags++; + } +} + +/* + * Setup controller + * Configure the registers to update the dma buffer address and + * enable interrupts. + * Note: Using the channel 1 for transfer + */ +static void skl_cldma_setup_controller(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, unsigned int max_size, + u32 count) +{ + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, + CL_SD_BDLPLBA(dmab_bdl->addr)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, + CL_SD_BDLPUBA(dmab_bdl->addr)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); +} + +static void skl_cldma_setup_spb(struct sst_dsp *ctx, + unsigned int size, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); + else + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); +} + +static void skl_cldma_cleanup(struct sst_dsp *ctx) +{ + skl_cldma_cleanup_spb(ctx); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + +static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +{ + int ret = 0; + + if (!wait_event_timeout(ctx->cl_dev.wait_queue, + ctx->cl_dev.wait_condition, + msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { + dev_err(ctx->dev, "%s: Wait timeout\n", __func__); + ret = -EIO; + goto cleanup; + } + + dev_dbg(ctx->dev, "%s: Event wake\n", __func__); + if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { + dev_err(ctx->dev, "%s: DMA Error\n", __func__); + ret = -EIO; + } + +cleanup: + ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; + return ret; +} + +static void skl_cldma_stop(struct sst_dsp *ctx) +{ + ctx->cl_dev.ops.cl_trigger(ctx, false); +} + +static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, + const void *curr_pos, bool intr_enable, bool trigger) +{ + dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); + dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", + ctx->cl_dev.dma_buffer_offset, trigger); + dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size); + + if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) + ctx->cl_dev.dma_buffer_offset = 0; + else + ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; + + ctx->cl_dev.wait_condition = false; + + if (intr_enable) + skl_cldma_int_enable(ctx); + + ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); + if (trigger) + ctx->cl_dev.ops.cl_trigger(ctx, true); +} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 34c366f..99e4c86 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -188,4 +188,64 @@ #define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK)
+/* SST IPC SKL defines */ +#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +enum skl_cl_dma_wake_states { + SKL_CL_DMA_STATUS_NONE = 0, + SKL_CL_DMA_BUF_COMPLETE, + SKL_CL_DMA_ERR, /* TODO: Expand the error states */ +}; + +struct sst_dsp; + +struct skl_cl_dev_ops { + void (*cl_setup_bdle)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc); + void (*cl_setup_controller)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 page_count); + void (*cl_setup_spb)(struct sst_dsp *ctx, + unsigned int size, bool enable); + void (*cl_cleanup_spb)(struct sst_dsp *ctx); + void (*cl_trigger)(struct sst_dsp *ctx, bool enable); + void (*cl_cleanup_controller)(struct sst_dsp *ctx); + int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, + const void *bin, u32 size); + void (*cl_stop_dma)(struct sst_dsp *ctx); +}; + +/** + * skl_cl_dev - holds information for code loader dma transfer + * + * @dmab_data: buffer pointer + * @dmab_bdl: buffer descriptor list + * @bufsize: ring buffer size + * @frags: Last valid buffer descriptor index in the BDL + * @curr_spib_pos: Current position in ring buffer + * @dma_buffer_offset: dma buffer offset + * @ops: operations supported on CL dma + * @wait_queue: wait queue to wake for wake event + * @wake_status: DMA wake status + * @wait_condition: condition to wait on wait queue + * @cl_dma_lock: for synchronized access to cldma + */ +struct skl_cl_dev { + struct snd_dma_buffer dmab_data; + struct snd_dma_buffer dmab_bdl; + + unsigned int bufsize; + unsigned int frags; + + unsigned int curr_spib_pos; + unsigned int dma_buffer_offset; + struct skl_cl_dev_ops ops; + + wait_queue_head_t wait_queue; + int wake_status; + bool wait_condition; +}; + #endif /* SKL_SST_CLDMA_H_ */
This patch adds the last piece of code loader DMA APIs by adding the code loader DMA APIs for the driver to use
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/common/sst-dsp-priv.h | 3 + sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-sst-cldma.c | 133 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 6 ++ 4 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index dd79648dfb3a..cbd568eac033 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -308,8 +308,11 @@ struct sst_dsp {
/* SKL data */
+ /* To allocate CL dma buffers */ + struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; int sst_state; + struct skl_cl_dev cl_dev; u32 intr_status; };
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 10c1319f7ed5..eff3e1758b89 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44019eef6114..44748ba98da2 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -192,3 +192,136 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, if (trigger) ctx->cl_dev.ops.cl_trigger(ctx, true); } + +/* + * The CL dma doesn't have any way to update the transfer status until a BDL + * buffer is fully transferred + * + * So Copying is divided in two parts. + * 1. Interrupt on buffer done where the size to be transferred is more than + * ring buffer size. + * 2. Polling on fw register to identify if data left to transferred doesn't + * fill the ring buffer. Caller takes care of polling the required status + * register to identify the transfer status. + */ +static int +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +{ + int ret = 0; + bool start = true; + unsigned int excess_bytes; + u32 size; + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + + if (total_size <= 0) + return -EINVAL; + + dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); + + while (bytes_left) { + if (bytes_left > ctx->cl_dev.bufsize) { + + /* + * dma transfers only till the write pointer as + * updated in spib + */ + if (ctx->cl_dev.curr_spib_pos == 0) + ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; + + size = ctx->cl_dev.bufsize; + skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); + + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } + + } else { + skl_cldma_int_disable(ctx); + + if ((ctx->cl_dev.curr_spib_pos + bytes_left) + <= ctx->cl_dev.bufsize) { + ctx->cl_dev.curr_spib_pos += bytes_left; + } else { + excess_bytes = bytes_left - + (ctx->cl_dev.bufsize - + ctx->cl_dev.curr_spib_pos); + ctx->cl_dev.curr_spib_pos = excess_bytes; + } + + size = bytes_left; + skl_cldma_fill_buffer(ctx, size, + curr_pos, false, start); + } + bytes_left -= size; + curr_pos = curr_pos + size; + } + + return ret; +} + +void skl_cldma_process_intr(struct sst_dsp *ctx) +{ + u8 cl_dma_intr_status; + + cl_dma_intr_status = + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); + + if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) + ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; + else + ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; + + ctx->cl_dev.wait_condition = true; + wake_up(&ctx->cl_dev.wait_queue); +} + +int skl_cldma_prepare(struct sst_dsp *ctx) +{ + int ret; + u32 *bdl; + + ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; + + /* Allocate cl ops */ + ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; + ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; + ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; + ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; + ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; + ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; + ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; + + /* Allocate buffer*/ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); + return ret; + } + /* Setup Code loader BDL */ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_bdl, PAGE_SIZE); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + return ret; + } + bdl = (u32 *)ctx->cl_dev.dmab_bdl.area; + + /* Allocate BDLs */ + ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, + &bdl, ctx->cl_dev.bufsize, 1); + ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, + ctx->cl_dev.bufsize, ctx->cl_dev.frags); + + ctx->cl_dev.curr_spib_pos = 0; + ctx->cl_dev.dma_buffer_offset = 0; + init_waitqueue_head(&ctx->cl_dev.wait_queue); + + return ret; +} diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index c2d28781309a..e8ce1364bf7b 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,7 +17,9 @@ #define __SKL_SST_DSP_H__
#include <sound/memalloc.h> +#include "skl-sst-cldma.h"
+struct sst_dsp; struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -113,6 +115,10 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); };
+void skl_cldma_process_intr(struct sst_dsp *ctx); +void skl_cldma_int_disable(struct sst_dsp *ctx); +int skl_cldma_prepare(struct sst_dsp *ctx); + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq);
The patch
ASoC: Intel: Skylake: Add code loader DMA APIs
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 3e40a78461739d86fe1084c515ec227507ba993d Mon Sep 17 00:00:00 2001
From: Vinod Koul vinod.koul@intel.com Date: Fri, 10 Jul 2015 22:18:42 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add code loader DMA APIs
This patch adds the last piece of code loader DMA APIs by adding the code loader DMA APIs for the driver to use
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/common/sst-dsp-priv.h | 3 + sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-sst-cldma.c | 133 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 6 ++ 4 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index dd79648..cbd568e 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -308,8 +308,11 @@ struct sst_dsp {
/* SKL data */
+ /* To allocate CL dma buffers */ + struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; int sst_state; + struct skl_cl_dev cl_dev; u32 intr_status; };
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 10c1319..eff3e17 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44019ee..44748ba 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -192,3 +192,136 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, if (trigger) ctx->cl_dev.ops.cl_trigger(ctx, true); } + +/* + * The CL dma doesn't have any way to update the transfer status until a BDL + * buffer is fully transferred + * + * So Copying is divided in two parts. + * 1. Interrupt on buffer done where the size to be transferred is more than + * ring buffer size. + * 2. Polling on fw register to identify if data left to transferred doesn't + * fill the ring buffer. Caller takes care of polling the required status + * register to identify the transfer status. + */ +static int +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +{ + int ret = 0; + bool start = true; + unsigned int excess_bytes; + u32 size; + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + + if (total_size <= 0) + return -EINVAL; + + dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); + + while (bytes_left) { + if (bytes_left > ctx->cl_dev.bufsize) { + + /* + * dma transfers only till the write pointer as + * updated in spib + */ + if (ctx->cl_dev.curr_spib_pos == 0) + ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; + + size = ctx->cl_dev.bufsize; + skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); + + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } + + } else { + skl_cldma_int_disable(ctx); + + if ((ctx->cl_dev.curr_spib_pos + bytes_left) + <= ctx->cl_dev.bufsize) { + ctx->cl_dev.curr_spib_pos += bytes_left; + } else { + excess_bytes = bytes_left - + (ctx->cl_dev.bufsize - + ctx->cl_dev.curr_spib_pos); + ctx->cl_dev.curr_spib_pos = excess_bytes; + } + + size = bytes_left; + skl_cldma_fill_buffer(ctx, size, + curr_pos, false, start); + } + bytes_left -= size; + curr_pos = curr_pos + size; + } + + return ret; +} + +void skl_cldma_process_intr(struct sst_dsp *ctx) +{ + u8 cl_dma_intr_status; + + cl_dma_intr_status = + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); + + if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) + ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; + else + ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; + + ctx->cl_dev.wait_condition = true; + wake_up(&ctx->cl_dev.wait_queue); +} + +int skl_cldma_prepare(struct sst_dsp *ctx) +{ + int ret; + u32 *bdl; + + ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; + + /* Allocate cl ops */ + ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; + ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; + ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; + ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; + ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; + ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; + ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; + + /* Allocate buffer*/ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); + return ret; + } + /* Setup Code loader BDL */ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_bdl, PAGE_SIZE); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + return ret; + } + bdl = (u32 *)ctx->cl_dev.dmab_bdl.area; + + /* Allocate BDLs */ + ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, + &bdl, ctx->cl_dev.bufsize, 1); + ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, + ctx->cl_dev.bufsize, ctx->cl_dev.frags); + + ctx->cl_dev.curr_spib_pos = 0; + ctx->cl_dev.dma_buffer_offset = 0; + init_waitqueue_head(&ctx->cl_dev.wait_queue); + + return ret; +} diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index c2d2878..e8ce136 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,7 +17,9 @@ #define __SKL_SST_DSP_H__
#include <sound/memalloc.h> +#include "skl-sst-cldma.h"
+struct sst_dsp; struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -113,6 +115,10 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); };
+void skl_cldma_process_intr(struct sst_dsp *ctx); +void skl_cldma_int_disable(struct sst_dsp *ctx); +int skl_cldma_prepare(struct sst_dsp *ctx); + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq);
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com
The code loader DMA interrupt is received by main interrupt handler which dispatches it to cldma routines
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-sst-dsp.c | 5 +++++ sound/soc/intel/skylake/skl-sst-ipc.c | 3 +++ 2 files changed, 8 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 313ca7c6ca7f..94875b008b0b 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -267,6 +267,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) result = IRQ_WAKE_THREAD; }
+ if (val & SKL_ADSPIS_CL_DMA) { + skl_cldma_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + spin_unlock(&ctx->spinlock);
return result; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 94be6cbf2698..bd5ac4165151 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -375,6 +375,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) u32 hipcie, hipct, hipcte; int ipc_irq = 0;
+ if (dsp->intr_status & SKL_ADSPIS_CL_DMA) + skl_cldma_process_intr(dsp); + /* Here we handle IPC interrupts only */ if (!(dsp->intr_status & SKL_ADSPIS_IPC)) return IRQ_NONE;
The patch
ASoC: Intel: Skylake: Process code loader DMA interrupt
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 6cb0033380ec6297589e68bfcf19aeda7ba95e99 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Fri, 10 Jul 2015 22:18:43 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Process code loader DMA interrupt
The code loader DMA interrupt is received by main interrupt handler which dispatches it to cldma routines
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-sst-dsp.c | 5 +++++ sound/soc/intel/skylake/skl-sst-ipc.c | 3 +++ 2 files changed, 8 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 313ca7c..94875b0 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -267,6 +267,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) result = IRQ_WAKE_THREAD; }
+ if (val & SKL_ADSPIS_CL_DMA) { + skl_cldma_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + spin_unlock(&ctx->spinlock);
return result; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 94be6cb..bd5ac41 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -375,6 +375,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) u32 hipcie, hipct, hipcte; int ipc_irq = 0;
+ if (dsp->intr_status & SKL_ADSPIS_CL_DMA) + skl_cldma_process_intr(dsp); + /* Here we handle IPC interrupts only */ if (!(dsp->intr_status & SKL_ADSPIS_IPC)) return IRQ_NONE;
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com
This adds the dsp and ipc initialization for the Skylake platform. It also requests firmware and uses code loader dma to load it.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/Makefile | 3 +- sound/soc/intel/skylake/skl-sst-dsp.h | 11 ++ sound/soc/intel/skylake/skl-sst-ipc.c | 2 + sound/soc/intel/skylake/skl-sst.c | 280 ++++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst.c
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index eff3e1758b89..1fccb378e62c 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,7 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index e8ce1364bf7b..6bfcef449bdc 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,10 +16,12 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__
+#include <linux/interrupt.h> #include <sound/memalloc.h> #include "skl-sst-cldma.h"
struct sst_dsp; +struct skl_sst; struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -62,6 +64,11 @@ struct sst_dsp_device;
#define SKL_ADSP_W1_SZ 0x1000
+#define SKL_FW_STS_MASK 0xf + +#define SKL_FW_INIT 0x1 +#define SKL_FW_RFW_START 0xf + #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1
@@ -106,6 +113,7 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); + unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); };
struct skl_dsp_loader_ops { @@ -130,5 +138,8 @@ int skl_dsp_sleep(struct sst_dsp *ctx); void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_boot(struct sst_dsp *ctx); +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index bd5ac4165151..c0d092861337 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -496,6 +496,8 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) /* Disable IPC BUSY interrupt */ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_BUSY, 0); + + sst_ipc_fini(ipc); }
int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c new file mode 100644 index 000000000000..c18ea51b7484 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst.c @@ -0,0 +1,280 @@ +/* + * skl-sst.c - HDA DSP library functions for SKL platform + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski rafal.f.redzimski@intel.com + * Jeeja KP jeeja.kp@intel.com + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/device.h> +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" +#include "skl-sst-ipc.h" + +#define SKL_BASEFW_TIMEOUT 300 +#define SKL_INIT_TIMEOUT 1000 + +/* Intel HD Audio SRAM Window 0*/ +#define SKL_ADSP_SRAM0_BASE 0x8000 + +/* Firmware status window */ +#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE +#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) + +#define SKL_INSTANCE_ID 0 +#define SKL_BASE_FW_MODULE_ID 0 + +static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) +{ + u32 cur_sts; + + cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; + + return (cur_sts == status); +} + +static int skl_transfer_firmware(struct sst_dsp *ctx, + const void *basefw, u32 base_fw_size) +{ + int ret = 0; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + if (ret < 0) + return ret; + + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_FW_STATUS, + SKL_FW_STS_MASK, + SKL_FW_RFW_START, + SKL_BASEFW_TIMEOUT, + "Firmware boot"); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_base_firmware(struct sst_dsp *ctx) +{ + int ret = 0, i; + const struct firmware *fw = NULL; + struct skl_sst *skl = ctx->thread_context; + u32 reg; + + ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + skl_dsp_disable_core(ctx); + return -EIO; + } + + /* enable Interrupt */ + skl_ipc_int_enable(ctx); + skl_ipc_op_int_enable(ctx); + + /* check ROM Status */ + for (i = SKL_INIT_TIMEOUT; i > 0; --i) { + if (skl_check_fw_status(ctx, SKL_FW_INIT)) { + dev_dbg(ctx->dev, + "ROM loaded, we can continue with FW loading\n"); + break; + } + mdelay(1); + } + if (!i) { + reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); + dev_err(ctx->dev, + "Timeout waiting for ROM init done, reg:0x%x\n", reg); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + ret = skl_transfer_firmware(ctx, fw->data, fw->size); + if (ret < 0) { + dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); + goto skl_load_base_firmware_failed; + } else { + ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0) { + dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + } + release_firmware(fw); + + return 0; + +skl_load_base_firmware_failed: + skl_dsp_disable_core(ctx); + release_firmware(fw); + return ret; +} + +static int skl_set_dsp_D0(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_load_base_firmware(ctx); + if (ret < 0) { + dev_err(ctx->dev, "unable to load firmware\n"); + return ret; + } + + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + + return ret; +} + +static int skl_set_dsp_D3(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_dxstate_info dx; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + mutex_lock(&ctx->mutex); + if (!is_skl_dsp_running(ctx)) { + mutex_unlock(&ctx->mutex); + return 0; + } + mutex_unlock(&ctx->mutex); + + dx.core_mask = SKL_DSP_CORE0_MASK; + dx.dx_mask = SKL_IPC_D3_MASK; + ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); + return ret; + } + + ret = skl_dsp_disable_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); + ret = -EIO; + } + skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); + + return ret; +} + +static unsigned int skl_get_errorcode(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); +} + +static struct skl_dsp_fw_ops skl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, +}; + +static struct sst_ops skl_ops = { + .irq_handler = skl_dsp_sst_interrupt, + .write = sst_shim32_write, + .read = sst_shim32_read, + .ram_read = sst_memcpy_fromio_32, + .ram_write = sst_memcpy_toio_32, + .free = skl_dsp_free, +}; + +static struct sst_dsp_device skl_dev = { + .thread = skl_dsp_irq_thread_handler, + .ops = &skl_ops, +}; + +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) +{ + struct skl_sst *skl; + struct sst_dsp *sst; + int ret; + + skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); + if (skl == NULL) + return -ENOMEM; + + skl->dev = dev; + skl_dev.thread_context = skl; + + skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); + if (!skl->dsp) { + dev_err(skl->dev, "%s: no device\n", __func__); + return -ENODEV; + } + + sst = skl->dsp; + + sst->addr.lpe = mmio_base; + sst->addr.shim = mmio_base; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), + SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + + sst->dsp_ops = dsp_ops; + sst->fw_ops = skl_fw_ops; + + ret = skl_ipc_init(dev, skl); + if (ret) + return ret; + + skl->boot_complete = false; + init_waitqueue_head(&skl->boot_wait); + + ret = skl_dsp_boot(sst); + if (ret < 0) { + dev_err(skl->dev, "Boot dsp core failed ret: %d", ret); + goto free_ipc; + } + + ret = skl_cldma_prepare(sst); + if (ret < 0) { + dev_err(dev, "CL dma prepare failed : %d", ret); + goto free_ipc; + } + + + ret = sst->fw_ops.load_fw(sst); + if (ret < 0) { + dev_err(dev, "Load base fw failed : %d", ret); + return ret; + } + + if (dsp) + *dsp = skl; + + return 0; + +free_ipc: + skl_ipc_free(&skl->ipc); + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +{ + skl_ipc_free(&ctx->ipc); + ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); + ctx->dsp->ops->free(ctx->dsp); +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake IPC driver");
The patch
ASoC: Intel: Skylake: Add SKL DSP initialization
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From a750ba5f5a564732ed2be87de836a5a74f9cc586 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" subhransu.s.prusty@intel.com Date: Fri, 10 Jul 2015 22:18:44 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add SKL DSP initialization
This adds the dsp and ipc initialization for the Skylake platform. It also requests firmware and uses code loader dma to load it.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/Makefile | 3 +- sound/soc/intel/skylake/skl-sst-dsp.h | 11 ++ sound/soc/intel/skylake/skl-sst-ipc.c | 2 + sound/soc/intel/skylake/skl-sst.c | 280 ++++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst.c
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index eff3e17..1fccb37 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,7 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index e8ce136..6bfcef4 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,10 +16,12 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__
+#include <linux/interrupt.h> #include <sound/memalloc.h> #include "skl-sst-cldma.h"
struct sst_dsp; +struct skl_sst; struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */ @@ -62,6 +64,11 @@ struct sst_dsp_device;
#define SKL_ADSP_W1_SZ 0x1000
+#define SKL_FW_STS_MASK 0xf + +#define SKL_FW_INIT 0x1 +#define SKL_FW_RFW_START 0xf + #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1
@@ -106,6 +113,7 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); + unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); };
struct skl_dsp_loader_ops { @@ -130,5 +138,8 @@ int skl_dsp_sleep(struct sst_dsp *ctx); void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_boot(struct sst_dsp *ctx); +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index bd5ac41..c0d0928 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -496,6 +496,8 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) /* Disable IPC BUSY interrupt */ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_BUSY, 0); + + sst_ipc_fini(ipc); }
int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c new file mode 100644 index 0000000..c18ea51 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst.c @@ -0,0 +1,280 @@ +/* + * skl-sst.c - HDA DSP library functions for SKL platform + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski rafal.f.redzimski@intel.com + * Jeeja KP jeeja.kp@intel.com + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/device.h> +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" +#include "skl-sst-ipc.h" + +#define SKL_BASEFW_TIMEOUT 300 +#define SKL_INIT_TIMEOUT 1000 + +/* Intel HD Audio SRAM Window 0*/ +#define SKL_ADSP_SRAM0_BASE 0x8000 + +/* Firmware status window */ +#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE +#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) + +#define SKL_INSTANCE_ID 0 +#define SKL_BASE_FW_MODULE_ID 0 + +static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) +{ + u32 cur_sts; + + cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; + + return (cur_sts == status); +} + +static int skl_transfer_firmware(struct sst_dsp *ctx, + const void *basefw, u32 base_fw_size) +{ + int ret = 0; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + if (ret < 0) + return ret; + + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_FW_STATUS, + SKL_FW_STS_MASK, + SKL_FW_RFW_START, + SKL_BASEFW_TIMEOUT, + "Firmware boot"); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_base_firmware(struct sst_dsp *ctx) +{ + int ret = 0, i; + const struct firmware *fw = NULL; + struct skl_sst *skl = ctx->thread_context; + u32 reg; + + ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + skl_dsp_disable_core(ctx); + return -EIO; + } + + /* enable Interrupt */ + skl_ipc_int_enable(ctx); + skl_ipc_op_int_enable(ctx); + + /* check ROM Status */ + for (i = SKL_INIT_TIMEOUT; i > 0; --i) { + if (skl_check_fw_status(ctx, SKL_FW_INIT)) { + dev_dbg(ctx->dev, + "ROM loaded, we can continue with FW loading\n"); + break; + } + mdelay(1); + } + if (!i) { + reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); + dev_err(ctx->dev, + "Timeout waiting for ROM init done, reg:0x%x\n", reg); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + ret = skl_transfer_firmware(ctx, fw->data, fw->size); + if (ret < 0) { + dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); + goto skl_load_base_firmware_failed; + } else { + ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0) { + dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + } + release_firmware(fw); + + return 0; + +skl_load_base_firmware_failed: + skl_dsp_disable_core(ctx); + release_firmware(fw); + return ret; +} + +static int skl_set_dsp_D0(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_load_base_firmware(ctx); + if (ret < 0) { + dev_err(ctx->dev, "unable to load firmware\n"); + return ret; + } + + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + + return ret; +} + +static int skl_set_dsp_D3(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_dxstate_info dx; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + mutex_lock(&ctx->mutex); + if (!is_skl_dsp_running(ctx)) { + mutex_unlock(&ctx->mutex); + return 0; + } + mutex_unlock(&ctx->mutex); + + dx.core_mask = SKL_DSP_CORE0_MASK; + dx.dx_mask = SKL_IPC_D3_MASK; + ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); + return ret; + } + + ret = skl_dsp_disable_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); + ret = -EIO; + } + skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); + + return ret; +} + +static unsigned int skl_get_errorcode(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); +} + +static struct skl_dsp_fw_ops skl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, +}; + +static struct sst_ops skl_ops = { + .irq_handler = skl_dsp_sst_interrupt, + .write = sst_shim32_write, + .read = sst_shim32_read, + .ram_read = sst_memcpy_fromio_32, + .ram_write = sst_memcpy_toio_32, + .free = skl_dsp_free, +}; + +static struct sst_dsp_device skl_dev = { + .thread = skl_dsp_irq_thread_handler, + .ops = &skl_ops, +}; + +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) +{ + struct skl_sst *skl; + struct sst_dsp *sst; + int ret; + + skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); + if (skl == NULL) + return -ENOMEM; + + skl->dev = dev; + skl_dev.thread_context = skl; + + skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); + if (!skl->dsp) { + dev_err(skl->dev, "%s: no device\n", __func__); + return -ENODEV; + } + + sst = skl->dsp; + + sst->addr.lpe = mmio_base; + sst->addr.shim = mmio_base; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), + SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + + sst->dsp_ops = dsp_ops; + sst->fw_ops = skl_fw_ops; + + ret = skl_ipc_init(dev, skl); + if (ret) + return ret; + + skl->boot_complete = false; + init_waitqueue_head(&skl->boot_wait); + + ret = skl_dsp_boot(sst); + if (ret < 0) { + dev_err(skl->dev, "Boot dsp core failed ret: %d", ret); + goto free_ipc; + } + + ret = skl_cldma_prepare(sst); + if (ret < 0) { + dev_err(dev, "CL dma prepare failed : %d", ret); + goto free_ipc; + } + + + ret = sst->fw_ops.load_fw(sst); + if (ret < 0) { + dev_err(dev, "Load base fw failed : %d", ret); + return ret; + } + + if (dsp) + *dsp = skl; + + return 0; + +free_ipc: + skl_ipc_free(&skl->ipc); + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +{ + skl_ipc_free(&ctx->ipc); + ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); + ctx->dsp->ops->free(ctx->dsp); +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake IPC driver");
From: Omair M Abdullah omair.m.abdullah@intel.com
Signed-off-by: Omair M Abdullah omair.m.abdullah@intel.com Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/skylake/skl-sst-ipc.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index c0d092861337..937a0a3a63a0 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -362,6 +362,12 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, break; }
+ if (reply != IPC_GLB_REPLY_SUCCESS) { + dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); + dev_err(ipc->dev, "FW Error Code: %u\n", + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + } + list_del(&msg->list); sst_ipc_tx_msg_reply_complete(ipc, msg); }
The patch
ASoC: Intel: Skylake: Print error code in IPC for SKL
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 28f3b6f113186ff69bdc5e63126ae7fd5e35a138 Mon Sep 17 00:00:00 2001
From: Omair M Abdullah omair.m.abdullah@intel.com Date: Fri, 10 Jul 2015 22:18:45 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Print error code in IPC for SKL
Signed-off-by: Omair M Abdullah omair.m.abdullah@intel.com Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-sst-ipc.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index c0d0928..937a0a3 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -362,6 +362,12 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, break; }
+ if (reply != IPC_GLB_REPLY_SUCCESS) { + dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); + dev_err(ipc->dev, "FW Error Code: %u\n", + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + } + list_del(&msg->list); sst_ipc_tx_msg_reply_complete(ipc, msg); }
This series add code loader DMA support to Skylake driver and then adds the IPC init routines
Omair M Abdullah (1): ASoC: Intel: Skylake: Print error code in IPC for SKL
Subhransu S. Prusty (3): ASoC: Intel: Skylake: Add dsp loader ops ASoC: Intel: Skylake: Process code loader DMA interrupt ASoC: Intel: Skylake: Add SKL DSP initialization
Vinod Koul (3): ASoC: Intel: Skylake: Add code loader DMA registers ASoC: Intel: Skylake: add code loader DMA operations ASoC: Intel: Skylake: Add code loader DMA APIs
sound/soc/intel/common/sst-dsp-priv.h | 2 + sound/soc/intel/skylake/Makefile | 3 +- sound/soc/intel/skylake/skl-sst-cldma.c | 307 ++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-cldma.h | 259 +++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.c | 5 + sound/soc/intel/skylake/skl-sst-dsp.h | 26 +++ sound/soc/intel/skylake/skl-sst-ipc.c | 11 ++ sound/soc/intel/skylake/skl-sst.c | 284 +++++++++++++++++++++++++++++ 8 files changed, 896 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.c create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.h create mode 100644 sound/soc/intel/skylake/skl-sst.c
participants (2)
-
Mark Brown
-
Vinod Koul