From 78cdf024a2db447aca95a92da367fdbc3463b80b Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 5 Sep 2014 18:51:36 +0800 Subject: [PATCH] ENGR00329948-3: dma: imx-sdma: Add hdmi audio support in sdma There's a missing script for hdmi audio support in current sdma driver, thus add it. This HDMI script doesn't use bd to copy memory like a normal one does but only to update the memory address for HDMI internal AHB DMA and then trigger its procedure automatically. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + drivers/dma/imx-sdma.c | 38 ++++++++++++++----- include/linux/platform_data/dma-imx.h | 3 +- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index d2e91f13343f..62f0d1b275ab 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -48,6 +48,7 @@ The full ID of peripheral types can be found below. 21 ESAI 22 SSI Dual FIFO (needs firmware ver >= 2) 23 Shared ASRC + 24 HDMI Audio The third cell specifies the transfer priority as below. diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index ac2073b3922e..519fbea5d193 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -677,7 +677,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) int channel = fls(stat) - 1; struct sdma_channel *sdmac = &sdma->channel[channel]; - if (sdmac->flags & IMX_DMA_SG_LOOP) + if ((sdmac->flags & IMX_DMA_SG_LOOP) && + (sdmac->peripheral_type != IMX_DMATYPE_HDMI)) sdma_update_channel_loop(sdmac); tasklet_schedule(&sdmac->tasklet); @@ -773,6 +774,9 @@ static void sdma_get_pc(struct sdma_channel *sdmac, case IMX_DMATYPE_IPU_MEMORY: emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; break; + case IMX_DMATYPE_HDMI: + emi_2_per = sdma->script_addrs->hdmi_dma_addr; + break; default: break; } @@ -817,11 +821,16 @@ static int sdma_load_context(struct sdma_channel *sdmac) /* Send by context the event mask,base address for peripheral * and watermark level */ - context->gReg[0] = sdmac->event_mask[1]; - context->gReg[1] = sdmac->event_mask[0]; - context->gReg[2] = sdmac->per_addr; - context->gReg[6] = sdmac->shp_addr; - context->gReg[7] = sdmac->watermark_level; + if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { + context->gReg[4] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + } else { + context->gReg[0] = sdmac->event_mask[1]; + context->gReg[1] = sdmac->event_mask[0]; + context->gReg[2] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + context->gReg[7] = sdmac->watermark_level; + } bd0->mode.command = C0_SETDM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; @@ -956,7 +965,8 @@ static int sdma_config_channel(struct sdma_channel *sdmac) /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ - if (sdmac->direction == DMA_DEV_TO_DEV) { + if (sdmac->direction == DMA_DEV_TO_DEV || + (sdmac->peripheral_type == IMX_DMATYPE_HDMI)) { sdmac->shp_addr = sdmac->per_address2; sdmac->per_addr = sdmac->per_address; } else { @@ -1207,9 +1217,9 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; - int num_periods = buf_len / period_len; int channel = sdmac->channel; int ret, i = 0, buf = 0; + int num_periods; dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); @@ -1227,6 +1237,11 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( if (ret) goto err_out; + if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) + return &sdmac->desc; + else + num_periods = buf_len / period_len; + if (num_periods > NUM_BD) { dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", channel, num_periods, NUM_BD); @@ -1304,12 +1319,17 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst & 0xff) << 16; sdmac->word_size = dmaengine_cfg->dst_addr_width; - } else { + } else if (dmaengine_cfg->direction == DMA_MEM_TO_DEV) { sdmac->per_address = dmaengine_cfg->dst_addr; sdmac->watermark_level = dmaengine_cfg->dst_maxburst * dmaengine_cfg->dst_addr_width; sdmac->word_size = dmaengine_cfg->dst_addr_width; + } else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { + sdmac->per_address = dmaengine_cfg->src_addr; + sdmac->per_address2 = dmaengine_cfg->dst_addr; + sdmac->watermark_level = 0; } + sdmac->direction = dmaengine_cfg->direction; return sdma_config_channel(sdmac); default: diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index 407a8f2d3f66..bc018386b20d 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -41,6 +41,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_ESAI, /* ESAI */ IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ + IMX_DMATYPE_HDMI, /* HDMI Audio */ }; enum imx_dma_prio { -- 2.39.5