LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/8] powerpc/spufs: simplify spufs core dumping
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

Replace the coredump ->read method with a ->dump method that must call
dump_emit itself.  That way we avoid a buffer allocation an messing with
set_fs() to call into code that is intended to deal with user buffers.
For the ->get case we can now use a small on-stack buffer and avoid
memory allocations as well.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Jeremy Kerr <jk@ozlabs.org>
---
 arch/powerpc/platforms/cell/spufs/coredump.c |  87 ++----
 arch/powerpc/platforms/cell/spufs/file.c     | 273 ++++++++++---------
 arch/powerpc/platforms/cell/spufs/spufs.h    |   3 +-
 3 files changed, 170 insertions(+), 193 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 8b3296b62f65..3b75e8f60609 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -21,22 +21,6 @@
 
 #include "spufs.h"
 
-static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
-				size_t size, loff_t *off)
-{
-	u64 data;
-	int ret;
-
-	if (spufs_coredump_read[num].read)
-		return spufs_coredump_read[num].read(ctx, buffer, size, off);
-
-	data = spufs_coredump_read[num].get(ctx);
-	ret = snprintf(buffer, size, "0x%.16llx", data);
-	if (ret >= size)
-		return size;
-	return ++ret; /* count trailing NULL */
-}
-
 static int spufs_ctx_note_size(struct spu_context *ctx, int dfd)
 {
 	int i, sz, total = 0;
@@ -118,58 +102,43 @@ int spufs_coredump_extra_notes_size(void)
 static int spufs_arch_write_note(struct spu_context *ctx, int i,
 				  struct coredump_params *cprm, int dfd)
 {
-	loff_t pos = 0;
-	int sz, rc, total = 0;
-	const int bufsz = PAGE_SIZE;
-	char *name;
-	char fullname[80], *buf;
+	size_t sz = spufs_coredump_read[i].size;
+	char fullname[80];
 	struct elf_note en;
-	size_t skip;
-
-	buf = (void *)get_zeroed_page(GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
+	size_t ret;
 
-	name = spufs_coredump_read[i].name;
-	sz = spufs_coredump_read[i].size;
-
-	sprintf(fullname, "SPU/%d/%s", dfd, name);
+	sprintf(fullname, "SPU/%d/%s", dfd, spufs_coredump_read[i].name);
 	en.n_namesz = strlen(fullname) + 1;
 	en.n_descsz = sz;
 	en.n_type = NT_SPU;
 
 	if (!dump_emit(cprm, &en, sizeof(en)))
-		goto Eio;
-
+		return -EIO;
 	if (!dump_emit(cprm, fullname, en.n_namesz))
-		goto Eio;
-
+		return -EIO;
 	if (!dump_align(cprm, 4))
-		goto Eio;
-
-	do {
-		rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
-		if (rc > 0) {
-			if (!dump_emit(cprm, buf, rc))
-				goto Eio;
-			total += rc;
-		}
-	} while (rc == bufsz && total < sz);
-
-	if (rc < 0)
-		goto out;
-
-	skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
-	if (!dump_skip(cprm, skip))
-		goto Eio;
-
-	rc = 0;
-out:
-	free_page((unsigned long)buf);
-	return rc;
-Eio:
-	free_page((unsigned long)buf);
-	return -EIO;
+		return -EIO;
+
+	if (spufs_coredump_read[i].dump) {
+		ret = spufs_coredump_read[i].dump(ctx, cprm);
+		if (ret < 0)
+			return ret;
+	} else {
+		char buf[32];
+
+		ret = snprintf(buf, sizeof(buf), "0x%.16llx",
+			       spufs_coredump_read[i].get(ctx));
+		if (ret >= sizeof(buf))
+			return sizeof(buf);
+
+		/* count trailing the NULL: */
+		if (!dump_emit(cprm, buf, ret + 1))
+			return -EIO;
+	}
+
+	if (!dump_skip(cprm, roundup(cprm->pos - ret + sz, 4) - cprm->pos))
+		return -EIO;
+	return 0;
 }
 
 int spufs_coredump_extra_notes_write(struct coredump_params *cprm)
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index c0f950a3f4e1..0f8c3d692af0 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -9,6 +9,7 @@
 
 #undef DEBUG
 
+#include <linux/coredump.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/export.h>
@@ -129,6 +130,14 @@ static ssize_t spufs_attr_write(struct file *file, const char __user *buf,
 	return ret;
 }
 
+static ssize_t spufs_dump_emit(struct coredump_params *cprm, void *buf,
+		size_t size)
+{
+	if (!dump_emit(cprm, buf, size))
+		return -EIO;
+	return size;
+}
+
 #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)	\
 static int __fops ## _open(struct inode *inode, struct file *file)	\
 {									\
@@ -172,12 +181,9 @@ spufs_mem_release(struct inode *inode, struct file *file)
 }
 
 static ssize_t
-__spufs_mem_read(struct spu_context *ctx, char __user *buffer,
-			size_t size, loff_t *pos)
+spufs_mem_dump(struct spu_context *ctx, struct coredump_params *cprm)
 {
-	char *local_store = ctx->ops->get_ls(ctx);
-	return simple_read_from_buffer(buffer, size, pos, local_store,
-					LS_SIZE);
+	return spufs_dump_emit(cprm, ctx->ops->get_ls(ctx), LS_SIZE);
 }
 
 static ssize_t
@@ -190,7 +196,8 @@ spufs_mem_read(struct file *file, char __user *buffer,
 	ret = spu_acquire(ctx);
 	if (ret)
 		return ret;
-	ret = __spufs_mem_read(ctx, buffer, size, pos);
+	ret = simple_read_from_buffer(buffer, size, pos, ctx->ops->get_ls(ctx),
+				      LS_SIZE);
 	spu_release(ctx);
 
 	return ret;
@@ -459,12 +466,10 @@ spufs_regs_open(struct inode *inode, struct file *file)
 }
 
 static ssize_t
-__spufs_regs_read(struct spu_context *ctx, char __user *buffer,
-			size_t size, loff_t *pos)
+spufs_regs_dump(struct spu_context *ctx, struct coredump_params *cprm)
 {
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
-	return simple_read_from_buffer(buffer, size, pos,
-				      lscsa->gprs, sizeof lscsa->gprs);
+	return spufs_dump_emit(cprm, ctx->csa.lscsa->gprs,
+			       sizeof(ctx->csa.lscsa->gprs));
 }
 
 static ssize_t
@@ -482,7 +487,8 @@ spufs_regs_read(struct file *file, char __user *buffer,
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
-	ret = __spufs_regs_read(ctx, buffer, size, pos);
+	ret = simple_read_from_buffer(buffer, size, pos, ctx->csa.lscsa->gprs,
+				      sizeof(ctx->csa.lscsa->gprs));
 	spu_release_saved(ctx);
 	return ret;
 }
@@ -517,12 +523,10 @@ static const struct file_operations spufs_regs_fops = {
 };
 
 static ssize_t
-__spufs_fpcr_read(struct spu_context *ctx, char __user * buffer,
-			size_t size, loff_t * pos)
+spufs_fpcr_dump(struct spu_context *ctx, struct coredump_params *cprm)
 {
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
-	return simple_read_from_buffer(buffer, size, pos,
-				      &lscsa->fpcr, sizeof(lscsa->fpcr));
+	return spufs_dump_emit(cprm, &ctx->csa.lscsa->fpcr,
+			       sizeof(ctx->csa.lscsa->fpcr));
 }
 
 static ssize_t
@@ -535,7 +539,8 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
-	ret = __spufs_fpcr_read(ctx, buffer, size, pos);
+	ret = simple_read_from_buffer(buffer, size, pos, &ctx->csa.lscsa->fpcr,
+				      sizeof(ctx->csa.lscsa->fpcr));
 	spu_release_saved(ctx);
 	return ret;
 }
@@ -967,28 +972,26 @@ spufs_signal1_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
-			size_t len, loff_t *pos)
+static ssize_t spufs_signal1_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
 {
-	int ret = 0;
-	u32 data;
+	if (!ctx->csa.spu_chnlcnt_RW[3])
+		return 0;
+	return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3],
+			       sizeof(ctx->csa.spu_chnldata_RW[3]));
+}
 
-	if (len < 4)
+static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
+			size_t len)
+{
+	if (len < sizeof(ctx->csa.spu_chnldata_RW[3]))
 		return -EINVAL;
-
-	if (ctx->csa.spu_chnlcnt_RW[3]) {
-		data = ctx->csa.spu_chnldata_RW[3];
-		ret = 4;
-	}
-
-	if (!ret)
-		goto out;
-
-	if (copy_to_user(buf, &data, 4))
+	if (!ctx->csa.spu_chnlcnt_RW[3])
+		return 0;
+	if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[3],
+			 sizeof(ctx->csa.spu_chnldata_RW[3])))
 		return -EFAULT;
-
-out:
-	return ret;
+	return sizeof(ctx->csa.spu_chnldata_RW[3]);
 }
 
 static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
@@ -1000,7 +1003,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
-	ret = __spufs_signal1_read(ctx, buf, len, pos);
+	ret = __spufs_signal1_read(ctx, buf, len);
 	spu_release_saved(ctx);
 
 	return ret;
@@ -1104,28 +1107,26 @@ spufs_signal2_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
-			size_t len, loff_t *pos)
+static ssize_t spufs_signal2_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
 {
-	int ret = 0;
-	u32 data;
+	if (!ctx->csa.spu_chnlcnt_RW[4])
+		return 0;
+	return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4],
+			       sizeof(ctx->csa.spu_chnldata_RW[4]));
+}
 
-	if (len < 4)
+static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
+			size_t len)
+{
+	if (len < sizeof(ctx->csa.spu_chnldata_RW[4]))
 		return -EINVAL;
-
-	if (ctx->csa.spu_chnlcnt_RW[4]) {
-		data =  ctx->csa.spu_chnldata_RW[4];
-		ret = 4;
-	}
-
-	if (!ret)
-		goto out;
-
-	if (copy_to_user(buf, &data, 4))
+	if (!ctx->csa.spu_chnlcnt_RW[4])
+		return 0;
+	if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[4],
+			 sizeof(ctx->csa.spu_chnldata_RW[4])))
 		return -EFAULT;
-
-out:
-	return ret;
+	return sizeof(ctx->csa.spu_chnldata_RW[4]);
 }
 
 static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
@@ -1137,7 +1138,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
-	ret = __spufs_signal2_read(ctx, buf, len, pos);
+	ret = __spufs_signal2_read(ctx, buf, len);
 	spu_release_saved(ctx);
 
 	return ret;
@@ -1961,18 +1962,13 @@ static const struct file_operations spufs_caps_fops = {
 	.release	= single_release,
 };
 
-static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static ssize_t spufs_mbox_info_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
 {
-	u32 data;
-
-	/* EOF if there's no entry in the mbox */
 	if (!(ctx->csa.prob.mb_stat_R & 0x0000ff))
 		return 0;
-
-	data = ctx->csa.prob.pu_mb_R;
-
-	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+	return spufs_dump_emit(cprm, &ctx->csa.prob.pu_mb_R,
+			       sizeof(ctx->csa.prob.pu_mb_R));
 }
 
 static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
@@ -1988,7 +1984,12 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
+	/* EOF if there's no entry in the mbox */
+	if (ctx->csa.prob.mb_stat_R & 0x0000ff) {
+		ret = simple_read_from_buffer(buf, len, pos,
+				&ctx->csa.prob.pu_mb_R,
+				sizeof(ctx->csa.prob.pu_mb_R));
+	}
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
@@ -2001,18 +2002,13 @@ static const struct file_operations spufs_mbox_info_fops = {
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t __spufs_ibox_info_read(struct spu_context *ctx,
-				char __user *buf, size_t len, loff_t *pos)
+static ssize_t spufs_ibox_info_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
 {
-	u32 data;
-
-	/* EOF if there's no entry in the ibox */
 	if (!(ctx->csa.prob.mb_stat_R & 0xff0000))
 		return 0;
-
-	data = ctx->csa.priv2.puint_mb_R;
-
-	return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
+	return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R,
+			       sizeof(ctx->csa.priv2.puint_mb_R));
 }
 
 static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
@@ -2028,7 +2024,12 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
+	/* EOF if there's no entry in the ibox */
+	if (ctx->csa.prob.mb_stat_R & 0xff0000) {
+		ret = simple_read_from_buffer(buf, len, pos,
+				&ctx->csa.priv2.puint_mb_R,
+				sizeof(ctx->csa.priv2.puint_mb_R));
+	}
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
@@ -2041,21 +2042,16 @@ static const struct file_operations spufs_ibox_info_fops = {
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
 {
-	int i, cnt;
-	u32 data[4];
-	u32 wbox_stat;
-
-	wbox_stat = ctx->csa.prob.mb_stat_R;
-	cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
-	for (i = 0; i < cnt; i++) {
-		data[i] = ctx->csa.spu_mailbox_data[i];
-	}
+	return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
+}
 
-	return simple_read_from_buffer(buf, len, pos, &data,
-				cnt * sizeof(u32));
+static ssize_t spufs_wbox_info_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
+{
+	return spufs_dump_emit(cprm, &ctx->csa.spu_mailbox_data,
+			spufs_wbox_info_cnt(ctx));
 }
 
 static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
@@ -2071,7 +2067,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
+	ret = simple_read_from_buffer(buf, len, pos, &ctx->csa.spu_mailbox_data,
+				      spufs_wbox_info_cnt(ctx));
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
@@ -2084,36 +2081,42 @@ static const struct file_operations spufs_wbox_info_fops = {
 	.llseek  = generic_file_llseek,
 };
 
-static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static void __spufs_dma_info_read(struct spu_context *ctx,
+		struct spu_dma_info *info)
 {
-	struct spu_dma_info info;
-	struct mfc_cq_sr *qp, *spuqp;
 	int i;
 
-	info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
-	info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
-	info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
-	info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
-	info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
+	info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
+	info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
+	info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
+	info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
+	info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
+
 	for (i = 0; i < 16; i++) {
-		qp = &info.dma_info_command_data[i];
-		spuqp = &ctx->csa.priv2.spuq[i];
+		struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
+		struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
 
 		qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
 		qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
 		qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
 	}
+}
+
+static ssize_t spufs_dma_info_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
+{
+	struct spu_dma_info info;
 
-	return simple_read_from_buffer(buf, len, pos, &info,
-				sizeof info);
+	__spufs_dma_info_read(ctx, &info);
+	return spufs_dump_emit(cprm, &info, sizeof(info));
 }
 
 static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 			      size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_dma_info info;
 	int ret;
 
 	if (!access_ok(buf, len))
@@ -2123,7 +2126,8 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_dma_info_read(ctx, buf, len, pos);
+	__spufs_dma_info_read(ctx, &info);
+	ret = simple_read_from_buffer(buf, len, pos, &info, sizeof(info));
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
@@ -2136,48 +2140,53 @@ static const struct file_operations spufs_dma_info_fops = {
 	.llseek = no_llseek,
 };
 
-static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
-			char __user *buf, size_t len, loff_t *pos)
+static void __spufs_proxydma_info_read(struct spu_context *ctx,
+	struct spu_proxydma_info *info)
 {
-	struct spu_proxydma_info info;
-	struct mfc_cq_sr *qp, *puqp;
-	int ret = sizeof info;
 	int i;
 
-	if (len < ret)
-		return -EINVAL;
-
-	if (!access_ok(buf, len))
-		return -EFAULT;
+	info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
+	info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
+	info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
 
-	info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
-	info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
-	info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
 	for (i = 0; i < 8; i++) {
-		qp = &info.proxydma_info_command_data[i];
-		puqp = &ctx->csa.priv2.puq[i];
+		struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
+		struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
 
 		qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
 		qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
 		qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
 		qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
 	}
+}
+
+static ssize_t spufs_proxydma_info_dump(struct spu_context *ctx,
+		struct coredump_params *cprm)
+{
+	struct spu_proxydma_info info;
 
-	return simple_read_from_buffer(buf, len, pos, &info,
-				sizeof info);
+	__spufs_proxydma_info_read(ctx, &info);
+	return spufs_dump_emit(cprm, &info, sizeof(info));
 }
 
 static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
 				   size_t len, loff_t *pos)
 {
 	struct spu_context *ctx = file->private_data;
+	struct spu_proxydma_info info;
 	int ret;
 
+	if (len < sizeof(info))
+		return -EINVAL;
+	if (!access_ok(buf, len))
+		return -EFAULT;
+
 	ret = spu_acquire_saved(ctx);
 	if (ret)
 		return ret;
 	spin_lock(&ctx->csa.register_lock);
-	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
+	__spufs_proxydma_info_read(ctx, &info);
+	ret = simple_read_from_buffer(buf, len, pos, &info, sizeof(info));
 	spin_unlock(&ctx->csa.register_lock);
 	spu_release_saved(ctx);
 
@@ -2625,23 +2634,23 @@ const struct spufs_tree_descr spufs_dir_debug_contents[] = {
 };
 
 const struct spufs_coredump_reader spufs_coredump_read[] = {
-	{ "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])},
-	{ "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) },
+	{ "regs", spufs_regs_dump, NULL, sizeof(struct spu_reg128[128])},
+	{ "fpcr", spufs_fpcr_dump, NULL, sizeof(struct spu_reg128) },
 	{ "lslr", NULL, spufs_lslr_get, 19 },
 	{ "decr", NULL, spufs_decr_get, 19 },
 	{ "decr_status", NULL, spufs_decr_status_get, 19 },
-	{ "mem", __spufs_mem_read, NULL, LS_SIZE, },
-	{ "signal1", __spufs_signal1_read, NULL, sizeof(u32) },
+	{ "mem", spufs_mem_dump, NULL, LS_SIZE, },
+	{ "signal1", spufs_signal1_dump, NULL, sizeof(u32) },
 	{ "signal1_type", NULL, spufs_signal1_type_get, 19 },
-	{ "signal2", __spufs_signal2_read, NULL, sizeof(u32) },
+	{ "signal2", spufs_signal2_dump, NULL, sizeof(u32) },
 	{ "signal2_type", NULL, spufs_signal2_type_get, 19 },
 	{ "event_mask", NULL, spufs_event_mask_get, 19 },
 	{ "event_status", NULL, spufs_event_status_get, 19 },
-	{ "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) },
-	{ "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) },
-	{ "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)},
-	{ "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)},
-	{ "proxydma_info", __spufs_proxydma_info_read,
+	{ "mbox_info", spufs_mbox_info_dump, NULL, sizeof(u32) },
+	{ "ibox_info", spufs_ibox_info_dump, NULL, sizeof(u32) },
+	{ "wbox_info", spufs_wbox_info_dump, NULL, 4 * sizeof(u32)},
+	{ "dma_info", spufs_dma_info_dump, NULL, sizeof(struct spu_dma_info)},
+	{ "proxydma_info", spufs_proxydma_info_dump,
 			   NULL, sizeof(struct spu_proxydma_info)},
 	{ "object-id", NULL, spufs_object_id_get, 19 },
 	{ "npc", NULL, spufs_npc_get, 19 },
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 413c89afe112..1ba4d884febf 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -337,8 +337,7 @@ void spufs_dma_callback(struct spu *spu, int type);
 extern struct spu_coredump_calls spufs_coredump_calls;
 struct spufs_coredump_reader {
 	char *name;
-	ssize_t (*read)(struct spu_context *ctx,
-			char __user *buffer, size_t size, loff_t *pos);
+	ssize_t (*dump)(struct spu_context *ctx, struct coredump_params *cprm);
 	u64 (*get)(struct spu_context *ctx);
 	size_t size;
 };
-- 
2.25.1


^ permalink raw reply related

* remove set_fs calls from the exec and coredump code v2
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman

Hi all,

this series gets rid of playing with the address limit in the exec and
coredump code.  Most of this was fairly trivial, the biggest changes are
those to the spufs coredump code.

Changes since v1:
 - properly spell NUL
 - properly handle the compat siginfo case in ELF coredumps

^ permalink raw reply

* [PATCH 2/8] signal: clean up __copy_siginfo_to_user32
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

Instead of an architecture specific calling convention in common code
just pass a flags argument with architecture specific values.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 arch/x86/ia32/ia32_signal.c   |  2 +-
 arch/x86/include/asm/compat.h |  4 ----
 arch/x86/include/asm/signal.h |  3 +++
 arch/x86/kernel/signal.c      |  3 ++-
 include/linux/compat.h        |  2 ++
 kernel/signal.c               | 21 ++++++++++++---------
 6 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index f9d8804144d0..2bf188942d5c 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -350,7 +350,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
 	unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault);
 	user_access_end();
 
-	if (__copy_siginfo_to_user32(&frame->info, &ksig->info, false))
+	if (__copy_siginfo_to_user32(&frame->info, &ksig->info, SA_IA32_ABI))
 		return -EFAULT;
 
 	/* Set up registers for signal handler */
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 52e9f3480f69..a787c9a82030 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -213,8 +213,4 @@ static inline bool in_compat_syscall(void)
 #define in_compat_syscall in_compat_syscall	/* override the generic impl */
 #endif
 
-struct compat_siginfo;
-int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
-		const kernel_siginfo_t *from, bool x32_ABI);
-
 #endif /* _ASM_X86_COMPAT_H */
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 33d3c88a7225..b3f7a14da428 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -28,6 +28,9 @@ typedef struct {
 #define SA_IA32_ABI	0x02000000u
 #define SA_X32_ABI	0x01000000u
 
+#define compat_siginfo_flags() \
+	(in_x32_syscall() ? SA_X32_ABI : SA_IA32_ABI)
+
 #ifndef CONFIG_COMPAT
 typedef sigset_t compat_sigset_t;
 #endif
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 83b74fb38c8f..bbd451631790 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -543,7 +543,8 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
 	user_access_end();
 
 	if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
-		if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
+		if (__copy_siginfo_to_user32(&frame->info, &ksig->info,
+				SA_X32_ABI))
 			return -EFAULT;
 	}
 
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 0480ba4db592..14eec6116110 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -404,6 +404,8 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
 		       unsigned long bitmap_size);
 int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
 int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
+int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
+		const kernel_siginfo_t *from, unsigned int flags);
 int get_compat_sigevent(struct sigevent *event,
 		const struct compat_sigevent __user *u_event);
 
diff --git a/kernel/signal.c b/kernel/signal.c
index e58a6c619824..092fee008242 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3235,15 +3235,8 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
 }
 
 #ifdef CONFIG_COMPAT
-int copy_siginfo_to_user32(struct compat_siginfo __user *to,
-			   const struct kernel_siginfo *from)
-#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
-{
-	return __copy_siginfo_to_user32(to, from, in_x32_syscall());
-}
 int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
-			     const struct kernel_siginfo *from, bool x32_ABI)
-#endif
+		const struct kernel_siginfo *from, unsigned int flags)
 {
 	struct compat_siginfo new;
 	memset(&new, 0, sizeof(new));
@@ -3298,7 +3291,7 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
 		new.si_uid    = from->si_uid;
 		new.si_status = from->si_status;
 #ifdef CONFIG_X86_X32_ABI
-		if (x32_ABI) {
+		if (flags & SA_X32_ABI) {
 			new._sifields._sigchld_x32._utime = from->si_utime;
 			new._sifields._sigchld_x32._stime = from->si_stime;
 		} else
@@ -3326,6 +3319,16 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
 	return 0;
 }
 
+#ifndef compat_siginfo_flags
+#define compat_siginfo_flags()		0
+#endif
+
+int copy_siginfo_to_user32(struct compat_siginfo __user *to,
+			   const struct kernel_siginfo *from)
+{
+	return __copy_siginfo_to_user32(to, from, compat_siginfo_flags());
+}
+
 static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
 					 const struct compat_siginfo *from)
 {
-- 
2.25.1


^ permalink raw reply related

* [PATCH 3/8] signal: replace __copy_siginfo_to_user32 with to_compat_siginfo
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

Move copying the siginfo to userspace into the callers, so that the
compat_siginfo conversion can be reused by the ELF coredump code without
set_fs magic.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 arch/x86/ia32/ia32_signal.c |  4 +-
 arch/x86/kernel/signal.c    |  5 ++-
 include/linux/compat.h      |  4 +-
 kernel/signal.c             | 89 ++++++++++++++++++-------------------
 4 files changed, 52 insertions(+), 50 deletions(-)

diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 2bf188942d5c..0fbaed2562bc 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -301,6 +301,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
 			compat_sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe_ia32 __user *frame;
+	struct compat_siginfo new;
 	void __user *restorer;
 	void __user *fp = NULL;
 
@@ -350,7 +351,8 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
 	unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault);
 	user_access_end();
 
-	if (__copy_siginfo_to_user32(&frame->info, &ksig->info, SA_IA32_ABI))
+	to_compat_siginfo(&new, &ksig->info, SA_IA32_ABI);
+	if (copy_to_user(&frame->info, &new, sizeof(frame->info)))
 		return -EFAULT;
 
 	/* Set up registers for signal handler */
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index bbd451631790..6ff1265f071b 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -517,6 +517,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
 {
 #ifdef CONFIG_X86_X32_ABI
 	struct rt_sigframe_x32 __user *frame;
+	struct compat_siginfo new;
 	unsigned long uc_flags;
 	void __user *restorer;
 	void __user *fp = NULL;
@@ -543,8 +544,8 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
 	user_access_end();
 
 	if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
-		if (__copy_siginfo_to_user32(&frame->info, &ksig->info,
-				SA_X32_ABI))
+		to_compat_siginfo(&new, &ksig->info, SA_X32_ABI);
+		if (copy_to_user(&frame->info, &new, sizeof(frame->info)))
 			return -EFAULT;
 	}
 
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 14eec6116110..218ebba1e454 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -404,8 +404,8 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
 		       unsigned long bitmap_size);
 int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
 int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
-int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
-		const kernel_siginfo_t *from, unsigned int flags);
+void to_compat_siginfo(struct compat_siginfo *to,
+		const struct kernel_siginfo *from, unsigned int flags);
 int get_compat_sigevent(struct sigevent *event,
 		const struct compat_sigevent __user *u_event);
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 092fee008242..0f3e7fded3a5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3235,88 +3235,82 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
 }
 
 #ifdef CONFIG_COMPAT
-int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
+void to_compat_siginfo(struct compat_siginfo *to,
 		const struct kernel_siginfo *from, unsigned int flags)
 {
-	struct compat_siginfo new;
-	memset(&new, 0, sizeof(new));
+	memset(to, 0, sizeof(*to));
+	to->si_signo = from->si_signo;
+	to->si_errno = from->si_errno;
+	to->si_code  = from->si_code;
 
-	new.si_signo = from->si_signo;
-	new.si_errno = from->si_errno;
-	new.si_code  = from->si_code;
-	switch(siginfo_layout(from->si_signo, from->si_code)) {
+	switch (siginfo_layout(from->si_signo, from->si_code)) {
 	case SIL_KILL:
-		new.si_pid = from->si_pid;
-		new.si_uid = from->si_uid;
+		to->si_pid = from->si_pid;
+		to->si_uid = from->si_uid;
 		break;
 	case SIL_TIMER:
-		new.si_tid     = from->si_tid;
-		new.si_overrun = from->si_overrun;
-		new.si_int     = from->si_int;
+		to->si_tid     = from->si_tid;
+		to->si_overrun = from->si_overrun;
+		to->si_int     = from->si_int;
 		break;
 	case SIL_POLL:
-		new.si_band = from->si_band;
-		new.si_fd   = from->si_fd;
+		to->si_band = from->si_band;
+		to->si_fd   = from->si_fd;
 		break;
 	case SIL_FAULT:
-		new.si_addr = ptr_to_compat(from->si_addr);
+		to->si_addr = ptr_to_compat(from->si_addr);
 #ifdef __ARCH_SI_TRAPNO
-		new.si_trapno = from->si_trapno;
+		to->si_trapno = from->si_trapno;
 #endif
 		break;
 	case SIL_FAULT_MCEERR:
-		new.si_addr = ptr_to_compat(from->si_addr);
+		to->si_addr = ptr_to_compat(from->si_addr);
 #ifdef __ARCH_SI_TRAPNO
-		new.si_trapno = from->si_trapno;
+		to->si_trapno = from->si_trapno;
 #endif
-		new.si_addr_lsb = from->si_addr_lsb;
+		to->si_addr_lsb = from->si_addr_lsb;
 		break;
 	case SIL_FAULT_BNDERR:
-		new.si_addr = ptr_to_compat(from->si_addr);
+		to->si_addr = ptr_to_compat(from->si_addr);
 #ifdef __ARCH_SI_TRAPNO
-		new.si_trapno = from->si_trapno;
+		to->si_trapno = from->si_trapno;
 #endif
-		new.si_lower = ptr_to_compat(from->si_lower);
-		new.si_upper = ptr_to_compat(from->si_upper);
+		to->si_lower = ptr_to_compat(from->si_lower);
+		to->si_upper = ptr_to_compat(from->si_upper);
 		break;
 	case SIL_FAULT_PKUERR:
-		new.si_addr = ptr_to_compat(from->si_addr);
+		to->si_addr = ptr_to_compat(from->si_addr);
 #ifdef __ARCH_SI_TRAPNO
-		new.si_trapno = from->si_trapno;
+		to->si_trapno = from->si_trapno;
 #endif
-		new.si_pkey = from->si_pkey;
+		to->si_pkey = from->si_pkey;
 		break;
 	case SIL_CHLD:
-		new.si_pid    = from->si_pid;
-		new.si_uid    = from->si_uid;
-		new.si_status = from->si_status;
+		to->si_pid    = from->si_pid;
+		to->si_uid    = from->si_uid;
+		to->si_status = from->si_status;
 #ifdef CONFIG_X86_X32_ABI
 		if (flags & SA_X32_ABI) {
-			new._sifields._sigchld_x32._utime = from->si_utime;
-			new._sifields._sigchld_x32._stime = from->si_stime;
+			to->_sifields._sigchld_x32._utime = from->si_utime;
+			to->_sifields._sigchld_x32._stime = from->si_stime;
 		} else
 #endif
 		{
-			new.si_utime = from->si_utime;
-			new.si_stime = from->si_stime;
+			to->si_utime = from->si_utime;
+			to->si_stime = from->si_stime;
 		}
 		break;
 	case SIL_RT:
-		new.si_pid = from->si_pid;
-		new.si_uid = from->si_uid;
-		new.si_int = from->si_int;
+		to->si_pid = from->si_pid;
+		to->si_uid = from->si_uid;
+		to->si_int = from->si_int;
 		break;
 	case SIL_SYS:
-		new.si_call_addr = ptr_to_compat(from->si_call_addr);
-		new.si_syscall   = from->si_syscall;
-		new.si_arch      = from->si_arch;
+		to->si_call_addr = ptr_to_compat(from->si_call_addr);
+		to->si_syscall   = from->si_syscall;
+		to->si_arch      = from->si_arch;
 		break;
 	}
-
-	if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
-		return -EFAULT;
-
-	return 0;
 }
 
 #ifndef compat_siginfo_flags
@@ -3326,7 +3320,12 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
 int copy_siginfo_to_user32(struct compat_siginfo __user *to,
 			   const struct kernel_siginfo *from)
 {
-	return __copy_siginfo_to_user32(to, from, compat_siginfo_flags());
+	struct compat_siginfo new;
+
+	to_compat_siginfo(&new, from, compat_siginfo_flags());
+	if (copy_to_user(to, &new, sizeof(*to)))
+		return -EFAULT;
+	return 0;
 }
 
 static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
-- 
2.25.1


^ permalink raw reply related

* [PATCH 4/8] binfmt_elf: open code copy_siginfo_to_user to kernelspace buffer
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

Instead of messing with the address limit just open code the trivial
memcpy + memset logic for the native version, and a call to
to_compat_siginfo for the compat version.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/binfmt_elf.c        | 9 +++++----
 fs/compat_binfmt_elf.c | 6 +++++-
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 13f25e241ac4..607c5a5f855e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1553,15 +1553,16 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
 	fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
 }
 
+#ifndef fill_siginfo_note
 static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
 		const kernel_siginfo_t *siginfo)
 {
-	mm_segment_t old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo);
-	set_fs(old_fs);
+	memcpy(csigdata, siginfo, sizeof(struct kernel_siginfo));
+	memset((char *)csigdata + sizeof(struct kernel_siginfo), 0,
+		SI_EXPANSION_SIZE);
 	fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata);
 }
+#endif
 
 #define MAX_FILE_NOTE_SIZE (4*1024*1024)
 /*
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c
index aaad4ca1217e..ab84e095618b 100644
--- a/fs/compat_binfmt_elf.c
+++ b/fs/compat_binfmt_elf.c
@@ -39,7 +39,11 @@
  */
 #define user_long_t		compat_long_t
 #define user_siginfo_t		compat_siginfo_t
-#define copy_siginfo_to_user	copy_siginfo_to_user32
+#define fill_siginfo_note(note, csigdata, siginfo)		\
+do {									\
+	to_compat_siginfo(csigdata, siginfo, compat_siginfo_flags());	\
+	fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); \
+} while (0)
 
 /*
  * The machine-dependent core note format types are defined in elfcore-compat.h,
-- 
2.25.1


^ permalink raw reply related

* [PATCH 5/8] binfmt_elf: remove the set_fs(KERNEL_DS) in elf_core_dump
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

There is no logic in elf_core_dump itself, or in the various arch helpers
called from it which use uaccess routines on kernel pointers, except for
the actual file writes that nicely encapsulated in __kernel_write used by
dump_emit.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/binfmt_elf.c | 40 +++++++++++++---------------------------
 1 file changed, 13 insertions(+), 27 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 607c5a5f855e..a53a6faa34b1 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1355,7 +1355,6 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
 	    vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
 		u32 __user *header = (u32 __user *) vma->vm_start;
 		u32 word;
-		mm_segment_t fs = get_fs();
 		/*
 		 * Doing it this way gets the constant folded by GCC.
 		 */
@@ -1368,14 +1367,8 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
 		magic.elfmag[EI_MAG1] = ELFMAG1;
 		magic.elfmag[EI_MAG2] = ELFMAG2;
 		magic.elfmag[EI_MAG3] = ELFMAG3;
-		/*
-		 * Switch to the user "segment" for get_user(),
-		 * then put back what elf_core_dump() had in place.
-		 */
-		set_fs(USER_DS);
 		if (unlikely(get_user(word, header)))
 			word = 0;
-		set_fs(fs);
 		if (word == magic.cmp)
 			return PAGE_SIZE;
 	}
@@ -2187,7 +2180,6 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
 static int elf_core_dump(struct coredump_params *cprm)
 {
 	int has_dumped = 0;
-	mm_segment_t fs;
 	int segs, i;
 	size_t vma_data_size = 0;
 	struct vm_area_struct *vma, *gate_vma;
@@ -2240,9 +2232,6 @@ static int elf_core_dump(struct coredump_params *cprm)
 
 	has_dumped = 1;
 
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-
 	offset += sizeof(elf);				/* Elf header */
 	offset += segs * sizeof(struct elf_phdr);	/* Program headers */
 
@@ -2254,7 +2243,7 @@ static int elf_core_dump(struct coredump_params *cprm)
 
 		phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
 		if (!phdr4note)
-			goto end_coredump;
+			goto cleanup;
 
 		fill_elf_note_phdr(phdr4note, sz, offset);
 		offset += sz;
@@ -2269,7 +2258,7 @@ static int elf_core_dump(struct coredump_params *cprm)
 	vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)),
 			      GFP_KERNEL);
 	if (!vma_filesz)
-		goto end_coredump;
+		goto cleanup;
 
 	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
@@ -2287,17 +2276,17 @@ static int elf_core_dump(struct coredump_params *cprm)
 	if (e_phnum == PN_XNUM) {
 		shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
 		if (!shdr4extnum)
-			goto end_coredump;
+			goto cleanup;
 		fill_extnum_info(&elf, shdr4extnum, e_shoff, segs);
 	}
 
 	offset = dataoff;
 
 	if (!dump_emit(cprm, &elf, sizeof(elf)))
-		goto end_coredump;
+		goto cleanup;
 
 	if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
-		goto end_coredump;
+		goto cleanup;
 
 	/* Write program headers for segments dump */
 	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
@@ -2319,22 +2308,22 @@ static int elf_core_dump(struct coredump_params *cprm)
 		phdr.p_align = ELF_EXEC_PAGESIZE;
 
 		if (!dump_emit(cprm, &phdr, sizeof(phdr)))
-			goto end_coredump;
+			goto cleanup;
 	}
 
 	if (!elf_core_write_extra_phdrs(cprm, offset))
-		goto end_coredump;
+		goto cleanup;
 
  	/* write out the notes section */
 	if (!write_note_info(&info, cprm))
-		goto end_coredump;
+		goto cleanup;
 
 	if (elf_coredump_extra_notes_write(cprm))
-		goto end_coredump;
+		goto cleanup;
 
 	/* Align to page */
 	if (!dump_skip(cprm, dataoff - cprm->pos))
-		goto end_coredump;
+		goto cleanup;
 
 	for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
@@ -2356,22 +2345,19 @@ static int elf_core_dump(struct coredump_params *cprm)
 			} else
 				stop = !dump_skip(cprm, PAGE_SIZE);
 			if (stop)
-				goto end_coredump;
+				goto cleanup;
 		}
 	}
 	dump_truncate(cprm);
 
 	if (!elf_core_write_extra_data(cprm))
-		goto end_coredump;
+		goto cleanup;
 
 	if (e_phnum == PN_XNUM) {
 		if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
-			goto end_coredump;
+			goto cleanup;
 	}
 
-end_coredump:
-	set_fs(fs);
-
 cleanup:
 	free_note_info(&info);
 	kfree(shdr4extnum);
-- 
2.25.1


^ permalink raw reply related

* [PATCH 6/8] binfmt_elf_fdpic: remove the set_fs(KERNEL_DS) in elf_fdpic_core_dump
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

There is no logic in elf_fdpic_core_dump itself that uses uaccess
routines on kernel pointers, the file writes are nicely encapsulated in
dump_emit which does its own set_fs.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/binfmt_elf_fdpic.c | 31 ++++++++++++-------------------
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 240f66663543..c62c17a5c34a 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1549,7 +1549,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 {
 #define	NUM_NOTES	6
 	int has_dumped = 0;
-	mm_segment_t fs;
 	int segs;
 	int i;
 	struct vm_area_struct *vma;
@@ -1678,9 +1677,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 			  "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
 #endif
 
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-
 	offset += sizeof(*elf);				/* Elf header */
 	offset += segs * sizeof(struct elf_phdr);	/* Program headers */
 
@@ -1695,7 +1691,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 
 		phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
 		if (!phdr4note)
-			goto end_coredump;
+			goto cleanup;
 
 		fill_elf_note_phdr(phdr4note, sz, offset);
 		offset += sz;
@@ -1711,17 +1707,17 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 	if (e_phnum == PN_XNUM) {
 		shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
 		if (!shdr4extnum)
-			goto end_coredump;
+			goto cleanup;
 		fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
 	}
 
 	offset = dataoff;
 
 	if (!dump_emit(cprm, elf, sizeof(*elf)))
-		goto end_coredump;
+		goto cleanup;
 
 	if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
-		goto end_coredump;
+		goto cleanup;
 
 	/* write program headers for segments dump */
 	for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
@@ -1745,16 +1741,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 		phdr.p_align = ELF_EXEC_PAGESIZE;
 
 		if (!dump_emit(cprm, &phdr, sizeof(phdr)))
-			goto end_coredump;
+			goto cleanup;
 	}
 
 	if (!elf_core_write_extra_phdrs(cprm, offset))
-		goto end_coredump;
+		goto cleanup;
 
  	/* write out the notes section */
 	for (i = 0; i < numnote; i++)
 		if (!writenote(notes + i, cprm))
-			goto end_coredump;
+			goto cleanup;
 
 	/* write out the thread status notes section */
 	list_for_each(t, &thread_list) {
@@ -1763,21 +1759,21 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 
 		for (i = 0; i < tmp->num_notes; i++)
 			if (!writenote(&tmp->notes[i], cprm))
-				goto end_coredump;
+				goto cleanup;
 	}
 
 	if (!dump_skip(cprm, dataoff - cprm->pos))
-		goto end_coredump;
+		goto cleanup;
 
 	if (!elf_fdpic_dump_segments(cprm))
-		goto end_coredump;
+		goto cleanup;
 
 	if (!elf_core_write_extra_data(cprm))
-		goto end_coredump;
+		goto cleanup;
 
 	if (e_phnum == PN_XNUM) {
 		if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
-			goto end_coredump;
+			goto cleanup;
 	}
 
 	if (cprm->file->f_pos != offset) {
@@ -1787,9 +1783,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 		       cprm->file->f_pos, offset);
 	}
 
-end_coredump:
-	set_fs(fs);
-
 cleanup:
 	while (!list_empty(&thread_list)) {
 		struct list_head *tmp = thread_list.next;
-- 
2.25.1


^ permalink raw reply related

* [PATCH 7/8] exec: simplify the copy_strings_kernel calling convention
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

copy_strings_kernel is always used with a single argument,
adjust the calling convention to that.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/binfmt_em86.c        |  6 +++---
 fs/binfmt_misc.c        |  4 ++--
 fs/binfmt_script.c      |  6 +++---
 fs/exec.c               | 13 ++++++-------
 include/linux/binfmts.h |  3 +--
 5 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 466497860c62..f33fa668c91f 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -68,15 +68,15 @@ static int load_em86(struct linux_binprm *bprm)
 	 * user environment and arguments are stored.
 	 */
 	remove_arg_zero(bprm);
-	retval = copy_strings_kernel(1, &bprm->filename, bprm);
+	retval = copy_string_kernel(bprm->filename, bprm);
 	if (retval < 0) return retval; 
 	bprm->argc++;
 	if (i_arg) {
-		retval = copy_strings_kernel(1, &i_arg, bprm);
+		retval = copy_string_kernel(i_arg, bprm);
 		if (retval < 0) return retval; 
 		bprm->argc++;
 	}
-	retval = copy_strings_kernel(1, &i_name, bprm);
+	retval = copy_string_kernel(i_name, bprm);
 	if (retval < 0)	return retval;
 	bprm->argc++;
 
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index cdb45829354d..b15257d8ff5e 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -190,13 +190,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
 		bprm->file = NULL;
 	}
 	/* make argv[1] be the path to the binary */
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
+	retval = copy_string_kernel(bprm->interp, bprm);
 	if (retval < 0)
 		goto error;
 	bprm->argc++;
 
 	/* add the interp as argv[0] */
-	retval = copy_strings_kernel(1, &fmt->interpreter, bprm);
+	retval = copy_string_kernel(fmt->interpreter, bprm);
 	if (retval < 0)
 		goto error;
 	bprm->argc++;
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index e9e6a6f4a35f..c4fb7f52a46e 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -117,17 +117,17 @@ static int load_script(struct linux_binprm *bprm)
 	retval = remove_arg_zero(bprm);
 	if (retval)
 		return retval;
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
+	retval = copy_string_kernel(bprm->interp, bprm);
 	if (retval < 0)
 		return retval;
 	bprm->argc++;
 	if (i_arg) {
-		retval = copy_strings_kernel(1, &i_arg, bprm);
+		retval = copy_string_kernel(i_arg, bprm);
 		if (retval < 0)
 			return retval;
 		bprm->argc++;
 	}
-	retval = copy_strings_kernel(1, &i_name, bprm);
+	retval = copy_string_kernel(i_name, bprm);
 	if (retval)
 		return retval;
 	bprm->argc++;
diff --git a/fs/exec.c b/fs/exec.c
index 06b4c550af5d..b2a77d5acede 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -588,24 +588,23 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
 }
 
 /*
- * Like copy_strings, but get argv and its values from kernel memory.
+ * Copy and argument/environment string from the kernel to the processes stack.
  */
-int copy_strings_kernel(int argc, const char *const *__argv,
-			struct linux_binprm *bprm)
+int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
 {
 	int r;
 	mm_segment_t oldfs = get_fs();
 	struct user_arg_ptr argv = {
-		.ptr.native = (const char __user *const  __user *)__argv,
+		.ptr.native = (const char __user *const  __user *)&arg,
 	};
 
 	set_fs(KERNEL_DS);
-	r = copy_strings(argc, argv, bprm);
+	r = copy_strings(1, argv, bprm);
 	set_fs(oldfs);
 
 	return r;
 }
-EXPORT_SYMBOL(copy_strings_kernel);
+EXPORT_SYMBOL(copy_string_kernel);
 
 #ifdef CONFIG_MMU
 
@@ -1863,7 +1862,7 @@ static int __do_execve_file(int fd, struct filename *filename,
 	if (retval < 0)
 		goto out;
 
-	retval = copy_strings_kernel(1, &bprm->filename, bprm);
+	retval = copy_string_kernel(bprm->filename, bprm);
 	if (retval < 0)
 		goto out;
 
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index a345d9fed3d8..3d3afe094c97 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -144,8 +144,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
 extern int transfer_args_to_stack(struct linux_binprm *bprm,
 				  unsigned long *sp_location);
 extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm);
-extern int copy_strings_kernel(int argc, const char *const *argv,
-			       struct linux_binprm *bprm);
+int copy_string_kernel(const char *arg, struct linux_binprm *bprm);
 extern void install_exec_creds(struct linux_binprm *bprm);
 extern void set_binfmt(struct linux_binfmt *new);
 extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);
-- 
2.25.1


^ permalink raw reply related

* [PATCH 8/8] exec: open code copy_string_kernel
From: Christoph Hellwig @ 2020-04-14  7:01 UTC (permalink / raw)
  To: Andrew Morton, Alexander Viro
  Cc: Arnd Bergmann, linux-kernel, Jeremy Kerr, linux-fsdevel,
	linuxppc-dev, Eric W . Biederman
In-Reply-To: <20200414070142.288696-1-hch@lst.de>

Currently copy_string_kernel is just a wrapper around copy_strings that
simplifies the calling conventions and uses set_fs to allow passing a
kernel pointer.  But due to the fact the we only need to handle a single
kernel argument pointer, the logic can be sigificantly simplified while
getting rid of the set_fs.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/exec.c | 43 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index b2a77d5acede..ea90af1fb236 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -592,17 +592,42 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
  */
 int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
 {
-	int r;
-	mm_segment_t oldfs = get_fs();
-	struct user_arg_ptr argv = {
-		.ptr.native = (const char __user *const  __user *)&arg,
-	};
+	int len = strnlen(arg, MAX_ARG_STRLEN) + 1 /* terminating NUL */;
+	unsigned long pos = bprm->p;
+
+	if (len == 0)
+		return -EFAULT;
+	if (!valid_arg_len(bprm, len))
+		return -E2BIG;
+
+	/* We're going to work our way backwards. */
+	arg += len;
+	bprm->p -= len;
+	if (IS_ENABLED(CONFIG_MMU) && bprm->p < bprm->argmin)
+		return -E2BIG;
+
+	while (len > 0) {
+		unsigned int bytes_to_copy = min_t(unsigned int, len,
+				min_not_zero(offset_in_page(pos), PAGE_SIZE));
+		struct page *page;
+		char *kaddr;
 
-	set_fs(KERNEL_DS);
-	r = copy_strings(1, argv, bprm);
-	set_fs(oldfs);
+		pos -= bytes_to_copy;
+		arg -= bytes_to_copy;
+		len -= bytes_to_copy;
 
-	return r;
+		page = get_arg_page(bprm, pos, 1);
+		if (!page)
+			return -E2BIG;
+		kaddr = kmap_atomic(page);
+		flush_arg_page(bprm, pos & PAGE_MASK, page);
+		memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy);
+		flush_kernel_dcache_page(page);
+		kunmap_atomic(kaddr);
+		put_arg_page(page);
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL(copy_string_kernel);
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH v8 0/7] ASoC: Add new module driver for new ASRC
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel

Add new module driver for new ASRC in i.MX8MN, several commits
are added for new property fsl,asrc-format

Shengjiu Wang (7):
  ASoC: fsl_asrc: rename asrc_priv to asrc
  ASoC: dt-bindings: fsl_asrc: Add new property fsl,asrc-format
  ASoC: fsl-asoc-card: Support new property fsl,asrc-format
  ASoC: fsl_asrc: Support new property fsl,asrc-format
  ASoC: fsl_asrc: Move common definition to fsl_asrc_common
  ASoC: dt-bindings: fsl_easrc: Add document for EASRC
  ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers

changes in v8
- change get_pair_priv_size to pair_priv_size variable

changes in v7
- updated according to Nicoin's comments.
- add get_pair_priv_size to replace PAIR_PRIVATE_SIZE

changes in v6
- updated according to Nicoin's and Rob's comments.

changes in v5
- Add new property fsl,asrc-format, rather than change fsl,asrc-width
  to fsl,asrc-formt.
- code change for above change.

changes in v4
- Add several commit for changing DT binding asrc-width to asrc-format
- rename asrc_priv to asrc

changes in v3
- add new commit "ASoC: fsl_asrc: Change asrc_width to asrc_format"
- modify binding doc to yaml format
- remove fsl_easrc_dma.c, make fsl_asrc_dma.c useable for easrc.

changes in v2
- change i.MX815 to i.MX8MN
- Add changes in Kconfig and Makefile

 .../devicetree/bindings/sound/fsl,asrc.txt    |    4 +
 .../devicetree/bindings/sound/fsl,easrc.yaml  |  101 +
 sound/soc/fsl/Kconfig                         |   11 +
 sound/soc/fsl/Makefile                        |    2 +
 sound/soc/fsl/fsl-asoc-card.c                 |   24 +-
 sound/soc/fsl/fsl_asrc.c                      |  305 +--
 sound/soc/fsl/fsl_asrc.h                      |   74 +-
 sound/soc/fsl/fsl_asrc_common.h               |  106 +
 sound/soc/fsl/fsl_asrc_dma.c                  |   54 +-
 sound/soc/fsl/fsl_easrc.c                     | 2114 +++++++++++++++++
 sound/soc/fsl/fsl_easrc.h                     |  651 +++++
 11 files changed, 3212 insertions(+), 234 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml
 create mode 100644 sound/soc/fsl/fsl_asrc_common.h
 create mode 100644 sound/soc/fsl/fsl_easrc.c
 create mode 100644 sound/soc/fsl/fsl_easrc.h

-- 
2.21.0


^ permalink raw reply

* [PATCH v8 2/7] ASoC: dt-bindings: fsl_asrc: Add new property fsl, asrc-format
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

In order to support new EASRC and simplify the code structure,
We decide to share the common structure between them. This bring
a problem that EASRC accept format directly from devicetree, but
ASRC accept width from devicetree.

In order to align with new ESARC, we add new property fsl,asrc-format.
The fsl,asrc-format can replace the fsl,asrc-width, then driver
can accept format from devicetree, don't need to convert it to
format through width.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 Documentation/devicetree/bindings/sound/fsl,asrc.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
index cb9a25165503..998b4c8a7f78 100644
--- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
@@ -51,6 +51,10 @@ Optional properties:
 			  will be in use as default. Otherwise, the big endian
 			  mode will be in use for all the device registers.
 
+   - fsl,asrc-format	: Defines a mutual sample format used by DPCM Back
+			  Ends, which can replace the fsl,asrc-width.
+			  The value is 2 (S16_LE), or 6 (S24_LE).
+
 Example:
 
 asrc: asrc@2034000 {
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 1/7] ASoC: fsl_asrc: rename asrc_priv to asrc
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

In order to move common structure to fsl_asrc_common.h
we change the name of asrc_priv to asrc, the asrc_priv
will be used by new struct fsl_asrc_priv.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 sound/soc/fsl/fsl_asrc.c     | 298 +++++++++++++++++------------------
 sound/soc/fsl/fsl_asrc.h     |   4 +-
 sound/soc/fsl/fsl_asrc_dma.c |  24 +--
 3 files changed, 163 insertions(+), 163 deletions(-)

diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 0dcebc24c312..4d3e51bfa949 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -21,10 +21,10 @@
 #define IDEAL_RATIO_DECIMAL_DEPTH 26
 
 #define pair_err(fmt, ...) \
-	dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
+	dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
 
 #define pair_dbg(fmt, ...) \
-	dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
+	dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
 
 /* Corresponding to process_option */
 static unsigned int supported_asrc_rate[] = {
@@ -157,15 +157,15 @@ static void fsl_asrc_sel_proc(int inrate, int outrate,
 int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
 {
 	enum asrc_pair_index index = ASRC_INVALID_PAIR;
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
-	struct device *dev = &asrc_priv->pdev->dev;
+	struct fsl_asrc *asrc = pair->asrc;
+	struct device *dev = &asrc->pdev->dev;
 	unsigned long lock_flags;
 	int i, ret = 0;
 
-	spin_lock_irqsave(&asrc_priv->lock, lock_flags);
+	spin_lock_irqsave(&asrc->lock, lock_flags);
 
 	for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
-		if (asrc_priv->pair[i] != NULL)
+		if (asrc->pair[i] != NULL)
 			continue;
 
 		index = i;
@@ -177,17 +177,17 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
 	if (index == ASRC_INVALID_PAIR) {
 		dev_err(dev, "all pairs are busy now\n");
 		ret = -EBUSY;
-	} else if (asrc_priv->channel_avail < channels) {
+	} else if (asrc->channel_avail < channels) {
 		dev_err(dev, "can't afford required channels: %d\n", channels);
 		ret = -EINVAL;
 	} else {
-		asrc_priv->channel_avail -= channels;
-		asrc_priv->pair[index] = pair;
+		asrc->channel_avail -= channels;
+		asrc->pair[index] = pair;
 		pair->channels = channels;
 		pair->index = index;
 	}
 
-	spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
+	spin_unlock_irqrestore(&asrc->lock, lock_flags);
 
 	return ret;
 }
@@ -195,25 +195,25 @@ int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
 /**
  * Release ASRC pair
  *
- * It clears the resource from asrc_priv and releases the occupied channels.
+ * It clears the resource from asrc and releases the occupied channels.
  */
 void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 	unsigned long lock_flags;
 
 	/* Make sure the pair is disabled */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_MASK(index), 0);
 
-	spin_lock_irqsave(&asrc_priv->lock, lock_flags);
+	spin_lock_irqsave(&asrc->lock, lock_flags);
 
-	asrc_priv->channel_avail += pair->channels;
-	asrc_priv->pair[index] = NULL;
+	asrc->channel_avail += pair->channels;
+	asrc->pair[index] = NULL;
 	pair->error = 0;
 
-	spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
+	spin_unlock_irqrestore(&asrc->lock, lock_flags);
 }
 
 /**
@@ -221,10 +221,10 @@ void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
  */
 static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 
-	regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
+	regmap_update_bits(asrc->regmap, REG_ASRMCR(index),
 			   ASRMCRi_EXTTHRSHi_MASK |
 			   ASRMCRi_INFIFO_THRESHOLD_MASK |
 			   ASRMCRi_OUTFIFO_THRESHOLD_MASK,
@@ -257,7 +257,7 @@ static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div)
 static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
 				    int inrate, int outrate)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 	unsigned long ratio;
 	int i;
@@ -286,8 +286,8 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
 			break;
 	}
 
-	regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio);
-	regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24);
+	regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio);
+	regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24);
 
 	return 0;
 }
@@ -309,7 +309,7 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
 static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 {
 	struct asrc_config *config = pair->config;
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 	enum asrc_word_width input_word_width;
 	enum asrc_word_width output_word_width;
@@ -392,11 +392,11 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 	}
 
 	/* Validate input and output clock sources */
-	clk_index[IN] = asrc_priv->clk_map[IN][config->inclk];
-	clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk];
+	clk_index[IN] = asrc->clk_map[IN][config->inclk];
+	clk_index[OUT] = asrc->clk_map[OUT][config->outclk];
 
 	/* We only have output clock for ideal ratio mode */
-	clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
+	clk = asrc->asrck_clk[clk_index[ideal ? OUT : IN]];
 
 	clk_rate = clk_get_rate(clk);
 	rem[IN] = do_div(clk_rate, inrate);
@@ -417,7 +417,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 
 	div[IN] = min_t(u32, 1024, div[IN]);
 
-	clk = asrc_priv->asrck_clk[clk_index[OUT]];
+	clk = asrc->asrck_clk[clk_index[OUT]];
 	clk_rate = clk_get_rate(clk);
 	if (ideal && use_ideal_rate)
 		rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE);
@@ -437,22 +437,22 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 	/* Set the channel number */
 	channels = config->channel_num;
 
-	if (asrc_priv->soc->channel_bits < 4)
+	if (asrc->soc->channel_bits < 4)
 		channels /= 2;
 
 	/* Update channels for current pair */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR,
-			   ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits),
-			   ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits));
+	regmap_update_bits(asrc->regmap, REG_ASRCNCR,
+			   ASRCNCR_ANCi_MASK(index, asrc->soc->channel_bits),
+			   ASRCNCR_ANCi(index, channels, asrc->soc->channel_bits));
 
 	/* Default setting: Automatic selection for processing mode */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index));
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_USRi_MASK(index), 0);
 
 	/* Set the input and output clock sources */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCSR,
+	regmap_update_bits(asrc->regmap, REG_ASRCSR,
 			   ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index),
 			   ASRCSR_AICS(index, clk_index[IN]) |
 			   ASRCSR_AOCS(index, clk_index[OUT]));
@@ -462,19 +462,19 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 	outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]);
 
 	/* Suppose indiv and outdiv includes prescaler, so add its MASK too */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index),
+	regmap_update_bits(asrc->regmap, REG_ASRCDR(index),
 			   ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) |
 			   ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index),
 			   ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv));
 
 	/* Implement word_width configurations */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index),
+	regmap_update_bits(asrc->regmap, REG_ASRMCR1(index),
 			   ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK,
 			   ASRMCR1i_OW16(output_word_width) |
 			   ASRMCR1i_IWD(input_word_width));
 
 	/* Enable BUFFER STALL */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index),
+	regmap_update_bits(asrc->regmap, REG_ASRMCR(index),
 			   ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi);
 
 	/* Set default thresholds for input and output FIFO */
@@ -486,18 +486,18 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 		return 0;
 
 	/* Clear ASTSx bit to use Ideal Ratio mode */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ATSi_MASK(index), 0);
 
 	/* Enable Ideal Ratio mode */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index),
 			   ASRCTR_IDR(index) | ASRCTR_USR(index));
 
 	fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc);
 
 	/* Apply configurations for pre- and post-processing */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+	regmap_update_bits(asrc->regmap, REG_ASRCFG,
 			   ASRCFG_PREMODi_MASK(index) |	ASRCFG_POSTMODi_MASK(index),
 			   ASRCFG_PREMOD(index, pre_proc) |
 			   ASRCFG_POSTMOD(index, post_proc));
@@ -512,28 +512,28 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
  */
 static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 	int reg, retry = 10, i;
 
 	/* Enable the current pair */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index));
 
 	/* Wait for status of initialization */
 	do {
 		udelay(5);
-		regmap_read(asrc_priv->regmap, REG_ASRCFG, &reg);
+		regmap_read(asrc->regmap, REG_ASRCFG, &reg);
 		reg &= ASRCFG_INIRQi_MASK(index);
 	} while (!reg && --retry);
 
 	/* Make the input fifo to ASRC STALL level */
-	regmap_read(asrc_priv->regmap, REG_ASRCNCR, &reg);
+	regmap_read(asrc->regmap, REG_ASRCNCR, &reg);
 	for (i = 0; i < pair->channels * 4; i++)
-		regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0);
+		regmap_write(asrc->regmap, REG_ASRDI(index), 0);
 
 	/* Enable overload interrupt */
-	regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE);
+	regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE);
 }
 
 /**
@@ -541,11 +541,11 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair)
  */
 static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 
 	/* Stop the current pair */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_MASK(index), 0);
 }
 
@@ -554,23 +554,23 @@ static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair)
  */
 struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir)
 {
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	enum asrc_pair_index index = pair->index;
 	char name[4];
 
 	sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a');
 
-	return dma_request_slave_channel(&asrc_priv->pdev->dev, name);
+	return dma_request_slave_channel(&asrc->pdev->dev, name);
 }
 EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel);
 
 static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
-	struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+	struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
 
 	/* Odd channel number is not valid for older ASRC (channel_bits==3) */
-	if (asrc_priv->soc->channel_bits == 3)
+	if (asrc->soc->channel_bits == 3)
 		snd_pcm_hw_constraint_step(substream->runtime, 0,
 					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 
@@ -583,7 +583,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
 				  struct snd_soc_dai *dai)
 {
-	struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+	struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
 	unsigned int channels = params_channels(params);
@@ -600,7 +600,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 
 	pair->config = &config;
 
-	if (asrc_priv->asrc_width == 16)
+	if (asrc->asrc_width == 16)
 		format = SNDRV_PCM_FORMAT_S16_LE;
 	else
 		format = SNDRV_PCM_FORMAT_S24_LE;
@@ -614,11 +614,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 		config.input_format   = params_format(params);
 		config.output_format  = format;
 		config.input_sample_rate  = rate;
-		config.output_sample_rate = asrc_priv->asrc_rate;
+		config.output_sample_rate = asrc->asrc_rate;
 	} else {
 		config.input_format   = format;
 		config.output_format  = params_format(params);
-		config.input_sample_rate  = asrc_priv->asrc_rate;
+		config.input_sample_rate  = asrc->asrc_rate;
 		config.output_sample_rate = rate;
 	}
 
@@ -676,10 +676,10 @@ static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
 
 static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
 {
-	struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
+	struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
 
-	snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx,
-				  &asrc_priv->dma_params_rx);
+	snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx,
+				  &asrc->dma_params_rx);
 
 	return 0;
 }
@@ -858,30 +858,30 @@ static const struct regmap_config fsl_asrc_regmap_config = {
 /**
  * Initialize ASRC registers with a default configurations
  */
-static int fsl_asrc_init(struct fsl_asrc *asrc_priv)
+static int fsl_asrc_init(struct fsl_asrc *asrc)
 {
 	/* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */
-	regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN);
+	regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN);
 
 	/* Disable interrupt by default */
-	regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0);
+	regmap_write(asrc->regmap, REG_ASRIER, 0x0);
 
 	/* Apply recommended settings for parameters from Reference Manual */
-	regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff);
-	regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555);
-	regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280);
-	regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280);
-	regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280);
+	regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff);
+	regmap_write(asrc->regmap, REG_ASRPM2, 0x255555);
+	regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280);
+	regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280);
+	regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280);
 
 	/* Base address for task queue FIFO. Set to 0x7C */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1,
+	regmap_update_bits(asrc->regmap, REG_ASRTFR1,
 			   ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc));
 
 	/* Set the processing clock for 76KHz to 133M */
-	regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6);
+	regmap_write(asrc->regmap, REG_ASR76K, 0x06D6);
 
 	/* Set the processing clock for 56KHz to 133M */
-	return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947);
+	return regmap_write(asrc->regmap, REG_ASR56K, 0x0947);
 }
 
 /**
@@ -889,15 +889,15 @@ static int fsl_asrc_init(struct fsl_asrc *asrc_priv)
  */
 static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
 {
-	struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id;
-	struct device *dev = &asrc_priv->pdev->dev;
+	struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id;
+	struct device *dev = &asrc->pdev->dev;
 	enum asrc_pair_index index;
 	u32 status;
 
-	regmap_read(asrc_priv->regmap, REG_ASRSTR, &status);
+	regmap_read(asrc->regmap, REG_ASRSTR, &status);
 
 	/* Clean overload error */
-	regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE);
+	regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE);
 
 	/*
 	 * We here use dev_dbg() for all exceptions because ASRC itself does
@@ -905,31 +905,31 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
 	 * interrupt would result a ridged conversion.
 	 */
 	for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) {
-		if (!asrc_priv->pair[index])
+		if (!asrc->pair[index])
 			continue;
 
 		if (status & ASRSTR_ATQOL) {
-			asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
+			asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD;
 			dev_dbg(dev, "ASRC Task Queue FIFO overload\n");
 		}
 
 		if (status & ASRSTR_AOOL(index)) {
-			asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
+			asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD;
 			pair_dbg("Output Task Overload\n");
 		}
 
 		if (status & ASRSTR_AIOL(index)) {
-			asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
+			asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD;
 			pair_dbg("Input Task Overload\n");
 		}
 
 		if (status & ASRSTR_AODO(index)) {
-			asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
+			asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW;
 			pair_dbg("Output Data Buffer has overflowed\n");
 		}
 
 		if (status & ASRSTR_AIDU(index)) {
-			asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
+			asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN;
 			pair_dbg("Input Data Buffer has underflowed\n");
 		}
 	}
@@ -940,18 +940,18 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
 static int fsl_asrc_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct fsl_asrc *asrc_priv;
+	struct fsl_asrc *asrc;
 	struct resource *res;
 	void __iomem *regs;
 	int irq, ret, i;
 	u32 map_idx;
 	char tmp[16];
 
-	asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL);
-	if (!asrc_priv)
+	asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL);
+	if (!asrc)
 		return -ENOMEM;
 
-	asrc_priv->pdev = pdev;
+	asrc->pdev = pdev;
 
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -959,13 +959,13 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
 
-	asrc_priv->paddr = res->start;
+	asrc->paddr = res->start;
 
-	asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
-						      &fsl_asrc_regmap_config);
-	if (IS_ERR(asrc_priv->regmap)) {
+	asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
+						 &fsl_asrc_regmap_config);
+	if (IS_ERR(asrc->regmap)) {
 		dev_err(&pdev->dev, "failed to init regmap\n");
-		return PTR_ERR(asrc_priv->regmap);
+		return PTR_ERR(asrc->regmap);
 	}
 
 	irq = platform_get_irq(pdev, 0);
@@ -973,49 +973,49 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 		return irq;
 
 	ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
-			       dev_name(&pdev->dev), asrc_priv);
+			       dev_name(&pdev->dev), asrc);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
 		return ret;
 	}
 
-	asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem");
-	if (IS_ERR(asrc_priv->mem_clk)) {
+	asrc->mem_clk = devm_clk_get(&pdev->dev, "mem");
+	if (IS_ERR(asrc->mem_clk)) {
 		dev_err(&pdev->dev, "failed to get mem clock\n");
-		return PTR_ERR(asrc_priv->mem_clk);
+		return PTR_ERR(asrc->mem_clk);
 	}
 
-	asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
-	if (IS_ERR(asrc_priv->ipg_clk)) {
+	asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(asrc->ipg_clk)) {
 		dev_err(&pdev->dev, "failed to get ipg clock\n");
-		return PTR_ERR(asrc_priv->ipg_clk);
+		return PTR_ERR(asrc->ipg_clk);
 	}
 
-	asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
-	if (IS_ERR(asrc_priv->spba_clk))
+	asrc->spba_clk = devm_clk_get(&pdev->dev, "spba");
+	if (IS_ERR(asrc->spba_clk))
 		dev_warn(&pdev->dev, "failed to get spba clock\n");
 
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
 		sprintf(tmp, "asrck_%x", i);
-		asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
-		if (IS_ERR(asrc_priv->asrck_clk[i])) {
+		asrc->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
+		if (IS_ERR(asrc->asrck_clk[i])) {
 			dev_err(&pdev->dev, "failed to get %s clock\n", tmp);
-			return PTR_ERR(asrc_priv->asrck_clk[i]);
+			return PTR_ERR(asrc->asrck_clk[i]);
 		}
 	}
 
-	asrc_priv->soc = of_device_get_match_data(&pdev->dev);
-	if (!asrc_priv->soc) {
+	asrc->soc = of_device_get_match_data(&pdev->dev);
+	if (!asrc->soc) {
 		dev_err(&pdev->dev, "failed to get soc data\n");
 		return -ENODEV;
 	}
 
 	if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
-		asrc_priv->clk_map[IN] = input_clk_map_imx35;
-		asrc_priv->clk_map[OUT] = output_clk_map_imx35;
+		asrc->clk_map[IN] = input_clk_map_imx35;
+		asrc->clk_map[OUT] = output_clk_map_imx35;
 	} else if (of_device_is_compatible(np, "fsl,imx53-asrc")) {
-		asrc_priv->clk_map[IN] = input_clk_map_imx53;
-		asrc_priv->clk_map[OUT] = output_clk_map_imx53;
+		asrc->clk_map[IN] = input_clk_map_imx53;
+		asrc->clk_map[OUT] = output_clk_map_imx53;
 	} else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") ||
 		   of_device_is_compatible(np, "fsl,imx8qxp-asrc")) {
 		ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx);
@@ -1029,44 +1029,44 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 			return -EINVAL;
 		}
 		if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) {
-			asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx];
-			asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx];
+			asrc->clk_map[IN] = clk_map_imx8qm[map_idx];
+			asrc->clk_map[OUT] = clk_map_imx8qm[map_idx];
 		} else {
-			asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx];
-			asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx];
+			asrc->clk_map[IN] = clk_map_imx8qxp[map_idx];
+			asrc->clk_map[OUT] = clk_map_imx8qxp[map_idx];
 		}
 	}
 
-	ret = fsl_asrc_init(asrc_priv);
+	ret = fsl_asrc_init(asrc);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to init asrc %d\n", ret);
 		return ret;
 	}
 
-	asrc_priv->channel_avail = 10;
+	asrc->channel_avail = 10;
 
 	ret = of_property_read_u32(np, "fsl,asrc-rate",
-				   &asrc_priv->asrc_rate);
+				   &asrc->asrc_rate);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get output rate\n");
 		return ret;
 	}
 
 	ret = of_property_read_u32(np, "fsl,asrc-width",
-				   &asrc_priv->asrc_width);
+				   &asrc->asrc_width);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get output width\n");
 		return ret;
 	}
 
-	if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) {
+	if (asrc->asrc_width != 16 && asrc->asrc_width != 24) {
 		dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
-		asrc_priv->asrc_width = 24;
+		asrc->asrc_width = 24;
 	}
 
-	platform_set_drvdata(pdev, asrc_priv);
+	platform_set_drvdata(pdev, asrc);
 	pm_runtime_enable(&pdev->dev);
-	spin_lock_init(&asrc_priv->lock);
+	spin_lock_init(&asrc->lock);
 
 	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component,
 					      &fsl_asrc_dai, 1);
@@ -1081,22 +1081,22 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int fsl_asrc_runtime_resume(struct device *dev)
 {
-	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+	struct fsl_asrc *asrc = dev_get_drvdata(dev);
 	int i, ret;
 
-	ret = clk_prepare_enable(asrc_priv->mem_clk);
+	ret = clk_prepare_enable(asrc->mem_clk);
 	if (ret)
 		return ret;
-	ret = clk_prepare_enable(asrc_priv->ipg_clk);
+	ret = clk_prepare_enable(asrc->ipg_clk);
 	if (ret)
 		goto disable_mem_clk;
-	if (!IS_ERR(asrc_priv->spba_clk)) {
-		ret = clk_prepare_enable(asrc_priv->spba_clk);
+	if (!IS_ERR(asrc->spba_clk)) {
+		ret = clk_prepare_enable(asrc->spba_clk);
 		if (ret)
 			goto disable_ipg_clk;
 	}
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
-		ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
+		ret = clk_prepare_enable(asrc->asrck_clk[i]);
 		if (ret)
 			goto disable_asrck_clk;
 	}
@@ -1105,27 +1105,27 @@ static int fsl_asrc_runtime_resume(struct device *dev)
 
 disable_asrck_clk:
 	for (i--; i >= 0; i--)
-		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
-	if (!IS_ERR(asrc_priv->spba_clk))
-		clk_disable_unprepare(asrc_priv->spba_clk);
+		clk_disable_unprepare(asrc->asrck_clk[i]);
+	if (!IS_ERR(asrc->spba_clk))
+		clk_disable_unprepare(asrc->spba_clk);
 disable_ipg_clk:
-	clk_disable_unprepare(asrc_priv->ipg_clk);
+	clk_disable_unprepare(asrc->ipg_clk);
 disable_mem_clk:
-	clk_disable_unprepare(asrc_priv->mem_clk);
+	clk_disable_unprepare(asrc->mem_clk);
 	return ret;
 }
 
 static int fsl_asrc_runtime_suspend(struct device *dev)
 {
-	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+	struct fsl_asrc *asrc = dev_get_drvdata(dev);
 	int i;
 
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
-		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
-	if (!IS_ERR(asrc_priv->spba_clk))
-		clk_disable_unprepare(asrc_priv->spba_clk);
-	clk_disable_unprepare(asrc_priv->ipg_clk);
-	clk_disable_unprepare(asrc_priv->mem_clk);
+		clk_disable_unprepare(asrc->asrck_clk[i]);
+	if (!IS_ERR(asrc->spba_clk))
+		clk_disable_unprepare(asrc->spba_clk);
+	clk_disable_unprepare(asrc->ipg_clk);
+	clk_disable_unprepare(asrc->mem_clk);
 
 	return 0;
 }
@@ -1134,37 +1134,37 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int fsl_asrc_suspend(struct device *dev)
 {
-	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+	struct fsl_asrc *asrc = dev_get_drvdata(dev);
 
-	regmap_read(asrc_priv->regmap, REG_ASRCFG,
-		    &asrc_priv->regcache_cfg);
+	regmap_read(asrc->regmap, REG_ASRCFG,
+		    &asrc->regcache_cfg);
 
-	regcache_cache_only(asrc_priv->regmap, true);
-	regcache_mark_dirty(asrc_priv->regmap);
+	regcache_cache_only(asrc->regmap, true);
+	regcache_mark_dirty(asrc->regmap);
 
 	return 0;
 }
 
 static int fsl_asrc_resume(struct device *dev)
 {
-	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+	struct fsl_asrc *asrc = dev_get_drvdata(dev);
 	u32 asrctr;
 
 	/* Stop all pairs provisionally */
-	regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr);
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_read(asrc->regmap, REG_ASRCTR, &asrctr);
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_ALL_MASK, 0);
 
 	/* Restore all registers */
-	regcache_cache_only(asrc_priv->regmap, false);
-	regcache_sync(asrc_priv->regmap);
+	regcache_cache_only(asrc->regmap, false);
+	regcache_sync(asrc->regmap);
 
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+	regmap_update_bits(asrc->regmap, REG_ASRCFG,
 			   ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
-			   ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
+			   ASRCFG_PREMODi_ALL_MASK, asrc->regcache_cfg);
 
 	/* Restart enabled pairs */
-	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
+	regmap_update_bits(asrc->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_ALL_MASK, asrctr);
 
 	return 0;
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 8a821132d9d0..95d62c45afde 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -448,7 +448,7 @@ struct fsl_asrc_soc_data {
 /**
  * fsl_asrc_pair: ASRC Pair private data
  *
- * @asrc_priv: pointer to its parent module
+ * @asrc: pointer to its parent module
  * @config: configuration profile
  * @error: error record
  * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C)
@@ -460,7 +460,7 @@ struct fsl_asrc_soc_data {
  * @private: pair private area
  */
 struct fsl_asrc_pair {
-	struct fsl_asrc *asrc_priv;
+	struct fsl_asrc *asrc;
 	struct asrc_config *config;
 	unsigned int error;
 
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index e7178817d7a7..5fe83aece25b 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -135,7 +135,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
-	struct fsl_asrc *asrc_priv = pair->asrc_priv;
+	struct fsl_asrc *asrc = pair->asrc;
 	struct dma_slave_config config_fe, config_be;
 	enum asrc_pair_index index = pair->index;
 	struct device *dev = component->dev;
@@ -170,7 +170,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 
 	/* Override dma_data of the Front-End and config its dmaengine */
 	dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
-	dma_params_fe->addr = asrc_priv->paddr + REG_ASRDx(!dir, index);
+	dma_params_fe->addr = asrc->paddr + REG_ASRDx(!dir, index);
 	dma_params_fe->maxburst = dma_params_be->maxburst;
 
 	pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir);
@@ -203,7 +203,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	 * need to configure dma_request and dma_request2, but get dma_chan via
 	 * dma_request_slave_channel directly with dma name of Front-End device
 	 */
-	if (!asrc_priv->soc->use_edma) {
+	if (!asrc->soc->use_edma) {
 		/* Get DMA request of Back-End */
 		tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx");
 		tmp_data = tmp_chan->private;
@@ -230,7 +230,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 		return -EINVAL;
 	}
 
-	if (asrc_priv->asrc_width == 16)
+	if (asrc->asrc_width == 16)
 		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
 	else
 		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -242,10 +242,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	config_be.dst_maxburst = dma_params_be->maxburst;
 
 	if (tx) {
-		config_be.src_addr = asrc_priv->paddr + REG_ASRDO(index);
+		config_be.src_addr = asrc->paddr + REG_ASRDO(index);
 		config_be.dst_addr = dma_params_be->addr;
 	} else {
-		config_be.dst_addr = asrc_priv->paddr + REG_ASRDI(index);
+		config_be.dst_addr = asrc->paddr + REG_ASRDI(index);
 		config_be.src_addr = dma_params_be->addr;
 	}
 
@@ -288,7 +288,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_dmaengine_dai_dma_data *dma_data;
 	struct device *dev = component->dev;
-	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
+	struct fsl_asrc *asrc = dev_get_drvdata(dev);
 	struct fsl_asrc_pair *pair;
 	struct dma_chan *tmp_chan = NULL;
 	u8 dir = tx ? OUT : IN;
@@ -306,7 +306,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
 	if (!pair)
 		return -ENOMEM;
 
-	pair->asrc_priv = asrc_priv;
+	pair->asrc = asrc;
 
 	runtime->private_data = pair;
 
@@ -361,15 +361,15 @@ static int fsl_asrc_dma_shutdown(struct snd_soc_component *component,
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
-	struct fsl_asrc *asrc_priv;
+	struct fsl_asrc *asrc;
 
 	if (!pair)
 		return 0;
 
-	asrc_priv = pair->asrc_priv;
+	asrc = pair->asrc;
 
-	if (asrc_priv->pair[pair->index] == pair)
-		asrc_priv->pair[pair->index] = NULL;
+	if (asrc->pair[pair->index] == pair)
+		asrc->pair[pair->index] = NULL;
 
 	kfree(pair);
 
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 3/7] ASoC: fsl-asoc-card: Support new property fsl, asrc-format
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

In order to align with new ESARC, we add new property fsl,asrc-format.
The fsl,asrc-format can replace the fsl,asrc-width, driver
can accept format from devicetree, don't need to convert it to
format through width.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 sound/soc/fsl/fsl-asoc-card.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index bb33601fab84..cf4feb835743 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -680,17 +680,23 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 			goto asrc_fail;
 		}
 
-		ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
+		ret = of_property_read_u32(asrc_np, "fsl,asrc-format",
+					   &priv->asrc_format);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to get output rate\n");
-			ret = -EINVAL;
-			goto asrc_fail;
-		}
+			/* Fallback to old binding; translate to asrc_format */
+			ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
+						   &width);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"failed to decide output format\n");
+				goto asrc_fail;
+			}
 
-		if (width == 24)
-			priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
-		else
-			priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+			if (width == 24)
+				priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+			else
+				priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+		}
 	}
 
 	/* Finish card registering */
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 4/7] ASoC: fsl_asrc: Support new property fsl,asrc-format
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

In order to align with new ESARC, we add new property fsl,asrc-format.
The fsl,asrc-format can replace the fsl,asrc-width, driver
can accept format from devicetree, don't need to convert it to
format through width.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 sound/soc/fsl/fsl_asrc.c     | 41 +++++++++++++++++++++++-------------
 sound/soc/fsl/fsl_asrc.h     |  4 ++--
 sound/soc/fsl/fsl_asrc_dma.c | 15 ++++++++++---
 3 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 4d3e51bfa949..a9458fe268bc 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -589,7 +589,6 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int rate = params_rate(params);
 	struct asrc_config config;
-	snd_pcm_format_t format;
 	int ret;
 
 	ret = fsl_asrc_request_pair(channels, pair);
@@ -600,11 +599,6 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 
 	pair->config = &config;
 
-	if (asrc->asrc_width == 16)
-		format = SNDRV_PCM_FORMAT_S16_LE;
-	else
-		format = SNDRV_PCM_FORMAT_S24_LE;
-
 	config.pair = pair->index;
 	config.channel_num = channels;
 	config.inclk = INCLK_NONE;
@@ -612,11 +606,11 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		config.input_format   = params_format(params);
-		config.output_format  = format;
+		config.output_format  = asrc->asrc_format;
 		config.input_sample_rate  = rate;
 		config.output_sample_rate = asrc->asrc_rate;
 	} else {
-		config.input_format   = format;
+		config.input_format   = asrc->asrc_format;
 		config.output_format  = params_format(params);
 		config.input_sample_rate  = asrc->asrc_rate;
 		config.output_sample_rate = rate;
@@ -946,6 +940,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 	int irq, ret, i;
 	u32 map_idx;
 	char tmp[16];
+	u32 width;
 
 	asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL);
 	if (!asrc)
@@ -1052,16 +1047,32 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = of_property_read_u32(np, "fsl,asrc-width",
-				   &asrc->asrc_width);
+	ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to get output width\n");
-		return ret;
+		ret = of_property_read_u32(np, "fsl,asrc-width", &width);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to decide output format\n");
+			return ret;
+		}
+
+		switch (width) {
+		case 16:
+			asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
+			break;
+		case 24:
+			asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+			break;
+		default:
+			dev_warn(&pdev->dev,
+				 "unsupported width, use default S24_LE\n");
+			asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+			break;
+		}
 	}
 
-	if (asrc->asrc_width != 16 && asrc->asrc_width != 24) {
-		dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
-		asrc->asrc_width = 24;
+	if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) {
+		dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n");
+		asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
 	}
 
 	platform_set_drvdata(pdev, asrc);
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 95d62c45afde..3b0f156af2c3 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -493,7 +493,7 @@ struct fsl_asrc_pair {
  * @channel_avail: non-occupied channel numbers
  * @clk_map: clock map for input/output clock
  * @asrc_rate: default sample rate for ASoC Back-Ends
- * @asrc_width: default sample width for ASoC Back-Ends
+ * @asrc_format: default sample format for ASoC Back-Ends
  * @regcache_cfg: store register value of REG_ASRCFG
  */
 struct fsl_asrc {
@@ -514,7 +514,7 @@ struct fsl_asrc {
 	unsigned char *clk_map[2];
 
 	int asrc_rate;
-	int asrc_width;
+	snd_pcm_format_t asrc_format;
 
 	u32 regcache_cfg;
 };
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 5fe83aece25b..a9dd3155ff35 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -146,7 +146,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	struct device *dev_be;
 	u8 dir = tx ? OUT : IN;
 	dma_cap_mask_t mask;
-	int ret;
+	int ret, width;
 
 	/* Fetch the Back-End dma_data from DPCM */
 	for_each_dpcm_be(rtd, stream, dpcm) {
@@ -230,10 +230,19 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 		return -EINVAL;
 	}
 
-	if (asrc->asrc_width == 16)
+	width = snd_pcm_format_physical_width(asrc->asrc_format);
+	if (width < 8 || width > 64)
+		return -EINVAL;
+	else if (width == 8)
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	else if (width == 16)
 		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-	else
+	else if (width == 24)
+		buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES;
+	else if (width <= 32)
 		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	else
+		buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
 
 	config_be.direction = DMA_DEV_TO_DEV;
 	config_be.src_addr_width = buswidth;
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 6/7] ASoC: dt-bindings: fsl_easrc: Add document for EASRC
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

EASRC (Enhanced Asynchronous Sample Rate Converter) is a new
IP module found on i.MX8MN.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 .../devicetree/bindings/sound/fsl,easrc.yaml  | 101 ++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,easrc.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
new file mode 100644
index 000000000000..14ea60084420
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,easrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Asynchronous Sample Rate Converter (ASRC) Controller
+
+maintainers:
+  - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+properties:
+  $nodename:
+    pattern: "^easrc@.*"
+
+  compatible:
+    const: fsl,imx8mn-easrc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Peripheral clock
+
+  clock-names:
+    items:
+      - const: mem
+
+  dmas:
+    maxItems: 8
+
+  dma-names:
+    items:
+      - const: ctx0_rx
+      - const: ctx0_tx
+      - const: ctx1_rx
+      - const: ctx1_tx
+      - const: ctx2_rx
+      - const: ctx2_tx
+      - const: ctx3_rx
+      - const: ctx3_tx
+
+  firmware-name:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+      - const: imx/easrc/easrc-imx8mn.bin
+    description: The coefficient table for the filters
+
+  fsl,asrc-rate:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 8000
+      - maximum: 192000
+    description: Defines a mutual sample rate used by DPCM Back Ends
+
+  fsl,asrc-format:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [2, 6, 10, 32, 36]
+        default: 2
+    description:
+      Defines a mutual sample format used by DPCM Back Ends
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+  - firmware-name
+  - fsl,asrc-rate
+  - fsl,asrc-format
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mn-clock.h>
+
+    easrc: easrc@300C0000 {
+           compatible = "fsl,imx8mn-easrc";
+           reg = <0x0 0x300C0000 0x0 0x10000>;
+           interrupts = <0x0 122 0x4>;
+           clocks = <&clk IMX8MN_CLK_ASRC_ROOT>;
+           clock-names = "mem";
+           dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>,
+                  <&sdma2 18 23 0> , <&sdma2 19 23 0>,
+                  <&sdma2 20 23 0> , <&sdma2 21 23 0>,
+                  <&sdma2 22 23 0> , <&sdma2 23 23 0>;
+           dma-names = "ctx0_rx", "ctx0_tx",
+                       "ctx1_rx", "ctx1_tx",
+                       "ctx2_rx", "ctx2_tx",
+                       "ctx3_rx", "ctx3_tx";
+           firmware-name = "imx/easrc/easrc-imx8mn.bin";
+           fsl,asrc-rate  = <8000>;
+           fsl,asrc-format = <2>;
+    };
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 5/7] ASoC: fsl_asrc: Move common definition to fsl_asrc_common
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

There is a new ASRC included in i.MX serial platform, there
are some common definition can be shared with each other.
So move the common definition to a separate header file.

And add fsl_asrc_pair_priv and fsl_asrc_priv for
the variable specific for the module, which can be used
internally.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 sound/soc/fsl/fsl_asrc.c        |  82 +++++++++++++++---------
 sound/soc/fsl/fsl_asrc.h        |  74 ++--------------------
 sound/soc/fsl/fsl_asrc_common.h | 106 ++++++++++++++++++++++++++++++++
 sound/soc/fsl/fsl_asrc_dma.c    |  25 ++++----
 4 files changed, 178 insertions(+), 109 deletions(-)
 create mode 100644 sound/soc/fsl/fsl_asrc_common.h

diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index a9458fe268bc..067a54ab554f 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -308,8 +308,10 @@ static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair,
  */
 static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 {
-	struct asrc_config *config = pair->config;
+	struct fsl_asrc_pair_priv *pair_priv = pair->private;
+	struct asrc_config *config = pair_priv->config;
 	struct fsl_asrc *asrc = pair->asrc;
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 	enum asrc_pair_index index = pair->index;
 	enum asrc_word_width input_word_width;
 	enum asrc_word_width output_word_width;
@@ -392,11 +394,11 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 	}
 
 	/* Validate input and output clock sources */
-	clk_index[IN] = asrc->clk_map[IN][config->inclk];
-	clk_index[OUT] = asrc->clk_map[OUT][config->outclk];
+	clk_index[IN] = asrc_priv->clk_map[IN][config->inclk];
+	clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk];
 
 	/* We only have output clock for ideal ratio mode */
-	clk = asrc->asrck_clk[clk_index[ideal ? OUT : IN]];
+	clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]];
 
 	clk_rate = clk_get_rate(clk);
 	rem[IN] = do_div(clk_rate, inrate);
@@ -417,7 +419,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 
 	div[IN] = min_t(u32, 1024, div[IN]);
 
-	clk = asrc->asrck_clk[clk_index[OUT]];
+	clk = asrc_priv->asrck_clk[clk_index[OUT]];
 	clk_rate = clk_get_rate(clk);
 	if (ideal && use_ideal_rate)
 		rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE);
@@ -437,13 +439,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
 	/* Set the channel number */
 	channels = config->channel_num;
 
-	if (asrc->soc->channel_bits < 4)
+	if (asrc_priv->soc->channel_bits < 4)
 		channels /= 2;
 
 	/* Update channels for current pair */
 	regmap_update_bits(asrc->regmap, REG_ASRCNCR,
-			   ASRCNCR_ANCi_MASK(index, asrc->soc->channel_bits),
-			   ASRCNCR_ANCi(index, channels, asrc->soc->channel_bits));
+			   ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits),
+			   ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits));
 
 	/* Default setting: Automatic selection for processing mode */
 	regmap_update_bits(asrc->regmap, REG_ASRCTR,
@@ -568,9 +570,10 @@ static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
 	struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 
 	/* Odd channel number is not valid for older ASRC (channel_bits==3) */
-	if (asrc->soc->channel_bits == 3)
+	if (asrc_priv->soc->channel_bits == 3)
 		snd_pcm_hw_constraint_step(substream->runtime, 0,
 					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 
@@ -586,6 +589,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 	struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
+	struct fsl_asrc_pair_priv *pair_priv = pair->private;
 	unsigned int channels = params_channels(params);
 	unsigned int rate = params_rate(params);
 	struct asrc_config config;
@@ -597,7 +601,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
-	pair->config = &config;
+	pair_priv->config = &config;
 
 	config.pair = pair->index;
 	config.channel_num = channels;
@@ -931,9 +935,15 @@ static irqreturn_t fsl_asrc_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
+{
+	return REG_ASRDx(dir, index);
+}
+
 static int fsl_asrc_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct fsl_asrc_priv *asrc_priv;
 	struct fsl_asrc *asrc;
 	struct resource *res;
 	void __iomem *regs;
@@ -946,7 +956,12 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 	if (!asrc)
 		return -ENOMEM;
 
+	asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL);
+	if (!asrc_priv)
+		return -ENOMEM;
+
 	asrc->pdev = pdev;
+	asrc->private = asrc_priv;
 
 	/* Get the addresses and IRQ */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -992,25 +1007,32 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
 		sprintf(tmp, "asrck_%x", i);
-		asrc->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
-		if (IS_ERR(asrc->asrck_clk[i])) {
+		asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
+		if (IS_ERR(asrc_priv->asrck_clk[i])) {
 			dev_err(&pdev->dev, "failed to get %s clock\n", tmp);
-			return PTR_ERR(asrc->asrck_clk[i]);
+			return PTR_ERR(asrc_priv->asrck_clk[i]);
 		}
 	}
 
-	asrc->soc = of_device_get_match_data(&pdev->dev);
-	if (!asrc->soc) {
+	asrc_priv->soc = of_device_get_match_data(&pdev->dev);
+	if (!asrc_priv->soc) {
 		dev_err(&pdev->dev, "failed to get soc data\n");
 		return -ENODEV;
 	}
 
+	asrc->use_edma = asrc_priv->soc->use_edma;
+	asrc->get_dma_channel = fsl_asrc_get_dma_channel;
+	asrc->request_pair = fsl_asrc_request_pair;
+	asrc->release_pair = fsl_asrc_release_pair;
+	asrc->get_fifo_addr = fsl_asrc_get_fifo_addr;
+	asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv);
+
 	if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
-		asrc->clk_map[IN] = input_clk_map_imx35;
-		asrc->clk_map[OUT] = output_clk_map_imx35;
+		asrc_priv->clk_map[IN] = input_clk_map_imx35;
+		asrc_priv->clk_map[OUT] = output_clk_map_imx35;
 	} else if (of_device_is_compatible(np, "fsl,imx53-asrc")) {
-		asrc->clk_map[IN] = input_clk_map_imx53;
-		asrc->clk_map[OUT] = output_clk_map_imx53;
+		asrc_priv->clk_map[IN] = input_clk_map_imx53;
+		asrc_priv->clk_map[OUT] = output_clk_map_imx53;
 	} else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") ||
 		   of_device_is_compatible(np, "fsl,imx8qxp-asrc")) {
 		ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx);
@@ -1024,11 +1046,11 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 			return -EINVAL;
 		}
 		if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) {
-			asrc->clk_map[IN] = clk_map_imx8qm[map_idx];
-			asrc->clk_map[OUT] = clk_map_imx8qm[map_idx];
+			asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx];
+			asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx];
 		} else {
-			asrc->clk_map[IN] = clk_map_imx8qxp[map_idx];
-			asrc->clk_map[OUT] = clk_map_imx8qxp[map_idx];
+			asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx];
+			asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx];
 		}
 	}
 
@@ -1093,6 +1115,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 static int fsl_asrc_runtime_resume(struct device *dev)
 {
 	struct fsl_asrc *asrc = dev_get_drvdata(dev);
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 	int i, ret;
 
 	ret = clk_prepare_enable(asrc->mem_clk);
@@ -1107,7 +1130,7 @@ static int fsl_asrc_runtime_resume(struct device *dev)
 			goto disable_ipg_clk;
 	}
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
-		ret = clk_prepare_enable(asrc->asrck_clk[i]);
+		ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
 		if (ret)
 			goto disable_asrck_clk;
 	}
@@ -1116,7 +1139,7 @@ static int fsl_asrc_runtime_resume(struct device *dev)
 
 disable_asrck_clk:
 	for (i--; i >= 0; i--)
-		clk_disable_unprepare(asrc->asrck_clk[i]);
+		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
 	if (!IS_ERR(asrc->spba_clk))
 		clk_disable_unprepare(asrc->spba_clk);
 disable_ipg_clk:
@@ -1129,10 +1152,11 @@ static int fsl_asrc_runtime_resume(struct device *dev)
 static int fsl_asrc_runtime_suspend(struct device *dev)
 {
 	struct fsl_asrc *asrc = dev_get_drvdata(dev);
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 	int i;
 
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
-		clk_disable_unprepare(asrc->asrck_clk[i]);
+		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
 	if (!IS_ERR(asrc->spba_clk))
 		clk_disable_unprepare(asrc->spba_clk);
 	clk_disable_unprepare(asrc->ipg_clk);
@@ -1146,9 +1170,10 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
 static int fsl_asrc_suspend(struct device *dev)
 {
 	struct fsl_asrc *asrc = dev_get_drvdata(dev);
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 
 	regmap_read(asrc->regmap, REG_ASRCFG,
-		    &asrc->regcache_cfg);
+		    &asrc_priv->regcache_cfg);
 
 	regcache_cache_only(asrc->regmap, true);
 	regcache_mark_dirty(asrc->regmap);
@@ -1159,6 +1184,7 @@ static int fsl_asrc_suspend(struct device *dev)
 static int fsl_asrc_resume(struct device *dev)
 {
 	struct fsl_asrc *asrc = dev_get_drvdata(dev);
+	struct fsl_asrc_priv *asrc_priv = asrc->private;
 	u32 asrctr;
 
 	/* Stop all pairs provisionally */
@@ -1172,7 +1198,7 @@ static int fsl_asrc_resume(struct device *dev)
 
 	regmap_update_bits(asrc->regmap, REG_ASRCFG,
 			   ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
-			   ASRCFG_PREMODi_ALL_MASK, asrc->regcache_cfg);
+			   ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
 
 	/* Restart enabled pairs */
 	regmap_update_bits(asrc->regmap, REG_ASRCTR,
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 3b0f156af2c3..86d2422ad606 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -10,8 +10,7 @@
 #ifndef _FSL_ASRC_H
 #define _FSL_ASRC_H
 
-#define IN	0
-#define OUT	1
+#include  "fsl_asrc_common.h"
 
 #define ASRC_DMA_BUFFER_NUM		2
 #define ASRC_INPUTFIFO_THRESHOLD	32
@@ -283,14 +282,6 @@
 #define ASRMCR1i_OW16_MASK		(1 << ASRMCR1i_OW16_SHIFT)
 #define ASRMCR1i_OW16(v)		((v) << ASRMCR1i_OW16_SHIFT)
 
-
-enum asrc_pair_index {
-	ASRC_INVALID_PAIR = -1,
-	ASRC_PAIR_A = 0,
-	ASRC_PAIR_B = 1,
-	ASRC_PAIR_C = 2,
-};
-
 #define ASRC_PAIR_MAX_NUM	(ASRC_PAIR_C + 1)
 
 enum asrc_inclk {
@@ -446,83 +437,28 @@ struct fsl_asrc_soc_data {
 };
 
 /**
- * fsl_asrc_pair: ASRC Pair private data
+ * fsl_asrc_pair_priv: ASRC Pair private data
  *
- * @asrc: pointer to its parent module
  * @config: configuration profile
- * @error: error record
- * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C)
- * @channels: occupied channel number
- * @desc: input and output dma descriptors
- * @dma_chan: inputer and output DMA channels
- * @dma_data: private dma data
- * @pos: hardware pointer position
- * @private: pair private area
  */
-struct fsl_asrc_pair {
-	struct fsl_asrc *asrc;
+struct fsl_asrc_pair_priv {
 	struct asrc_config *config;
-	unsigned int error;
-
-	enum asrc_pair_index index;
-	unsigned int channels;
-
-	struct dma_async_tx_descriptor *desc[2];
-	struct dma_chan *dma_chan[2];
-	struct imx_dma_data dma_data;
-	unsigned int pos;
-
-	void *private;
 };
 
 /**
- * fsl_asrc_pair: ASRC private data
+ * fsl_asrc_priv: ASRC private data
  *
- * @dma_params_rx: DMA parameters for receive channel
- * @dma_params_tx: DMA parameters for transmit channel
- * @pdev: platform device pointer
- * @regmap: regmap handler
- * @paddr: physical address to the base address of registers
- * @mem_clk: clock source to access register
- * @ipg_clk: clock source to drive peripheral
- * @spba_clk: SPBA clock (optional, depending on SoC design)
  * @asrck_clk: clock sources to driver ASRC internal logic
- * @lock: spin lock for resource protection
- * @pair: pair pointers
  * @soc: soc specific data
- * @channel_avail: non-occupied channel numbers
  * @clk_map: clock map for input/output clock
- * @asrc_rate: default sample rate for ASoC Back-Ends
- * @asrc_format: default sample format for ASoC Back-Ends
  * @regcache_cfg: store register value of REG_ASRCFG
  */
-struct fsl_asrc {
-	struct snd_dmaengine_dai_dma_data dma_params_rx;
-	struct snd_dmaengine_dai_dma_data dma_params_tx;
-	struct platform_device *pdev;
-	struct regmap *regmap;
-	unsigned long paddr;
-	struct clk *mem_clk;
-	struct clk *ipg_clk;
-	struct clk *spba_clk;
+struct fsl_asrc_priv {
 	struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
-	spinlock_t lock;
-
-	struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM];
 	const struct fsl_asrc_soc_data *soc;
-	unsigned int channel_avail;
 	unsigned char *clk_map[2];
 
-	int asrc_rate;
-	snd_pcm_format_t asrc_format;
-
 	u32 regcache_cfg;
 };
 
-#define DRV_NAME "fsl-asrc-dai"
-extern struct snd_soc_component_driver fsl_asrc_component;
-struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir);
-int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair);
-void fsl_asrc_release_pair(struct fsl_asrc_pair *pair);
-
 #endif /* _FSL_ASRC_H */
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h
new file mode 100644
index 000000000000..77665b15c8db
--- /dev/null
+++ b/sound/soc/fsl/fsl_asrc_common.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#ifndef _FSL_ASRC_COMMON_H
+#define _FSL_ASRC_COMMON_H
+
+/* directions */
+#define IN	0
+#define OUT	1
+
+enum asrc_pair_index {
+	ASRC_INVALID_PAIR = -1,
+	ASRC_PAIR_A = 0,
+	ASRC_PAIR_B = 1,
+	ASRC_PAIR_C = 2,
+	ASRC_PAIR_D = 3,
+};
+
+#define PAIR_CTX_NUM  0x4
+
+/**
+ * fsl_asrc_pair: ASRC Pair common data
+ *
+ * @asrc: pointer to its parent module
+ * @error: error record
+ * @index: pair index (ASRC_PAIR_A, ASRC_PAIR_B, ASRC_PAIR_C)
+ * @channels: occupied channel number
+ * @desc: input and output dma descriptors
+ * @dma_chan: inputer and output DMA channels
+ * @dma_data: private dma data
+ * @pos: hardware pointer position
+ * @private: pair private area
+ */
+struct fsl_asrc_pair {
+	struct fsl_asrc *asrc;
+	unsigned int error;
+
+	enum asrc_pair_index index;
+	unsigned int channels;
+
+	struct dma_async_tx_descriptor *desc[2];
+	struct dma_chan *dma_chan[2];
+	struct imx_dma_data dma_data;
+	unsigned int pos;
+
+	void *private;
+};
+
+/**
+ * fsl_asrc: ASRC common data
+ *
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @paddr: physical address to the base address of registers
+ * @mem_clk: clock source to access register
+ * @ipg_clk: clock source to drive peripheral
+ * @spba_clk: SPBA clock (optional, depending on SoC design)
+ * @lock: spin lock for resource protection
+ * @pair: pair pointers
+ * @channel_avail: non-occupied channel numbers
+ * @asrc_rate: default sample rate for ASoC Back-Ends
+ * @asrc_format: default sample format for ASoC Back-Ends
+ * @use_edma: edma is used
+ * @get_dma_channel: function pointer
+ * @request_pair: function pointer
+ * @release_pair: function pointer
+ * @get_fifo_addr: function pointer
+ * @pair_priv_size: size of pair private struct.
+ * @private: private data structure
+ */
+struct fsl_asrc {
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	unsigned long paddr;
+	struct clk *mem_clk;
+	struct clk *ipg_clk;
+	struct clk *spba_clk;
+	spinlock_t lock;      /* spin lock for resource protection */
+
+	struct fsl_asrc_pair *pair[PAIR_CTX_NUM];
+	unsigned int channel_avail;
+
+	int asrc_rate;
+	snd_pcm_format_t asrc_format;
+	bool use_edma;
+
+	struct dma_chan *(*get_dma_channel)(struct fsl_asrc_pair *pair, bool dir);
+	int (*request_pair)(int channels, struct fsl_asrc_pair *pair);
+	void (*release_pair)(struct fsl_asrc_pair *pair);
+	int (*get_fifo_addr)(u8 dir, enum asrc_pair_index index);
+	size_t pair_priv_size;
+
+	void *private;
+};
+
+#define DRV_NAME "fsl-asrc-dai"
+extern struct snd_soc_component_driver fsl_asrc_component;
+
+#endif /* _FSL_ASRC_COMMON_H */
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index a9dd3155ff35..e5d1b218acf8 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -12,7 +12,7 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm_params.h>
 
-#include "fsl_asrc.h"
+#include "fsl_asrc_common.h"
 
 #define FSL_ASRC_DMABUF_SIZE	(256 * 1024)
 
@@ -170,10 +170,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 
 	/* Override dma_data of the Front-End and config its dmaengine */
 	dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
-	dma_params_fe->addr = asrc->paddr + REG_ASRDx(!dir, index);
+	dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index);
 	dma_params_fe->maxburst = dma_params_be->maxburst;
 
-	pair->dma_chan[!dir] = fsl_asrc_get_dma_channel(pair, !dir);
+	pair->dma_chan[!dir] = asrc->get_dma_channel(pair, !dir);
 	if (!pair->dma_chan[!dir]) {
 		dev_err(dev, "failed to request DMA channel\n");
 		return -EINVAL;
@@ -203,7 +203,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	 * need to configure dma_request and dma_request2, but get dma_chan via
 	 * dma_request_slave_channel directly with dma name of Front-End device
 	 */
-	if (!asrc->soc->use_edma) {
+	if (!asrc->use_edma) {
 		/* Get DMA request of Back-End */
 		tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx");
 		tmp_data = tmp_chan->private;
@@ -211,7 +211,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 		dma_release_channel(tmp_chan);
 
 		/* Get DMA request of Front-End */
-		tmp_chan = fsl_asrc_get_dma_channel(pair, dir);
+		tmp_chan = asrc->get_dma_channel(pair, dir);
 		tmp_data = tmp_chan->private;
 		pair->dma_data.dma_request2 = tmp_data->dma_request;
 		pair->dma_data.peripheral_type = tmp_data->peripheral_type;
@@ -222,7 +222,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 			dma_request_channel(mask, filter, &pair->dma_data);
 	} else {
 		pair->dma_chan[dir] =
-			fsl_asrc_get_dma_channel(pair, dir);
+			asrc->get_dma_channel(pair, dir);
 	}
 
 	if (!pair->dma_chan[dir]) {
@@ -251,10 +251,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
 	config_be.dst_maxburst = dma_params_be->maxburst;
 
 	if (tx) {
-		config_be.src_addr = asrc->paddr + REG_ASRDO(index);
+		config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
 		config_be.dst_addr = dma_params_be->addr;
 	} else {
-		config_be.dst_addr = asrc->paddr + REG_ASRDI(index);
+		config_be.dst_addr = asrc->paddr + asrc->get_fifo_addr(IN, index);
 		config_be.src_addr = dma_params_be->addr;
 	}
 
@@ -311,11 +311,12 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
 		return ret;
 	}
 
-	pair = kzalloc(sizeof(struct fsl_asrc_pair), GFP_KERNEL);
+	pair = kzalloc(sizeof(*pair) + asrc->pair_priv_size, GFP_KERNEL);
 	if (!pair)
 		return -ENOMEM;
 
 	pair->asrc = asrc;
+	pair->private = (void *)pair + sizeof(struct fsl_asrc_pair);
 
 	runtime->private_data = pair;
 
@@ -323,14 +324,14 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
 	 * Request pair function needs channel num as input, for this
 	 * dummy pair, we just request "1" channel temporarily.
 	 */
-	ret = fsl_asrc_request_pair(1, pair);
+	ret = asrc->request_pair(1, pair);
 	if (ret < 0) {
 		dev_err(dev, "failed to request asrc pair\n");
 		goto req_pair_err;
 	}
 
 	/* Request a dummy dma channel, which will be released later. */
-	tmp_chan = fsl_asrc_get_dma_channel(pair, dir);
+	tmp_chan = asrc->get_dma_channel(pair, dir);
 	if (!tmp_chan) {
 		dev_err(dev, "failed to get dma channel\n");
 		ret = -EINVAL;
@@ -356,7 +357,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
 	dma_release_channel(tmp_chan);
 
 dma_chan_err:
-	fsl_asrc_release_pair(pair);
+	asrc->release_pair(pair);
 
 req_pair_err:
 	if (release_pair)
-- 
2.21.0


^ permalink raw reply related

* [PATCH v8 7/7] ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers
From: Shengjiu Wang @ 2020-04-14  6:56 UTC (permalink / raw)
  To: timur, nicoleotsuka, Xiubo.Lee, festevam, broonie, alsa-devel,
	lgirdwood, perex, tiwai, robh+dt, mark.rutland, devicetree
  Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1586845137.git.shengjiu.wang@nxp.com>

EASRC (Enhanced Asynchronous Sample Rate Converter) is a new IP module
found on i.MX8MN. It is different with old ASRC module.

The primary features for the EASRC are as follows:
- 4 Contexts - groups of channels with an independent time base
- Fully independent and concurrent context control
- Simultaneous processing of up to 32 audio channels
- Programmable filter charachteristics for each context
- 32, 24, 20, and 16-bit fixed point audio sample support
- 32-bit floating point audio sample support
- 8kHz to 384kHz sample rate
- 1/16 to 8x sample rate conversion ratio

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Signed-off-by: Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 sound/soc/fsl/Kconfig     |   11 +
 sound/soc/fsl/Makefile    |    2 +
 sound/soc/fsl/fsl_easrc.c | 2114 +++++++++++++++++++++++++++++++++++++
 sound/soc/fsl/fsl_easrc.h |  651 ++++++++++++
 4 files changed, 2778 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_easrc.c
 create mode 100644 sound/soc/fsl/fsl_easrc.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 65e8cd4be930..ea7b4787a8af 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -84,6 +84,17 @@ config SND_SOC_FSL_MICFIL
 	  Say Y if you want to add Pulse Density Modulation microphone
 	  interface (MICFIL) support for NXP.
 
+config SND_SOC_FSL_EASRC
+	tristate "Enhanced Asynchronous Sample Rate Converter (EASRC) module support"
+	depends on SND_SOC_FSL_ASRC
+	select REGMAP_MMIO
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y if you want to add Enhanced ASRC support for NXP. The ASRC is
+	  a digital module that converts audio from a source sample rate to a
+	  destination sample rate. It is a new design module compare with the
+	  old ASRC.
+
 config SND_SOC_FSL_UTILS
 	tristate
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8cde88c72d93..b835eebf8825 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -24,6 +24,7 @@ snd-soc-fsl-micfil-objs := fsl_micfil.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 snd-soc-fsl-mqs-objs := fsl_mqs.o
+snd-soc-fsl-easrc-objs := fsl_easrc.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
 obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
+obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
new file mode 100644
index 000000000000..233f26ff885c
--- /dev/null
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -0,0 +1,2114 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/sched/signal.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/gcd.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+
+#include "fsl_easrc.h"
+#include "imx-pcm.h"
+
+#define FSL_EASRC_FORMATS       (SNDRV_PCM_FMTBIT_S16_LE | \
+				 SNDRV_PCM_FMTBIT_U16_LE | \
+				 SNDRV_PCM_FMTBIT_S24_LE | \
+				 SNDRV_PCM_FMTBIT_S24_3LE | \
+				 SNDRV_PCM_FMTBIT_U24_LE | \
+				 SNDRV_PCM_FMTBIT_U24_3LE | \
+				 SNDRV_PCM_FMTBIT_S32_LE | \
+				 SNDRV_PCM_FMTBIT_U32_LE | \
+				 SNDRV_PCM_FMTBIT_S20_3LE | \
+				 SNDRV_PCM_FMTBIT_U20_3LE | \
+				 SNDRV_PCM_FMTBIT_FLOAT_LE)
+
+static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp);
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	unsigned int regval = ucontrol->value.integer.value[0];
+
+	easrc_priv->bps_iec958[mc->regbase] = regval;
+
+	return 0;
+}
+
+static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	struct fsl_asrc *easrc = snd_soc_component_get_drvdata(comp);
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+
+	ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase];
+
+	return 0;
+}
+
+static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	unsigned int regval;
+	int ret;
+
+	ret = snd_soc_component_read(component, mc->regbase, &regval);
+	if (ret < 0)
+		return ret;
+
+	ucontrol->value.integer.value[0] = regval;
+
+	return 0;
+}
+
+static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_mreg_control *mc =
+		(struct soc_mreg_control *)kcontrol->private_value;
+	unsigned int regval = ucontrol->value.integer.value[0];
+	int ret;
+
+	ret = snd_soc_component_write(component, mc->regbase, regval);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+#define SOC_SINGLE_REG_RW(xname, xreg) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \
+	.put = fsl_easrc_set_reg, \
+	.private_value = (unsigned long)&(struct soc_mreg_control) \
+		{ .regbase = xreg, .regcount = 1, .nbits = 32, \
+		  .invert = 0, .min = 0, .max = 0xffffffff, } }
+
+#define SOC_SINGLE_VAL_RW(xname, xreg) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.info = snd_soc_info_xr_sx, .get = fsl_easrc_iec958_get_bits, \
+	.put = fsl_easrc_iec958_put_bits, \
+	.private_value = (unsigned long)&(struct soc_mreg_control) \
+		{ .regbase = xreg, .regcount = 1, .nbits = 32, \
+		  .invert = 0, .min = 0, .max = 2, } }
+
+static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = {
+	SOC_SINGLE("Context 0 Dither Switch", REG_EASRC_COC(0), 0, 1, 0),
+	SOC_SINGLE("Context 1 Dither Switch", REG_EASRC_COC(1), 0, 1, 0),
+	SOC_SINGLE("Context 2 Dither Switch", REG_EASRC_COC(2), 0, 1, 0),
+	SOC_SINGLE("Context 3 Dither Switch", REG_EASRC_COC(3), 0, 1, 0),
+
+	SOC_SINGLE("Context 0 IEC958 Validity", REG_EASRC_COC(0), 2, 1, 0),
+	SOC_SINGLE("Context 1 IEC958 Validity", REG_EASRC_COC(1), 2, 1, 0),
+	SOC_SINGLE("Context 2 IEC958 Validity", REG_EASRC_COC(2), 2, 1, 0),
+	SOC_SINGLE("Context 3 IEC958 Validity", REG_EASRC_COC(3), 2, 1, 0),
+
+	SOC_SINGLE_VAL_RW("Context 0 IEC958 Bits Per Sample", 0),
+	SOC_SINGLE_VAL_RW("Context 1 IEC958 Bits Per Sample", 1),
+	SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2),
+	SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3),
+
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)),
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)),
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)),
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)),
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)),
+	SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)),
+	SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)),
+	SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)),
+	SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)),
+};
+
+/*
+ * fsl_easrc_set_rs_ratio
+ *
+ * According to the resample taps, calculate the resample ratio
+ * ratio = in_rate / out_rate
+ */
+static int fsl_easrc_set_rs_ratio(struct fsl_asrc_pair *ctx)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+	unsigned int in_rate = ctx_priv->in_params.norm_rate;
+	unsigned int out_rate = ctx_priv->out_params.norm_rate;
+	unsigned int int_bits;
+	unsigned int frac_bits;
+	u64 val;
+	u32 *r;
+
+	switch (easrc_priv->rs_num_taps) {
+	case EASRC_RS_32_TAPS:
+		int_bits = 5;
+		frac_bits = 39;
+		break;
+	case EASRC_RS_64_TAPS:
+		int_bits = 6;
+		frac_bits = 38;
+		break;
+	case EASRC_RS_128_TAPS:
+		int_bits = 7;
+		frac_bits = 37;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = (u64)in_rate << frac_bits;
+	do_div(val, out_rate);
+	r = (uint32_t *)&val;
+
+	if (r[1] & 0xFFFFF000) {
+		dev_err(&easrc->pdev->dev, "ratio exceed range\n");
+		return -EINVAL;
+	}
+
+	regmap_write(easrc->regmap, REG_EASRC_RRL(ctx->index),
+		     EASRC_RRL_RS_RL(r[0]));
+	regmap_write(easrc->regmap, REG_EASRC_RRH(ctx->index),
+		     EASRC_RRH_RS_RH(r[1]));
+
+	return 0;
+}
+
+/* Normalize input and output sample rates */
+static void fsl_easrc_normalize_rates(struct fsl_asrc_pair *ctx)
+{
+	struct fsl_easrc_ctx_priv *ctx_priv;
+	int a, b;
+
+	if (!ctx)
+		return;
+
+	ctx_priv = ctx->private;
+
+	a = ctx_priv->in_params.sample_rate;
+	b = ctx_priv->out_params.sample_rate;
+
+	a = gcd(a, b);
+
+	/* Divide by gcd to normalize the rate */
+	ctx_priv->in_params.norm_rate = ctx_priv->in_params.sample_rate / a;
+	ctx_priv->out_params.norm_rate = ctx_priv->out_params.sample_rate / a;
+}
+
+/* Resets the pointer of the coeff memory pointers */
+static int fsl_easrc_coeff_mem_ptr_reset(struct fsl_asrc *easrc,
+					 unsigned int ctx_id, int mem_type)
+{
+	struct device *dev;
+	u32 reg, mask, val;
+
+	if (!easrc)
+		return -ENODEV;
+
+	dev = &easrc->pdev->dev;
+
+	switch (mem_type) {
+	case EASRC_PF_COEFF_MEM:
+		/* This resets the prefilter memory pointer addr */
+		if (ctx_id >= EASRC_CTX_MAX_NUM) {
+			dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+			return -EINVAL;
+		}
+
+		reg = REG_EASRC_CCE1(ctx_id);
+		mask = EASRC_CCE1_COEF_MEM_RST_MASK;
+		val = EASRC_CCE1_COEF_MEM_RST;
+		break;
+	case EASRC_RS_COEFF_MEM:
+		/* This resets the resampling memory pointer addr */
+		reg = REG_EASRC_CRCC;
+		mask = EASRC_CRCC_RS_CPR_MASK;
+		val = EASRC_CRCC_RS_CPR;
+		break;
+	default:
+		dev_err(dev, "Unknown memory type\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * To reset the write pointer back to zero, the register field
+	 * ASRC_CTX_CTRL_EXT1x[PF_COEFF_MEM_RST] can be toggled from
+	 * 0x0 to 0x1 to 0x0.
+	 */
+	regmap_update_bits(easrc->regmap, reg, mask, 0);
+	regmap_update_bits(easrc->regmap, reg, mask, val);
+	regmap_update_bits(easrc->regmap, reg, mask, 0);
+
+	return 0;
+}
+
+static inline uint32_t bits_taps_to_val(unsigned int t)
+{
+	switch (t) {
+	case EASRC_RS_32_TAPS:
+		return 32;
+	case EASRC_RS_64_TAPS:
+		return 64;
+	case EASRC_RS_128_TAPS:
+		return 128;
+	}
+
+	return 0;
+}
+
+static int fsl_easrc_resampler_config(struct fsl_asrc *easrc)
+{
+	struct device *dev = &easrc->pdev->dev;
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct asrc_firmware_hdr *hdr =  easrc_priv->firmware_hdr;
+	struct interp_params *interp = easrc_priv->interp;
+	struct interp_params *selected_interp = NULL;
+	unsigned int num_coeff;
+	unsigned int i;
+	u64 *coef;
+	u32 *r;
+	int ret;
+
+	if (!hdr) {
+		dev_err(dev, "firmware not loaded!\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < hdr->interp_scen; i++) {
+		if ((interp[i].num_taps - 1) !=
+		    bits_taps_to_val(easrc_priv->rs_num_taps))
+			continue;
+
+		coef = interp[i].coeff;
+		selected_interp = &interp[i];
+		dev_dbg(dev, "Selected interp_filter: %u taps - %u phases\n",
+			selected_interp->num_taps,
+			selected_interp->num_phases);
+		break;
+	}
+
+	if (!selected_interp) {
+		dev_err(dev, "failed to get interpreter configuration\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * RS_LOW - first half of center tap of the sinc function
+	 * RS_HIGH - second half of center tap of the sinc function
+	 * This is due to the fact the resampling function must be
+	 * symetrical - i.e. odd number of taps
+	 */
+	r = (uint32_t *)&selected_interp->center_tap;
+	regmap_write(easrc->regmap, REG_EASRC_RCTCL, EASRC_RCTCL_RS_CL(r[0]));
+	regmap_write(easrc->regmap, REG_EASRC_RCTCH, EASRC_RCTCH_RS_CH(r[1]));
+
+	/*
+	 * Write Number of Resampling Coefficient Taps
+	 * 00b - 32-Tap Resampling Filter
+	 * 01b - 64-Tap Resampling Filter
+	 * 10b - 128-Tap Resampling Filter
+	 * 11b - N/A
+	 */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CRCC,
+			   EASRC_CRCC_RS_TAPS_MASK,
+			   EASRC_CRCC_RS_TAPS(easrc_priv->rs_num_taps));
+
+	/* Reset prefilter coefficient pointer back to 0 */
+	ret = fsl_easrc_coeff_mem_ptr_reset(easrc, 0, EASRC_RS_COEFF_MEM);
+	if (ret)
+		return ret;
+
+	/*
+	 * When the filter is programmed to run in:
+	 * 32-tap mode, 16-taps, 128-phases 4-coefficients per phase
+	 * 64-tap mode, 32-taps, 64-phases 4-coefficients per phase
+	 * 128-tap mode, 64-taps, 32-phases 4-coefficients per phase
+	 * This means the number of writes is constant no matter
+	 * the mode we are using
+	 */
+	num_coeff = 16 * 128 * 4;
+
+	for (i = 0; i < num_coeff; i++) {
+		r = (uint32_t *)&coef[i];
+		regmap_write(easrc->regmap, REG_EASRC_CRCM,
+			     EASRC_CRCM_RS_CWD(r[0]));
+		regmap_write(easrc->regmap, REG_EASRC_CRCM,
+			     EASRC_CRCM_RS_CWD(r[1]));
+	}
+
+	return 0;
+}
+
+/**
+ *  Scale filter coefficients (64 bits float)
+ *  For input float32 normalized range (1.0,-1.0) -> output int[16,24,32]:
+ *      scale it by multiplying filter coefficients by 2^31
+ *  For input int[16, 24, 32] -> output float32
+ *      scale it by multiplying filter coefficients by 2^-15, 2^-23, 2^-31
+ *  input:
+ *      asrc:  Structure pointer of fsl_asrc
+ *      infilter : Pointer to non-scaled input filter
+ *      shift:  The multiply factor
+ *  output:
+ *      outfilter: scaled filter
+ */
+static int fsl_easrc_normalize_filter(struct fsl_asrc *easrc,
+				      u64 *infilter,
+				      u64 *outfilter,
+				      int shift)
+{
+	struct device *dev = &easrc->pdev->dev;
+	u64 coef = *infilter;
+	s64 exp  = (coef & 0x7ff0000000000000ll) >> 52;
+	u64 outcoef;
+
+	/*
+	 * If exponent is zero (value == 0), or 7ff (value == NaNs)
+	 * dont touch the content
+	 */
+	if (exp == 0 || exp == 0x7ff) {
+		*outfilter = coef;
+		return 0;
+	}
+
+	/* coef * 2^shift ==> exp + shift */
+	exp += shift;
+
+	if ((shift > 0 && exp >= 0x7ff) || (shift < 0 && exp <= 0)) {
+		dev_err(dev, "coef out of range\n");
+		return -EINVAL;
+	}
+
+	outcoef = (u64)(coef & 0x800FFFFFFFFFFFFFll) + ((u64)exp << 52);
+	*outfilter = outcoef;
+
+	return 0;
+}
+
+static int fsl_easrc_write_pf_coeff_mem(struct fsl_asrc *easrc, int ctx_id,
+					u64 *coef, int n_taps, int shift)
+{
+	struct device *dev = &easrc->pdev->dev;
+	int ret = 0;
+	int i;
+	u32 *r;
+	u64 tmp;
+
+	/* If STx_NUM_TAPS is set to 0x0 then return */
+	if (!n_taps)
+		return 0;
+
+	if (!coef) {
+		dev_err(dev, "coef table is NULL\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * When switching between stages, the address pointer
+	 * should be reset back to 0x0 before performing a write
+	 */
+	ret = fsl_easrc_coeff_mem_ptr_reset(easrc, ctx_id, EASRC_PF_COEFF_MEM);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < (n_taps + 1) / 2; i++) {
+		ret = fsl_easrc_normalize_filter(easrc, &coef[i], &tmp, shift);
+		if (ret)
+			return ret;
+
+		r = (uint32_t *)&tmp;
+		regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id),
+			     EASRC_PCF_CD(r[0]));
+		regmap_write(easrc->regmap, REG_EASRC_PCF(ctx_id),
+			     EASRC_PCF_CD(r[1]));
+	}
+
+	return 0;
+}
+
+static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc,
+				      unsigned int ctx_id)
+{
+	struct prefil_params *prefil, *selected_prefil = NULL;
+	struct fsl_easrc_ctx_priv *ctx_priv;
+	struct fsl_easrc_priv *easrc_priv;
+	struct asrc_firmware_hdr *hdr;
+	struct fsl_asrc_pair *ctx;
+	struct device *dev;
+	u32 inrate, outrate, offset = 0;
+	u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt;
+	int ret, i;
+
+	if (!easrc)
+		return -ENODEV;
+
+	dev = &easrc->pdev->dev;
+
+	if (ctx_id >= EASRC_CTX_MAX_NUM) {
+		dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+		return -EINVAL;
+	}
+
+	easrc_priv = easrc->private;
+
+	ctx = easrc->pair[ctx_id];
+	ctx_priv = ctx->private;
+
+	in_s_rate = ctx_priv->in_params.sample_rate;
+	out_s_rate = ctx_priv->out_params.sample_rate;
+	in_s_fmt = ctx_priv->in_params.sample_format;
+	out_s_fmt = ctx_priv->out_params.sample_format;
+
+	ctx_priv->in_filled_sample = bits_taps_to_val(easrc_priv->rs_num_taps) / 2;
+	ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate;
+
+	ctx_priv->st1_num_taps = 0;
+	ctx_priv->st2_num_taps = 0;
+
+	regmap_write(easrc->regmap, REG_EASRC_CCE1(ctx_id), 0);
+	regmap_write(easrc->regmap, REG_EASRC_CCE2(ctx_id), 0);
+
+	/*
+	 * The audio float point data range is (-1, 1), the asrc would output
+	 * all zero for float point input and integer output case, that is to
+	 * drop the fractional part of the data directly.
+	 *
+	 * In order to support float to int conversion or int to float
+	 * conversion we need to do special operation on the coefficient to
+	 * enlarge/reduce the data to the expected range.
+	 *
+	 * For float to int case:
+	 * Up sampling:
+	 * 1. Create a 1 tap filter with center tap (only tap) of 2^31
+	 *    in 64 bits floating point.
+	 *    double value = (double)(((uint64_t)1) << 31)
+	 * 2. Program 1 tap prefilter with center tap above.
+	 *
+	 * Down sampling,
+	 * 1. If the filter is single stage filter, add "shift" to the exponent
+	 *    of stage 1 coefficients.
+	 * 2. If the filter is two stage filter , add "shift" to the exponent
+	 *    of stage 2 coefficients.
+	 *
+	 * The "shift" is 31, same for int16, int24, int32 case.
+	 *
+	 * For int to float case:
+	 * Up sampling:
+	 * 1. Create a 1 tap filter with center tap (only tap) of 2^-31
+	 *    in 64 bits floating point.
+	 * 2. Program 1 tap prefilter with center tap above.
+	 *
+	 * Down sampling,
+	 * 1. If the filter is single stage filter, subtract "shift" to the
+	 *    exponent of stage 1 coefficients.
+	 * 2. If the filter is two stage filter , subtract "shift" to the
+	 *    exponent of stage 2 coefficients.
+	 *
+	 * The "shift" is 15,23,31, different for int16, int24, int32 case.
+	 *
+	 */
+	if (out_s_rate >= in_s_rate) {
+		if (out_s_rate == in_s_rate)
+			regmap_update_bits(easrc->regmap,
+					   REG_EASRC_CCE1(ctx_id),
+					   EASRC_CCE1_RS_BYPASS_MASK,
+					   EASRC_CCE1_RS_BYPASS);
+
+		ctx_priv->st1_num_taps = 1;
+		ctx_priv->st1_coeff    = &easrc_priv->const_coeff;
+		ctx_priv->st1_num_exp  = 1;
+		ctx_priv->st2_num_taps = 0;
+
+		if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE &&
+		    out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE)
+			ctx_priv->st1_addexp = 31;
+		else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE &&
+			 out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE)
+			ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp;
+	} else {
+		inrate = ctx_priv->in_params.norm_rate;
+		outrate = ctx_priv->out_params.norm_rate;
+
+		hdr = easrc_priv->firmware_hdr;
+		prefil = easrc_priv->prefil;
+
+		for (i = 0; i < hdr->prefil_scen; i++) {
+			if (inrate == prefil[i].insr &&
+			    outrate == prefil[i].outsr) {
+				selected_prefil = &prefil[i];
+				dev_dbg(dev, "Selected prefilter: %u insr, %u outsr, %u st1_taps, %u st2_taps\n",
+					selected_prefil->insr,
+					selected_prefil->outsr,
+					selected_prefil->st1_taps,
+					selected_prefil->st2_taps);
+				break;
+			}
+		}
+
+		if (!selected_prefil) {
+			dev_err(dev, "Conversion from in ratio %u(%u) to out ratio %u(%u) is not supported\n",
+				in_s_rate, inrate,
+				out_s_rate, outrate);
+			return -EINVAL;
+		}
+
+		/*
+		 * In prefilter coeff array, first st1_num_taps represent the
+		 * stage1 prefilter coefficients followed by next st2_num_taps
+		 * representing stage 2 coefficients
+		 */
+		ctx_priv->st1_num_taps = selected_prefil->st1_taps;
+		ctx_priv->st1_coeff    = selected_prefil->coeff;
+		ctx_priv->st1_num_exp  = selected_prefil->st1_exp;
+
+		offset = ((selected_prefil->st1_taps + 1) / 2);
+		ctx_priv->st2_num_taps = selected_prefil->st2_taps;
+		ctx_priv->st2_coeff    = selected_prefil->coeff + offset;
+
+		if (in_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE &&
+		    out_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE) {
+			/* only change stage2 coefficient for 2 stage case */
+			if (ctx_priv->st2_num_taps > 0)
+				ctx_priv->st2_addexp = 31;
+			else
+				ctx_priv->st1_addexp = 31;
+		} else if (in_s_fmt != SNDRV_PCM_FORMAT_FLOAT_LE &&
+			   out_s_fmt == SNDRV_PCM_FORMAT_FLOAT_LE) {
+			if (ctx_priv->st2_num_taps > 0)
+				ctx_priv->st2_addexp -= ctx_priv->in_params.fmt.addexp;
+			else
+				ctx_priv->st1_addexp -= ctx_priv->in_params.fmt.addexp;
+		}
+	}
+
+	ctx_priv->in_filled_sample += (ctx_priv->st1_num_taps / 2) * ctx_priv->st1_num_exp +
+				  ctx_priv->st2_num_taps / 2;
+	ctx_priv->out_missed_sample = ctx_priv->in_filled_sample * out_s_rate / in_s_rate;
+
+	if (ctx_priv->in_filled_sample * out_s_rate % in_s_rate != 0)
+		ctx_priv->out_missed_sample += 1;
+	/*
+	 * To modify the value of a prefilter coefficient, the user must
+	 * perform a write to the register ASRC_PRE_COEFF_FIFOn[COEFF_DATA]
+	 * while the respective context RUN_EN bit is set to 0b0
+	 */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+			   EASRC_CC_EN_MASK, 0);
+
+	if (ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) {
+		dev_err(dev, "ST1 taps [%d] mus be lower than %d\n",
+			ctx_priv->st1_num_taps, EASRC_MAX_PF_TAPS);
+		ret = -EINVAL;
+		goto ctx_error;
+	}
+
+	/* Update ctx ST1_NUM_TAPS in Context Control Extended 2 register */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id),
+			   EASRC_CCE2_ST1_TAPS_MASK,
+			   EASRC_CCE2_ST1_TAPS(ctx_priv->st1_num_taps - 1));
+
+	/* Prefilter Coefficient Write Select to write in ST1 coeff */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+			   EASRC_CCE1_COEF_WS_MASK,
+			   EASRC_PF_ST1_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT);
+
+	ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id,
+					   ctx_priv->st1_coeff,
+					   ctx_priv->st1_num_taps,
+					   ctx_priv->st1_addexp);
+	if (ret)
+		goto ctx_error;
+
+	if (ctx_priv->st2_num_taps > 0) {
+		if (ctx_priv->st2_num_taps + ctx_priv->st1_num_taps > EASRC_MAX_PF_TAPS) {
+			dev_err(dev, "ST2 taps [%d] mus be lower than %d\n",
+				ctx_priv->st2_num_taps, EASRC_MAX_PF_TAPS);
+			ret = -EINVAL;
+			goto ctx_error;
+		}
+
+		regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+				   EASRC_CCE1_PF_TSEN_MASK,
+				   EASRC_CCE1_PF_TSEN);
+		/*
+		 * Enable prefilter stage1 writeback floating point
+		 * which is used for FLOAT_LE case
+		 */
+		regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+				   EASRC_CCE1_PF_ST1_WBFP_MASK,
+				   EASRC_CCE1_PF_ST1_WBFP);
+
+		regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+				   EASRC_CCE1_PF_EXP_MASK,
+				   EASRC_CCE1_PF_EXP(ctx_priv->st1_num_exp - 1));
+
+		/* Update ctx ST2_NUM_TAPS in Context Control Extended 2 reg */
+		regmap_update_bits(easrc->regmap, REG_EASRC_CCE2(ctx_id),
+				   EASRC_CCE2_ST2_TAPS_MASK,
+				   EASRC_CCE2_ST2_TAPS(ctx_priv->st2_num_taps - 1));
+
+		/* Prefilter Coefficient Write Select to write in ST2 coeff */
+		regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+				   EASRC_CCE1_COEF_WS_MASK,
+				   EASRC_PF_ST2_COEFF_WR << EASRC_CCE1_COEF_WS_SHIFT);
+
+		ret = fsl_easrc_write_pf_coeff_mem(easrc, ctx_id,
+						   ctx_priv->st2_coeff,
+						   ctx_priv->st2_num_taps,
+						   ctx_priv->st2_addexp);
+		if (ret)
+			goto ctx_error;
+	}
+
+	return 0;
+
+ctx_error:
+	return ret;
+}
+
+static int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx,
+				     struct fsl_easrc_slot *slot)
+{
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+	int st1_mem_alloc = 0, st2_mem_alloc = 0;
+	int pf_mem_alloc = 0;
+	int max_channels = 8 - slot->num_channel;
+	int channels = 0;
+
+	if (ctx_priv->st1_num_taps > 0) {
+		if (ctx_priv->st2_num_taps > 0)
+			st1_mem_alloc =
+				(ctx_priv->st1_num_taps - 1) * ctx_priv->st1_num_exp + 1;
+		else
+			st1_mem_alloc = ctx_priv->st1_num_taps;
+	}
+
+	if (ctx_priv->st2_num_taps > 0)
+		st2_mem_alloc = ctx_priv->st2_num_taps;
+
+	pf_mem_alloc = st1_mem_alloc + st2_mem_alloc;
+
+	if (pf_mem_alloc != 0)
+		channels = (6144 - slot->pf_mem_used) / pf_mem_alloc;
+	else
+		channels = 8;
+
+	if (channels < max_channels)
+		max_channels = channels;
+
+	return max_channels;
+}
+
+static int fsl_easrc_config_one_slot(struct fsl_asrc_pair *ctx,
+				     struct fsl_easrc_slot *slot,
+				     unsigned int slot_ctx_idx,
+				     unsigned int *req_channels,
+				     unsigned int *start_channel,
+				     unsigned int *avail_channel)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+	int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc = 0;
+	unsigned int reg0, reg1, reg2, reg3;
+	unsigned int addr;
+
+	if (slot->slot_index == 0) {
+		reg0 = REG_EASRC_DPCS0R0(slot_ctx_idx);
+		reg1 = REG_EASRC_DPCS0R1(slot_ctx_idx);
+		reg2 = REG_EASRC_DPCS0R2(slot_ctx_idx);
+		reg3 = REG_EASRC_DPCS0R3(slot_ctx_idx);
+	} else {
+		reg0 = REG_EASRC_DPCS1R0(slot_ctx_idx);
+		reg1 = REG_EASRC_DPCS1R1(slot_ctx_idx);
+		reg2 = REG_EASRC_DPCS1R2(slot_ctx_idx);
+		reg3 = REG_EASRC_DPCS1R3(slot_ctx_idx);
+	}
+
+	if (*req_channels <= *avail_channel) {
+		slot->num_channel = *req_channels;
+		*req_channels = 0;
+	} else {
+		slot->num_channel = *avail_channel;
+		*req_channels -= *avail_channel;
+	}
+
+	slot->min_channel = *start_channel;
+	slot->max_channel = *start_channel + slot->num_channel - 1;
+	slot->ctx_index = ctx->index;
+	slot->busy = true;
+	*start_channel += slot->num_channel;
+
+	regmap_update_bits(easrc->regmap, reg0,
+			   EASRC_DPCS0R0_MAXCH_MASK,
+			   EASRC_DPCS0R0_MAXCH(slot->max_channel));
+
+	regmap_update_bits(easrc->regmap, reg0,
+			   EASRC_DPCS0R0_MINCH_MASK,
+			   EASRC_DPCS0R0_MINCH(slot->min_channel));
+
+	regmap_update_bits(easrc->regmap, reg0,
+			   EASRC_DPCS0R0_NUMCH_MASK,
+			   EASRC_DPCS0R0_NUMCH(slot->num_channel - 1));
+
+	regmap_update_bits(easrc->regmap, reg0,
+			   EASRC_DPCS0R0_CTXNUM_MASK,
+			   EASRC_DPCS0R0_CTXNUM(slot->ctx_index));
+
+	if (ctx_priv->st1_num_taps > 0) {
+		if (ctx_priv->st2_num_taps > 0)
+			st1_mem_alloc =
+				(ctx_priv->st1_num_taps - 1) * slot->num_channel *
+				ctx_priv->st1_num_exp + slot->num_channel;
+		else
+			st1_mem_alloc = ctx_priv->st1_num_taps * slot->num_channel;
+
+		slot->pf_mem_used = st1_mem_alloc;
+		regmap_update_bits(easrc->regmap, reg2,
+				   EASRC_DPCS0R2_ST1_MA_MASK,
+				   EASRC_DPCS0R2_ST1_MA(st1_mem_alloc));
+
+		if (slot->slot_index == 1)
+			addr = PREFILTER_MEM_LEN - st1_mem_alloc;
+		else
+			addr = 0;
+
+		regmap_update_bits(easrc->regmap, reg2,
+				   EASRC_DPCS0R2_ST1_SA_MASK,
+				   EASRC_DPCS0R2_ST1_SA(addr));
+	}
+
+	if (ctx_priv->st2_num_taps > 0) {
+		st1_chanxexp = slot->num_channel * (ctx_priv->st1_num_exp - 1);
+
+		regmap_update_bits(easrc->regmap, reg1,
+				   EASRC_DPCS0R1_ST1_EXP_MASK,
+				   EASRC_DPCS0R1_ST1_EXP(st1_chanxexp));
+
+		st2_mem_alloc = slot->num_channel * ctx_priv->st2_num_taps;
+		slot->pf_mem_used += st2_mem_alloc;
+		regmap_update_bits(easrc->regmap, reg3,
+				   EASRC_DPCS0R3_ST2_MA_MASK,
+				   EASRC_DPCS0R3_ST2_MA(st2_mem_alloc));
+
+		if (slot->slot_index == 1)
+			addr = PREFILTER_MEM_LEN - st1_mem_alloc - st2_mem_alloc;
+		else
+			addr = st1_mem_alloc;
+
+		regmap_update_bits(easrc->regmap, reg3,
+				   EASRC_DPCS0R3_ST2_SA_MASK,
+				   EASRC_DPCS0R3_ST2_SA(addr));
+	}
+
+	regmap_update_bits(easrc->regmap, reg0,
+			   EASRC_DPCS0R0_EN_MASK, EASRC_DPCS0R0_EN);
+
+	return 0;
+}
+
+/*
+ * fsl_easrc_config_slot
+ *
+ * A single context can be split amongst any of the 4 context processing pipes
+ * in the design.
+ * The total number of channels consumed within the context processor must be
+ * less than or equal to 8. if a single context is configured to contain more
+ * than 8 channels then it must be distributed across multiple context
+ * processing pipe slots.
+ *
+ */
+static int fsl_easrc_config_slot(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct fsl_asrc_pair *ctx = easrc->pair[ctx_id];
+	int req_channels = ctx->channels;
+	int start_channel = 0, avail_channel;
+	struct fsl_easrc_slot *slot0, *slot1;
+	struct fsl_easrc_slot *slota, *slotb;
+	int i, ret;
+
+	if (req_channels <= 0)
+		return -EINVAL;
+
+	for (i = 0; i < EASRC_CTX_MAX_NUM; i++) {
+		slot0 = &easrc_priv->slot[i][0];
+		slot1 = &easrc_priv->slot[i][1];
+
+		if (slot0->busy && slot1->busy) {
+			continue;
+		} else if ((slot0->busy && slot0->ctx_index == ctx->index) ||
+			 (slot1->busy && slot1->ctx_index == ctx->index)) {
+			continue;
+		} else if (!slot0->busy) {
+			slota = slot0;
+			slotb = slot1;
+			slota->slot_index = 0;
+		} else if (!slot1->busy) {
+			slota = slot1;
+			slotb = slot0;
+			slota->slot_index = 1;
+		}
+
+		if (!slota || !slotb)
+			continue;
+
+		avail_channel = fsl_easrc_max_ch_for_slot(ctx, slotb);
+		if (avail_channel <= 0)
+			continue;
+
+		ret = fsl_easrc_config_one_slot(ctx, slota, i, &req_channels,
+						&start_channel, &avail_channel);
+		if (ret)
+			return ret;
+
+		if (req_channels > 0)
+			continue;
+		else
+			break;
+	}
+
+	if (req_channels > 0) {
+		dev_err(&easrc->pdev->dev, "no avail slot.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * fsl_easrc_release_slot
+ *
+ * Clear the slot configuration
+ */
+static int fsl_easrc_release_slot(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct fsl_asrc_pair *ctx = easrc->pair[ctx_id];
+	int i;
+
+	for (i = 0; i < EASRC_CTX_MAX_NUM; i++) {
+		if (easrc_priv->slot[i][0].busy &&
+		    easrc_priv->slot[i][0].ctx_index == ctx->index) {
+			easrc_priv->slot[i][0].busy = false;
+			easrc_priv->slot[i][0].num_channel = 0;
+			easrc_priv->slot[i][0].pf_mem_used = 0;
+			/* set registers */
+			regmap_write(easrc->regmap, REG_EASRC_DPCS0R0(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS0R1(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS0R2(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS0R3(i), 0);
+		}
+
+		if (easrc_priv->slot[i][1].busy &&
+		    easrc_priv->slot[i][1].ctx_index == ctx->index) {
+			easrc_priv->slot[i][1].busy = false;
+			easrc_priv->slot[i][1].num_channel = 0;
+			easrc_priv->slot[i][1].pf_mem_used = 0;
+			/* set registers */
+			regmap_write(easrc->regmap, REG_EASRC_DPCS1R0(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS1R1(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS1R2(i), 0);
+			regmap_write(easrc->regmap, REG_EASRC_DPCS1R3(i), 0);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * fsl_easrc_config_context
+ *
+ * Configure the register relate with context.
+ */
+int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
+{
+	struct fsl_easrc_ctx_priv *ctx_priv;
+	struct fsl_asrc_pair *ctx;
+	struct device *dev;
+	unsigned long lock_flags;
+	int ret;
+
+	if (!easrc)
+		return -ENODEV;
+
+	dev = &easrc->pdev->dev;
+
+	if (ctx_id >= EASRC_CTX_MAX_NUM) {
+		dev_err(dev, "Invalid context id[%d]\n", ctx_id);
+		return -EINVAL;
+	}
+
+	ctx = easrc->pair[ctx_id];
+
+	ctx_priv = ctx->private;
+
+	fsl_easrc_normalize_rates(ctx);
+
+	ret = fsl_easrc_set_rs_ratio(ctx);
+	if (ret)
+		return ret;
+
+	/* Initialize the context coeficients */
+	ret = fsl_easrc_prefilter_config(easrc, ctx->index);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&easrc->lock, lock_flags);
+	ret = fsl_easrc_config_slot(easrc, ctx->index);
+	spin_unlock_irqrestore(&easrc->lock, lock_flags);
+	if (ret)
+		return ret;
+
+	/*
+	 * Both prefilter and resampling filters can use following
+	 * initialization modes:
+	 * 2 - zero-fil mode
+	 * 1 - replication mode
+	 * 0 - software control
+	 */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+			   EASRC_CCE1_RS_INIT_MASK,
+			   EASRC_CCE1_RS_INIT(ctx_priv->rs_init_mode));
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_CCE1(ctx_id),
+			   EASRC_CCE1_PF_INIT_MASK,
+			   EASRC_CCE1_PF_INIT(ctx_priv->pf_init_mode));
+
+	/*
+	 * Context Input FIFO Watermark
+	 * DMA request is generated when input FIFO < FIFO_WTMK
+	 */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+			   EASRC_CC_FIFO_WTMK_MASK,
+			   EASRC_CC_FIFO_WTMK(ctx_priv->in_params.fifo_wtmk));
+
+	/*
+	 * Context Output FIFO Watermark
+	 * DMA request is generated when output FIFO > FIFO_WTMK
+	 * So we set fifo_wtmk -1 to register.
+	 */
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx_id),
+			   EASRC_COC_FIFO_WTMK_MASK,
+			   EASRC_COC_FIFO_WTMK(ctx_priv->out_params.fifo_wtmk - 1));
+
+	/* Number of channels */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx_id),
+			   EASRC_CC_CHEN_MASK,
+			   EASRC_CC_CHEN(ctx->channels - 1));
+	return 0;
+}
+
+static int fsl_easrc_process_format(struct fsl_asrc_pair *ctx,
+				    struct fsl_easrc_data_fmt *fmt,
+				    snd_pcm_format_t raw_fmt)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	int ret;
+
+	if (!fmt)
+		return -EINVAL;
+
+	/*
+	 * Context Input Floating Point Format
+	 * 0 - Integer Format
+	 * 1 - Single Precision FP Format
+	 */
+	fmt->floating_point = !snd_pcm_format_linear(raw_fmt);
+	fmt->sample_pos = 0;
+	fmt->iec958 = 0;
+
+	/* Get the data width */
+	switch (snd_pcm_format_width(raw_fmt)) {
+	case 16:
+		fmt->width = EASRC_WIDTH_16_BIT;
+		fmt->addexp = 15;
+		break;
+	case 20:
+		fmt->width = EASRC_WIDTH_20_BIT;
+		fmt->addexp = 19;
+		break;
+	case 24:
+		fmt->width = EASRC_WIDTH_24_BIT;
+		fmt->addexp = 23;
+		break;
+	case 32:
+		fmt->width = EASRC_WIDTH_32_BIT;
+		fmt->addexp = 31;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (raw_fmt) {
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		fmt->width = easrc_priv->bps_iec958[ctx->index];
+		fmt->iec958 = 1;
+		fmt->floating_point = 0;
+		if (fmt->width == EASRC_WIDTH_16_BIT) {
+			fmt->sample_pos = 12;
+			fmt->addexp = 15;
+		} else if (fmt->width == EASRC_WIDTH_20_BIT) {
+			fmt->sample_pos = 8;
+			fmt->addexp = 19;
+		} else if (fmt->width == EASRC_WIDTH_24_BIT) {
+			fmt->sample_pos = 4;
+			fmt->addexp = 23;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Data Endianness
+	 * 0 - Little-Endian
+	 * 1 - Big-Endian
+	 */
+	ret = snd_pcm_format_big_endian(raw_fmt);
+	if (ret < 0)
+		return ret;
+
+	fmt->endianness = ret;
+
+	/*
+	 * Input Data sign
+	 * 0b - Signed Format
+	 * 1b - Unsigned Format
+	 */
+	fmt->unsign = snd_pcm_format_unsigned(raw_fmt) > 0 ? 1 : 0;
+
+	return 0;
+}
+
+int fsl_easrc_set_ctx_format(struct fsl_asrc_pair *ctx,
+			     snd_pcm_format_t *in_raw_format,
+			     snd_pcm_format_t *out_raw_format)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+	struct fsl_easrc_data_fmt *in_fmt = &ctx_priv->in_params.fmt;
+	struct fsl_easrc_data_fmt *out_fmt = &ctx_priv->out_params.fmt;
+	int ret;
+
+	/* Get the bitfield values for input data format */
+	if (in_raw_format && out_raw_format) {
+		ret = fsl_easrc_process_format(ctx, in_fmt, *in_raw_format);
+		if (ret)
+			return ret;
+	}
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_BPS_MASK,
+			   EASRC_CC_BPS(in_fmt->width));
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_ENDIANNESS_MASK,
+			   in_fmt->endianness << EASRC_CC_ENDIANNESS_SHIFT);
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_FMT_MASK,
+			   in_fmt->floating_point << EASRC_CC_FMT_SHIFT);
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_INSIGN_MASK,
+			   in_fmt->unsign << EASRC_CC_INSIGN_SHIFT);
+
+	/* In Sample Position */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_SAMPLE_POS_MASK,
+			   EASRC_CC_SAMPLE_POS(in_fmt->sample_pos));
+
+	/* Get the bitfield values for input data format */
+	if (in_raw_format && out_raw_format) {
+		ret = fsl_easrc_process_format(ctx, out_fmt, *out_raw_format);
+		if (ret)
+			return ret;
+	}
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_BPS_MASK,
+			   EASRC_COC_BPS(out_fmt->width));
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_ENDIANNESS_MASK,
+			   out_fmt->endianness << EASRC_COC_ENDIANNESS_SHIFT);
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_FMT_MASK,
+			   out_fmt->floating_point << EASRC_COC_FMT_SHIFT);
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_OUTSIGN_MASK,
+			   out_fmt->unsign << EASRC_COC_OUTSIGN_SHIFT);
+
+	/* Out Sample Position */
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_SAMPLE_POS_MASK,
+			   EASRC_COC_SAMPLE_POS(out_fmt->sample_pos));
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_IEC_EN_MASK,
+			   out_fmt->iec958 << EASRC_COC_IEC_EN_SHIFT);
+
+	return ret;
+}
+
+/*
+ * The ASRC provides interleaving support in hardware to ensure that a
+ * variety of sample sources can be internally combined
+ * to conform with this format. Interleaving parameters are accessed
+ * through the ASRC_CTRL_IN_ACCESSa and ASRC_CTRL_OUT_ACCESSa registers
+ */
+int fsl_easrc_set_ctx_organziation(struct fsl_asrc_pair *ctx)
+{
+	struct fsl_easrc_ctx_priv *ctx_priv;
+	struct device *dev;
+	struct fsl_asrc *easrc;
+
+	if (!ctx)
+		return -ENODEV;
+
+	easrc = ctx->asrc;
+	ctx_priv = ctx->private;
+	dev = &easrc->pdev->dev;
+
+	/* input interleaving parameters */
+	regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+			   EASRC_CIA_ITER_MASK,
+			   EASRC_CIA_ITER(ctx_priv->in_params.iterations));
+	regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+			   EASRC_CIA_GRLEN_MASK,
+			   EASRC_CIA_GRLEN(ctx_priv->in_params.group_len));
+	regmap_update_bits(easrc->regmap, REG_EASRC_CIA(ctx->index),
+			   EASRC_CIA_ACCLEN_MASK,
+			   EASRC_CIA_ACCLEN(ctx_priv->in_params.access_len));
+
+	/* output interleaving parameters */
+	regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+			   EASRC_COA_ITER_MASK,
+			   EASRC_COA_ITER(ctx_priv->out_params.iterations));
+	regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+			   EASRC_COA_GRLEN_MASK,
+			   EASRC_COA_GRLEN(ctx_priv->out_params.group_len));
+	regmap_update_bits(easrc->regmap, REG_EASRC_COA(ctx->index),
+			   EASRC_COA_ACCLEN_MASK,
+			   EASRC_COA_ACCLEN(ctx_priv->out_params.access_len));
+
+	return 0;
+}
+
+/*
+ * Request one of the available contexts
+ *
+ * Returns a negative number on error and >=0 as context id
+ * on success
+ */
+int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
+{
+	enum asrc_pair_index index = ASRC_INVALID_PAIR;
+	struct fsl_asrc *easrc = ctx->asrc;
+	struct device *dev;
+	unsigned long lock_flags;
+	int ret = 0;
+	int i;
+
+	dev = &easrc->pdev->dev;
+
+	spin_lock_irqsave(&easrc->lock, lock_flags);
+
+	for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
+		if (easrc->pair[i])
+			continue;
+
+		index = i;
+		break;
+	}
+
+	if (index == ASRC_INVALID_PAIR) {
+		dev_err(dev, "all contexts are busy\n");
+		ret = -EBUSY;
+	} else if (channels > easrc->channel_avail) {
+		dev_err(dev, "can't give the required channels: %d\n",
+			channels);
+		ret = -EINVAL;
+	} else {
+		ctx->index = index;
+		ctx->channels = channels;
+		easrc->pair[index] = ctx;
+		easrc->channel_avail -= channels;
+	}
+
+	spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+	return ret;
+}
+
+/*
+ * Release the context
+ *
+ * This funciton is mainly doing the revert thing in request context
+ */
+void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
+{
+	unsigned long lock_flags;
+	struct fsl_asrc *easrc;
+	struct device *dev;
+
+	if (!ctx)
+		return;
+
+	easrc = ctx->asrc;
+	dev = &easrc->pdev->dev;
+
+	spin_lock_irqsave(&easrc->lock, lock_flags);
+
+	fsl_easrc_release_slot(easrc, ctx->index);
+
+	easrc->channel_avail += ctx->channels;
+	easrc->pair[ctx->index] = NULL;
+
+	spin_unlock_irqrestore(&easrc->lock, lock_flags);
+}
+
+/*
+ * Start the context
+ *
+ * Enable the DMA request and context
+ */
+int fsl_easrc_start_context(struct fsl_asrc_pair *ctx)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_FWMDE_MASK, EASRC_CC_FWMDE);
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_FWMDE_MASK, EASRC_COC_FWMDE);
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_EN_MASK, EASRC_CC_EN);
+	return 0;
+}
+
+/*
+ * Stop the context
+ *
+ * Disable the DMA request and context
+ */
+int fsl_easrc_stop_context(struct fsl_asrc_pair *ctx)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	int val, i;
+	int size = 0;
+	int retry = 200;
+
+	regmap_read(easrc->regmap, REG_EASRC_CC(ctx->index), &val);
+
+	if (val & EASRC_CC_EN_MASK) {
+		regmap_update_bits(easrc->regmap,
+				   REG_EASRC_CC(ctx->index),
+				   EASRC_CC_STOP_MASK, EASRC_CC_STOP);
+		do {
+			regmap_read(easrc->regmap, REG_EASRC_SFS(ctx->index), &val);
+			val &= EASRC_SFS_NSGO_MASK;
+			size = val >> EASRC_SFS_NSGO_SHIFT;
+
+			/* Read FIFO, drop the data */
+			for (i = 0; i < size * ctx->channels; i++)
+				regmap_read(easrc->regmap, REG_EASRC_RDFIFO(ctx->index), &val);
+			/* Check RUN_STOP_DONE */
+			regmap_read(easrc->regmap, REG_EASRC_IRQF, &val);
+			if (val & EASRC_IRQF_RSD(1 << ctx->index)) {
+				/*Clear RUN_STOP_DONE*/
+				regmap_write_bits(easrc->regmap,
+						  REG_EASRC_IRQF,
+						  EASRC_IRQF_RSD(1 << ctx->index),
+						  EASRC_IRQF_RSD(1 << ctx->index));
+				break;
+			}
+			udelay(100);
+		} while (--retry);
+
+		if (retry == 0)
+			dev_warn(&easrc->pdev->dev, "RUN STOP fail\n");
+	}
+
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_EN_MASK | EASRC_CC_STOP_MASK, 0);
+	regmap_update_bits(easrc->regmap, REG_EASRC_CC(ctx->index),
+			   EASRC_CC_FWMDE_MASK, 0);
+	regmap_update_bits(easrc->regmap, REG_EASRC_COC(ctx->index),
+			   EASRC_COC_FWMDE_MASK, 0);
+	return 0;
+}
+
+struct dma_chan *fsl_easrc_get_dma_channel(struct fsl_asrc_pair *ctx,
+					   bool dir)
+{
+	struct fsl_asrc *easrc = ctx->asrc;
+	enum asrc_pair_index index = ctx->index;
+	char name[8];
+
+	/* Example of dma name: ctx0_rx */
+	sprintf(name, "ctx%c_%cx", index + '0', dir == IN ? 'r' : 't');
+
+	return dma_request_slave_channel(&easrc->pdev->dev, name);
+};
+EXPORT_SYMBOL_GPL(fsl_easrc_get_dma_channel);
+
+static const unsigned int easrc_rates[] = {
+	8000, 11025, 12000, 16000,
+	22050, 24000, 32000, 44100,
+	48000, 64000, 88200, 96000,
+	128000, 176400, 192000, 256000,
+	352800, 384000, 705600, 768000,
+};
+
+static const struct snd_pcm_hw_constraint_list easrc_rate_constraints = {
+	.count = ARRAY_SIZE(easrc_rates),
+	.list = easrc_rates,
+};
+
+static int fsl_easrc_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &easrc_rate_constraints);
+}
+
+static int fsl_easrc_trigger(struct snd_pcm_substream *substream,
+			     int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct fsl_asrc_pair *ctx = runtime->private_data;
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = fsl_easrc_start_context(ctx);
+		if (ret)
+			return ret;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = fsl_easrc_stop_context(ctx);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fsl_easrc_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct fsl_asrc *easrc = snd_soc_dai_get_drvdata(dai);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct device *dev = &easrc->pdev->dev;
+	struct fsl_asrc_pair *ctx = runtime->private_data;
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+	unsigned int channels = params_channels(params);
+	unsigned int rate = params_rate(params);
+	snd_pcm_format_t format = params_format(params);
+	int ret;
+
+	ret = fsl_easrc_request_context(channels, ctx);
+	if (ret) {
+		dev_err(dev, "failed to request context\n");
+		return ret;
+	}
+
+	ctx_priv->ctx_streams |= BIT(substream->stream);
+
+	/*
+	 * Set the input and output ratio so we can compute
+	 * the resampling ratio in RS_LOW/HIGH
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ctx_priv->in_params.sample_rate = rate;
+		ctx_priv->in_params.sample_format = format;
+		ctx_priv->out_params.sample_rate = easrc->asrc_rate;
+		ctx_priv->out_params.sample_format = easrc->asrc_format;
+	} else {
+		ctx_priv->out_params.sample_rate = rate;
+		ctx_priv->out_params.sample_format = format;
+		ctx_priv->in_params.sample_rate = easrc->asrc_rate;
+		ctx_priv->in_params.sample_format = easrc->asrc_format;
+	}
+
+	ctx->channels = channels;
+	ctx_priv->in_params.fifo_wtmk  = 0x20;
+	ctx_priv->out_params.fifo_wtmk = 0x20;
+
+	/*
+	 * Do only rate conversion and keep the same format for input
+	 * and output data
+	 */
+	ret = fsl_easrc_set_ctx_format(ctx,
+				       &ctx_priv->in_params.sample_format,
+				       &ctx_priv->out_params.sample_format);
+	if (ret) {
+		dev_err(dev, "failed to set format %d", ret);
+		return ret;
+	}
+
+	ret = fsl_easrc_config_context(easrc, ctx->index);
+	if (ret) {
+		dev_err(dev, "failed to config context\n");
+		return ret;
+	}
+
+	ctx_priv->in_params.iterations = 1;
+	ctx_priv->in_params.group_len = ctx->channels;
+	ctx_priv->in_params.access_len = ctx->channels;
+	ctx_priv->out_params.iterations = 1;
+	ctx_priv->out_params.group_len = ctx->channels;
+	ctx_priv->out_params.access_len = ctx->channels;
+
+	ret = fsl_easrc_set_ctx_organziation(ctx);
+	if (ret) {
+		dev_err(dev, "failed to set fifo organization\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct fsl_asrc_pair *ctx = runtime->private_data;
+	struct fsl_easrc_ctx_priv *ctx_priv = ctx->private;
+
+	if (ctx && (ctx_priv->ctx_streams & BIT(substream->stream))) {
+		ctx_priv->ctx_streams &= ~BIT(substream->stream);
+		fsl_easrc_release_context(ctx);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+	.startup = fsl_easrc_startup,
+	.trigger = fsl_easrc_trigger,
+	.hw_params = fsl_easrc_hw_params,
+	.hw_free = fsl_easrc_hw_free,
+};
+
+static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+	struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev);
+
+	snd_soc_dai_init_dma_data(cpu_dai,
+				  &easrc->dma_params_tx,
+				  &easrc->dma_params_rx);
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_easrc_dai = {
+	.probe = fsl_easrc_dai_probe,
+	.playback = {
+		.stream_name = "ASRC-Playback",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 8000,
+		.rate_max = 768000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = FSL_EASRC_FORMATS,
+	},
+	.capture = {
+		.stream_name = "ASRC-Capture",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rate_min = 8000,
+		.rate_max = 768000,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = FSL_EASRC_FORMATS |
+			   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+	.ops = &fsl_easrc_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_easrc_component = {
+	.name		= "fsl-easrc-dai",
+	.controls       = fsl_easrc_snd_controls,
+	.num_controls   = ARRAY_SIZE(fsl_easrc_snd_controls),
+};
+
+static const struct reg_default fsl_easrc_reg_defaults[] = {
+	{REG_EASRC_WRFIFO(0),	0x00000000},
+	{REG_EASRC_WRFIFO(1),	0x00000000},
+	{REG_EASRC_WRFIFO(2),	0x00000000},
+	{REG_EASRC_WRFIFO(3),	0x00000000},
+	{REG_EASRC_RDFIFO(0),	0x00000000},
+	{REG_EASRC_RDFIFO(1),	0x00000000},
+	{REG_EASRC_RDFIFO(2),	0x00000000},
+	{REG_EASRC_RDFIFO(3),	0x00000000},
+	{REG_EASRC_CC(0),	0x00000000},
+	{REG_EASRC_CC(1),	0x00000000},
+	{REG_EASRC_CC(2),	0x00000000},
+	{REG_EASRC_CC(3),	0x00000000},
+	{REG_EASRC_CCE1(0),	0x00000000},
+	{REG_EASRC_CCE1(1),	0x00000000},
+	{REG_EASRC_CCE1(2),	0x00000000},
+	{REG_EASRC_CCE1(3),	0x00000000},
+	{REG_EASRC_CCE2(0),	0x00000000},
+	{REG_EASRC_CCE2(1),	0x00000000},
+	{REG_EASRC_CCE2(2),	0x00000000},
+	{REG_EASRC_CCE2(3),	0x00000000},
+	{REG_EASRC_CIA(0),	0x00000000},
+	{REG_EASRC_CIA(1),	0x00000000},
+	{REG_EASRC_CIA(2),	0x00000000},
+	{REG_EASRC_CIA(3),	0x00000000},
+	{REG_EASRC_DPCS0R0(0),	0x00000000},
+	{REG_EASRC_DPCS0R0(1),	0x00000000},
+	{REG_EASRC_DPCS0R0(2),	0x00000000},
+	{REG_EASRC_DPCS0R0(3),	0x00000000},
+	{REG_EASRC_DPCS0R1(0),	0x00000000},
+	{REG_EASRC_DPCS0R1(1),	0x00000000},
+	{REG_EASRC_DPCS0R1(2),	0x00000000},
+	{REG_EASRC_DPCS0R1(3),	0x00000000},
+	{REG_EASRC_DPCS0R2(0),	0x00000000},
+	{REG_EASRC_DPCS0R2(1),	0x00000000},
+	{REG_EASRC_DPCS0R2(2),	0x00000000},
+	{REG_EASRC_DPCS0R2(3),	0x00000000},
+	{REG_EASRC_DPCS0R3(0),	0x00000000},
+	{REG_EASRC_DPCS0R3(1),	0x00000000},
+	{REG_EASRC_DPCS0R3(2),	0x00000000},
+	{REG_EASRC_DPCS0R3(3),	0x00000000},
+	{REG_EASRC_DPCS1R0(0),	0x00000000},
+	{REG_EASRC_DPCS1R0(1),	0x00000000},
+	{REG_EASRC_DPCS1R0(2),	0x00000000},
+	{REG_EASRC_DPCS1R0(3),	0x00000000},
+	{REG_EASRC_DPCS1R1(0),	0x00000000},
+	{REG_EASRC_DPCS1R1(1),	0x00000000},
+	{REG_EASRC_DPCS1R1(2),	0x00000000},
+	{REG_EASRC_DPCS1R1(3),	0x00000000},
+	{REG_EASRC_DPCS1R2(0),	0x00000000},
+	{REG_EASRC_DPCS1R2(1),	0x00000000},
+	{REG_EASRC_DPCS1R2(2),	0x00000000},
+	{REG_EASRC_DPCS1R2(3),	0x00000000},
+	{REG_EASRC_DPCS1R3(0),	0x00000000},
+	{REG_EASRC_DPCS1R3(1),	0x00000000},
+	{REG_EASRC_DPCS1R3(2),	0x00000000},
+	{REG_EASRC_DPCS1R3(3),	0x00000000},
+	{REG_EASRC_COC(0),	0x00000000},
+	{REG_EASRC_COC(1),	0x00000000},
+	{REG_EASRC_COC(2),	0x00000000},
+	{REG_EASRC_COC(3),	0x00000000},
+	{REG_EASRC_COA(0),	0x00000000},
+	{REG_EASRC_COA(1),	0x00000000},
+	{REG_EASRC_COA(2),	0x00000000},
+	{REG_EASRC_COA(3),	0x00000000},
+	{REG_EASRC_SFS(0),	0x00000000},
+	{REG_EASRC_SFS(1),	0x00000000},
+	{REG_EASRC_SFS(2),	0x00000000},
+	{REG_EASRC_SFS(3),	0x00000000},
+	{REG_EASRC_RRL(0),	0x00000000},
+	{REG_EASRC_RRL(1),	0x00000000},
+	{REG_EASRC_RRL(2),	0x00000000},
+	{REG_EASRC_RRL(3),	0x00000000},
+	{REG_EASRC_RRH(0),	0x00000000},
+	{REG_EASRC_RRH(1),	0x00000000},
+	{REG_EASRC_RRH(2),	0x00000000},
+	{REG_EASRC_RRH(3),	0x00000000},
+	{REG_EASRC_RUC(0),	0x00000000},
+	{REG_EASRC_RUC(1),	0x00000000},
+	{REG_EASRC_RUC(2),	0x00000000},
+	{REG_EASRC_RUC(3),	0x00000000},
+	{REG_EASRC_RUR(0),	0x7FFFFFFF},
+	{REG_EASRC_RUR(1),	0x7FFFFFFF},
+	{REG_EASRC_RUR(2),	0x7FFFFFFF},
+	{REG_EASRC_RUR(3),	0x7FFFFFFF},
+	{REG_EASRC_RCTCL,	0x00000000},
+	{REG_EASRC_RCTCH,	0x00000000},
+	{REG_EASRC_PCF(0),	0x00000000},
+	{REG_EASRC_PCF(1),	0x00000000},
+	{REG_EASRC_PCF(2),	0x00000000},
+	{REG_EASRC_PCF(3),	0x00000000},
+	{REG_EASRC_CRCM,	0x00000000},
+	{REG_EASRC_CRCC,	0x00000000},
+	{REG_EASRC_IRQC,	0x00000FFF},
+	{REG_EASRC_IRQF,	0x00000000},
+	{REG_EASRC_CS0(0),	0x00000000},
+	{REG_EASRC_CS0(1),	0x00000000},
+	{REG_EASRC_CS0(2),	0x00000000},
+	{REG_EASRC_CS0(3),	0x00000000},
+	{REG_EASRC_CS1(0),	0x00000000},
+	{REG_EASRC_CS1(1),	0x00000000},
+	{REG_EASRC_CS1(2),	0x00000000},
+	{REG_EASRC_CS1(3),	0x00000000},
+	{REG_EASRC_CS2(0),	0x00000000},
+	{REG_EASRC_CS2(1),	0x00000000},
+	{REG_EASRC_CS2(2),	0x00000000},
+	{REG_EASRC_CS2(3),	0x00000000},
+	{REG_EASRC_CS3(0),	0x00000000},
+	{REG_EASRC_CS3(1),	0x00000000},
+	{REG_EASRC_CS3(2),	0x00000000},
+	{REG_EASRC_CS3(3),	0x00000000},
+	{REG_EASRC_CS4(0),	0x00000000},
+	{REG_EASRC_CS4(1),	0x00000000},
+	{REG_EASRC_CS4(2),	0x00000000},
+	{REG_EASRC_CS4(3),	0x00000000},
+	{REG_EASRC_CS5(0),	0x00000000},
+	{REG_EASRC_CS5(1),	0x00000000},
+	{REG_EASRC_CS5(2),	0x00000000},
+	{REG_EASRC_CS5(3),	0x00000000},
+	{REG_EASRC_DBGC,	0x00000000},
+	{REG_EASRC_DBGS,	0x00000000},
+};
+
+static const struct regmap_range fsl_easrc_readable_ranges[] = {
+	regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RCTCH),
+	regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_PCF(3)),
+	regmap_reg_range(REG_EASRC_CRCC, REG_EASRC_DBGS),
+};
+
+static const struct regmap_access_table fsl_easrc_readable_table = {
+	.yes_ranges = fsl_easrc_readable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(fsl_easrc_readable_ranges),
+};
+
+static const struct regmap_range fsl_easrc_writeable_ranges[] = {
+	regmap_reg_range(REG_EASRC_WRFIFO(0), REG_EASRC_WRFIFO(3)),
+	regmap_reg_range(REG_EASRC_CC(0), REG_EASRC_COA(3)),
+	regmap_reg_range(REG_EASRC_RRL(0), REG_EASRC_RCTCH),
+	regmap_reg_range(REG_EASRC_PCF(0), REG_EASRC_DBGC),
+};
+
+static const struct regmap_access_table fsl_easrc_writeable_table = {
+	.yes_ranges = fsl_easrc_writeable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(fsl_easrc_writeable_ranges),
+};
+
+static const struct regmap_range fsl_easrc_volatileable_ranges[] = {
+	regmap_reg_range(REG_EASRC_RDFIFO(0), REG_EASRC_RDFIFO(3)),
+	regmap_reg_range(REG_EASRC_SFS(0), REG_EASRC_SFS(3)),
+	regmap_reg_range(REG_EASRC_IRQF, REG_EASRC_IRQF),
+	regmap_reg_range(REG_EASRC_DBGS, REG_EASRC_DBGS),
+};
+
+static const struct regmap_access_table fsl_easrc_volatileable_table = {
+	.yes_ranges = fsl_easrc_volatileable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(fsl_easrc_volatileable_ranges),
+};
+
+static const struct regmap_config fsl_easrc_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = REG_EASRC_DBGS,
+	.reg_defaults = fsl_easrc_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(fsl_easrc_reg_defaults),
+	.rd_table = &fsl_easrc_readable_table,
+	.wr_table = &fsl_easrc_writeable_table,
+	.volatile_table = &fsl_easrc_volatileable_table,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#ifdef DEBUG
+static void fsl_easrc_dump_firmware(struct fsl_asrc *easrc)
+{
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct asrc_firmware_hdr *firm = easrc_priv->firmware_hdr;
+	struct interp_params *interp = easrc_priv->interp;
+	struct prefil_params *prefil = easrc_priv->prefil;
+	struct device *dev = &easrc->pdev->dev;
+	int i;
+
+	if (firm->magic != FIRMWARE_MAGIC) {
+		dev_err(dev, "Wrong magic. Something went wrong!");
+		return;
+	}
+
+	dev_dbg(dev, "Firmware v%u dump:\n", firm->firmware_version);
+	dev_dbg(dev, "Num prefitler scenarios: %u\n", firm->prefil_scen);
+	dev_dbg(dev, "Num interpolation scenarios: %u\n", firm->interp_scen);
+	dev_dbg(dev, "\nInterpolation scenarios:\n");
+
+	for (i = 0; i < firm->interp_scen; i++) {
+		if (interp[i].magic != FIRMWARE_MAGIC) {
+			dev_dbg(dev, "%d. wrong interp magic: %x\n",
+				i, interp[i].magic);
+			continue;
+		}
+		dev_dbg(dev, "%d. taps: %u, phases: %u, center: %llu\n", i,
+			interp[i].num_taps, interp[i].num_phases,
+			interp[i].center_tap);
+	}
+
+	for (i = 0; i < firm->prefil_scen; i++) {
+		if (prefil[i].magic != FIRMWARE_MAGIC) {
+			dev_dbg(dev, "%d. wrong prefil magic: %x\n",
+				i, prefil[i].magic);
+			continue;
+		}
+		dev_dbg(dev, "%d. insr: %u, outsr: %u, st1: %u, st2: %u\n", i,
+			prefil[i].insr, prefil[i].outsr,
+			prefil[i].st1_taps, prefil[i].st2_taps);
+	}
+
+	dev_dbg(dev, "end of firmware dump\n");
+}
+#endif
+
+static int fsl_easrc_get_firmware(struct fsl_asrc *easrc)
+{
+	struct fsl_easrc_priv *easrc_priv;
+	const struct firmware **fw_p;
+	u32 pnum, inum, offset;
+	const u8 *data;
+	int ret;
+
+	if (!easrc)
+		return -EINVAL;
+
+	easrc_priv = easrc->private;
+	fw_p = &easrc_priv->fw;
+
+	ret = request_firmware(fw_p, easrc_priv->fw_name, &easrc->pdev->dev);
+	if (ret)
+		return ret;
+
+	data = easrc_priv->fw->data;
+
+	easrc_priv->firmware_hdr = (struct asrc_firmware_hdr *)data;
+	pnum = easrc_priv->firmware_hdr->prefil_scen;
+	inum = easrc_priv->firmware_hdr->interp_scen;
+
+	if (inum) {
+		offset = sizeof(struct asrc_firmware_hdr);
+		easrc_priv->interp = (struct interp_params *)(data + offset);
+	}
+
+	if (pnum) {
+		offset = sizeof(struct asrc_firmware_hdr) +
+				inum * sizeof(struct interp_params);
+		easrc_priv->prefil = (struct prefil_params *)(data + offset);
+	}
+
+#ifdef DEBUG
+	fsl_easrc_dump_firmware(easrc);
+#endif
+
+	return 0;
+}
+
+static irqreturn_t fsl_easrc_isr(int irq, void *dev_id)
+{
+	struct fsl_asrc *easrc = (struct fsl_asrc *)dev_id;
+	struct device *dev = &easrc->pdev->dev;
+	int val;
+
+	regmap_read(easrc->regmap, REG_EASRC_IRQF, &val);
+
+	if (val & EASRC_IRQF_OER_MASK)
+		dev_dbg(dev, "output FIFO underflow\n");
+
+	if (val & EASRC_IRQF_IFO_MASK)
+		dev_dbg(dev, "input FIFO overflow\n");
+
+	return IRQ_HANDLED;
+}
+
+static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
+{
+	return REG_EASRC_FIFO(dir, index);
+}
+
+static const struct of_device_id fsl_easrc_dt_ids[] = {
+	{ .compatible = "fsl,imx8mn-easrc",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_easrc_dt_ids);
+
+static int fsl_easrc_probe(struct platform_device *pdev)
+{
+	struct fsl_easrc_priv *easrc_priv;
+	struct device *dev = &pdev->dev;
+	struct fsl_asrc *easrc;
+	struct resource *res;
+	struct device_node *np;
+	void __iomem *regs;
+	int ret, irq;
+
+	easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL);
+	if (!easrc)
+		return -ENOMEM;
+
+	easrc_priv = devm_kzalloc(dev, sizeof(*easrc_priv), GFP_KERNEL);
+	if (!easrc_priv)
+		return -ENOMEM;
+
+	easrc->pdev = pdev;
+	easrc->private = easrc_priv;
+	np = dev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(&pdev->dev, "failed ioremap\n");
+		return PTR_ERR(regs);
+	}
+
+	easrc->paddr = res->start;
+
+	easrc->regmap = devm_regmap_init_mmio_clk(dev, "mem", regs,
+						  &fsl_easrc_regmap_config);
+	if (IS_ERR(easrc->regmap)) {
+		dev_err(dev, "failed to init regmap");
+		return PTR_ERR(easrc->regmap);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no irq for node %pOF\n", np);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, fsl_easrc_isr, 0,
+			       dev_name(dev), easrc);
+	if (ret) {
+		dev_err(dev, "failed to claim irq %u: %d\n", irq, ret);
+		return ret;
+	}
+
+	easrc->mem_clk = devm_clk_get(dev, "mem");
+	if (IS_ERR(easrc->mem_clk)) {
+		dev_err(dev, "failed to get mem clock\n");
+		return PTR_ERR(easrc->mem_clk);
+	}
+
+	/* Set default value */
+	easrc->channel_avail = 32;
+	easrc->get_dma_channel = fsl_easrc_get_dma_channel;
+	easrc->request_pair = fsl_easrc_request_context;
+	easrc->release_pair = fsl_easrc_release_context;
+	easrc->get_fifo_addr = fsl_easrc_get_fifo_addr;
+	easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv);
+
+	easrc_priv->rs_num_taps = EASRC_RS_32_TAPS;
+	easrc_priv->const_coeff = 0x3FF0000000000000;
+
+	ret = of_property_read_u32(np, "fsl,asrc-rate", &easrc->asrc_rate);
+	if (ret) {
+		dev_err(dev, "failed to asrc rate\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format);
+	if (ret) {
+		dev_err(dev, "failed to asrc format\n");
+		return ret;
+	}
+
+	if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) {
+		dev_warn(dev, "unsupported format, switching to S24_LE\n");
+		easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
+	}
+
+	ret = of_property_read_string(np, "firmware-name",
+				      &easrc_priv->fw_name);
+	if (ret) {
+		dev_err(dev, "failed to get firmware name\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, easrc);
+	pm_runtime_enable(dev);
+
+	spin_lock_init(&easrc->lock);
+
+	regcache_cache_only(easrc->regmap, true);
+
+	ret = devm_snd_soc_register_component(dev, &fsl_easrc_component,
+					      &fsl_easrc_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register ASoC DAI\n");
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(dev, &fsl_asrc_component,
+					      NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register ASoC platform\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_easrc_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int fsl_easrc_runtime_suspend(struct device *dev)
+{
+	struct fsl_asrc *easrc = dev_get_drvdata(dev);
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	unsigned long lock_flags;
+
+	regcache_cache_only(easrc->regmap, true);
+
+	clk_disable_unprepare(easrc->mem_clk);
+
+	spin_lock_irqsave(&easrc->lock, lock_flags);
+	easrc_priv->firmware_loaded = 0;
+	spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+	return 0;
+}
+
+static int fsl_easrc_runtime_resume(struct device *dev)
+{
+	struct fsl_asrc *easrc = dev_get_drvdata(dev);
+	struct fsl_easrc_priv *easrc_priv = easrc->private;
+	struct fsl_easrc_ctx_priv *ctx_priv;
+	struct fsl_asrc_pair *ctx;
+	unsigned long lock_flags;
+	int ret;
+	int i;
+
+	ret = clk_prepare_enable(easrc->mem_clk);
+	if (ret)
+		return ret;
+
+	regcache_cache_only(easrc->regmap, false);
+	regcache_mark_dirty(easrc->regmap);
+	regcache_sync(easrc->regmap);
+
+	spin_lock_irqsave(&easrc->lock, lock_flags);
+	if (easrc_priv->firmware_loaded) {
+		spin_unlock_irqrestore(&easrc->lock, lock_flags);
+		goto skip_load;
+	}
+	easrc_priv->firmware_loaded = 1;
+	spin_unlock_irqrestore(&easrc->lock, lock_flags);
+
+	ret = fsl_easrc_get_firmware(easrc);
+	if (ret) {
+		dev_err(dev, "failed to get firmware\n");
+		goto disable_mem_clk;
+	}
+
+	/*
+	 * Write Resampling Coefficients
+	 * The coefficient RAM must be configured prior to beginning of
+	 * any context processing within the ASRC
+	 */
+	ret = fsl_easrc_resampler_config(easrc);
+	if (ret) {
+		dev_err(dev, "resampler config failed\n");
+		goto disable_mem_clk;
+	}
+
+	for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
+		ctx = easrc->pair[i];
+		if (!ctx)
+			continue;
+
+		ctx_priv = ctx->private;
+		fsl_easrc_set_rs_ratio(ctx);
+		ctx_priv->out_missed_sample = ctx_priv->in_filled_sample *
+					      ctx_priv->out_params.sample_rate /
+					      ctx_priv->in_params.sample_rate;
+		if (ctx_priv->in_filled_sample * ctx_priv->out_params.sample_rate
+		    % ctx_priv->in_params.sample_rate != 0)
+			ctx_priv->out_missed_sample += 1;
+
+		ret = fsl_easrc_write_pf_coeff_mem(easrc, i,
+						   ctx_priv->st1_coeff,
+						   ctx_priv->st1_num_taps,
+						   ctx_priv->st1_addexp);
+		if (ret)
+			goto disable_mem_clk;
+
+		ret = fsl_easrc_write_pf_coeff_mem(easrc, i,
+						   ctx_priv->st2_coeff,
+						   ctx_priv->st2_num_taps,
+						   ctx_priv->st2_addexp);
+		if (ret)
+			goto disable_mem_clk;
+	}
+
+skip_load:
+	return 0;
+
+disable_mem_clk:
+	clk_disable_unprepare(easrc->mem_clk);
+	return ret;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops fsl_easrc_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_easrc_runtime_suspend,
+			   fsl_easrc_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_easrc_driver = {
+	.probe = fsl_easrc_probe,
+	.remove = fsl_easrc_remove,
+	.driver = {
+		.name = "fsl-easrc",
+		.pm = &fsl_easrc_pm_ops,
+		.of_match_table = fsl_easrc_dt_ids,
+	},
+};
+module_platform_driver(fsl_easrc_driver);
+
+MODULE_DESCRIPTION("NXP Enhanced Asynchronous Sample Rate (eASRC) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h
new file mode 100644
index 000000000000..30620d56252c
--- /dev/null
+++ b/sound/soc/fsl/fsl_easrc.h
@@ -0,0 +1,651 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 NXP
+ */
+
+#ifndef _FSL_EASRC_H
+#define _FSL_EASRC_H
+
+#include <sound/asound.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include "fsl_asrc_common.h"
+
+/* EASRC Register Map */
+
+/* ASRC Input Write FIFO */
+#define REG_EASRC_WRFIFO(ctx)		(0x000 + 4 * (ctx))
+/* ASRC Output Read FIFO */
+#define REG_EASRC_RDFIFO(ctx)		(0x010 + 4 * (ctx))
+/* ASRC Context Control */
+#define REG_EASRC_CC(ctx)		(0x020 + 4 * (ctx))
+/* ASRC Context Control Extended 1 */
+#define REG_EASRC_CCE1(ctx)		(0x030 + 4 * (ctx))
+/* ASRC Context Control Extended 2 */
+#define REG_EASRC_CCE2(ctx)		(0x040 + 4 * (ctx))
+/* ASRC Control Input Access */
+#define REG_EASRC_CIA(ctx)		(0x050 + 4 * (ctx))
+/* ASRC Datapath Processor Control Slot0 */
+#define REG_EASRC_DPCS0R0(ctx)		(0x060 + 4 * (ctx))
+#define REG_EASRC_DPCS0R1(ctx)		(0x070 + 4 * (ctx))
+#define REG_EASRC_DPCS0R2(ctx)		(0x080 + 4 * (ctx))
+#define REG_EASRC_DPCS0R3(ctx)		(0x090 + 4 * (ctx))
+/* ASRC Datapath Processor Control Slot1 */
+#define REG_EASRC_DPCS1R0(ctx)		(0x0A0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R1(ctx)		(0x0B0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R2(ctx)		(0x0C0 + 4 * (ctx))
+#define REG_EASRC_DPCS1R3(ctx)		(0x0D0 + 4 * (ctx))
+/* ASRC Context Output Control */
+#define REG_EASRC_COC(ctx)		(0x0E0 + 4 * (ctx))
+/* ASRC Control Output Access */
+#define REG_EASRC_COA(ctx)		(0x0F0 + 4 * (ctx))
+/* ASRC Sample FIFO Status */
+#define REG_EASRC_SFS(ctx)		(0x100 + 4 * (ctx))
+/* ASRC Resampling Ratio Low */
+#define REG_EASRC_RRL(ctx)		(0x110 + 8 * (ctx))
+/* ASRC Resampling Ratio High */
+#define REG_EASRC_RRH(ctx)		(0x114 + 8 * (ctx))
+/* ASRC Resampling Ratio Update Control */
+#define REG_EASRC_RUC(ctx)		(0x130 + 4 * (ctx))
+/* ASRC Resampling Ratio Update Rate */
+#define REG_EASRC_RUR(ctx)		(0x140 + 4 * (ctx))
+/* ASRC Resampling Center Tap Coefficient Low */
+#define REG_EASRC_RCTCL			(0x150)
+/* ASRC Resampling Center Tap Coefficient High */
+#define REG_EASRC_RCTCH			(0x154)
+/* ASRC Prefilter Coefficient FIFO */
+#define REG_EASRC_PCF(ctx)		(0x160 + 4 * (ctx))
+/* ASRC Context Resampling Coefficient Memory */
+#define REG_EASRC_CRCM			0x170
+/* ASRC Context Resampling Coefficient Control*/
+#define REG_EASRC_CRCC			0x174
+/* ASRC Interrupt Control */
+#define REG_EASRC_IRQC			0x178
+/* ASRC Interrupt Status Flags */
+#define REG_EASRC_IRQF			0x17C
+/* ASRC Channel Status 0 */
+#define REG_EASRC_CS0(ctx)		(0x180 + 4 * (ctx))
+/* ASRC Channel Status 1 */
+#define REG_EASRC_CS1(ctx)		(0x190 + 4 * (ctx))
+/* ASRC Channel Status 2 */
+#define REG_EASRC_CS2(ctx)		(0x1A0 + 4 * (ctx))
+/* ASRC Channel Status 3 */
+#define REG_EASRC_CS3(ctx)		(0x1B0 + 4 * (ctx))
+/* ASRC Channel Status 4 */
+#define REG_EASRC_CS4(ctx)		(0x1C0 + 4 * (ctx))
+/* ASRC Channel Status 5 */
+#define REG_EASRC_CS5(ctx)		(0x1D0 + 4 * (ctx))
+/* ASRC Debug Control Register */
+#define REG_EASRC_DBGC			0x1E0
+/* ASRC Debug Status Register */
+#define REG_EASRC_DBGS			0x1E4
+
+#define REG_EASRC_FIFO(x, ctx)		(x == IN ? REG_EASRC_WRFIFO(ctx) \
+						: REG_EASRC_RDFIFO(ctx))
+
+/* ASRC Context Control (CC) */
+#define EASRC_CC_EN_SHIFT		31
+#define EASRC_CC_EN_MASK		BIT(EASRC_CC_EN_SHIFT)
+#define EASRC_CC_EN			BIT(EASRC_CC_EN_SHIFT)
+#define EASRC_CC_STOP_SHIFT		29
+#define EASRC_CC_STOP_MASK		BIT(EASRC_CC_STOP_SHIFT)
+#define EASRC_CC_STOP			BIT(EASRC_CC_STOP_SHIFT)
+#define EASRC_CC_FWMDE_SHIFT		28
+#define EASRC_CC_FWMDE_MASK		BIT(EASRC_CC_FWMDE_SHIFT)
+#define EASRC_CC_FWMDE			BIT(EASRC_CC_FWMDE_SHIFT)
+#define EASRC_CC_FIFO_WTMK_SHIFT	16
+#define EASRC_CC_FIFO_WTMK_WIDTH	7
+#define EASRC_CC_FIFO_WTMK_MASK		((BIT(EASRC_CC_FIFO_WTMK_WIDTH) - 1) \
+					 << EASRC_CC_FIFO_WTMK_SHIFT)
+#define EASRC_CC_FIFO_WTMK(v)		(((v) << EASRC_CC_FIFO_WTMK_SHIFT) \
+					 & EASRC_CC_FIFO_WTMK_MASK)
+#define EASRC_CC_SAMPLE_POS_SHIFT	11
+#define EASRC_CC_SAMPLE_POS_WIDTH	5
+#define EASRC_CC_SAMPLE_POS_MASK	((BIT(EASRC_CC_SAMPLE_POS_WIDTH) - 1) \
+					 << EASRC_CC_SAMPLE_POS_SHIFT)
+#define EASRC_CC_SAMPLE_POS(v)		(((v) << EASRC_CC_SAMPLE_POS_SHIFT) \
+					 & EASRC_CC_SAMPLE_POS_MASK)
+#define EASRC_CC_ENDIANNESS_SHIFT	10
+#define EASRC_CC_ENDIANNESS_MASK	BIT(EASRC_CC_ENDIANNESS_SHIFT)
+#define EASRC_CC_ENDIANNESS		BIT(EASRC_CC_ENDIANNESS_SHIFT)
+#define EASRC_CC_BPS_SHIFT		8
+#define EASRC_CC_BPS_WIDTH		2
+#define EASRC_CC_BPS_MASK		((BIT(EASRC_CC_BPS_WIDTH) - 1) \
+					 << EASRC_CC_BPS_SHIFT)
+#define EASRC_CC_BPS(v)			(((v) << EASRC_CC_BPS_SHIFT) \
+					 & EASRC_CC_BPS_MASK)
+#define EASRC_CC_FMT_SHIFT		7
+#define EASRC_CC_FMT_MASK		BIT(EASRC_CC_FMT_SHIFT)
+#define EASRC_CC_FMT			BIT(EASRC_CC_FMT_SHIFT)
+#define EASRC_CC_INSIGN_SHIFT		6
+#define EASRC_CC_INSIGN_MASK		BIT(EASRC_CC_INSIGN_SHIFT)
+#define EASRC_CC_INSIGN			BIT(EASRC_CC_INSIGN_SHIFT)
+#define EASRC_CC_CHEN_SHIFT		0
+#define EASRC_CC_CHEN_WIDTH		5
+#define EASRC_CC_CHEN_MASK		((BIT(EASRC_CC_CHEN_WIDTH) - 1) \
+					 << EASRC_CC_CHEN_SHIFT)
+#define EASRC_CC_CHEN(v)		(((v) << EASRC_CC_CHEN_SHIFT) \
+					 & EASRC_CC_CHEN_MASK)
+
+/* ASRC Context Control Extended 1 (CCE1) */
+#define EASRC_CCE1_COEF_WS_SHIFT	25
+#define EASRC_CCE1_COEF_WS_MASK		BIT(EASRC_CCE1_COEF_WS_SHIFT)
+#define EASRC_CCE1_COEF_WS		BIT(EASRC_CCE1_COEF_WS_SHIFT)
+#define EASRC_CCE1_COEF_MEM_RST_SHIFT	24
+#define EASRC_CCE1_COEF_MEM_RST_MASK	BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT)
+#define EASRC_CCE1_COEF_MEM_RST		BIT(EASRC_CCE1_COEF_MEM_RST_SHIFT)
+#define EASRC_CCE1_PF_EXP_SHIFT		16
+#define EASRC_CCE1_PF_EXP_WIDTH		8
+#define EASRC_CCE1_PF_EXP_MASK		((BIT(EASRC_CCE1_PF_EXP_WIDTH) - 1) \
+					 << EASRC_CCE1_PF_EXP_SHIFT)
+#define EASRC_CCE1_PF_EXP(v)		(((v) << EASRC_CCE1_PF_EXP_SHIFT) \
+					 & EASRC_CCE1_PF_EXP_MASK)
+#define EASRC_CCE1_PF_ST1_WBFP_SHIFT	9
+#define EASRC_CCE1_PF_ST1_WBFP_MASK	BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT)
+#define EASRC_CCE1_PF_ST1_WBFP		BIT(EASRC_CCE1_PF_ST1_WBFP_SHIFT)
+#define EASRC_CCE1_PF_TSEN_SHIFT	8
+#define EASRC_CCE1_PF_TSEN_MASK		BIT(EASRC_CCE1_PF_TSEN_SHIFT)
+#define EASRC_CCE1_PF_TSEN		BIT(EASRC_CCE1_PF_TSEN_SHIFT)
+#define EASRC_CCE1_RS_BYPASS_SHIFT	7
+#define EASRC_CCE1_RS_BYPASS_MASK	BIT(EASRC_CCE1_RS_BYPASS_SHIFT)
+#define EASRC_CCE1_RS_BYPASS		BIT(EASRC_CCE1_RS_BYPASS_SHIFT)
+#define EASRC_CCE1_PF_BYPASS_SHIFT	6
+#define EASRC_CCE1_PF_BYPASS_MASK	BIT(EASRC_CCE1_PF_BYPASS_SHIFT)
+#define EASRC_CCE1_PF_BYPASS		BIT(EASRC_CCE1_PF_BYPASS_SHIFT)
+#define EASRC_CCE1_RS_STOP_SHIFT	5
+#define EASRC_CCE1_RS_STOP_MASK		BIT(EASRC_CCE1_RS_STOP_SHIFT)
+#define EASRC_CCE1_RS_STOP		BIT(EASRC_CCE1_RS_STOP_SHIFT)
+#define EASRC_CCE1_PF_STOP_SHIFT	4
+#define EASRC_CCE1_PF_STOP_MASK		BIT(EASRC_CCE1_PF_STOP_SHIFT)
+#define EASRC_CCE1_PF_STOP		BIT(EASRC_CCE1_PF_STOP_SHIFT)
+#define EASRC_CCE1_RS_INIT_SHIFT	2
+#define EASRC_CCE1_RS_INIT_WIDTH	2
+#define EASRC_CCE1_RS_INIT_MASK		((BIT(EASRC_CCE1_RS_INIT_WIDTH) - 1) \
+					 << EASRC_CCE1_RS_INIT_SHIFT)
+#define EASRC_CCE1_RS_INIT(v)		(((v) << EASRC_CCE1_RS_INIT_SHIFT) \
+					 & EASRC_CCE1_RS_INIT_MASK)
+#define EASRC_CCE1_PF_INIT_SHIFT	0
+#define EASRC_CCE1_PF_INIT_WIDTH	2
+#define EASRC_CCE1_PF_INIT_MASK		((BIT(EASRC_CCE1_PF_INIT_WIDTH) - 1) \
+					 << EASRC_CCE1_PF_INIT_SHIFT)
+#define EASRC_CCE1_PF_INIT(v)		(((v) << EASRC_CCE1_PF_INIT_SHIFT) \
+					 & EASRC_CCE1_PF_INIT_MASK)
+
+/* ASRC Context Control Extended 2 (CCE2) */
+#define EASRC_CCE2_ST2_TAPS_SHIFT	16
+#define EASRC_CCE2_ST2_TAPS_WIDTH	9
+#define EASRC_CCE2_ST2_TAPS_MASK	((BIT(EASRC_CCE2_ST2_TAPS_WIDTH) - 1) \
+					 << EASRC_CCE2_ST2_TAPS_SHIFT)
+#define EASRC_CCE2_ST2_TAPS(v)		(((v) << EASRC_CCE2_ST2_TAPS_SHIFT) \
+					 & EASRC_CCE2_ST2_TAPS_MASK)
+#define EASRC_CCE2_ST1_TAPS_SHIFT	0
+#define EASRC_CCE2_ST1_TAPS_WIDTH	9
+#define EASRC_CCE2_ST1_TAPS_MASK	((BIT(EASRC_CCE2_ST1_TAPS_WIDTH) - 1) \
+					 << EASRC_CCE2_ST1_TAPS_SHIFT)
+#define EASRC_CCE2_ST1_TAPS(v)		(((v) << EASRC_CCE2_ST1_TAPS_SHIFT) \
+					 & EASRC_CCE2_ST1_TAPS_MASK)
+
+/* ASRC Control Input Access (CIA) */
+#define EASRC_CIA_ITER_SHIFT		16
+#define EASRC_CIA_ITER_WIDTH		6
+#define EASRC_CIA_ITER_MASK		((BIT(EASRC_CIA_ITER_WIDTH) - 1) \
+					 << EASRC_CIA_ITER_SHIFT)
+#define EASRC_CIA_ITER(v)		(((v) << EASRC_CIA_ITER_SHIFT) \
+					 & EASRC_CIA_ITER_MASK)
+#define EASRC_CIA_GRLEN_SHIFT		8
+#define EASRC_CIA_GRLEN_WIDTH		6
+#define EASRC_CIA_GRLEN_MASK		((BIT(EASRC_CIA_GRLEN_WIDTH) - 1) \
+					 << EASRC_CIA_GRLEN_SHIFT)
+#define EASRC_CIA_GRLEN(v)		(((v) << EASRC_CIA_GRLEN_SHIFT) \
+					 & EASRC_CIA_GRLEN_MASK)
+#define EASRC_CIA_ACCLEN_SHIFT		0
+#define EASRC_CIA_ACCLEN_WIDTH		6
+#define EASRC_CIA_ACCLEN_MASK		((BIT(EASRC_CIA_ACCLEN_WIDTH) - 1) \
+					 << EASRC_CIA_ACCLEN_SHIFT)
+#define EASRC_CIA_ACCLEN(v)		(((v) << EASRC_CIA_ACCLEN_SHIFT) \
+					 & EASRC_CIA_ACCLEN_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register0 (DPCS0R0) */
+#define EASRC_DPCS0R0_MAXCH_SHIFT	24
+#define EASRC_DPCS0R0_MAXCH_WIDTH	5
+#define EASRC_DPCS0R0_MAXCH_MASK	((BIT(EASRC_DPCS0R0_MAXCH_WIDTH) - 1) \
+					 << EASRC_DPCS0R0_MAXCH_SHIFT)
+#define EASRC_DPCS0R0_MAXCH(v)		(((v) << EASRC_DPCS0R0_MAXCH_SHIFT) \
+					 & EASRC_DPCS0R0_MAXCH_MASK)
+#define EASRC_DPCS0R0_MINCH_SHIFT	16
+#define EASRC_DPCS0R0_MINCH_WIDTH	5
+#define EASRC_DPCS0R0_MINCH_MASK	((BIT(EASRC_DPCS0R0_MINCH_WIDTH) - 1) \
+					 << EASRC_DPCS0R0_MINCH_SHIFT)
+#define EASRC_DPCS0R0_MINCH(v)		(((v) << EASRC_DPCS0R0_MINCH_SHIFT) \
+					 & EASRC_DPCS0R0_MINCH_MASK)
+#define EASRC_DPCS0R0_NUMCH_SHIFT	8
+#define EASRC_DPCS0R0_NUMCH_WIDTH	5
+#define EASRC_DPCS0R0_NUMCH_MASK	((BIT(EASRC_DPCS0R0_NUMCH_WIDTH) - 1) \
+					 << EASRC_DPCS0R0_NUMCH_SHIFT)
+#define EASRC_DPCS0R0_NUMCH(v)		(((v) << EASRC_DPCS0R0_NUMCH_SHIFT) \
+					 & EASRC_DPCS0R0_NUMCH_MASK)
+#define EASRC_DPCS0R0_CTXNUM_SHIFT	1
+#define EASRC_DPCS0R0_CTXNUM_WIDTH	2
+#define EASRC_DPCS0R0_CTXNUM_MASK	((BIT(EASRC_DPCS0R0_CTXNUM_WIDTH) - 1) \
+					 << EASRC_DPCS0R0_CTXNUM_SHIFT)
+#define EASRC_DPCS0R0_CTXNUM(v)		(((v) << EASRC_DPCS0R0_CTXNUM_SHIFT) \
+					 & EASRC_DPCS0R0_CTXNUM_MASK)
+#define EASRC_DPCS0R0_EN_SHIFT		0
+#define EASRC_DPCS0R0_EN_MASK		BIT(EASRC_DPCS0R0_EN_SHIFT)
+#define EASRC_DPCS0R0_EN		BIT(EASRC_DPCS0R0_EN_SHIFT)
+
+/* ASRC Datapath Processor Control Slot0 Register1 (DPCS0R1) */
+#define EASRC_DPCS0R1_ST1_EXP_SHIFT	0
+#define EASRC_DPCS0R1_ST1_EXP_WIDTH	13
+#define EASRC_DPCS0R1_ST1_EXP_MASK	((BIT(EASRC_DPCS0R1_ST1_EXP_WIDTH) - 1) \
+					 << EASRC_DPCS0R1_ST1_EXP_SHIFT)
+#define EASRC_DPCS0R1_ST1_EXP(v)	(((v) << EASRC_DPCS0R1_ST1_EXP_SHIFT) \
+					 & EASRC_DPCS0R1_ST1_EXP_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register2 (DPCS0R2) */
+#define EASRC_DPCS0R2_ST1_MA_SHIFT	16
+#define EASRC_DPCS0R2_ST1_MA_WIDTH	13
+#define EASRC_DPCS0R2_ST1_MA_MASK	((BIT(EASRC_DPCS0R2_ST1_MA_WIDTH) - 1) \
+					 << EASRC_DPCS0R2_ST1_MA_SHIFT)
+#define EASRC_DPCS0R2_ST1_MA(v)		(((v) << EASRC_DPCS0R2_ST1_MA_SHIFT) \
+					 & EASRC_DPCS0R2_ST1_MA_MASK)
+#define EASRC_DPCS0R2_ST1_SA_SHIFT	0
+#define EASRC_DPCS0R2_ST1_SA_WIDTH	13
+#define EASRC_DPCS0R2_ST1_SA_MASK	((BIT(EASRC_DPCS0R2_ST1_SA_WIDTH) - 1) \
+					 << EASRC_DPCS0R2_ST1_SA_SHIFT)
+#define EASRC_DPCS0R2_ST1_SA(v)		(((v) << EASRC_DPCS0R2_ST1_SA_SHIFT) \
+					 & EASRC_DPCS0R2_ST1_SA_MASK)
+
+/* ASRC Datapath Processor Control Slot0 Register3 (DPCS0R3) */
+#define EASRC_DPCS0R3_ST2_MA_SHIFT	16
+#define EASRC_DPCS0R3_ST2_MA_WIDTH	13
+#define EASRC_DPCS0R3_ST2_MA_MASK	((BIT(EASRC_DPCS0R3_ST2_MA_WIDTH) - 1) \
+					 << EASRC_DPCS0R3_ST2_MA_SHIFT)
+#define EASRC_DPCS0R3_ST2_MA(v)		(((v) << EASRC_DPCS0R3_ST2_MA_SHIFT) \
+					 & EASRC_DPCS0R3_ST2_MA_MASK)
+#define EASRC_DPCS0R3_ST2_SA_SHIFT	0
+#define EASRC_DPCS0R3_ST2_SA_WIDTH	13
+#define EASRC_DPCS0R3_ST2_SA_MASK	((BIT(EASRC_DPCS0R3_ST2_SA_WIDTH) - 1) \
+					 << EASRC_DPCS0R3_ST2_SA_SHIFT)
+#define EASRC_DPCS0R3_ST2_SA(v)		(((v) << EASRC_DPCS0R3_ST2_SA_SHIFT) \
+						 & EASRC_DPCS0R3_ST2_SA_MASK)
+
+/* ASRC Context Output Control (COC) */
+#define EASRC_COC_FWMDE_SHIFT		28
+#define EASRC_COC_FWMDE_MASK		BIT(EASRC_COC_FWMDE_SHIFT)
+#define EASRC_COC_FWMDE			BIT(EASRC_COC_FWMDE_SHIFT)
+#define EASRC_COC_FIFO_WTMK_SHIFT	16
+#define EASRC_COC_FIFO_WTMK_WIDTH	7
+#define EASRC_COC_FIFO_WTMK_MASK	((BIT(EASRC_COC_FIFO_WTMK_WIDTH) - 1) \
+					 << EASRC_COC_FIFO_WTMK_SHIFT)
+#define EASRC_COC_FIFO_WTMK(v)		(((v) << EASRC_COC_FIFO_WTMK_SHIFT) \
+					 & EASRC_COC_FIFO_WTMK_MASK)
+#define EASRC_COC_SAMPLE_POS_SHIFT	11
+#define EASRC_COC_SAMPLE_POS_WIDTH	5
+#define EASRC_COC_SAMPLE_POS_MASK	((BIT(EASRC_COC_SAMPLE_POS_WIDTH) - 1) \
+					 << EASRC_COC_SAMPLE_POS_SHIFT)
+#define EASRC_COC_SAMPLE_POS(v)		(((v) << EASRC_COC_SAMPLE_POS_SHIFT) \
+					 & EASRC_COC_SAMPLE_POS_MASK)
+#define EASRC_COC_ENDIANNESS_SHIFT	10
+#define EASRC_COC_ENDIANNESS_MASK	BIT(EASRC_COC_ENDIANNESS_SHIFT)
+#define EASRC_COC_ENDIANNESS		BIT(EASRC_COC_ENDIANNESS_SHIFT)
+#define EASRC_COC_BPS_SHIFT		8
+#define EASRC_COC_BPS_WIDTH		2
+#define EASRC_COC_BPS_MASK		((BIT(EASRC_COC_BPS_WIDTH) - 1) \
+					 << EASRC_COC_BPS_SHIFT)
+#define EASRC_COC_BPS(v)		(((v) << EASRC_COC_BPS_SHIFT) \
+					 & EASRC_COC_BPS_MASK)
+#define EASRC_COC_FMT_SHIFT		7
+#define EASRC_COC_FMT_MASK		BIT(EASRC_COC_FMT_SHIFT)
+#define EASRC_COC_FMT			BIT(EASRC_COC_FMT_SHIFT)
+#define EASRC_COC_OUTSIGN_SHIFT		6
+#define EASRC_COC_OUTSIGN_MASK		BIT(EASRC_COC_OUTSIGN_SHIFT)
+#define EASRC_COC_OUTSIGN_OUT		BIT(EASRC_COC_OUTSIGN_SHIFT)
+#define EASRC_COC_IEC_VDATA_SHIFT	2
+#define EASRC_COC_IEC_VDATA_MASK	BIT(EASRC_COC_IEC_VDATA_SHIFT)
+#define EASRC_COC_IEC_VDATA		BIT(EASRC_COC_IEC_VDATA_SHIFT)
+#define EASRC_COC_IEC_EN_SHIFT		1
+#define EASRC_COC_IEC_EN_MASK		BIT(EASRC_COC_IEC_EN_SHIFT)
+#define EASRC_COC_IEC_EN		BIT(EASRC_COC_IEC_EN_SHIFT)
+#define EASRC_COC_DITHER_EN_SHIFT	0
+#define EASRC_COC_DITHER_EN_MASK	BIT(EASRC_COC_DITHER_EN_SHIFT)
+#define EASRC_COC_DITHER_EN		BIT(EASRC_COC_DITHER_EN_SHIFT)
+
+/* ASRC Control Output Access (COA) */
+#define EASRC_COA_ITER_SHIFT		16
+#define EASRC_COA_ITER_WIDTH		6
+#define EASRC_COA_ITER_MASK		((BIT(EASRC_COA_ITER_WIDTH) - 1) \
+					 << EASRC_COA_ITER_SHIFT)
+#define EASRC_COA_ITER(v)		(((v) << EASRC_COA_ITER_SHIFT) \
+					 & EASRC_COA_ITER_MASK)
+#define EASRC_COA_GRLEN_SHIFT		8
+#define EASRC_COA_GRLEN_WIDTH		6
+#define EASRC_COA_GRLEN_MASK		((BIT(EASRC_COA_GRLEN_WIDTH) - 1) \
+					 << EASRC_COA_GRLEN_SHIFT)
+#define EASRC_COA_GRLEN(v)		(((v) << EASRC_COA_GRLEN_SHIFT) \
+					 & EASRC_COA_GRLEN_MASK)
+#define EASRC_COA_ACCLEN_SHIFT		0
+#define EASRC_COA_ACCLEN_WIDTH		6
+#define EASRC_COA_ACCLEN_MASK		((BIT(EASRC_COA_ACCLEN_WIDTH) - 1) \
+					 << EASRC_COA_ACCLEN_SHIFT)
+#define EASRC_COA_ACCLEN(v)		(((v) << EASRC_COA_ACCLEN_SHIFT) \
+					 & EASRC_COA_ACCLEN_MASK)
+
+/* ASRC Sample FIFO Status (SFS) */
+#define EASRC_SFS_IWTMK_SHIFT		23
+#define EASRC_SFS_IWTMK_MASK		BIT(EASRC_SFS_IWTMK_SHIFT)
+#define EASRC_SFS_IWTMK			BIT(EASRC_SFS_IWTMK_SHIFT)
+#define EASRC_SFS_NSGI_SHIFT		16
+#define EASRC_SFS_NSGI_WIDTH		7
+#define EASRC_SFS_NSGI_MASK		((BIT(EASRC_SFS_NSGI_WIDTH) - 1) \
+					 << EASRC_SFS_NSGI_SHIFT)
+#define EASRC_SFS_NSGI(v)		(((v) << EASRC_SFS_NSGI_SHIFT) \
+					 & EASRC_SFS_NSGI_MASK)
+#define EASRC_SFS_OWTMK_SHIFT		7
+#define EASRC_SFS_OWTMK_MASK		BIT(EASRC_SFS_OWTMK_SHIFT)
+#define EASRC_SFS_OWTMK			BIT(EASRC_SFS_OWTMK_SHIFT)
+#define EASRC_SFS_NSGO_SHIFT		0
+#define EASRC_SFS_NSGO_WIDTH		7
+#define EASRC_SFS_NSGO_MASK		((BIT(EASRC_SFS_NSGO_WIDTH) - 1) \
+					 << EASRC_SFS_NSGO_SHIFT)
+#define EASRC_SFS_NSGO(v)		(((v) << EASRC_SFS_NSGO_SHIFT) \
+					 & EASRC_SFS_NSGO_MASK)
+
+/* ASRC Resampling Ratio Low (RRL) */
+#define EASRC_RRL_RS_RL_SHIFT		0
+#define EASRC_RRL_RS_RL_WIDTH		32
+#define EASRC_RRL_RS_RL(v)		((v) << EASRC_RRL_RS_RL_SHIFT)
+
+/* ASRC Resampling Ratio High (RRH) */
+#define EASRC_RRH_RS_VLD_SHIFT		31
+#define EASRC_RRH_RS_VLD_MASK		BIT(EASRC_RRH_RS_VLD_SHIFT)
+#define EASRC_RRH_RS_VLD		BIT(EASRC_RRH_RS_VLD_SHIFT)
+#define EASRC_RRH_RS_RH_SHIFT		0
+#define EASRC_RRH_RS_RH_WIDTH		12
+#define EASRC_RRH_RS_RH_MASK		((BIT(EASRC_RRH_RS_RH_WIDTH) - 1) \
+					 << EASRC_RRH_RS_RH_SHIFT)
+#define EASRC_RRH_RS_RH(v)		(((v) << EASRC_RRH_RS_RH_SHIFT) \
+					 & EASRC_RRH_RS_RH_MASK)
+
+/* ASRC Resampling Ratio Update Control (RSUC) */
+#define EASRC_RSUC_RS_RM_SHIFT		0
+#define EASRC_RSUC_RS_RM_WIDTH		32
+#define EASRC_RSUC_RS_RM(v)		((v) << EASRC_RSUC_RS_RM_SHIFT)
+
+/* ASRC Resampling Ratio Update Rate (RRUR) */
+#define EASRC_RRUR_RRR_SHIFT		0
+#define EASRC_RRUR_RRR_WIDTH		31
+#define EASRC_RRUR_RRR_MASK		((BIT(EASRC_RRUR_RRR_WIDTH) - 1) \
+					 << EASRC_RRUR_RRR_SHIFT)
+#define EASRC_RRUR_RRR(v)		(((v) << EASRC_RRUR_RRR_SHIFT) \
+					 & EASRC_RRUR_RRR_MASK)
+
+/* ASRC Resampling Center Tap Coefficient Low (RCTCL) */
+#define EASRC_RCTCL_RS_CL_SHIFT		0
+#define EASRC_RCTCL_RS_CL_WIDTH		32
+#define EASRC_RCTCL_RS_CL(v)		((v) << EASRC_RCTCL_RS_CL_SHIFT)
+
+/* ASRC Resampling Center Tap Coefficient High (RCTCH) */
+#define EASRC_RCTCH_RS_CH_SHIFT		0
+#define EASRC_RCTCH_RS_CH_WIDTH		32
+#define EASRC_RCTCH_RS_CH(v)		((v) << EASRC_RCTCH_RS_CH_SHIFT)
+
+/* ASRC Prefilter Coefficient FIFO (PCF) */
+#define EASRC_PCF_CD_SHIFT		0
+#define EASRC_PCF_CD_WIDTH		32
+#define EASRC_PCF_CD(v)			((v) << EASRC_PCF_CD_SHIFT)
+
+/* ASRC Context Resampling Coefficient Memory (CRCM) */
+#define EASRC_CRCM_RS_CWD_SHIFT		0
+#define EASRC_CRCM_RS_CWD_WIDTH		32
+#define EASRC_CRCM_RS_CWD(v)		((v) << EASRC_CRCM_RS_CWD_SHIFT)
+
+/* ASRC Context Resampling Coefficient Control (CRCC) */
+#define EASRC_CRCC_RS_CA_SHIFT		16
+#define EASRC_CRCC_RS_CA_WIDTH		11
+#define EASRC_CRCC_RS_CA_MASK		((BIT(EASRC_CRCC_RS_CA_WIDTH) - 1) \
+					 << EASRC_CRCC_RS_CA_SHIFT)
+#define EASRC_CRCC_RS_CA(v)		(((v) << EASRC_CRCC_RS_CA_SHIFT) \
+					 & EASRC_CRCC_RS_CA_MASK)
+#define EASRC_CRCC_RS_TAPS_SHIFT	1
+#define EASRC_CRCC_RS_TAPS_WIDTH	2
+#define EASRC_CRCC_RS_TAPS_MASK		((BIT(EASRC_CRCC_RS_TAPS_WIDTH) - 1) \
+					 << EASRC_CRCC_RS_TAPS_SHIFT)
+#define EASRC_CRCC_RS_TAPS(v)		(((v) << EASRC_CRCC_RS_TAPS_SHIFT) \
+					 & EASRC_CRCC_RS_TAPS_MASK)
+#define EASRC_CRCC_RS_CPR_SHIFT		0
+#define EASRC_CRCC_RS_CPR_MASK		BIT(EASRC_CRCC_RS_CPR_SHIFT)
+#define EASRC_CRCC_RS_CPR		BIT(EASRC_CRCC_RS_CPR_SHIFT)
+
+/* ASRC Interrupt_Control (IC) */
+#define EASRC_IRQC_RSDM_SHIFT		8
+#define EASRC_IRQC_RSDM_WIDTH		4
+#define EASRC_IRQC_RSDM_MASK		((BIT(EASRC_IRQC_RSDM_WIDTH) - 1) \
+					 << EASRC_IRQC_RSDM_SHIFT)
+#define EASRC_IRQC_RSDM(v)		(((v) << EASRC_IRQC_RSDM_SHIFT) \
+					 & EASRC_IRQC_RSDM_MASK)
+#define EASRC_IRQC_OERM_SHIFT		4
+#define EASRC_IRQC_OERM_WIDTH		4
+#define EASRC_IRQC_OERM_MASK		((BIT(EASRC_IRQC_OERM_WIDTH) - 1) \
+					 << EASRC_IRQC_OERM_SHIFT)
+#define EASRC_IRQC_OERM(v)		(((v) << EASRC_IRQC_OERM_SHIFT) \
+					 & EASRC_IEQC_OERM_MASK)
+#define EASRC_IRQC_IOM_SHIFT		0
+#define EASRC_IRQC_IOM_WIDTH		4
+#define EASRC_IRQC_IOM_MASK		((BIT(EASRC_IRQC_IOM_WIDTH) - 1) \
+					 << EASRC_IRQC_IOM_SHIFT)
+#define EASRC_IRQC_IOM(v)		(((v) << EASRC_IRQC_IOM_SHIFT) \
+					 & EASRC_IRQC_IOM_MASK)
+
+/* ASRC Interrupt Status Flags (ISF) */
+#define EASRC_IRQF_RSD_SHIFT		8
+#define EASRC_IRQF_RSD_WIDTH		4
+#define EASRC_IRQF_RSD_MASK		((BIT(EASRC_IRQF_RSD_WIDTH) - 1) \
+					 << EASRC_IRQF_RSD_SHIFT)
+#define EASRC_IRQF_RSD(v)		(((v) << EASRC_IRQF_RSD_SHIFT) \
+					 & EASRC_IRQF_RSD_MASK)
+#define EASRC_IRQF_OER_SHIFT		4
+#define EASRC_IRQF_OER_WIDTH		4
+#define EASRC_IRQF_OER_MASK		((BIT(EASRC_IRQF_OER_WIDTH) - 1) \
+					 << EASRC_IRQF_OER_SHIFT)
+#define EASRC_IRQF_OER(v)		(((v) << EASRC_IRQF_OER_SHIFT) \
+					 & EASRC_IRQF_OER_MASK)
+#define EASRC_IRQF_IFO_SHIFT		0
+#define EASRC_IRQF_IFO_WIDTH		4
+#define EASRC_IRQF_IFO_MASK		((BIT(EASRC_IRQF_IFO_WIDTH) - 1) \
+					 << EASRC_IRQF_IFO_SHIFT)
+#define EASRC_IRQF_IFO(v)		(((v) << EASRC_IRQF_IFO_SHIFT) \
+					 & EASRC_IRQF_IFO_MASK)
+
+/* ASRC Context Channel STAT */
+#define EASRC_CSx_CSx_SHIFT		0
+#define EASRC_CSx_CSx_WIDTH		32
+#define EASRC_CSx_CSx(v)		((v) << EASRC_CSx_CSx_SHIFT)
+
+/* ASRC Debug Control Register */
+#define EASRC_DBGC_DMS_SHIFT		0
+#define EASRC_DBGC_DMS_WIDTH		6
+#define EASRC_DBGC_DMS_MASK		((BIT(EASRC_DBGC_DMS_WIDTH) - 1) \
+					 << EASRC_DBGC_DMS_SHIFT)
+#define EASRC_DBGC_DMS(v)		(((v) << EASRC_DBGC_DMS_SHIFT) \
+					 & EASRC_DBGC_DMS_MASK)
+
+/* ASRC Debug Status Register */
+#define EASRC_DBGS_DS_SHIFT		0
+#define EASRC_DBGS_DS_WIDTH		32
+#define EASRC_DBGS_DS(v)		((v) << EASRC_DBGS_DS_SHIFT)
+
+/* General Constants */
+#define EASRC_CTX_MAX_NUM		4
+#define EASRC_RS_COEFF_MEM		0
+#define EASRC_PF_COEFF_MEM		1
+
+/* Prefilter constants */
+#define EASRC_PF_ST1_ONLY		0
+#define EASRC_PF_TWO_STAGE_MODE		1
+#define EASRC_PF_ST1_COEFF_WR		0
+#define EASRC_PF_ST2_COEFF_WR		1
+#define EASRC_MAX_PF_TAPS		384
+
+/* Resampling constants */
+#define EASRC_RS_32_TAPS		0
+#define EASRC_RS_64_TAPS		1
+#define EASRC_RS_128_TAPS		2
+
+/* Initialization mode */
+#define EASRC_INIT_MODE_SW_CONTROL	0
+#define EASRC_INIT_MODE_REPLICATE	1
+#define EASRC_INIT_MODE_ZERO_FILL	2
+
+/* FIFO watermarks */
+#define FSL_EASRC_INPUTFIFO_WML		0x4
+#define FSL_EASRC_OUTPUTFIFO_WML	0x1
+
+#define EASRC_INPUTFIFO_THRESHOLD_MIN	0
+#define EASRC_INPUTFIFO_THRESHOLD_MAX	127
+#define EASRC_OUTPUTFIFO_THRESHOLD_MIN	0
+#define EASRC_OUTPUTFIFO_THRESHOLD_MAX	63
+
+#define EASRC_DMA_BUFFER_SIZE		(1024 * 48 * 9)
+#define EASRC_MAX_BUFFER_SIZE		(1024 * 48)
+
+#define FIRMWARE_MAGIC			0xDEAD
+#define FIRMWARE_VERSION		1
+
+#define PREFILTER_MEM_LEN		0x1800
+
+enum easrc_word_width {
+	EASRC_WIDTH_16_BIT = 0,
+	EASRC_WIDTH_20_BIT = 1,
+	EASRC_WIDTH_24_BIT = 2,
+	EASRC_WIDTH_32_BIT = 3,
+};
+
+struct __attribute__((__packed__))  asrc_firmware_hdr {
+	u32 magic;
+	u32 interp_scen;
+	u32 prefil_scen;
+	u32 firmware_version;
+};
+
+struct __attribute__((__packed__)) interp_params {
+	u32 magic;
+	u32 num_taps;
+	u32 num_phases;
+	u64 center_tap;
+	u64 coeff[8192];
+};
+
+struct __attribute__((__packed__)) prefil_params {
+	u32 magic;
+	u32 insr;
+	u32 outsr;
+	u32 st1_taps;
+	u32 st2_taps;
+	u32 st1_exp;
+	u64 coeff[256];
+};
+
+struct dma_block {
+	void *dma_vaddr;
+	unsigned int length;
+	unsigned int max_buf_size;
+};
+
+struct fsl_easrc_data_fmt {
+	unsigned int width : 2;
+	unsigned int endianness : 1;
+	unsigned int unsign : 1;
+	unsigned int floating_point : 1;
+	unsigned int iec958: 1;
+	unsigned int sample_pos: 5;
+	unsigned int addexp;
+};
+
+struct fsl_easrc_io_params {
+	struct fsl_easrc_data_fmt fmt;
+	unsigned int group_len;
+	unsigned int iterations;
+	unsigned int access_len;
+	unsigned int fifo_wtmk;
+	unsigned int sample_rate;
+	unsigned int sample_format;
+	unsigned int norm_rate;
+};
+
+struct fsl_easrc_slot {
+	bool busy;
+	int ctx_index;
+	int slot_index;
+	int num_channel;  /* maximum is 8 */
+	int min_channel;
+	int max_channel;
+	int pf_mem_used;
+};
+
+/**
+ * fsl_easrc_ctx_priv: EASRC context private data
+ *
+ * @in_params: input parameter
+ * @out_params:  output parameter
+ * @st1_num_taps: tap number of stage 1
+ * @st2_num_taps: tap number of stage 2
+ * @st1_num_exp: exponent number of stage 1
+ * @pf_init_mode: prefilter init mode
+ * @rs_init_mode:  resample filter init mode
+ * @ctx_streams: stream flag of ctx
+ * @rs_ratio: resampler ratio
+ * @st1_coeff: pointer of stage 1 coeff
+ * @st2_coeff: pointer of stage 2 coeff
+ * @in_filled_sample: input filled sample
+ * @out_missed_sample: sample missed in output
+ * @st1_addexp: exponent added for stage1
+ * @st2_addexp: exponent added for stage2
+ */
+struct fsl_easrc_ctx_priv {
+	struct fsl_easrc_io_params in_params;
+	struct fsl_easrc_io_params out_params;
+	unsigned int st1_num_taps;
+	unsigned int st2_num_taps;
+	unsigned int st1_num_exp;
+	unsigned int pf_init_mode;
+	unsigned int rs_init_mode;
+	unsigned int ctx_streams;
+	u64 rs_ratio;
+	u64 *st1_coeff;
+	u64 *st2_coeff;
+	int in_filled_sample;
+	int out_missed_sample;
+	int st1_addexp;
+	int st2_addexp;
+};
+
+/**
+ * fsl_easrc_priv: EASRC private data
+ *
+ * @slot: slot setting
+ * @firmware_hdr:  the header of firmware
+ * @interp: pointer to interpolation filter coeff
+ * @prefil: pointer to prefilter coeff
+ * @fw: firmware of coeff table
+ * @fw_name: firmware name
+ * @rs_num_taps:  resample filter taps, 32, 64, or 128
+ * @bps_iec958: bits per sample of iec958
+ * @rs_coeff: resampler coefficient
+ * @const_coeff: one tap prefilter coefficient
+ * @firmware_loaded: firmware is loaded
+ */
+struct fsl_easrc_priv {
+	struct fsl_easrc_slot slot[EASRC_CTX_MAX_NUM][2];
+	struct asrc_firmware_hdr *firmware_hdr;
+	struct interp_params *interp;
+	struct prefil_params *prefil;
+	const struct firmware *fw;
+	const char *fw_name;
+	unsigned int rs_num_taps;
+	unsigned int bps_iec958[EASRC_CTX_MAX_NUM];
+	u64 *rs_coeff;
+	u64 const_coeff;
+	int firmware_loaded;
+};
+#endif /* _FSL_EASRC_H */
-- 
2.21.0


^ permalink raw reply related

* Re: [PATCH v2 4/4] mm/vmalloc: Hugepage vmalloc mappings
From: Christoph Hellwig @ 2020-04-14  7:23 UTC (permalink / raw)
  To: Nicholas Piggin
  Cc: linux-arch, Will Deacon, Catalin Marinas, x86, linux-kernel,
	linux-mm, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20200413125303.423864-5-npiggin@gmail.com>

On Mon, Apr 13, 2020 at 10:53:03PM +1000, Nicholas Piggin wrote:
> For platforms that define HAVE_ARCH_HUGE_VMAP and support PMD vmap mappings,
> have vmalloc attempt to allocate PMD-sized pages first, before falling back
> to small pages. Allocations which use something other than PAGE_KERNEL
> protections are not permitted to use huge pages yet, not all callers expect
> this (e.g., module allocations vs strict module rwx).
> 
> This gives a 6x reduction in dTLB misses for a `git diff` (of linux), from
> 45600 to 6500 and a 2.2% reduction in cycles on a 2-node POWER9.
> 
> This can result in more internal fragmentation and memory overhead for a
> given allocation. It can also cause greater NUMA unbalance on hashdist
> allocations.
> 
> There may be other callers that expect small pages under vmalloc but use
> PAGE_KERNEL, I'm not sure if it's feasible to catch them all. An
> alternative would be a new function or flag which enables large mappings,
> and use that in callers.

Why do we even use vmalloc in this case rather than just doing a huge
page allocation?  What callers are you intersted in?

^ permalink raw reply

* Re: [PATCH] vhost: do not enable VHOST_MENU by default
From: Christian Borntraeger @ 2020-04-14  7:26 UTC (permalink / raw)
  To: Jason Wang, mst
  Cc: linux-s390, Thomas Bogendoerfer, Vasily Gorbik, kvm, linux-kernel,
	Heiko Carstens, linux-mips, virtualization, geert, netdev,
	Paul Mackerras, linuxppc-dev
In-Reply-To: <20200414024438.19103-1-jasowang@redhat.com>



On 14.04.20 04:44, Jason Wang wrote:
> We try to keep the defconfig untouched after decoupling CONFIG_VHOST
> out of CONFIG_VIRTUALIZATION in commit 20c384f1ea1a
> ("vhost: refine vhost and vringh kconfig") by enabling VHOST_MENU by
> default. Then the defconfigs can keep enabling CONFIG_VHOST_NET
> without the caring of CONFIG_VHOST.
> 
> But this will leave a "CONFIG_VHOST_MENU=y" in all defconfigs and even
> for the ones that doesn't want vhost. So it actually shifts the
> burdens to the maintainers of all other to add "CONFIG_VHOST_MENU is
> not set". So this patch tries to enable CONFIG_VHOST explicitly in
> defconfigs that enables CONFIG_VHOST_NET and CONFIG_VHOST_VSOCK.
> 
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
> Cc: Vasily Gorbik <gor@linux.ibm.com>
> Cc: Christian Borntraeger <borntraeger@de.ibm.com>

Fine with me.
s390 part

Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>

 That was my first approach to get things fixed before I reported
this to you.

> Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
>  arch/mips/configs/malta_kvm_defconfig  |  1 +
>  arch/powerpc/configs/powernv_defconfig |  1 +
>  arch/powerpc/configs/ppc64_defconfig   |  1 +
>  arch/powerpc/configs/pseries_defconfig |  1 +
>  arch/s390/configs/debug_defconfig      |  1 +
>  arch/s390/configs/defconfig            |  1 +
>  drivers/vhost/Kconfig                  | 18 +++++-------------
>  7 files changed, 11 insertions(+), 13 deletions(-)
> 
> diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
> index 8ef612552a19..06f0c7a0ca87 100644
> --- a/arch/mips/configs/malta_kvm_defconfig
> +++ b/arch/mips/configs/malta_kvm_defconfig
> @@ -18,6 +18,7 @@ CONFIG_PCI=y
>  CONFIG_VIRTUALIZATION=y
>  CONFIG_KVM=m
>  CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS=y
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_MODULES=y
>  CONFIG_MODULE_UNLOAD=y
> diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig
> index 71749377d164..404245b4594d 100644
> --- a/arch/powerpc/configs/powernv_defconfig
> +++ b/arch/powerpc/configs/powernv_defconfig
> @@ -346,5 +346,6 @@ CONFIG_CRYPTO_DEV_VMX=y
>  CONFIG_VIRTUALIZATION=y
>  CONFIG_KVM_BOOK3S_64=m
>  CONFIG_KVM_BOOK3S_64_HV=m
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_PRINTK_TIME=y
> diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
> index 7e68cb222c7b..4599fc7be285 100644
> --- a/arch/powerpc/configs/ppc64_defconfig
> +++ b/arch/powerpc/configs/ppc64_defconfig
> @@ -61,6 +61,7 @@ CONFIG_ELECTRA_CF=y
>  CONFIG_VIRTUALIZATION=y
>  CONFIG_KVM_BOOK3S_64=m
>  CONFIG_KVM_BOOK3S_64_HV=m
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_OPROFILE=m
>  CONFIG_KPROBES=y
> diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
> index 6b68109e248f..4cad3901b5de 100644
> --- a/arch/powerpc/configs/pseries_defconfig
> +++ b/arch/powerpc/configs/pseries_defconfig
> @@ -321,5 +321,6 @@ CONFIG_CRYPTO_DEV_VMX=y
>  CONFIG_VIRTUALIZATION=y
>  CONFIG_KVM_BOOK3S_64=m
>  CONFIG_KVM_BOOK3S_64_HV=m
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_PRINTK_TIME=y
> diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
> index 0c86ba19fa2b..6ec6e69630d1 100644
> --- a/arch/s390/configs/debug_defconfig
> +++ b/arch/s390/configs/debug_defconfig
> @@ -57,6 +57,7 @@ CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
>  CONFIG_CMM=m
>  CONFIG_APPLDATA_BASE=y
>  CONFIG_KVM=m
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_VHOST_VSOCK=m
>  CONFIG_OPROFILE=m
> diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
> index 6b27d861a9a3..d1b3bf83d687 100644
> --- a/arch/s390/configs/defconfig
> +++ b/arch/s390/configs/defconfig
> @@ -57,6 +57,7 @@ CONFIG_PROTECTED_VIRTUALIZATION_GUEST=y
>  CONFIG_CMM=m
>  CONFIG_APPLDATA_BASE=y
>  CONFIG_KVM=m
> +CONFIG_VHOST=m
>  CONFIG_VHOST_NET=m
>  CONFIG_VHOST_VSOCK=m
>  CONFIG_OPROFILE=m
> diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
> index e79cbbdfea45..14d296dc18cd 100644
> --- a/drivers/vhost/Kconfig
> +++ b/drivers/vhost/Kconfig
> @@ -12,23 +12,18 @@ config VHOST_RING
>  	  This option is selected by any driver which needs to access
>  	  the host side of a virtio ring.
>  
> -config VHOST
> -	tristate
> +menuconfig VHOST
> +	tristate "Vhost Devices"
>  	select VHOST_IOTLB
>  	help
> -	  This option is selected by any driver which needs to access
> -	  the core of vhost.
> -
> -menuconfig VHOST_MENU
> -	bool "VHOST drivers"
> -	default y
> +	  Enable option to support host kernel or hardware accelerator
> +	  for virtio device.
>  
> -if VHOST_MENU
> +if VHOST
>  
>  config VHOST_NET
>  	tristate "Host kernel accelerator for virtio net"
>  	depends on NET && EVENTFD && (TUN || !TUN) && (TAP || !TAP)
> -	select VHOST
>  	---help---
>  	  This kernel module can be loaded in host kernel to accelerate
>  	  guest networking with virtio_net. Not to be confused with virtio_net
> @@ -40,7 +35,6 @@ config VHOST_NET
>  config VHOST_SCSI
>  	tristate "VHOST_SCSI TCM fabric driver"
>  	depends on TARGET_CORE && EVENTFD
> -	select VHOST
>  	default n
>  	---help---
>  	Say M here to enable the vhost_scsi TCM fabric module
> @@ -49,7 +43,6 @@ config VHOST_SCSI
>  config VHOST_VSOCK
>  	tristate "vhost virtio-vsock driver"
>  	depends on VSOCKETS && EVENTFD
> -	select VHOST
>  	select VIRTIO_VSOCKETS_COMMON
>  	default n
>  	---help---
> @@ -63,7 +56,6 @@ config VHOST_VSOCK
>  config VHOST_VDPA
>  	tristate "Vhost driver for vDPA-based backend"
>  	depends on EVENTFD
> -	select VHOST
>  	depends on VDPA
>  	help
>  	  This kernel module can be loaded in host kernel to accelerate
> 


^ permalink raw reply

* Re: [PATCH v2] qtpm2: Export tpm2_get_cc_attrs_tbl for ibmvtpm driver as module
From: Jarkko Sakkinen @ 2020-04-14  7:29 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Sachin Sant, Stefan Berger, LKML, linux-next, linux-integrity,
	linuxppc-dev, Stefan Berger
In-Reply-To: <87k12ikhye.fsf@mpe.ellerman.id.au>

On Tue, Apr 14, 2020 at 10:51:37AM +1000, Michael Ellerman wrote:
> Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> writes:
> > On Wed, Apr 01, 2020 at 02:40:30PM +0530, Sachin Sant wrote:
> >> > On 20-Mar-2020, at 1:27 AM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote:
> >> > 
> >> > On Wed, Mar 18, 2020 at 09:00:17PM -0400, Stefan Berger wrote:
> >> >> From: Stefan Berger <stefanb@linux.ibm.com>
> >> >> 
> >> >> This patch fixes the following problem when the ibmvtpm driver
> >> >> is built as a module:
> >> >> 
> >> >> ERROR: modpost: "tpm2_get_cc_attrs_tbl" [drivers/char/tpm/tpm_ibmvtpm.ko] undefined!
> >> >> make[1]: *** [scripts/Makefile.modpost:94: __modpost] Error 1
> >> >> make: *** [Makefile:1298: modules] Error 2
> >> >> 
> >> >> Fixes: 18b3670d79ae ("tpm: ibmvtpm: Add support for TPM2")
> >> >> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> >> >> Reported-by: Sachin Sant <sachinp@linux.vnet.ibm.com>
> >> >> Tested-by: Sachin Sant <sachinp@linux.vnet.ibm.com>
> >> > 
> >> 
> >> Ping. This failure can now be seen in mainline (cad18da0af) as well.
> >
> > It is in my tree
> 
> Can you please send it to Linus?
> 
> cheers

Yes.

/Jarkko

^ permalink raw reply

* Re: -Wincompatible-pointer-types in arch/powerpc/platforms/embedded6xx/mvme5100.c
From: Michael Ellerman @ 2020-04-14  7:33 UTC (permalink / raw)
  To: Nathan Chancellor, linuxppc-dev, clang-built-linux; +Cc: Scott Wood
In-Reply-To: <20200413201034.GA18373@ubuntu-s3-xlarge-x86>

Hi Nathan,

Thanks for the report.

Nathan Chancellor <natechancellor@gmail.com> writes:
> Hi all,
>
> 0day reported a build error in arch/powerpc/platforms/embedded6xx/mvme5100.c
> when building with clang [1]. This is not a clang specific issue since
> it also happens with gcc:
>
> $ curl -LSs https://lore.kernel.org/lkml/202004131704.6MH1jcq3%25lkp@intel.com/2-a.bin | gzip -d > .config
> $ make -j$(nproc) -s ARCH=powerpc CROSS_COMPILE=powerpc-linux- olddefconfig arch/powerpc/platforms/embedded6xx/mvme5100.o
> arch/powerpc/platforms/embedded6xx/mvme5100.c: In function 'mvme5100_add_bridge':
> arch/powerpc/platforms/embedded6xx/mvme5100.c:135:58: error: passing argument 5 of 'early_read_config_dword' from incompatible pointer type [-Werror=incompatible-pointer-types]
>   135 |  early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
>       |                                                          ^~~~~~~~~~~~
>       |                                                          |
>       |                                                          phys_addr_t * {aka long long unsigned int *}


Yuck.

> ...
> I am not sure how exactly this should be fixed. Should this driver just
> not be selectable when CONFIG_PHYS_ADDR_T_64BIT is selected or is there
> something else that I am missing?

I'm not sure TBH. This is all ancient history as far as I can tell, none
of it's been touched for ~7 years.

Your config has:

CONFIG_EMBEDDED6xx=y
CONFIG_PPC_BOOK3S_32=y
CONFIG_PPC_BOOK3S_6xx=y
CONFIG_PPC_MPC52xx=y
CONFIG_PPC_86xx=y


Which I'm not sure really makes sense at all, ie. it's trying to build a
kernel for multiple platforms at once (EMBEDDED6xx, MPC52xx, 86xx), but
the Kconfig doesn't exclude that so I guess we have to live with it for
now.

Then Kconfig has:

config PHYS_64BIT
	bool 'Large physical address support' if E500 || PPC_86xx
	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
	select PHYS_ADDR_T_64BIT


So it's PPC_86xx that allows 64-bit phys_addr_t.

That was added in:

  4ee7084eb11e ("POWERPC: Allow 32-bit hashed pgtable code to support 36-bit physical")

Which did:

config PHYS_64BIT
-	bool 'Large physical address support' if E500
-	depends on 44x || E500
+	bool 'Large physical address support' if E500 || PPC_86xx
+	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx


ie. it wanted to add support for PPC_86xx but had to deliberately
exclude some of the other BOOK3S_32 based platforms.

So I'm going to guess it should have also excluded embedded6xx, and this
seems to fix it:

diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 0c3c1902135c..134fc383daf7 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -278,7 +278,7 @@ config PTE_64BIT
 
 config PHYS_64BIT
 	bool 'Large physical address support' if E500 || PPC_86xx
-	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
+	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx && !EMBEDDED6xx
 	select PHYS_ADDR_T_64BIT
 	---help---
 	  This option enables kernel support for larger than 32-bit physical


So unless anyone can tell me otherwise I'm inclined to commit that ^

cheers

^ permalink raw reply related

* Re: [PATCH] lib/mpi: Fix building for powerpc with clang
From: Michael Ellerman @ 2020-04-14  7:36 UTC (permalink / raw)
  To: Nathan Chancellor, Herbert Xu
  Cc: kbuild test robot, linux-kernel, clang-built-linux,
	Paul Mackerras, linux-crypto, Nathan Chancellor, linuxppc-dev
In-Reply-To: <20200413195041.24064-1-natechancellor@gmail.com>

Nathan Chancellor <natechancellor@gmail.com> writes:
> 0day reports over and over on an powerpc randconfig with clang:
>
> lib/mpi/generic_mpih-mul1.c:37:13: error: invalid use of a cast in a
> inline asm context requiring an l-value: remove the cast or build with
> -fheinous-gnu-extensions
>
> Remove the superfluous casts, which have been done previously for x86
> and arm32 in commit dea632cadd12 ("lib/mpi: fix build with clang") and
> commit 7b7c1df2883d ("lib/mpi/longlong.h: fix building with 32-bit
> x86").
>
> Reported-by: kbuild test robot <lkp@intel.com>
> Link: https://github.com/ClangBuiltLinux/linux/issues/991
> Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
> ---
>
> Herbet seems to take lib/mpi patches but there does not seem to be a
> formal maintainer so Michael could take it since it is just a powerpc
> thing.

Oh you mean it's inside:

#if (defined(_ARCH_PPC) || defined(_IBMR2)) && W_TYPE_SIZE == 32


I don't mind taking it with Herbet's ack, or he could just merge it.

cheers


>
>  lib/mpi/longlong.h | 34 +++++++++++++++++-----------------
>  1 file changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
> index 2dceaca27489..891e1c3549c4 100644
> --- a/lib/mpi/longlong.h
> +++ b/lib/mpi/longlong.h
> @@ -722,22 +722,22 @@ do {									\
>  do { \
>  	if (__builtin_constant_p(bh) && (bh) == 0) \
>  		__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "%r" ((USItype)(ah)), \
>  		"%r" ((USItype)(al)), \
>  		"rI" ((USItype)(bl))); \
>  	else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
>  		__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "%r" ((USItype)(ah)), \
>  		"%r" ((USItype)(al)), \
>  		"rI" ((USItype)(bl))); \
>  	else \
>  		__asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "%r" ((USItype)(ah)), \
>  		"r" ((USItype)(bh)), \
>  		"%r" ((USItype)(al)), \
> @@ -747,36 +747,36 @@ do { \
>  do { \
>  	if (__builtin_constant_p(ah) && (ah) == 0) \
>  		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "r" ((USItype)(bh)), \
>  		"rI" ((USItype)(al)), \
>  		"r" ((USItype)(bl))); \
>  	else if (__builtin_constant_p(ah) && (ah) == ~(USItype) 0) \
>  		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "r" ((USItype)(bh)), \
>  		"rI" ((USItype)(al)), \
>  		"r" ((USItype)(bl))); \
>  	else if (__builtin_constant_p(bh) && (bh) == 0) \
>  		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "r" ((USItype)(ah)), \
>  		"rI" ((USItype)(al)), \
>  		"r" ((USItype)(bl))); \
>  	else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
>  		__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "r" ((USItype)(ah)), \
>  		"rI" ((USItype)(al)), \
>  		"r" ((USItype)(bl))); \
>  	else \
>  		__asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
> -		: "=r" ((USItype)(sh)), \
> -		"=&r" ((USItype)(sl)) \
> +		: "=r" (sh), \
> +		"=&r" (sl) \
>  		: "r" ((USItype)(ah)), \
>  		"r" ((USItype)(bh)), \
>  		"rI" ((USItype)(al)), \
> @@ -787,7 +787,7 @@ do { \
>  do { \
>  	USItype __m0 = (m0), __m1 = (m1); \
>  	__asm__ ("mulhwu %0,%1,%2" \
> -	: "=r" ((USItype) ph) \
> +	: "=r" (ph) \
>  	: "%r" (__m0), \
>  	"r" (__m1)); \
>  	(pl) = __m0 * __m1; \
>
> base-commit: 8f3d9f354286745c751374f5f1fcafee6b3f3136
> -- 
> 2.26.0

^ permalink raw reply

* Re: -Wincompatible-pointer-types in arch/powerpc/platforms/embedded6xx/mvme5100.c
From: Nathan Chancellor @ 2020-04-14  7:52 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: Scott Wood, clang-built-linux, linuxppc-dev
In-Reply-To: <87eesqjzc6.fsf@mpe.ellerman.id.au>

Hi Michael,

On Tue, Apr 14, 2020 at 05:33:45PM +1000, Michael Ellerman wrote:
> Hi Nathan,
> 
> Thanks for the report.
> 
> Nathan Chancellor <natechancellor@gmail.com> writes:
> > Hi all,
> >
> > 0day reported a build error in arch/powerpc/platforms/embedded6xx/mvme5100.c
> > when building with clang [1]. This is not a clang specific issue since
> > it also happens with gcc:
> >
> > $ curl -LSs https://lore.kernel.org/lkml/202004131704.6MH1jcq3%25lkp@intel.com/2-a.bin | gzip -d > .config
> > $ make -j$(nproc) -s ARCH=powerpc CROSS_COMPILE=powerpc-linux- olddefconfig arch/powerpc/platforms/embedded6xx/mvme5100.o
> > arch/powerpc/platforms/embedded6xx/mvme5100.c: In function 'mvme5100_add_bridge':
> > arch/powerpc/platforms/embedded6xx/mvme5100.c:135:58: error: passing argument 5 of 'early_read_config_dword' from incompatible pointer type [-Werror=incompatible-pointer-types]
> >   135 |  early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
> >       |                                                          ^~~~~~~~~~~~
> >       |                                                          |
> >       |                                                          phys_addr_t * {aka long long unsigned int *}
> 
> 
> Yuck.
> 
> > ...
> > I am not sure how exactly this should be fixed. Should this driver just
> > not be selectable when CONFIG_PHYS_ADDR_T_64BIT is selected or is there
> > something else that I am missing?
> 
> I'm not sure TBH. This is all ancient history as far as I can tell, none
> of it's been touched for ~7 years.
> 
> Your config has:
> 
> CONFIG_EMBEDDED6xx=y
> CONFIG_PPC_BOOK3S_32=y
> CONFIG_PPC_BOOK3S_6xx=y
> CONFIG_PPC_MPC52xx=y
> CONFIG_PPC_86xx=y
> 
> 
> Which I'm not sure really makes sense at all, ie. it's trying to build a
> kernel for multiple platforms at once (EMBEDDED6xx, MPC52xx, 86xx), but
> the Kconfig doesn't exclude that so I guess we have to live with it for
> now.

c'est la randconfig :)

> Then Kconfig has:
> 
> config PHYS_64BIT
> 	bool 'Large physical address support' if E500 || PPC_86xx
> 	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
> 	select PHYS_ADDR_T_64BIT
> 
> 
> So it's PPC_86xx that allows 64-bit phys_addr_t.
> 
> That was added in:
> 
>   4ee7084eb11e ("POWERPC: Allow 32-bit hashed pgtable code to support 36-bit physical")
> 
> Which did:
> 
> config PHYS_64BIT
> -	bool 'Large physical address support' if E500
> -	depends on 44x || E500
> +	bool 'Large physical address support' if E500 || PPC_86xx
> +	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
> 
> 
> ie. it wanted to add support for PPC_86xx but had to deliberately
> exclude some of the other BOOK3S_32 based platforms.
> 
> So I'm going to guess it should have also excluded embedded6xx, and this
> seems to fix it:

This is what I was thinking as well; I agree with your analysis. Feel
free to slap the following tags on:

Reviewed-by: Nathan Chancellor <natechancellor@gmail.com>
Tested-by: Nathan Chancellor <natechancellor@gmail.com> # build

> diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
> index 0c3c1902135c..134fc383daf7 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -278,7 +278,7 @@ config PTE_64BIT
>  
>  config PHYS_64BIT
>  	bool 'Large physical address support' if E500 || PPC_86xx
> -	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
> +	depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx && !EMBEDDED6xx
>  	select PHYS_ADDR_T_64BIT
>  	---help---
>  	  This option enables kernel support for larger than 32-bit physical
> 
> 
> So unless anyone can tell me otherwise I'm inclined to commit that ^
> 
> cheers

Cheers,
Nathan

^ permalink raw reply

* [PATCH v10 14/14] powerpc: Use mm_context vas_windows counter to issue CP_ABORT
From: Haren Myneni @ 2020-04-14  7:54 UTC (permalink / raw)
  To: mpe
  Cc: mikey, ajd, frederic.barrat, srikar, linux-kernel, npiggin, hch,
	oohall, clg, sukadev, linuxppc-dev, herbert
In-Reply-To: <1585812024.2275.68.camel@hbabu-laptop>

(Thanks Michael for your review. Here is the updated patch with your
comments and from Nick - Moved mm_context_add/remove_coproc() to 
add/remove_vas_window())

>From 521f86710f3605dc575f13634fd7520087993ffb Mon Sep 17 00:00:00 2001
From: Haren Myneni <haren@us.ibm.com>
Date: Wed, 1 Apr 2020 23:12:12 -0500
Subject: [PATCH] powerpc: Use mm_context vas_windows counter to issue CP_ABORT

set_thread_uses_vas() sets used_vas flag for a process that opened VAS
window and issue CP_ABORT during context switch for only that process.
In multi-thread application, windows can be shared. For example Thread
A can open a window and Thread B can run COPY/PASTE instructions to
send NX request which may cause corruption or snooping or a covert
channel Also once this flag is set, continue to run CP_ABORT even the
VAS window is closed.

So define vas-windows counter in process mm_context, increment this
counter for each window open and decrement it for window close. If
vas-windows is set, issue CP_ABORT during context switch. It means
clear the foreign real address mapping only if the process / thread
uses COPY/PASTE. Then disable it for that process if windows are not
open.

Moved set_thread_uses_vas() code to vas_tx_win_open() as this
functionality is needed only for userspace open windows. We are adding
VAS userspace support along with this fix. So no need to include this
fix in stable releases.

Fixes: 9d2a4d71332c ("powerpc: Define set_thread_uses_vas()")
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
Reported-by: Nicholas Piggin <npiggin@gmail.com>
Suggested-by: Milton Miller <miltonm@us.ibm.com>
Suggested-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/include/asm/book3s/64/mmu.h    |  3 +++
 arch/powerpc/include/asm/mmu_context.h      | 30 +++++++++++++++++++++++++++++
 arch/powerpc/include/asm/processor.h        |  1 -
 arch/powerpc/include/asm/switch_to.h        |  2 --
 arch/powerpc/kernel/process.c               | 24 ++---------------------
 arch/powerpc/platforms/powernv/vas-window.c | 22 ++++++++++++---------
 6 files changed, 48 insertions(+), 34 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index bb3deb7..f0a9ff6 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -116,6 +116,9 @@ struct patb_entry {
 	/* Number of users of the external (Nest) MMU */
 	atomic_t copros;
 
+	/* Number of user space windows opened in process mm_context */
+	atomic_t vas_windows;
+
 	struct hash_mm_context *hash_context;
 
 	unsigned long vdso_base;
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 360367c..1a474f6b 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -185,11 +185,41 @@ static inline void mm_context_remove_copro(struct mm_struct *mm)
 			dec_mm_active_cpus(mm);
 	}
 }
+
+/*
+ * vas_windows counter shows number of open windows in the mm
+ * context. During context switch, use this counter to clear the
+ * foreign real address mapping (CP_ABORT) for the thread / process
+ * that intend to use COPY/PASTE. When a process closes all windows,
+ * disable CP_ABORT which is expensive to run.
+ *
+ * For user context, register a copro so that TLBIs are seen by the
+ * nest MMU. mm_context_add/remove_vas_window() are used only for user
+ * space windows.
+ */
+static inline void mm_context_add_vas_window(struct mm_struct *mm)
+{
+	atomic_inc(&mm->context.vas_windows);
+	mm_context_add_copro(mm);
+}
+
+static inline void mm_context_remove_vas_window(struct mm_struct *mm)
+{
+	int v;
+
+	mm_context_remove_copro(mm);
+	v = atomic_dec_if_positive(&mm->context.vas_windows);
+
+	/* Detect imbalance between add and remove */
+	WARN_ON(v < 0);
+}
 #else
 static inline void inc_mm_active_cpus(struct mm_struct *mm) { }
 static inline void dec_mm_active_cpus(struct mm_struct *mm) { }
 static inline void mm_context_add_copro(struct mm_struct *mm) { }
 static inline void mm_context_remove_copro(struct mm_struct *mm) { }
+static inline void mm_context_add_vas_windows(struct mm_struct *mm) { }
+static inline void mm_context_remove_vas_windows(struct mm_struct *mm) { }
 #endif
 
 
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index eedcbfb..bfa336f 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -272,7 +272,6 @@ struct thread_struct {
 	unsigned 	mmcr0;
 
 	unsigned 	used_ebb;
-	unsigned int	used_vas;
 #endif
 };
 
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 5b03d8a..012db9a 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -91,8 +91,6 @@ static inline void clear_task_ebb(struct task_struct *t)
 #endif
 }
 
-extern int set_thread_uses_vas(void);
-
 extern int set_thread_tidr(struct task_struct *t);
 
 #endif /* _ASM_POWERPC_SWITCH_TO_H */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index fad50db..ed3f645 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1221,7 +1221,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
 		 * mappings, we must issue a cp_abort to clear any state and
 		 * prevent snooping, corruption or a covert channel.
 		 */
-		if (current->thread.used_vas)
+		if (current->mm &&
+			atomic_read(&current->mm->context.vas_windows))
 			asm volatile(PPC_CP_ABORT);
 	}
 #endif /* CONFIG_PPC_BOOK3S_64 */
@@ -1460,27 +1461,6 @@ void arch_setup_new_exec(void)
 }
 #endif
 
-int set_thread_uses_vas(void)
-{
-#ifdef CONFIG_PPC_BOOK3S_64
-	if (!cpu_has_feature(CPU_FTR_ARCH_300))
-		return -EINVAL;
-
-	current->thread.used_vas = 1;
-
-	/*
-	 * Even a process that has no foreign real address mapping can use
-	 * an unpaired COPY instruction (to no real effect). Issue CP_ABORT
-	 * to clear any pending COPY and prevent a covert channel.
-	 *
-	 * __switch_to() will issue CP_ABORT on future context switches.
-	 */
-	asm volatile(PPC_CP_ABORT);
-
-#endif /* CONFIG_PPC_BOOK3S_64 */
-	return 0;
-}
-
 #ifdef CONFIG_PPC64
 /**
  * Assign a TIDR (thread ID) for task @t and set it in the thread
diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c
index 3ffad5a..4085fd6 100644
--- a/arch/powerpc/platforms/powernv/vas-window.c
+++ b/arch/powerpc/platforms/powernv/vas-window.c
@@ -1058,13 +1058,6 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
 			rc = -ENODEV;
 			goto free_window;
 		}
-		/*
-		 * A user mapping must ensure that context switch issues
-		 * CP_ABORT for this thread.
-		 */
-		rc = set_thread_uses_vas();
-		if (rc)
-			goto free_window;
 
 		/*
 		 * Window opened by a child thread may not be closed when
@@ -1090,7 +1083,7 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
 
 		mmgrab(txwin->mm);
 		mmput(txwin->mm);
-		mm_context_add_copro(txwin->mm);
+		mm_context_add_vas_window(txwin->mm);
 		/*
 		 * Process closes window during exit. In the case of
 		 * multithread application, the child thread can open
@@ -1099,6 +1092,17 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
 		 * to take pid reference for parent thread.
 		 */
 		txwin->tgid = find_get_pid(task_tgid_vnr(current));
+		/*
+		 * Even a process that has no foreign real address mapping can
+		 * use an unpaired COPY instruction (to no real effect). Issue
+		 * CP_ABORT to clear any pending COPY and prevent a covert
+		 * channel.
+		 *
+		 * __switch_to() will issue CP_ABORT on future context switches
+		 * if process / thread has any open VAS window (Use
+		 * current->mm->context.vas_windows).
+		 */
+		asm volatile(PPC_CP_ABORT);
 	}
 
 	set_vinst_win(vinst, txwin);
@@ -1332,7 +1336,7 @@ int vas_win_close(struct vas_window *window)
 			/* Drop references to pid and mm */
 			put_pid(window->pid);
 			if (window->mm) {
-				mm_context_remove_copro(window->mm);
+				mm_context_remove_vas_window(window->mm);
 				mmdrop(window->mm);
 			}
 		}
-- 
1.8.3.1




^ permalink raw reply related

* Re: [PATCH] kvm_host: unify VM_STAT and VCPU_STAT definitions in a single place
From: Paolo Bonzini @ 2020-04-14  8:18 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Emanuele Giuseppe Esposito, kvm
  Cc: Wanpeng Li, David Hildenbrand, linux-mips, kvmarm, linux-s390,
	Janosch Frank, Marc Zyngier, Joerg Roedel, Christian Borntraeger,
	Julien Thierry, Suzuki K Poulose, kvm-ppc, linux-arm-kernel,
	Jim Mattson, Cornelia Huck, linux-kernel, Sean Christopherson,
	James Morse, Vitaly Kuznetsov, linuxppc-dev
In-Reply-To: <03a481a8-bcf2-8755-d113-71ef393508bf@amsat.org>

On 13/04/20 23:34, Philippe Mathieu-Daudé wrote:
>> +#define VM_STAT(x, ...) offsetof(struct kvm, stat.x), KVM_STAT_VM, ## __VA_ARGS__
>> +#define VCPU_STAT(x, ...) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU, ## __VA_ARGS__
> I find this macro expanding into multiple fields odd... Maybe a matter
> of taste. Sugggestion, have the macro define the full structure, as in
> the arm64 arch:
> 
> #define VM_STAT(n, x, ...) { n, offsetof(struct kvm, stat.x),
> KVM_STAT_VM, ## __VA_ARGS__ }
> 
> Ditto for VCPU_STAT().
> 

Yes, that's a good idea.  Emanuele, can you switch it to this format?

Thanks,

Paolo


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox