[alsa-devel] [PATCH v3 0/4] Add dual-fifo mode support of i.MX ssi
Changelog v3: * PATCH-1: Add comments to indicate the end of v1 and v2 array. * PATCH-3: Use better way to keep watermark as even number. * * Nothing changes for PATCH-2 and PATCH-4 v2: * Instead of adding rogue scripts to current SDMA driver based on firmware * V1, we define the new SDMA firmware as version 2 and bisect the PATCH-1 * to two patches: The first is to add version check code to the SDMA driver; * And the second is to add SSI dual FIFO DMATYPE. * * Nothing changes for the last two patches. v1: * SSI can reduce hardware overrun/underrun possibility when using dual * fifo mode. To support this mode, we need to first update sdma sciprt * list, and then enable dual fifo BIT in SSI driver, and last update DT * bindings of i.MX series. * * ! This series of patches has a direct dependency between them. When * ! applying them, we need to apply to one single branch. Otherwise, * ! it would break currect branches. Nicolin Chen (4): dma: imx-sdma: Add sdma firmware version 2 support dma: imx-sdma: Add new dma type for ssi dual fifo script ASoC: fsl_ssi: Add dual fifo mode support ARM: dts: imx: use dual-fifo sdma script for ssi
.../devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + arch/arm/boot/dts/imx51.dtsi | 4 ++-- arch/arm/boot/dts/imx53.dtsi | 4 ++-- arch/arm/boot/dts/imx6qdl.dtsi | 12 ++++++------ arch/arm/boot/dts/imx6sl.dtsi | 12 ++++++------ drivers/dma/imx-sdma.c | 19 ++++++++++++++++++- include/linux/platform_data/dma-imx-sdma.h | 5 +++++ include/linux/platform_data/dma-imx.h | 1 + sound/soc/fsl/fsl_ssi.c | 22 +++++++++++++++++++++- 9 files changed, 62 insertions(+), 18 deletions(-)
On i.MX5/6 series, SDMA is using new version firmware to support SSI dual FIFO feature and HDMI Audio (i.MX6Q/DL only). Thus add it.
Signed-off-by: Nicolin Chen b42378@freescale.com --- drivers/dma/imx-sdma.c | 15 ++++++++++++++- include/linux/platform_data/dma-imx-sdma.h | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index fc43603..c7ece8d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -323,6 +323,7 @@ struct sdma_engine { struct clk *clk_ipg; struct clk *clk_ahb; spinlock_t channel_0_lock; + u32 script_number; struct sdma_script_start_addrs *script_addrs; const struct sdma_driver_data *drvdata; }; @@ -1238,6 +1239,7 @@ static void sdma_issue_pending(struct dma_chan *chan) }
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) @@ -1246,7 +1248,7 @@ static void sdma_add_scripts(struct sdma_engine *sdma, s32 *saddr_arr = (u32 *)sdma->script_addrs; int i;
- for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; } @@ -1272,6 +1274,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) goto err_firmware; if (header->ram_code_start + header->ram_code_size > fw->size) goto err_firmware; + switch (header->version_major) { + case 1: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + break; + case 2: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; + break; + default: + dev_err(sdma->dev, "unknown firmware version\n"); + return; + }
addr = (void *)header + header->script_addrs_start; ram_code = (void *)header + header->ram_code_start; diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h index 3a39428..eabac4e 100644 --- a/include/linux/platform_data/dma-imx-sdma.h +++ b/include/linux/platform_data/dma-imx-sdma.h @@ -43,6 +43,11 @@ struct sdma_script_start_addrs { s32 dptc_dvfs_addr; s32 utra_addr; s32 ram_code_start_addr; + /* End of v1 array */ + s32 mcu_2_ssish_addr; + s32 ssish_2_mcu_addr; + s32 hdmi_dma_addr; + /* End of v2 array */ };
/**
This patch adds a new DMA_TYPE for SSI dual FIFO script, included in SDMA firmware version 2. This script would allow SSI use dual fifo mode to transimit/receive data without occasional hardware underrun/overrun.
Signed-off-by: Nicolin Chen b42378@freescale.com --- Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + drivers/dma/imx-sdma.c | 4 ++++ include/linux/platform_data/dma-imx.h | 1 + 3 files changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 4fa814d..68b83ec 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -42,6 +42,7 @@ The full ID of peripheral types can be found below. 19 IPU Memory 20 ASRC 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2)
The third cell specifies the transfer priority as below.
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c7ece8d..efaa9a9 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -725,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->app_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_app_addr; break; + case IMX_DMATYPE_SSI_DUAL: + per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; + break; case IMX_DMATYPE_SSI_SP: case IMX_DMATYPE_MMC: case IMX_DMATYPE_SDHC: diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index beac6b8..bcbc6c3 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -39,6 +39,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */ IMX_DMATYPE_ASRC, /* ASRC */ IMX_DMATYPE_ESAI, /* ESAI */ + IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ };
enum imx_dma_prio {
By enabling dual fifo mode, it would allow SSI enter a better performance to transimit/receive data without occasional hardware underrun/overrun.
[ Passed compile-test with mpc85xx_defconfig ]
Signed-off-by: Nicolin Chen b42378@freescale.com --- sound/soc/fsl/fsl_ssi.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 35e2773..51a2022 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -143,6 +143,7 @@ struct fsl_ssi_private { bool ssi_on_imx; bool imx_ac97; bool use_dma; + bool use_dual_fifo; struct clk *clk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -413,6 +414,16 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor); }
+ if (ssi_private->use_dual_fifo) { + write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1); + write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1); + write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN); + } else { + write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0); + write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0); + write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0); + } + return 0; }
@@ -947,7 +958,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi_private->fifo_depth = 8;
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) { - u32 dma_events[2]; + u32 dma_events[2], dmas[4]; ssi_private->ssi_on_imx = true;
ssi_private->clk = devm_clk_get(&pdev->dev, NULL); @@ -1001,6 +1012,15 @@ static int fsl_ssi_probe(struct platform_device *pdev) dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx, dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI); + if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4) + && dmas[2] == IMX_DMATYPE_SSI_DUAL) { + ssi_private->use_dual_fifo = true; + /* When using dual fifo mode, we need to keep watermark + * as even numbers due to dma script limitation. + */ + ssi_private->dma_params_tx.maxburst &= ~0x1; + ssi_private->dma_params_rx.maxburst &= ~0x1; + } } else if (ssi_private->use_dma) { /* The 'name' should not have any slashes in it. */ ret = devm_request_irq(&pdev->dev, ssi_private->irq,
Nicolin Chen wrote:
- if (ssi_private->use_dual_fifo) {
write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
- } else {
write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0);
write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0);
write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0);
- }
Why do you need the "else" part? Why can't you just do this:
if (ssi_private->use_dual_fifo) { write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1); write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1); write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN); }
Thank you for the comments. I'll refine this part.
Sent by Android device.
Timur Tabi timur@tabi.org wrote:
Nicolin Chen wrote:
if (ssi_private->use_dual_fifo) {
write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
} else {
write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0);
write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0);
write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0);
}
Why do you need the "else" part? Why can't you just do this:
if (ssi_private->use_dual_fifo) { write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1); write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1); write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN); }
Use dual-fifo sdma scripts instead of shared scripts for ssi on i.MX series.
Signed-off-by: Nicolin Chen b42378@freescale.com --- arch/arm/boot/dts/imx51.dtsi | 4 ++-- arch/arm/boot/dts/imx53.dtsi | 4 ++-- arch/arm/boot/dts/imx6qdl.dtsi | 12 ++++++------ arch/arm/boot/dts/imx6sl.dtsi | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 54cee65..1a71eac 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -154,8 +154,8 @@ reg = <0x70014000 0x4000>; interrupts = <30>; clocks = <&clks 49>; - dmas = <&sdma 24 1 0>, - <&sdma 25 1 0>; + dmas = <&sdma 24 22 0>, + <&sdma 25 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 4307e80..7208fde 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -153,8 +153,8 @@ reg = <0x50014000 0x4000>; interrupts = <30>; clocks = <&clks 49>; - dmas = <&sdma 24 1 0>, - <&sdma 25 1 0>; + dmas = <&sdma 24 22 0>, + <&sdma 25 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 57e9c38..6e096ca 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -223,8 +223,8 @@ reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; clocks = <&clks 178>; - dmas = <&sdma 37 1 0>, - <&sdma 38 1 0>; + dmas = <&sdma 37 22 0>, + <&sdma 38 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <38 37>; @@ -236,8 +236,8 @@ reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; clocks = <&clks 179>; - dmas = <&sdma 41 1 0>, - <&sdma 42 1 0>; + dmas = <&sdma 41 22 0>, + <&sdma 42 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <42 41>; @@ -249,8 +249,8 @@ reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; clocks = <&clks 180>; - dmas = <&sdma 45 1 0>, - <&sdma 46 1 0>; + dmas = <&sdma 45 22 0>, + <&sdma 46 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; fsl,ssi-dma-events = <46 45>; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index c46651e..b32ba99 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -195,8 +195,8 @@ reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; clocks = <&clks IMX6SL_CLK_SSI1>; - dmas = <&sdma 37 1 0>, - <&sdma 38 1 0>; + dmas = <&sdma 37 22 0>, + <&sdma 38 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; status = "disabled"; @@ -207,8 +207,8 @@ reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; clocks = <&clks IMX6SL_CLK_SSI2>; - dmas = <&sdma 41 1 0>, - <&sdma 42 1 0>; + dmas = <&sdma 41 22 0>, + <&sdma 42 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; status = "disabled"; @@ -219,8 +219,8 @@ reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; clocks = <&clks IMX6SL_CLK_SSI3>; - dmas = <&sdma 45 1 0>, - <&sdma 46 1 0>; + dmas = <&sdma 45 22 0>, + <&sdma 46 22 0>; dma-names = "rx", "tx"; fsl,fifo-depth = <15>; status = "disabled";
participants (3)
-
Chen Guangyu-B42378
-
Nicolin Chen
-
Timur Tabi