summaryrefslogtreecommitdiff
path: root/drivers/dma/imx-sdma.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-25 16:55:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-25 16:55:16 -0700
commitd7227785e384d4422b3ca189aa5bf19f462337cc (patch)
treefbd117e5e3f31a8561f6b6d159413bc744f460e5 /drivers/dma/imx-sdma.c
parent2518f226c60d8e04d18ba4295500a5b0b8ac7659 (diff)
parent60571929d06b028800f27b51a7c81de1144944cf (diff)
Merge tag 'sound-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "Not much dramatic changes at this time, but we've received quite a lot of changes for ASoC, while there are still a few fixes and quirks for usual HD- and USB-auido. Here are some highlights. ASoC: - Overhaul of endianness specification for data formats, avoiding needless restrictions due to CODECs - Initial stages of Intel AVS driver merge - Introduction of v4 IPC mechanism for SOF - TDM mode support for AK4613 - Support for Analog Devices ADAU1361, Cirrus Logic CS35L45, Maxim MAX98396, MediaTek MT8186, NXP i.MX8 micfil and SAI interfaces, nVidia Tegra186 ASRC, and Texas Instruments TAS2764 and TAS2780 Others: - A few regression fixes after the USB-audio endpoint management refactoring - More enhancements for Cirrus HD-audio codec support (still ongoing) - Addition of generic serial MIDI driver" * tag 'sound-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (504 commits) ALSA: hda/realtek - Add new type for ALC245 ALSA: usb-audio: Configure sync endpoints before data ALSA: ctxfi: fix typo in comment ALSA: cs5535audio: fix typo in comment ALSA: ctxfi: Add SB046x PCI ID ALSA: usb-audio: Add missing ep_idx in fixed EP quirks ALSA: usb-audio: Workaround for clock setup on TEAC devices ALSA: lola: Bounds check loop iterator against streams array size ASoC: max98090: Move check for invalid values before casting in max98090_put_enab_tlv() ASoC: rt1308-sdw: add the default value of register 0xc320 ASoC: rt9120: Use pm_runtime and regcache to optimize 'pwdnn' logic ASoC: rt9120: Fix 3byte read, valule offset typo ASoC: amd: acp: Set Speaker enable/disable pin through rt1019 codec driver. ASoC: amd: acp: Set Speaker enable/disable pin through rt1019 codec driver ASoC: wm2000: fix missing clk_disable_unprepare() on error in wm2000_anc_transition() ASoC: codecs: lpass: Fix passing zero to 'PTR_ERR' ASoC: SOF: sof-client-ipc-flood-test: use pm_runtime_resume_and_get() ASoC: SOF: mediatek: remove duplicate include in mt8195.c ASoC: SOF: mediatek: Add mt8195 debug dump ASoC: SOF: mediatek: Add mediatek common debug dump ...
Diffstat (limited to 'drivers/dma/imx-sdma.c')
-rw-r--r--drivers/dma/imx-sdma.c76
1 files changed, 71 insertions, 5 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 6196a7b3956b..8535018ee7a2 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -14,6 +14,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
@@ -35,7 +36,7 @@
#include <linux/workqueue.h>
#include <asm/irq.h>
-#include <linux/platform_data/dma-imx.h>
+#include <linux/dma/imx-dma.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -73,6 +74,7 @@
#define SDMA_CHNENBL0_IMX35 0x200
#define SDMA_CHNENBL0_IMX31 0x080
#define SDMA_CHNPRI_0 0x100
+#define SDMA_DONE0_CONFIG 0x1000
/*
* Buffer descriptor status values.
@@ -180,6 +182,12 @@
BIT(DMA_MEM_TO_DEV) | \
BIT(DMA_DEV_TO_DEV))
+#define SDMA_WATERMARK_LEVEL_N_FIFOS GENMASK(15, 12)
+#define SDMA_WATERMARK_LEVEL_SW_DONE BIT(23)
+
+#define SDMA_DONE0_CONFIG_DONE_SEL BIT(7)
+#define SDMA_DONE0_CONFIG_DONE_DIS BIT(6)
+
/**
* struct sdma_script_start_addrs - SDMA script start pointers
*
@@ -441,6 +449,9 @@ struct sdma_channel {
struct work_struct terminate_worker;
struct list_head terminated;
bool is_ram_script;
+ unsigned int n_fifos_src;
+ unsigned int n_fifos_dst;
+ bool sw_done;
};
#define IMX_DMA_SG_LOOP BIT(0)
@@ -778,6 +789,14 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
val = readl_relaxed(sdma->regs + chnenbl);
__set_bit(channel, &val);
writel_relaxed(val, sdma->regs + chnenbl);
+
+ /* Set SDMA_DONEx_CONFIG is sw_done enabled */
+ if (sdmac->sw_done) {
+ val = readl_relaxed(sdma->regs + SDMA_DONE0_CONFIG);
+ val |= SDMA_DONE0_CONFIG_DONE_SEL;
+ val &= ~SDMA_DONE0_CONFIG_DONE_DIS;
+ writel_relaxed(val, sdma->regs + SDMA_DONE0_CONFIG);
+ }
}
static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -940,7 +959,7 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
/*
* sets the pc of SDMA script according to the peripheral type
*/
-static void sdma_get_pc(struct sdma_channel *sdmac,
+static int sdma_get_pc(struct sdma_channel *sdmac,
enum sdma_peripheral_type peripheral_type)
{
struct sdma_engine *sdma = sdmac->sdma;
@@ -1038,14 +1057,22 @@ 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;
- default:
+ case IMX_DMATYPE_MULTI_SAI:
+ per_2_emi = sdma->script_addrs->sai_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_sai_addr;
break;
+ default:
+ dev_err(sdma->dev, "Unsupported transfer type %d\n",
+ peripheral_type);
+ return -EINVAL;
}
sdmac->pc_from_device = per_2_emi;
sdmac->pc_to_device = emi_2_per;
sdmac->device_to_device = per_2_per;
sdmac->pc_to_pc = emi_2_emi;
+
+ return 0;
}
static int sdma_load_context(struct sdma_channel *sdmac)
@@ -1210,9 +1237,26 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
}
+static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
+{
+ unsigned int n_fifos;
+
+ if (sdmac->sw_done)
+ sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE;
+
+ if (sdmac->direction == DMA_DEV_TO_MEM)
+ n_fifos = sdmac->n_fifos_src;
+ else
+ n_fifos = sdmac->n_fifos_dst;
+
+ sdmac->watermark_level |=
+ FIELD_PREP(SDMA_WATERMARK_LEVEL_N_FIFOS, n_fifos);
+}
+
static int sdma_config_channel(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
+ int ret;
sdma_disable_channel(chan);
@@ -1233,7 +1277,9 @@ static int sdma_config_channel(struct dma_chan *chan)
break;
}
- sdma_get_pc(sdmac, sdmac->peripheral_type);
+ ret = sdma_get_pc(sdmac, sdmac->peripheral_type);
+ if (ret)
+ return ret;
if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) &&
(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
@@ -1243,6 +1289,10 @@ static int sdma_config_channel(struct dma_chan *chan)
sdmac->peripheral_type == IMX_DMATYPE_ASRC)
sdma_set_watermarklevel_for_p2p(sdmac);
} else {
+ if (sdmac->peripheral_type ==
+ IMX_DMATYPE_MULTI_SAI)
+ sdma_set_watermarklevel_for_sais(sdmac);
+
__set_bit(sdmac->event_id0, sdmac->event_mask);
}
@@ -1349,7 +1399,9 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
mem_data.dma_request2 = 0;
data = &mem_data;
- sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY);
+ ret = sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY);
+ if (ret)
+ return ret;
}
switch (data->priority) {
@@ -1698,9 +1750,23 @@ static int sdma_config(struct dma_chan *chan,
struct dma_slave_config *dmaengine_cfg)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
+ if (dmaengine_cfg->peripheral_config) {
+ struct sdma_peripheral_config *sdmacfg = dmaengine_cfg->peripheral_config;
+ if (dmaengine_cfg->peripheral_size != sizeof(struct sdma_peripheral_config)) {
+ dev_err(sdma->dev, "Invalid peripheral size %zu, expected %zu\n",
+ dmaengine_cfg->peripheral_size,
+ sizeof(struct sdma_peripheral_config));
+ return -EINVAL;
+ }
+ sdmac->n_fifos_src = sdmacfg->n_fifos_src;
+ sdmac->n_fifos_dst = sdmacfg->n_fifos_dst;
+ sdmac->sw_done = sdmacfg->sw_done;
+ }
+
/* Set ENBLn earlier to make sure dma request triggered after that */
if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
return -EINVAL;